# Raff Technologies — Full Content > Cloud infrastructure platform — VMs, S3-compatible object storage, managed Kubernetes, VPC networking, and a one-click app marketplace. AMD EPYC processors, NVMe SSD, unmetered bandwidth. ## Products - Raff VM: High-performance virtual machines built for production workloads. https://rafftechnologies.com/products/raff-vm - Linux VPS Hosting: Deploy Ubuntu, Debian, Rocky Linux, and 6 more distros in 60 seconds. Full root access, NVMe SSD, unmetered bandwidth. Plans start at $3.49 for your first month, then $4.99/mo. https://rafftechnologies.com/products/linux-vm - Windows VPS Hosting: Windows VPS hosting on Windows Server 2019, 2022 or 2025 with full RDP access, deployed in 55 seconds. Plans start at $13.99 for your first month, then $28.99/mo. 14-day money-back guarantee. https://rafftechnologies.com/products/windows-vm - ASP.NET Hosting: ASP.NET hosting on a Windows Server VPS you administer: IIS, the .NET Hosting Bundle for ASP.NET Core 8 to 10 and .NET Framework 4.8.1, SQL Server Express on the same box. Plans start at $13.99 for your first month, then $28.99/mo. https://rafftechnologies.com/products/aspnet-hosting - Block Storage Volumes: NVMe block storage volumes with online resize, snapshots, and volumes that survive VM deletion. 10 GiB to 1 TB. https://rafftechnologies.com/products/volumes - Cloud Security: Cloud security included free: automatic DDoS protection on every public IP, stateful firewalls, isolated VPCs, IAM and audit logs. https://rafftechnologies.com/products/security - Forex VPS: Windows VPS for MetaTrader 4, MT5 and cTrader, with low-latency US networking for Expert Advisors that run around the clock. https://rafftechnologies.com/products/forex-vm - Identity and Access Management (IAM): Identity and access management, free: built-in and custom roles with granular per-action permissions, project-scoped access, API keys, MFA and audit logs. https://rafftechnologies.com/products/iam - Load Balancers: Scalable load balancers for distributing traffic across your services. https://rafftechnologies.com/products/load-balancers - Managed ClickHouse: Columnar OLAP analytics hosting with flat pricing. https://rafftechnologies.com/products/managed-databases/clickhouse - Managed Databases: Fully managed database services for production workloads. https://rafftechnologies.com/products/managed-databases - Managed Kafka: Apache Kafka with flat per-broker pricing and schema registry. https://rafftechnologies.com/products/managed-databases/kafka - Managed Kubernetes: Production-ready Kubernetes clusters powered by OneKE. https://rafftechnologies.com/products/kubernetes - Managed Valkey: Redis-compatible in-memory caching, sessions and queues. https://rafftechnologies.com/products/managed-databases/valkey - MySQL Hosting: Managed MySQL 8 with automatic failover and daily backups. https://rafftechnologies.com/products/managed-databases/mysql - Object Storage: S3-compatible object storage on NVMe. $7/month includes 100 GB and 1 TB egress; no per-request fees. https://rafftechnologies.com/products/object-storage - PostgreSQL Hosting: Managed PostgreSQL with pgvector, HA and point-in-time recovery. https://rafftechnologies.com/products/managed-databases/postgresql - QuickBooks Enterprise Hosting: Self-managed QuickBooks Enterprise and Desktop hosting in multi-user mode on a Windows Server VPS you control. One person starts at $48.99 for the first month, then $63.99/mo, plus $8.00 per added user. Bring your own Intuit licence. https://rafftechnologies.com/products/quickbooks-vps - Raff Apps: Push-to-deploy PaaS on Raff's own cloud. Visual service canvas, managed Postgres/MySQL/Valkey, $0 egress, spend cap on by default, no per-seat pricing. The Railway, Render and Heroku alternative. https://rafftechnologies.com/products/app-platform - Raff Functions: Serverless functions billed on two meters: memory and active CPU. Free requests, free egress, no 15-minute cap. https://rafftechnologies.com/products/serverless-functions - Remote Desktop Hosting: Remote desktop hosting on a Windows Server VPS. Hosted virtual desktops at $8.00 per user per month through Raff SPLA, on a server you administer. One person starts at $30.99 for the first month, then $45.99/mo. https://rafftechnologies.com/products/remote-desktop-vps - Sage Hosting: Self-managed Sage hosting on a Windows Server VPS you control: Sage 50 multi-user over Remote Desktop as Sage documents it, Sage 100 and Sage 300 with SQL Server. One person starts at $48.99 for the first month, then $63.99/mo, plus $8.00 per added user. Bring your own Sage licence. https://rafftechnologies.com/products/sage-hosting - Server Backups & Snapshots: Automated incremental VM backups with schedules, snapshots and a free storage pool of 50 GB plus 10–15% of each VM disk. https://rafftechnologies.com/products/data-protection - Site-to-Site VPN: Site-to-site VPN from your office or another cloud into your Raff VPC: WireGuard or IPsec (IKEv2), up to 10 tunnels per gateway, unmetered tunnel traffic. https://rafftechnologies.com/products/site-to-site-vpn - SQL Server Hosting: SQL Server hosting on a Windows Server VPS. Express and Developer free, Standard and Enterprise through Raff SPLA or bring your own licence. Plans start at $13.99 for your first month, then $28.99/mo, with Windows included. https://rafftechnologies.com/products/sql-server-hosting - Virtual Private Cloud (VPC): Free virtual private cloud networking: isolated VPCs with security groups, peering, PrivateLink and site-to-site VPN. Private traffic unmetered. https://rafftechnologies.com/products/vpc ## Pricing Full pricing at https://rafftechnologies.com/pricing - VMs start at $4.99/mo (1 vCPU, 1 GB RAM, 25 GB NVMe) - All plans include unmetered bandwidth - Hourly billing with monthly invoicing - 14-day money-back guarantee ## Blog Articles ### Should You Run Kubernetes on a VPS in 2026? URL: https://rafftechnologies.com/blog/should-i-run-kubernetes-on-a-vps Published: 2026-03-12T00:00:00.000Z Description: Should You Run Kubernetes on a VPS in 2026? Kubernetes on a VPS makes sense when you need real container orchestration, control over your infrastructure, and predictable VM-level costs — but it is usually the wrong first step for a simple application. At Raff Technologies, we see Kubernetes as an upgrade path, not a badge of seriousness. Start with the simplest system that keeps your product reliable, then move to Kubernetes when the operational value is greater than the operational burden. Kubernetes on a VPS means running your Kubernetes nodes on virtual private servers instead of using a managed Kubernetes service. That gives you control over the operating system, networking, storage, upgrades, and cluster configuration. It also means your team owns the failure modes: node health, certificates, ingress, backups, persistent volumes, monitoring, security patches, and recovery. That trade-off is the heart of the decision. A VPS-based Kubernetes cluster can be efficient, flexible, and surprisingly capable. It can also become a small team’s most expensive “cheap” infrastructure choice if it turns every deployment into a cluster maintenance session. ## The Short Answer: Yes, But Not Too Early You should run Kubernetes on a VPS if your application has multiple services, needs orchestration across more than one machine, and your team is comfortable operating infrastructure. You should not run Kubernetes on a VPS just because Kubernetes is popular. This is where many teams lose time. They begin with a simple web app, one database, one background worker, and maybe a reverse proxy. Then they add Kubernetes before they have a deployment problem that Kubernetes actually solves. The result is not “cloud-native.” It is usually one developer debugging YAML, ingress, DNS, certificates, storage classes, and node pressure instead of shipping product. Our practical rule is this: if a single [Linux VPS](/products/linux-vm) with Docker Compose, Nginx, backups, and monitoring can run your workload reliably, stay there. If you are coordinating many services, need repeatable deployments across nodes, and want a production-like orchestration layer, Kubernetes becomes reasonable. ## What Running Kubernetes on a VPS Actually Means Running Kubernetes on a VPS means each node in your cluster is a virtual machine. A small setup might be one VPS running K3s for learning, development, or a lightweight internal tool. A more realistic production-style setup might use three VPS nodes, private networking, external backups, proper monitoring, and a clear storage strategy. That sounds simple until you list what you now own: * Node provisioning and operating system updates * Kubernetes installation and upgrades * Container runtime behavior * Ingress and TLS certificates * Cluster networking and firewall rules * Persistent storage and backup recovery * Monitoring, logging, and alerting * Security hardening and access control * Disaster recovery when a node fails This is not a reason to avoid Kubernetes. It is a reason to be honest about it. Kubernetes is excellent at orchestrating containers. It is not a replacement for infrastructure operations. ## The Real Decision Is Not VPS vs Kubernetes The real decision is not “Should I use a VPS or Kubernetes?” It is “How much operational complexity does my application justify right now?” For many small teams, the best path looks like this: | Stage | Best fit | Why | |---|---|---| | One app, one database, one worker | Single VPS + Docker Compose | Simple, cheap, easy to debug | | Several containers, still one server | Larger VPS + Docker Compose | More capacity without cluster overhead | | Multiple services needing orchestration | K3s on VPS nodes | Lightweight Kubernetes with lower overhead | | Mission-critical production platform | Managed Kubernetes or well-designed HA cluster | Better resilience and operational maturity | The mistake is skipping the early stages because Kubernetes feels more professional. Professional infrastructure is not the most complex infrastructure you can build. Professional infrastructure is the one your team can understand, maintain, and recover under pressure. ## When Kubernetes on a VPS Is a Good Idea Kubernetes on a VPS is a good idea when you have a real orchestration problem. That usually means you are running multiple services that need independent deployment, restart behavior, service discovery, or horizontal scaling. For example, a SaaS product with an API, frontend, background workers, internal admin tools, scheduled jobs, and several supporting services may benefit from a cluster model. It is also a good fit when your team wants to learn Kubernetes in an environment that behaves more like production than a laptop. Local tools are useful, but they hide parts of the operational picture. A VPS-based cluster forces you to think about networking, public IPs, firewall rules, storage, monitoring, and recovery. Kubernetes on a VPS can also make sense for cost-conscious teams. You can build a small cluster without paying for a large managed platform. On Raff, for example, a realistic lightweight K3s starting point would be a CPU-Optimized VM with 2 vCPU, 4 GB RAM, and 80 GB NVMe SSD at $36.99/month. A three-node starter cluster using that same VM size would be $110.97/month before optional snapshots, backups, external storage, or load balancing. For a team that understands Kubernetes, that can be a reasonable trade-off. ## When Kubernetes on a VPS Is the Wrong Move Kubernetes on a VPS is the wrong move when you are using it to solve a problem you do not have yet. If your application is still simple, Docker Compose is often enough. A single VM can run a frontend, backend, database, Redis, and Nginx with a clear backup plan. That architecture may not be fashionable, but it is understandable. A small team can SSH into the machine, inspect logs, restart services, restore a backup, and keep moving. It is also the wrong move if your team does not want to own infrastructure operations. Self-managed Kubernetes is not “set and forget.” Certificates expire. Nodes need patches. Pods get evicted. Storage behaves differently than you expect. Ingress controllers need maintenance. A small misconfiguration can create large debugging sessions. The most dangerous setup is a one-node “production” Kubernetes cluster that people assume is highly available. It is not. If the node dies, the workloads die with it. Kubernetes can restart pods, but it cannot restart a failed physical or virtual machine unless you have additional infrastructure around it. ## K3s Is Usually the Right Starting Point If you decide to run Kubernetes on VPS infrastructure, start with K3s unless you have a specific reason not to. K3s is a lightweight Kubernetes distribution designed to reduce operational overhead while keeping the Kubernetes API familiar. It packages many useful components by default and is widely used for edge, development, homelab, CI, and resource-constrained environments. For VPS users, that matters because the control plane should not consume the same resources your application needs. This does not mean K3s makes resource planning optional. The official K3s requirements are baseline requirements for K3s and its packaged components; they do not include the CPU and memory your workloads consume. In plain English: do not size your VPS only for Kubernetes. Size it for Kubernetes plus your application. A practical starting point is: | Use case | Suggested setup | |---|---| | Learning Kubernetes | 1 VPS, K3s, no production data | | Internal tool or staging | 1 larger VPS, K3s, backups, monitoring | | Small production workload | 2–3 VPS nodes, K3s, private networking, external backup plan | | Serious production platform | HA control plane, worker separation, load balancing, tested recovery | If you are using full kubeadm-based Kubernetes, plan more carefully. Production high availability usually requires multiple control-plane machines, an odd number of etcd members, reliable networking, and a load balancer in front of the API server. That is no longer “just run Kubernetes on a VPS.” That is a real platform project. ## The Cost Comparison That Matters Kubernetes does not only cost money. It costs attention. A single Raff CPU-Optimized VM at $36.99/month can run a small Docker Compose deployment with clear operations. A three-node K3s setup using the same VM size starts at $110.97/month. The price difference is not the only cost. You also add upgrade planning, cluster monitoring, ingress design, persistent volume decisions, and more failure modes. That does not make Kubernetes expensive. It makes Kubernetes honest. If Kubernetes helps your team deploy faster, isolate services, recover workloads, and standardize operations, the extra cost is justified. If it only adds a cluster around a simple app, you are paying for complexity without receiving the benefit. This is why we prefer decision-based infrastructure planning. Start with the deployment model that fits the stage of your product. Then upgrade when the product demands it. ## What About Managed Kubernetes? Managed Kubernetes exists because many teams want the Kubernetes API without owning every piece of the control plane. Raff’s [Kubernetes product](/products/kubernetes) is designed for teams that want managed container orchestration without starting from raw VM assembly. That path makes sense when your team wants Kubernetes as a platform, but does not want to spend its time maintaining the platform itself. Until then, a VPS-based K3s cluster is useful for learning, staging, internal tools, and cost-sensitive workloads. It gives you control. It teaches you the real moving parts. It can run real applications. But once uptime, scaling, multi-node resilience, and team workflows become critical, managed Kubernetes becomes more attractive. ## A Practical Decision Framework Use this framework before you choose Kubernetes on a VPS. Choose Docker Compose on a VPS if: * You run one application or a small group of containers * You do not need multi-node orchestration * You want the fastest path to production * Your team is small and prefers simple operations * You can handle restarts, backups, and deployments with straightforward scripts Choose K3s on VPS nodes if: * You want to learn Kubernetes properly * You run multiple services with independent deployments * You need service discovery, ingress, and orchestration * You accept responsibility for upgrades and cluster health * You want lower raw infrastructure cost than many managed options Choose managed Kubernetes if: * Your team needs Kubernetes but not control-plane maintenance * Reliability and recovery matter more than raw VM cost * You need autoscaling, monitoring, logging, and upgrade workflows * You are building a platform for multiple developers or teams * You want to spend less time operating the cluster itself The right answer depends on your stage. A startup validating a product should not copy the infrastructure pattern of a mature platform team. A mature platform team should not run mission-critical workloads on a casual one-node experiment. ## What This Means for You If you are deciding today, start with the smallest architecture that gives you reliable deployment and recovery. For many teams, that means launching a [Linux VM on Raff](/products/linux-vm), running Docker Compose, adding backups, and keeping the architecture simple. You can see the current VM options on the [pricing page](/pricing), then scale the VM or move into K3s when the workload becomes more complex. If you already know you need Kubernetes, treat VPS-based Kubernetes as a self-managed platform. Choose the VM size based on both cluster overhead and application requirements. Use private networking where possible. Plan backups before you deploy stateful workloads. Do not call a one-node cluster highly available. My recommendation is direct: run Kubernetes on a VPS when it solves a coordination problem, not when it only makes the architecture look more advanced. Start simple, move deliberately, and let your infrastructure complexity follow your product complexity — not the other way around. --- ### Why Backup Is a Sales Promise for MSPs, Not a Checkbox URL: https://rafftechnologies.com/blog/why-backup-is-a-sales-promise-for-msps Published: 2026-04-14T00:00:00.000Z Description: Why Backup Is a Sales Promise for MSPs, Not a Checkbox Most MSPs do not get blamed because a backup job existed. They get blamed because a recovery promise failed. That is the real reason I do not think backup should be treated as a checkbox service. For an MSP, backup is not only a technical control. It is a sales promise, a trust promise, and in the worst moments, a reputation promise. At Raff Technologies, that distinction matters because infrastructure decisions change what an MSP can confidently sell, what it can defend in front of a client, and what it can recover when something has already gone wrong. A backup is only useful if the client can get back to a working state inside an acceptable time window, with acceptable data loss, and without chaos. That is why I think MSPs make a mistake when they package backup as if it were only about scheduled jobs or storage usage. Clients do not buy “successful backup completion.” They buy confidence that their systems, files, and databases can come back when it matters. This is also why I think backup should be discussed alongside restore discipline, snapshots, object storage, and recovery design. If you sell backup without a credible recovery story, you are not really selling resilience. You are selling a dashboard status. ## The Client Does Not Buy the Backup Job This is the first mindset shift I would make if I were building an MSP offer today. Your client does not wake up wanting incremental schedules, retention policies, or storage tiers. They want a simpler answer to a harder question: “If something goes wrong, can you get us back?” That is the product. The technical stack behind it matters, of course. But the commercial value is not the backup file itself. The value is the confidence that a recovery path exists, is understood, and has enough operational discipline behind it that your team can execute under pressure. That is why I think backup is a sales promise. It sits in the proposal. It influences whether a client signs. It affects whether they trust you with production systems. And when an incident happens, it becomes the promise they judge most harshly. This is also where a lot of MSP packaging goes wrong. “Daily backups included” sounds fine in a pricing table. But it says almost nothing about recovery quality. Daily backups do not tell the client: * how fast restore starts * what data-loss window is realistic * whether the backup is isolated enough to matter * whether the team has tested the recovery path * whether a bad change replicated everywhere before anyone noticed Those are the questions that decide whether backup feels like protection or theater. ## Backup Is Really About Defensibility I think this is the most underrated part of managed backup services. Backup is not only about whether your system can recover. It is also about whether your team can defend its design after an incident. That means the infrastructure has to make sense when someone starts asking uncomfortable questions: Where was the backup stored? Was it on the same server? How recent was it? Was it tested? Was there a snapshot before the risky change? How long was the recovery supposed to take? Who owned the runbook? If an MSP cannot answer those questions clearly, then the service was never really mature enough to sell with confidence. That is one reason I like the separation Raff already makes across [Linux Virtual Machines](/products/linux-vm), [Data Protection](/products/data-protection), and [Object Storage](/products/object-storage). It encourages a cleaner conversation about what belongs on the runtime system, what belongs in backup policy, and what should live off-server as part of a more durable recovery design. To me, that separation matters commercially as much as technically. It gives an MSP a more defensible story. ## Snapshots, Backups, and Object Storage Should Not Be Sold as the Same Thing This is another place where I think many MSP offers get blurry too quickly. A snapshot is not the same thing as a backup. And neither is the same thing as object storage. A snapshot is usually the fastest tool for rollback around risky changes. It is perfect for “we are about to update, migrate, patch, or reconfigure something and want a point-in-time safety net.” That makes it valuable operationally, especially before admin work. A backup is broader recovery protection. It is what supports retention, longer rollback windows, and restoration after bigger incidents. That is the system clients usually think they are buying when they hear the word “backup.” Object storage solves a different part of the problem again. It gives you a cleaner place for exports, archives, longer-lived copies, and backup designs that do not pretend everything should remain tied to the same VM disk forever. Raff’s own object storage direction already reflects this kind of thinking: storage should not only exist, it should support practical operations and cleaner service design. :contentReference[oaicite:3]{index=3} That is why I would never bundle these three things into one vague sentence like “your data is protected.” That sentence may sell once. It will not defend you later. A better MSP position is more honest: * snapshots help you roll back quickly * backups help you recover after bigger problems * object storage helps you keep recovery data in a cleaner, more durable place outside the core server path That is a service promise a serious client can understand. ## The Real Product Is Restore Discipline This is where I think the entire conversation becomes more useful. If you want to know whether an MSP actually has a backup service, do not start by asking whether backup jobs run. Ask whether restore discipline exists. Can the team restore to a clean target? Can it estimate recovery time honestly? Can it validate the recovered state? Can it explain what gets restored first? Can it prove the backups are not only present but usable? That is the difference between backup as a checkbox and backup as an operational product. At Raff, I would frame this as a design question before a tooling question. Build the infrastructure so recovery is practical, then build the service package so the promise is clear. That means a simple server layer, well-defined snapshots, real backup policy, and an off-server storage path where appropriate. It also means not pretending a green status light is the same thing as readiness. This is why I think the pillar guide [Cloud Server Backup Strategies: Snapshots, RPO, and Recovery Planning](/learn/guides/cloud-server-backup-strategies) is the right center of gravity for this cluster. It gets closer to the real decision: what kind of recovery posture are you actually building? Then the sibling pieces become clearer: [Cloud Snapshots vs Backups: What’s the Difference?](/learn/guides/snapshots-vs-backups-cloud-server) for recovery-layer clarity, and [S3-Compatible Object Storage Use Cases for Developers](/learn/guides/s3-compatible-object-storage-use-cases-for-developers) for where backup-related storage strategy gets cleaner. ## Cheap Backup Is Often Expensive for an MSP This is the commercial part many providers still avoid saying directly. Cheap backup is often expensive for the MSP. Not because storage itself costs more. Because weak backup design creates labor, support drag, and trust damage. An MSP loses money when: * restores take too long * backup scope is misunderstood * retention is unclear * recovery steps are manual and inconsistent * client expectations were sold too loosely * the infrastructure forces the team into ticket-heavy cleanup This is why I do not like selling backup purely as a low-cost add-on. The cheaper the promise sounds, the more likely the client assumes it is universal and complete. Then the first real incident reveals the missing qualifiers. A better model is to package backup around outcome language: recovery confidence, restore speed, scope clarity, retention visibility, and pre-change rollback safety. That is also where predictable infrastructure matters. Raff’s pricing model and infrastructure building blocks make it easier to price around service outcomes rather than burying backup inside vague cost assumptions. The current CPU-Optimized entry tier starts at **$15.99/month** for **1 vCPU, 1 GB RAM, and 25 GB NVMe SSD**, and Tier 2 starts at **$18.99/month** for **1 vCPU, 2 GB RAM, and 50 GB NVMe SSD**. That gives an MSP a realistic low-cost place to standardize small client environments or isolated recovery tests without jumping immediately into oversized infrastructure decisions. :contentReference[oaicite:4]{index=4} ## The MSP Opportunity Is Bigger Than “Backup Included” What I find interesting is that managed backup and disaster recovery remain one of the strongest service lanes for MSPs, even as the threat environment gets worse and more identity-driven. That means clients need stronger answers, not broader marketing language. :contentReference[oaicite:5]{index=5} So the opportunity is not just to say: “we include backup.” The opportunity is to say: “we have a defined recovery posture, and we can explain it.” That changes the conversation from feature checklist selling to trust-based selling. It also helps MSPs differentiate without pretending to be a giant enterprise platform. A smaller provider can still win if its recovery story is simpler, clearer, and more believable than a bigger competitor’s bundle of vague promises. That is why I think this matters for Raff as well. MSPs are not only buying compute. They are buying an infrastructure base they can package into a service promise of their own. The more that infrastructure supports clear recovery design, the easier it becomes for them to sell with confidence. ## What This Means for You If you run an MSP, I would stop asking whether your package “includes backups.” I would ask four better questions: 1. Can we explain our recovery promise in plain English? 2. Can we separate snapshots, backups, and off-server storage clearly? 3. Can we test restores in a way we would defend in front of a client? 4. Can our infrastructure support that promise without margin-killing complexity? That is the level where backup becomes a real service. If you are building that kind of MSP offer on Raff, I would start with a simple [Linux VM](/products/linux-vm), define the core recovery posture using [Cloud Server Backup Strategies: Snapshots, RPO, and Recovery Planning](/learn/guides/cloud-server-backup-strategies), separate rollback from recovery with [Cloud Snapshots vs Backups: What’s the Difference?](/learn/guides/snapshots-vs-backups-cloud-server), and use [Object Storage](/products/object-storage) or the current [pricing](/pricing) page to shape a cleaner service package around retention and off-server copies. Because in the end, clients do not stay with an MSP because a backup job ran last night. They stay because when something breaks, the MSP can bring them back. And that is not a checkbox. That is the sale. --- ### Identity Is the New Front Door — What MSPs Should Change First URL: https://rafftechnologies.com/blog/dentity-is-the-new-front-door-for-msps Published: 2026-04-14T00:00:00.000Z Description: Identity Is the New Front Door — What MSPs Should Change First The first thing I would change in a small MSP environment today is not the SIEM, the backup SKU, or the dashboard stack. I would reduce the number of identity-controlled admin paths exposed to the public internet. That sounds simple, but it changes almost everything. At Raff Technologies, we spend a lot of time thinking about how infrastructure should be arranged so that a mistake, a stolen session, or a compromised credential does not immediately become an incident with a wide blast radius. For MSPs, that question matters even more, because one admin identity rarely touches just one system. It often touches several clients, multiple control panels, backup tools, remote access paths, and internal documentation systems. Identity security is no longer only about passwords or MFA checkboxes. It is the control layer that decides who can reach what, from where, and with how much privilege. If that layer is too broad, too exposed, or too fragmented, your environment becomes harder to defend even when every individual tool looks “secure enough” on paper. ## More Attacks Begin With Valid Access, Not Broken Locks One of the most important mindset shifts for MSPs is this: many modern attacks do not begin with an attacker “breaking in” through a dramatic exploit. They begin with access that looks valid enough to move forward. That access might come from a phished session, a weak remote admin path, a stale account, a poorly scoped privileged role, or an admin panel that should never have been internet-facing in the first place. Once an attacker is operating through identity, the question is no longer “Did the firewall block the packet?” It becomes “What can this identity touch now?” That is why I think “identity is the new front door” is not just a catchy line. It is a design problem. A common mistake here is treating identity as a separate security layer instead of treating it as part of network architecture. In practice, identity and exposure are tied together. If a privileged path is publicly reachable, identity abuse becomes far more dangerous. If that same path is reachable only through a private network segment with narrow firewall rules and fewer entry points, the operational risk changes immediately. ## The Real MSP Problem Is Too Many Exposed Admin Paths If I were auditing a typical small MSP environment, I would not start by asking which security products are installed. I would start by listing every admin path that is still publicly reachable. That usually includes things like: * SSH on client servers * RDP on Windows workloads * database admin interfaces * backup consoles * control panel logins * remote management tools * monitoring dashboards * web apps with hidden but public `/admin` routes Individually, each one may have a justification. Together, they often create a messy access surface that depends too heavily on users always authenticating correctly and attackers never getting a foothold. That is too much trust in the public edge. A cleaner design is to separate **customer-facing traffic** from **management traffic** early. Public services can stay public where needed. Administrative paths should move behind stricter boundaries. This is where I think many MSP environments drift into avoidable risk. They grow by adding tools faster than they standardize access patterns. A portal gets exposed because it is convenient. A remote admin path stays open because a migration was rushed. A shared operational habit becomes permanent because it “still works.” Then one compromised identity inherits a much larger map than anyone intended. ## What I Would Change First If the goal is to reduce identity-driven risk quickly, I would change four things before I bought another product. ### 1. Separate Public Traffic From Management Traffic Do not keep SSH, RDP, database access, and internal dashboards in the same exposure model as the public application. If a path exists only for operators, treat it like an operator path. That means moving it off the public lane where possible and making it reachable only from a narrower administrative boundary. Raff already has good foundational reading for this in [Private Networking in Cloud: Public vs Private Traffic](/learn/guides/private-networking-public-vs-private-traffic) and [Understanding Private Cloud Networks: VPC Design and Best Practices](/learn/guides/understanding-private-cloud-networks). A common mistake here is leaving a service public “temporarily” because firewall rules are in place. Temporary public management paths have a habit of becoming permanent. ### 2. Reduce the Number of Publicly Reachable Admin Interfaces This is the fastest cleanup with the clearest payoff. If an admin interface does not need to be internet-facing, remove it from the public path. That includes control surfaces people forget about because they are not part of the main application: internal Grafana instances, backup interfaces, phpMyAdmin, custom dashboards, direct database listeners, file manager panels, and default service ports. The fewer privileged surfaces a stolen identity can reach directly, the better. ### 3. Standardize How Admin Access Works MSPs often inherit inconsistent access patterns across clients. One server uses passwords, another uses SSH keys, another still has an open management port restricted only by IP, and a fourth depends on tribal knowledge inside the team. That inconsistency becomes operational debt very quickly. I would standardize admin access in the same order every time: * key-based access where applicable * minimal exposed ports * clear host naming and access ownership * narrow firewall rules * documented admin path expectations * fast removal of stale accounts and exceptions If your team needs a refresher on the basics, [How to Set Up SSH Keys on Ubuntu 24.04](/learn/tutorials/set-up-ssh-keys-ubuntu-24-04) and [How to Secure an Ubuntu 24.04 Server](/learn/tutorials/secure-ubuntu-24-04-server) are exactly the kind of foundation I would want in the cluster. ### 4. Treat Firewall Design as Part of Identity Design This is one point I think gets overlooked. Firewall rules are not only network policy. They shape what a compromised identity can attempt next. If your firewall still allows broad admin reachability, identity abuse has room to move. If your firewall policy is narrow and intentional, the same compromised session has fewer useful paths available. That is why I would review identity and firewall design together, not separately. Raff’s own guide [Firewall Best Practices for Cloud Servers](/learn/guides/firewall-best-practices-cloud-servers) fits naturally here because firewall discipline is one of the simplest ways to reduce what a valid-but-abused identity can touch. ## Private Networking Changes the Identity Problem This is the part I would want MSP operators to take seriously. Private networking does not “solve identity” on its own. But it changes the shape of the problem in a very practical way. Instead of trusting public reachability plus authentication to carry the whole burden, you reduce exposure first and let identity operate inside a narrower, better-defined environment. That is a much better place to defend from. On a small cloud layout, private networking helps you keep databases, internal services, admin utilities, and east-west traffic off the public edge. That means a compromised admin credential has fewer immediate paths if the attacker is not already inside the right network boundary. It also makes your diagrams cleaner, your runbooks clearer, and your client explanations easier to defend. From a design perspective, that is usually a better first move than adding more security tooling to an already overexposed layout. I have seen teams do the reverse. They add one more alerting layer, one more monitoring product, one more agent, one more console, but they still leave too many sensitive entry points reachable from the public side. That is expensive complexity without enough exposure reduction. ## Tool Sprawl Makes Identity Harder to Defend There is another reason this topic matters for MSPs: the more fragmented the access model becomes, the harder it is to know which identity actually has meaningful control. This is not just about convenience. It is about visibility. If one engineer signs into the backup console one way, the hypervisor another way, the remote support tool a third way, and the client application environment a fourth way, your team ends up with too many places where privilege exists and too many places where cleanup gets missed. That increases risk in quiet ways: * old accounts survive too long * admin rights stay broader than they should * exception paths never get removed * operators stop trusting the map of who can reach what For MSPs, this gets worse because environments are repeated across clients, but never repeated perfectly. Small inconsistencies multiply. That is why I think the first architectural win is not “better identity technology” in the abstract. It is fewer exposed decisions. Fewer public admin paths. Fewer special cases. Fewer control surfaces that depend on memory instead of design. ## What This Means for You If you run an MSP, I would start with one question: **Which privileged paths in our environment are still publicly reachable for convenience rather than necessity?** That question is much more useful than asking whether you “have identity security.” If the answer includes SSH, RDP, database access, backup portals, or internal dashboards, I would fix exposure first. Then I would tighten admin access patterns. Then I would standardize firewall behavior. Then I would review account scope and stale privileges. That order matters. If you want to build that way on Raff, start with a simple [Linux VM](/products/linux-vm), use [Private Cloud Networks](/products/private-cloud-networks) to move management traffic off the public edge, and keep your cost model clean through [Raff pricing](/pricing). A small isolated admin, bastion, or utility environment can start on a CPU-Optimized Tier 1 VM at **$15.99/month** for **1 vCPU, 1 GB RAM, and 25 GB NVMe SSD**. If you want more room for tooling, logs, or light internal services, Tier 2 starts at **$18.99/month** for **1 vCPU, 2 GB RAM, and 50 GB NVMe SSD**. Those numbers matter because access cleanup should not require overbuilding. It should be practical enough that you actually do it. If you want a clean next reading path, I would pair this post with [Private Networking in Cloud: Public vs Private Traffic](/learn/guides/private-networking-public-vs-private-traffic), [Understanding Private Cloud Networks: VPC Design and Best Practices](/learn/guides/understanding-private-cloud-networks), [Firewall Best Practices for Cloud Servers](/learn/guides/firewall-best-practices-cloud-servers), and [How to Secure an Ubuntu 24.04 Server](/learn/tutorials/secure-ubuntu-24-04-server). Because right now, the most useful change for many MSPs is not buying another security layer. It is making the front door smaller. --- ### Why Microsoft Licensing Matters When Choosing a Windows VM Provider URL: https://rafftechnologies.com/blog/why-microsoft-licensing-matters-windows-vm-provider Published: 2026-05-09T00:00:00.000Z Description: Why Microsoft Licensing Matters When Choosing a Windows VM Provider Microsoft licensing should be part of the Windows VM decision before you launch, not after the server is already running. That may sound like a small detail, but it is not. When a business chooses a Windows VM provider, it usually compares CPU, RAM, storage, bandwidth, support, deployment speed, and monthly price. Those things matter. But if the workload depends on Microsoft software, licensing clarity matters just as much. At Raff Technologies, this became even more important after Raff LLC became a Microsoft SPLA Partner. Through our Microsoft Service Provider License Agreement, Raff can provide hosted Microsoft software licensing through SPLA where applicable. A Windows VM is not only a virtual machine with Windows installed. It is a licensed Microsoft software environment running in a hosted cloud setting. That changes the buying decision. ## The Hidden Question Behind Every Windows VM Most Windows VM buyers start with a practical need. They need to run a business application. They need Remote Desktop access. They need to test software on Windows Server. They need to host a legacy application. They need a stable Windows environment that can be accessed from anywhere. Those are all valid reasons to use a hosted Windows VM. But behind each use case is a licensing question: Who is responsible for the Microsoft license? That question should be answered before the workload becomes important. A provider may offer a Windows server, but the customer still needs to understand whether that server is using an evaluation license, provider-supplied SPLA licensing, bring-your-own-license, or another valid licensing path. If the provider cannot explain that clearly, the customer inherits uncertainty. And uncertainty is not a good foundation for business infrastructure. ## Why Licensing Is Part of Infrastructure Quality Licensing may not look like a product feature at first. You cannot see it in the same way you see a dashboard, VM size, storage plan, or login screen. But for Windows workloads, licensing clarity is part of infrastructure quality. A properly sized VM with unclear licensing is still risky. A fast server with vague Microsoft software rights is still incomplete. A cheap Windows VPS can become expensive if the customer later discovers that the workload was not licensed correctly for production use. That is why Windows VM buyers should treat licensing as a trust signal. A serious provider should be able to explain: * Which Windows Server versions are available. * Whether the default license is evaluation, SPLA, or BYOL. * Whether the workload is suitable for production. * What happens after the evaluation period ends. * Whether Remote Desktop Services creates additional licensing needs. * Whether SQL Server or Microsoft 365 Apps introduce separate licensing questions. * What documentation or confirmation the customer should keep. This is not paperwork for the sake of paperwork. It is operational clarity. ## The Three Common Windows VM Licensing Paths Most hosted Windows VM decisions come down to three practical licensing paths. | Licensing path | Best for | Production-ready? | Who handles licensing? | |---|---|---:|---| | Evaluation license | Testing, demos, learning, short-term trials | No | Microsoft evaluation terms | | SPLA through provider | Hosted production workloads | Yes, where applicable | Service provider | | BYOL | Customers with eligible Microsoft licenses | Yes, if eligible | Customer | These paths are not interchangeable. An evaluation license can be useful when you are testing a workload or building a proof of concept. It gives you time to confirm whether the application works before committing to a production licensing path. SPLA is often the practical path when the provider supplies the eligible Microsoft software license for a hosted service. BYOL can work when the customer already owns eligible Microsoft licenses and has the right usage rights, such as Software Assurance or License Mobility where required. The important point is simple: Owning a Microsoft license does not automatically mean you can use it in every hosted cloud scenario. That is why BYOL should be checked carefully. For a deeper explanation of the three paths on Raff, read our guide: [Windows Server Licensing on Raff: Evaluation, SPLA, and BYOL Explained](/windows-server/windows-licensing). ## Why SPLA Matters The Microsoft Services Provider License Agreement, or SPLA, exists for hosted software service scenarios. Microsoft describes SPLA as a program for service providers and software companies that want to license eligible Microsoft products to provide software services and hosted applications to end customers. In practical terms, SPLA gives a cloud or hosting provider a structured way to provide eligible Microsoft software licensing for hosted customer workloads. For a Windows VM customer, that matters because it moves the licensing conversation from vague to structured. Instead of asking: “Is this Windows server licensed somehow?” the customer can ask: “Is this workload covered through the provider’s SPLA agreement, or do I need another licensing path?” That is a better conversation. It gives the customer a clearer way to evaluate the provider. It also shows whether the provider is treating Microsoft workloads responsibly. Raff LLC is now a Microsoft SPLA Partner, and we explained why that matters in our announcement: [Raff Is Now a Microsoft SPLA Partner](/blog/raff-microsoft-spla-partner). ## Why We Took This Seriously at Raff One lesson I have learned while building Raff is that customers do not only buy infrastructure. They buy confidence. A developer may start by comparing server specs. A founder may care about monthly cost. A freelancer may need fast deployment. A business may care about support and uptime. But when Windows workloads are involved, licensing becomes part of the trust equation. That is why Raff becoming a Microsoft SPLA Partner matters. It gives us a clearer framework for providing hosted Microsoft software services through SPLA where applicable. It also helps us support Windows VM customers more responsibly as Raff grows. This is not about using the biggest possible partnership language. It is about being precise. Raff LLC is a Microsoft SPLA Partner. Raff is licensed to host Microsoft software through its SPLA agreement where applicable. Microsoft software licensing can be provided through Raff’s SPLA agreement for eligible hosted workloads. Those are strong statements without overstating the relationship. And that is exactly how trust should be built. ## What Buyers Should Watch For When choosing a Windows VM provider, I would not start with the lowest monthly price. Start with the licensing model. A very cheap Windows VM can look attractive, but if the provider cannot explain the Microsoft license path clearly, the risk may be pushed onto you. Before choosing a provider, ask these questions: * Is the Windows Server license included, evaluation-based, SPLA-based, or BYOL? * Is the workload allowed for production use? * What happens after the evaluation period ends? * Are Windows licenses billed separately? * Can the provider support SPLA licensing? * Can I bring my own Microsoft license? * Do I need RDS CALs for multiple Remote Desktop users? * Does SQL Server introduce a separate licensing requirement? * Can the provider give written licensing clarification if needed? These questions are not only for enterprise customers. They matter for small businesses too. A small business running accounting software, ERP software, custom Windows applications, or Remote Desktop workflows may not have an internal licensing team. That makes provider clarity even more important. ## Windows VM Pricing Is Not Only the VM Price Windows VM pricing can be confusing because the VM and the Microsoft license may be separate. The VM price covers compute resources such as CPU, RAM, storage, bandwidth, and infrastructure features. The Microsoft software license may be billed separately depending on the provider and licensing path. This distinction matters. A customer comparing Windows VM providers should not only ask: “What is the server price?” They should ask: “What is the full monthly cost with the Windows license included?” That is the number that matters for planning. On Raff, Windows VPS plans start from $13.99/month, and each Windows VM can start with a 6-month evaluation license for non-production testing. For production workloads, customers should choose the right licensing path before relying on the server. Pricing clarity is not just a finance detail. It affects whether a customer can trust the platform enough to run real workloads on it. You can review current plans on the [Raff pricing page](/pricing), then compare your licensing path using the [Windows Server Licensing on Raff](/windows-server/windows-licensing) guide. ## Remote Desktop Changes the Conversation Many customers choose Windows VMs because they need Remote Desktop access. That makes sense. RDP is one of the most practical reasons to use a hosted Windows server. But Remote Desktop licensing has its own rules. A basic Windows Server setup usually allows limited administrative access. That is not the same as building a multi-user Remote Desktop environment for a team. If multiple users will connect regularly, RDS Client Access Licenses may be required. This is where many buyers get surprised. They assume that because the VM has Windows Server, every Remote Desktop scenario is automatically covered. That is not always true. If your team needs shared remote access, ask the provider how RDS CAL licensing works before deployment. The simplest way to think about it is this: A Windows VM can give you the server. A licensing plan determines what kind of access and usage is allowed. Those two things need to match. ## SQL Server and Office Need Separate Attention Windows Server licensing does not automatically solve every Microsoft software licensing question. SQL Server has its own licensing model. Microsoft 365 Apps and Office also have specific requirements, especially in shared or hosted desktop scenarios. That means a Windows VM provider should not treat “Microsoft licensing” as one generic answer. A customer may need Windows Server only. Another customer may need SQL Server. Another may need Remote Desktop Services. Another may want Microsoft 365 Apps in a shared environment. Each scenario can create different licensing requirements. This is why clear provider guidance matters. The better provider does not simply say, “Yes, we support Windows.” The better provider helps you understand what kind of Windows workload you are actually running. ## A Practical Decision Framework Use this simple framework before choosing a Windows VM provider. | Your situation | What to check first | |---|---| | You are testing software on Windows Server | Confirm the evaluation license is enough and keep the workload non-production. | | You are running business software | Confirm whether SPLA or eligible BYOL is needed before production. | | You need more than two RDP users | Review RDS CAL requirements before sizing the server. | | You need SQL Server | Check SQL Server edition, licensing model, and backup requirements separately. | | You already own Microsoft licenses | Confirm BYOL eligibility, Software Assurance, and License Mobility requirements. | | You want the provider to supply licensing | Ask whether SPLA licensing is available for your workload. | | You care about audit posture | Ask for written clarification of the licensing path. | This table is not a substitute for legal or licensing advice. But it is a better starting point than comparing Windows VM prices without understanding what those prices include. ## How Raff Approaches Windows VM Licensing Raff’s approach is to make the licensing path visible. For Windows VMs, the practical paths are: * Evaluation licensing for non-production testing and learning. * SPLA licensing through Raff for eligible hosted production workloads. * BYOL for customers with eligible Microsoft licenses and the right usage rights. This gives customers a way to start, test, and then move into the correct production path. For example, a developer can start with a Windows Server evaluation environment to test an application. If the project becomes production, the customer can move into a proper licensing path instead of pretending the evaluation environment was enough. That matters because testing and production are not the same thing. A lab workload can tolerate uncertainty. A business workload should not. You can explore Raff’s Windows VM product here: [Raff Windows VMs](/products/windows-vm). ## Infrastructure Still Matters Licensing is critical, but it is not the only decision. A properly licensed Windows VM still needs the right infrastructure behind it. For production workloads, buyers should also consider: * VM sizing * storage performance * backup strategy * private networking * firewall rules * support responsiveness * recovery planning * upgrade path * total monthly cost This is where the full provider decision becomes clearer. A Windows VM provider should not only give you a Microsoft license path. It should also give you infrastructure that can support the workload responsibly. For example, a Windows business application may need automated backups, restore points, and a recovery plan. Raff provides data protection features such as backups and snapshots, which you can review here: [Raff data protection](/products/data-protection). If your workload involves multiple servers or internal services, private networking can also matter. You can review that here: [Raff private cloud networks](/products/private-cloud-networks). Licensing answers the question: “Are we allowed to run this?” Infrastructure answers the question: “Can we run this reliably?” You need both. ## Provider Trust Is Built Before the First Login A customer’s trust in a Windows VM provider begins before they connect with RDP. It begins when they read the pricing page. It begins when they ask how licensing works. It begins when the provider explains limitations clearly. It begins when the provider is willing to say, “This path is right for testing, but not for production.” That kind of honesty matters. It may slow down a sale in the short term, but it builds a better customer relationship in the long term. At Raff, we want customers to understand what they are using. That includes server resources, pricing, backups, networking, support, and licensing. Especially licensing. Because when a business puts real work on a Windows VM, “probably fine” is not good enough. ## When a Windows VM Provider Is a Good Fit A Windows VM provider is a good fit when the workload needs more than a generic server. Look for a provider that can support: * Windows Server versions your software actually supports. * Full administrator access. * RDP access from different devices. * Clear VM sizing and pricing. * Backups and snapshots. * Networking and firewall controls. * A clear Microsoft licensing path. * SPLA or BYOL guidance where applicable. * Support that understands Windows workloads. Raff Windows VMs support Windows Server 2019, 2022, and 2025, with full administrator access and RDP. For businesses running Windows applications, that combination matters because the server is not just a test machine. It can become part of daily operations. The provider should be ready for that responsibility. If you are still comparing Windows and Linux workloads, you can also review the broader [Raff VM options](/products/raff-vm) before choosing the right environment. ## Red Flags to Avoid A Windows VM provider does not need to make licensing sound complicated. But it should be able to answer basic licensing questions clearly. Watch out for these red flags: * The provider cannot explain whether the Windows license is evaluation, SPLA, or BYOL. * The provider says “license included” without explaining what license path is being used. * The provider treats production and testing as if they are the same. * The provider ignores RDS CALs when multiple users need Remote Desktop. * The provider says BYOL is always allowed without checking eligibility. * The provider cannot explain SQL Server or Microsoft 365 Apps licensing separately. * The provider avoids giving written clarification for business workloads. None of these automatically mean a provider is bad. But they do mean you should slow down and ask more questions. For Microsoft workloads, vague answers create real risk. ## What This Means for You If you are choosing a Windows VM provider, do not treat Microsoft licensing as a footnote. Ask about it early. If you are testing, an evaluation license may be enough. If you are running production workloads, you need a proper licensing path. If you already own Microsoft licenses, check whether BYOL is actually eligible. If you need Remote Desktop for more than administrative access, review RDS CAL requirements. If you need SQL Server, review SQL Server licensing separately. If you want the provider to handle licensing for eligible hosted Microsoft workloads, ask whether SPLA is available. For Raff customers, the important point is simple: Raff LLC is a Microsoft SPLA Partner, licensed to provide hosted Microsoft software services through SPLA where applicable. That gives Windows VM customers a clearer foundation when evaluating Raff for business workloads. Start with the workload. Then choose the license path. Then choose the VM size. That order will save confusion later. ## Final Thought Windows VM hosting is not only about launching a server. It is about running a licensed Microsoft software environment in a hosted cloud setting. That means the provider’s licensing posture matters. The cheapest Windows VM is not always the safest choice. The most powerful VM is not always the right choice either. The right choice is the provider that gives you the performance, access, support, pricing clarity, and licensing path your workload needs. That is what Raff is working to provide. Fast infrastructure. Simple deployment. Reliable operations. And now, a stronger Microsoft licensing foundation through SPLA. --- ### Inside a Good Linux VM Base Image: What We Check Before It Goes Live URL: https://rafftechnologies.com/blog/inside-a-good-linux-vm-base-image Published: 2026-04-21T00:00:00.000Z Description: Inside a Good Linux VM Base Image: What We Check Before It Goes Live A good Linux VM base image is not just a bootable operating system. It is a starting state you can trust under automation, at scale, and under pressure. At Raff Technologies, that means we do not judge an image by whether it launches once. We judge it by whether package state is current, boot behavior is predictable, SSH defaults are sane, cloud-init is boring, disk expansion works cleanly, and rollback is possible when something changes underneath it. That sounds strict, but base images deserve that level of suspicion. Every small mistake in a base image gets multiplied. One weak SSH default becomes hundreds of weak SSH defaults. One cloud-init edge case becomes a noisy support pattern. One package that should have been refreshed becomes an avoidable patching problem on day one. This post is about the checks I care about before a Linux VM base image goes live. Not the marketing version. The operator version. > **Editor note:** Add one real Aybars-tested sentence in the first two sections before publishing. This topic needs a Category B first-hand signal from actual image validation, not a generic “we tested it” line. ## The Image Has to Be Safe Before It Is Convenient The easiest mistake with base images is to treat them like a shortcut. They are not. A base image is an opinionated operating environment that decides what every new VM inherits before the user touches anything. That is why image quality matters more than it first appears. The base image decides package age, boot defaults, service posture, initialization behavior, partition expectations, and early access paths. If those defaults are clean, the VM feels reliable immediately. If they are messy, the VM feels “mostly fine” until the first reboot, resize, or access issue exposes the cracks. I think that is the right frame for this topic. A good base image reduces future cleanup. A bad one quietly creates it. ## Package Freshness Is More Than Running Updates Once Package freshness is the first thing people mention, but I think it gets simplified too often. A fresh image is not just an image that ran `apt upgrade` or `dnf update` at some point. A fresh image is an image whose package state is recent enough that the user is not starting their VM by paying off hidden maintenance debt. Those are not the same thing. What I care about here is whether the image is shipping with a package set that still makes sense for first boot. Security updates matter, but so does consistency. If you publish an image with stale packages, the user’s first interaction becomes a remediation session. That is a bad first five minutes. The trick is that freshness has to be balanced against repeatability. You want current packages, but you also want to know what changed between image revisions. Otherwise the image feels current but not stable. A practical base image check should answer three questions: * Are the core packages recent enough to avoid obvious day-one patch debt? * Did anything important change compared to the previous image revision? * Would a user be surprised by what needs updating immediately after first boot? That last question matters more than most teams expect. Users do not evaluate freshness as an abstract security idea. They evaluate it as friction. ## systemd Sanity Is Really a Boot Predictability Check When I say I check systemd sanity, I do not mean “systemd exists and the machine boots.” I mean the machine boots in a way that makes sense. This is one of the most overlooked parts of image QA because the image may look fine under a quick launch test. Then later someone notices a service waiting on the wrong dependency, a unit starting too early, or a login path that behaves differently on the second reboot than it did on the first. A clean image should be boring at boot time. That is the goal. I usually think about systemd sanity in layers: * Does the image reach the expected target cleanly? * Are there failed or degraded units that should not be there? * Do cloud-specific services start in the right order? * Does the image behave the same on the first boot, second boot, and after a clean reboot? * Is there anything enabled by default that makes sense for a developer laptop image but not for a cloud VM image? A lot of Linux image problems are not catastrophic. They are ambiguous. The machine boots, but not confidently. For a base image, that is still a problem. A VM should not require interpretation after first boot. ## SSH Defaults Tell You Whether the Image Respects Reality SSH defaults are one of the clearest signals of whether a base image was built for the real world or only for internal convenience. A good image should make secure access straightforward without forcing the user into recovery mode on day one. A bad image usually fails in one of two directions: it is too permissive by default, or it becomes unnecessarily fragile the moment the user tries to harden it. That is why I look at SSH defaults as part of the image contract. I want to know: * what the default login path is * whether the image behaves cleanly with key-based access * whether root access is exposed in a way we are comfortable shipping * whether first-boot access and recovery still make sense if the user changes SSH behavior later This matters even more on a cloud platform because remote access is not theoretical. It is the first support boundary the user touches. At Raff, that question sits next to platform capabilities too. The fact that Linux VMs ship with web console access, snapshots, private networking, and other recovery-friendly infrastructure features changes how strict you can be with defaults, because the user still needs a safe path back if normal access goes sideways. That makes image design less about convenience and more about responsible starting assumptions. ## cloud-init Should Be Invisible When It Works cloud-init is one of those components people only notice when it misbehaves. That is exactly why it matters. A Linux VM base image in a cloud environment needs cloud-init to be predictable, not clever. Hostname assignment, SSH key injection, user creation, metadata handling, networking, and first-boot scripts all become part of the VM’s lived experience through cloud-init. If that behavior is inconsistent, the image stops feeling production-ready very quickly. What I want from cloud-init is simple: it should do the expected thing once, do it clearly, and get out of the way. A few questions usually reveal whether the image is ready: * Does first boot behave differently from subsequent boots in a way the user can understand? * Does the image pick up metadata cleanly? * Are SSH keys and user data processed as expected? * Are cloud-init logs useful when something fails? * Does the image reset the right state before publishing so the new VM does not inherit the wrong identity or cached behavior? That last one is a classic base-image trap. An image can pass a superficial launch test while still carrying state that should never have survived the image pipeline. A good cloud image is not just configured. It is de-personalized correctly. ## Disk Growth Has to Work Without Drama Disk growth is one of those things that looks obvious until it is not. Everyone expects a VM to handle more storage cleanly. Fewer people check whether the image actually expands partitions and filesystems in a way that feels safe and predictable when the disk changes after launch. That is why I do not treat disk growth as a nice extra. I treat it as part of image readiness. A base image should answer these questions before it goes live: * Does the root disk expand correctly when the VM launches with a larger volume? * Does the filesystem reflect the added space without awkward manual recovery? * Does the image handle common cloud expansion behavior without leaving the user in a half-grown state? * If expansion fails, does it fail clearly enough for someone to fix without guessing? This is especially important on a platform like Raff where VM usage can start small and grow later. General Purpose plans begin at $4.99/month for 1 vCPU, 1 GB RAM, and 25 GB NVMe SSD, while CPU-Optimized tiers begin at $15.99/month and scale upward depending on performance needs. That makes clean growth behavior part of the real user journey, not an edge case. An image that behaves badly when storage changes is not just technically incomplete. It is commercially awkward. ## Rollback Readiness Starts Before the Image Ships Rollback is often discussed as a platform feature, but I think it also belongs in image quality. A base image should not only be launchable. It should be survivable. That means understanding what happens if the image revision introduces a problem, if a package change creates boot regressions, or if a first-boot workflow behaves differently than expected. This is where snapshots, backups, revision discipline, and recovery paths stop being separate infrastructure topics and become part of image publishing maturity. I do not think every image team needs a dramatic rollback story. I do think every image team needs to answer these questions honestly: * Can we identify what changed between this image and the previous one? * Can we pull the image back out of circulation quickly? * Can a user recover a broken VM with the platform tools available? * Did we test the rollback path, or only talk about it? That is where image publishing becomes operator work instead of packaging work. ## What Actually Blocks Release for Me There are some issues I would treat as immediate stop signs. If package state is stale enough that first boot begins with preventable cleanup, I would block release. If the image boots with unclear service behavior, degraded units, or confusing startup order, I would block release. If SSH access works only under a narrow happy path, I would block release. If cloud-init still carries the wrong state, behaves inconsistently, or makes first boot hard to reason about, I would block release. If disk expansion works only in demos but not under real resize conditions, I would block release. And if the team cannot explain how to recover from an image-level mistake, I would block release too. That may sound like a harsh standard, but base images are upstream from too many other things to grade them generously. A shortcut here becomes support work later. ## What This Means for You If you launch Linux VMs regularly, the quality of the base image matters more than most people think. It affects patching, boot behavior, SSH access, provisioning, storage growth, and recovery before you install the first application. That is one reason I like thinking about base images as operational products rather than technical artifacts. A good image removes uncertainty from the first hour of a VM’s life. A bad one hides uncertainty inside it. If you are evaluating infrastructure, look beyond whether a VM can launch quickly. Ask what the base image is inheriting, what the platform gives you when something goes wrong, and whether growth and rollback are part of the design. On Raff, that conversation naturally connects to [Linux VMs](/products/linux-vm), [snapshots and backups](/products/data-protection), and the [web console](/blog/access-your-vm-anywhere-with-our-new-vnc-console), because image quality is only as useful as the recovery and scaling model around it. That is the standard I would use before publishing a Linux VM base image: not “it boots,” but “it stays predictable after first contact.” --- ### What Enterprise Buyers Really Notice About Startup Infrastructure URL: https://rafftechnologies.com/blog/what-enterprise-buyers-really-notice-about-startup-infrastructure Published: 2026-04-19T00:00:00.000Z Description: What Enterprise Buyers Really Notice About Startup Infrastructure ## Enterprise Buyers Do Not Buy the Most Complicated Stack Enterprise buyers rarely reject a startup because the infrastructure is too simple. They usually hesitate because the infrastructure story feels risky. At Raff Technologies, what I keep seeing is that larger buyers are not looking for the most fashionable architecture. They are looking for signs that your team understands risk, access, recovery, and operational discipline. That is the real shift founders need to understand. Enterprise-ready infrastructure is not infrastructure with the most tools. It is infrastructure that can answer predictable trust questions without hesitation. When a buyer asks who can access production, how environments are separated, where backups live, or what happens when a server fails, they are not making small talk. They are measuring whether your company is safe to depend on. This is where many startup teams misread the room. They assume enterprise buyers care most about scale diagrams, Kubernetes screenshots, or a long vendor list. Those things can matter later. But early on, buyers are usually reading for confidence. They want to know whether your infrastructure is understandable, controlled, and recoverable. ## What They Notice First Is Risk, Not Sophistication The first infrastructure questions in an enterprise conversation are usually not about how advanced your platform is. They are about how predictable it is. A buyer wants to know whether production access is limited, whether environments are separated, whether critical services are exposed only where necessary, and whether your team can recover from failure without improvising. Those questions sound operational, but they are commercial. If the answers feel vague, trust drops. And once trust drops, the sales cycle gets slower, legal gets louder, and procurement starts asking harder questions. This is why a clean setup often beats a flashy one. A startup that can clearly explain its production environment, access model, backup policy, and monitoring approach usually feels more credible than a startup with a sprawling architecture nobody can describe in plain English. In other words, enterprise buyers are not rewarding technical theater. They are rewarding operational clarity. ## The Signals That Quietly Build Confidence There are a few signals that matter far more than founders expect. The first is **environment separation**. Buyers want to hear that development, staging, and production are not all mixed together. They do not need a huge platform team behind it. They need evidence that experiments happen away from customer-facing systems. The second is **access discipline**. If everyone on the team can SSH into production whenever they want, that may feel fast internally, but externally it sounds fragile. Mature teams can explain who has access, how access is granted, and how it is removed. The third is **recovery discipline**. A buyer may never ask for your exact backup policy on the first call, but they will absolutely notice whether your answers sound rehearsed or invented on the spot. “We have backups” is not reassuring. “We know what is backed up, how often it runs, and how we would restore it” is reassuring. The fourth is **network boundaries**. Not everything should be public by default. Buyers may not use the phrase “attack surface,” but they definitely react to whether your infrastructure exposes only what it needs to expose. The fifth is **operational explainability**. This one matters more than people admit. If your team cannot explain the current setup without opening five dashboards and arguing in real time, the buyer notices. Enterprise customers are not only evaluating your product. They are evaluating whether your company behaves like a reliable operator. ## What Buyers Really Mean When They Say “Maturity” Founders often hear the word “maturity” and translate it into “we need more tooling.” I think that is usually the wrong translation. In enterprise buying, maturity usually means: * your team has clear boundaries between environments * production access is controlled * secrets are handled deliberately * backups and recovery are real, not theoretical * monitoring exists before the incident, not after it * the infrastructure can be explained by a human in normal language That is a much more practical standard than most teams imagine. It also means many startups are closer than they think. A lean setup can look mature if it is intentional. A messy setup can look immature even if it is expensive. This is one reason I like straightforward infrastructure foundations. A startup does not need ten layers of abstraction to look credible. It needs a setup that supports discipline. A [Linux Virtual Machine](/products/linux-vm), a defined network boundary, a backup plan, and limited production access often do more for enterprise trust than another month spent adding fashionable complexity. ## The Signals That Quietly Kill Confidence There are also a few patterns that almost always create doubt. One is **shared credentials**. Another is **production being used as a testing environment**. Another is **public exposure everywhere because it was faster during the first build**. Buyers may not always call these out directly, but they feel them in the conversation. The same is true when teams cannot answer basic operational questions. If someone asks how you would restore service after a bad deployment and the answer is effectively “we would figure it out,” that tells the buyer more than you think. It tells them the system may work today, but the company has not yet built dependable operating habits around it. This is also where overspending creates a false sense of progress. You can absolutely buy more infrastructure than you can operate well. You can also buy enterprise optics without building enterprise discipline. Buyers are usually better at spotting that than founders expect. ## Why Simplicity Is Still an Advantage One of the biggest mistakes startups make is assuming they need to imitate large companies too early. Big companies often have complex infrastructure because they have complex constraints: many teams, legacy systems, geographic spread, compliance requirements, internal platform layers, and years of accumulated decisions. Early-stage companies usually do not have those conditions yet. Copying the shape of enterprise infrastructure without having enterprise infrastructure needs often creates cost and confusion before it creates trust. In my view, buyers are usually more comfortable with a simple architecture that is well run than an advanced architecture that is poorly understood. That is also why predictable infrastructure products matter. If your team can launch on a clean [Linux Virtual Machine](/products/linux-vm), isolate services with [Private Cloud Networks](/products/private-cloud-networks), protect recovery with [Data Protection](/products/data-protection), and tighten exposure with clearly defined [Security features](/products/security), you already have a stronger enterprise story than many founders realize. A lean environment does not need to be expensive either. On Raff, a General Purpose VM with **2 vCPU, 4 GB DDR5 RAM, and 80 GB NVMe storage costs $17.99/month**, while a CPU-Optimized VM at the same **2 vCPU, 4 GB RAM, and 80 GB NVMe SSD costs $36.99/month** when you need more predictable compute behavior. The important part is not the price alone. It is that the setup stays understandable as you grow. ## What Founders Should Fix Earlier If you want to look more enterprise-ready without overbuilding, I would start with four things. First, separate environments clearly. Even a modest staging environment changes the conversation because it shows you do not treat production as a sandbox. Second, define access before someone asks. Know who can reach production, who approves changes, and how credentials are handled. You do not need a giant IAM project to do this better than most early teams. Third, decide your recovery story while the system is still small. Backups, snapshots, rollback paths, and deployment discipline are cheaper to organize early than to retrofit under pressure. Fourth, keep the architecture explainable. If a buyer asks how your application is deployed, where the data lives, what is public, and how you recover from failure, the answer should be understandable in minutes. That last point is underrated. Clear explanations reduce perceived risk. Reduced perceived risk shortens sales friction. In B2B infrastructure conversations, clarity is not just technical hygiene. It is sales leverage. ## The Real Enterprise Readiness Test A useful question for any founder is this: if a serious enterprise prospect asked me five operational questions tomorrow, would my team answer calmly or defensively? That question gets to the heart of it. Enterprise buyers are not looking for perfection. They know startups are still building. What they want is evidence that the company makes deliberate infrastructure decisions. They want to see that the system is not being held together by habit, memory, and luck. If your infrastructure can be explained, access can be justified, recovery can be described, and risks have visible boundaries, you already look more mature than a lot of startup teams competing for the same buyer attention. ## What This Means for You If you sell to larger customers, infrastructure should stop being an internal-only topic. It directly affects sales confidence. You do not need to become an enterprise infrastructure company overnight. You need to remove the obvious trust gaps first. Start with environment separation, access control, recovery, network boundaries, and operational clarity. Then make those decisions visible enough that a buyer can understand them. That is why I think infrastructure simplicity is still a competitive advantage when it is paired with discipline. A startup that runs on understandable systems, clear boundaries, and predictable pricing is often easier to trust than one hiding behind complexity. If your current setup feels more improvised than intentional, fix the basics before you add more layers. Review your production boundaries, access model, backup posture, and exposure points. Then look at whether your current platform still supports that cleanly on the operational side and on the cost side. A quick pass through your [pricing](/pricing), core VM setup, and network/security foundation is often a better next move than another architectural detour. ## Final Thought The infrastructure that wins enterprise trust is usually less dramatic than founders expect. It is not the stack with the most moving parts. It is the one that makes risk feel contained. That is the part worth remembering. Enterprise buyers are not only asking whether your product works. They are asking whether your company can be trusted when things go wrong. And most of the time, they answer that question by looking at the boring parts first. --- ### Small Enterprise Teams Need Cloud VMs, Not Red Tape URL: https://rafftechnologies.com/blog/why-small-enterprise-teams-gain-the-most-from-cloud-v-ms Published: 2025-09-22T00:00:00.000Z Description: Small Enterprise Teams Need Cloud VMs, Not Red Tape Small enterprise teams often gain more from cloud VMs than large enterprise departments because they feel infrastructure friction immediately. When a team of 3 to 10 people is trying to launch an internal tool, test a workflow, host a small application, or support a client project, waiting weeks for procurement, approvals, and shared infrastructure access can kill momentum. At Raff Technologies, this is one of the clearest use cases for focused cloud infrastructure. A small enterprise team does not always need a giant cloud architecture. It often needs a reliable VM, clear pricing, fast provisioning, backups, snapshots, private networking, and enough control to move without turning every project into an IT ticket. That is the real point of cloud VMs for smaller enterprise teams: they create a practical middle ground between slow enterprise infrastructure and risky shadow IT. The team gets speed and autonomy, while the organization keeps the workload on infrastructure that can be secured, documented, and scaled. ## Enterprise Teams Are Not All the Same Size When people say “enterprise,” they usually imagine huge departments, formal IT roadmaps, centralized procurement, and large infrastructure teams. That picture is incomplete. Inside many enterprise companies, real work often happens in smaller groups: * A data team building an internal dashboard * A product team testing a new customer workflow * A regional office running a local application * A support team automating repetitive tasks * A development team creating a staging environment * A business unit testing a proof of concept * A training team needing temporary Linux or Windows environments * A project team supporting one client implementation These teams may sit inside large organizations, but they operate with small-team urgency. They need infrastructure that moves at project speed, not committee speed. That is why cloud VMs are so useful. They give small enterprise teams a direct path to compute without forcing them to wait for a full platform decision. ## The Problem Is Usually Not Lack of Infrastructure Large companies usually have infrastructure. That is not the problem. The problem is access. A small team may technically have access to enterprise IT, but the path can be slow: * Submit a request * Wait for approval * Clarify the workload * Wait for budget confirmation * Wait for security review * Wait for provisioning * Wait for networking * Wait for credentials * Wait for change windows For major production systems, that process may be necessary. But for a short-term test, internal dashboard, developer environment, prototype, or isolated workload, it can be too heavy. Small teams do not always need more infrastructure. They need a faster path to the right amount of infrastructure. That distinction matters. ## Cloud VMs Give Small Teams a Clean Starting Point A cloud VM gives a small enterprise team something very practical: a clean server they can control. That server can become: * A development environment * A staging server * A test database host * A lightweight production app * A client demo environment * A remote desktop * A training lab * A backup target * An automation runner * A monitoring node * A proof-of-concept environment The value is not only compute power. The value is separation. A project does not need to run on someone’s laptop. A test does not need to pollute a shared server. A temporary workload does not need to become permanent infrastructure. A team can create an environment for the job, document it, secure it, and remove it when it is no longer needed. That is exactly where a [Raff Linux VM](/products/linux-vm) or [Raff Windows VM](/products/windows-vm) can fit into enterprise workflows without forcing a heavy platform migration. ## The Best Use Cases Are Practical, Not Theoretical The strongest cloud VM use cases for small enterprise teams are usually boring in the best way. They are not always giant AI clusters or complex distributed systems. They are the everyday blockers that slow teams down. A team needs a Linux box to test an API. A developer needs a clean Ubuntu server for a client build. A business unit needs a Windows environment for a specific tool. A support team needs a small internal dashboard. A QA team needs a staging server that can be rebuilt. A manager needs a demo environment for next week. A junior developer needs a safe place to learn server setup. These are not “enterprise transformation” projects. They are practical infrastructure needs. And practical infrastructure should not require unnecessary ceremony. If your team is still deciding which VM size fits the workload, start with [Choosing the Right VM Size](/learn/guides/choosing-right-vm-size) before overbuying resources. ## Cloud VMs Reduce Shadow IT Risk When small teams cannot get infrastructure through official channels quickly enough, they often improvise. That is where shadow IT begins. Someone uses a personal cloud account. Someone runs a service on a laptop. Someone creates an unmanaged server. Someone stores credentials in the wrong place. Someone forgets who owns the environment. The intention is usually not bad. The team just needs to move. But unmanaged infrastructure creates risk. It becomes harder to secure, monitor, back up, document, and retire. A better model is to give small teams a sanctioned, simple way to launch cloud VMs with clear ownership and guardrails. That gives them speed without losing control. This is where Raff can be useful for enterprise-adjacent teams. The platform keeps the VM model straightforward while still supporting important infrastructure basics such as SSH access, web console access, snapshots, backups, firewall management, and private networking. For teams thinking about secure internal connectivity, [Private Cloud Networks](/products/private-cloud-networks) are a natural next layer after the first VM. ## Small Teams Need Cost Clarity More Than Complex Discounts Enterprise cloud pricing can become difficult to explain, especially when teams only need a few simple workloads. A small team may not have time to forecast dozens of resource categories. They need to know what a server costs, what storage costs, and what happens when the workload grows. This is why cloud VMs are attractive. They give teams a more understandable unit of infrastructure. On Raff, CPU-Optimized VMs start at $15.99/month for 1 vCPU, 1 GB RAM, and 25 GB NVMe SSD. General Purpose VMs start at $4.99/month for the same 1 vCPU, 1 GB RAM, and 25 GB NVMe SSD on shared vCPU. That makes it easier for small teams to start with a real server without committing to a large enterprise architecture. Cost clarity helps teams move faster because the decision becomes easier to approve. If the workload grows, the team can resize, split roles, or add more VMs later. If the project ends, the team can shut it down instead of leaving unused hardware or forgotten infrastructure behind. You can compare current plans on the [Raff pricing page](/pricing). ## Speed Matters Because Small Teams Have Less Slack Large teams can sometimes absorb slow infrastructure processes. A delay is annoying, but there may be another team, another sprint, or another parallel workstream. Small teams feel delays immediately. If a 5-person team loses three days waiting for a test environment, the impact is visible. The developer waits. The product manager waits. The customer demo waits. The experiment waits. That is why fast provisioning is not just convenience. It is productivity. A VM that can be launched quickly gives the team a place to work now. They can test the idea, validate the setup, and decide whether the workload deserves more investment. This is the same reason cloud VMs are useful for development workflows. The related Raff article [Why More Modern Dev Workflows Start in the Cloud, Not on a Laptop](/blog/why-cloud-v-ms-beat-local-machines-for-modern-dev-workflows) explains why project environments increasingly belong in reproducible cloud infrastructure rather than only on personal machines. ## Cloud VMs Help Teams Stay Focused Small enterprise teams rarely want to become infrastructure teams. They want to ship the internal tool, complete the client project, support the business unit, test the workflow, or launch the demo. The infrastructure should support that goal without becoming the main project. That is why VM simplicity matters. A clean VM model gives teams enough control without forcing them into a maze of services they do not need yet. A good starting point often looks like this: * One VM for the app or tool * Firewall rules for access control * Backups or snapshots for recovery * Private networking if the VM needs to communicate with internal services * Clear ownership inside the team * A documented shutdown or handoff plan That setup is not glamorous, but it works. For many internal projects, that is exactly the point. ## When One VM Is Enough A single VM is often enough when the workload is small, isolated, and easy to understand. Use one VM when: * The project is early * Traffic is low * The workload is internal * Downtime is acceptable * The database is small * The team needs speed more than high availability * The environment is temporary * The project is a proof of concept A single VM gives the team simplicity. There is one server to configure, monitor, secure, and document. That simplicity is valuable, especially when the project is still being validated. If the workload later becomes more important, the team can evolve the architecture. Raff’s [Single VM vs Multi-VM Architecture for SaaS Apps](/learn/guides/single-vm-vs-multi-vm-saas-architecture) explains when to split app, database, worker, and cache roles across multiple VMs. ## When Small Teams Should Add More Structure Small teams should add more infrastructure structure when the workload becomes important enough to justify it. That usually happens when: * More users depend on the service * The database needs stronger protection * Downtime becomes expensive * Backups need formal retention * Background jobs affect app performance * Multiple people need access * Compliance or security review becomes necessary * The project moves from experiment to production At that point, the team may need a separate database, better backup planning, a load balancer, private networking, monitoring, or a more formal deployment process. The key is sequencing. Do not start with enterprise complexity if the workload is still a prototype. But do not keep prototype infrastructure after the workload becomes important. For scaling decisions, [Horizontal vs Vertical Scaling](/learn/guides/horizontal-vs-vertical-scaling-cloud) is a useful companion guide. ## The Business Case Is Autonomy With Guardrails The real business case for cloud VMs inside small enterprise teams is autonomy with guardrails. Autonomy means the team can move without waiting for every small infrastructure action. Guardrails mean the organization still has a sensible operating model: known infrastructure, documented access, clear billing, recoverable environments, and a path to scale. That balance matters. Too much centralization slows small teams down. Too much freedom creates unmanaged risk. A focused cloud VM platform gives teams a practical middle ground. This is why Raff’s positioning matters for these teams. The platform is not trying to recreate every hyperscaler service. It gives teams the core cloud infrastructure they need first: VMs, storage, networking, backups, snapshots, and simple scaling paths. That is often enough to turn an idea into a working environment. ## What This Means for Small Enterprise Teams If you are part of a small team inside a larger company, the cloud VM question is not only technical. It is operational. Ask yourself: * How long does it take us to get a usable server? * Are we using personal or unmanaged accounts to move faster? * Can we explain the cost of a small workload clearly? * Can we rebuild the environment if something breaks? * Do we know who owns each server? * Are backups and snapshots part of the plan? * Can this project scale if it becomes important? * Can we shut it down cleanly if it does not? If the answer to those questions is unclear, your team may not need a huge new platform. You may need a simpler infrastructure path. Start with the smallest useful setup. Launch the VM. Secure it. Document it. Add backups. Then scale only when the workload proves it deserves more. ## Why Raff Fits This Use Case Raff fits small enterprise teams because the platform is built around practical cloud infrastructure rather than enterprise cloud complexity. A team can start with a [Raff VM](/products/raff-vm), use [Linux VMs](/products/linux-vm) or [Windows VMs](/products/windows-vm) depending on the workload, compare pricing clearly on `/pricing`, and add infrastructure layers only when needed. For internal tools, staging environments, prototypes, demos, and lightweight production workloads, that is often the right model. It gives the team speed without forcing them to buy more cloud than they need. And if the project grows, Raff gives them room to move: resize resources, add storage, use snapshots, separate workloads, or connect services through private networking. ## Final Thoughts Small enterprise teams gain the most from cloud VMs because they sit in the gap between corporate process and startup-style urgency. They need infrastructure that is fast enough for real work, simple enough for lean teams, and structured enough to avoid shadow IT. Cloud VMs solve that gap well. They give teams clean environments, flexible compute, clearer costs, and a path from experiment to production without making every small project feel like a full enterprise platform rollout. For Raff, this is one of the clearest use cases: helping small teams inside larger organizations move faster while keeping infrastructure understandable, secure, and ready to grow. If your team is ready to test that model, start with a [Raff Linux VM](/products/linux-vm), compare plans on the [pricing page](/pricing), and use [Choosing the Right VM Size](/learn/guides/choosing-right-vm-size) to avoid overprovisioning from day one. --- ### What Is Ubuntu? Beginner’s Guide to Cloud Linux (2026) URL: https://rafftechnologies.com/blog/what-is-ubuntu-cloud-linux-guide Published: 2025-09-04T00:00:00.000Z Description: What Is Ubuntu? Beginner’s Guide to Cloud Linux (2026) Ubuntu is one of the most practical Linux distributions for beginners because it gives you a friendly starting point, strong documentation, a huge software ecosystem, and a clear path from learning Linux to running real cloud servers. For Raff Technologies users, Ubuntu is often the first operating system I recommend when someone wants to deploy a clean Linux VM and understand how cloud infrastructure actually works. Ubuntu is a Debian-based Linux distribution maintained by Canonical. In simple terms, it is an operating system you can install on laptops, desktops, servers, and cloud VMs. Developers use it because it is predictable, well documented, widely supported, and compatible with the tools most modern projects need. I like Ubuntu for beginner cloud work because it removes unnecessary friction. When I test server setups, Ubuntu gives me a clean baseline: `apt` works as expected, common packages are easy to install, and most tutorials for Docker, Node.js, Python, PostgreSQL, Nginx, and security hardening assume Ubuntu or another Debian-based system. ## Why Ubuntu Became So Popular Ubuntu became popular because it made Linux feel less intimidating. Before Ubuntu, many Linux distributions were powerful but harder for beginners to approach. Ubuntu helped change that by focusing on usability, predictable releases, simple installation, and a strong community. That made Linux more accessible to students, developers, businesses, and people who wanted an alternative to Windows or macOS. The name “Ubuntu” comes from an African philosophy often translated around the idea of “humanity to others.” That fits the project’s open-source direction: a system that anyone can use, study, modify, and share. For beginners, the important point is not only history. The important point is that Ubuntu became a default learning path. If you want to learn Linux commands, server administration, package management, SSH, Docker, or web hosting, Ubuntu gives you one of the clearest starting points. ## Ubuntu Desktop vs Ubuntu Server Ubuntu comes in different editions, but beginners usually need to understand two: Ubuntu Desktop and Ubuntu Server. Ubuntu Desktop is designed for personal computers. It includes a graphical interface, browser, file manager, desktop applications, and the familiar experience most people expect from a laptop or workstation operating system. Ubuntu Server is designed for servers and cloud infrastructure. It usually does not include a desktop interface. Instead, you manage it through SSH, terminal commands, configuration files, and services. For Raff users, Ubuntu Server is the important one. When you deploy a [Raff Linux VM](/products/linux-vm), you are usually creating a server environment for apps, APIs, websites, databases, self-hosted tools, automation, or learning. That distinction matters. A beginner may learn Linux on Ubuntu Desktop, but most real cloud work happens on Ubuntu Server. ## Why Developers Like Ubuntu Developers like Ubuntu because it works well with the tools they already use. A fresh Ubuntu server can quickly become a working environment for: * Node.js applications * Python backends * PHP websites * Docker containers * Nginx or Apache web servers * PostgreSQL or MySQL databases * Redis caches * Git repositories * CI/CD runners * Self-hosted apps * Monitoring tools * Automation scripts The `apt` package manager is one of Ubuntu’s biggest strengths. You can install, update, and remove software using consistent commands. That makes Ubuntu easier to document and easier to support in tutorials. For example, if you want to start with JavaScript backend development, Raff already has a tutorial for [installing Node.js on Ubuntu 24.04](/learn/tutorials/install-nodejs-ubuntu-24-04). If you want containers, start with [installing Docker on Ubuntu 24.04](/learn/tutorials/install-docker-ubuntu-24-04). Ubuntu is popular because it helps beginners move from “I want to learn Linux” to “I deployed something real.” ## Why Ubuntu Works So Well on Cloud VMs Ubuntu is one of the strongest operating systems for cloud VMs because it is lightweight enough for servers, familiar enough for beginners, and supported broadly across cloud environments. A cloud VM needs to be predictable. It should boot cleanly, accept SSH access, handle package updates, run services reliably, and support automation. Ubuntu Server fits that model well. This is why Ubuntu is common in tutorials, hosting guides, DevOps examples, and self-hosting documentation. When someone says “deploy this app on a VPS,” the example is often written for Ubuntu. On Raff, Ubuntu is useful because you can start with a clean VM, install only what the workload needs, and grow from there. You are not forced into a complex platform before you understand the basics. A good beginner path looks like this: * Deploy an Ubuntu VM * Connect over SSH * Create a non-root user * Configure firewall rules * Install the software you need * Run one application * Add backups or snapshots when the environment matters * Resize or split infrastructure later if the workload grows That path teaches real infrastructure without overwhelming the user too early. ## Why Ubuntu 24.04 LTS Is the Best Starting Point Ubuntu 24.04 LTS is the best starting point for most new cloud VM projects in 2026. LTS means Long-Term Support. That matters because beginners and production teams both need stability. You do not want your first server to depend on a short-lived release that forces upgrades before you understand the system. Ubuntu 24.04 LTS gives you a modern package base, broad compatibility, and a long support window. It is new enough for current developer tools, but stable enough to use as a serious server foundation. Use Ubuntu 24.04 LTS when you are: * Learning Linux server administration * Deploying a new web app * Setting up Docker * Running a backend API * Testing PostgreSQL, MySQL, or Redis * Building a staging environment * Creating a self-hosted tool * Writing repeatable setup instructions Ubuntu 22.04 LTS can still make sense for older workloads that were already tested on that release. But for new projects, Ubuntu 24.04 LTS is usually the cleaner default. ## Ubuntu Is Beginner-Friendly, But Still Real Infrastructure Ubuntu is beginner-friendly, but it is not a toy environment. That is important. When you learn Ubuntu on a cloud VM, you are learning real server skills: * SSH access * Users and permissions * Package management * Firewall rules * System services * Logs * Updates * Web server configuration * Process management * Storage layout * Backups and recovery Those skills transfer directly to production environments. This is why Ubuntu is valuable for students and early-career developers. You can start with simple commands, then gradually learn how real infrastructure behaves. A beginner might first learn: ```bash sudo apt update sudo apt upgrade sudo systemctl status nginx ``` Those commands may look small, but they are the foundation of real server work. They teach you how Linux updates packages, manages services, and exposes system state. That is the difference between reading about cloud and actually using it. ## The First Things to Do on a Fresh Ubuntu VM A fresh Ubuntu VM should not go straight into production. It needs a basic security baseline first. Before installing your main application, you should: * Connect with SSH * Create a non-root user * Use SSH key authentication where possible * Configure a firewall * Allow only the ports you need * Apply package updates * Enable automatic security updates if appropriate * Document what the server is for * Add backups or snapshots for important workloads This is where many beginners make the same mistake: they deploy the server, install the app, and forget the basics. The better path is to secure the server first. Raff has a dedicated tutorial for this: [Secure Your Ubuntu 24.04 Server](/learn/tutorials/secure-ubuntu-24-04-server). Read that before exposing any serious workload to the internet. A common beginner mistake is opening too many ports because something did not work on the first try. Do not do that. Open only what the workload actually needs. ## Ubuntu and Docker Ubuntu is one of the easiest Linux distributions for learning Docker. Docker lets you run applications in containers, which makes it easier to package software with its dependencies. Instead of installing every dependency directly on the system, you run the app in a container with a defined environment. For beginners, Docker can feel like another layer at first. But on Ubuntu, the learning path is well documented and practical. A typical beginner progression is: * Learn basic Ubuntu commands * Install Docker * Run your first container * Learn Docker Compose * Deploy one self-hosted app * Add a reverse proxy * Secure the service with HTTPS * Back up persistent data That progression is useful because it teaches both Linux and modern deployment patterns. If you want to follow that path on Raff, start with [Install Docker on Ubuntu 24.04](/learn/tutorials/install-docker-ubuntu-24-04). From there, you can move into real self-hosted tools like n8n, Uptime Kuma, Gitea, or Portainer. ## Ubuntu and Cloud Automation Ubuntu also works well for cloud automation because it supports cloud-init, shell scripts, package automation, and repeatable provisioning. Cloud-init is especially important. It helps configure cloud instances during first boot: users, SSH keys, packages, hostnames, scripts, and other startup tasks. That makes Ubuntu useful when you want repeatable VM setup instead of manually configuring every server. For beginners, this may sound advanced. But the concept is simple: instead of clicking and typing the same setup steps every time, you define the first-boot behavior once and reuse it. That is how teams move from manual server setup to more reliable infrastructure. If you want to understand the options, read Raff’s guide to [VM provisioning models with cloud-init, custom images, and one-click apps](/learn/guides/vm-provisioning-models-cloud-init-custom-images-one-click). ## Ubuntu Is Not Always the Right Choice Ubuntu is a strong default, but it is not always the right operating system. Choose Debian when you want a more minimal and conservative Linux base. Choose Rocky Linux or AlmaLinux when you need a RHEL-compatible environment. Choose Fedora when you want newer packages and do not need a long production support window. Choose Windows Server when your workload depends on Microsoft technologies such as IIS, Remote Desktop, Windows-only applications, or the .NET Framework. The operating system should match the workload. For most beginners learning Linux and cloud VMs, Ubuntu is the right starting point because it gives you the best mix of ease, documentation, stability, and practical server use. ## Choosing the Right Raff VM for Ubuntu Ubuntu itself is not usually the expensive part. The real decision is how much CPU, RAM, and storage your workload needs. A small learning server does not need the same resources as a production app. A Docker host does not need the same resources as a database server. A Node.js app does not behave the same way as a CI runner. For light learning, testing, and simple tools, a smaller VM may be enough. For production services, databases, CI/CD, or heavier Docker workloads, you should choose more resources and consider dedicated CPU. On Raff, General Purpose VMs start at $4.99/month for 1 vCPU, 1 GB RAM, and 25 GB NVMe SSD. CPU-Optimized VMs start at $15.99/month for the same 1 vCPU, 1 GB RAM, and 25 GB NVMe SSD with a guaranteed vCPU. If you are unsure, read [Choosing the Right VM Size](/learn/guides/choosing-right-vm-size) before deploying. You can also compare current options on the [Raff pricing page](/pricing). The safest beginner move is to start small, measure the workload, and resize when you have evidence. ## What This Means for You If you are new to Linux, Ubuntu is one of the best places to begin. It is approachable enough for beginners, useful enough for developers, and serious enough for real cloud servers. You can learn basic commands today and use the same operating system tomorrow to deploy a web app, database, Docker stack, or self-hosted tool. The practical path is simple: * Start with Ubuntu 24.04 LTS * Deploy it on a cloud VM * Secure the server * Install one useful workload * Document what you did * Rebuild or resize when you need to * Add more infrastructure only when the workload asks for it That is how you learn cloud infrastructure without getting lost. Ubuntu gives you the operating system foundation. A Raff VM gives you the cloud environment to practice and deploy on. ## Final Thoughts Ubuntu remains popular because it solves beginner and developer problems at the same time. It is easy enough to learn, stable enough to trust, and flexible enough to run real workloads. That combination is why Ubuntu continues to be one of the first Linux distributions people meet — and one of the operating systems they keep using after they become more experienced. For your next step, deploy a [Raff Linux VM](/products/linux-vm), secure it with [Ubuntu initial server setup](/learn/tutorials/secure-ubuntu-24-04-server), then install a practical workload such as [Docker on Ubuntu 24.04](/learn/tutorials/install-docker-ubuntu-24-04) or [Node.js on Ubuntu 24.04](/learn/tutorials/install-nodejs-ubuntu-24-04). Start small. Learn the server. Then build something real. --- ### Cloudflare VM in 2026: Virtual Machines, Containers & VPS URL: https://rafftechnologies.com/blog/cloudflare-vs-vps-why-developers-still-need-a-server Published: 2026-03-10T00:00:00.000Z Description: Cloudflare VM in 2026: Virtual Machines, Containers & VPS People searching for **Cloudflare VM** usually want a simple answer: can you rent a normal virtual machine from Cloudflare the way you can rent an EC2 instance, DigitalOcean Droplet, or Raff VM? The answer in 2026 is **not exactly**. Cloudflare does **not** sell a traditional general-purpose virtual machine product where you choose a fixed VM size, boot a persistent Linux or Windows operating system, SSH or RDP into it, and manage it like a conventional cloud server. But Cloudflare's compute platform has expanded significantly: **Workers** provides serverless edge compute, while **Cloudflare Containers** can now run container images with full Linux-like environments on the Workers platform. That makes the modern comparison more nuanced than “Cloudflare cannot run servers.” Cloudflare can now run much broader workloads, but its Containers product still has a different operating model from a traditional VPS or VM. ## Cloudflare VM: quick answer | Question | Answer | |---|---| | Does Cloudflare offer traditional virtual machines? | No, not as a general-purpose VM product with a fixed persistent OS instance | | Can Cloudflare run backend code? | Yes, through Workers and related developer-platform services | | Can Cloudflare run container images? | Yes. Cloudflare Containers is generally available on the Workers Paid plan | | Is Cloudflare Containers the same as a VPS? | No. Containers are orchestrated through Workers, start on demand, can scale to zero, and use usage-based resource billing | | Can you still put Cloudflare in front of a normal VPS? | Yes, and that remains a common architecture | | Is there a Cloudflare VM price? | No traditional VM price exists; Workers and Containers use their own pricing models | If you specifically want a normal VPS behind Cloudflare, see our [Cloudflare VPS Hosting guide](/blog/host-app-on-vps-with-cloudflare). This page focuses on the **Cloudflare VM question** and on when Containers or Workers can replace a conventional VM. ## Does Cloudflare have virtual machines? Cloudflare operates a huge global infrastructure fleet internally, but that is different from exposing a public general-purpose VM service to customers. A conventional cloud VM normally gives you: - a persistent guest operating system; - root or administrator access; - a fixed CPU/RAM/storage shape; - long-running background services; - your own package manager and system services; - predictable server lifecycle under your control; - SSH for Linux or RDP for Windows; - attached or local storage options; - arbitrary software stacks. Cloudflare's public compute platform is designed differently. **Workers** runs application code without provisioning servers. **Cloudflare Containers** extends that model by allowing applications packaged as container images to run with more CPU, memory, disk, filesystems, runtimes, and Linux-oriented tooling than Workers alone. So the accurate 2026 answer is: > Cloudflare offers serverless compute and serverless containers, but not a traditional customer-managed VM product. ## Cloudflare Containers changed the old “Cloudflare vs VPS” answer Older comparisons often said Cloudflare could not run Docker containers or full Linux environments. That is now outdated. Cloudflare Containers became generally available in April 2026. Cloudflare documents support for workloads including: - applications packaged as container images; - resource-intensive applications; - software that needs a full filesystem; - applications that require a specific runtime; - CLI tools and broader Linux-like environments; - images from Docker Hub and supported registries. Cloudflare also supports SSH access for debugging live containers. That means some workloads that previously required a VPS can now run on Cloudflare's platform without a traditional VM. However, Containers are still **not simply “Cloudflare VMs.”** They are part of the Workers platform and are controlled by Worker code. Container instances start when needed and can go to sleep after inactivity. That usage-driven lifecycle is different from paying for a VM that stays allocated until you shut it down. ## Cloudflare Containers vs VM | Area | Cloudflare Containers | Traditional VM / VPS | |---|---|---| | Deployment unit | Container image + Worker integration | Full virtual machine | | Operating model | Serverless / orchestrated | Customer-managed server | | OS control | Linux-like container environment | Full guest OS control | | Windows Server | No traditional Windows VM product | Available from Windows VM providers | | Lifecycle | Can start on demand and scale to zero | Usually remains running until stopped | | Billing | Resource usage | Commonly hourly or monthly VM allocation | | SSH | Supported for live container debugging | Standard administration path on Linux | | systemd / full machine management | Not a normal VM model | Yes | | Fixed public VM IP | Not the conventional model | Common | | Docker image support | Yes | Yes, if you install Docker | | Multiple arbitrary system services | Possible only within platform constraints | Normal VM use case | | Best fit | Containerized, elastic application workloads | Full infrastructure control and persistent server workloads | The question is therefore not “can Cloudflare run Docker?” anymore. It can. The better question is: **does your workload fit Cloudflare's container lifecycle and platform model, or do you need a conventional server that you control directly?** ## Cloudflare VM pricing: what do you actually pay? There is no traditional **Cloudflare VM pricing** table because Cloudflare does not sell fixed general-purpose VM instances. Cloudflare Containers is available on the **Workers Paid plan**. As of August 2026, Cloudflare lists a $5/month Workers Paid plan with included monthly container resources: - 25 GiB-hours of memory; - 375 vCPU-minutes; - 200 GB-hours of disk. Above the included usage, Cloudflare currently bills Containers at usage-based rates for memory, active CPU, and provisioned disk. Cloudflare's published additional rates are: | Resource | Additional rate | |---|---:| | Memory | $0.0000025 per GiB-second | | CPU | $0.000020 per vCPU-second | | Disk | $0.00000007 per GB-second | Cloudflare says container charges begin when an instance receives a request or is manually started and stop after the instance goes to sleep. CPU is billed on active usage rather than simply on provisioned wall-clock time. That can be attractive for bursty applications. A traditional VM can be easier to predict when the workload is continuously running and you want one fixed monthly infrastructure bill. Always check Cloudflare's current Containers pricing page before budgeting because platform pricing and included allowances can change. ## Workers vs VM Cloudflare Workers is an even more abstracted compute model than Containers. Workers is a strong fit when you want: - API endpoints; - request/response logic; - authentication middleware; - lightweight backend logic; - edge personalization; - routing and transformations; - integrations with Cloudflare storage and developer services; - globally distributed execution without managing servers. A traditional VM is better when the application needs: - direct operating-system administration; - conventional daemon management; - custom kernel-level behavior; - a Windows Server environment; - software that expects a persistent machine; - arbitrary networking and long-lived infrastructure services; - a traditional database server you manage directly; - server software whose vendor explicitly expects a VM or dedicated host. Cloudflare Containers fills some of the space between these two models. ## Cloudflare Containers vs VPS A VPS gives you a virtual server. Cloudflare Containers gives you a managed container execution platform. Choose **Cloudflare Containers** when: - your application is already containerized; - you want instances to scale up and down automatically; - you do not want to patch and maintain a guest operating system; - usage is bursty enough that scale-to-zero economics are useful; - your architecture already uses Workers or other Cloudflare services; - the application fits Cloudflare's current container limits and lifecycle. Choose a **VPS or VM** when: - you need persistent machine-level control; - you need Linux system administration as part of the workload; - you need Windows Server; - you run several tightly coupled services on one machine; - you need direct access to system packages, networking, firewalling, or service management; - a vendor application assumes a conventional server; - you want one always-on server with fixed resources and straightforward monthly pricing. Neither model is universally better. They solve different infrastructure problems. ## When Cloudflare can replace a VM Cloudflare can replace a traditional VM when the application maps cleanly to the platform. Examples include: - stateless APIs built for Workers; - edge middleware; - frontend applications; - event-driven services; - containerized web applications that can scale to zero; - agent or sandbox workloads designed for Cloudflare's runtime; - workloads that rely heavily on Cloudflare's distributed edge and storage services. In those cases, avoiding a VM can reduce server maintenance. ## When you still need a VM A conventional VM remains the simpler fit for many workloads. Examples include: - Windows Server and RDP workloads; - IIS-hosted applications that require Windows; - self-managed PostgreSQL, MySQL, MongoDB, or SQL Server; - Docker Compose stacks with several persistent services; - VPN servers; - control panels; - legacy business applications; - monitoring systems that expect machine-level access; - long-running worker processes with conventional system-service management; - software that requires root-level host configuration. A VM is also easier when your team already operates Linux servers and does not need serverless orchestration. ## Cloudflare + VM remains a strong architecture Using Cloudflare does not require replacing your server. A common production design remains: ```text Users ↓ Cloudflare DNS / Proxy / CDN / WAF / TLS ↓ Linux or Windows VM ↓ Reverse proxy / application ↓ Database and internal services ``` Cloudflare handles the public edge while the VM handles the application environment. This is useful when you want Cloudflare's DNS, CDN, DDoS protection, TLS, caching, and security features but still need a conventional operating system. For the detailed architecture and setup path, read [Cloudflare VPS Hosting: What It Is, Pricing & How It Works](/blog/host-app-on-vps-with-cloudflare). ## Do you need both Cloudflare and a VPS? Often, yes. Cloudflare and a VPS are not direct substitutes when the workload needs a real server. The VPS or VM can provide: - Linux or Windows; - CPU and RAM reserved for your server; - Docker; - Nginx or Caddy; - application processes; - databases; - scheduled jobs; - private networking; - full filesystem and OS control. Cloudflare can provide the public-facing layer: - DNS; - reverse proxying; - CDN; - TLS; - DDoS protection; - WAF and security controls; - caching; - edge logic. This layered model is especially practical for SaaS applications, APIs, dashboards, WordPress, business software, and self-hosted developer tools. ## Cloudflare VM vs Raff VM Raff and Cloudflare are not equivalent products in this comparison. Cloudflare is primarily providing edge and serverless platform services. Raff VMs are conventional cloud virtual machines. A Raff VM is a better fit when you need: - full Linux root access or Windows Server administrator access; - a persistent VM; - Docker or Docker Compose under your control; - system packages and long-running services; - self-managed databases; - a predictable VM resource shape; - direct server-level networking and firewall management. Cloudflare can still sit in front of that Raff VM. This means the choice does not have to be **Cloudflare or Raff**. For many workloads, the architecture is **Cloudflare + Raff VM**. ## Cloudflare VM FAQs ### Does Cloudflare offer virtual machines? Cloudflare does not offer a traditional general-purpose VM product comparable to EC2, Droplets, or a standard VPS. It offers Workers and Cloudflare Containers, which provide different serverless compute models. ### Does Cloudflare have a VPS? Cloudflare does not sell a conventional VPS with a persistent guest operating system and root access. You can use Cloudflare in front of a VPS from another provider. ### Can Cloudflare run Docker containers? Yes. Cloudflare Containers can deploy container images and is generally available on the Workers Paid plan. This is different from renting a traditional VM and installing Docker yourself. ### How much does a Cloudflare VM cost? There is no Cloudflare VM price because Cloudflare does not sell fixed general-purpose VM instances. Containers and Workers use platform-specific pricing instead. ### Is Cloudflare Containers cheaper than a VPS? It depends on utilization. Containers can scale to zero and bill active resources, which can be efficient for bursty workloads. An always-on VPS can be simpler and more predictable for continuously running services. ### Can Cloudflare replace AWS EC2? Cloudflare Workers and Containers can replace EC2 for some application architectures, but they are not drop-in EC2 equivalents. Workloads requiring full VM control, Windows Server, or conventional host administration still need a VM or another infrastructure model. ### Can I use Cloudflare with a virtual machine? Yes. Point your DNS to the VM, proxy supported web traffic through Cloudflare, configure TLS correctly, and keep the VM responsible for the application and operating-system layer. ## Conclusion The old idea that “Cloudflare cannot run containers, so you always need a VPS” is no longer accurate in 2026. Cloudflare now offers Workers and generally available Containers that can run much broader application workloads without a traditional VM. But Cloudflare still does not sell a conventional general-purpose virtual machine with the same lifecycle and administration model as EC2, a Droplet, or a Raff VM. Choose Cloudflare-native compute when the application fits its serverless model. Choose a VPS or VM when you need persistent server control, Windows Server, traditional system administration, or software that expects a normal machine. And for many production applications, use both: **Cloudflare at the edge and a VM as the origin**. ## Sources - Cloudflare Developers — [Cloudflare Containers](https://developers.cloudflare.com/containers/) - Cloudflare Developers — [Cloudflare Containers pricing](https://developers.cloudflare.com/containers/pricing/) - Cloudflare Changelog — [Containers and Sandboxes are generally available](https://developers.cloudflare.com/changelog/post/2026-04-13-containers-sandbox-ga/) - Cloudflare — [Plans and pricing](https://www.cloudflare.com/plans/) - Sources verified: 2026-08-28 --- ### Cloudflare VPS Hosting: What It Is, Pricing & How It Works URL: https://rafftechnologies.com/blog/host-app-on-vps-with-cloudflare Published: 2026-03-11T00:00:00.000Z Description: Cloudflare VPS Hosting: What It Is, Pricing & How It Works People searching for **Cloudflare VPS** are usually asking one of two questions: does Cloudflare sell a traditional VPS, or how do you combine Cloudflare with a VPS you already run? The short answer is: **Cloudflare does not provide a traditional virtual private server product with root access, a persistent operating system, arbitrary daemons, and a fixed VM shape.** Cloudflare provides edge networking, security, CDN, DNS, Workers, Pages, and other developer-platform services. If your application needs a normal Linux or Windows server, you still use a VPS or cloud VM from a compute provider and place Cloudflare in front of it. A typical Cloudflare + VPS architecture looks like this: ```text Users ↓ Cloudflare DNS / Proxy / TLS / CDN / Security ↓ VPS public IP ↓ Nginx or Caddy ↓ Application on a private local port ``` That combination is what people often mean by **Cloudflare VPS hosting**. ## Cloudflare VPS: quick answer | Question | Answer | |---|---| | Does Cloudflare sell a traditional VPS? | No, not in the conventional VM-with-root-access sense | | Can Cloudflare host applications? | Yes, through products such as Workers and Pages, but those are not traditional VPS instances | | Can you use Cloudflare with any VPS? | Usually yes, if you control DNS and the application is reachable over supported web protocols | | Does Cloudflare replace Nginx or your app server? | No; your VPS still runs the operating system, runtime, database clients, workers, and reverse proxy | | Is there “Cloudflare VPS pricing”? | There is no single Cloudflare VPS plan; your cost is your VPS plus whichever Cloudflare plan/products you use | | Best fit | A VPS for compute + Cloudflare for the public edge | If you already know you want to configure the stack, use our dedicated [step-by-step Cloudflare + VPS tutorial](/learn/tutorials/host-app-on-vps-with-cloudflare). This page focuses on the **architecture, pricing model, and buying decision** so the two pages do not compete for the same intent. ## Does Cloudflare offer VPS hosting? Not as a traditional VPS provider. A normal VPS gives you a persistent virtual machine with features such as: - root or administrator access; - a full Linux or Windows operating system; - long-running processes; - custom packages; - Docker and container runtimes; - background workers; - databases; - arbitrary TCP services; - persistent local or attached storage. Cloudflare's developer platform can run application code and host sites, but its operating model is different from renting a conventional VM. That distinction is important because a developer who needs to install PostgreSQL, run Docker Compose, host a custom daemon, use systemd, or maintain a long-running application process is usually looking for a VPS rather than an edge runtime. ## What does “Cloudflare VPS hosting” actually mean? In practice, **Cloudflare VPS hosting** means using Cloudflare as the public-facing layer in front of a virtual server hosted somewhere else. The VPS owns the compute layer: - application runtime; - Nginx or Caddy; - containers; - background jobs; - local services; - database connections; - operating-system configuration. Cloudflare owns the edge layer: - authoritative DNS; - proxied web traffic; - TLS at the edge; - CDN and caching; - DDoS mitigation; - WAF and security controls, depending on plan; - rate limiting and other edge features, depending on configuration. This separation is useful because you can keep full server control while using Cloudflare's network for the public entry point. ## Cloudflare VPS pricing: what do you actually pay? There is no single **Cloudflare VPS price** because Cloudflare is not selling the VM in this architecture. Your monthly cost has two layers: ```text Total monthly cost = VPS / cloud VM cost + Cloudflare plan and optional product costs ``` Cloudflare has a Free plan for many core website features, while paid plans and usage-based developer products add their own pricing dimensions. Your VPS is billed by the infrastructure provider separately. For example, a small application might use: - one Linux VPS; - Cloudflare Free for DNS/proxy/TLS; - Nginx on the VPS; - no paid Cloudflare add-ons. A larger application could add paid WAF features, Workers usage, R2, load balancing, or other Cloudflare services. The important comparison is therefore not “Cloudflare VPS vs another VPS provider.” It is usually **“which VPS should I put behind Cloudflare, and what Cloudflare services do I actually need?”** ## Why use Cloudflare with a VPS? ### 1. Keep the origin architecture simple Your application can remain on a normal Linux VM while Cloudflare handles the public DNS and proxy layer. That is attractive for small teams because you do not need to redesign the application around an edge runtime just to gain CDN, TLS, and DDoS-protection benefits. ### 2. Hide the origin IP from normal proxied DNS responses When an A, AAAA, or CNAME web record is proxied, users normally resolve Cloudflare addresses rather than the origin address. This does not magically make the origin impossible to discover. Old DNS records, direct services, email records, certificates, application leaks, and other configuration can still reveal it. Treat origin protection as a firewall and architecture problem, not only a DNS setting. ### 3. Add a global edge in front of one VPS region A VPS may run in one datacenter while Cloudflare operates a distributed edge network. Static/cacheable content can benefit from edge delivery even though dynamic requests still return to the origin server when they are not served from cache. ### 4. Separate public traffic from application ports A clean architecture exposes only the reverse proxy publicly: | Port | Service | Public? | |---:|---|---| | 22 | SSH | Restrict where possible | | 80 | HTTP / redirect | Yes | | 443 | HTTPS | Yes | | 3000 | Node.js app | No | | 5432 | PostgreSQL | No | | 3306 | MySQL | No | The app can listen on `127.0.0.1:3000`, while Nginx receives public traffic on 80/443. ## Cloudflare + VPS vs Cloudflare Workers A common source of confusion is whether Workers removes the need for a VPS. Sometimes it does. Sometimes it does not. Choose a Cloudflare-native runtime when your application fits that execution model and you want to avoid operating a full server. Choose a VPS when you need things such as: - a persistent operating system; - custom system packages; - Docker Compose; - long-running worker processes; - custom network services; - self-hosted databases; - filesystem-level control; - software that expects a conventional server environment. Many production systems use both: Workers or other edge logic for selected functions, plus a VPS or cloud VM for the main application and stateful services. ## Cloudflare + VPS vs Cloudflare Pages Cloudflare Pages is well suited to frontend and static-site workflows, with server-side capabilities available through the broader Cloudflare developer platform. A VPS is a better fit when the deployment requires full OS control or when the application stack does not map naturally to a managed edge platform. If all you are hosting is a static frontend, a VPS may be unnecessary. If you need a normal server, Cloudflare Pages is not a drop-in replacement for one. ## What VPS should you use with Cloudflare? Cloudflare itself does not require a special “Cloudflare VPS.” The server should be chosen around the workload. For a small API, dashboard, SaaS MVP, or Node.js application, look at: - enough RAM for the runtime and peaks; - sufficient CPU for normal and burst load; - fast storage; - predictable bandwidth policy; - backups and snapshots; - firewall controls; - a region close to the application's users or data dependencies; - an upgrade path as the workload grows. A simple starting point for many small applications is 2 vCPU with 2–4 GB RAM, but application requirements should drive the final size. On Raff, Linux VMs provide full root access, NVMe storage, firewall controls, private networking, backups/snapshots, and unmetered VM bandwidth. You can use a Raff VM as the origin while Cloudflare remains the public edge. ## A recommended Cloudflare VPS architecture For a single-server application, keep the first version straightforward: ```text Internet ↓ Cloudflare proxied DNS ↓ HTTPS Nginx / Caddy on VPS ↓ Application on localhost ↓ Database or external managed database ``` The responsibilities should be clear. **Cloudflare:** - DNS - proxying - edge TLS - caching where appropriate - security rules **VPS:** - operating system - application runtime - reverse proxy - process management - application logs - local firewall - backups for server-side state Do not expose every backend service just because Cloudflare is in front of the website. ## Full (strict) TLS is the production default For a normal VPS origin, the preferred request path is: ```text Browser → HTTPS → Cloudflare → HTTPS → VPS ``` Cloudflare's **Full (strict)** mode validates the certificate presented by the origin. The VPS can use a publicly trusted certificate such as Let's Encrypt or an appropriate Cloudflare Origin CA certificate when traffic is designed to remain behind Cloudflare. Avoid treating Flexible SSL as the standard production configuration. It can leave the Cloudflare-to-origin connection on HTTP and can create redirect problems when the origin is also trying to enforce HTTPS. ## Should you restrict ports 80 and 443 to Cloudflare IPs? This can reduce direct access to the origin, but it must be implemented carefully. If you restrict web traffic to Cloudflare's published IP ranges: - maintain the allowlist when Cloudflare updates it; - keep your certificate-renewal method in mind; - have an emergency access path; - test health checks and monitoring; - do not accidentally lock yourself out of required origin traffic. For many small deployments, start with a correct app binding, firewall, HTTPS, SSH restrictions, and proxied DNS. Add Cloudflare-only origin filtering when the operational process is ready to maintain it. ## Can Cloudflare protect a VPS from DDoS attacks? Cloudflare can protect **proxied supported web traffic** before it reaches the VPS. That is one of the major reasons to put Cloudflare in front of a public website or API. But Cloudflare cannot protect a service that bypasses the proxy simply because the domain also uses Cloudflare. Examples of origin exposure include: - public SSH; - a database port exposed to the internet; - a game server or other unsupported protocol connected directly to the origin; - users connecting directly to the VPS IP; - unproxied DNS records. Secure those services at the VPS and network layer. ## Does Cloudflare make VPS bandwidth free? No. Cloudflare may serve cached responses from its edge, which can reduce traffic reaching your origin. But dynamic and uncached traffic can still reach the VPS, and your VPS provider's bandwidth policy still applies. If your VM provider meters egress, model that separately. Raff's current VM plans use unmetered VM bandwidth, which can simplify cost forecasting for an origin behind Cloudflare. ## When Cloudflare + VPS is a good fit This architecture is especially useful for: - SaaS MVPs; - APIs; - dashboards; - customer portals; - WordPress or PHP applications; - Node.js, Python, Go, Java, and .NET applications; - Docker Compose deployments; - self-hosted developer tools; - small business websites with backend services; - MSP-managed customer applications. It works well when the team wants normal server control without giving up Cloudflare's DNS and edge capabilities. ## When you may not need a VPS A VPS is unnecessary if the application fits completely inside a managed hosting or edge platform and you do not need server-level control. Examples include: - a static marketing site; - a simple frontend deployed to a managed platform; - an edge-native application built entirely around Workers-compatible services; - a small site where server administration would add more work than value. Do not buy a VPS only because the term appears in a tutorial. Use it when the workload actually needs a server. ## Cloudflare VPS setup: high-level checklist If you decide to combine the two, the deployment sequence is: 1. Create the VPS and secure SSH. 2. Install the application runtime. 3. Bind the application to localhost/private networking. 4. Install Nginx or Caddy as the reverse proxy. 5. Point Cloudflare DNS to the VPS public IP. 6. Enable proxying on public web records. 7. Install an origin certificate. 8. Set Cloudflare SSL/TLS to Full (strict). 9. Keep database and application-runtime ports private. 10. Test HTTPS, reboot behavior, backups, logs, and rollback. For every command and verification step, continue with [Host Your App on a VPS with Cloudflare: Step-by-Step Tutorial](/learn/tutorials/host-app-on-vps-with-cloudflare). ## Cloudflare VPS FAQs ### Does Cloudflare have a VPS? Cloudflare does not offer a traditional general-purpose VPS with a persistent operating system and root access. Its developer platform provides application-hosting and edge-computing services with a different operating model. ### What is Cloudflare VPS hosting? The phrase usually describes a VPS from a compute provider placed behind Cloudflare DNS, proxying, TLS, CDN, and security services. ### How much does Cloudflare VPS cost? There is no single Cloudflare VPS price. You pay your VPS provider for compute and separately pay Cloudflare if you use a paid plan or usage-based Cloudflare products. Many small setups can start with a VPS plus Cloudflare's Free plan. ### Can I connect Cloudflare to a VPS? Yes. Point the relevant DNS record to the VPS, enable Cloudflare proxying for supported web traffic, configure HTTPS on the origin, and use Full (strict) TLS for production. ### Can Cloudflare replace a VPS? Cloudflare can replace a VPS for some edge-native or managed-hosting use cases. It does not replace a conventional server when you need full OS control, Docker, arbitrary packages, persistent system services, or other traditional VM capabilities. ### Is Cloudflare good for VPS hosting? Cloudflare and VPS hosting complement each other well. The VPS runs the application while Cloudflare handles the public edge. The combination is especially useful for teams that want full server control plus DNS, CDN, TLS, and edge security. ## Conclusion **Cloudflare VPS** is best understood as an architecture, not a Cloudflare VM product. Cloudflare handles the public edge. A VPS provider supplies the actual server. Together they create a simple pattern for developers who need full compute control while still benefiting from Cloudflare's DNS, proxy, TLS, caching, and security features. If your workload needs a traditional server, choose the VPS based on CPU, RAM, storage, bandwidth, backups, support, and region. Then place Cloudflare in front of it. If you want to build the configuration now, follow the [Cloudflare + VPS step-by-step tutorial](/learn/tutorials/host-app-on-vps-with-cloudflare). If you are deciding whether you need a server at all, read [Cloudflare vs VPS: When Your App Needs a Server](/blog/cloudflare-vs-vps-why-developers-still-need-a-server). For a Raff origin server, see [Raff Cloud VMs](/products/raff-vm) and [current VM pricing](/pricing). --- ### The Real Cost of Running n8n in the Cloud vs SaaS (2026) URL: https://rafftechnologies.com/blog/real-cost-n8n-cloud-vs-saas Published: 2026-03-29T00:00:00.000Z Description: The Real Cost of Running n8n in the Cloud vs SaaS (2026) ## The Cheapest n8n Option on Day One Is Not Always the Cheapest in Month Three If you are evaluating n8n in 2026, the real pricing question is not just “What does n8n cost?” It is “Which cost model gets more expensive as my workflows become important?” n8n is a workflow automation platform that lets you connect apps, APIs, databases, webhooks, and AI tools through visual, node-based workflows. You can use n8n as a hosted service, or you can run it yourself on infrastructure you control. That sounds like a simple convenience-versus-control decision. In practice, it is a cost-model decision. That is exactly why this topic matters to us at Raff. We built a dedicated n8n VM offer because some teams want the freedom of self-hosting without turning deployment into a side project. Once automation becomes part of operations, the conversation changes. The question stops being “Can we automate this?” and becomes “What happens to our cost, control, and risk when this workflow starts running all day?” That is the lens I want to use here. In this post, “cloud” means running self-hosted n8n on your own cloud VM. “SaaS” means using n8n’s hosted plans. Both can work. But they behave very differently once your automations stop being experiments and start becoming part of how your team operates. ## The First Mistake Is Comparing Only the Subscription Price Most people start with the obvious numbers. On n8n’s current pricing page, the hosted Starter plan is listed at 20€ per month billed annually and includes 2.5K workflow executions. The hosted Pro plan is listed at 50€ per month billed annually. n8n also makes it clear that its pricing is based on monthly workflow executions, not per-step billing. That is more understandable than many automation tools, but it is still only one layer of cost. If you self-host n8n, the software itself can be free to run in Community Edition. Your cost moves away from an execution-based subscription and into infrastructure: the VM, storage, backups, updates, SSL, monitoring, and the time required to keep the instance healthy. That is why “self-hosted is free” is not a serious cost answer. It removes one pricing model and replaces it with another. ## What You Are Really Paying For in Each Model The cleanest way to think about the decision is this: * SaaS pricing charges you for managed convenience and platform ownership. * Self-hosted cloud pricing charges you for infrastructure and operational responsibility. That sounds obvious, but it changes how you should evaluate cost. With SaaS, you are paying to avoid infrastructure work. You do not provision a server. You do not handle patching the host. You do not deal with reverse proxies, TLS termination, backup jobs, or resource sizing on day one. You get a smoother start, which has real value. With self-hosting, you are paying for a machine, not a usage meter. That changes the economics quickly once workflow count, data volume, webhook traffic, or internal integrations grow. It also changes the control boundary. The workflows run on infrastructure you choose, with networking, storage, access, and recovery options you define. The right question is not “Which one is cheaper?” The right question is “Which cost model fits the way my automations will behave over the next 6 to 12 months?” ## Where SaaS Usually Wins SaaS is often the right answer earlier than self-hosting advocates like to admit. If you are still validating whether n8n is useful for your team, the hosted option can be the smarter financial choice even if the long-term unit economics are worse. That is because it removes the operational delay between interest and value. You do not need to think about server sizing. You do not need to think about backups on day one. You do not need to explain to a teammate why automation broke because the VM ran out of memory or because an update was skipped. For a solo operator, non-technical team, or early proof of concept, that convenience matters. It is not fake value. It is real time saved. SaaS is especially attractive when: * your workflow volume is still low * your integrations are mostly external SaaS apps * you do not need special networking or internal database access * speed to first automation matters more than infrastructure ownership * your team does not want to operate another service yet In those situations, the subscription is buying focus. ## Where Self-Hosted Cloud Starts to Win The economics change when automation becomes operational rather than experimental. This is the inflection point that matters. Once workflows become part of lead handling, support routing, reporting, internal ops, engineering notifications, AI enrichment, or backend orchestration, execution volume usually stops being neat and predictable. Usage grows unevenly. Teams add more triggers. Someone connects a database. Someone adds retries. Someone builds a second workflow that depends on the first one. Suddenly the automation layer is no longer a side tool. That is where running n8n on your own cloud VM starts making more sense. On Raff’s n8n product page, the positioning is explicit: your n8n instance is self-hosted, under your control, with no execution limits added by the platform. Raff also highlights 400+ integrations, custom node support, and full data ownership. That is a materially different operating model from paying for hosted workflow execution under a plan threshold. The other part of the equation is price discipline. Raff’s n8n page currently shows snapshots and backups at $0.06 per GB per month, with the first three backups per VM included free. For teams that are already technical, that is often easier to reason about than a subscription tied to execution thresholds. That does not mean it is always cheaper in total. It means the bill behaves differently. ## The Real Cost of Self-Hosting Is Not the VM. It Is Ownership This is where people get sloppy. If you only compare a SaaS fee to a VM fee, the self-hosted side can look like an automatic win. That is incomplete. The real self-hosting cost includes: * provisioning and initial setup * software updates * backup policy * SSL and domain setup * monitoring and alerting * recovery planning * whoever gets called when something breaks If nobody on your team can own those things comfortably, a cheap VM is not actually cheap. It is deferred operational work. That is why the self-hosted decision is strongest for technical teams, agencies, startups with a builder mindset, and operators who already run adjacent infrastructure. If your team already lives comfortably with Linux VMs, reverse proxies, containers, and backup routines, the marginal cost of running n8n is much lower. If you do not, the hidden cost is not money first. It is interruption. So the honest framing is this: self-hosted n8n is often cheaper on infrastructure, but only cheaper in total if your team can absorb the ownership model without creating drag. ## A More Useful Cost Comparison Here is the practical version of the decision. | Scenario | Hosted n8n SaaS | Self-Hosted n8n on a Cloud VM | |---|---|---| | Early proof of concept | Usually better | Usually unnecessary | | Low workflow volume, non-technical owner | Better fit | Adds avoidable ops work | | Internal tools with database/API access | Limited by hosted model assumptions | Usually stronger fit | | Growing execution volume | Subscription pressure increases | Infrastructure cost stays easier to model | | Sensitive data or internal systems | Less control | More control | | Teams already comfortable with VMs | Convenience still nice | Often better long-term economics | | Custom nodes or deeper environment control | Limited | Stronger fit | That is the real cost table, even more than the sticker prices. A team running five light workflows may rationally prefer the hosted option because the avoided setup time is worth more than the savings. A team running always-on internal automations tied to APIs, queues, databases, and business operations may prefer a VM-based model because the infrastructure cost is steadier while workflow volume grows. ## Why This Matters More in 2026 Automation in 2026 is not just “if this, then that.” Teams are using n8n for AI-assisted workflows, webhook processing, lead qualification, content operations, support handoffs, internal notifications, data sync, and backend task chaining. That means more automations are becoming high-frequency, business-critical, and harder to move once they are embedded into daily operations. When that happens, the pricing model matters more than it did during experimentation. n8n’s current pricing already reflects this reality. The company emphasizes that it charges for full workflow executions, not individual steps. That makes the product more predictable than many step-based automation tools. But predictability at the platform level is still different from predictability at the infrastructure level. A subscription threshold asks, “How much did you run?” A VM model asks, “How much environment do you need?” Those are not the same question. For technical teams, the second question often becomes easier to manage over time. ## Where Raff Fits in This Decision Raff is not trying to turn this into an ideological argument about self-hosting. The real goal is to make the self-hosted option practical enough that you can choose it when it genuinely fits. That is why the n8n product exists as a dedicated offer instead of forcing customers to assemble every piece from scratch. The platform is designed around the idea that some teams want the control of self-hosting without turning setup into a side project. Fast provisioning, NVMe storage, AMD EPYC infrastructure, predictable VM pricing, and low-friction backup options all matter more when the service you are running becomes part of your daily operations. The business pattern behind this is simple. Teams usually do not move toward self-hosting because they love infrastructure. They move because they want fewer pricing surprises, more control over data, cleaner integration with internal systems, or a deployment model that still makes sense once automation becomes central to the business. That is the actual decision. ## What I Would Recommend If you are deciding today, I would use this framework. Choose hosted n8n SaaS if: * you want the fastest possible start * your workflow count is still modest * you do not want infrastructure ownership yet * your automations live mostly in external SaaS tools Choose self-hosted n8n on a cloud VM if: * your workflows are becoming operationally important * you need database, webhook, or internal service access on your terms * you want more stable long-term economics than execution-based pricing * your team is already comfortable operating cloud infrastructure And if you are in the middle, do not force a philosophical decision too early. Start with the model that reduces friction now, but choose a platform path that does not trap you when usage grows. That is why I think the best n8n cost conversation is not about “free vs paid.” It is about which ownership model matches the stage your team is actually in. ## What This Means for You If you are evaluating n8n today, do not stop at the subscription page. Map your likely workflow behavior over the next six months. Estimate how often triggers will fire, whether those automations will touch internal systems, and whether your team wants to own the environment or outsource it. Then compare that to infrastructure cost, not just software cost. If you want a practical path to the self-hosted side, start with Raff’s [n8n VM product](/products/n8n-vm) and compare it against the broader [pricing page](/pricing). Those two pages tell you the most important part of the story: how the ownership model changes once your automations stop being experiments and start becoming infrastructure. From where I sit, that is the real pricing conversation. Not whether n8n can automate your work. Whether the cost model still makes sense when the automation starts working. --- ### Getting Started with Raff: Launch Your First VM in 5 Minutes URL: https://rafftechnologies.com/blog/getting-started-with-raff-launch-your-first-vm-in-5-minutes Published: 2025-05-07T00:00:00.000Z Description: Getting Started with Raff: Launch Your First VM in 5 Minutes Cloud infrastructure only feels complicated when the first step is heavier than it needs to be. That is something we think about a lot at Raff. Most people starting with cloud do not need a lecture on distributed systems before they can launch a server. They need a clear way to go from “I need a machine for this project” to “my VM is live and ready” without losing an afternoon to setup friction. That is exactly why we made this process simple. On Raff, you can launch a VM quickly, choose an operating system you already know, and start working without being forced into a giant platform learning curve. If you are new to cloud servers, this is the place to start. ## Why your first VM should feel simple A virtual machine is a software-defined server that gives you dedicated resources and a clean operating system environment in the cloud. For a developer, student, founder, or small team, that means you can work on a project without depending entirely on your local machine. Your first VM does not need to be perfect. It needs to be useful. In practical terms, a first VM usually helps you do one of these things: * create a clean development environment * test a web app outside your laptop * host a small service or internal tool * learn Linux and server basics in a real environment * run workloads that feel too heavy or messy on your personal computer That is the right mindset for getting started. You are not building the final architecture for a billion-request platform. You are creating a reliable place to work, test, and learn. ## Why we built this experience the way we did When small teams first move into cloud infrastructure, they usually make one of two mistakes. The first mistake is overthinking everything. They try to solve scale, security, cost optimization, automation, staging, and production architecture all at once before they even launch one machine. The second mistake is underestimating how valuable a clean environment can be. They keep piling tools, dependencies, containers, and test data onto a local machine until everything starts to feel slower, harder to reproduce, and more fragile than it should. We built Raff to sit in the healthy middle. Start quickly, keep control, and add complexity only when your work actually needs it. That is why the first-VM experience matters. It sets the tone for how a team will use infrastructure going forward. If the first launch is easy to understand, teams make better decisions later about resizing, backups, snapshots, and production readiness. ## Step one is knowing what you actually need Before you launch anything, ask one simple question: What is this VM for? That single question makes the rest of the process easier. If you are building or learning, a lightweight Linux VM is usually the right place to begin. If you need a stable environment for web development, automation, scripting, or general backend work, Linux gives you the most flexibility. Raff publicly supports multiple Linux distributions including Ubuntu, Debian, Fedora, CentOS Stream, AlmaLinux, Rocky Linux, Alpine, OpenSUSE, and FreeBSD, with Linux VMs positioned as deployable in under 60 seconds. If you rely on Windows-specific software, .NET workflows, or graphical tools tied to the Windows ecosystem, then a Windows VM can make more sense. Raff’s FAQ also confirms support for both major Linux distributions and Windows Server. For most first-time users, though, Linux is the better start because it is lighter, widely documented, and fits the majority of modern development and hosting workflows. ## What launching your first VM looks like The process should feel straightforward. You sign up, choose the kind of VM you want, pick an operating system, decide on a size, name the machine, and launch it. That is the mental model. Everything else is refinement. The mistake some providers make is turning this into a giant configuration exercise. Too many optional decisions too early can make a simple task feel like infrastructure architecture. For a first VM, that is unnecessary friction. The better experience is this: ### 1. Start with the workload, not the specs Do not start by staring at CPU and RAM tables with no context. Start with the job you want the machine to do. If your goal is terminal-based development, lightweight app hosting, or learning Linux, you do not need to begin with an oversized machine. If your goal is heavier testing, multiple services, or staging a more demanding application, you can step up to a larger configuration. The good news is that you are not locked in forever. Raff’s FAQ states that you can resize your VM later, which is exactly how smaller teams should think about infrastructure: start with a sane baseline, then adjust once the workload becomes real. ### 2. Choose an operating system you already understand The fastest setup is usually the one that matches your current comfort zone. If you already use Ubuntu locally, pick Ubuntu. If your team prefers Debian, choose Debian. If you have a specific distro requirement for a project, use that as your starting point. The goal is not to prove you can run a more obscure operating system. The goal is to get productive quickly. Raff’s Linux VM product page highlights Ubuntu, Debian, Fedora, Rocky Linux, AlmaLinux, Alpine, OpenSUSE, and FreeBSD among the supported choices, which gives you plenty of room to match the VM to your workflow instead of forcing your workflow to match the VM. ### 3. Name the machine like it will matter later This sounds small, but it saves confusion. A VM named `test` is forgettable. A VM named `portfolio-site-ubuntu`, `django-staging`, or `ml-lab-01` is far easier to manage later when you have more than one machine. Naming becomes even more important once you start taking snapshots, adding backups, or creating separate development and staging systems. ### 4. Launch and verify the basics immediately Your first few minutes after launch matter. Once the VM is provisioned, check the essentials right away: * confirm the machine is running * confirm you can access it * confirm the OS is what you selected * confirm networking works * confirm you know how you will log in again later Raff publicly states that Linux VMs deploy in under 60 seconds, and the FAQ says VMs deploy in about 60 seconds on average including OS installation and network configuration. That is fast enough that the real bottleneck is usually not the platform. It is deciding what you want the VM to do next. ## What to do in your first 15 minutes after launch This is where a lot of first-time users either build momentum or lose it. You do not need to do everything. You just need to do the right first few things. ### Update the machine If you launched a Linux VM, update the package index and apply available updates. Even when the image is current, this is a good habit because it gives you a clean starting point. ### Create a purpose for the server Do one useful thing immediately. Install Docker. Clone a project. Set up a web server. Create a small API. Add your SSH key. The first practical action is important because it turns the VM from “a server that exists” into “a tool that is already helping me.” ### Decide whether this is disposable or persistent Some first VMs are experiments. Others become the starting point for something longer-lived. That distinction matters. If it is disposable, move fast and learn. If it is persistent, think about backups, naming, access, and documentation right away. Raff’s pricing page makes this easier because snapshots and backups are built into the platform model rather than treated like an afterthought. Snapshots are listed at $0.06 per GB per month, and backups are also $0.06 per GB per month, with the first three backups per VM included free. That matters because the earlier you build recovery habits, the safer your workflow becomes. ## Common first-use cases that make sense on Raff A first VM should solve a real problem, not just satisfy curiosity. Here are some of the most practical starting use cases. ### A clean development box If your local machine is crowded with dependencies, containers, SDKs, and experiments from multiple projects, a cloud VM gives you a cleaner workspace. That is especially helpful when you want to separate client work, personal projects, and experimental stacks. ### A lightweight staging environment Many small teams wait too long before creating a staging environment because they assume it will be expensive or complicated. In reality, one modest VM is often enough to validate release workflows, test environment variables, and preview changes outside local development. ### A hosted side project or MVP A first VM is often the cheapest serious place to host a small application. If you are validating an idea, a VM gives you control over the OS, runtime, packages, networking, and deployment process. ### A learning lab This is one of the most underrated uses. If you want to learn Linux, Docker, Nginx, firewalls, SSH, or deployment basics, nothing teaches faster than having a real server to work with. The risk feels lower when the environment is clearly separated from your personal machine. ## Where teams usually overcomplicate the first launch This part matters because overcomplication is expensive. The first VM is where some teams start introducing too much process too early. They debate environments before they have users. They choose a larger machine because it feels safer. They create a long provisioning checklist before they know which parts they actually need. My advice is simpler. Launch one machine with a clear purpose. Use it. Learn from it. Then improve the next decision. That is a more practical cloud habit than trying to design your forever-architecture in week one. Raff’s product positioning supports that kind of approach. Pricing starts at $4.99 per month, the platform emphasizes transparent pricing, unmetered bandwidth, fast deployment, and 24/7 support, and Linux VMs are marketed as quick to deploy with full root access. Those are exactly the traits that make “start small, then iterate” a realistic strategy instead of a risky one. ## A better way to think about your first VM Do not think of your first VM as infrastructure you must get perfectly right. Think of it as a working base. A place to code. A place to test. A place to host. A place to learn. A place to separate one project from the chaos of everything else. Once you treat it that way, the first launch becomes less intimidating. You stop asking, “What is the perfect setup?” and start asking, “What is the next useful setup?” That shift is important. It is how small teams move from hesitation into momentum. ## What This Means for You If you are just getting started with cloud infrastructure, your first goal should not be mastering every cloud concept at once. Your goal should be getting one useful VM online quickly, understanding what it is for, and creating enough confidence to keep going. That is the practical value of a first VM on Raff. You can start with an operating system you already know, launch quickly, resize later if needed, and build better habits around access, backups, and deployment as your workload grows. If you are ready to turn this into action, start with [Raff pricing](/pricing), explore [Linux VM options](/products/linux-vm), and then make your first decision as simple as possible: choose the machine that helps you do your next piece of work today. --- ### The 48-Hour MVP Stack: Simple Infrastructure That Ships URL: https://rafftechnologies.com/blog/48-hour-mvp-stack-simple-infrastructure Published: 2026-03-30T00:00:00.000Z Description: The 48-Hour MVP Stack: Simple Infrastructure That Ships A 48-hour MVP infrastructure stack is a minimal cloud setup that helps teams launch and validate a product within two days using simple compute, managed data services, and lightweight operational tooling. At Raff Technologies, we see this pattern often: early teams lose momentum not because their idea is weak, but because their infrastructure becomes heavier than the product itself. Before the first real user arrives, they are already debating Kubernetes, multi-service deployments, complex CI/CD flows, and cloud architectures designed for traffic they do not yet have. That is usually the wrong first battle. If your MVP needs a DevOps team before it has users, the stack is probably too complicated. Raff Technologies supports 10K+ deployed VMs, 3,000+ customers, and cloud servers that can be deployed in seconds, which gives us a practical view into what early teams actually need when they are trying to ship quickly. This guide explains what a 48-hour MVP infrastructure stack should include, what it should avoid, and how to decide when your product has earned the next layer of complexity. ![Diagram showing a 48-hour MVP stack with users, domain and SSL, a single VM application, managed PostgreSQL, optional object storage, and basic monitoring.](https://raff-images.s3.raffusercloud.com/48_hour_mvp_stack_diagram_png_e5dd4c1cbd.png) *Suggested placement: after the opening block. This visual introduces the whole MVP stack before the reader enters the detailed explanation.* ## The real MVP infrastructure problem is not scale Most MVPs do not fail because the first version was hosted on infrastructure that was too simple. They fail because the team spends too much time building around imaginary scale instead of real usage. At the MVP stage, your primary risk is usually not that the product receives millions of requests overnight. Your primary risk is that you do not launch fast enough to learn whether users care. That changes the infrastructure decision completely. A mature product optimizes for resilience, redundancy, automation, separation of concerns, compliance, and predictable scaling. An MVP optimizes for speed, clarity, and reversibility. Those are different jobs. A simple stack lets one developer understand the whole system. They know where the app runs, where the logs are, where the database lives, how deployment works, and what to check when something breaks. That clarity matters more than architectural elegance when the product is still trying to prove demand. The question is not: > What stack would look impressive to another engineer? The better question is: > What stack gives us the best chance of launching this week and learning from real users? That question usually leads to a smaller, better infrastructure plan. ## What a 48-hour MVP stack should include A practical 48-hour MVP stack should include only the infrastructure required to make the product usable, reachable, and maintainable. For most web-based MVPs, that means: * One application runtime * One primary database * A real domain * SSL * Basic deployment * Basic monitoring * Backups or snapshots * Optional object storage if the product handles files That is enough for a surprising number of early products. The stack can support a SaaS dashboard, a marketplace prototype, an internal tool, a developer product, a content platform, an API service, or a customer portal. What matters is not the exact framework. The framework could be Next.js, Django, Laravel, Rails, Node.js, FastAPI, Go, or something else your team already understands. The more important decision is the operational shape. A good MVP stack should be easy to answer in one sentence: > One app, on simple compute, connected to a managed database, secured with SSL, deployed from Git, monitored enough to catch obvious failures. That sentence is boring. That is the point. Boring infrastructure is often excellent MVP infrastructure because it leaves your attention for the product, users, pricing, onboarding, positioning, and feedback loops. ## The decision framework for choosing your MVP stack The right MVP stack depends on what you need to prove. If you are still validating demand, choose the simplest stack that gets the product in front of users. If you already have traction and a team that can manage more operational layers, a managed platform or more modular architecture may make sense. If you are already operating at scale, microservices can become reasonable. But most MVPs are not there yet. The table below gives a practical decision framework. | Stack type | Setup speed | Complexity | Cost | Scalability | Best fit | | ---------------------- | ----------: | ---------: | -----: | ----------: | ------------------------------------------------------------- | | Single VM stack | Fast | Low | Low | Moderate | MVPs, early SaaS, founder-led products | | Managed platform stack | Medium-fast | Medium | Medium | High | Teams with early traction and limited infrastructure appetite | | Microservices stack | Slow | High | High | Very high | Scale-stage products with multiple engineering teams | A single VM stack is usually the best choice when speed matters more than distributed architecture. It gives you a clear place to run the app, a simple path to deploy updates, and fewer moving parts to debug. A managed platform can be useful when your team wants less server ownership and is comfortable paying more for abstraction. It can reduce some operational burden, but it may also hide details that become important when debugging performance, networking, or cost. A microservices stack should usually wait. It becomes useful when separate teams own separate domains, deployment independence matters, and the product has real operational pressure. Before that, it often creates more coordination cost than value. Use this rule: > If your product has fewer than 10 active users, fewer than 10 engineers, and no proven traffic bottleneck, microservices are probably premature. That does not mean microservices are bad. It means timing matters. ### Choose a single VM stack if Choose a single VM stack if you need to launch quickly, keep costs low, and understand the full environment without involving a dedicated infrastructure team. This is usually the right option when: * You are pre-product-market fit * You need to launch in days, not weeks * The team is small * One developer should be able to debug the whole system * You are running a web app, API, dashboard, internal tool, or early SaaS product * Your current scaling needs are unknown A single VM does not mean careless infrastructure. It means focused infrastructure. You can still use version control, SSL, backups, monitoring, Docker, firewalls, and clean deployment practices. The difference is that everything remains understandable. ![which_mvp_stack_to_choose.png.png](https://raff-images.s3.raffusercloud.com/which_mvp_stack_to_choose_png_61c2121bc1.png) ### Choose a managed platform if Choose a managed platform if you want to avoid server management and are willing to accept more platform constraints. This can work well when: * You have early users * You value convenience over low-level control * Your team does not want to manage operating system updates * Your app fits the platform’s deployment model cleanly * You are comfortable with pricing that may rise as usage grows Managed platforms can be excellent for some teams. The risk is that they sometimes make the first launch easy but later make cost control, migration, or advanced configuration harder. For an MVP, that trade-off may still be worth it. ### Avoid microservices if Avoid microservices if the product does not yet have clear service boundaries, multiple engineering teams, or real scaling pain. Microservices add overhead in several places: * More repositories or packages * More deployments * More internal networking * More logs * More secrets * More failure modes * More coordination * More local development complexity For a mature platform, that overhead may be worth it. For a young MVP, it usually is not. A distributed system is harder to debug than a simple one. If the product itself is still changing every day, the infrastructure should not be the most rigid part of the company. *Suggested placement: after the decision framework table. This visual reinforces why the single VM stack is usually the best fit for a fast MVP launch.* ## The core components of a simple MVP stack A good MVP stack is not random. It is deliberately small. Each part should have a clear job. If a component does not help the product launch, support users, or reduce real operational risk, it probably does not belong in the first version. ### Application compute The compute layer is where your application runs. For a 48-hour MVP, a Linux VM is often the most direct option. It gives you a dedicated server environment, full root access, predictable resources, and enough flexibility to run common frameworks, APIs, background workers, reverse proxies, and Docker-based setups. This is one reason VMs remain underrated for early-stage products. They are easy to reason about. You know where the app is. You know how to restart it. You know where the logs live. You know what resources are attached to it. You can SSH into the machine, inspect the system, and fix issues directly. That level of visibility is valuable when speed matters. A single VM can run: * A web application * An API server * A reverse proxy such as Nginx or Caddy * Background workers * Docker Compose * A small Redis instance * Lightweight internal tools * A staging environment The goal is not to put everything on one machine forever. The goal is to avoid splitting things before splitting solves a real problem. ### Database For most MVPs, the database should be boring and reliable. PostgreSQL is usually the default choice because it is mature, widely supported, flexible, and familiar to most engineering teams. Whether you use managed PostgreSQL or a carefully maintained database setup, the key principle is the same: do not let database operations become the product. At the MVP stage, you do not want your best hours going into backup scripts, replication design, database tuning, or emergency maintenance unless your product specifically requires that depth. A managed database reduces operational burden. It lets the team focus on schema design, data quality, and product behavior instead of database administration. If managed PostgreSQL is available in your chosen environment, use it. If not, keep the database setup conservative, documented, backed up, and easy to migrate later. ### Domain and SSL A real domain and SSL are not optional for a serious MVP. They are basic technically, but important psychologically. A real domain makes the product easier to share, easier to test, easier to support, and easier for users to trust. Early products already ask users to tolerate some rough edges. Do not make the product feel temporary before the user even signs in. For most MVPs, a simple setup is enough: * Domain connected to the app * HTTPS enabled * Redirects configured correctly * Basic DNS records documented * No unnecessary CDN or edge complexity unless the product needs it A domain and SSL layer gives the product a minimum level of credibility. That matters when asking early users, investors, teammates, or pilot customers to take the product seriously. ### Deployment flow Deployment should be boring. A simple MVP deployment flow might look like this: * Code lives in GitHub * Changes are merged into the main branch * Basic tests or checks run * The app builds * The server pulls or receives the new version * The process restarts cleanly * Logs can be reviewed if something breaks That is enough to start. You do not need an enterprise CI/CD platform on day one. You need a repeatable deployment flow that the team trusts. If Docker makes deployment more consistent, use it. If Docker becomes another layer your team has to fight, skip it until it earns its place. The tool is not the point. Reliable shipping is the point. ### Monitoring MVP monitoring should answer simple questions: * Is the app up? * Is it responding? * Is it failing? * Are CPU, memory, or disk usage becoming dangerous? * Can someone see logs quickly? * Will the team know if something important breaks? That is enough for the first version. A wall of dashboards does not make an MVP more responsible. Useful visibility does. Start with uptime checks, basic server metrics, error visibility, and logs that a normal developer can understand. Add deeper observability when the product has enough users or revenue to justify it. ### Backups and snapshots Backups are not advanced infrastructure. They are basic survival. Even an MVP needs a way to recover from mistakes. Early teams often move quickly, change schemas, run scripts, test migrations, and experiment with product logic. That speed is useful, but it increases the chance of accidental data loss. A practical MVP backup plan should include: * Database backups * VM snapshots before risky changes * Clear restore expectations * Basic documentation on where backups live * Periodic restore testing when the product becomes business-critical The key is not to build an elaborate disaster recovery system on day one. The key is to avoid having no recovery path at all. ### Object storage Object storage should be added only when the product actually needs it. If users upload files, images, documents, generated assets, exports, or media, object storage makes sense. If the product does not handle files, adding object storage “just in case” creates another service to configure and monitor. A useful rule is: > Store application state in the database. Store user files and large static assets in object storage. Do not add object storage until the product has a real file-storage need. This keeps the initial stack clean while leaving a clear path to expand later. ## Best practices for 48-hour MVP infrastructure The best MVP infrastructure is not the smallest possible stack. It is the smallest responsible stack. That distinction matters. A careless stack creates future pain. A disciplined stack avoids unnecessary complexity while still giving the product a stable foundation. ### Keep the architecture flat Keep the application as close together as possible until the product proves why it should be split. A flat architecture reduces coordination cost. There are fewer network calls, fewer deployment paths, fewer logs, fewer secrets, and fewer places for bugs to hide. This does not mean writing messy code. You can still structure the application cleanly internally. The point is to avoid operational separation before the business has earned it. ### Use tools your team already understands For a 48-hour MVP, familiarity beats novelty. If your team knows Laravel, use Laravel. If your team knows Django, use Django. If your team is fastest with Next.js, use Next.js. The framework choice matters less than the team’s ability to build, deploy, debug, and improve the product quickly. A technically superior tool that slows the team down is usually the wrong MVP choice. The best stack is often the one your team can operate calmly under pressure. ### Make debugging obvious A good MVP stack should make debugging easy. When something breaks, the team should know where to look first. That means logs should be accessible, deployment history should be understandable, and the relationship between components should be simple. If a user reports a problem, you should be able to ask: * Is the app running? * Did the last deployment cause this? * Is the database reachable? * Are environment variables correct? * Are errors appearing in logs? * Is the server under resource pressure? If answering those questions requires searching across five tools and three services, the stack may be too complex for the stage. ### Delay orchestration until it solves a real problem Kubernetes is powerful, but it is rarely the right first move for a 48-hour MVP. The problem is not Kubernetes itself. The problem is operational timing. Kubernetes introduces clusters, manifests, services, ingress, secrets, resource requests, monitoring, deployment strategies, and operational concepts that must be understood and maintained. That investment can be justified when the product needs it. It is much harder to justify before users arrive. Use orchestration when the product has enough scale, team structure, or reliability requirements to make the overhead worthwhile. Until then, keep deployment simpler. ### Treat infrastructure changes as product decisions Infrastructure decisions affect product speed. Every new tool changes how fast the team can deploy, debug, hire, onboard, document, and recover. That means infrastructure decisions should not be made only on technical preference. Before adding a new component, ask: * What user problem does this help solve? * What operational problem does this remove? * What new maintenance does this introduce? * Who will own it? * Can we launch without it? * Can we add it later without major damage? If the answer is unclear, wait. ## What not to use in the first 48 hours A good MVP stack is defined as much by what it excludes as what it includes. The early version should avoid tools that create operational weight before the product proves it needs them. ### Do not start with Kubernetes by default Kubernetes is excellent for certain production workloads, but it is not automatically excellent for MVPs. At the MVP stage, Kubernetes often adds more decisions than it removes. You need to think about cluster setup, ingress, container registries, secrets, scaling policies, deployment patterns, resource limits, and monitoring before the product has proven demand. That can be a poor trade. If your MVP can run on a single VM with a simple deployment process, start there. You can move to orchestration later when the product has earned the shift. ### Do not split into microservices too early Most MVPs do not have a service-boundary problem. They have a focus problem. Splitting a young product into services can make the team feel more “scalable,” but it also creates more deployment work, more integration work, and more debugging complexity. Worse, the boundaries are often wrong because the product is still changing. Good service boundaries emerge from real usage, real domain understanding, and real team ownership. Guessing them too early usually creates rework. ### Do not add tools for imagined future needs A tool that might be useful later is not automatically useful now. Object storage, queues, service meshes, distributed tracing, event buses, orchestration, and multiple environments can all be valuable. But each one should earn its place. At the MVP stage, “we might need this later” is not enough. The better question is: > Does this help us launch, validate, recover, or serve users right now? If not, document it as a future option and move on. ## When to add more infrastructure Simple infrastructure does not mean staying simple forever. Healthy products evolve. They begin with a clear foundation, then add complexity when growth makes the trade worthwhile. The mistake is not adding complexity. The mistake is adding it before there is evidence. Add more infrastructure when one of these conditions becomes true: * Users are growing and performance bottlenecks are measurable * Deployments are becoming risky or too frequent for the current setup * The team has grown and ownership boundaries are becoming clearer * Background jobs need to be separated from request handling * File storage, caching, queues, or search become core product needs * Security or compliance requirements demand stronger separation * Downtime risk becomes more expensive than infrastructure complexity * The cost of staying simple becomes higher than the cost of evolving That is what “complexity should be earned” means. A growing product may eventually need load balancing, separate services, caching, object storage, queues, staging environments, infrastructure as code, or orchestration. But those should come from pressure, not fear. Fear says: > We might need this someday, so let’s build it now. Discipline says: > We know what would trigger this upgrade, and we will add it when that trigger appears. The second approach is usually healthier. ![Roadmap showing MVP infrastructure evolving from a single VM and managed PostgreSQL to validation, optimization, and scale-stage infrastructure.](https://raff-images.s3.raffusercloud.com/tech_roadmap_for_scalable_growth_png_4863bcb0fd.png) *Suggested placement: after the “When to add more infrastructure” section. This visual explains the growth path from simple MVP infrastructure to scalable infrastructure.* ## How this applies on Raff Technologies Raff Technologies is designed around a simple idea: cloud infrastructure should be fast, understandable, and reliable without forcing early teams into unnecessary complexity. That philosophy fits the 48-hour MVP stack well. For teams building an MVP, a Raff Linux VM gives you a straightforward place to run the first version of the product. You can deploy common Linux distributions, use full root access, connect over SSH, install the runtime your application needs, configure a reverse proxy, and run the app in an environment your team can understand. Raff Linux VPS plans start at $4.99/month, support 9 Linux distributions, and can be deployed in under 60 seconds. That matters for MVPs because infrastructure setup should not consume the week you planned to spend building and validating the product. A simple Raff-based MVP stack might look like this: * Raff Linux VM for the application runtime * PostgreSQL for relational data * Domain and SSL for trust * Basic monitoring for uptime and resource usage * Snapshots or backups before risky changes * Object storage only if the product handles files or generated assets The decision rationale is simple: early teams need infrastructure that preserves momentum. At Raff, we see that small teams often move faster when they can understand the whole system without waiting on infrastructure specialists. A single VM gives enough control to deploy real software, enough flexibility to evolve, and enough simplicity to keep the team focused on users rather than cloud architecture. If your decision framework points toward a single VM stack, Raff is a practical place to start because it gives you the core compute layer without forcing a complex platform model on day one. ## Common mistakes when building MVP infrastructure Even simple stacks can become messy if the team does not make deliberate choices. The most common mistake is treating the MVP as a smaller version of a future enterprise platform. That mindset leads to too many services, too many tools, and too many assumptions before the product has evidence. Another mistake is ignoring recovery. Some founders hear “simple infrastructure” and interpret it as “no operational discipline.” That is dangerous. Simple infrastructure still needs backups, SSL, access control, and basic monitoring. A third mistake is spreading the stack across too many providers too early. It can feel flexible, but it often creates more account management, more billing complexity, more networking questions, and more failure points. Early teams usually benefit from fewer surfaces to manage. The final mistake is optimizing for what looks impressive rather than what ships. A 48-hour MVP stack should not be judged by how sophisticated the diagram looks. It should be judged by whether the product gets into users’ hands quickly, reliably, and with enough operational clarity to improve it. ## Conclusion A 48-hour MVP stack is not about choosing weak infrastructure. It is about choosing infrastructure that matches the stage of the product. Before product-market fit, the best infrastructure decision is often the one that helps you launch, learn, and iterate with the least operational drag. For many teams, that means a single VM, a reliable database, SSL, basic monitoring, and a clear recovery path. You can always add complexity later. In fact, you should — when users, revenue, team size, or operational pressure justify it. If you are building your first MVP and want a simple place to run it, start with a Raff Linux VM, keep the stack understandable, and add each new layer only when the product earns it. --- ### Why Cheap Cloud Often Costs MSPs More Than They Expect URL: https://rafftechnologies.com/blog/why-cheap-cloud-often-costs-msps-more Published: 2026-04-17T00:00:00.000Z Description: Why Cheap Cloud Often Costs MSPs More Than They Expect Cheap cloud is often expensive for MSPs. Not because the monthly VM price is high. Because the total cost of delivering service around that VM gets worse. The cheaper the infrastructure looks on paper, the more often MSPs end up paying through labor, billing confusion, reactive support, and awkward client conversations. At Raff Technologies, that distinction matters a lot because MSPs do not really buy infrastructure the way a solo developer does. They buy something they have to package, explain, defend, and operate repeatedly across multiple clients. That is why I think many MSPs evaluate cloud pricing too narrowly. They compare the advertised server number and stop there. But a cloud platform is not only a line item. It is an operating model. If the platform introduces billing ambiguity, bandwidth anxiety, slow provisioning, or too much manual work, the invoice may look cheap while the service margin quietly erodes. We have thought about this carefully at Raff Technologies. One reason we include unmetered bandwidth on every plan is that bandwidth overage billing creates the wrong behavior: teams become more hesitant, more defensive, and less confident about scaling or testing because they are designing around invoice uncertainty instead of actual workload needs. That is not only a developer problem. For MSPs, it becomes a packaging problem. When the underlying cost model is unpredictable, your service promise becomes harder to price cleanly too. That logic already shows up in Raff’s public positioning around unmetered bandwidth, transparent pricing, and simple VM economics. It is also why I think “cheap cloud” can be one of the most expensive decisions an MSP makes. ## The Sticker Price Is Not the Operating Cost This is the first thing I would want any MSP owner to separate clearly. A low VM price is not the same thing as a low delivery cost. If the platform is slow to provision, awkward to explain, difficult to standardize, or full of cost conditions your team has to remember, the infrastructure stops being “cheap” the moment service delivery begins. That is especially true for MSPs because they do not feel cloud cost only once. They feel it again and again in onboarding, templating, support, billing, recovery work, and client-facing expectation management. That is why I do not think MSPs should ask only: “How much is the server?” They should ask: “How much repeat work will this platform create around the server?” That second question is usually more expensive. ## Hidden Labor Is Where Cheap Cloud Starts to Fail In my view, hidden labor is the biggest reason cheap cloud hurts MSPs. A platform can undercut everyone on entry price and still cost more in real operations if your team has to keep solving the same avoidable problems: * explaining unclear invoices * tracking bandwidth assumptions * cleaning up inconsistent deployments * waiting too long for environments to be ready * manually checking what is or is not included * answering client questions that should never have existed in the first place This is where “cheap” turns into drag. MSPs win when they can repeat clean delivery. They lose margin when every client stack becomes a small exception. If provisioning is slow, billing is vague, or the platform requires too much interpretation, the team spends more time managing friction and less time delivering value. That is why I think the real comparison is not cheap cloud versus expensive cloud. It is cheap-looking cloud versus low-friction cloud. Those are very different things. ## Unclear Billing Is a Margin Problem, Not Just an Annoyance I think this is the most underestimated part of the whole conversation. Unclear cloud billing does not just frustrate technical buyers. It damages packaging. An MSP needs to turn infrastructure into a service that clients can understand. That means the pricing underneath matters. If the base cost changes unpredictably, or if bandwidth, snapshots, traffic behavior, or usage edge cases create surprise charges, the MSP has two bad options: either absorb the uncertainty, or pass it on and make the client relationship harder. Neither is attractive. This is why transparent pricing matters much more in MSP environments than in one-off developer experiments. A developer might tolerate a slightly confusing invoice once. An MSP has to build a repeatable service model on top of it. If the cloud provider’s bill is hard to interpret, the MSP’s own pricing becomes harder to defend. Raff’s public pricing and product pages are strong on exactly this point: published VM tiers, unlimited bandwidth, and straightforward entry pricing starting from **$4.99/month** on the public pricing page. That is not just a positioning line. It changes how easily a provider can package, quote, and standardize a service. For MSPs, pricing clarity is operational clarity. ([pricing](/pricing), [Raff VM](/products/raff-vm)) ## Bandwidth Surprises Change Behavior in the Worst Way This is one of the easiest cloud costs to underestimate and one of the worst for MSP confidence. Bandwidth pricing changes behavior before it even changes the bill. Teams test less confidently. They plan more defensively. They hesitate before launching something public. They worry that a successful month will cost more than expected. That is a bad mindset for any infrastructure team. It is even worse for an MSP, because your client is paying you for confidence, not hesitation. If every growth event, traffic spike, file delivery pattern, or client success story might trigger an uncomfortable cost discussion, the platform is quietly undermining your service model. That is why I think unmetered bandwidth is more than a feature bullet. It is a commercial simplifier. Raff’s current public product pages explicitly position **unlimited bandwidth** across the VM offering, and Raff has already made the public argument that bandwidth overage billing encourages the wrong operating behavior. I think that point is especially true for MSPs. Predictable transfer economics make it easier to quote, easier to sell, and easier to support. :contentReference[oaicite:3]{index=3} ## Slow Provisioning Is More Expensive Than People Admit A slow provisioning flow is one of those costs that rarely shows up in cloud comparison charts, but MSPs feel it immediately. The more clients you manage, the more expensive delay becomes. If standing up a clean environment takes too long, if standard builds do not feel repeatable, or if new workloads require too much manual work before they are usable, then your platform is consuming one of the most valuable things an MSP has: team attention. This is why fast deployment matters more than it looks. It affects: * onboarding speed * migration turnaround * recovery readiness * how quickly you can spin up a replacement environment * how confidently you can standardize templates across clients Raff’s public product and pricing pages currently position VM deployment as happening in **seconds** and, on the Linux product page, **under 60 seconds**. That kind of speed matters because it helps MSPs preserve momentum during onboarding, support, and recovery situations instead of turning basic infrastructure creation into a ticket queue. :contentReference[oaicite:4]{index=4} A cheap VM that takes too much organizational effort to turn into a working client environment is not actually cheap. ## Cheap Cloud Gets Worse When You Sell Backup and Recovery This is where the problem becomes more serious. An MSP is not only selling compute. It is often selling support, continuity, backup confidence, and some version of operational trust. The more unclear the underlying infrastructure becomes, the harder it is to sell those promises cleanly. If your team already has to explain variable billing, interpret transfer costs, and work around slow provisioning, then backup and recovery design become harder to package too. You cannot build a clean service promise on top of a messy cost foundation. This is why I think MSPs should evaluate cloud platforms based on how well they support standardization around: * predictable monthly quoting * fast repeat deployments * low-friction backup posture * simple upgrade paths * fewer support-triggering surprises That is also why this topic fits naturally into Raff’s broader backup and recovery content. If you are packaging managed services, the next useful reads are [Cloud Server Backup Strategies: Snapshots, RPO, and Recovery Planning](/learn/guides/cloud-server-backup-strategies) and [High Availability vs Disaster Recovery: What Small Teams Actually Need](/learn/guides/high-availability-vs-disaster-recovery-small-teams). Cheap infrastructure is not helpful if it makes recoverability harder to price and operate. ## What Good Cloud Economics Actually Look Like for MSPs For MSPs, good cloud economics usually look less dramatic than people expect. It is not about chasing the lowest visible price. It is about reducing the number of expensive unknowns. That means the better platform is often the one that gives you: * predictable billing * fewer edge-case charges * repeatable deployments * cleaner internal packaging * fast spin-up for new and replacement environments * lower support burden around infrastructure basics This is exactly where a simpler cloud model becomes valuable. Raff’s public pricing currently starts at **$4.99/month**, includes **NVMe storage**, and positions **unlimited bandwidth**, fast deployment, and a **14-day money-back guarantee**. That combination is useful because it lowers both technical and commercial friction. The point is not that every MSP should buy the absolute cheapest VM. The point is that a provider with simpler economics can make the MSP’s own business model healthier. :contentReference[oaicite:5]{index=5} ## What This Means for You If you run an MSP, I would stop asking only: “Which cloud is cheaper?” I would ask: “Which cloud is cheaper to operate repeatedly across clients?” That is the more useful question. If the platform introduces billing confusion, bandwidth anxiety, slow provisioning, or too much manual work, your margin will feel that before your finance sheet does. Cheap cloud becomes expensive the moment your team has to keep compensating for it. If you are evaluating that trade-off right now, start with [Raff pricing](/pricing), look at [Raff VM](/products/raff-vm) as the base infrastructure layer, and then review whether your service packaging around backup, recovery, and client onboarding would get simpler or harder on top of it. In my view, that is the real economics test. Because MSPs do not win by buying the lowest advertised VM. They win by delivering infrastructure with the least unnecessary friction. --- ### Best VPS for Cloud-Native DevOps Teams in 2026 URL: https://rafftechnologies.com/blog/best-vps-cloud-native-devops-2026 Published: 2026-02-22T00:00:00.000Z Description: Best VPS for Cloud-Native DevOps Teams in 2026 The best VPS for cloud-native DevOps teams is a high-performance virtual server that provides predictable compute, fast NVMe storage, reliable networking, root access, transparent pricing, and enough flexibility to run containers, APIs, CI/CD runners, databases, and internal tools. Modern DevOps teams do not just need a cheap server. They need infrastructure that supports real engineering workflows. A cloud-native team may use a VPS for Docker workloads, staging environments, API services, CI/CD runners, observability tools, internal dashboards, test databases, automation jobs, or small production systems. These workloads behave differently from traditional shared hosting. They need more control, better I/O performance, predictable pricing, and a clean path to scale when usage grows. The mistake many teams make is assuming cloud-native infrastructure must always start with complex managed platforms, Kubernetes clusters, or large cloud accounts. Sometimes that is true. But for many teams, especially early-stage SaaS companies, small DevOps teams, freelancers, agencies, and infrastructure-conscious startups, a properly configured VPS is faster, simpler, and more cost-effective. This guide explains what DevOps teams should look for in a VPS in 2026, when a VPS makes sense, when it does not, and how Raff Technologies fits into the decision. ## Cloud-native teams need more than basic hosting Traditional hosting is usually designed around websites. Cloud-native teams usually need more than that. They need an environment where they can install packages, run containers, configure firewalls, manage SSH access, deploy APIs, test infrastructure scripts, run background workers, connect storage, and debug performance issues without fighting platform limitations. A good VPS for DevOps should support: * Full root access * SSH key authentication * Docker and container workloads * Fast provisioning * Predictable CPU and RAM * NVMe SSD storage * Unmetered or predictable bandwidth * Cloud firewall controls * DDoS protection * Backups and snapshots * Monitoring compatibility * API or automation support * Clear upgrade paths This is different from shared hosting. Shared hosting hides most of the server environment. That can be fine for a simple website, but it is limiting for DevOps teams. You cannot properly test deployment flows, container behavior, background jobs, custom runtimes, system packages, or infrastructure automation when the environment is locked down. Cloud-native teams need control. A VPS gives them that control without requiring the complexity of a full enterprise cloud account. ## What makes a VPS good for DevOps in 2026? A good DevOps VPS should be judged by workload behavior, not marketing labels. The most important factors are: | Factor | Why it matters for DevOps | | -------------------- | ----------------------------------------------------------------------------- | | CPU performance | Affects builds, APIs, workers, containers, and concurrent workloads | | RAM | Keeps databases, containers, caches, and application runtimes stable | | NVMe storage | Improves build speed, database I/O, container startup, and file operations | | Network quality | Affects deployments, backups, API latency, remote access, and service traffic | | Pricing transparency | Prevents surprise bills from bandwidth, I/O, or hidden fees | | Provisioning speed | Helps teams spin up dev, test, staging, and recovery environments quickly | | Root access | Gives teams full control over the operating system and runtime | | Security features | Firewalls, SSH keys, DDoS protection, and backups reduce operational risk | | Scalability | Lets teams resize or add servers as workloads grow | | Support | Matters when infrastructure issues affect delivery or customers | DevOps teams should not choose a VPS only because it is cheap. They should choose the provider that gives the best balance of performance, reliability, cost predictability, and operational control. A low-cost server with weak I/O, poor networking, hidden bandwidth limits, or unstable performance can become expensive quickly. The monthly price may be low, but the engineering time lost to debugging, slow builds, failed deploys, and downtime can be much higher. ## The decision framework for choosing a DevOps VPS The right VPS depends on the workload. A staging server, CI/CD runner, database VM, internal dashboard, Docker host, and production API do not need the same resource profile. Before choosing a VPS, define the job the server must perform. Use this framework: | Workload | Best VPS priority | Recommended direction | | ------------------- | --------------------------------------------- | ------------------------------------------------------ | | Development server | Cost efficiency and flexibility | Small Linux VPS with root access | | Staging environment | Similarity to production | General Purpose VPS with enough RAM | | Docker host | CPU, RAM, and NVMe storage | Balanced VPS with room for containers | | CI/CD runner | CPU consistency and fast disk | CPU-Optimized VPS | | Production API | CPU consistency, uptime, network quality | CPU-Optimized or larger balanced VPS | | Database workload | RAM, storage I/O, backups | CPU-Optimized VPS with NVMe and backup strategy | | Internal dashboard | Reliability and predictable cost | General Purpose VPS | | Automation server | CPU and long-running process stability | General Purpose or CPU-Optimized depending on job load | | Kubernetes lab | Multiple VMs, private networking, root access | Several smaller Linux VMs | | Small SaaS platform | Performance, uptime, scaling path | 4 vCPU / 8 GB RAM class or higher depending on usage | The practical rule is simple: > Choose a VPS based on the workload’s bottleneck, not the cheapest plan on the page. If the workload is CPU-bound, prioritize compute. If it is memory-bound, prioritize RAM. If it writes often, prioritize NVMe storage. If it serves users, prioritize uptime and network reliability. If it is experimental, prioritize cost and flexibility. This makes the VPS decision much clearer. ## VPS vs big cloud: which is better for DevOps teams? Large cloud platforms are powerful. They offer managed databases, serverless services, object storage, queues, Kubernetes, IAM systems, global networking, observability tools, and advanced enterprise features. For some teams, that ecosystem is necessary. But not every DevOps workload needs that complexity. A VPS can be a better choice when the team needs: * A predictable monthly bill * A simple Linux environment * Full root access * Fast setup * Docker or Docker Compose * A staging server * A CI/CD runner * A test database * A production API with moderate traffic * An internal tool * A self-hosted monitoring stack * A small SaaS deployment * A Kubernetes lab or lightweight cluster The difference is not “VPS is better” or “big cloud is better.” The real question is: > Does this workload need cloud platform complexity, or does it need a reliable server? Many DevOps workloads are stable, understandable, and server-shaped. They do not need five managed services, complex IAM rules, usage-based billing surprises, and a long configuration chain. They need a fast machine, predictable networking, enough storage, a clean Linux image, and the freedom to configure the environment. That is where a modern VPS can be the better tool. ## CPU performance matters for builds, APIs, and workers CPU performance is one of the most important factors for DevOps workloads. A slow or inconsistent CPU affects: * CI/CD build times * Test execution * API response time * Container startup * Background workers * Data processing jobs * Compression and encryption * Package installation * Dependency builds * Queue processing For DevOps teams, CPU performance is not only about user-facing speed. It directly affects engineering velocity. If builds are slow, developers wait. If tests are slow, releases slow down. If workers fall behind, product behavior becomes unreliable. If APIs respond slowly, customers feel it. This is why CPU architecture matters when comparing VPS providers. Modern AMD EPYC processors are strong for multi-threaded workloads, containerized applications, and concurrent server tasks. For DevOps teams running builds, APIs, workers, and databases, modern CPU generations can make a real difference. When evaluating a VPS provider, ask: * What CPU generation is being used? * Are vCPUs shared or dedicated? * Is CPU performance consistent under load? * Are there CPU-Optimized plans? * Are benchmarks available? * Is performance stable during peak usage? The cheapest VPS is not always the best value. A slightly more expensive server that completes builds faster, handles more API requests, and stays stable under load may be the better DevOps decision. ## NVMe storage is critical for modern workloads Storage performance matters more than many teams expect. DevOps workflows often create a lot of disk activity: * Pulling container images * Building Docker layers * Installing dependencies * Running database queries * Writing logs * Creating artifacts * Running test suites * Processing files * Storing temporary build data NVMe SSD storage improves these workflows because it offers lower latency and higher throughput than older storage types. This affects: * Faster container startup * Faster package installs * Faster database reads and writes * Faster build pipelines * Faster local caching * Better performance under concurrent disk activity For Docker and Kubernetes workloads, storage speed can be especially visible. Container images, layer caching, logs, and volumes all depend on disk performance. If a VPS provider still uses slow storage, the CPU may not matter as much because the workload becomes I/O-bound. In 2026, DevOps teams should treat NVMe storage as a baseline expectation, not a premium luxury. ## Predictable pricing matters more than complex flexibility DevOps teams often care about cost, but they care even more about cost predictability. Large cloud platforms can become expensive because the bill may include separate charges for compute, storage, bandwidth, snapshots, I/O, IPs, load balancers, managed services, logs, metrics, and data transfer. That flexibility can be useful, but it also creates uncertainty. For stable workloads, predictable pricing is often better. A DevOps team should be able to answer: * What will this server cost each month? * Is bandwidth included? * Are there hidden transfer fees? * Is storage included? * Are backups and snapshots priced clearly? * Is the pricing understandable before deployment? * Can we scale without billing surprises? Predictable pricing is especially important for startups, agencies, freelancers, small teams, and internal platform teams managing multiple environments. If the workload is stable, a high-performance VPS with transparent monthly pricing can be easier to plan than a usage-based cloud setup. ## Containers do not always require Kubernetes Cloud-native teams often use containers. But containers do not automatically mean Kubernetes. For many teams, Docker or Docker Compose on a VPS is enough. This is especially true for early-stage products, internal tools, staging servers, dev environments, small APIs, and self-hosted services. A VPS can run: * Docker containers * Docker Compose stacks * Reverse proxies * Background workers * Databases for test or small production use * Monitoring agents * CI/CD runners * Internal tools * Web apps and APIs Kubernetes becomes useful when the workload needs orchestration, scheduling, self-healing, rolling deployments, service discovery, multiple nodes, and operational separation across teams. Before that, it can be unnecessary overhead. A simple VPS-based container setup is often easier to understand, easier to debug, and cheaper to operate. Use Kubernetes when the architecture earns it. Use a VPS with Docker when the team needs speed, simplicity, and control. ## Best VPS baseline for cloud-native projects A good starting configuration for many cloud-native DevOps workloads is: ```text 4 vCPU 8 GB RAM NVMe SSD storage Unmetered bandwidth Linux OS Full root access SSH key authentication Firewall controls Backups or snapshots ``` This is not the right size for every workload, but it is a strong baseline for early-stage SaaS apps, Docker hosts, staging environments, internal tools, APIs, automation servers, and small production workloads. Smaller workloads can start lower. For example: | Workload | Starting size | | -------------------- | -------------------------------- | | Small dev server | 1–2 vCPU, 1–2 GB RAM | | Staging app | 2 vCPU, 2–4 GB RAM | | Small production API | 2 vCPU, 4 GB RAM | | Docker Compose app | 2–4 vCPU, 4–8 GB RAM | | CI/CD runner | 4+ vCPU, 8+ GB RAM | | Database VM | 4+ vCPU, 8+ GB RAM, NVMe storage | | Moderate SaaS app | 4 vCPU, 8 GB RAM or higher | The correct plan depends on workload behavior. Start with a safe baseline, monitor usage, then resize when evidence appears. ## Security features DevOps teams should check A VPS for DevOps should not only be fast. It should also provide the basic security controls needed for production and internal infrastructure. Look for: * SSH key authentication * Full root access with control * Cloud firewall support * DDoS protection * Private networking options * Backups and snapshots * OS image choices * Clear access controls * Monitoring compatibility * Ability to restrict management ports DevOps teams should avoid exposing everything directly to the public internet. A safer VPS setup usually includes: * Public access only for HTTP and HTTPS * SSH restricted to trusted IPs, VPN, or bastion access * Databases kept private * Firewalls configured with least privilege * Backups enabled * Patching and updates scheduled * Logs monitored A good VPS provider gives teams the building blocks. The team still needs to configure them properly. ## When a VPS is not enough A VPS is powerful, but it is not the right answer for every workload. You may need a more advanced cloud architecture when: * You need managed databases with automated failover * You need multi-region traffic routing * You need advanced IAM and compliance controls * You need large autoscaling fleets * You need fully managed Kubernetes * You need event-driven serverless architecture * You need complex data pipelines * You need advanced enterprise networking * You cannot tolerate single-server failure * You need strict regulatory architecture This is where larger cloud platforms or more complex architectures may make sense. The point is not to force everything onto a VPS. The point is to avoid unnecessary complexity for workloads that do not need it. A modern VPS is best for workloads where server-level control, performance, predictable pricing, and simplicity are more valuable than a large catalog of managed services. ## Why Raff fits cloud-native DevOps teams Raff Technologies is built around a simple infrastructure promise: Fast. Simple. Reliable. For DevOps teams, that means a VPS platform that supports modern cloud-native workflows without forcing unnecessary complexity. Raff Linux VMs support 9 Linux distributions, deploy in under 60 seconds, and provide full root access with SSH key authentication. That makes them practical for developers and DevOps teams that need quick environments for testing, staging, production APIs, containers, runners, and internal systems. Raff infrastructure includes: * AMD EPYC processors * NVMe SSD storage * DDR5 ECC memory * Unmetered bandwidth * 3 Gbps port speed * 99.9% uptime SLA * DDoS protection * Cloud firewall support * Docker-ready Linux environments * Transparent monthly pricing * Plans starting at $4.99/month This combination matters because DevOps teams usually do not want infrastructure that slows them down. They want to deploy quickly, control the environment, understand the bill, and scale when the workload proves the need. Raff is especially useful for: * Docker-based applications * Staging environments * Development servers * CI/CD runners * Backend APIs * Small SaaS platforms * Internal tools * Automation servers * Test databases * Kubernetes labs * Self-hosted DevOps tools The goal is not to replace every part of the cloud ecosystem. The goal is to provide a faster, simpler, more predictable VPS foundation for teams that need performance and control without enterprise-level cloud complexity. ## VPS checklist for DevOps teams Before choosing a VPS provider in 2026, use this checklist: * Does the provider use modern CPUs? * Is NVMe SSD storage included? * Is bandwidth predictable or unmetered? * Are there hidden fees? * Can servers deploy quickly? * Is full root access available? * Is SSH key authentication supported? * Are Docker and container workloads supported? * Are backups and snapshots available? * Is cloud firewall support included? * Is DDoS protection available? * Are there General Purpose and CPU-Optimized plans? * Can the server be resized later? * Is uptime clearly stated? * Is support available when infrastructure becomes urgent? * Does the monthly price make sense for stable workloads? If the workload is important, do not choose only by the lowest price. Choose the VPS that gives the best mix of performance, predictability, reliability, and operational control. ## FAQ ### What is the best VPS for DevOps teams? The best VPS for DevOps teams is one that provides modern CPU performance, NVMe storage, root access, predictable pricing, reliable uptime, Docker support, backups, firewall controls, and enough flexibility to run development, staging, CI/CD, and production workloads. ### Is VPS good for cloud-native applications? Yes. A VPS is a strong fit for many cloud-native workloads, especially Docker apps, APIs, staging environments, internal tools, CI/CD runners, self-hosted services, and early-stage SaaS platforms. ### Do DevOps teams need Kubernetes to be cloud-native? No. Kubernetes is useful for orchestration at scale, but many cloud-native teams can run Docker, Docker Compose, APIs, workers, and internal tools effectively on VPS infrastructure. ### What VPS size should I choose for DevOps workloads? A common starting point for cloud-native DevOps workloads is 4 vCPU, 8 GB RAM, NVMe SSD storage, and unmetered bandwidth. Smaller dev or staging workloads can start lower, while databases and CI/CD runners may need more CPU and RAM. ### Why does NVMe storage matter for DevOps? NVMe storage improves container startup, package installation, database I/O, build pipelines, logging, and file-heavy workloads by reducing storage latency and improving throughput. ### Is a VPS cheaper than major cloud providers? A VPS can be more cost-efficient for stable workloads because pricing is often more predictable and less fragmented than large usage-based cloud platforms. ### Does Raff support Docker workloads? Yes. Raff Linux VMs provide full root access, SSH key authentication, modern Linux distributions, NVMe storage, and Docker-ready environments for containerized workloads. ### How much does Raff Linux VPS start at? Raff Linux VPS plans start at $4.99/month, with 9 Linux distributions, deployment in under 60 seconds, full root access, and unmetered bandwidth. ## Conclusion The best VPS for cloud-native DevOps teams in 2026 is not simply the cheapest server. It is the VPS that gives teams the right balance of performance, control, reliability, and predictable cost. DevOps teams need infrastructure that supports containers, APIs, CI/CD pipelines, staging environments, internal tools, databases, automation, and production services without adding unnecessary complexity. A modern VPS with strong CPU performance, NVMe storage, root access, firewall controls, backups, and clear pricing can be the right foundation for many workloads. Large cloud platforms still have their place. But for stable workloads, small teams, early-stage SaaS products, internal systems, and practical DevOps workflows, a high-performance VPS can be faster to deploy, easier to manage, and more affordable. Raff Technologies is built for that use case: fast, simple, reliable VPS infrastructure for teams that want performance without cloud billing complexity. --- ### What Is a VPS? A Simple Guide for Beginners (2026) URL: https://rafftechnologies.com/blog/what-is-a-vps-guide-for-beginners-2026 Published: 2026-01-24T00:00:00.000Z Description: What Is a VPS? A Simple Guide for Beginners (2026) A VPS is a private cloud server environment you can use to host websites, applications, databases, development tools, and self-hosted software without buying physical hardware. For beginners, the easiest way to understand a VPS is this: it gives you your own controllable server on the internet, with dedicated resources, root access, and more freedom than shared hosting. VPS stands for Virtual Private Server. “Virtual” means the server is created using virtualization software instead of being one entire physical machine. “Private” means your server environment is isolated from other users. “Server” means it can run websites, apps, APIs, databases, and services that other people or systems can access over the internet. At Raff Technologies, we usually explain a VPS as the first serious step after shared hosting or limited managed platforms. It gives developers, founders, SMBs, and learners a practical way to run real infrastructure without needing to own a data center, buy a server, or manage physical hardware. ## The Simple Apartment Analogy The easiest VPS analogy is housing. Shared hosting is like living in a shared hostel room. It is cheap, but you share space, performance, and limits with many other people. If another website on the same server uses too many resources, your site may slow down. A VPS is like renting your own apartment inside a larger building. You still share the physical building, but your apartment has its own walls, space, lock, and resources. What your neighbor does should not directly control your environment. A dedicated server is like renting or buying the entire building. You get maximum control, but it costs more and usually gives you more infrastructure than most beginners need. For most websites, small apps, internal tools, and development environments, a VPS is the practical middle ground: more control than shared hosting, less cost and responsibility than a dedicated physical server. ## How a VPS Works A VPS works by splitting one powerful physical server into multiple isolated virtual servers. The physical server has real CPU, RAM, storage, and networking. A virtualization layer, often called a hypervisor, divides that machine into separate environments. Each environment behaves like its own server, with its own operating system, resources, users, services, files, and network configuration. When you rent a VPS, you usually get: * CPU resources * RAM * Disk storage * Public IP address * Operating system choice * Root or administrator access * Firewall options * Remote access through SSH or RDP * Ability to install software * Ability to host websites, apps, and services This is why a VPS is more flexible than shared hosting. You are not limited to a hosting control panel or a small list of supported applications. You can configure the server based on what your project actually needs. ## VPS vs Shared Hosting Shared hosting is usually the beginner’s first hosting product. It works well for simple static sites, small WordPress websites, and users who do not want to touch server administration. The limitation is control. On shared hosting, you usually cannot install system packages, change low-level server configuration, run background workers, set up custom databases freely, or control the full runtime environment. You are using a managed slice of someone else’s server setup. A VPS gives you more control because you manage the server environment yourself. | Factor | Shared Hosting | VPS | |---|---|---| | Control | Limited | High | | Root access | Usually no | Usually yes | | Performance | Shared with many users | More isolated | | Custom software | Limited | Flexible | | Best for | Simple websites | Apps, APIs, self-hosting, growing sites | | Learning value | Low | High | | Responsibility | Lower | Higher | Choose shared hosting when you want the simplest possible website setup and do not need control. Choose a VPS when you need custom software, better isolation, root access, predictable server behavior, or a place to run real applications. ## VPS vs Cloud VM The terms VPS and cloud VM are often used together, and in many practical conversations they overlap. A VPS traditionally refers to a virtual server sold as a hosting product. A cloud VM refers to a virtual machine running on cloud infrastructure. Both give you a virtual server with CPU, RAM, storage, networking, and operating system access. The difference is usually in the platform behind it. A traditional VPS may be tied to one physical server and sold as a fixed monthly package. A modern cloud VM may run on a more flexible cloud infrastructure layer, with features such as snapshots, backups, private networking, fast provisioning, and easier scaling. For beginners, the practical takeaway is simple: both give you a server you can control. The provider’s infrastructure, reliability, pricing, storage, bandwidth, support, and security features matter more than the label alone. On Raff, a [Raff VM](/products/raff-vm) gives you a cloud server experience with clear pricing, fast deployment, NVMe storage, DDoS protection, snapshots, backups, private networking, and Linux or Windows options. ## When Do You Need a VPS? You need a VPS when your project needs more control, isolation, or flexibility than shared hosting or simple app platforms provide. A VPS makes sense when you want to: * Host a website with better control * Run a backend API * Deploy a Node.js, Python, PHP, Go, or Java app * Host multiple small projects on one server * Run Docker containers * Create a staging environment * Self-host tools such as n8n, Ghost, Plausible, or Uptime Kuma * Install custom packages * Manage your own database * Learn Linux server administration * Run scripts, workers, or scheduled jobs * Create a remote development environment * Host a client demo A VPS is not only for production hosting. It is also useful for learning, testing, development, and repeatable cloud environments. If your project has moved beyond “I just need a simple page online,” a VPS is often the next reasonable step. ## When You Do Not Need a VPS Yet A VPS is powerful, but it is not always necessary. You may not need a VPS if: * You only need a basic static website * You do not want to manage updates or security * You are not comfortable with server administration yet * Your app works perfectly on a managed platform * Your traffic is tiny and shared hosting is enough * You do not need custom packages or background services The important point is honesty. A VPS gives you control, but control comes with responsibility. You need to secure the server, update packages, configure access, monitor usage, and think about backups. For many beginners, this is a good thing because it teaches real infrastructure. But for non-technical users who only want a simple brochure site, managed hosting may be enough. ## VPS Use Cases for Beginners A VPS becomes easier to understand when you connect it to real use cases. ### Website Hosting You can use a VPS to host WordPress, Ghost CMS, static sites, landing pages, company websites, portfolios, and client projects. Compared with shared hosting, a VPS gives you more control over web server configuration, performance tuning, and security settings. If you want a content-focused website, a VPS gives you room to run Nginx, configure HTTPS, manage the database, and install the tools your site needs. ### Application Hosting A VPS is useful for hosting APIs, dashboards, SaaS apps, side projects, internal tools, and backend services. Developers often choose VPS hosting because they can install their exact runtime: Node.js, Python, PHP, Ruby, Go, Java, Docker, PostgreSQL, Redis, or whatever the app requires. For app hosting, a [Raff Linux VM](/products/linux-vm) is usually the right starting point unless your workload specifically needs Windows. ### Self-Hosted Tools Self-hosting means running software on your own infrastructure instead of using a hosted SaaS version. Popular VPS-friendly self-hosted tools include: * n8n * Plausible Analytics * Ghost CMS * Uptime Kuma * Gitea * Vaultwarden * Nextcloud * Mattermost * Coolify A VPS is a natural home for these tools because it gives you control over the environment, data, and configuration. ### Development and Testing A VPS is excellent for development environments because it gives you a clean server that is separate from your laptop. You can use it for: * Staging environments * QA testing * CI/CD runners * Docker experiments * Linux learning * Client demos * Temporary workloads This is one reason many developers eventually stop relying only on local machines. A cloud VM behaves more like production than a laptop does. For more on this idea, read [Rent a Virtual Machine, Don’t Buy Hardware](/blog/rent-virtual-machine-vs-buy-hardware). ## VPS Operating Systems: Linux or Windows? Most beginners should choose Linux for a VPS, especially Ubuntu 24.04 LTS. Ubuntu is beginner-friendly, widely documented, and works well for websites, APIs, Docker, databases, and server learning. Raff’s FAQ also recommends Ubuntu 24.04 LTS for most Linux VPS users because it balances ease of use, community support, and package availability. Choose Linux when you want to run: * WordPress * Nginx or Apache * Docker * Node.js * Python * PHP * PostgreSQL * MySQL * Redis * Open-source tools * Self-hosted apps Choose Windows Server when your workload depends on: * Remote Desktop * IIS * ASP.NET Framework * Windows-only software * Microsoft SQL Server * Active Directory-connected workflows * GUI-based Windows administration If you are unsure, read [Linux vs Windows VPS: Which Server Fits Your App?](/blog/linux-vs-windows-vps-server-choice). The operating system should match the workload, not personal preference. ## What to Look for in a VPS Provider Not all VPS providers are the same. Beginners often compare only the monthly price, but price alone is not enough. Here is what matters. ### Performance Look for modern CPUs, enough RAM, and fast storage. NVMe SSD storage is especially important because disk speed affects websites, databases, package installs, builds, and application startup time. Raff’s public pricing page highlights AMD EPYC processors, DDR5 ECC memory, NVMe SSD storage, unmetered bandwidth, and fast deployment as core infrastructure points. ### Clear Pricing Pricing should be easy to understand before you deploy. You should know what the VM costs, what storage costs, what backups cost, and whether bandwidth creates surprise charges. Raff’s pricing page positions the platform around transparent pricing, and the FAQ explains that Raff uses a subscription model with monthly, 1-year, and 2-year terms. ### Bandwidth Bandwidth matters when your website or app gets traffic. Some providers include only a limited transfer amount and charge for overages. Raff’s FAQ says data transfer is unlimited and untracked, except for suspicious or abusive usage. That makes bandwidth easier to understand for beginners. ### Backups and Snapshots A VPS should not be treated as disposable if it hosts important work. You need recovery options. Backups protect data over time. Snapshots capture server state at a point in time. Both are useful, but they are not the same thing. If your VPS hosts anything important, read [Cloud Server Backup Strategies](/learn/guides/cloud-server-backup-strategies) before you need recovery. ### Scaling Your first VPS size may not be your final size. A good provider should let you start small and grow when the workload proves it needs more resources. If you are unsure how much CPU, RAM, or storage you need, start with [Choosing the Right VM Size](/learn/guides/choosing-right-vm-size). If performance consistency matters, read [Shared vs Dedicated vCPU](/learn/guides/shared-vs-dedicated-vcpu). ### Security Features A VPS provider should make it practical to secure your server with firewall rules, private networking, SSH access, backups, and support. The provider cannot secure everything for you. But it should give you the controls you need. ## How Much Does a VPS Cost? VPS pricing depends on CPU, RAM, storage, bandwidth, operating system, backups, support, and provider infrastructure. Entry-level VPS plans are often inexpensive, but the cheapest plan is not always the best choice. A very cheap VPS may have weak performance, old storage, limited bandwidth, poor support, or oversold resources. A practical beginner approach is to choose the smallest plan that fits the workload, then monitor usage and resize when there is evidence. On Raff, the public pricing page positions cloud VPS plans from $4.99/month. Raff also publishes clear monthly pricing, supports longer subscription terms, and includes unmetered bandwidth positioning on the pricing page. For beginners, the goal is not to buy the biggest server. The goal is to buy enough server for the current workload and keep a path to grow. ## How to Get Started With Your First VPS The basic VPS setup process looks like this: 1. Choose a VPS provider. 2. Choose your operating system. 3. Select a VM size. 4. Deploy the server. 5. Connect with SSH or RDP. 6. Apply security updates. 7. Configure firewall rules. 8. Install the software you need. 9. Set up your domain and HTTPS. 10. Add backups or snapshots if the workload matters. 11. Monitor the server and resize later if needed. For most beginners on Linux, I recommend starting with Ubuntu 24.04 LTS. It is widely documented, beginner-friendly, and practical for real server work. After deploying your first Ubuntu VPS, secure it before installing your application. Follow [Secure Your Ubuntu 24.04 Server](/learn/tutorials/secure-ubuntu-24-04-server), then review [Cloud Firewall Rules Explained](/learn/guides/cloud-firewall-rules-explained) so you understand inbound rules, outbound rules, and least privilege. ## Common Beginner Mistakes The first mistake is opening too many ports. If something does not work, beginners sometimes allow everything through the firewall. Do not do that. Open only what the workload needs. The second mistake is using weak passwords or relying on password login when SSH keys would be safer. The third mistake is skipping updates. A fresh VPS should be updated before it runs important workloads. The fourth mistake is ignoring backups. If the server matters, recovery matters. The fifth mistake is choosing too large a server too early. Overprovisioning wastes money and hides the real workload requirements. The sixth mistake is putting every service on one VPS forever. A single VPS is fine at the beginning, but growing applications may eventually need separate app, database, worker, cache, or storage roles. If your app grows beyond one server, read [Single VM vs Multi-VM Architecture for SaaS Apps](/learn/guides/single-vm-vs-multi-vm-saas-architecture). ## VPS vs Managed Platforms Managed platforms such as Vercel, Netlify, Render, and similar services can be excellent for fast deployment. You push code, and the platform handles much of the server layer. The trade-off is control. A managed platform is usually easier at first, but you may run into limits around custom software, background workers, server configuration, data location, pricing, or runtime behavior. A VPS gives you more responsibility, but also more freedom. Choose a managed platform when you want the simplest deployment path and your app fits the platform’s rules. Choose a VPS when you want root access, custom configuration, self-hosted tools, background workers, or more control over cost and infrastructure. There is no universal winner. The best choice depends on how much control your project needs. ## What This Means for You If you are a beginner, a VPS is one of the best ways to learn real cloud infrastructure. It teaches you how servers work, how websites are hosted, how Linux administration feels, how firewalls protect services, how deployments behave, and why backups matter. Start small. Choose a simple workload. Deploy a clean server. Secure it properly. Install one useful application. Document what you did. Then grow from there. A VPS is not only a hosting product. It is a learning environment, development workspace, and production foundation in one. For your first Raff setup, start with a [Raff Linux VM](/products/linux-vm), compare plans on the [pricing page](/pricing), and use [Choosing the Right VM Size](/learn/guides/choosing-right-vm-size) if you are unsure which plan fits your project. ## Final Thoughts A VPS gives beginners the right balance of control, cost, and learning value. Shared hosting is easier but limited. Dedicated servers are powerful but expensive. Managed platforms are convenient but restrictive. A VPS sits in the middle: flexible enough for real work, affordable enough to start, and practical enough to grow with your project. If you want to host websites, run apps, learn Linux, self-host tools, or build real cloud skills, a VPS is one of the most useful places to begin. Start with one server. Secure it. Run something real. Then scale only when your workload asks for it. --- ### Top 10 Developer Use Cases for Cloud Virtual Machines URL: https://rafftechnologies.com/blog/top-10-developer-use-cases-for-cloud-virtual-machines Published: 2025-08-24T00:00:00.000Z Description: Top 10 Developer Use Cases for Cloud Virtual Machines I've set up a lot of VMs. Some for production workloads, some for testing wild ideas at 11pm, some because a developer messaged us asking "what tier should I use for X?" and I wanted to actually test before answering. That hands-on context is what I'm bringing to this post. Cloud VMs aren't magic. They're just computers you rent by the month — powerful, flexible ones that don't sit under your desk. But the use cases where they genuinely make your development life better are worth spelling out concretely. Here are ten I see regularly, with specific notes on what works and what to watch out for. ## 1 — Running a Persistent Development Environment Your local machine is shared: your browser, Slack, music, and four other projects all compete for CPU and RAM with whatever you're actually trying to build. A cloud VM gives you a dedicated, distraction-free environment that's always on and always ready. The practical benefit isn't just performance — it's consistency. When you SSH into your Raff VM and run your project, it behaves exactly the same way it did yesterday, last week, and three months ago. No accidental `brew upgrade` that broke your Node version. No OS update that shuffled your Python path. A Tier 3 VM (2 vCPU / 4 GB RAM) handles most development environments comfortably — running a dev server, a database, and a background worker simultaneously without swapping. If you're working with larger codebases or running build tools like webpack or esbuild on every save, Tier 4 (4 vCPU / 8 GB RAM) is where compilation times stop being annoying. ## 2 — CI/CD Pipeline Runners Running CI jobs on your local machine ties up your machine for the duration of every build. Running them on a shared CI provider means queuing. Running them on a dedicated VM means neither. A self-hosted GitHub Actions runner or GitLab Runner on a Raff VM gives you a fixed build environment you fully control. You choose the OS, the installed tools, the Node or Python version, and the available memory. There's no "runner unavailable" wait, and there's no per- minute charge that compounds across a team running dozens of builds per day. For a small team running builds for 2-3 repositories, a Tier 3 VM handles the load well. For teams with parallel jobs or longer compilation steps (Go, Rust, Java), Tier 4 or Tier 5 gives you the vCPU headroom to run multiple jobs concurrently without builds queuing behind each other. > **Tip:** Pair your CI runner VM with a [block storage volume](/products/volumes) for > caching build artefacts and Docker layers between runs. This alone can cut build times > by 40-60% on dependency-heavy projects. ## 3 — Hosting Development and Staging Servers Sending a teammate a localhost URL is a dead end — they can't access it, and you can't leave your machine running overnight. A cloud VM running your staging environment means anyone with the IP and credentials can hit it at any time. This is especially useful for: * Sharing in-progress work with non-technical stakeholders * Running end-to-end tests against a real server (not a mocked localhost) * Keeping a stable staging environment separate from your local dev loop * Webhooks that need a real public endpoint (Stripe, GitHub, Slack integrations) A Tier 2 VM (1 vCPU / 2 GB RAM) is enough for most staging environments. You're not handling real traffic — just QA, demos, and integration tests. ## 4 — Self-Hosted Automation with n8n n8n is an open-source workflow automation tool — think Zapier, but self-hosted. It connects APIs, triggers actions on schedules, processes webhooks, and chains together workflows that would otherwise require a custom script for every integration. Running n8n on a cloud VM means your automations run 24/7 without keeping your laptop open. We've seen this use case grow significantly among developers who want automation power without the per-task pricing of SaaS tools. Raff offers a [dedicated n8n VM](/products/n8n-vm) image that gets you running in minutes. For most automation workloads, a Tier 2 or Tier 3 VM is sufficient — n8n is lightweight unless you're processing very large payloads or running dozens of concurrent workflows. > **Tip:** Enable automated backups on your n8n VM. Your workflow configurations and > credentials are stored on disk — a daily backup costs almost nothing and means you can > restore a full working environment in minutes if something goes wrong. ## 5 — Isolated Experiment Environments Testing a new database, trying a different web server configuration, running a beta version of a framework — these experiments have a way of leaving traces on your local machine that cause problems weeks later. A cloud VM gives you a genuinely isolated environment. You can install whatever you want, break whatever you want, and either fix it or destroy the VM and create a fresh one from a snapshot. The experiment stays contained. The workflow I recommend: before you start an experiment, take a snapshot of the VM. Run your experiment. If it works, keep going. If it breaks, restore the snapshot and you're back to a clean state in under a minute. Raff's [snapshot feature](/products/data-protection) is available on all tiers at no fixed cost — you pay only for the storage the snapshot uses. ## 6 — Learning Linux and Server Administration If you want to get serious about Linux, DevOps, or cloud infrastructure, you need a real server to practice on. Your local VM is fine for basics, but it doesn't replicate the experience of managing a remote machine: SSH access, firewall rules, service management, log monitoring, disk management. A Tier 1 VM ($4.99/month, 1 vCPU / 1 GB RAM) is enough for learning. It runs Ubuntu or Debian comfortably, handles all the standard tooling, and costs less than a coffee per week. The 7-day free trial means you can run through an entire learning project before spending anything. Common things developers practice on a dedicated cloud VM: * Configuring Nginx or Apache as a reverse proxy * Setting up SSL certificates with Let's Encrypt * Managing systemd services * Configuring UFW firewall rules * Setting up SSH key authentication and disabling password login * Monitoring disk usage, process lists, and system logs These skills don't transfer from reading — you need to break things and fix them on a real server. ## 7 — Running Databases Separately from Application Servers A common mistake in early-stage projects is running your database on the same VM as your application. It works until it doesn't — a memory spike from your application kills your database, or a misconfigured query runs the CPU to 100% and takes down both. Separating your database onto its own VM, connected via [private networking](/products/private-cloud-networks), gives each layer its own resources and makes both easier to scale independently. A dedicated database VM on Tier 3 or Tier 4 (depending on data size and query load) with a [block storage volume](/products/volumes) attached for the data directory is a reliable setup that mirrors how production environments are actually built. > **Note:** Use Raff's private network (VPC) to connect your application VM and database VM. > Traffic between VMs on the same private network doesn't leave the data centre — it's faster > and more secure than connecting over a public IP. ## 8 — Deploying and Testing Docker Workloads Docker is easier to learn and manage on a cloud VM than on a local machine. You get a consistent Linux environment, no macOS networking quirks, no Docker Desktop memory limits, and a public IP so you can test containers that expose ports. A Tier 3 VM comfortably runs a multi-container Docker Compose stack — a web app, a database, and a cache — with room to spare. If you're building container images as part of your workflow, the faster NVMe I/O on Raff VMs makes layer reads and writes noticeably quicker than on slower storage backends. For developers learning Docker for the first time, starting with a Raff VM removes a lot of the environment-specific friction that makes local Docker setups frustrating. ## 9 — Web Scraping and Long-Running Scripts Scripts that take hours to run — web scrapers, data processors, bulk API callers — can't live on your local machine. Your laptop goes to sleep. The VPN disconnects. You need the terminal tab to stay open. A cloud VM runs your scripts 24/7 with no interruptions. SSH in, start your script in a `tmux` or `screen` session, disconnect, and come back when it's done. The process keeps running regardless of what happens on your local machine. For scraping and data processing workloads, the right tier depends on how CPU-intensive your processing is. Pure I/O-bound scrapers run fine on Tier 2. If you're doing heavy parsing, image processing, or running headless browsers (Playwright, Puppeteer), Tier 3 or Tier 4 gives you the CPU to handle concurrent workers without throttling. ## 10 — Building Your Portfolio: Always-On Project Hosting Side projects that only run when your laptop is open aren't impressive to show people. A cloud VM that hosts your project at a real domain, with HTTPS, running 24/7 — that's something you can put on a resume and send to a hiring manager at midnight. A Tier 2 VM ($9.99/month) running Nginx, a Node.js or Python app, and a small database handles portfolio-scale traffic comfortably. Add a free SSL certificate from Let's Encrypt, point your domain, and your side project looks like a real product. This is one of the most underrated uses of a cheap cloud VM — the professional credibility of having your work actually live on the internet, not just in a GitHub repo. ## What This Means for You The pattern across all ten use cases is the same: a cloud VM gives you a computer that's always on, always available, and completely yours to configure. It removes the constraints of your local machine — power management, shared resources, environment pollution — without adding complexity. Most of the use cases above work fine on a Tier 2 or Tier 3 [Linux VM](/products/linux-vm). Start there, watch your actual CPU and RAM usage for a week, and resize up if the numbers tell you to. Raff's monthly billing means you're not locked into anything. If you're not sure which tier fits your specific use case, the [pricing page](/pricing) has the full breakdown. Or just try it — the 7-day free trial gives you enough time to run through a real workload and see how it performs. --- ### Why We Standardized on AMD EPYC for Raff Cloud Servers URL: https://rafftechnologies.com/blog/why-we-chose-amd-epyc-for-raff-s-cloud-infrastructure Published: 2025-07-18T00:00:00.000Z Description: Why We Standardized on AMD EPYC for Raff Cloud Servers ## AMD EPYC is part of how we keep Raff consistent We chose AMD EPYC for Raff Technologies because we wanted one modern CPU foundation across the platform, not a mixed hardware story that changes depending on where a VM lands. For a cloud provider, that matters more than a benchmark screenshot. The processor decision affects pricing discipline, virtualization consistency, and how predictable the platform feels once users move beyond one small server. A lot of infrastructure vendors talk about CPUs like they are decorative specs. I think that misses the real point. A cloud customer is not buying a chip in isolation. They are buying the experience that sits on top of that hardware: VM responsiveness, stable virtualization behavior, cleaner performance expectations, and a platform that does not quietly shift character between plans or hosts. That is why this was not a spec-sheet decision for us. It was a platform decision. ## We did not want mixed expectations across the product One of the things I dislike in cloud infrastructure is silent inconsistency. A platform can look simple from the outside while behaving differently depending on host generation, CPU family, or which hardware pool a workload lands on. That may be operationally normal for some providers, but it creates the wrong experience for users. A developer should not have to wonder whether one VM feels different from another because the provider made a quiet hardware trade-off in the background. Standardizing on AMD EPYC helped us avoid that kind of fragmentation. The point was not just modern server performance. The point was to give Raff a cleaner baseline across the platform so Linux VMs, storage-heavy workloads, and everyday development environments all sit on infrastructure chosen with consistency in mind. ## CPU choice changes more than raw speed A lot of people think CPU selection is mostly about “faster” versus “slower.” In a cloud platform, the decision reaches much further than that. It affects: * how well the platform behaves under virtualization, * how confidently you can define VM tiers, * how predictable the price-to-performance story stays, * and whether the infrastructure feels current or patched together. That is the real reason I think CPU choice deserves a stronger explanation than most providers give it. At Raff, we are not selling processors. We are selling cloud infrastructure that people use for web apps, databases, containers, CI pipelines, and development environments. The hardware layer should support those workloads cleanly. If it does not, the rest of the stack inherits that weakness. ## Virtualization quality mattered more than marketing value This is the part I care about most. Raff is built around virtual machines. That means the hardware decision had to make sense specifically in a virtualization-heavy environment. We were not picking a processor because it looked good in a rack spec sheet. We were choosing the foundation underneath the VM experience itself. That changes the evaluation. The real question becomes: * does this hardware support clean VM performance? * does it fit the platform we want to build? * does it help the cloud product stay understandable as it grows? For us, AMD EPYC made sense because it aligned with the kind of virtualization-first platform we wanted to build, not just the kind of marketing sentence we wanted to publish. ## The decision was also about economics This is where hardware and product philosophy meet. A lot of infrastructure choices look strong technically and weak economically. The hardware may be impressive, but if it pushes the platform toward the wrong pricing logic, the customer eventually pays for that inefficiency. We did not want that. We wanted hardware that supported a practical platform — one where the cloud product above it could stay rational, modern, and predictable as we expanded VMs, storage, networking, and protection layers. That is one reason this decision fits the rest of Raff so well. It supports a platform built around AMD EPYC, NVMe-backed infrastructure, fast provisioning, and pricing clarity instead of one where “premium hardware” becomes a separate upsell category later. Raff’s public site already reflects that broader positioning: AMD EPYC, NVMe, fast deployment, and pricing starting from $4.99/month are presented as part of one infrastructure story, not separate premium tiers. ([Raff Technologies][1]) That is the more useful frame: not “which CPU sounds most impressive?” but “which hardware lets us build the right cloud product on top?” ## Why this matters to users A user does not need to memorize EPYC model numbers for this decision to matter. The practical benefit is that the platform is built on hardware chosen for the right reasons: * a cleaner VM baseline, * a more current infrastructure layer, * stronger alignment with virtualization-heavy workloads, * and a better long-term performance story for the product above it. That is also why we do not think of AMD EPYC as a standalone bragging point. It matters together with the rest of the platform: [Linux VMs](/products/linux-vm), [private cloud networks](/products/private-cloud-networks), [data protection](/products/data-protection), and the broader architecture choices underneath Raff. The CPU is not the product. But it absolutely shapes the product. ## Why this page exists now This is also part of why I wanted this post to be more specific than the usual “AMD is powerful” article. That angle already exists everywhere, including on our own site. The more useful explanation is not that AMD has become important in cloud. The more useful explanation is why we standardized on it for Raff specifically, and what that says about the kind of platform we are building. That distinction matters for search too. People searching for AMD EPYC in cloud infrastructure are not only asking whether the processor is good. They are often really asking what that hardware choice means for VM consistency, virtualization, pricing, and long-term platform design. That is the question I actually wanted to answer. ## What This Means for You If you are evaluating cloud infrastructure, I would look past CPU branding as a decorative spec and ask a more useful question: What does the processor choice say about the platform behind it? Does it look like the provider chose hardware that supports a coherent cloud experience, or just something easy to advertise? Does the rest of the stack make sense around that decision? Will the platform still feel predictable when you add storage, networking, backups, and more demanding workloads? That is the better question. At Raff, AMD EPYC is not there to make a product page look modern. It is part of a larger infrastructure philosophy: build on current hardware, keep the platform understandable, and let the layers above it grow in the right order. If you want to see how that shows up in practice, start with [Linux VMs](/products/linux-vm), then look at how the broader platform connects through [object storage](/products/object-storage), [private networking](/products/private-cloud-networks), and [data protection](/products/data-protection). That is where the decision makes the most sense. Not as a chip choice in isolation. As part of the kind of cloud platform we are trying to build. [1]: https://rafftechnologies.com/?utm_source=chatgpt.com "Raff Cloud Servers & VPS Hosting | From $4.99/mo" --- ### Simple and Affordable Cloud Infrastructure for Small Teams URL: https://rafftechnologies.com/blog/simple-and-affordable-cloud-power-for-sm-bs-startups-and-learners Published: 2025-04-14T00:00:00.000Z Description: Simple and Affordable Cloud Infrastructure for Small Teams ## In short Small teams usually do not need the largest cloud service catalog. They need infrastructure they can understand, deploy, secure, back up, and grow without turning every decision into a separate project. A practical starting point is often one right-sized VM, clear storage, restricted networking, backups, and a documented owner for the operating system and application. Raff focuses on those core building blocks for developers, startups, SMBs, and learners. Current plans and product availability should always be checked on the live product and pricing pages rather than copied from an old article. ## Why small teams struggle with cloud complexity The problem is rarely a lack of available services. It is the amount of attention required to choose, connect, price, and operate them. Small teams often need to: - host an application or website; - run a Windows business workload; - create a development or staging server; - self-host an internal tool; - store files or backups; - give a remote team access to one controlled environment. These workloads do not always justify a complex platform architecture on day one. ## Start with the workload, not the cloud catalog Before choosing infrastructure, answer: 1. What must run? 2. Which operating system does it require? 3. How many users or requests will it serve? 4. How much data will it store? 5. Which services need public access? 6. What must be backed up? 7. Who will maintain it? This usually leads to a simpler and more defensible first design. ## The building blocks most teams need first ### Virtual machines A VM gives the team a clear compute environment for applications, APIs, databases, development, remote work, and self-hosted software. Use Linux when the application stack supports it and Windows when the workload depends on Windows Server, RDP, or supported Windows business applications. ### Storage Separate operating-system capacity from growing application data when the workload justifies it. Plan for database growth, uploads, logs, reports, and backups instead of sizing only for installation day. ### Private networking Internal databases and services should not be exposed publicly merely because another VM needs to reach them. Private networking helps create cleaner service boundaries. ### Backups and snapshots Snapshots are useful before risky changes. Backups and restore testing are needed when the data or application matters to the business. ### Recovery access Browser console access provides another way to reach a VM when normal SSH or RDP access is broken. ## Simplicity does not remove responsibility A simpler platform still requires operational ownership. Customers running their own VMs remain responsible for: - operating-system updates; - administrator accounts; - application deployment; - firewall configuration; - database maintenance; - monitoring; - backups and restore testing; - incident response. The goal of simplicity is to reduce unnecessary friction, not to hide these responsibilities. ## When a broader platform is the better fit A hyperscale or highly managed platform may be more appropriate when the team needs: - many global regions; - a large managed-service catalog; - advanced enterprise governance; - native serverless or analytics ecosystems; - organization-wide cloud standards already built around another provider; - a fully managed application platform instead of VM administration. The best platform is the one that matches the team's current operational capability and workload—not the one with the longest feature list. ## A practical small-team architecture ```text Users | v One public application VM | +-- Application service +-- Reverse proxy +-- Monitoring | v Private database or internal service | v Backups and recovery copies ``` Start with one understandable environment. Separate services when performance, security, team ownership, or recovery requirements create a real reason. ## How Raff fits Raff provides Linux and Windows VMs, block storage, private networking, security controls, snapshots, backups, and browser console access for practical cloud workloads. Use [Linux VM](/products/linux-vm), [Windows VM](/products/windows-vm), [Volumes](/products/volumes), [Private Cloud Networks](/products/private-cloud-networks), and [Data Protection](/products/data-protection) to evaluate the building blocks your workload actually needs. Review the live [pricing page](/pricing) for current plan information. :::cta Learn More Explore practical cloud building blocks without unnecessary platform complexity. ::: ## Final takeaway Small teams should not buy complexity in anticipation of every possible future. Start with infrastructure the team can operate confidently, measure the workload, and add new layers when a clear requirement appears. Simple cloud infrastructure is not limited infrastructure. It is infrastructure whose purpose, cost, ownership, and recovery path remain understandable. --- ### We Built Raff for Developers Who Outgrow Shared Hosting URL: https://rafftechnologies.com/blog/developers-who-outgrow-shared-hosting Published: 2026-04-27T00:00:00.000Z Description: We Built Raff for Developers Who Outgrow Shared Hosting ## In short Shared hosting works well for simple websites, but developers often outgrow it when they need Docker, background workers, custom runtimes, server-level configuration, private services, staging environments, or more control over deployment. A cloud VM is the next step when the project needs an operating environment you can manage directly. That control also brings responsibility for updates, security, backups, monitoring, and application configuration. Raff was built for teams that need a practical path from limited hosting to real Linux or Windows infrastructure without starting with an oversized cloud architecture. ## The moment shared hosting stops being enough Shared hosting is designed to simplify website publishing. The provider controls most of the server and exposes a limited set of tools through a hosting panel. That model becomes restrictive when the workload requires: - Docker or custom system packages; - background jobs and queues; - application servers and APIs; - custom versions of Node.js, Python, PHP, Java, or .NET; - database configuration beyond the hosting plan; - SSH and root-level administration; - staging or test environments; - private networking between services; - predictable resource allocation. At that point, the problem is no longer the website plan. The project has become infrastructure. ## What a VM changes A cloud VM gives you an operating system you control. You decide what runs, which ports are open, how services are configured, and how deployments are performed. | Shared hosting | Cloud VM | |---|---| | Provider-managed environment | Customer-managed operating system | | Limited packages and runtimes | Install supported software directly | | Panel-based workflow | SSH, RDP, scripts, APIs, and automation | | Designed mainly for websites | Suitable for apps, APIs, tools, and services | | Provider controls server configuration | Customer controls server configuration | | Less operational responsibility | More control and more responsibility | A VM is not automatically better. It is better when the workload needs that control. ## Do not move before the project is ready Stay with shared hosting when: - the site is simple and stable; - no custom server software is required; - the hosting provider handles the needed backups and maintenance; - nobody on the team can own server administration; - the current platform meets performance and support needs. Move to a VM when the limits are blocking product or operational work—not because a VM sounds more advanced. ## Plan the first VM around one real workload A first migration should remain understandable. A common starting pattern is: ```text Users | v Nginx or another web server | v Application service | +-- Background worker +-- Local or private database +-- Monitoring | v Backups and recovery copies ``` Keep the architecture small until traffic, security, or recovery requirements justify separating roles. ## Responsibilities that move to your team With a VM, your team normally owns: - operating-system updates; - application deployment; - SSH or RDP access; - firewall configuration; - database maintenance; - monitoring and alerts; - backup design and restore testing; - incident response; - capacity planning. The infrastructure provider supplies the VM platform, but it does not automatically operate everything installed inside the server. ## Migration checklist Before leaving shared hosting: 1. Inventory domains, files, databases, email dependencies, cron jobs, and certificates. 2. Confirm the new VM supports the application stack. 3. Build a test environment before changing DNS. 4. Configure firewall rules and administrator access. 5. Copy the application and database. 6. Test uploads, forms, background jobs, and scheduled tasks. 7. Configure backups and perform a restore test. 8. Lower DNS TTL before cutover where appropriate. 9. Keep the old environment available during validation. 10. Monitor errors and resource usage after launch. ## How Raff fits Raff offers Linux and Windows VMs with root or administrator access, NVMe storage, firewall controls, private networking, snapshots, backups, and browser console access. Use [Linux VM](/products/linux-vm) for Linux applications and self-hosted tools, [Windows VM](/products/windows-vm) for supported Windows workloads, and the [Learn Hub](/learn) for practical deployment guidance. Review the live [pricing page](/pricing) after estimating the workload instead of choosing from an old hard-coded price. :::cta Explore Raff VM Move beyond shared hosting when your workload needs real control. ::: ## Final takeaway Shared hosting is a good starting point. A VM becomes the better tool when hosting limitations prevent you from operating the application correctly. The goal is not to add complexity. It is to gain the specific control the project now requires while keeping the first infrastructure design simple, recoverable, and supportable. --- ### Why More MSPs Should Offer a U.S.-Hosted Infrastructure Option URL: https://rafftechnologies.com/blog/why-more-msps-should-offer-us-hosted-infrastructure-option Published: 2026-04-22T00:00:00.000Z Description: Why More MSPs Should Offer a U.S.-Hosted Infrastructure Option ## In short A U.S.-hosted infrastructure option helps MSPs give clients a clearer answer about where workloads run, who manages them, and how remote users, applications, backups, and internal services are connected. It can improve service packaging for U.S.-focused clients, but location alone does not guarantee compliance, low latency, or security. The MSP still needs to define access, data handling, backups, recovery, monitoring, and support ownership. ## Why hosting location matters to MSP clients Clients often ask simple questions before they ask technical ones: - Where is the workload hosted? - Is the environment staying in the United States? - Who can access it? - What happens if the server fails? - Can the MSP move or recover it later? A clear U.S.-hosted option makes these conversations easier to document in proposals, onboarding records, and service descriptions. ## It creates a more repeatable service package MSPs scale more effectively when each client environment follows a known pattern. A repeatable U.S.-hosted package might define: - supported Linux or Windows VM sizes; - standard firewall rules; - private-network layout; - backup and retention options; - monitoring requirements; - administrator access; - escalation and recovery responsibilities. This reduces one-off decisions and makes support handoffs easier. ## Geography is not compliance U.S. hosting may support a client's data-location preference, but it should not be marketed as automatic compliance. Compliance depends on the full system: contracts, access controls, encryption requirements, data processing, retention, logging, incident response, and the customer's industry obligations. The MSP should use precise language such as “U.S.-hosted infrastructure” rather than making unsupported legal or certification claims. ## Private networking strengthens the design A useful MSP environment separates public and internal services. ```text Client users | v Approved public or remote-access endpoint | v Client VM environment | +-- Application server +-- Windows business server +-- Internal tools | v Private database, storage, or support service ``` Private networking can reduce public exposure, but every service still needs authentication, least privilege, and logging. ## Good MSP use cases A U.S.-hosted option is especially useful for: - Windows business applications and RDP environments; - client file and application servers; - Linux application hosting; - dedicated client infrastructure; - backup and disaster-recovery targets; - test and migration environments; - SaaS and agency client workloads; - internal tools used by U.S.-based teams. ## Questions to answer before standardizing The MSP should define: 1. Which workloads are supported? 2. Which operating systems and applications are allowed? 3. Who owns OS and application updates? 4. How are administrator accounts managed? 5. Which backup layers are included? 6. Who tests restores? 7. What is the response process when a client is locked out? 8. How are client environments separated? 9. What must remain local or vendor-hosted? ## How Raff fits Raff provides U.S.-hosted Linux and Windows VM infrastructure with firewall controls, private networking, snapshots, backups, and browser console access. The MSP remains responsible for client architecture, user access, application licensing, workload security, monitoring, backup policy, and support delivery. Review [U.S. Cloud Server](/products/us-cloud-server), [Windows VM](/products/windows-vm), [Linux VM](/products/linux-vm), [Private Cloud Networks](/products/private-cloud-networks), and [Data Protection](/products/data-protection) when designing a repeatable client service. :::cta Explore US Cloud Server Standardize U.S.-hosted client environments with clearer operational boundaries. ::: ## Final takeaway For MSPs, hosting geography is part of the service story—not the whole service. The real value comes from pairing a clear U.S.-hosted option with repeatable architecture, controlled access, documented recovery, and honest responsibility boundaries. --- ### Access Your VM Anywhere with the Raff VNC Console URL: https://rafftechnologies.com/blog/access-your-vm-anywhere-with-our-new-vnc-console Published: 2025-08-17T00:00:00.000Z Description: Access Your VM Anywhere with the Raff VNC Console ## In short The Raff VNC Console gives you browser-based access to a virtual machine when normal SSH or RDP access is unavailable. It is most valuable as a recovery path after a firewall mistake, broken network configuration, failed remote-access service, or boot problem. It should not replace secure day-to-day administration. Use SSH for normal Linux management and RDP for supported Windows workflows. Use the VNC Console when the normal network path is broken or direct console visibility is required. ## Why a second access path matters Remote administration normally depends on the guest operating system, its network stack, firewall rules, and SSH or RDP service. If one of those components is misconfigured, the same path needed to fix the server may no longer work. Browser console access provides a separate way to inspect and repair the machine. ## When to use the VNC Console ### After a firewall lockout A rule may close SSH or RDP, restrict the wrong source address, or block required traffic. The VNC Console lets you reach the operating system and correct the configuration. ### When SSH or RDP fails The service may be stopped, misconfigured, or unable to start after an update. Console access lets you inspect logs, restart services, and correct configuration files. ### During boot problems If a VM does not complete startup normally, a network connection may never become available. Console visibility can reveal boot prompts, filesystem problems, or service failures that are otherwise difficult to diagnose. ### During network reconfiguration Changes to interfaces, routes, DNS, or guest firewall settings can interrupt connectivity. A separate console path reduces the risk of turning a recoverable change into a rebuild. ## What the VNC Console does not replace The console is not a substitute for: - SSH keys and restricted Linux administration; - secure RDP or RDS design; - operating-system updates; - cloud firewall rules; - backups and snapshots; - monitoring and logging; - a tested recovery plan. It is one layer in a broader resilience strategy. ## A safer change workflow Before a risky change: 1. Confirm you can open the VNC Console. 2. Create a snapshot or backup where appropriate. 3. Record the current network or access configuration. 4. Apply one controlled change at a time. 5. Test SSH or RDP from a separate session. 6. Keep the console open until the new configuration is confirmed. This is especially useful when changing firewall rules, SSH settings, RDP policies, network interfaces, or authentication configuration. ## Shared responsibility still applies Raff provides the browser console and the underlying VM infrastructure. Customers remain responsible for guest operating-system configuration, user accounts, firewall rules inside the VM, SSH or RDP security, application access, and recovery decisions. A console can help you repair a configuration problem, but it cannot replace good access control or a backup strategy. ## How Raff fits The VNC Console is available as part of the Raff VM management experience for supported workloads. Pair it with [Security](/products/security), [Data Protection](/products/data-protection), [Linux VM](/products/linux-vm), or [Windows VM](/products/windows-vm) depending on the environment you operate. :::cta Deploy Your Server Launch a VM with browser-based recovery access available when needed. ::: ## Final takeaway The best recovery tool is the one that exists before the lockout happens. Use the Raff VNC Console as an independent access path, keep regular administration on secure protocols, and protect important workloads with tested backups and rollback procedures. --- ### 7 Mistakes Developers Make When Choosing a Cloud VPS URL: https://rafftechnologies.com/blog/cloud-vps-mistakes-2026 Published: 2026-03-19T00:00:00.000Z Description: 7 Mistakes Developers Make When Choosing a Cloud VPS ## In short The most expensive VPS mistakes usually come from choosing only by headline price and ignoring what happens after deployment. Developers should evaluate sizing, storage, bandwidth policy, resize paths, backups, security controls, support boundaries, and migration risk before committing. A VPS is not just CPU, RAM, and disk. It becomes part of the way your team deploys, recovers, scales, and operates. ## Mistake 1: choosing by price alone A low monthly price can hide important trade-offs: limited storage, capped transfer, paid backups, rigid upgrades, or weak recovery options. Compare the complete operating cost, not one number. Include storage growth, backup retention, support time, migration effort, and the impact of downtime. Use the live [Raff pricing page](/pricing) for current plans rather than relying on figures embedded in an older article. ## Mistake 2: sizing only for today's workload A server that works during launch may struggle after adding background jobs, more users, larger databases, monitoring, or staging services. Start lean, but confirm the provider gives you a practical resize path. Monitor CPU, memory, disk latency, and storage growth so scaling decisions are based on evidence. ## Mistake 3: ignoring storage performance Slow storage can make package installation, container builds, database queries, backups, and deployments feel inconsistent even when CPU usage looks normal. Ask what storage technology is used, how much capacity is included, and whether extra block storage can be added without rebuilding the VM. ## Mistake 4: treating bandwidth as a footnote Applications that serve files, APIs, media, backups, or synchronization traffic can grow faster than expected. Review whether bandwidth is metered, what fair-use rules apply, and whether traffic growth could create unexpected cost or throttling. Bandwidth policy should be understood before a successful launch changes usage patterns. ## Mistake 5: assuming a snapshot is a backup strategy Snapshots are useful before upgrades, configuration changes, and migrations. They are not automatically a complete backup plan. A production workload may also need database-aware backups, file-level recovery, off-server copies, retention rules, and restore testing. A backup process is only proven when the team can restore the application and its data successfully. ## Mistake 6: exposing services before designing access New servers are often deployed with broad SSH, RDP, database, or administration access because it is convenient during setup. Instead: - expose only required ports; - use named administrator accounts; - restrict source networks where practical; - keep databases and internal services private; - separate daily users from privileged accounts; - patch the OS and applications deliberately. Infrastructure controls and customer configuration are both required. A provider cannot protect a weak password, leaked key, outdated package, or public database inside a customer-managed VM. ## Mistake 7: choosing a platform with no clear recovery or support boundary Before deploying, know who owns: - operating-system updates; - application configuration; - database maintenance; - backups and restores; - firewall rules; - monitoring; - incident response; - migration and rollback. A platform may provide infrastructure support without managing everything installed inside the VM. This boundary should be clear before a production issue occurs. ## A practical VPS evaluation table | Decision area | Question to ask | |---|---| | Compute | Can the VM be resized when the workload changes? | | Storage | Is storage fast enough and expandable? | | Network | Is bandwidth predictable and are private networks available? | | Security | Can public access be restricted easily? | | Recovery | Are snapshots, backups, and restore paths available? | | Operations | Is browser console or recovery access available? | | Support | Who handles the platform, OS, application, and database? | | Migration | Can the workload be moved without rebuilding everything? | ## How Raff fits Raff provides Linux and Windows VMs with NVMe storage, cloud firewall controls, private networking, snapshots, backups, and browser console access. Customers remain responsible for the operating system, applications, identities, databases, workload security, and recovery acceptance. Review [Linux VM](/products/linux-vm), [Windows VM](/products/windows-vm), [Volumes](/products/volumes), [Security](/products/security), and [Data Protection](/products/data-protection) when comparing the complete environment. :::cta View Pricing Compare current VM options after defining your real workload needs. ::: ## Final checklist Before choosing a VPS, confirm: 1. The application and operating system are supported. 2. The starting size is based on a real workload. 3. Storage and bandwidth policies are understood. 4. Resize and migration paths are documented. 5. Public ports are minimized. 6. Backups and restores have an owner. 7. Support responsibilities are clear. The best VPS is not the one that looks cheapest on day one. It is the one that remains practical when the workload becomes real. --- ### What to Host on a U.S.-Based Cloud Server URL: https://rafftechnologies.com/blog/what-to-host-us-based-cloud-server-2026 Published: 2026-03-18T00:00:00.000Z Description: What to Host on a U.S.-Based Cloud Server ## In short A U.S.-based cloud server is a strong fit when most users, customers, integrations, or operators are in North America. Common workloads include web applications, APIs, background workers, internal tools, self-hosted software, databases placed near the application, and Windows business workloads. Location alone does not guarantee speed, compliance, or reliability. The right choice also depends on user geography, application architecture, network paths, data requirements, backups, and operational ownership. Raff provides U.S.-hosted infrastructure for teams that need practical Linux or Windows compute. Customers remain responsible for application design, data classification, security configuration, and legal or compliance decisions. ## Workloads that usually benefit from U.S. hosting ### Customer-facing applications Web applications, SaaS dashboards, portals, and e-commerce backends benefit when the origin infrastructure is close to the users who make most requests. A CDN may distribute static content globally, but application logic and database calls still depend on the origin architecture. ### APIs and integration services Place APIs near the systems and users they communicate with most frequently. U.S.-based hosting can be useful for applications integrated with U.S.-based payment, communications, developer, and business services. Do not assume geography eliminates timeout or reliability problems. Use retries, idempotency, queueing, and monitoring for important integrations. ### Databases near the application The application and its primary database should usually be in the same location or private network unless a deliberate distributed design requires otherwise. Avoid exposing database ports publicly. Use private networking, restricted accounts, application-aware backups, and tested restores. ### Background workers and scheduled jobs Queue workers, data imports, reporting jobs, webhooks, automation tasks, and scheduled scripts are good VM workloads when they need a stable environment and do not justify a larger platform. Separate these jobs from the public application when resource spikes or security boundaries make that useful. ### Internal tools Monitoring dashboards, admin tools, CI runners, documentation services, and private business applications can fit U.S.-based infrastructure when the team primarily operates in North America. Restrict internal tools by identity and network policy instead of relying on obscure URLs. ### Windows business workloads Remote Desktop, supported accounting or ERP applications, shared business files, legacy Windows software, and office-server replacement can fit a U.S.-hosted Windows VM. Confirm software compatibility, Microsoft and application licensing, RDS requirements, printers, integrations, and backup responsibilities before migration. ## Workloads that need more careful evaluation ### Global applications A single U.S. server may be sufficient for an early product, but globally distributed users can experience different latency. Measure real user performance before introducing multi-region complexity. ### Regulated or sensitive data U.S. hosting does not automatically make a workload compliant. Data location is only one part of privacy, contractual, industry, and regulatory obligations. ### GPU-intensive workloads Do not assume a general-purpose cloud VM includes GPU capacity. Training, rendering, and other accelerator-dependent workloads require infrastructure designed and explicitly offered for that purpose. ### High-availability systems One VM is one failure domain. Applications with strict uptime requirements need redundancy, health checks, database recovery, and a tested failover design. ## A practical starter architecture ```text Users | v Public application endpoint | v Linux or Windows VM | +-- Application +-- Background services +-- Monitoring agent | v Private database or internal service | v Backups and recovery copies ``` Start with the simplest architecture that satisfies the current workload, then separate roles when performance, security, or recovery requirements justify it. ## Security and recovery basics A production U.S.-hosted server should include: - only required public ports; - named administrator accounts; - current operating-system and application patches; - private connectivity for internal services; - database and file backups; - snapshots before risky changes; - monitoring for CPU, memory, storage, errors, and failed logins; - a tested restore or rebuild process. Infrastructure protection and customer configuration work together. The provider cannot secure an outdated application, leaked credential, or publicly exposed database inside a customer-managed VM. ## How Raff fits Raff supports U.S.-hosted Linux and Windows VM workloads with NVMe storage, firewall controls, private networking, snapshots, backups, and browser console access. Use [Linux VM](/products/linux-vm) for Linux applications and infrastructure, [Windows VM](/products/windows-vm) for supported Windows workloads, [Private Cloud Networks](/products/private-cloud-networks) for internal traffic, and [Data Protection](/products/data-protection) for recovery planning. Review the live [pricing page](/pricing) for current plans rather than relying on a fixed figure in an article. :::cta Explore US Cloud Server Place North American workloads on practical U.S.-hosted infrastructure. ::: ## Placement checklist Before choosing a U.S.-based server, confirm: 1. Where are the majority of users and operators? 2. Where are the application's key integrations? 3. Can the application and database stay close together? 4. Does the workload need local hardware or another region? 5. What data-location obligations apply? 6. What happens if the VM or internet path becomes unavailable? 7. Who owns updates, security, backups, and recovery? The right location is the one that best matches the workload—not the one with the strongest marketing label. --- ### MCP Server Security: Run AI Agents Without Leaking Secrets URL: https://rafftechnologies.com/blog/mcp-server-security-2026 Published: 2026-03-23T00:00:00.000Z Description: MCP Server Security: Run AI Agents Without Leaking Secrets ## In short An MCP server should be treated like a privileged production backend, not a harmless AI add-on. It can connect models to files, databases, APIs, internal tools, and credentials, so a weak design can turn prompt injection or excessive permissions into a real infrastructure incident. The safest architecture keeps secrets outside model context, exposes narrowly scoped tools, validates every action, isolates the MCP service from unrelated workloads, and records sensitive operations for review. Raff can provide the Linux VM, firewall controls, private networking, backups, and recovery access underneath this architecture. The customer remains responsible for the MCP implementation, tool permissions, application security, secrets, logging, and incident response. ## Why MCP servers create a different risk Traditional APIs expose predetermined endpoints. MCP servers allow an AI system to discover and call tools based on user input and model reasoning. That creates three linked risks: 1. **Prompt injection:** untrusted content influences which tool the model calls. 2. **Over-privileged tools:** one tool can read, write, delete, or administer more than the task requires. 3. **Secret exposure:** credentials appear in prompts, logs, tool output, files, or environment dumps. A secure MCP design assumes the model can make a bad decision and limits the damage that decision can cause. ## Keep secrets outside model context Do not place API keys, database passwords, private tokens, or administrator credentials in prompts or tool descriptions. Use a backend execution layer that retrieves credentials only when an approved tool action is executed. The model should request an operation such as `create_support_ticket` or `read_invoice_status`, not receive the raw credential used to perform it. Also review logs. Debug logging can unintentionally capture headers, environment variables, tool arguments, user data, and full third-party responses. ## Use narrow tools instead of broad access Avoid tools such as: - `run_any_sql` - `execute_shell_command` - `read_any_file` - `call_any_api` - `manage_all_users` Prefer task-specific tools such as: - `get_customer_by_id` - `create_draft_invoice` - `read_deployment_status` - `restart_staging_service` - `search_approved_documents` Each tool should define allowed inputs, output limits, authorization rules, timeouts, and failure behavior. ## Put a policy layer between the model and external systems A practical architecture is: ```text User request | v AI model | v MCP server | v Policy and validation layer | +-- Authentication +-- Authorization +-- Input validation +-- Rate limits +-- Approval rules +-- Audit logging | v Approved API, database, or internal service ``` The model proposes an action. The policy layer decides whether that action is allowed. High-impact actions such as deleting data, changing permissions, sending payments, publishing content, or accessing sensitive records should require additional checks or human approval. ## Isolate the MCP service Run production MCP services separately from unrelated applications and development environments. A stronger deployment normally includes: - a dedicated VM or isolated service boundary; - no unnecessary public ports; - restricted outbound access; - private connectivity to internal services; - separate development and production credentials; - non-administrator service accounts; - independent logs and monitoring. Private networking reduces public exposure, but it does not replace authentication or authorization. A private service can still be abused by a compromised internal workload. ## Defend against prompt injection Prompt injection cannot be solved with one system prompt. Reduce risk by combining: - strict tool schemas; - untrusted-content labeling; - allowlisted actions; - output validation; - data-access boundaries; - human confirmation for destructive operations; - separate read and write tools; - monitoring for unusual tool sequences. Never let content retrieved from a webpage, email, uploaded document, or database record automatically redefine security policy. ## Logging without leaking data Audit logs should answer: - who initiated the request; - which tool was called; - what resource was targeted; - whether the action was approved; - when it occurred; - whether it succeeded; - which policy rule applied. Logs should not store raw secrets, unnecessary personal data, full authentication headers, or unrestricted model context. ## Backups and recovery still matter Security controls reduce risk but do not eliminate mistakes. An agent may still modify the wrong record, trigger a faulty integration, or expose an application bug. Plan: - database backups; - versioned configuration; - snapshots before major changes; - rollback procedures; - credential rotation; - a method to disable tools quickly; - restore tests for critical systems. ## How Raff fits Raff Linux VMs can host MCP services with root access, NVMe storage, firewall controls, private networking, snapshots, backups, and browser console access. Raff provides the infrastructure layer. Customers remain responsible for application code, model behavior, MCP tool design, secrets, permissions, monitoring, and compliance decisions. Review [Linux VM](/products/linux-vm), [Private Cloud Networks](/products/private-cloud-networks), [Security](/products/security), and [Data Protection](/products/data-protection) when designing the environment. :::cta Explore Security Build stronger boundaries around agents, tools, secrets, and services. ::: ## Production checklist Before launching an MCP server, confirm: - secrets never enter prompts or model-visible output; - tools are narrowly scoped; - destructive actions require stronger approval; - development and production are separated; - public exposure is minimized; - outbound network access is restricted; - logs exclude sensitive values; - tool usage is auditable; - credentials can be rotated quickly; - backups and rollback have been tested. The central principle is simple: the model should never have more authority than the task requires. --- ### Why Self-Hosted CI Runners Still Make Sense for Small Teams URL: https://rafftechnologies.com/blog/self-hosted-ci-runners-2026 Published: 2026-03-23T00:00:00.000Z Description: Why Self-Hosted CI Runners Still Make Sense for Small Teams ## In short Self-hosted CI runners still make sense for small teams when builds are frequent, resource-intensive, dependent on custom tooling, or slowed down by repeated downloads and cold caches. The benefit is control: you choose the operating system, CPU and memory, installed packages, network access, cache strategy, and runner lifecycle. The trade-off is responsibility. Your team must secure, patch, monitor, clean, and replace the runner instead of delegating those tasks to a managed CI provider. A good first design is usually one dedicated Linux VM for CI, isolated from production, with restricted repository access and no inbound public services unless they are truly required. ## What a self-hosted CI runner actually changes A managed runner is temporary infrastructure supplied by the CI platform. A self-hosted runner is infrastructure that your team operates and registers with the CI system. ```text Source repository | v CI platform and job queue | v Dedicated self-hosted runner | +-- Build and test +-- Reuse approved caches +-- Build container images +-- Publish artifacts +-- Deploy through restricted credentials ``` The CI platform still handles workflow definitions, job scheduling, and repository integration. Your runner handles the actual execution. ## When self-hosting creates real value ### Frequent builds A persistent runner can reuse package, compiler, and container caches between jobs. That can reduce repeated network downloads and setup work. Caching should remain controlled. A cache can become stale, consume the disk, or allow one workflow to influence another. Define cache keys, expiration rules, disk thresholds, and cleanup jobs instead of treating persistence as automatically beneficial. ### Custom system dependencies Some pipelines need specific SDKs, browsers, database clients, kernel features, internal certificates, or licensed build tools. A self-hosted runner lets the team create a known environment rather than reinstalling everything for every job. Document the runner build process in a script, image, or configuration-management repository. A manually configured runner that nobody can reproduce becomes operational debt. ### Predictable resources Teams with long compiles, large test suites, container builds, or parallel jobs may benefit from assigning a known amount of CPU, memory, and NVMe-backed storage to CI. This does not guarantee that every build will be faster. Performance still depends on the workflow, cache quality, concurrency, dependency servers, and test design. Measure queue time and job duration before and after moving workloads. ### Access to private services A runner may need to test against an internal database, package registry, staging API, or private artifact store. Private networking can reduce the need to expose those services publicly. Keep access narrow. A runner should reach only the systems required for its jobs, not every production service in the environment. ## When managed runners remain the better choice Self-hosting is not automatically cheaper or simpler. Managed runners are usually a better fit when: - build volume is low; - workflows are short and standard; - the team does not want to manage another server; - jobs process untrusted pull requests from public contributors; - rapid elasticity matters more than persistent caching; - the organization lacks an owner for patching, monitoring, and incident response. The correct comparison includes engineering time, security work, maintenance, failed jobs, replacement procedures, and idle capacity—not only the server price. ## The security boundary matters more than the hardware CI runners handle valuable assets: source code, repository tokens, deployment credentials, signing keys, package-registry access, and cloud secrets. Treat the runner as a privileged automation system. ### Do not mix CI and production workloads A production application and its CI runner should not share one VM. Build scripts execute code from repositories and dependencies. A compromised workflow should not automatically gain access to production processes, files, or credentials. ### Restrict which repositories can use the runner Register runners at the narrowest practical scope. Separate trusted production repositories from experiments and public projects. Review who can edit workflow files because workflow access can become infrastructure access. ### Minimize secrets Provide each workflow only the credentials it needs. Prefer short-lived credentials and deployment-specific service accounts. Avoid placing broad administrator keys in global runner configuration, shell history, cached directories, or reusable images. ### Be careful with untrusted pull requests Running code from unknown contributors on a persistent runner can expose files, credentials, caches, and network access. Public projects should use isolated or disposable execution patterns unless the team has designed a strong trust boundary. ### Control outbound access Inbound firewall rules are only part of the picture. Restrict the services the runner can reach, especially production databases, control panels, internal administration endpoints, and metadata services. ## A practical small-team architecture A sensible first deployment can be simple: ```text GitHub or GitLab | v Dedicated Linux runner VM | +-- No public application ports +-- Repository-specific runner registration +-- Minimal deployment credentials +-- Separate build workspace +-- Disk and resource monitoring +-- Controlled private access where needed | v Artifact registry or staging environment ``` Do not start with an autoscaling runner fleet unless build demand justifies it. One well-documented runner gives the team real usage data before it adds orchestration complexity. ## How to size the first runner Start from the heaviest representative job, not from employee count. | Workload characteristic | Resource most likely to matter | |---|---| | Compiling large projects | CPU and memory | | Running many tests in parallel | CPU and memory | | Building container images | CPU, memory, and storage I/O | | Large dependency caches | Storage capacity | | Browser or end-to-end tests | Memory and CPU | | Multiple concurrent jobs | CPU, memory, and runner concurrency | | Large artifacts | Storage and network throughput | Run representative pipelines, then review CPU peaks, memory pressure, free disk, cache growth, job duration, and queue time. Increase resources only after identifying the actual bottleneck. ## Maintenance tasks teams often forget Assign an owner for: - operating-system and runner updates; - runner-token rotation; - disk and cache cleanup; - failed service alerts; - capacity monitoring; - dependency and base-image updates; - backup decisions for configuration files; - replacement and re-registration procedures; - incident response when a workflow is compromised. Build output should normally be reproducible from source, so backing up a runner's entire workspace may be unnecessary. Back up the configuration, scripts, certificates, and any unique state that cannot be recreated safely. ## How Raff fits Raff Linux VMs provide full root access on AMD EPYC infrastructure with NVMe storage. Teams can combine a dedicated runner with cloud firewall controls, private networking, snapshots, backups, and browser console access. Raff supplies the infrastructure layer. The customer remains responsible for runner registration, CI platform permissions, operating-system security, workflow trust, secrets, monitoring, and cleanup. Review [Raff Linux VM](/products/linux-vm) for the compute layer, [Private Cloud Networks](/products/private-cloud-networks) for internal connectivity, [Security](/products/security) for infrastructure controls, and [Data Protection](/products/data-protection) for recovery planning. Use the live [pricing page](/pricing) when comparing current plans rather than relying on a hard-coded figure in an article. :::cta Deploy Your Server Build a dedicated CI runner without mixing builds and production. ::: ## Final decision checklist A self-hosted runner is worth testing when you can answer these questions: 1. Which workflows will use it? 2. Are those repositories trusted? 3. Which secrets and private services does it need? 4. Who will patch and monitor the runner? 5. How will caches and workspaces be cleaned? 6. Can the runner be rebuilt from documented configuration? 7. What measurements will determine whether it improved the pipeline? Self-hosting works best when it solves a measured CI problem and has a clear operational owner. Without those two conditions, a managed runner is usually the safer default. --- ### Looking for a Windows VPS? What to Check Before You Deploy URL: https://rafftechnologies.com/blog/looking-for-a-windows-vps-what-to-check Published: 2025-07-17T00:00:00.000Z Description: Looking for a Windows VPS? What to Check Before You Deploy ## In short A Windows VPS is a practical fit when your workload depends on Windows software, Remote Desktop, .NET, business applications, scheduled tasks, or an always-available Windows environment. The right provider should make the infrastructure clear: available Windows versions, current pricing, licensing terms, VM sizing, storage, remote-access options, backup choices, and support responsibilities. These details can change, so this article no longer publishes fixed license fees, unsupported BYOL promises, exact provisioning times, or hard-coded operating-system availability. Before deploying, confirm the current options on the [Windows VM product page](/products/windows-vm) and [Raff pricing page](/pricing). ## What a Windows VPS is A Windows VPS is a cloud virtual machine running an available Windows Server image. It gives the customer administrator-level control and is commonly accessed through Remote Desktop Protocol, with browser-based console access available as a recovery path on Raff. Typical use cases include: * Windows-only business applications * Remote work environments * .NET development and testing * Accounting, ERP, inventory, and legacy software * Browser automation and scheduled Windows tasks * Application demonstrations and QA environments A Windows VPS provides the infrastructure. Customers and their software vendors remain responsible for application compatibility, application licensing, user configuration, database administration, and workload-specific testing. ## Check software compatibility first Do not choose a Windows Server version only because it is the newest option shown in a control panel. Confirm: * which Windows Server releases the application vendor supports * whether the application requires a specific .NET version * whether the database should run on the same VM or separately * whether USB devices, scanners, printers, smart cards, or serial equipment are involved * whether the software supports Remote Desktop sessions * whether multiple users require Remote Desktop Services and separate licensing Legacy applications can behave differently on newer server releases. Test the complete workflow before moving production users. ## Verify licensing from the current product information Windows licensing is not a detail that should be frozen inside an old blog post. The available licensing model, included editions, pricing, and eligibility rules may change. Before purchasing, verify: * whether the Windows license is included or billed separately * which editions and versions are currently available * whether your planned use requires additional Microsoft licenses * whether multi-user access requires RDS CALs * whether a bring-your-own-license arrangement is explicitly supported for your agreement Do not assume that a desktop Windows license, Microsoft 365 subscription, or existing server key can automatically be used in a hosted environment. Licensing questions should be checked against the current Raff offer and the customer's Microsoft licensing position. ## Size the VM for the workload, not only the user count Windows Server has its own memory and storage requirements before the business application starts consuming resources. Sizing should consider: * number of concurrent users * application memory usage * database size and query activity * background services * Windows Update and antivirus overhead * file storage growth * reporting and batch jobs * peak CPU usage during login or processing periods Start from a measured baseline where possible. A five-user accounting environment and a five-user engineering application can require very different resources. ## Plan RDP access carefully RDP is the normal day-to-day access method for many Windows workloads, but it should not be exposed carelessly. Use strong administrator credentials, restrict access where possible, keep Windows updated, review failed login activity, and avoid giving every user broad administrative privileges. Where the business requires multiple simultaneous user sessions, plan the correct Remote Desktop Services roles and licensing rather than relying on the two administrative sessions intended for server management. The Raff browser console should be treated as a recovery path when RDP is unavailable, not as a replacement for a properly configured remote-access model. ## Separate cloud workloads from local hardware dependencies A Windows VPS works best for software and data that can operate over a network connection. Some workflows may still need a local or hybrid component, including: * warehouse scanners and label printers * local scales or serial devices * specialized USB license keys * high-end GPU applications * latency-sensitive plant equipment * software that must continue during an internet outage Test these dependencies before migration. A hybrid design is often safer than forcing every physical workflow into the cloud. ## Protect the environment before it becomes critical A production Windows VPS should have a documented protection plan covering: * application-consistent backups where required * database backups * file and document backups * snapshots before risky changes * off-server copies where appropriate * retention periods * restore testing * administrator access during recovery Snapshots are useful, but they should not automatically be treated as the only backup strategy. The recovery process matters more than the presence of a backup button. ## Understand the support boundary Raff provides the cloud infrastructure and platform controls. The customer, software vendor, or MSP normally owns: * application installation and configuration * application and Microsoft licensing decisions * database maintenance * user permissions * RDS configuration * device and printer testing * application-level security * migration planning and validation * backup contents and restore acceptance Clear ownership prevents a migration from stalling when an application-specific problem appears. ## What to confirm before ordering Use this checklist: 1. Confirm the application supports a currently available Windows Server image. 2. Verify current Windows pricing and licensing terms. 3. Estimate concurrent users, RAM, CPU, storage, and database growth. 4. Identify printers, scanners, USB devices, and local integrations. 5. Decide whether the database stays on the same VM. 6. Plan RDP and RDS licensing correctly. 7. Define backups and test restoration. 8. Confirm which tasks Raff, your MSP, and the software vendor will own. 9. Test the full workflow before the final cutover. ## What this means for you A good Windows VPS decision is not based on one advertised price or one server specification. It depends on compatibility, licensing, sizing, access, data protection, and whether the complete business workflow has been tested. Review the current [Windows VM options](/products/windows-vm), then speak with the team before moving a business-critical or multi-user workload. :::cta Talk to Windows Engineer Confirm compatibility, sizing, and current Windows VM options. ::: --- ### Is Raff Secure? How Cloud Security Responsibility Works URL: https://rafftechnologies.com/blog/is-raff-secure-cloud-security-shared-responsibility Published: 2025-05-20T00:00:00.000Z Description: Is Raff Secure? How Cloud Security Responsibility Works ## In short Raff provides the infrastructure controls needed to build a safer cloud environment, including network-level DDoS protection, firewall controls, private networking options, snapshots, backups, and recovery access through the web console. But no cloud provider can secure everything inside a customer-managed virtual machine automatically. Security is a shared responsibility. Raff protects and operates the cloud platform; customers remain responsible for the operating system, user accounts, SSH or RDP access, application configuration, software updates, secrets, and backup recovery planning. This distinction matters because vague security claims create the wrong expectations. A secure cloud setup is not created by one checkbox or one provider feature. It comes from combining infrastructure protection with disciplined server administration. ## What Raff protects at the infrastructure layer Raff operates the physical and cloud infrastructure underneath your virtual machines. The platform provides controls that help reduce common infrastructure risks and give customers practical ways to protect and recover their workloads. ### Network-level DDoS protection Raff includes network-level protection designed to help absorb and filter malicious traffic aimed at disrupting services. DDoS protection reduces infrastructure-level exposure, but it does not replace application security, rate limiting, authentication, or monitoring inside your workload. ### Cloud firewall controls Firewall rules help customers limit which ports and services are reachable from the public internet. A strong starting configuration normally exposes only the services the workload needs, such as HTTPS and carefully restricted administrative access. A firewall cannot protect an application that is misconfigured or running vulnerable software. It should be treated as one layer in a broader security model. ### Private networking Private cloud networks allow supported Raff resources to communicate without exposing every internal service publicly. This is useful for separating application servers, databases, internal tools, and management services. A database, Redis instance, or internal API generally should not be public merely because another server needs to reach it. Private networking gives teams a cleaner way to design those boundaries. ### Snapshots, backups, and recovery paths Security also includes recovery. Accidental deletion, failed updates, ransomware, application bugs, and administrator mistakes can be as damaging as external attacks. Snapshots and backups help create recovery points, while the browser-based console provides another access path when SSH or RDP is unavailable. These tools reduce recovery risk, but customers should still define retention periods and test restores instead of assuming that a successful backup automatically guarantees a successful recovery. ## What customers are responsible for A Raff VM gives you administrative control. That control also creates responsibility. Customers should manage: * operating-system updates and security patches * SSH keys, passwords, RDP access, and administrator accounts * application authentication and authorization * secrets, API keys, database credentials, and environment variables * firewall rules inside the guest operating system where applicable * services and ports exposed by the application * database permissions and data-access policies * malware prevention and application-level monitoring * backup schedules, retention, and restore testing Raff does not automatically inspect or securely configure every application installed inside a customer VM. A server can be deployed on protected infrastructure and still become vulnerable through an outdated package, weak password, exposed database port, leaked API key, or overly permissive account. ## Secure connections depend on the protocol you use The previous version of this article incorrectly suggested that every connection to a Raff VM used universal end-to-end SSL encryption. That was too broad. Connection security depends on the service and protocol being used. Linux administrators should use SSH with strong keys and restricted access. Windows administrators should secure RDP access and use appropriate account controls. Web applications should use HTTPS with correctly configured TLS certificates. Private services should stay on private networks or localhost whenever possible. The important rule is simple: do not expose an unencrypted or unnecessary service to the public internet merely because the VM has a public IP address. ## What we do not claim without verification Security documentation should be precise. Raff does not use this article to make universal claims about disk encryption, end-to-end encryption for every protocol, compliance certifications, or application-level protection unless those capabilities are explicitly documented for the relevant product. That is intentional. Customers should be able to distinguish between a verified platform feature, a configuration they must implement, and a security requirement that may need additional products or professional review. ## A practical Raff VM security baseline For a new Linux or Windows VM, use this baseline: 1. Create only the administrator accounts you need. 2. Use SSH keys for Linux and strong, restricted administrator access for Windows. 3. Apply operating-system and application updates. 4. Close every public port that the workload does not require. 5. Place databases and internal services behind private networking where possible. 6. Keep secrets outside source code and public repositories. 7. Create backups before the workload becomes business-critical. 8. Test at least one restore before relying on the backup process. 9. Monitor login attempts, service errors, storage usage, and unusual activity. 10. Remove unused accounts, packages, services, and credentials. This approach is more useful than assuming a cloud provider can make a customer-managed server secure without customer participation. ## Security is a system, not a marketing claim The safest way to evaluate a cloud provider is to ask specific questions: * Which infrastructure protections are included? * Which ports and networks can I control? * How do I recover from a bad configuration or failed update? * Which security tasks remain my responsibility? * Are product claims documented clearly enough to verify? Raff's goal is to provide practical infrastructure controls without pretending that infrastructure alone solves every security problem. Use [Raff Security](/products/security) to review platform protections, [Private Cloud Networks](/products/private-cloud-networks) to separate internal services, and [Data Protection](/products/data-protection) to plan snapshots, backups, and recovery. :::cta Explore Security Review the controls available for protecting your Raff workloads. ::: --- ### Why We Keep Support Human in a Cloud-First World URL: https://rafftechnologies.com/blog/real-human-support-in-a-digital-world-why-raff-puts-developers-first Published: 2025-08-17T00:00:00.000Z Description: Why We Keep Support Human in a Cloud-First World Cloud infrastructure is technical, but the support experience should not feel distant, scripted, or impossible to reach. At Raff, we see support as part of the product itself. When a developer is launching a VM, moving a workload, checking a network issue, restoring data, or choosing the right infrastructure setup, the quality of support directly affects how fast they can keep moving. That is why we keep support human, close to the product, and focused on context instead of generic replies. Automation helps with speed. Documentation helps with repeatable answers. But when infrastructure decisions affect production workloads, people still need clear help from people who understand the system. ## Support is part of the infrastructure experience Most cloud platforms talk about support as if it sits outside the product. You build on the platform first. Then, if something goes wrong, you open a ticket. I do not think infrastructure works that way. For developers, startups, small teams, agencies, and MSPs, support is not a separate department. It is part of the real experience of using the platform. If a user cannot understand why a VM is unreachable, if a backup workflow feels unclear, if an app is slow and they do not know whether the problem is CPU, disk, network, or application code, the product experience is already affected. That is not just a support issue. It is a product issue. Cloud infrastructure is only useful when people can actually operate it with confidence. That confidence comes from a few things: - clear products - predictable pricing - useful documentation - stable infrastructure - fast provisioning - visibility into what is happening - support that helps users understand the situation, not just close the ticket That last part matters more than people admit. ## Automation is useful, but it cannot replace understanding We use automation. Any serious infrastructure platform should. Automation helps with: - faster VM provisioning - repeatable server actions - safer reset flows - billing workflows - monitoring - alerts - internal operations - customer-facing product actions Automation is not the problem. The problem starts when companies use automation to avoid understanding the customer's actual issue. A bot can route a ticket. A help article can explain a common setup step. A status page can confirm whether a platform-level incident is happening. But many infrastructure questions are not that simple. A developer may ask: ```text Why is my server slow? ``` But the real question might be: ```text Did I choose the wrong VM size? Is my app using too much memory? Is the database on the same server becoming the bottleneck? Is this a disk issue? Is the problem network-related? Should I scale vertically or split the workload? ``` Those are different questions. They require context. That is where human support still matters. ## Why many cloud support experiences feel broken A lot of cloud support feels frustrating because it is designed around internal scale before customer momentum. Large platforms often use: - layered ticket queues - scripted replies - generic troubleshooting flows - separate sales, billing, and technical support paths - support teams far away from product decisions - documentation loops instead of direct help That model may be efficient for the provider. It often feels slow for the customer. The user has to explain the same problem multiple times. They get answers that technically relate to the issue but do not solve the real situation. They lose time. They lose confidence. Sometimes they even change their architecture around what is easiest to get support for, instead of what is best for the application. For enterprise teams with dedicated cloud engineers, that friction may be manageable. For small teams, it is expensive. Not only in money. In attention. In delay. In uncertainty. In the cost of stopping real work to decode the platform. ## Smaller teams need clarity, not ceremony A lot of cloud content assumes the buyer has a large engineering organization behind them. But many teams do not work that way. A founder may be handling infrastructure. A developer may also be responsible for deployment, backups, and basic security. An agency may be managing client apps with a small technical team. An MSP may need a cloud provider that helps them move faster without adding operational confusion. A small SaaS team may be running production without a dedicated platform engineer. These users are capable. They are not asking for hand-holding. They are asking for clarity. They need support that respects momentum. They need answers that help them understand: - what is happening - what is safe to change - what should be checked first - what belongs to the infrastructure layer - what belongs to the application layer - what the next practical step should be That is a different standard from generic "premium support." It is not about sounding friendly. It is about being useful. ## What human support should actually mean "Human support" is easy to say and hard to do well. To us, it should mean a few concrete things. ### 1. Context before templates A support reply should not feel like a pasted checklist that ignores the situation. Sometimes the right answer is a command. Sometimes the right answer is a link. But often, the right answer starts by identifying the category of the problem. Is it a VM issue? A DNS issue? A firewall issue? A disk space issue? An application process issue? A Windows RDP issue? A database sizing issue? A backup or restore concern? Infrastructure problems often look similar at the surface but have very different causes underneath. Human support should help users find the real layer of the problem. ### 2. Momentum matters People use infrastructure because they are trying to do something else. They are building. Launching. Migrating. Debugging. Serving customers. Shipping a feature. Testing a new idea. Support should help them keep moving. The goal is not simply to close a ticket. The goal is to reduce friction so the user can continue the work they came to do. That mindset changes the quality of the answer. ### 3. Product knowledge matters Support is better when it is close to the product. If the people helping users understand how the infrastructure actually works, they can give better answers. They can also see patterns faster: - where users get stuck - where docs are unclear - where a workflow needs improvement - where a feature solves most of the problem but leaves confusion - where the dashboard should explain more - where product design can remove a future support request That loop matters. Support should not only react to problems. It should improve the product. ### 4. Honesty matters Good support does not pretend every issue is simple. Sometimes the answer is: ```text This is an application-level bottleneck. ``` Sometimes it is: ```text You need a larger VM. ``` Sometimes it is: ```text This setup should be split across services. ``` Sometimes it is: ```text This is not something the infrastructure layer can fix directly. ``` That honesty helps users make better decisions. A vague answer may feel easier in the moment, but it does not build trust. ## Why Raff made a different decision At Raff, we wanted support to stay close to the product from the beginning. That means support is not just a contact form on top of the platform. It is part of how we think about the product. When someone launches a Raff VM, connects to a Windows VM, reviews data protection, uses Object Storage, or builds across private networks, the support experience should feel connected to the same system. The product should be simple enough that users do not need support for every basic action. But when they do need help, the answer should feel grounded in how the platform actually works. That is the balance we care about: Simple enough to use without constant support. Human enough when support matters. That is one of the reasons we focus on clear infrastructure products instead of trying to turn every cloud feature into a maze. ## Documentation is necessary, but it is not enough We believe in documentation. Docs, tutorials, guides, FAQs, and product pages are important. They help users move independently. But documentation and support are not the same thing. Documentation works best when the user already knows what they are trying to do. Support becomes critical when the user is unsure what the real problem is. A guide can explain how to connect to a server. A tutorial can explain how to configure a firewall. A product page can explain what a VM includes. But when a user is deciding whether to scale, restore, resize, split workloads, change architecture, or debug a production issue, they often need interpretation. Not just information. That is why support still matters in a world full of docs, AI assistants, community forums, and automated workflows. ## Human support also improves the platform Support is not only useful for users. It is useful for the company building the product. When support stays close to product development, the team learns faster. You can see: - which terms confuse users - which product pages need clearer explanations - which dashboard actions need better labels - which errors need better messaging - which workflows should be simplified - which features need stronger defaults - which documentation should be written next That feedback is valuable. If support is too far from the product, the learning becomes weaker. The company may keep answering the same questions without fixing the product reason those questions exist. That is not the model we want. We want support to feed back into a better Raff experience. ## The real cost of bad support Bad support makes infrastructure more expensive than it looks. Not always through the invoice. Through the work around the invoice. Every unclear reply creates another round trip. Every generic answer forces the customer to investigate alone. Every delayed response slows down the work that was supposed to be the actual priority. Every confusing workflow creates hesitation. For a developer, that may mean a launch takes longer. For an agency, it may mean client work slows down. For a startup, it may mean the founder loses a day to infrastructure uncertainty. For an MSP, it may mean operational overhead increases. That is why we do not separate support quality from product quality. A cloud provider can have strong hardware, good pricing, and useful features. But if users cannot get clear help when it matters, the real experience is weaker than the feature list suggests. ## What we are trying to build at Raff We are trying to build a cloud experience where support feels native to the product. That means: - the platform should be simple enough that users need less help - help should still be reachable when users need it - answers should reflect real infrastructure understanding - support should reduce confusion, not add another process - documentation should improve based on real user questions - product decisions should reduce repeated support friction - users should feel like they are talking to people who understand what they are building This is harder than only saying "we care about customers." But it is the kind of company we want to build. Raff is built for developers, small teams, founders, MSPs, and businesses that want infrastructure without unnecessary complexity. For those users, support is not a luxury feature. It is part of the operating experience. ## What this means when choosing a cloud provider When evaluating a cloud provider, do not only ask: ```text Do they offer support? ``` Ask better questions: - How close is support to the actual product? - Will I get context or only scripted replies? - Can I reach someone when the issue matters? - Does the documentation match the real product? - Does support help me keep moving? - Do repeated support questions improve the product over time? Those questions reveal more about the real experience than a generic support badge. Infrastructure is not just CPUs, RAM, storage, and bandwidth. It is the full system around those resources. Provisioning. Networking. Backups. Security. Documentation. Billing clarity. Recovery paths. Support. All of it shapes whether the platform feels usable in real work. ## Why we keep it human We keep support human because infrastructure is still used by humans. Even when the systems are automated. Even when the docs are detailed. Even when dashboards are improving. Someone still has to make decisions under pressure. Someone still has to debug the server. Someone still has to decide whether to resize, restore, redeploy, or wait. Someone still has to explain the problem to a customer, a teammate, or a client. When support is human, close to the product, and focused on context, that person does not have to carry the whole uncertainty alone. That is the kind of cloud experience we want Raff to represent. Not support as a wall between the company and the user. Support as part of the product itself. --- ### What You Can Build with Claude AI + Raff Technologies VPS URL: https://rafftechnologies.com/blog/build-ai-apps-claude-vps-guide Published: 2026-03-11T00:00:00.000Z Description: What You Can Build with Claude AI + Raff Technologies VPS Claude is a powerful model for building AI products, but the model alone is not the product. If you are building with Claude through an API, your real application still needs infrastructure. You need a backend. You need authentication. You need a database. You need API key protection. You need streaming support. You need rate-limit handling. You need logs. You need workers. You need backups. You need a place where the app can reliably run. That is where VPS infrastructure still matters. The short answer: > You can build many Claude-powered AI apps on a VPS because the heavy AI model runs through Claude’s API. Your VPS runs the product layer: backend API, database, Redis, workers, queues, file processing, tool execution, security, monitoring, and deployment. This guide explains what developers can build with Claude, what infrastructure those apps need, when a single VPS is enough, and how to design a clean architecture that can grow. ## Quick answer A Claude-powered app usually looks like this: ```text User ↓ Frontend ↓ Backend API on VPS ↓ Claude API ↓ Database / Redis / files / tools / workers ``` The VPS does not run Claude itself. The VPS runs your application. That application is responsible for: * user accounts * permissions * prompt construction * Claude API calls * streaming responses * conversation storage * tool execution * file processing * database writes * rate limits * retries * logs * backups * security * monitoring For many MVPs and early production apps, one VPS can host the full backend stack. As the product grows, you can split the architecture into multiple VMs or managed services. ## What you can build with Claude and a VPS Claude can be used as the AI layer for many types of applications. A VPS gives you the backend foundation to turn that AI layer into a real product. Common Claude-powered apps include: * AI chatbots * internal assistants * document analysis tools * customer support copilots * sales assistants * developer tools * AI agents * workflow automation systems * knowledge base assistants * report generators * contract review tools * research assistants * SaaS copilots * onboarding assistants * operations dashboards The key difference between a demo and a product is infrastructure. A demo can call Claude once. A product must handle users, data, reliability, cost, security, and operations. ## Why Claude apps still need infrastructure Claude provides the model. Your app still needs the system around the model. A real Claude-powered app needs to handle questions like: * Who is the user? * What organization do they belong to? * What data can they access? * What prompt should be sent to Claude? * Should the response stream back to the frontend? * Should Claude use tools? * Should documents be retrieved first? * Should the request be queued? * What happens if the Claude API is slow? * What happens if a rate limit is hit? * How is usage tracked? * Where is chat history stored? * How are files stored? * How are logs handled? * How are secrets protected? * How are backups restored? Those are infrastructure and backend questions. A VPS gives you a controlled environment to answer them. ## Claude API app architecture A simple Claude app can start with this architecture: ```text Browser ↓ Frontend ↓ Backend API ↓ Claude API ↓ Response ``` A more complete production architecture looks like this: ```text User ↓ Frontend ↓ Nginx or Caddy ↓ Backend API ├── Claude API ├── PostgreSQL ├── Redis ├── Queue ├── Worker process ├── Object storage ├── Vector search └── Logs / monitoring ``` The backend API is the control layer. It decides what gets sent to Claude, what gets stored, what gets shown to the user, and how failures are handled. ## The role of the VPS A VPS is useful because it gives you a dedicated server environment for the backend of your Claude app. Your VPS can run: * Node.js backend * Python FastAPI backend * Laravel backend * Go backend * Nginx or Caddy reverse proxy * PostgreSQL * Redis * background workers * queue workers * Docker containers * monitoring tools * admin dashboards * document processing jobs * webhook handlers * cron jobs The VPS does not replace Claude. It supports Claude. Think of Claude as the intelligence layer and the VPS as the application layer. ## Why most Claude apps do not need GPU servers If you are using Claude through an API, you are not hosting the model yourself. That means your infrastructure does not need to run large model inference. You usually do not need a GPU server for: * Claude chatbots * Claude-powered SaaS features * document Q&A apps * internal assistants * AI support tools * AI workflow automations * report generation tools * customer-facing copilots Your main server workload is usually: * backend request handling * database queries * file processing * queue workers * API calls to Claude * streaming responses * logs * security checks That is why a VPS can be a good starting point. You need GPU infrastructure only when you are running or fine-tuning models yourself, not when you are using Claude as an external API. ## Core components of a Claude-powered app ## 1. Backend API The backend API is the center of the product. It receives requests from the frontend and decides how to interact with Claude. The backend usually handles: * authentication * organization logic * permissions * prompt templates * system instructions * Claude API requests * streaming responses * rate limits * retries * file upload logic * document retrieval * conversation storage * usage tracking * billing checks * logs Common backend stacks include: * Node.js * Express * Fastify * Next.js API routes * Python FastAPI * Django * Flask * Laravel * Go * .NET For a first version, choose the stack your team can operate confidently. ## 2. Database Most Claude apps need a database. PostgreSQL is a strong default for many AI apps because it can store: * users * organizations * conversations * messages * prompts * files * metadata * billing events * usage records * permissions * audit logs * settings A Claude chatbot without a database is usually just a demo. A Claude app with a database becomes a product. ## 3. Redis Redis is not required for every Claude app, but it becomes useful quickly. Use Redis for: * caching * sessions * rate limits * queue state * temporary context * token counters * cooldowns * duplicate request protection * job coordination Example: ```text User sends message ↓ Backend checks Redis rate limit ↓ Backend sends prompt to Claude ↓ Backend stores result in PostgreSQL ``` This prevents one user, bug, or script from overwhelming the system. ## 4. Queues and workers Claude apps often have tasks that should not run directly inside the web request. Examples: * parsing PDFs * generating summaries * extracting structured data * creating embeddings * processing long documents * generating reports * retrying failed Claude calls * sending emails * processing webhooks * syncing knowledge bases A better pattern is: ```text User action ↓ Backend API ↓ Queue ↓ Worker ↓ Claude API ↓ Database result ``` This makes the app more stable because long-running jobs do not block the frontend request. ## 5. File storage Many Claude apps work with files. Examples: * PDFs * contracts * CSVs * Word documents * support transcripts * product manuals * invoices * reports Do not treat uploaded files casually. You need to decide: * where files are stored * who can access them * how long they are retained * how they are processed * whether they are deleted * whether extracted text is stored * whether files are sent to Claude * whether private data is logged A clean architecture separates file storage from app code. For production apps, object storage is often better than storing everything inside the application directory. ## 6. Vector search for Claude apps Claude can answer questions better when your app retrieves relevant context first. This is common for: * document Q&A * internal knowledge assistants * customer support bots * legal document tools * onboarding assistants * product documentation search * company wiki assistants A simplified RAG flow: ```text User asks a question ↓ Backend searches relevant documents ↓ Backend retrieves useful context ↓ Backend sends context + question to Claude ↓ Claude returns grounded answer ``` For early apps, you can start simple. As the product grows, you may add dedicated vector search infrastructure. The important rule: > Do not send every document to Claude on every request. Retrieve only the context that is relevant. ## 7. Reverse proxy Use Nginx or Caddy in front of the app. A reverse proxy helps with: * HTTPS * routing * static files * compression * request forwarding * security headers * keeping the app port private A clean setup looks like this: ```text User ↓ Nginx or Caddy ↓ Backend app on localhost ``` Do not expose your backend development port directly to the internet. ## 8. Monitoring and logs Claude apps need normal system monitoring and AI-specific monitoring. System metrics: * CPU usage * RAM usage * disk usage * HTTP error rate * request latency * database performance * Redis memory * queue depth * worker failures Claude-specific metrics: * Claude API latency * Claude API error rate * rate-limit errors * retry count * timeout count * input token usage * output token usage * cost per user * cost per workspace * failed generations * streaming failures * tool call failures If you cannot see these metrics, you cannot operate the app properly. ## Example: simple Claude app on one VPS A clean MVP architecture can run on one VPS: ```text Single Raff VM ├── Nginx or Caddy ├── Backend API ├── PostgreSQL ├── Redis ├── Worker process └── Logs / monitoring ``` This is enough for many early Claude apps. Use one VPS when: * traffic is low to moderate * the app is still early * you want predictable monthly cost * the database is not large * workers are not heavy * you want operational simplicity * you are validating product demand A single VPS is not the final architecture for every app. But it is often the right first production foundation. ## Example: multi-VM Claude app architecture As the product grows, split services: ```text Load balancer ↓ App VM ↓ Database VM ↓ Redis / queue VM ↓ Worker VM ↓ Monitoring ``` Move to this when: * web traffic grows * workers slow down the main app * database load increases * you need stronger isolation * uptime requirements increase * multiple developers are deploying * customers depend on the app daily * background jobs are business-critical The goal is not to overbuild from day one. The goal is to design the first version so it can grow without a painful rewrite. ## Minimal Claude backend example Here is a simplified Node.js-style backend flow. This is not a full production app, but it shows the right pattern: ```js import express from "express"; import Anthropic from "@anthropic-ai/sdk"; const app = express(); app.use(express.json()); const anthropic = new Anthropic({ apiKey: process.env.CLAUDE_API_KEY }); app.post("/api/chat", async (req, res) => { try { const { message } = req.body; if (!message || typeof message !== "string") { return res.status(400).json({ error: "Message is required." }); } const response = await anthropic.messages.create({ model: process.env.CLAUDE_MODEL, max_tokens: 800, system: "You are a helpful assistant for this application.", messages: [ { role: "user", content: message } ] }); return res.json({ answer: response.content }); } catch (error) { console.error("Claude request failed:", error); return res.status(500).json({ error: "AI response failed. Please try again." }); } }); app.listen(3000, () => { console.log("Claude app backend running on port 3000"); }); ``` Important details: * the Claude API key stays on the server * the frontend never calls Claude directly * the backend validates input * errors are handled * the app runs behind a reverse proxy * the model name is controlled by environment variable * production apps should add authentication, rate limits, logs, and database storage ## Streaming Claude responses For chat experiences, streaming improves perceived speed. Without streaming: ```text User sends message ↓ Wait ↓ Full response appears ``` With streaming: ```text User sends message ↓ First tokens appear ↓ Response continues in real time ``` Streaming requires the backend and reverse proxy to support longer-lived responses. You should test: * frontend streaming UI * proxy timeout settings * backend timeout settings * user cancellation * partial response handling * error handling during stream * logging for failed streams Streaming is useful, but it adds complexity. For an MVP, start without streaming if needed. For a polished chatbot, add streaming once the core flow is stable. ## Claude tool use architecture Claude can work with tools, but your application must decide how tools are executed. A tool can be something like: * search internal documents * check order status * create a support ticket * query a database * call a CRM API * generate a report * schedule an event * fetch product information * run a workflow A simplified tool flow: ```text User asks a request ↓ Backend sends tool definitions to Claude ↓ Claude requests a tool call ↓ Backend validates permission ↓ Backend executes tool ↓ Backend sends tool result back to Claude ↓ Claude responds to user ``` Tool use is powerful, but it must be controlled. Do not let AI tools execute dangerous actions without validation. For production: * define strict schemas * validate tool inputs * check user permissions * log tool calls * add approval steps for risky actions * prevent access to unauthorized data * avoid exposing internal admin tools directly Claude can decide when a tool may be useful, but your backend is responsible for safe execution. ## Prompt caching for Claude apps Prompt caching can help when your app repeatedly sends the same long context. Useful cases include: * long system prompts * repeated tool definitions * large instruction blocks * documentation context * repeated examples * long multi-turn conversations * stable knowledge packs A simple example: ```text System prompt + tool definitions + stable docs ↓ Cached prefix ↓ New user message changes each request ``` This can reduce cost and latency for repeated workloads. But prompt caching works best when the cached part stays stable. If your app changes the prompt structure on every request, caching becomes less effective. Good caching strategy: * keep stable instructions at the beginning * keep dynamic user content later * avoid constantly changing tool definitions * monitor cache hit rate * cache large repeated context, not tiny prompts * keep private data handling rules clear Prompt caching is not a replacement for good retrieval. For document apps, still retrieve only relevant context. ## Handling rate limits and retries Claude API usage is not unlimited. Your backend should expect limits and failures. Handle: * request rate limits * input token limits * output token limits * temporary API errors * timeouts * retry-after headers * sharp traffic spikes * user abuse * duplicate requests Bad pattern: ```text User sends request ↓ Claude rate limit hit ↓ App crashes or returns generic error ``` Better pattern: ```text User sends request ↓ Backend checks local rate limit ↓ Claude request sent ↓ If rate-limited, respect retry timing ↓ Return clear message or retry safely ↓ Log the event ``` Add your own application-level limits too. Examples: * messages per minute * tokens per day * requests per workspace * file upload limits * document processing limits * free plan usage caps * paid plan usage caps This protects your product and your AI API budget. ## Security basics for Claude apps Claude apps often handle sensitive information. Treat security as part of the architecture. ## Keep API keys on the server Never expose your Claude API key in frontend code. Bad pattern: ```text Browser → Claude API ``` Better pattern: ```text Browser → your backend → Claude API ``` The backend protects secrets and controls usage. ## Use environment variables or secrets Do not hard-code API keys into source code. Use: * environment variables * secret managers * deployment secrets * restricted server files Also rotate keys if they are exposed. ## Validate user access Every request should check: * user identity * workspace membership * role * document access * billing status * usage limits * admin permissions This is especially important for SaaS products and internal assistants. ## Protect files and documents If users upload files, control: * max file size * file types * access permissions * retention * deletion * storage location * extraction safety * whether file content is logged * whether file content is sent to Claude Document apps need strong data handling rules. ## Do not over-log sensitive content Logs are useful, but dangerous if they contain private data. Avoid logging: * API keys * passwords * full private documents * sensitive prompts * customer secrets * payment data * personal data you do not need Log enough to debug. Do not log everything. ## Example Claude app use cases ## 1. Customer support chatbot A support chatbot can answer customer questions using: * product documentation * FAQ pages * help center articles * account metadata * ticket history * order status tools Infrastructure needed: * backend API * database * vector search * Redis rate limits * support tool integrations * logs * admin review tools ## 2. Document analysis app A document app lets users upload files and ask questions. Infrastructure needed: * file upload handling * object storage * text extraction * background workers * vector search * PostgreSQL * Claude API calls * file access controls * retention rules ## 3. Internal company assistant An internal assistant can help employees search company knowledge. Infrastructure needed: * authentication * role-based access * document sync jobs * vector database * Claude API integration * audit logs * admin controls * private networking if needed ## 4. AI SaaS copilot A SaaS copilot helps users complete actions inside a product. Infrastructure needed: * product database access * user permissions * tool execution * workflow controls * safe action approvals * usage tracking * billing integration * monitoring ## 5. AI workflow automation A workflow automation app uses Claude to classify, summarize, or generate actions. Infrastructure needed: * webhook handlers * queue workers * retries * scheduled jobs * tool calls * API integrations * Redis * logs * error handling ## Deployment pattern for a Claude app on a VPS A practical first deployment can look like this: ```text Raff VM ↓ Ubuntu ↓ Firewall ↓ Nginx or Caddy ↓ Backend app on localhost ↓ PostgreSQL + Redis ↓ Claude API ``` The backend app should not be exposed directly. Use a reverse proxy. Use HTTPS. Keep databases private. Use firewall rules. Run the app with a process manager such as: * systemd * PM2 * Docker Compose * Supervisor Pick the method your team can maintain. ## Production checklist Before launching a Claude-powered app, check these basics. ## Server * Use a stable Linux server. * Configure SSH key access. * Disable password login if possible. * Configure firewall rules. * Install Nginx or Caddy. * Use HTTPS. * Keep app ports private. * Set up automatic security updates if appropriate. * Monitor CPU, RAM, disk, and network usage. ## Backend * Keep Claude API keys on the server. * Use environment variables. * Validate user input. * Add authentication. * Add authorization. * Store conversations in a database. * Add rate limits. * Handle timeouts. * Handle retries safely. * Return clear user-facing errors. * Log failures without leaking sensitive data. ## Claude integration * Use system prompts intentionally. * Keep prompts versioned. * Track token usage. * Monitor latency. * Monitor errors. * Handle rate limits. * Use streaming only after testing proxy and frontend behavior. * Use prompt caching for repeated long context. * Use tools only with validation and permission checks. ## Data * Back up the database. * Back up uploaded files. * Define retention rules. * Restrict document access. * Test restore. * Avoid logging sensitive prompts or documents. * Separate customer data by workspace or organization. ## Workers * Use queues for slow tasks. * Monitor queue depth. * Track worker failures. * Retry safely. * Avoid duplicate job execution. * Keep long tasks outside normal web requests. ## Operations * Create a staging environment. * Document deployment steps. * Add rollback strategy. * Monitor logs. * Monitor API spend. * Track usage by user or workspace. * Review failed requests regularly. ## When one VPS is enough One VPS is often enough when: * you are building an MVP * traffic is low to moderate * users are early-stage * the database is not large * background jobs are light * uptime needs are reasonable * you want simple operations * you want predictable monthly pricing * you are still validating the product Example starter stack: ```text 1 VPS ├── Nginx ├── Backend API ├── PostgreSQL ├── Redis ├── Worker └── Monitoring ``` This is a strong starting point for many Claude-based products. ## When to split into multiple VMs Move beyond one VPS when: * traffic grows * workers slow down the app * database load increases * Redis becomes critical * file processing becomes heavy * uptime requirements increase * multiple developers deploy frequently * staging and production must be isolated * customers depend on the app daily * you need clearer security boundaries A next-stage setup: ```text Load balancer ↓ App VM ↓ Database VM ↓ Redis / queue VM ↓ Worker VM ↓ Monitoring ``` This gives you more control over scaling and reliability. ## How Raff VM fits Claude app infrastructure Raff VM gives developers a simple cloud server foundation for Claude-powered apps. You can use Raff VM to run: * Claude app backends * AI chatbot APIs * SaaS copilots * internal assistants * document analysis tools * Redis * PostgreSQL * workers * queues * Docker workloads * staging environments * monitoring tools For an MVP, one Raff VM can host the full backend stack. As the product grows, you can split services across multiple Raff VMs: ```text App VM Database VM Redis VM Worker VM Monitoring VM ``` Raff VM is useful when you want: * simple deployment * full server control * predictable monthly pricing * strong CPU performance * NVMe storage * unmetered bandwidth * Linux or Windows VM options * a clean path from MVP to production The goal is not to add cloud complexity. The goal is to give the Claude app a reliable place to run. ## Common mistakes when building Claude apps ## Mistake 1: Calling Claude directly from the frontend This exposes your API key and removes backend control. Always use a backend. ## Mistake 2: No database If conversations, users, and usage are not stored, the app is only a demo. Use a database early. ## Mistake 3: No rate limits A single user, bot, or bug can create high API costs. Add rate limits before public launch. ## Mistake 4: No worker queue Long document processing and batch AI tasks should not block web requests. Use workers. ## Mistake 5: No prompt versioning Prompts are application logic. Track prompt changes like code changes. ## Mistake 6: No cost monitoring AI API usage can grow quickly. Track requests, tokens, retries, and cost by user or workspace. ## Mistake 7: No restore testing Backups are not enough. You must test restore. ## Mistake 8: Overbuilding too early Do not start with complex architecture before users exist. Start clean, then scale. ## Mistake 9: Underbuilding after customers arrive Once customers depend on the app, add staging, monitoring, backups, security hardening, and failure handling. ## Final architecture recommendation For most Claude app builders, use this path: ```text Stage 1: Prototype Local development + Claude API Stage 2: MVP One VPS with backend, database, Redis, worker Stage 3: Early production One stronger VPS or separate database Stage 4: Growth App VM + database VM + Redis/queue VM + worker VM Stage 5: Scale Load balancer, multiple app VMs, stronger observability, managed services where needed ``` This keeps infrastructure practical. Do not overbuild before demand. Do not stay too simple when users depend on the product. ## FAQ ### Can I build Claude apps on a VPS? Yes. Many Claude-powered apps can run on a VPS because Claude itself runs through an external API. The VPS runs your backend, database, Redis, workers, queues, logs, and application logic. ### Do Claude apps need GPU servers? Not if you are using Claude through the API. GPU servers are needed when you run models yourself. API-based Claude apps usually need reliable backend infrastructure, not GPU inference infrastructure. ### What can I build with Claude and a VPS? You can build AI chatbots, document analysis tools, internal assistants, support copilots, SaaS copilots, automation tools, developer tools, and AI workflow systems. ### What infrastructure does a Claude app need? A Claude app usually needs a backend API, database, reverse proxy, authentication, rate limits, logs, and Claude API integration. More advanced apps may need Redis, queues, workers, object storage, vector search, and monitoring. ### Should the frontend call Claude directly? No. The frontend should call your backend, and your backend should call Claude. This keeps API keys private and lets you control permissions, rate limits, logging, and usage. ### Do I need Redis for a Claude app? Not always, but Redis is useful for caching, sessions, rate limits, queues, temporary state, and background job coordination. ### When should I use workers in a Claude app? Use workers for slow or long-running tasks such as document parsing, embeddings, report generation, batch processing, retries, webhooks, and scheduled AI jobs. ### How does Raff VM help with Claude app deployment? Raff VM gives developers a cloud server foundation for running Claude app backends, databases, Redis, workers, Docker workloads, staging environments, and monitoring tools with simple deployment and predictable monthly pricing. ## Conclusion Claude can power powerful AI products, but Claude alone is not your application. Your product still needs backend infrastructure. It needs authentication, database storage, rate limits, streaming, tools, workers, queues, security, logs, monitoring, backups, and deployment discipline. For many Claude-powered apps, a VPS is the right starting point. It gives enough control to build a real backend without forcing your team into unnecessary cloud complexity. Start with a clean VPS architecture. Run the backend properly. Protect your API keys. Store data carefully. Add rate limits and observability. Use workers for slow tasks. Use prompt caching and retrieval where they make sense. Then scale into multiple VMs when the product proves it needs more structure. The AI model generates the intelligence. Your infrastructure makes it reliable. --- ### AI Chatbot Infrastructure in 2026: How to Run API-Based AI Apps on a VPS URL: https://rafftechnologies.com/blog/ai-chatbots-api-infrastructure-2026 Published: 2026-03-02T00:00:00.000Z Description: AI Chatbot Infrastructure in 2026: How to Run API-Based AI Apps on a VPS AI chatbots are no longer just demos. In 2026, teams are building AI chatbots for: * customer support * internal knowledge search * sales assistance * coding workflows * document analysis * onboarding * operations * reporting * SaaS copilots * workflow automation But there is one mistake many builders still make. They think the hardest infrastructure problem is the AI model. For most API-based AI chatbots, that is not true. If you are using AI providers through APIs, the model is not running on your server. Your real infrastructure problem is the application backend. Your backend must handle users, sessions, prompts, context, API calls, retries, rate limits, logs, storage, queues, workers, security, and uptime. That is where infrastructure still matters. The short answer: > Most API-based AI chatbots do not need GPU servers. They need a reliable backend server that can orchestrate AI API calls, store context, run workers, manage queues, protect secrets, and stay online. A well-sized VPS can be enough for many AI chatbot MVPs and early production apps. This guide explains how API-based AI chatbot infrastructure works, what components you need, when one VPS is enough, and when to split into multiple servers. ## Quick answer Most AI chatbots built with external AI APIs need infrastructure like this: ```text User ↓ Frontend ↓ Backend API ↓ AI provider API ↓ Database / Redis / vector store / queue / workers ``` The backend is the control layer. It decides: * who the user is * what the user is allowed to do * what prompt should be sent * what context should be included * which AI model or provider to call * how to handle streaming responses * how to store messages * how to retry failed requests * how to manage rate limits * how to log errors * how to protect API keys * how to monitor cost and usage For an MVP, this can often run on one VPS. For a growing AI product, you may later separate the app server, database, Redis, workers, and monitoring into different VMs or managed services. ## Why most AI chatbots do not need GPU servers Some AI workloads need GPU infrastructure. Examples include: * training models * fine-tuning large models * running local LLM inference * serving open-source models at scale * image or video generation workloads * high-throughput model hosting But many AI chatbot products do not start there. Most early AI chatbot apps use external AI APIs. That means the heavy model inference happens outside your infrastructure. Your server does not need to run the model. Your server needs to run the product. That includes: * user accounts * chat interface backend * conversation storage * prompt construction * retrieval logic * payment checks * usage limits * API provider calls * streaming response handling * background jobs * logs and monitoring * admin tools * security controls So for many teams, the first infrastructure question should not be: ```text Which GPU server do we need? ``` It should be: ```text Where should we run the backend that controls the AI product? ``` For many MVPs, SaaS prototypes, internal tools, and production-ready small apps, the answer can be a VPS. ## What the AI chatbot backend actually does A serious AI chatbot is not just a frontend calling an AI API. The backend is responsible for the logic that turns a model response into a usable product. A typical AI chatbot backend handles: * authentication * user permissions * organization or workspace logic * chat history * prompt templates * system instructions * message formatting * AI provider requests * response streaming * rate limits * retries and timeouts * billing or usage limits * file uploads * document parsing * vector search * database writes * logs * analytics * security checks * admin dashboards This is why infrastructure matters. The model may generate the answer, but your backend decides how the product behaves. If your backend is slow, unstable, insecure, or poorly designed, the AI experience will feel broken even if the model is good. ## Typical AI chatbot architecture A simple API-based AI chatbot architecture looks like this: ```text Browser or mobile app ↓ Frontend application ↓ Backend API ↓ AI provider API ↓ Response back to user ``` A more realistic production architecture looks like this: ```text User ↓ Frontend ↓ Backend API ├── PostgreSQL for users, messages, billing, metadata ├── Redis for cache, sessions, rate limits, queues ├── Vector database for document search and embeddings ├── Worker process for background jobs ├── Object storage for uploaded files └── AI provider API for model responses ``` The backend is the center of the system. It connects your product to the AI provider, but also controls everything around that provider. That is the difference between a demo and a real AI application. ## Core infrastructure components An API-based AI chatbot usually needs several infrastructure pieces. Not every project needs all of them on day one, but most serious products eventually use some version of this stack. ## 1. Backend API server The backend API server is the main application layer. It may be built with: * Node.js * Python * FastAPI * Flask * Django * Laravel * Go * Ruby on Rails * .NET * Java The backend receives user requests, validates them, builds prompts, calls AI APIs, stores results, and returns responses. For small teams, this is usually the first thing to deploy on a VPS. A simple starting point: ```text Ubuntu VPS ↓ Nginx reverse proxy ↓ Backend app ↓ PostgreSQL / Redis / AI provider API ``` ## 2. Database Most AI chatbots need a relational database. PostgreSQL is a common choice because it works well for: * users * teams * organizations * permissions * subscriptions * chat sessions * conversation metadata * message history * usage tracking * audit logs * billing events * application settings A database gives your AI chatbot memory at the product level. Without a database, you may be able to generate answers, but you cannot build a serious product. ## 3. Redis Redis is useful for fast, temporary, and high-frequency data. In AI chatbot infrastructure, Redis can help with: * caching * session storage * rate limiting * request deduplication * queue management * temporary conversation state * API cooldowns * token budget counters * background job coordination Redis is especially useful when the app becomes more than a simple request-response chatbot. For example, if users upload documents and you need to process them in the background, Redis can support a queue system that sends jobs to workers. ## 4. Queue and workers Many AI tasks should not run directly inside the web request. Examples: * document parsing * file conversion * embedding generation * long summaries * report generation * email workflows * scheduled jobs * webhook processing * batch AI calls * retrying failed provider requests If these jobs run inside the main web request, users may wait too long or the request may time out. A better pattern is: ```text User request ↓ Backend API ↓ Add job to queue ↓ Worker processes job ↓ Store result ↓ Notify user or update UI ``` This keeps the app responsive. It also makes scaling easier because workers can be separated from the main web server later. ## 5. Vector database or vector search Many AI chatbots need to answer questions using private documents or company knowledge. That is where vector search comes in. A vector search system stores embeddings so the app can retrieve relevant chunks of information before calling the AI model. Typical use cases: * support knowledge base chatbot * internal company assistant * document Q&A * legal document assistant * product documentation chatbot * onboarding assistant * customer success copilot * sales enablement assistant A simplified retrieval flow looks like this: ```text User question ↓ Create query embedding ↓ Search vector database ↓ Retrieve relevant context ↓ Send context + question to AI API ↓ Return grounded answer ``` This is often called retrieval-augmented generation, or RAG. A simple AI chatbot may not need vector search. A chatbot that answers from private knowledge usually does. ## 6. Object storage AI chatbot products often handle uploaded files. Examples: * PDFs * Word documents * CSV files * images * contracts * support transcripts * knowledge base exports * product manuals The app should not always store these directly on the application server. For many products, object storage is better for uploaded files because it separates file storage from compute. A common pattern: ```text User uploads file ↓ Backend stores file in object storage ↓ Worker extracts text ↓ Worker creates embeddings ↓ Vector database stores searchable chunks ``` This is cleaner than keeping everything inside one app directory. ## 7. Reverse proxy A reverse proxy such as Nginx or Caddy sits in front of your backend app. It can handle: * HTTPS * request routing * compression * static files * connection handling * basic security headers * proxying traffic to the app * redirecting HTTP to HTTPS A common setup: ```text User browser ↓ Nginx ↓ Backend app on localhost ``` This keeps the app port private and exposes only standard web ports. ## 8. Monitoring and logs AI chatbot infrastructure needs visibility. You should be able to answer: * Is the app online? * Are AI API calls failing? * Are users seeing errors? * Are requests timing out? * Are workers stuck? * Is Redis overloaded? * Is the database slow? * Are rate limits being hit? * Are costs increasing? * Which deployment caused problems? At minimum, track: * application logs * error logs * request latency * AI API latency * failed AI API calls * token usage or request volume * database performance * queue depth * worker failures * disk usage * CPU and RAM usage Observability becomes more important as the AI app moves from demo to product. ## Why queues and background workers matter AI apps often involve slow or unpredictable tasks. A normal web app might save a form and return immediately. An AI app may need to: * call an external AI API * wait for streaming output * process documents * generate embeddings * summarize long files * retry failed requests * call multiple tools * update a vector database * generate follow-up actions If all of this happens inside the main web request, the app becomes fragile. Queues solve this. They let you process long-running work outside the user request. For example: ```text User uploads 50-page PDF ↓ Backend accepts file ↓ Queue job created ↓ Worker extracts text ↓ Worker chunks document ↓ Worker creates embeddings ↓ Worker stores vectors ↓ User can ask questions later ``` This is a much better experience than forcing the user to wait while everything happens synchronously. ## Rate limits, retries, and API failure handling AI APIs can fail. They can also be slow, rate-limited, unavailable, or return errors. Your backend should expect this. A reliable AI chatbot backend should handle: * timeouts * retries * rate limits * provider errors * invalid responses * partial streaming failures * duplicate requests * user cancellation * slow requests * fallback behavior * graceful error messages Bad pattern: ```text User sends message ↓ Backend calls AI API ↓ AI API fails ↓ User sees generic error ``` Better pattern: ```text User sends message ↓ Backend calls AI API with timeout ↓ If temporary failure, retry safely ↓ If still failing, return clear message ↓ Log error for debugging ↓ Track failure rate ``` You do not need a complex system on day one. But you should avoid pretending AI APIs will always respond perfectly. Production AI apps need failure handling. ## Streaming responses Many chatbots stream responses token by token. This makes the product feel faster because the user sees output while the model is still generating. Streaming requires your backend to handle open connections properly. Your infrastructure should support: * long-lived HTTP responses * connection timeouts * reverse proxy configuration * frontend streaming UI * cancellation handling * partial response storage * error handling during streaming For a basic chatbot MVP, streaming is optional. For a polished chat experience, it often matters. ## Security basics for AI chatbot infrastructure AI chatbots introduce security risks. Your backend may handle: * user messages * private documents * API keys * customer data * uploaded files * internal knowledge * database credentials * AI provider credentials * billing information * admin access Start with these basics. ## Protect API keys Never expose AI provider API keys in frontend code. API keys should live on the server. Bad pattern: ```text Browser → AI provider API directly using public key ``` Better pattern: ```text Browser → your backend → AI provider API ``` This lets your backend control usage, permissions, rate limits, and logging. ## Validate users and permissions Do not assume every authenticated user can access every conversation or file. Check: * user ID * organization ID * workspace access * document permissions * admin role * billing status * usage limits This is especially important for multi-tenant SaaS chatbots. ## Do not expose private services publicly Databases, Redis, admin panels, and internal dashboards should not be open to the public internet. Only expose what must be public. For many AI apps, public ports should usually be limited to: * 80 for HTTP * 443 for HTTPS * SSH access restricted and secured Private services should be bound to localhost, private networking, or protected access controls. ## Sanitize and control uploaded files If your AI chatbot accepts files, treat uploads carefully. Think about: * file type limits * file size limits * malware scanning * text extraction safety * storage permissions * user access controls * deletion policy * retention rules * private data exposure Document chatbots are useful, but uploaded files create real operational responsibility. ## Log carefully Logs help debugging. But logs can also leak sensitive data. Avoid logging: * full API keys * passwords * secrets * private documents * payment data * unnecessary personal data * full prompts containing sensitive customer information Log enough to debug. Do not log everything blindly. ## When one VPS is enough One VPS is often enough for an AI chatbot MVP or early production product. A simple architecture can run: * backend API * Nginx or Caddy * PostgreSQL * Redis * worker process * application logs * monitoring agent Example: ```text Single VPS ├── Nginx ├── Backend API ├── PostgreSQL ├── Redis ├── Worker process └── Monitoring ``` This can be a good starting point when: * traffic is low to moderate * the app is early-stage * the team wants simplicity * the database is not huge * workers are not heavy * uptime requirements are reasonable * the product is still validating demand * the team wants predictable monthly cost Do not overbuild too early. For many AI products, the first bottleneck is not infrastructure. It is product-market fit, prompt quality, onboarding, retention, and workflow design. A simple VPS keeps the system understandable. ## When you need more than one VM As the AI product grows, the single-server setup may become limiting. Move toward multi-VM architecture when: * web traffic grows * background jobs slow down the app * database load increases * Redis becomes critical * workers need independent scaling * downtime risk becomes unacceptable * deploys need better separation * staging and production must be isolated * monitoring becomes more important * the team needs clearer security boundaries A next-step architecture: ```text Load balancer ↓ App VM ↓ Database VM ↓ Redis / queue VM ↓ Worker VM ↓ Monitoring / logs ``` You do not need this on day one. But it is good to design the app so it can grow into this structure. The easiest way to scale later is to avoid hard-coding everything into one machine from the beginning. ## Single VPS vs multi-VM AI chatbot architecture | Stage | Infrastructure | Best for | | ---------------- | -------------------------------------------------- | ------------------------------------------- | | Prototype | Local app or small VPS | Testing idea and UI | | MVP | One VPS with app, database, Redis, worker | Early users and product validation | | Early production | VPS with app + managed or separate database | More reliability and safer operations | | Growing product | Separate app, database, Redis, worker VMs | Higher traffic and background jobs | | Larger scale | Load balancer, multiple app VMs, separate services | Teams with serious uptime and scaling needs | Start simple. Scale when the workload proves it needs more structure. ## Example MVP stack for an AI chatbot on a VPS A practical MVP stack could look like this: ```text Ubuntu VPS Nginx Node.js or FastAPI backend PostgreSQL Redis Worker process AI provider API Basic logs Daily backups ``` This stack can support: * user login * chat sessions * AI API calls * saved conversations * rate limits * background jobs * document processing * basic admin tools * staged deployment process For many builders, this is enough to launch the first version. ## Example production-ready stack A stronger production setup could look like this: ```text Frontend ↓ Load balancer ↓ App VM ↓ PostgreSQL VM or managed database ↓ Redis / queue VM ↓ Worker VM ↓ Object storage ↓ Monitoring and logs ``` This setup is better when: * the app has paying users * uptime matters * background jobs are frequent * database load is growing * multiple developers deploy changes * file uploads are common * business data must be protected * the app needs staging and production separation This is the point where infrastructure becomes part of the product experience. ## Cost control for AI chatbot infrastructure AI chatbot cost has two sides. The first is infrastructure cost. This includes: * VPS * database * object storage * backups * bandwidth * monitoring * logs The second is AI provider cost. This includes: * model API calls * input tokens * output tokens * embeddings * batch jobs * retries * tool calls * image, audio, or multimodal usage if used A good backend helps control both. You can reduce waste by adding: * request caching * prompt size limits * document chunking * rate limits per user * usage quotas * retry limits * model selection by task * background batch processing * shorter system prompts * response length controls * analytics for expensive users or workflows Infrastructure is not just about uptime. It also helps control AI spend. ## Common mistakes when building AI chatbot infrastructure ## Mistake 1: Calling the AI API directly from the frontend This exposes secrets and removes backend control. Use a backend server. ## Mistake 2: Not storing conversations properly Chat history is product data. Store it in a database with user and organization ownership. ## Mistake 3: No rate limits Without rate limits, one user or bug can create high API usage. Use rate limits by user, organization, IP, or plan. ## Mistake 4: No queue for slow tasks Long-running AI tasks should often run in background workers. Do not force every task into the main web request. ## Mistake 5: No observability If you cannot see errors, latency, queue depth, and AI API failures, you cannot operate the product properly. ## Mistake 6: Treating prompts as hard-coded text Prompts become part of the application. Version them, test them, and review changes. ## Mistake 7: Ignoring data privacy AI chatbots often handle sensitive information. Think carefully about retention, logs, access, and user permissions. ## Mistake 8: Overbuilding before users exist Do not build enterprise-scale infrastructure before validating the product. Start with a clean VPS architecture. Scale when the workload proves it needs it. ## Mistake 9: Underbuilding after users arrive Once customers depend on the chatbot, infrastructure matters more. Add backups, monitoring, staging, security hardening, and recovery planning. ## What to monitor in an AI chatbot app Monitor both system health and AI-specific behavior. System metrics: * CPU usage * RAM usage * disk usage * network usage * database performance * Redis memory * queue depth * worker failures * HTTP error rate * request latency AI-specific metrics: * AI API latency * AI API error rate * timeout rate * retries * token usage * cost per user * cost per workspace * failed generations * average response length * document processing failures * embedding job failures Product metrics: * messages per user * retained users * active workspaces * completed workflows * user satisfaction * support escalations * conversion from trial to paid A chatbot that is technically online can still be failing as a product. Monitor the system and the user experience. ## How Raff VM fits AI chatbot infrastructure Raff VM is a good fit for teams building API-based AI chatbots because these apps often need a reliable cloud server more than a GPU cluster. A Raff VM can run: * backend API server * Nginx or Caddy reverse proxy * PostgreSQL * Redis * worker processes * Docker workloads * internal AI tools * chatbot backends * SaaS admin panels * staging environments * monitoring tools For an MVP, one Raff VM can act as the main backend server. As the product grows, teams can separate services across multiple VMs: ```text App VM Database VM Redis / queue VM Worker VM Monitoring VM ``` This gives the app a clean growth path. Raff VM fits AI chatbot teams that want: * simple deployment * full server control * predictable monthly pricing * strong CPU performance * NVMe storage * unmetered bandwidth * Linux or Windows VM options * a practical path from MVP to production The goal is not to make infrastructure complicated. The goal is to give the AI product a stable place to run. ## Practical launch checklist Before launching an AI chatbot backend, check the basics. ## Server setup * Choose a VPS size that fits your expected traffic. * Use a stable Linux distribution. * Configure SSH key access. * Set up a firewall. * Install your runtime. * Put Nginx or Caddy in front of the app. * Use HTTPS. * Keep the app process managed with systemd, PM2, Docker, or another process manager. ## App setup * Store API keys on the server, not in frontend code. * Use environment variables or a secrets strategy. * Add authentication. * Store users and conversations in a database. * Add rate limits. * Add request timeouts. * Handle retries safely. * Log failures. * Add basic admin visibility. ## AI setup * Track model usage. * Limit prompt size. * Control response length. * Add usage quotas. * Handle API provider errors. * Add streaming only when the backend and proxy are ready. * Use background workers for slow tasks. * Test with real user workflows. ## Data setup * Back up the database. * Decide retention rules. * Protect uploaded files. * Avoid logging sensitive data. * Separate user data by organization or workspace. * Test restore before production. ## Operations setup * Monitor uptime. * Monitor disk usage. * Monitor logs. * Monitor queue depth. * Monitor AI API failures. * Create a rollback plan. * Create a staging environment before serious releases. A simple checklist prevents many painful launch problems. ## When a VPS is not enough A VPS is a good starting point for many AI chatbot apps, but it is not always enough. You may need more infrastructure when: * you run local LLM inference * you need GPU acceleration * traffic is very high * uptime requirements are strict * database size grows quickly * multiple workers are constantly busy * customers require dedicated environments * compliance requirements increase * you need regional deployment * you need high availability architecture At that point, you may move toward: * multiple VMs * load balancers * managed databases * object storage * Kubernetes * GPU servers * dedicated vector search infrastructure * separate environments for each customer Do not start there unless the product needs it. But design your system so it can grow. ## FAQ ### Do AI chatbots need GPU servers? Not always. API-based AI chatbots usually do not need GPU servers because the AI model runs through an external provider API. The chatbot backend still needs reliable infrastructure for users, prompts, sessions, queues, databases, logs, and API orchestration. ### Can I run an AI chatbot backend on a VPS? Yes. Many AI chatbot MVPs and early production apps can run on a VPS, especially if they use external AI APIs. The VPS can host the backend API, reverse proxy, PostgreSQL, Redis, worker processes, and monitoring tools. ### What infrastructure does an AI chatbot need? A typical AI chatbot needs a backend API server, database, AI provider integration, authentication, logging, rate limits, and error handling. More advanced chatbots may also need Redis, queues, background workers, object storage, and vector search. ### What database should I use for an AI chatbot? PostgreSQL is a strong default for users, conversations, organizations, permissions, usage tracking, and metadata. If the chatbot uses private documents or knowledge search, you may also need vector search or a vector database. ### Do I need Redis for an AI chatbot? Not always, but Redis is useful for caching, sessions, rate limits, queues, temporary state, and background job coordination. It becomes more useful as the chatbot grows beyond a simple request-response app. ### What is the best architecture for an AI chatbot MVP? A practical MVP architecture is one VPS running Nginx or Caddy, a backend API, PostgreSQL, Redis, and a worker process. This keeps infrastructure simple while still supporting real users, stored conversations, and background tasks. ### When should I split an AI chatbot across multiple VMs? Split the architecture when traffic grows, background jobs slow down the app, the database needs isolation, workers need independent scaling, or uptime requirements become more serious. A common next step is separate app, database, Redis, and worker VMs. ### How does Raff VM help with AI chatbot infrastructure? Raff VM gives teams a cloud server foundation for running AI chatbot backends, APIs, Redis, PostgreSQL, workers, Docker workloads, staging environments, and monitoring tools. It is a practical starting point for API-based AI apps that need reliable backend infrastructure without unnecessary cloud complexity. ## Conclusion AI chatbots may look like model-driven products, but real AI products still depend on infrastructure. For API-based chatbots, the model usually runs through an external provider. Your responsibility is the backend. That backend must handle users, sessions, prompts, context, database writes, Redis, queues, workers, API failures, rate limits, logs, security, and uptime. For many teams, a VPS is the right starting point. It gives enough control to build a real product without forcing the team into complex cloud architecture too early. Start with a clean VPS setup. Run the backend, database, Redis, and workers properly. Add monitoring, backups, security, and staging. Then split into multiple VMs or managed services when the workload proves it needs more structure. For builders creating AI chatbots, AI agents, SaaS copilots, internal AI tools, or document Q&A systems, Raff VM provides a simple cloud server foundation for the backend infrastructure that keeps the product running. The AI model may generate the answer. But your infrastructure makes the product reliable. --- ### Cloud Computing in 2026: What Small Teams Should Watch URL: https://rafftechnologies.com/blog/cloud-computing-in-2025-navigating-the-new-frontiers Published: 2025-06-30T00:00:00.000Z Description: Cloud Computing in 2026: What Small Teams Should Watch Cloud computing in 2026 is not only about AI data centers, hyperscaler spending, or the next big platform announcement. For small teams, startups, developers, and SMBs, the real cloud question is more practical: how do you get reliable infrastructure without buying more complexity than you can operate? At Raff Technologies, we see this every day. Most teams do not wake up asking for “cloud transformation.” They need a VM for an app, a database for a product, storage for files, a secure test environment, or a simple way to move faster without turning infrastructure into a full-time job. That is why the most important cloud trend in 2026 is not only bigger infrastructure. It is more focused infrastructure. The teams that win will not be the ones using every cloud service available. They will be the ones choosing the few services that directly help them ship, secure, automate, and scale. ## The Cloud Market Is Bigger, But Teams Need Simpler Decisions The cloud industry keeps expanding, but that does not mean every team needs a larger cloud footprint. This is the mistake many small teams make. They look at enterprise cloud adoption and assume they need the same architecture. They see AI infrastructure, multicloud diagrams, edge computing, Kubernetes, managed platforms, serverless, and automation tools — then they feel behind before they have even deployed their first useful workload. But small teams do not need to copy enterprise infrastructure. They need to understand what problem they are solving. A startup launching a SaaS app needs a different cloud model than a global enterprise running hundreds of workloads. A student learning Linux needs a different cloud model than a bank designing compliance-heavy systems. An SMB hosting an internal tool needs a different model than a hyperscaler training foundation models. The right question is not “What is everyone using?” The right question is: > **What is the smallest reliable cloud architecture that solves our current problem and still gives us room to grow?** That is the lens small teams should use in 2026. ## AI Is Making Infrastructure More Important, Not Less AI is changing cloud infrastructure, but not always in the way people expect. The loudest part of the AI cloud story is GPU clusters, model training, and massive data center investment. That matters, but it is not the whole story. For many small teams, AI creates a different need: more automation, more internal tools, more API-connected workflows, and more backend services that need reliable compute. AI tools still need somewhere to run. Automation agents need servers. Vector databases need storage. Internal dashboards need hosting. Webhooks need endpoints. MCP servers, workflow engines, and API bridges need secure environments. That means cloud VMs are not becoming less relevant. In many cases, they are becoming more relevant because they are the flexible base layer for AI-assisted development and automation. A [Raff Linux VM](/products/linux-vm) can host the practical side of AI workflows: automation services, backend APIs, internal tools, n8n instances, testing environments, model-adjacent services, and lightweight agent infrastructure. This is where the opportunity is for small teams. You do not need to build an AI data center to benefit from AI infrastructure. You need clean, secure, flexible compute that can run the tools around your AI workflows. ## Cost Control Will Matter More Than Cloud Access In 2026, cloud access is not the problem. Almost anyone can create an account and launch resources. The problem is cost control. Small teams need to know what they are paying for, why they are paying for it, and when to resize, stop, or replace a workload. Cloud waste usually starts quietly: one oversized server, one forgotten test environment, one storage volume nobody owns, one workload copied from production “just in case.” Large enterprises can sometimes absorb waste for a while. Small teams feel it quickly. That is why cost control should be treated as a product habit, not an accounting task. Every workload should have a reason, owner, size, and review point. For Raff users, that starts with choosing the right VM size instead of guessing. A workload that needs 2 GB RAM should not be deployed on a large machine because the team is afraid to make a decision. A database that needs consistent CPU should not be placed on the wrong plan because the team only looked at monthly price. If you are unsure where to start, use [Choosing the Right VM Size](/learn/guides/choosing-right-vm-size) before deploying production workloads. If you are comparing predictable performance against lower-cost shared compute, read [Shared vs Dedicated vCPU](/learn/guides/shared-vs-dedicated-vcpu). Cloud cost control is not about choosing the cheapest plan. It is about choosing the plan that matches the workload. ## Simple Cloud Will Keep Winning for SMBs and Startups The more complex the cloud market becomes, the more valuable simple infrastructure becomes for small teams. This may sound counterintuitive, but it is true. Complexity has a cost. Every new service adds a learning curve, security model, billing model, and operational responsibility. Sometimes that complexity is worth it. Often, it is not. For many SMBs and startups, the best first cloud architecture is still simple: * One VM for the app * A database when needed * Backups and snapshots when the environment matters * Private networking when services need isolation * Object storage when files should not live on the app server * A load balancer when one app server is no longer enough That path is understandable. It gives the team a way to start small and grow only when the workload demands it. This is the reason Raff’s positioning is intentionally practical. We are not trying to make every small team buy cloud like an enterprise. We are trying to give them the core infrastructure they actually need first: VMs, storage, networking, backups, snapshots, and a path to scale. If this sounds familiar, read [Small Teams Need Simple Cloud, Not More Complexity](/blog/simple-cloud-for-small-teams). That article explains why small teams should avoid buying complexity before their workloads earn it. ## The VM Is Still the Most Understandable Cloud Building Block Every few years, someone says virtual machines are old news. Yet VMs keep remaining useful because they are understandable. A VM gives you a server. You know where the app runs. You know where logs live. You know which operating system is installed. You can SSH into it. You can install packages, configure services, monitor resources, resize when needed, and rebuild from a clean baseline. That clarity matters. For developers, VMs are useful because they behave like real infrastructure. For founders, they are useful because cost and ownership are easier to understand. For SMBs, they are useful because a VM maps directly to a business need: host this app, run this tool, test this service, support this client. Containers, managed platforms, and serverless all have their place. But in 2026, the VM is still one of the strongest starting points for teams that want control without unnecessary abstraction. That does not mean every workload should stay on one VM forever. It means one VM is often the right place to begin. When a workload grows, the team can resize vertically, split app and database roles, add workers, introduce caching, or move multiple app VMs behind a load balancer. Raff’s [Single VM vs Multi-VM Architecture for SaaS Apps](/learn/guides/single-vm-vs-multi-vm-saas-architecture) explains that growth path in more detail. ## Automation Will Move From Nice-to-Have to Expected In 2026, automation is no longer only for large DevOps teams. Small teams increasingly expect infrastructure to support repeatable workflows. They want to provision environments faster, trigger tasks from APIs, connect tools, automate backups, and reduce manual work without hiring a full platform team. The key is to automate the right things. Bad automation makes bad decisions faster. Good automation turns a known, repeated action into a safer workflow. A practical small-team automation path looks like this: * Start with manual deployment until the workflow is understood * Document the steps * Automate provisioning or setup * Add monitoring and alerts * Use API keys carefully * Keep rollback simple * Review permissions regularly This is where cloud infrastructure and automation tools meet. A VM can host automation engines, internal tools, API bridges, and workflow systems. A platform API can help teams connect infrastructure actions to business workflows. If your team is thinking about cloud automation, read [Raff API Keys for Small-Team Automation](/learn/guides/raff-api-keys-automation-small-teams). For workflow automation specifically, Raff’s [n8n self-hosted automation guide](/learn/guides/n8n-self-hosted-workflow-automation-guide) is a useful companion. ## Data Will Need Better Separation In early-stage projects, teams often keep everything together: app, database, uploads, logs, backups, and background jobs. That can work for a while. But in 2026, small teams should become more disciplined about separating data from application compute. The reason is simple: applications can be rebuilt faster than data can be recovered. User uploads should not live forever on the app server if the product is growing. Databases should not be treated like disposable local files. Backups should not be an afterthought. Snapshots should not be confused with a full data strategy. As workloads mature, teams should ask: * Where does persistent data live? * Is the database separate from the app? * Are backups tested? * Are user uploads stored outside the app server? * Who can access production data? * Can the environment be rebuilt if the VM fails? * Does the team know the recovery process? This is where products such as managed databases, object storage, volumes, backups, and snapshots become important. The point is not to add complexity for its own sake. The point is to protect the parts of the system that matter most. For growing SaaS apps, the database is usually the first thing worth separating from the app server. Raff’s [Managed Database or VM Database](/learn/guides/managed-database-or-vm-database) guide explains when to use a managed database and when running your own database on a VM still makes sense. ## Security Will Be About Defaults and Discipline Security in 2026 will not only be about advanced tools. It will also be about whether teams consistently do the basics. For small teams, the most common security problems are rarely exotic. They are usually simple: * Public services that should be private * Weak SSH practices * Unpatched servers * Over-permissive firewall rules * Credentials stored carelessly * No backup testing * No clear ownership * Too much access for too many people * Test environments treated like production Good cloud security starts with defaults and discipline. A secure VM setup should include SSH keys, firewall rules, least-privilege access, regular updates, backups, and clear ownership. If the workload involves internal services, private networking should be considered early. If the app handles customer data, backup and recovery planning should not wait until after an incident. This is why Raff’s infrastructure topics connect together. VM sizing, private networking, backups, firewalls, and scaling are not separate concerns. They are all part of operating cloud systems responsibly. A useful starting point is [Cloud Firewall Rules Explained](/learn/guides/cloud-firewall-rules-explained), especially if your team is exposing services to the internet or connecting multiple VMs. ## Multicloud Is Not Automatically a Strategy Multicloud gets a lot of attention, but small teams should be careful with it. Using multiple cloud providers can reduce vendor dependency and improve resilience in some cases. It can also multiply complexity. Every provider adds separate networking, billing, IAM, monitoring, deployment, and support models. For a small team, multicloud should solve a real problem, not create a more impressive architecture diagram. Good reasons for multicloud include: * Regulatory or customer requirements * Geographic latency needs * Specific service availability * Disaster recovery planning * Avoiding dependency on one critical provider * Cost optimization for specific workloads Weak reasons include: * “Large companies do it” * “It sounds more resilient” * “We want optionality someday” * “It looks more enterprise” Most small teams should first build one clean, documented, secure cloud environment. Then they can add additional providers when the business need is clear. The same principle applies to every cloud trend: adopt what solves the current problem, not what makes the diagram look modern. ## What This Means for Small Teams If you are planning cloud infrastructure in 2026, keep your decision process practical. Start with the workload. Choose the simplest reliable architecture. Use VMs when you need control and clarity. Use managed services when they remove real operational burden. Separate persistent data from disposable compute. Measure before scaling. Automate only after the workflow is understood. Add complexity only when the workload earns it. That is not a conservative strategy. It is a focused strategy. Small teams do not win by imitating enterprise cloud architecture. They win by moving faster with infrastructure they can understand, secure, and afford. For Raff users, this usually means starting with a [Linux VM](/products/linux-vm) or [Raff VM](/products/raff-vm), comparing plans on the [pricing page](/pricing), then adding databases, object storage, private networking, backups, and load balancing only when the workload asks for them. ## Final Thoughts Cloud computing in 2026 will be shaped by AI, automation, data growth, edge use cases, and continued infrastructure expansion. But small teams should not let the size of the market distract them from the reality of their own workload. The future of cloud is not only bigger. It is more selective. The best teams will know when to use a VM, when to resize, when to split services, when to automate, when to choose managed infrastructure, and when to say no to complexity. That is the cloud strategy Raff Technologies cares about: practical infrastructure for teams that need to build, test, ship, and grow without turning cloud into a maze. Start simple. Measure honestly. Add complexity only when it creates real value. --- ### Raff Is Now a Microsoft SPLA Partner URL: https://rafftechnologies.com/blog/raff-microsoft-spla-partner Published: 2026-05-08T00:00:00.000Z Description: Raff Is Now a Microsoft SPLA Partner Raff Technologies is now a Microsoft SPLA Partner. For us, this is more than a licensing milestone. It is a trust milestone. Raff Technologies has always focused on making cloud infrastructure easier for developers, startups, freelancers, learners, small teams, and businesses that need practical computing power without unnecessary complexity. Becoming a Microsoft Service Provider License Agreement Partner strengthens that direction, especially for customers who need Windows VMs, hosted Microsoft software, or clearer licensing around Microsoft workloads. The Microsoft Services Provider License Agreement, usually called SPLA, is a licensing program that allows service providers to license eligible Microsoft products and provide hosted software services to customers. In practical terms, Raff LLC is now licensed to host Microsoft software through our SPLA agreement where applicable. That matters because infrastructure is not only about CPU, RAM, storage, and bandwidth. It is also about confidence. When a customer launches a Windows VM, they are not only choosing a server. They are trusting the provider behind it to operate responsibly, license properly, and support the workload in a way that makes business sense. That is the part we want to make clearer. ## Why This Matters Microsoft software is widely used in real businesses. Windows Server, Remote Desktop environments, Microsoft-based applications, business tools, internal systems, and legacy workloads are still part of how many organizations operate. Even as Linux, containers, and open-source infrastructure continue to grow, Windows workloads remain important for many teams. For cloud providers, that creates responsibility. It is not enough to simply say, “we offer Windows servers.” Customers should also know whether the provider has a proper path for Microsoft software licensing in hosted environments. That is why SPLA matters. SPLA gives service providers a licensing framework for offering hosted Microsoft software services to customers. Microsoft explains the program as a way for service providers and software companies to license eligible Microsoft products on a monthly basis during a three-year agreement term, so they can provide software services and hosted applications to end customers. For Raff, this directly supports our Windows VM direction. It allows us to speak more clearly about Microsoft software licensing through our SPLA agreement and gives customers another reason to trust the infrastructure they are building on. ## What We Can Now Say Clearly There are a few phrases we can now use confidently and responsibly: * Raff LLC is a Microsoft SPLA Partner. * Raff LLC is a Microsoft Service Provider License Agreement Partner. * Raff LLC is licensed to host Microsoft software through SPLA. * Microsoft software licensing is available through our SPLA agreement where applicable. * Raff can provide hosted Microsoft software services under our SPLA agreement. These statements are important because they are specific. They do not overclaim. They do not suggest that Raff is Microsoft, or that Microsoft is endorsing every Raff service. They simply explain the licensing relationship in a way customers can understand. That distinction matters. Trust is not built by using the biggest words possible. Trust is built by being precise. So we will be careful with the language. We will not describe Raff as a “Microsoft-certified cloud provider” or “Microsoft-endorsed hosting provider” unless that exact status is separately granted and documented. SPLA is already a meaningful trust signal on its own. We do not need to exaggerate it. The accurate message is strong enough: Raff LLC is a Microsoft SPLA Partner, licensed to provide hosted Microsoft software services through the Microsoft Services Provider License Agreement. ## Why We Took This Step One lesson I have learned while building Raff is that business customers do not only buy infrastructure. They buy confidence. A developer may start by comparing CPU, RAM, storage, and price. A founder may look at monthly cost and deployment speed. A small team may care about simplicity and support. But as soon as Microsoft workloads enter the conversation, licensing clarity becomes part of the decision. That is especially true for Windows VM customers. A Windows VM is often used for business-specific tasks: remote desktop access, Windows-based applications, legacy software, testing environments, development workflows, administration tools, and workloads that cannot easily move to Linux. In those cases, licensing cannot be treated as an afterthought. This is one reason we pursued SPLA. We want Raff to be a serious infrastructure provider, not just a place where someone can launch a server. Serious infrastructure includes performance, pricing, networking, backups, support, and licensing clarity. The Microsoft SPLA partnership helps us strengthen that foundation. It gives us a clearer framework for hosting eligible Microsoft software services and gives customers a cleaner answer when they ask, “How is Microsoft licensing handled?” That question deserves a real answer. Now we have one. ## What This Means for Windows VM Customers For customers using or evaluating [Raff Windows VMs](/products/windows-vm), this means Raff has a proper licensing path for hosted Microsoft software through SPLA where applicable. That is important for several types of users. A business running Windows-based applications may need a cloud environment that is both practical and properly licensed. A freelancer may need a Windows VM for client work, testing, or remote access. A small team may need Windows Server infrastructure without buying and maintaining physical hardware. A company may want hosted Microsoft software services without managing every licensing detail alone. In all of these cases, the provider matters. The server is only one part of the decision. The operating model behind the server matters too. With SPLA, Raff can support hosted Microsoft software licensing in a more structured way. That gives customers a clearer foundation when choosing Raff for Windows workloads. It also fits our broader product direction. We want Raff to make cloud infrastructure feel easier to understand without removing the serious parts that customers depend on. Licensing is one of those serious parts. ## Why Licensing Clarity Is a Product Feature Licensing may not sound like a product feature at first. But for business infrastructure, it absolutely is. A product feature is not only something visible in the dashboard. It is anything that helps the customer use the service with more confidence. Clear pricing is a product feature. Reliable backups are a product feature. Private networking is a product feature. Support is a product feature. And for Microsoft workloads, licensing clarity is a product feature. If a customer is unsure whether their Windows VM is properly licensed, that uncertainty affects the whole experience. It affects trust. It affects procurement. It affects whether a business feels comfortable putting real work on the platform. That is why this announcement matters. It is not only a badge. It is part of Raff becoming more mature as a cloud infrastructure provider. ## The Practical Customer Benefit The practical benefit is simple: customers evaluating Windows workloads on Raff can now see that Microsoft software licensing is handled through Raff LLC’s SPLA agreement where applicable. This is especially useful for customers who care about: * Windows Server hosting * Remote Desktop workloads * hosted Microsoft software services * business applications that require Microsoft environments * development or testing on Windows VMs * clearer licensing responsibility * infrastructure providers with stronger trust signals For some users, Linux will still be the natural starting point. Raff continues to support Linux VMs for development, self-hosting, automation, Docker, web hosting, and general cloud workloads. But for customers who need Windows, this is a different conversation. They need performance and simplicity, yes. They also need licensing confidence. That is where SPLA makes Raff stronger. ## How This Fits Raff’s Direction Raff’s positioning is simple: Fast. Simple. Reliable. The Microsoft SPLA partnership supports the “Reliable” part in a very practical way. Reliability is not only uptime. Reliability is also whether the provider is taking the right operational steps behind the scenes. A customer may never read the full licensing terms behind a Microsoft-hosted workload. But they still benefit when the provider has a structured licensing agreement in place. That is the kind of invisible work that makes infrastructure more trustworthy. From the outside, a VM may look like CPU, RAM, storage, and an operating system. From the inside, cloud infrastructure is a series of responsibilities. Hardware responsibility. Network responsibility. Backup responsibility. Security responsibility. Billing responsibility. Support responsibility. Licensing responsibility. The stronger we become in each of these areas, the stronger Raff becomes as a company. That is why this milestone matters to me. It is not just about being able to say we are a Microsoft SPLA Partner. It is about what that says regarding the kind of cloud provider we are trying to become. ## What This Does Not Mean It is also important to be clear about what this does not mean. This does not mean every Microsoft product is automatically included in every Raff service. It does not mean every workload has the same licensing requirements. It does not mean customers should ignore their own compliance, software, or contractual responsibilities. It does not mean Raff is claiming a separate Microsoft endorsement beyond the SPLA relationship. Microsoft licensing can be specific, and the right answer depends on the product, workload, deployment model, and customer scenario. That is why we will continue to be careful with language. The correct statement is that Raff LLC is licensed to provide hosted Microsoft software services through the Microsoft Services Provider License Agreement where applicable. For customers, the practical takeaway is this: If your workload involves Microsoft software, Raff now has a clearer licensing framework to support hosted services through SPLA. That is the trust signal. ## What This Means for You If you are evaluating a Windows VM provider, do not only compare price. Price matters, but it is not the whole decision. Ask whether the provider can clearly explain how Microsoft software licensing is handled. Ask whether the infrastructure gives you enough control. Ask whether backups, snapshots, networking, and support fit your workload. Ask whether the pricing model is understandable before you deploy. Ask whether the provider is serious enough for the work you plan to run. If you need a Windows environment for development, business applications, remote access, testing, or hosted Microsoft workloads, you can start with [Raff Windows VMs](/products/windows-vm). If you are still comparing operating systems or workload types, you can also review [Raff VM options](/products/raff-vm) and [Raff pricing](/pricing) before deciding. For Microsoft workloads specifically, the important update is this: Raff LLC is now a Microsoft SPLA Partner, licensed to host Microsoft software through our SPLA agreement where applicable. That gives us a stronger foundation for Windows VM customers and a clearer trust signal for businesses evaluating Raff. ## Final Thought Cloud infrastructure is built in layers. Some layers are visible: the dashboard, the VM, the operating system, the storage, the price. Other layers are less visible: licensing, operational responsibility, provider maturity, and the decisions made before the customer ever launches a server. Becoming a Microsoft SPLA Partner strengthens one of those less visible layers. It helps Raff serve Windows VM customers more responsibly. It gives business users a clearer answer around Microsoft software licensing. And it moves Raff one step further toward becoming the kind of infrastructure company we want to build. Fast. Simple. Reliable. And now, stronger for Microsoft-hosted workloads through SPLA. --- ### Cloud-Native Apps in 2026: What Small Teams Get Wrong URL: https://rafftechnologies.com/blog/cloud-native-best-practices-2026 Published: 2026-01-26T00:00:00.000Z Description: Cloud-Native Apps in 2026: What Small Teams Get Wrong Cloud-native apps in 2026 are not about using every modern infrastructure tool at once. They are about building applications that can be deployed, recovered, scaled, observed, and secured without turning the platform itself into the hardest part of the product. At Raff Technologies, this is the cloud-native lesson I care about most: small teams should not jump from one VM directly into Kubernetes, service meshes, and five observability tools because a diagram told them to. A healthy cloud-native path usually starts simpler: one clean VM, containerized workloads, repeatable deployment, basic monitoring, backups, firewall rules, and only then more advanced orchestration when the workload earns it. Cloud-native means designing applications to take advantage of cloud infrastructure: elastic compute, automation, isolation, repeatable deployment, resilient recovery, and observable systems. It does not mean every app needs microservices. It does not mean every team needs Kubernetes on day one. It means your infrastructure should help the application survive change. ## Cloud-Native Is a Discipline, Not a Tool List The biggest mistake in cloud-native engineering is treating it like a shopping list. Containers? Add them. Kubernetes? Add it. CI/CD? Add it. Observability? Add it. Service mesh? Add it. Infrastructure as Code? Add it. That approach creates complexity faster than it creates resilience. A cloud-native system is not better because it has more layers. It is better when those layers solve specific operational problems. If a team cannot explain why a tool exists, who owns it, and what happens when it fails, the tool is not helping yet. The practical question is: > What is the smallest cloud architecture that lets this application deploy safely, recover quickly, and grow without becoming fragile? That question keeps engineering honest. ## Start With the Runtime You Can Operate Before Kubernetes, before autoscaling, before multi-region diagrams, start with a runtime your team can actually operate. For many small teams, that runtime is still a VM. A [Raff Linux VM](/products/linux-vm) gives you a clean server environment where you can install the application runtime, run Docker, configure Nginx, set up firewall rules, manage logs, and understand exactly what is happening. That clarity matters. A VM is not the opposite of cloud-native. A VM can be the first cloud-native building block if it is treated correctly: documented, reproducible, secured, monitored, backed up, and sized for the workload. The problem is not “using a VM.” The problem is using a VM like an undocumented box that nobody can rebuild. A cloud-native VM should have: * A clear role * A documented setup path * Firewall rules * SSH key-based access * Backups or snapshots * Monitoring and logs * A known deployment process * A plan for resizing or splitting later If those basics are missing, Kubernetes will not magically fix the environment. ## Containers Are Useful Because They Reduce Drift Containers are one of the most practical cloud-native tools because they reduce environment drift. A container packages the application with its runtime, dependencies, and configuration expectations. That makes it easier to run the same workload across development, staging, and production without relying on every server being manually configured the same way. For developers, containers solve a real problem: “it worked on my machine” becomes less common when the application runs in a defined container image. But containers are not enough by themselves. You still need to think about: * Persistent storage * Environment variables * Secrets * Image updates * Logs * Networking * Health checks * Backups * Resource usage * Deployment rollback Containers make applications more portable. They do not remove operational responsibility. If your team is still early, learn containers on one VM before jumping into clusters. Start with [Install Docker on Ubuntu 24.04](/learn/tutorials/install-docker-ubuntu-24-04), then move toward Docker Compose or a more structured deployment model. ## Kubernetes Should Solve a Real Problem Kubernetes is powerful, but it should not be the default answer for every small application. Use Kubernetes when you need orchestration: multiple services, multiple replicas, rolling updates, self-healing behavior, service discovery, resource scheduling, and standardized deployment across a cluster. Do not use Kubernetes only because the word “cloud-native” appears in the same sentence. A single app with one database and predictable traffic may run better on a simple VM or a small multi-VM architecture. A startup that has not validated its workload yet should probably not start by operating a cluster. A small team without DevOps capacity should be careful before adding a control plane, ingress layer, manifests, resource limits, cluster networking, and upgrade procedures. The right question is not “Is Kubernetes modern?” It is: > Is container orchestration currently one of our real bottlenecks? If the answer is no, start simpler. For a deeper decision path, read [Kubernetes for Developers: When to Use K8s vs VMs](/blog/kubernetes-for-developers-k8s-vs-vms). The short version is simple: Kubernetes is valuable when manual container operations become more expensive than running a cluster. ## Build for Failure, But Keep Failure Modes Visible Cloud-native systems should assume failure. Servers fail. Containers crash. Deployments break. Networks drop. Dependencies time out. Databases slow down. Disk fills up. Human mistakes happen. The goal is not to pretend failure can be avoided. The goal is to make failure smaller, more visible, and easier to recover from. A practical resilience plan includes: * Health checks * Graceful shutdowns * Retry limits * Timeouts * Queue-based processing for slow work * Backups * Snapshots before risky changes * Monitoring and alerting * Clear rollback steps * Separation between app and data The most important part is visibility. If your application fails and the team cannot quickly answer what changed, where it failed, and how to roll back, the system is not resilient yet. Simple infrastructure helps here. When the architecture is understandable, failure is easier to diagnose. When the architecture is overcomplicated, failure hides inside layers. ## Separate App, Database, Worker, and Cache When It Matters Cloud-native does not always mean microservices. Sometimes the first meaningful improvement is simply separating infrastructure roles. A common early setup puts everything on one VM: * App * Database * Background workers * Cache * Logs * Uploads * Cron jobs That is fine for a prototype. It becomes risky when the workload grows. The first role to separate is usually the database. Application compute is replaceable. Production data needs stronger protection. After that, background workers often deserve their own VM because jobs can spike CPU, memory, or database load without directly slowing web requests. A practical cloud-native progression looks like this: | Stage | Architecture | Why It Helps | |---|---|---| | Early app | One VM | Simple, low-cost, fast to understand | | First production step | App VM + database | Protects persistent data | | Growing workload | App VM + database + worker VM | Stops background jobs from hurting web traffic | | Scaling app | Multiple app VMs + load balancer | Adds capacity and better availability | | Advanced orchestration | Kubernetes | Standardizes container operations across a cluster | That path is boring in the right way. It adds complexity only when there is a reason. If your app is starting to outgrow one server, use [Single VM vs Multi-VM Architecture for SaaS Apps](/learn/guides/single-vm-vs-multi-vm-saas-architecture) to decide whether to split the database, workers, cache, or app servers before moving to Kubernetes. ## CI/CD Should Make Deployments Boring Cloud-native teams do not need dramatic deployments. A good deployment should be boring: repeatable, observable, reversible, and understood by the team. CI/CD helps because it turns the build-test-deploy path into a controlled workflow. But a pipeline should encode a process the team already understands. If the deployment process is unclear, automation will only hide the confusion. A practical small-team CI/CD path looks like this: * Build the application * Run tests * Build the container image * Deploy to staging * Verify the app * Create or confirm a recovery point * Deploy to production * Monitor logs and health * Roll back if needed The point is not to deploy 50 times a day. The point is to make each deployment safer. For small teams, a VM-based DevOps lifecycle can be enough for a long time. Raff’s [DevOps Lifecycle on VMs](/blog/devops-lifecycle-on-vms) explains how build, test, staging, deployment, and recovery can work without buying a heavy platform stack too early. ## Observability Should Answer Real Questions Monitoring tells you whether something is up. Observability helps you understand why something is behaving the way it is. For cloud-native apps, you need enough visibility to answer practical questions: * Is the app slow? * Is the database the bottleneck? * Are background jobs piling up? * Did the latest deployment increase errors? * Is memory leaking? * Are users affected? * Which service changed? * Can we roll back safely? Start simple. A small team does not need an enterprise observability stack on day one. It needs useful logs, basic metrics, uptime checks, deployment notes, and alerts tied to real user impact. As the system grows, add more: * Centralized logging * Metrics dashboards * Error tracking * Request tracing * Queue depth monitoring * Database performance metrics * Deployment annotations * Alert routing The rule is simple: observe what helps you make decisions. Do not collect data nobody uses. ## Security Belongs in the First Deployment Security should not be a later phase. The first deployment should already include the basics: SSH keys, firewall rules, least-privilege access, updates, backups, and clear ownership. A cloud-native app usually has more moving parts than a traditional single-server app. More services mean more network paths, credentials, ports, images, and dependencies. That makes early security discipline more important, not less. Start with these controls: * Use SSH keys instead of weak password access * Keep only necessary ports open * Put private services on private networks where possible * Use separate credentials for each service * Avoid storing secrets in source code * Patch the operating system and packages * Limit admin access * Back up important data * Review public exposure after every architecture change Firewall design is especially important. If a database, cache, worker, or internal API does not need to be public, do not make it public. Raff’s [Cloud Firewall Rules Explained](/learn/guides/cloud-firewall-rules-explained) is a good companion piece because cloud-native security starts with basic network boundaries before advanced tools matter. ## Recovery Is the Part Teams Ignore Until It Hurts A cloud-native app without recovery planning is not resilient. Backups, snapshots, rollback steps, and restore testing are part of the application architecture. They are not administrative extras. A good recovery plan answers: * What data must be protected? * How often is it backed up? * Where are backups stored? * Who can restore them? * How long does restore take? * Have we tested the restore process? * What happens if the latest deployment breaks production? * Can we roll back without losing data? Snapshots are useful before risky infrastructure changes. Backups are necessary for long-term recovery. They solve related but different problems. If your team has not tested recovery, do not call the system resilient yet. For a practical framework, read [Cloud Server Backup Strategies](/learn/guides/cloud-server-backup-strategies). Build recovery into the lifecycle before a real incident forces the lesson. ## Cost Is a Cloud-Native Design Constraint Cloud-native architecture should scale, but scaling without cost discipline creates waste. Small teams should treat cost as an engineering signal. If a workload is oversized, forgotten, duplicated, or running without an owner, the system is not well designed. Cost-aware cloud-native practices include: * Right-sizing VMs * Shutting down temporary environments * Separating workloads only when needed * Choosing dedicated CPU only when consistency matters * Avoiding Kubernetes before orchestration is necessary * Reviewing backups, volumes, and idle resources * Using staging environments intentionally * Measuring before scaling Raff’s [Choosing the Right VM Size](/learn/guides/choosing-right-vm-size) is useful here because many cost problems begin with guessing. Start with the workload, choose the smallest reasonable plan, measure, then resize when there is evidence. That is better than overprovisioning because the team is afraid to make a decision. ## Raff’s Practical Cloud-Native Path The Raff approach to cloud-native infrastructure is simple: start with usable building blocks, then add complexity only when the workload asks for it. A practical path on Raff looks like this: * Start with a Linux VM * Deploy the app * Containerize when consistency matters * Add backups and snapshots when the environment matters * Use firewall rules and private networking to reduce exposure * Split database and worker roles when one VM becomes too crowded * Add load balancing when one app server is not enough * Consider Kubernetes when orchestration becomes the real problem That path is not as flashy as starting with a full platform stack. But it is healthier for small teams because every layer has a reason. Cloud-native should make your system easier to change and recover. If it only makes the diagram look more modern, something is wrong. ## What This Means for You If you are building cloud-native apps in 2026, do not start with the tool. Start with the pressure. Are deployments risky? Improve CI/CD. Are environments inconsistent? Use containers. Are workloads competing on one VM? Split roles. Is one app server overloaded? Scale horizontally. Are services hard to debug? Improve observability. Is data at risk? Fix backups and recovery. Is the system too exposed? Tighten firewall rules and private networking. Are container operations becoming painful? Then evaluate Kubernetes. This is how you avoid cloud-native chaos. Start simple, measure honestly, and add infrastructure only when it solves a real operational problem. ## Final Thoughts Cloud-native best practices in 2026 are not about adopting every modern infrastructure trend. They are about building systems that are easier to deploy, easier to recover, easier to secure, and easier to scale without overwhelming the team operating them. For many teams, the right first step is still a clean VM, Docker, clear firewall rules, backups, and a boring deployment process. Kubernetes, advanced automation, and multi-service platforms come later when the workload proves they are worth it. That is the cloud-native path I trust: simple first, resilient always, complex only when necessary. Start with a [Raff Linux VM](/products/linux-vm), compare plans on the [pricing page](/pricing), and build the smallest reliable architecture your application actually needs. --- ### Why Backup Tools Matter More Than Backup Promises URL: https://rafftechnologies.com/blog/why-backup-tools-matter-more-than-backup-promises Published: 2026-05-03T00:00:00.000Z Description: Why Backup Tools Matter More Than Backup Promises Backup tools matter more than backup promises because recovery is not a slogan — it is an operational path that either works under pressure or does not. At Raff Technologies, we think about backups less as a checkbox and more as a chain of tools, decisions, and restore habits that must survive the worst possible moment: the moment when a server is already broken, a deployment has already gone wrong, or a database has already been damaged. The promise is usually easy to write. “Daily backups included.” “Your data is safe.” “Disaster recovery ready.” Those phrases look clean on a pricing page, but they do not answer the question that matters: can you actually get back to a working state when something fails? That is why I care more about the tools behind the promise. A backup strategy is not one feature. It is a set of recovery paths: snapshots for fast rollback, file-level backups for selective recovery, database dumps for application state, object storage for off-server copies, and restore tests to prove the whole thing is more than decoration. ## A Backup Promise Is Not a Recovery Plan A backup promise tells you that something is being copied. A recovery plan tells you what can be restored, where it can be restored, how long it should take, and how much data you may lose. That distinction sounds simple, but it is where a lot of teams get into trouble. They buy or configure “backup” and assume the job is done. Then the first serious incident arrives and they discover the backup is too old, too incomplete, stored on the same machine, missing database consistency, or impossible to restore without guessing. This is why we publish recovery-focused guides like [Understanding Cloud Server Backups: RPO, RTO, and Snapshots](/learn/guides/cloud-server-backup-rpo-rto-snapshots). RPO and RTO are not enterprise jargon. They are practical questions every server owner should answer. How much data can you afford to lose? How quickly do you need the system back? If you cannot answer those two questions, the backup promise is still vague. It may be technically true that a backup exists, but you do not yet know whether it solves your actual failure scenario. ## Tools Reveal What the Promise Really Means The tool you choose reveals the kind of failure you are preparing for. A VM snapshot helps when you need to roll back an entire server quickly. That is useful before risky upgrades, package changes, firewall edits, or application deployments. But a snapshot is not the same as a long-term backup strategy, because it captures a point-in-time state of the machine rather than giving you clean, application-aware recovery forever. That is why [Cloud Snapshots vs Backups: What’s the Difference?](/learn/guides/snapshots-vs-backups-cloud-server) exists as a separate guide. We do not want users to treat snapshots and backups as interchangeable words. They are different tools for different types of pain. File-level backups solve a different problem. If a user deletes an upload directory, a configuration file, or a project folder, you may not want to roll back the entire VM. You may only want the missing files. That is where tools like `rsync`, `tar`, and scheduled scripts are still useful. They are boring, predictable, and easy to inspect. Database backups solve another problem again. A database is not just a folder of files you can copy casually while writes are happening. PostgreSQL, MySQL, and MariaDB need backup methods that respect consistency. For databases, a “backup” that cannot restore a valid database is not a backup. It is just a false sense of comfort. The promise sounds the same in all three cases: “we have backups.” The tools tell the truth. ## The Dangerous Backup Is the One Stored Too Close to the Failure One of the most common mistakes we see in small infrastructure setups is storing the backup too close to the thing it protects. A backup folder on the same VM is better than nothing, but it does not protect you from enough failure modes. If the VM disk becomes corrupted, credentials are compromised, a bad script deletes too much, or the server needs to be rebuilt cleanly, a local-only backup may disappear with the incident. That is why off-server storage matters. A stronger backup design moves recovery data away from the main server path. It does not necessarily need to be complicated, but it does need separation. This is one reason [S3-compatible object storage](/learn/guides/s3-compatible-object-storage-use-cases-for-developers) is so useful in real infrastructure design. Object storage gives you a clean place for backups, database dumps, logs, exports, and application files that should not live forever on the VM disk. It separates compute from durable file storage. On Raff, that separation is deliberate. A [Linux VM](/products/linux-vm) should run the application. VM disk should hold the operating system and runtime state. [Object storage](/products/object-storage) should hold data that benefits from being outside the server lifecycle. When those responsibilities are mixed together, backup design becomes harder to reason about. ## Restore Testing Is Where Backup Marketing Ends The real test of a backup tool is not whether it produces files. The real test is whether you can restore those files into a working system. This is where backup promises often collapse. A dashboard says the job completed. A folder contains archives. A bucket contains objects. But no one has restored the database, checked the application, validated permissions, confirmed service startup, or measured how long the process takes. A backup that has never been restored is only a backup candidate. That is why I like simple restore drills. Pick a clean target. Restore the files. Import the database. Start the application. Check logs. Confirm users can reach the service. Write down what failed, then fix the backup process so the next restore is less dramatic. This is not glamorous work. It does not create a shiny feature announcement. But it is the difference between “we probably have backups” and “we know exactly how recovery works.” If you want a practical example, our tutorial on [automating backups with cron and rsync on Ubuntu 24.04](/learn/tutorials/automate-backups-cron-rsync-ubuntu-24-04) does not stop at scheduling a script. It also includes retention and restore thinking because the job is not finished when the archive is created. The job is finished when you can use it. ## The Right Tool Depends on the Failure No single backup tool protects against everything. A snapshot is excellent before an upgrade. It gives you a fast rollback path if the server state changes badly. But if the application writes bad data into the database and the snapshot happens after the corruption, the snapshot faithfully preserves the broken state. A file backup is useful when you need a specific directory or configuration file. But it may not capture a live database safely unless you dump the database properly first. A database dump is essential for application recovery. But it does not restore the whole server, firewall rules, system packages, Nginx configuration, TLS certificates, uploads, and background workers by itself. Object storage is excellent for keeping backup data away from the VM. But object storage is not a restore plan by itself. You still need naming conventions, retention, credentials, lifecycle rules, and restore documentation. Replication is useful for availability. But replication is not a replacement for backups because it can replicate bad changes too. This is why our guide on [PostgreSQL replication vs backups vs snapshots](/learn/guides/postgresql-replication-vs-backups-vs-snapshots) separates the failure classes clearly: replication helps you stay online, backups help you go back, and snapshots help you roll back infrastructure quickly. The wrong question is “which backup tool is best?” The better question is “which failure am I trying to survive?” ## Backup Tools Should Create Operational Options A good backup system gives you options when something goes wrong. You should be able to roll back the whole VM when the server state is the problem. You should be able to restore one folder when a file-level mistake is the problem. You should be able to restore a database when application state is the problem. You should be able to rebuild on a clean VM when the original server is no longer trustworthy. That last point matters. In a serious incident, restoring onto the same machine is not always the safest choice. If credentials were exposed, packages were modified, or unknown changes happened on the server, a clean rebuild may be better. In that case, the backup tool must support recovery away from the original machine. This is where object storage, documented restore steps, and infrastructure discipline work together. You can launch a new VM, pull clean backup data, restore the application, and cut traffic over once the result is verified. The backup tool is not just preserving history. It is creating a route out of chaos. That is also why we built Raff’s platform around separate primitives instead of pretending one checkbox solves recovery. Snapshots, automated backups, object storage, block storage, web console access, and private networking all solve different operational problems. The job of the platform is to make those tools available. The job of the operator is to combine them honestly. ## Promises Hide Trade-Offs. Tools Expose Them. Every backup decision has a trade-off. Frequent backups reduce data loss but increase storage usage. Long retention gives more recovery history but costs more and requires better organization. Snapshots restore quickly but are not a full substitute for independent backups. Database dumps are portable but must be scheduled and secured properly. Object storage is durable and flexible, but permissions and lifecycle rules need care. A vague promise hides those trade-offs. A real toolchain exposes them so you can make better decisions. This matters for small teams because they usually do not have a dedicated recovery engineer. The developer who deploys the app is often the same person who has to recover it. The founder who approves the cloud bill may also be the person explaining downtime to a customer. In that environment, backup design must be understandable. A simple backup plan that the team can restore under pressure is better than an impressive-looking plan nobody understands. ## A Practical Backup Stack for Small Teams For many small teams, a practical backup stack does not need to be complicated. Start with snapshots before risky infrastructure changes. Add automated VM backups for broad rollback coverage. Use database-native dumps for application state. Store copies outside the VM, ideally in object storage. Document the restore process. Then test it on a clean machine before the first real incident forces you to learn under pressure. That structure gives you several recovery paths: * Roll back quickly if a deployment breaks the server. * Restore a database if application state is damaged. * Recover specific files if something is deleted. * Rebuild cleanly if the original VM should not be trusted. * Keep backup data outside the server that failed. If you already use Raff Object Storage, the [AWS CLI tutorial for Raff S3-compatible storage](/learn/tutorials/raff-s3-object-storage-aws-cli) is a useful next step because it shows how to create buckets, upload files, sync directories, and generate pre-signed URLs. Once you can move data in and out of object storage reliably, you can build better backup workflows around it. The goal is not to make backups complicated. The goal is to make recovery less mysterious. ## What This Means for You If you are running production workloads, stop evaluating backup by the promise and start evaluating it by the restore path. Ask these questions: * What exact tool creates the backup? * What data does it include? * What data does it miss? * Where is the backup stored? * Can the backup survive the original VM failing? * Who has access to restore it? * How long would recovery take? * When was the last restore test? * What would we rebuild first if the server disappeared? Those questions are uncomfortable in a useful way. They turn backup from a marketing phrase into an operating practice. If you are just starting, begin with [Cloud Server Backup Strategies: Snapshots, RPO, and Recovery Planning](/learn/guides/cloud-server-backup-rpo-rto-snapshots). Then read [Cloud Snapshots vs Backups: What’s the Difference?](/learn/guides/snapshots-vs-backups-cloud-server). If you want a practical implementation path, follow [Automate Server Backups with Cron and Rsync on Ubuntu 24.04](/learn/tutorials/automate-backups-cron-rsync-ubuntu-24-04), then move off-server copies into [Raff Object Storage](/products/object-storage). Backup tools matter because incidents do not care about promises. They only care whether your recovery path works. At Raff, that is the standard we want our own infrastructure content to push toward: fewer vague claims, more usable tools, and restore processes that can survive the day they are actually needed. --- ### Kubernetes for Developers: When to Use K8s vs VMs URL: https://rafftechnologies.com/blog/kubernetes-for-developers-k8s-vs-vms Published: 2026-01-20T00:00:00.000Z Description: Kubernetes for Developers: When to Use K8s vs VMs Kubernetes is useful when your application has outgrown “one container on one server” and you need a reliable way to deploy, scale, update, and recover containerized workloads across multiple machines. For developers, the important question is not “Should I learn Kubernetes?” The important question is “When does Kubernetes solve a real infrastructure problem?” At Raff Technologies, we think Kubernetes should be treated as a serious operations layer, not a badge of technical maturity. A single VM, Docker Compose, or a small multi-VM setup is often the right first step. Kubernetes becomes valuable when the cost of managing containers manually becomes higher than the cost of running a cluster. Kubernetes, often shortened to K8s, is an open-source platform for managing containerized applications. It helps teams declare how an application should run, then works continuously to keep the system close to that desired state. That makes it powerful — but also easy to overuse too early. ## Kubernetes Solves Container Operations, Not Every Hosting Problem Kubernetes exists because containers are easy to start but harder to operate at scale. Running one Docker container on one VM is simple. Running dozens of containers across multiple machines, with rolling updates, service discovery, restarts, traffic routing, resource limits, secrets, and health checks, is a different problem. That is the problem Kubernetes was built to solve. Kubernetes helps answer operational questions like: * Where should this container run? * What happens if the container crashes? * How many replicas should exist? * How do we update without replacing everything manually? * How does traffic reach the right workload? * How do workloads discover each other? * How do we separate configuration from application code? * How do we scale a service without rebuilding the whole system? If those questions are not painful yet, Kubernetes may be premature. The first lesson for developers is simple: Kubernetes is not the first step in cloud infrastructure. It is the step you take when container operations become complex enough to justify an orchestration layer. ## The Developer Mental Model Think of Kubernetes as a control system for applications. You describe the desired state. Kubernetes tries to make the actual state match it. If you say, “run three replicas of this API,” Kubernetes schedules Pods across available nodes. If one Pod fails, Kubernetes can replace it. If you update the image version, Kubernetes can roll out the change gradually. If traffic needs a stable endpoint, Kubernetes uses a Service to route requests to the right Pods. This desired-state model is the core idea. A developer does not usually need to understand every Kubernetes internal component on day one. But they do need to understand the main objects they will work with. ## The Core Kubernetes Objects Developers Should Know Kubernetes has many concepts, but the beginner path should start with a few. | Concept | What It Means | Why Developers Care | |---|---|---| | Cluster | The full Kubernetes environment | This is where your workloads run | | Node | A machine inside the cluster | Nodes provide CPU, RAM, storage, and networking | | Pod | The smallest deployable unit | Your containers run inside Pods | | Deployment | A controller for running and updating Pods | This is how you run app replicas and rollouts | | Service | A stable network endpoint for Pods | This is how traffic reaches changing workloads | | Ingress | HTTP routing into the cluster | This is often how web apps become reachable | | ConfigMap | Non-secret configuration | Keeps config separate from container images | | Secret | Sensitive configuration | Stores credentials and tokens, but still needs care | | Namespace | Logical separation inside a cluster | Helps divide environments, teams, or workloads | You do not need to memorize the entire ecosystem before deploying your first application. Learn the objects that match the first workload: Deployment, Service, ConfigMap, Secret, and Ingress. That is enough to understand the basic Kubernetes loop. ## Kubernetes vs Docker Docker and Kubernetes solve different problems. Docker helps you package and run containers. Kubernetes helps you operate containers across a cluster. A developer can use Docker without Kubernetes. In fact, that is often the right starting point. Build the container. Run it locally. Deploy it on a VM. Understand logs, environment variables, volumes, networking, and image updates. Only after that should Kubernetes enter the picture. If you do not understand containers yet, Kubernetes will feel like a maze. If you understand containers first, Kubernetes becomes easier because you know what is being orchestrated. For Raff users, the practical path is usually: * Learn Linux basics * Learn Docker * Deploy one container on a VM * Use Docker Compose for a small stack * Split workloads if needed * Move to Kubernetes when orchestration becomes the problem If you are still at the Docker stage, start with [Install Docker on Ubuntu 24.04](/learn/tutorials/install-docker-ubuntu-24-04) before jumping into cluster concepts. ## When a VM Is Enough A VM is enough when your application is small, understandable, and easy to operate without orchestration. Use a VM when: * You have one app or a small stack * Traffic is predictable * Downtime is acceptable or easy to manage * One deployment path is enough * Docker Compose solves the workload cleanly * You do not need multiple replicas across nodes * You do not have a platform team * You want low operational overhead A [Raff Linux VM](/products/linux-vm) is often a better starting point than Kubernetes for early apps because it gives you full control without the cluster overhead. You can install Docker, run the app, configure Nginx, add a database, monitor logs, and understand the full system. There is nothing wrong with this. In fact, one of the mistakes I see teams make is moving to Kubernetes before they have a workload that deserves it. They add a control plane, manifests, ingress rules, resource requests, cluster networking, persistent volume decisions, and monitoring complexity before one VM has become a real bottleneck. That is not engineering maturity. That is premature complexity. ## When Kubernetes Starts to Make Sense Kubernetes starts to make sense when you need the same operational behavior across multiple containers, machines, environments, or teams. Use Kubernetes when: * You run multiple services that need independent scaling * You need rolling deployments across replicas * You need self-healing behavior for failed workloads * You need standardized deployment patterns * You have multiple environments with similar architecture * You need service discovery between internal components * You need resource requests and limits per workload * You need platform-level consistency across teams * You are already operating enough containers that manual management is painful A useful rule: Kubernetes is worth considering when the cost of not having orchestration becomes visible. That cost might appear as deployment risk, inconsistent environments, slow rollouts, poor failure recovery, manual scaling, or too many one-off server scripts. If you are not feeling those problems, do not force Kubernetes just because the industry talks about it. ## Kubernetes Is Not the Same as Microservices Kubernetes and microservices often appear together, but they are not the same thing. You can run a monolith on Kubernetes. You can run microservices without Kubernetes. You can run a modular monolith on VMs for a long time before a cluster becomes useful. This distinction matters because many teams confuse application architecture with infrastructure architecture. A small team should not split its codebase into microservices just because it wants to learn Kubernetes. That usually creates more problems than it solves. Kubernetes helps operate workloads. It does not automatically make a bad service boundary good. It does not fix unclear ownership. It does not remove the need for observability, security, database planning, or deployment discipline. If your team is still deciding whether to split the application itself, read [Monolith vs Microservices for Small Teams](/learn/guides/monolith-vs-microservices-small-teams) before treating Kubernetes as the answer. ## The Cost of Kubernetes Is Mostly Operational Kubernetes has infrastructure cost, but the bigger cost is usually operational. A cluster needs: * Cluster upgrades * Node upgrades * Networking decisions * Ingress configuration * Persistent storage planning * Resource requests and limits * Secrets management * Monitoring and alerting * Image registry workflow * RBAC and access control * Backup and recovery planning * Troubleshooting skills This is why I do not recommend Kubernetes as the default for every small team. A simple VM has fewer moving parts. A multi-VM architecture has more moving parts, but still less than a full cluster. Kubernetes becomes valuable when the workload needs orchestration badly enough to justify that operating surface. If your app is still early, the better investment may be right-sizing the VM, splitting the database, separating workers, or adding a load balancer before adopting Kubernetes. For that decision path, read [Single VM vs Multi-VM Architecture for SaaS Apps](/learn/guides/single-vm-vs-multi-vm-saas-architecture) and [Horizontal vs Vertical Scaling](/learn/guides/horizontal-vs-vertical-scaling-cloud). ## What Developers Should Learn First Developers should learn Kubernetes in layers. Do not start with Helm, operators, service meshes, admission controllers, and cluster autoscaling. Those are useful later, but they are not the first lesson. Start with this sequence: 1. Containers 2. Images 3. Pods 4. Deployments 5. Services 6. ConfigMaps 7. Secrets 8. Ingress 9. Resource requests and limits 10. Logs and rollout debugging That sequence teaches you how an app actually lives inside Kubernetes. The first useful goal is not “master Kubernetes.” The first useful goal is simpler: deploy one containerized app, expose it safely, update it, roll it back, and understand what happened. That is enough to make the platform real. ## A Practical Learning Path Here is the learning path I would recommend to a developer. First, containerize a small app. Use a basic API or web service you understand. Do not start with a complicated production application. Second, run the app with Docker locally. Confirm you understand the image, ports, environment variables, and logs. Third, deploy the same app to a VM. This teaches the difference between local development and real server operation. Fourth, run the app with Docker Compose if it needs a database or cache. This teaches multi-container thinking without a cluster. Fifth, deploy the same app to a local Kubernetes environment such as Kind or Minikube. Now you can compare the Kubernetes model against the Docker model. Sixth, learn Deployments and Services. These are the objects you will touch constantly. Seventh, learn ConfigMaps and Secrets. Configuration management becomes important quickly. Eighth, learn Ingress and TLS. Most real web apps need a safe route into the cluster. Ninth, learn resource requests and limits. This is where Kubernetes starts becoming an operations tool instead of a deployment toy. Tenth, learn how to debug. Use `kubectl get`, `kubectl describe`, logs, events, rollout status, and basic node inspection. That path keeps Kubernetes practical. ## Where Raff Fits Today Raff fits the Kubernetes learning path in two ways. First, Raff VMs are a practical foundation for learning the container and server skills that come before Kubernetes. You can deploy Ubuntu, install Docker, run a small app, test Docker Compose, build a staging environment, and understand the operations baseline before moving into clusters. Second, Raff’s Kubernetes product path is planned around managed container orchestration. The current Kubernetes product page lists a managed control plane, node and pod autoscaling, one-click cluster provisioning, monitoring, security updates, Helm support, operators, and CI/CD integration as expected capabilities. That matters because managed Kubernetes should remove part of the operational burden, especially around the control plane. But developers still need to understand workloads, resources, networking, and deployment behavior. Managed Kubernetes does not remove the need to understand Kubernetes. It removes some of the work required to operate the cluster infrastructure. Until the Kubernetes product is generally available, the most practical Raff path is: * Learn containers on a Raff VM * Run Docker and Docker Compose on Linux * Understand VM sizing and networking * Build small workloads first * Move to Kubernetes when orchestration is the problem That path is healthier than skipping straight to clusters. ## Common Kubernetes Mistakes Developers Make The first mistake is learning Kubernetes before learning containers. If Docker concepts are not clear, Kubernetes will feel unnecessarily difficult. The second mistake is using Kubernetes for one small app that would run perfectly well on a VM. That adds operational overhead without a real payoff. The third mistake is ignoring resource requests and limits. Kubernetes scheduling depends on resource planning. If you never define CPU and memory expectations, the cluster cannot make good placement decisions. The fourth mistake is treating Secrets as a complete security solution. Kubernetes Secrets are part of configuration management, not a full security model. Access control, encryption, network policy, and credential hygiene still matter. The fifth mistake is exposing too much. Services, ingress rules, dashboards, and admin endpoints should be reviewed carefully. Not every internal tool belongs on the public internet. The sixth mistake is skipping observability. If you cannot inspect Pods, logs, events, rollouts, and resource usage, you cannot operate Kubernetes safely. The seventh mistake is assuming Kubernetes fixes application architecture. It does not. If the app has poor boundaries, bad configuration, or fragile deployment behavior, Kubernetes may only make those problems more visible. ## Kubernetes and Security Kubernetes security starts with the same principle as cloud security generally: reduce unnecessary access. A secure Kubernetes setup should consider: * Who can access the cluster * Which users can deploy workloads * Which namespaces separate environments * Which services are public * Which secrets each workload can read * Which images are allowed * How updates are handled * How logs and events are monitored * How network traffic is restricted * How recovery works if a deployment breaks Kubernetes gives you powerful controls, but it also gives you many ways to misconfigure access. For developers, the most important habit is least privilege. A workload should have only the permissions, network access, and credentials it needs. A development namespace should not have production-level privileges. A public ingress should not expose internal dashboards. If your team is still building cloud security fundamentals, start with [Cloud Firewall Rules Explained](/learn/guides/cloud-firewall-rules-explained) and [Cloud Security Fundamentals](/learn/guides/cloud-security-fundamentals) before adding cluster complexity. ## What This Means for Developers If you are a developer, learn Kubernetes because it teaches how modern cloud-native systems are operated. But do not confuse learning Kubernetes with needing Kubernetes for every workload. Start with Docker. Deploy to a VM. Understand Linux, networking, logs, environment variables, services, storage, and security. Then learn Kubernetes as the next layer. This approach makes you a better engineer because you understand what Kubernetes is abstracting. If you skip the lower layers, Kubernetes becomes a collection of YAML files you copy without understanding. If you learn the lower layers first, Kubernetes becomes a tool you can reason about. That is the difference between “using Kubernetes” and operating it responsibly. ## Final Thoughts Kubernetes matters because container operations eventually become difficult without orchestration. It helps teams deploy, update, scale, and recover workloads across clusters in a more consistent way. But Kubernetes is not the right starting point for every developer or every team. A VM is still the right starting point for many applications. Docker Compose is still enough for many small stacks. Multi-VM architecture can solve many growth problems before a cluster is necessary. The best engineering decision is not to adopt Kubernetes early. It is to adopt Kubernetes when the workload has earned it. Start with a [Raff Linux VM](/products/linux-vm), learn containers with [Docker on Ubuntu 24.04](/learn/tutorials/install-docker-ubuntu-24-04), understand when to split infrastructure with [Single VM vs Multi-VM Architecture](/learn/guides/single-vm-vs-multi-vm-saas-architecture), and follow the [Raff Kubernetes product path](/products/kubernetes) when your workload needs real orchestration. --- ### Ubuntu for Cloud VMs: Why Developers Still Choose It (2026) URL: https://rafftechnologies.com/blog/why-developers-still-love-ubuntu-a-deep-dive-into-the-linux-powerhouse Published: 2025-07-18T00:00:00.000Z Description: Ubuntu for Cloud VMs: Why Developers Still Choose It (2026) Ubuntu is still one of the safest default choices for cloud VMs in 2026 because it gives developers a stable Linux base, a huge package ecosystem, strong cloud image support, and a familiar path from local development to production servers. For Raff Technologies users, Ubuntu works especially well when you need a clean Linux VM for testing, deployment, Docker, APIs, databases, or remote development. Ubuntu is a Debian-based Linux distribution maintained by Canonical and widely used across desktops, servers, and cloud infrastructure. In practice, developers choose Ubuntu because it is predictable: `apt` works the way they expect, documentation is everywhere, security updates are easy to understand, and most deployment tutorials assume Ubuntu or Debian-style commands. I use Ubuntu often when testing server setups because it gives me a repeatable baseline. A fresh Ubuntu VM on Raff lets me confirm whether a setup works on a real cloud server, not just on a local machine with months of old packages and hidden configuration changes. ## Ubuntu Wins Because It Is Predictable Developers do not choose an operating system only because it is popular. They choose it because it reduces surprises. Ubuntu’s biggest advantage is predictability. The commands are familiar, the package names are usually easy to find, and the system layout is close to what most Linux tutorials, GitHub projects, and deployment guides expect. That matters when you are setting up: * Node.js apps * Python backends * Docker containers * Nginx or Caddy reverse proxies * PostgreSQL or MySQL databases * Redis caches * CI/CD runners * Self-hosted tools * Monitoring agents * VPNs and private services For a developer, the value is not theoretical. If you can copy a setup from a reliable guide, understand the commands, and troubleshoot errors quickly, you ship faster. That is why Ubuntu keeps showing up in production workflows. It is not always the most minimal Linux distribution. It is not always the most customizable. But it is often the most practical starting point. ## Ubuntu 24.04 LTS Is the Practical Default For most new cloud VM projects, Ubuntu 24.04 LTS is the strongest default choice. It has a modern package base, long-term support, and broad compatibility with current developer tools. LTS matters because production servers should not feel experimental. You want security updates, stable package behavior, and a release lifecycle that gives your team time to plan upgrades instead of reacting to end-of-life deadlines. On Raff, Ubuntu 24.04 LTS is a natural fit for a [Linux VM](/products/linux-vm) because it gives you a clean server environment with full root access, SSH, NVMe SSD storage, and enough flexibility to run modern workloads. Use Ubuntu 24.04 LTS when you are starting a new project, writing a deployment guide, building a production web server, or creating a repeatable team environment. Ubuntu 22.04 LTS still makes sense for older production stacks that are already tested there. If a project’s dependencies, deployment scripts, or client environment still expect 22.04, stability may matter more than using the newest LTS immediately. ## Developers Like Ubuntu Because the Package Ecosystem Is Huge The `apt` package manager is one of Ubuntu’s biggest strengths. Installing common server tools is usually straightforward, and most major open-source projects document Ubuntu installation steps clearly. That lowers setup friction. A developer can move quickly from a blank VM to a working environment: * Install Nginx or Caddy * Add Node.js, Python, PHP, Go, or Java * Install Docker * Set up PostgreSQL, MySQL, MariaDB, Redis, or MongoDB * Configure UFW firewall rules * Add Certbot for HTTPS * Install monitoring and logging agents * Run application services with systemd This is the practical reason Ubuntu stays popular. The ecosystem around it is massive. When I test tutorials, I care about whether a reader can follow the path without hunting through obscure package names or distribution-specific edge cases. Ubuntu usually gives the smoothest path for that. For example, Raff already has hands-on Ubuntu tutorials such as [Install Docker on Ubuntu 24.04](/learn/tutorials/install-docker-ubuntu-24-04), [Deploy a Node.js App with PM2 on Ubuntu 24.04](/learn/tutorials/deploy-nodejs-pm2-ubuntu-24-04), and [Install PostgreSQL on Ubuntu 24.04](/learn/tutorials/install-postgresql-ubuntu-24-04). ## Ubuntu Is Built for Cloud Workflows Ubuntu works well on cloud VMs because it has strong support for cloud images, SSH access, automation, and headless server operation. A cloud VM is different from a laptop. It needs to boot quickly, accept secure remote access, apply network configuration correctly, and run without a desktop environment. Ubuntu Server is designed for that style of operation. Cloud-init is a major part of this story. It helps automate first-boot configuration, including users, SSH keys, packages, hostnames, and initialization scripts. That makes Ubuntu useful not only for one-off VMs, but also for repeatable infrastructure. This is important for developers and small teams. You do not want every VM to become a hand-built snowflake. You want a baseline you can rebuild, document, and trust. If you are planning repeatable server setup, Raff’s guide to [VM provisioning models with cloud-init, custom images, and one-click apps](/learn/guides/vm-provisioning-models-cloud-init-custom-images-one-click) is a good companion topic. ## Ubuntu Makes Security Easier to Start Ubuntu is not automatically secure just because it is Ubuntu. But it gives you a good starting point. A secure Ubuntu server still needs the basics: * SSH key authentication * Disabled password login where appropriate * UFW firewall rules * Regular security updates * Least-privilege users * Fail2Ban or equivalent protection * Backups and restore testing * Monitoring and logs * Careful secret management The advantage is that these tasks are well documented and widely understood. If you are new to server security, Ubuntu gives you a clear learning path. Raff has a dedicated tutorial for this exact first step: [Secure Your Ubuntu 24.04 Server](/learn/tutorials/secure-ubuntu-24-04-server). If you are exposing a VM to the internet, that should be one of the first articles you read after deployment. For firewall-specific setup, use [Set Up UFW Firewall on Ubuntu 24.04](/learn/tutorials/set-up-ufw-firewall-ubuntu-24-04). UFW is one of the reasons Ubuntu remains approachable for developers who are not full-time Linux administrators. ## Ubuntu Works Well for Docker and Self-Hosting A lot of modern developer infrastructure starts with Docker. Ubuntu is a comfortable base for Docker because the installation path is well documented, the kernel support is strong, and most self-hosting tutorials assume an Ubuntu server. This matters if you are deploying: * n8n * Uptime Kuma * Nextcloud * Gitea * Portainer * Supabase * Coolify * Custom APIs * Internal dashboards * Background workers * Monitoring stacks Ubuntu gives you enough stability for production but enough freshness for modern tooling. That balance is why so many self-hosted projects use Ubuntu 22.04 or 24.04 in their examples. For developers using Raff, this creates a simple path: deploy a VM, install Docker, add the application stack, configure a reverse proxy, secure the server, and then scale or split services when the workload grows. If you are building a self-hosted environment, start with [Install Docker on Ubuntu 24.04](/learn/tutorials/install-docker-ubuntu-24-04), then move into service-specific tutorials like [Self-Host n8n with Docker Compose](/learn/tutorials/self-host-n8n-docker) or [Install Coolify on Ubuntu 24.04](/learn/tutorials/install-coolify-ubuntu-24-04). ## Ubuntu Is Beginner-Friendly Without Being Toy Infrastructure Ubuntu has a rare position in the Linux world: it is friendly enough for beginners, but serious enough for production servers. That is why it works across different skill levels. A student can use Ubuntu to learn Linux commands. A freelancer can use Ubuntu to host a client app. A startup can use Ubuntu for staging and production. A DevOps engineer can use Ubuntu as a standard server base. A technical writer can use Ubuntu to test repeatable setup steps. This range is valuable. A team can teach new developers on the same operating system they use for real deployments. That reduces context switching. Ubuntu also makes mistakes easier to recover from because the community is huge. Error messages, package conflicts, firewall issues, Nginx problems, Docker setup errors, and SSH configuration mistakes are usually searchable. That does not replace good engineering, but it does reduce friction. ## Ubuntu Is Not Always the Right Choice Ubuntu is practical, but it is not the right answer for every workload. Choose Debian when you want a more conservative base and maximum simplicity. Choose Rocky Linux or AlmaLinux when you need a RHEL-compatible environment. Choose Fedora when you want newer packages and do not need long production support windows. Choose Alpine when you are optimizing for very small containers or minimal environments. The point is not that Ubuntu wins every comparison. The point is that Ubuntu is often the best default when you need a cloud VM that is easy to deploy, easy to document, and easy to hand off to another developer. If you are choosing between Linux distributions for a Raff VM, start with the workload: * For general web apps, choose Ubuntu 24.04 LTS. * For Docker and self-hosting, choose Ubuntu 24.04 LTS. * For older production compatibility, consider Ubuntu 22.04 LTS. * For RHEL-style enterprise environments, choose Rocky Linux or AlmaLinux. * For minimal container-focused setups, consider Alpine. When you are unsure, Ubuntu is usually the safest first VM. ## Choosing the Right Raff VM for Ubuntu The operating system is only one part of the decision. You also need the right VM size. A small development server does not need the same resources as a production API, database, or CI runner. CPU, RAM, and storage should match the workload rather than the operating system alone. For light testing, learning, small tools, and simple web apps, a smaller General Purpose VM may be enough. For databases, CI/CD runners, build workloads, and production services that need consistent compute, CPU-Optimized VMs are usually a better fit. Raff’s [Choosing the Right VM Size](/learn/guides/choosing-right-vm-size) guide explains how to think about CPU, RAM, and storage before deploying. If you are deciding between shared and dedicated compute, read [Shared vs Dedicated vCPU](/learn/guides/shared-vs-dedicated-vcpu) before choosing a plan. You can also compare current plans on the [Raff pricing page](/pricing). ## What This Means for Developers Ubuntu remains popular because it helps developers get from idea to working server quickly. It gives you a predictable Linux base, a large package ecosystem, strong cloud support, simple security defaults, and a huge body of tutorials. On Raff, that makes Ubuntu a practical first choice for cloud VMs, especially when you are testing, deploying, self-hosting, or building repeatable infrastructure. The best way to use Ubuntu is not to treat it as magic. Treat it as a clean baseline. Start with Ubuntu 24.04 LTS. Secure SSH. Configure the firewall. Install only what your workload needs. Document the setup. Add backups. Monitor the server. Resize or split infrastructure when the workload grows. That workflow is simple, but it is also production-minded. ## Final Thoughts Developers still choose Ubuntu because it solves the boring problems well. It boots cleanly, installs packages predictably, supports cloud automation, works with modern developer tooling, and has answers available when something breaks. That boring reliability is exactly what you want from a cloud VM operating system. At Raff Technologies, Ubuntu remains one of the most practical starting points for developers who want a real Linux server without unnecessary complexity. Deploy it, test your workload, secure the basics, and grow from there. For your next step, start with a [Raff Linux VM](/products/linux-vm), secure it with [Ubuntu initial server setup](/learn/tutorials/secure-ubuntu-24-04-server), then install a real workload such as [Docker on Ubuntu 24.04](/learn/tutorials/install-docker-ubuntu-24-04) or [Node.js with PM2 on Ubuntu 24.04](/learn/tutorials/deploy-nodejs-pm2-ubuntu-24-04). --- ### What Is MCP? How AI Agents Connect to Cloud Infrastructure URL: https://rafftechnologies.com/blog/model-context-protocol-mcp-the-revolutionary-standard-transforming-ai-integration-in-2025 Published: 2025-05-23T00:00:00.000Z Description: What Is MCP? How AI Agents Connect to Cloud Infrastructure Model Context Protocol, or MCP, is becoming the connection layer between AI agents and real systems: APIs, databases, files, developer tools, and cloud infrastructure. For Raff Technologies users, the important question is not only “what is MCP?” but “where should MCP servers and AI automation tools run safely?” MCP is an open standard that lets AI applications connect to external systems through a consistent interface. Instead of building a custom integration for every AI assistant, tool, database, or API, developers can expose capabilities through MCP servers and let compatible AI clients use them in a more structured way. The practical infrastructure angle is simple: if an AI agent can read data, call tools, or trigger actions, the server that exposes those capabilities must be hosted, secured, monitored, and isolated properly. That is where cloud VMs, private networking, firewall rules, and careful access control become part of the MCP conversation. ## MCP Solves the AI Integration Problem Before MCP, connecting AI tools to real systems often meant building one-off integrations. One assistant needed one custom connector for one database. Another needed a different connector for the same system. Over time, this creates duplicated work, inconsistent security, and fragile automation. MCP changes the pattern. A developer can build an MCP server that exposes a system once, then compatible MCP clients can connect to that server through the same protocol. Think of it this way: * The AI application is the client. * The MCP server exposes tools, data, or prompts. * The external system is the database, API, file store, cloud service, or workflow engine. * The protocol defines how the client and server communicate. This matters because AI agents are becoming more useful when they can interact with real systems. A chatbot that only answers from memory is limited. An AI assistant that can query a database, inspect logs, open a ticket, generate a report, or call an internal API becomes much more practical. ## MCP Is Not Magic Automation MCP does not make infrastructure safe by itself. It only standardizes how AI applications connect to tools and data. That distinction matters. If you expose a powerful internal API through an MCP server, the protocol does not remove your responsibility to secure it. If the server can restart services, query customer data, edit files, or call billing APIs, then authentication, authorization, logging, and least-privilege access become critical. The best way to think about MCP is this: > MCP gives AI agents a structured door into your systems. Your job is to decide where that door is hosted, what it can access, and who is allowed to open it. That is why MCP belongs in the same conversation as cloud security, private networking, and infrastructure operations — not only AI product development. ## How MCP Works in Simple Terms An MCP setup usually has three parts. First, there is an MCP client. This is the AI application or development tool that wants to use external context or actions. Examples can include AI assistants, coding tools, or agent frameworks. Second, there is an MCP server. This is the service that exposes specific capabilities. It may provide access to a database, file system, API, search tool, internal workflow, cloud resource, or documentation source. Third, there is the external system itself. That could be PostgreSQL, GitHub, Slack, a CRM, an internal admin API, a cloud dashboard, or a custom backend service. The MCP server acts as the controlled bridge. Instead of giving an AI assistant unrestricted access to everything, you expose specific tools and resources intentionally. A simple MCP workflow might look like this: * An AI coding assistant asks for context from a repository. * The MCP client sends a request to the relevant MCP server. * The server checks what it is allowed to expose. * The server returns the requested file, metadata, query result, or tool response. * The AI assistant uses that context to help the user. That structure is why MCP is useful. It creates a repeatable model for connecting AI to real systems. ## Why Developers Should Care Developers should care about MCP because it reduces integration work and makes AI tooling more practical. Without a standard protocol, every connection between AI and a tool can become a custom project. With MCP, the goal is to make the connection model more reusable. A team can build or use MCP servers for common systems, then plug them into clients that support the protocol. This is useful for: * Codebase-aware AI assistants * Internal documentation search * Database query assistants * Cloud operations tools * DevOps workflows * Support automation * Data analysis workflows * AI-powered admin dashboards * Custom internal agents For developers, MCP is most interesting when the workflow touches real infrastructure. An assistant that can read deployment logs, query a database, inspect service status, or interact with internal APIs is more useful than one that only generates text. But that usefulness also raises the risk level. The closer an AI system gets to production infrastructure, the more carefully the MCP server must be designed. ## Why Cloud Infrastructure Matters for MCP MCP servers need somewhere to run. For local experiments, a laptop may be enough. For team workflows, internal tools, production-adjacent automation, or long-running agents, local hosting is usually not enough. A cloud VM gives an MCP server a stable environment with predictable networking, operating system control, and separation from a personal machine. That makes it easier to configure access rules, monitor the process, update dependencies, and keep the service available for the team. A [Raff Linux VM](/products/linux-vm) is a practical starting point for MCP server experiments because you can create a clean server environment, install only what the project needs, and isolate the workload from your main application infrastructure. This is especially useful when your MCP server needs to communicate with other cloud services, private APIs, databases, automation tools, or internal dashboards. ## Practical MCP Use Cases for Cloud Teams MCP becomes more interesting when it connects AI agents to infrastructure and developer workflows. Here are practical examples. | Use Case | What the MCP Server Exposes | Why It Helps | |---|---|---| | Log analysis | Application logs or observability API | AI can summarize incidents and identify patterns | | Database assistant | Read-only database queries | Teams can ask operational questions without writing SQL each time | | Deployment helper | CI/CD or release metadata | AI can explain failed deployments or suggest next steps | | Documentation search | Internal docs and runbooks | New team members can find answers faster | | Cloud resource helper | VM, storage, or network metadata | Operators can inspect infrastructure through natural language | | Support workflow | Ticket and customer metadata | Support teams can triage issues faster | | Automation bridge | n8n or internal workflow APIs | AI can trigger controlled workflows | The important word is “controlled.” MCP should expose limited capabilities with clear boundaries. For example, a read-only database MCP server is safer than one that can modify production records. A server that summarizes logs is safer than one that can restart services. ## The Security Problem MCP Introduces MCP security matters because MCP servers can sit between AI agents and sensitive systems. A poorly designed MCP server can expose too much data, execute unsafe commands, leak credentials, or give an AI agent access it should not have. This risk becomes higher when the server connects to infrastructure tools, databases, file systems, or admin APIs. Before deploying an MCP server, ask these questions: * What data can this server access? * Can it only read, or can it also write? * Which users or clients can connect? * Are credentials stored safely? * Are requests logged? * Can actions be audited later? * Is the server reachable from the public internet? * Does the server need private networking? * What happens if the AI client makes a bad request? * Can the server be rolled back or disabled quickly? A safe MCP design starts with least privilege. Expose the minimum set of tools needed for the workflow, then expand only when there is a clear reason. ## Hosting MCP Servers on Raff A Raff VM can host MCP servers for development, testing, internal tools, or production-adjacent automation. The right architecture depends on what the server can access. For a low-risk experiment, you might run one MCP server on a small VM with limited test data. For an internal team tool, you may want a dedicated VM, firewall restrictions, private networking, and stronger monitoring. For a sensitive production workflow, you should isolate the MCP server from public access and expose only narrow, auditable capabilities. A practical Raff setup might include: * A dedicated [Raff VM](/products/raff-vm) for the MCP server * Firewall rules that limit inbound access * SSH key-based administration * Private networking for internal service communication * Separate credentials for each connected system * Read-only permissions where possible * Backups for configuration and workflow data * Logs for audit and troubleshooting If the MCP server connects to private services, a public server with broad access is the wrong model. Use tighter network boundaries and expose only what the workflow actually needs. ## MCP and Private Networking Private networking becomes important when MCP connects AI tools to systems that should not be publicly reachable. For example, an MCP server may need to query an internal API, inspect a database, or talk to a worker service. Those systems should not be opened to the internet just because an AI assistant needs context. A better model is to place the MCP server near the systems it needs to access, then restrict external access to the MCP layer itself. That lets you build a controlled bridge rather than exposing every backend service directly. Raff’s [Private Cloud Networks](/products/private-cloud-networks) product path is relevant here because MCP is fundamentally about controlled connectivity. The safer pattern is not “AI can reach everything.” The safer pattern is “AI can reach one carefully designed service that has limited access to the right systems.” ## MCP and Automation Workflows MCP also fits naturally with automation tools. An AI agent may not need direct access to every system. Sometimes it should trigger a controlled workflow instead. For example, instead of giving an AI agent direct permission to modify infrastructure, you could expose a tool that triggers a predefined workflow: * Create a staging environment * Run a backup check * Generate a deployment report * Open a support ticket * Summarize failed jobs * Run a safe diagnostic script This is a healthier automation model. The AI agent requests a known operation, and the workflow system performs the steps with guardrails. If your team already uses workflow automation, Raff’s article on [n8n self-hosted automation](/learn/guides/n8n-self-hosted-workflow-automation-guide) is a useful companion topic. n8n handles workflow orchestration; MCP can help AI agents interact with tools and workflows through a standardized interface. ## What I Would Test Before Deploying MCP Seriously Before using MCP for anything important, I would test the server in a clean environment. First, test the permissions. Start with read-only access and prove the workflow works before adding write actions. If the server only needs to read documentation, it should not have access to production databases. Second, test failure behavior. What happens if the external API times out, returns bad data, or rejects authentication? The MCP server should fail safely, not expose internal errors or retry dangerous actions. Third, test logging. You should know which client requested which tool, when it happened, and what result came back. If an AI agent performs an action through MCP, you need an audit trail. Fourth, test network exposure. If the MCP server does not need to be public, do not make it public. If it must be reachable, restrict who can reach it. Fifth, test rebuildability. A clean VM should be easy to recreate with documented setup steps. If the server becomes important, the deployment process should not depend on one person’s memory. This is why I prefer testing infrastructure tools on fresh VMs. A clean VM shows whether the setup is actually repeatable. ## When MCP Is a Good Fit MCP is a good fit when your team wants AI tools to interact with real systems in a structured way. Use MCP when: * You need AI agents to access internal tools * You want reusable integrations instead of one-off connectors * You need controlled access to APIs, files, databases, or workflows * You want AI assistants to understand your operational context * You are building developer tools or internal automation * You want to standardize how agents connect to systems Avoid MCP when the workflow is simple enough to solve with a normal API call, scheduled script, or basic automation rule. MCP is powerful, but it still adds another layer to operate. ## What This Means for Raff Users For Raff users, MCP should be viewed as part of the infrastructure stack when it touches cloud systems. A developer can run an MCP server on a VM. A team can place that server near internal tools. An operator can restrict access with firewall rules and private networking. A founder can use MCP to explore AI automation without giving uncontrolled access to production systems. The safest starting point is small: * Pick one useful workflow. * Use a dedicated VM. * Start with read-only access. * Limit network exposure. * Log every request. * Test failure paths. * Add write actions only when necessary. You can start with a [Linux VM](/products/linux-vm), review [Raff pricing](/pricing), and connect the MCP idea to broader cloud automation using [Raff API keys for small-team automation](/learn/guides/raff-api-keys-automation-small-teams). ## Final Thoughts MCP is useful because it gives AI agents a standard way to connect with the tools developers already use. But the real value appears when the protocol is paired with secure infrastructure. The question is not only whether an AI assistant can connect to a tool. The question is whether that connection is limited, observable, recoverable, and hosted in the right place. That is why the cloud layer matters. If MCP servers become part of your automation stack, they deserve the same care as any other infrastructure component: isolation, access control, backups, monitoring, and clear ownership. Start with one MCP server. Keep permissions narrow. Run it in a clean environment. Then expand only when the workflow proves its value. --- ### What is n8n? The Open-Source Automation Tool Built for Developers URL: https://rafftechnologies.com/blog/what-is-n8n-the-open-source-automation-tool-built-for-developers Published: 2025-07-23T00:00:00.000Z Description: What is n8n? The Open-Source Automation Tool Built for Developers What is n8n? n8n is a fair-code workflow automation platform that lets developers connect apps, APIs, databases, and internal tools through visual workflows while still keeping room for custom code. Raff Technologies users usually care about n8n for one reason: it gives you automation power without forcing every workflow into a closed SaaS platform. If you have ever wanted to say “when this happens, run these steps automatically,” n8n is built for that. A workflow can start from a webhook, schedule, app event, form submission, database change, or manual trigger. Then each step passes data to the next node, where you can transform, filter, enrich, route, or send that data somewhere else. I like n8n because it sits in a useful middle ground. It is visual enough for fast workflow building, but technical enough for developers who need custom JavaScript, API calls, credentials, branching logic, and self-hosted control. That combination is why it has become a serious option for founders, DevOps teams, internal tooling builders, and automation-heavy startups. ## n8n Is Not Just Another No-Code Tool n8n looks simple at first because the interface is visual. You drag nodes, connect them, configure credentials, and watch data move between steps. But calling n8n “just no-code” misses the point. Most no-code automation platforms are designed to keep users inside a controlled interface. That is fine for simple workflows, but it becomes frustrating when you need custom logic, internal APIs, private infrastructure, or more control over where your automation data runs. n8n is different because it gives technical users more room. You can use built-in integrations for common tools, but you can also write custom code, call private APIs, transform JSON, build conditional branches, and self-host the whole system on your own infrastructure. That makes n8n especially useful when your automation is not just “send a Slack message when a form is submitted.” It is useful when your workflow needs to behave like a small internal application. ## How n8n Workflows Work An n8n workflow is built from connected nodes. Each node does one job: receive data, transform data, call an API, check a condition, send a message, write to a database, or trigger another action. A simple workflow might look like this: * A webhook receives a new lead from a website form. * n8n checks whether the email domain is valid. * It enriches the lead with company data. * It creates a CRM record. * It sends a Slack notification. * It stores a copy in a database. * It triggers a follow-up email sequence. A more technical workflow might call an internal API, run JavaScript to reshape a payload, check error conditions, and send failed records into a retry path. This is where n8n becomes interesting for developers. The visual editor helps you understand the flow, but the workflow can still include real logic. You are not limited to prebuilt templates or shallow integrations. ## Why Developers Like n8n Developers tend to like n8n for four reasons: control, extensibility, self-hosting, and visibility. Control matters because automation often touches sensitive systems. A workflow may handle customer data, API tokens, internal dashboards, billing events, support tickets, or operational alerts. When that workflow runs on infrastructure you control, you can decide how it is secured, monitored, backed up, and exposed. Extensibility matters because real workflows rarely stay simple. A startup may begin with a form-to-Slack workflow, then add enrichment, filtering, routing, database writes, and error handling. n8n allows that growth without forcing the team to rebuild everything from scratch. Self-hosting matters because some teams do not want every automation running through a third-party SaaS environment. If you want that control, Raff’s [n8n VM](/products/n8n-vm) gives you a dedicated path for running n8n as cloud infrastructure rather than another external subscription. Visibility matters because visual workflows are easier to inspect than hidden scripts. When something breaks, you can open the workflow, inspect the failed step, view the data, and fix the logic. ## n8n vs Zapier, Make, and Similar Tools Zapier and Make are excellent for quick SaaS-to-SaaS workflows. They are often faster for non-technical users who want simple automations between common apps. n8n is usually better when the workflow is more technical, private, or infrastructure-aware. | Need | Better Fit | |---|---| | Quick personal productivity automation | Zapier or Make | | Simple SaaS-to-SaaS workflows | Zapier or Make | | Internal APIs and private tools | n8n | | Custom code inside workflows | n8n | | Self-hosted automation | n8n | | Data-sensitive workflows | n8n on controlled infrastructure | | Developer-owned automation systems | n8n | The decision is not about which tool is universally better. It is about who owns the workflow, where the data runs, and how much control the team needs. If you want a deeper decision framework, Raff’s [n8n self-hosted automation guide](/learn/guides/n8n-self-hosted-workflow-automation-guide) explains when self-hosting makes sense and when a managed automation platform may be enough. ## What You Can Build with n8n n8n is flexible because it works across many types of workflows. It can support internal operations, product automation, customer support, marketing systems, infrastructure tasks, and AI workflows. Common examples include: * Lead routing from forms to CRM systems * Slack or Discord alerts from webhooks * GitHub issue automation * Customer onboarding workflows * Invoice and payment notifications * Database cleanup jobs * API monitoring and alerting * Scheduled reports * Support ticket enrichment * AI content or data pipelines * Backup reminders * Internal approval flows The most useful n8n workflows often start from repetitive team pain. If someone on your team says, “I do this same thing every day,” that is a good candidate for automation. For more ideas, read Raff’s related post: [What Can You Build with n8n? 10 Real Use Cases You Can Deploy Today](/blog/w4rbnhj7kfhe4ww99w75jnal). ## Why Self-Hosting n8n Matters Self-hosting n8n gives you more responsibility, but also more control. When you self-host, you control: * Where the workflow server runs * Which network can access it * How credentials are stored * How backups are handled * Which database n8n uses * How updates are applied * How logs and monitoring work * Which integrations can reach internal systems That control is useful for developers and teams that treat automation as part of their infrastructure, not just a convenience tool. But self-hosting also means you need to operate it correctly. n8n should not be thrown onto a public server with weak authentication, no backups, and no update plan. Automation tools often hold powerful credentials, so security matters. A good self-hosted n8n setup should include HTTPS, secure credentials, firewall rules, strong authentication, regular updates, reliable backups, and a database setup that matches the workload. ## Running n8n on Raff Raff is a natural place to run n8n when you want a cloud VM dedicated to automation. You get a server environment that is separate from your laptop, separate from your production app, and available whenever your workflows need to run. There are two practical paths. The fastest path is to use Raff’s [n8n VM](/products/n8n-vm), which is designed for teams that want a pre-configured automation environment without manually assembling every part. The more hands-on path is to deploy n8n yourself on a [Raff Linux VM](/products/linux-vm). This is useful if you want to learn the full setup, customize the stack, or control the deployment from the first package install. If you want the hands-on version, follow the tutorial: [How to Self-Host n8n on Ubuntu 24.04 with Docker Compose](/learn/tutorials/self-host-n8n-docker). ## What I Would Test Before Using n8n Seriously Before using n8n for important workflows, I would test five things. First, test how credentials are stored and who can access them. Automation systems often connect to email, databases, APIs, CRMs, and internal dashboards. That makes credential security a first-order concern. Second, test failure paths. A workflow that works once is not enough. What happens if an API times out? What happens if a webhook sends malformed data? What happens if the database is temporarily unavailable? Third, test backups. If your n8n workflows matter to your business, you should be able to restore them. Export workflows, back up the database, and confirm recovery before you rely on it. Fourth, test performance under realistic workflow volume. A workflow that runs once per day behaves very differently from a workflow triggered every minute. Fifth, test updates. n8n changes over time, and self-hosted tools need maintenance. Make sure you know how to update safely and roll back if needed. This is where running n8n on a clean VM helps. You can test the setup, document the steps, and rebuild the environment if something goes wrong. ## When n8n Is the Right Tool n8n is a strong fit when your team wants automation that is flexible, developer-friendly, and controllable. Use n8n when: * You need to connect APIs and internal tools * You want visual workflows with custom code options * You care where automation data runs * You want to self-host your workflow engine * You need more complex logic than simple SaaS automations allow * You want developers and operations teams to share workflow visibility * You want automation to become part of your infrastructure Avoid n8n when your needs are very simple and a SaaS automation tool already solves the problem with less maintenance. Self-hosting is powerful, but it should have a reason. ## What This Means for You If you are a developer, founder, or technical operator, n8n can become a serious part of your internal infrastructure. It can connect the tools you already use, automate repetitive work, and give your team more control than closed automation platforms usually allow. The important decision is deployment model. If you only need a few lightweight SaaS automations, a managed automation tool may be enough. If you need custom code, private APIs, internal systems, and stronger control over where workflows run, self-hosting n8n is worth considering. On Raff, you can start with a dedicated [n8n VM](/products/n8n-vm), deploy manually with the [Docker Compose n8n tutorial](/learn/tutorials/self-host-n8n-docker), or read [Why We Made n8n Easy to Launch on Raff](/blog/y8veqrl21voygzmttv4wilk9) for the product-side reasoning. ## Final Thoughts n8n is popular because it gives developers something many automation tools do not: visual workflow building without giving up technical control. It is approachable enough to build workflows quickly, but flexible enough to connect APIs, add code, run private automations, and operate on your own infrastructure. That makes it especially useful for technical teams that want automation to be part of their stack, not a black box outside it. If your team is repeating manual work, connecting tools by hand, or writing small scripts that nobody wants to maintain, n8n is worth testing. Start small. Build one useful workflow. Test failure handling. Secure it properly. Then decide whether n8n should become a permanent part of your automation stack. --- ### Why a 60-Second Server Launch Matters More Than It Sounds URL: https://rafftechnologies.com/blog/why-60-second-server-launch-matters-more-than-it-sounds Published: 2026-04-24T00:00:00.000Z Description: Why a 60-Second Server Launch Matters More Than It Sounds # Why a 60-Second Server Launch Matters More Than It Sounds At Raff Technologies, we take cloud infrastructure seriously. But there's one detail we often emphasize that goes unnoticed by many — the importance of speed in provisioning a server. You may wonder, "Why does it matter if a server takes 60 seconds or a couple of minutes to launch?" In fact, that **60-second launch time** matters a lot more than it sounds. It’s not just a feature. It's a reflection of **how we view the cloud experience** — fast, reliable, and frictionless. Let's explore why a quick server launch has a larger impact on your workflow than you might think. ## Onboarding Without the Wait Getting started with cloud infrastructure is often a hassle. From selecting the right plans to waiting for a server to provision, the early friction can be discouraging. As a founder, I know how important it is to keep things **moving fast**. If you have a small team or are running a solo startup, the **waiting game** can eat into your productivity. You need **instant access to your resources** to quickly test, debug, or iterate on your ideas. Raff Technologies eliminates these barriers. With our **60-second server launch**, you don’t waste time staring at loading screens. Instead, you can **get to work immediately**. Our customers love that **speed**. Whether they’re deploying a simple web app, testing a new feature, or tweaking a staging environment, the **instant provisioning** means that no matter what, **their virtual machine (VM)** is up and running in a minute. ## Rapid Iteration with No Roadblocks In the world of cloud development, **speed equals iteration**. The faster you can deploy a test server or a new environment, the faster you can measure, adjust, and optimize. By eliminating long wait times, Raff allows your team to deploy, test, and **iterate** without the **delays**. For startups, small teams, or individual developers, this is incredibly powerful. You no longer need to wait for **long server provisioning times** to try out new ideas or features. The beauty of having a server up and running in 60 seconds is that it enables faster **feedback loops**. The quicker you can deploy and get feedback, the faster you can iterate. At Raff, that **instant deployment** allows you to push changes, test new features, and experiment without the infrastructure getting in your way. ## Minimizing Friction at Every Step One of the biggest barriers for developers working with cloud infrastructure is **friction**. Whether it’s waiting for a server to spin up or navigating through complex dashboards and configurations, every second of friction slows down progress. At Raff, we’ve built our platform to minimize that friction. By providing **instant provisioning** and an easy-to-use interface, we ensure that **you spend less time managing infrastructure** and more time building products. If you’re constantly waiting for resources to be provisioned, it’s easy to feel like you’re losing control over your own projects. But with Raff, we give you the tools to **scale and deploy without hesitation**, keeping you in the driver’s seat of your project’s momentum. ## The Business Impact of Speed Behind every server launch, there’s an **opportunity cost**. A slow launch time might not seem like much on the surface, but when you multiply that delay by every instance your team launches, it adds up. Every minute wasted provisioning servers is **a minute you can’t be testing, building, or iterating**. By reducing the time it takes to get a server up and running, you gain more control over your team’s workflow, helping you execute faster and more efficiently. This translates directly into **higher productivity, faster innovation**, and **reduced overhead costs**. At Raff, we believe that every second counts. That’s why we’ve made our platform not just fast — but **predictably fast**. Our **60-second server launches** ensure that your team spends more time creating and less time waiting for infrastructure. ## Conclusion: It’s All About Efficiency A **60-second server launch** might seem like a small feature, but it’s actually a reflection of our overall approach: **Raff Technologies is built for efficiency**. Whether you're a solo developer, a small team, or a larger organization, having infrastructure that’s **simple, fast, and scalable** isn’t just a luxury — it’s essential for any team looking to move quickly, scale efficiently, and deliver their product without delays. This is why at Raff Technologies, **speed is at the heart of everything we do**. From the initial launch to scaling as you grow, we ensure that the **cloud infrastructure supports your business needs** — not the other way around. So the next time you need to launch a server, you’ll know that with Raff, it will be **up and running in 60 seconds**, giving you more time to focus on what really matters — building something amazing. --- ### What We Learned Testing Cloud-Init Templates Across Ubuntu, Debian, and Rocky Linux URL: https://rafftechnologies.com/blog/what-we-learned-testing-cloud-init-templates Published: 2026-04-22T00:00:00.000Z Description: What We Learned Testing Cloud-Init Templates Across Ubuntu, Debian, and Rocky Linux Cloud-init templates are only as good as their first boot behavior, and the differences between Ubuntu, Debian, and Rocky Linux are real enough to affect reliability. At Raff Technologies, this matters because a template that looks clean in the image pipeline can still behave differently once it has to process metadata, inject SSH keys, bring networking up, and hand control back to the user on a fresh VM. That is what makes cloud-init testing more interesting than it first sounds. You are not only testing whether an operating system supports cloud-init. You are testing whether the distribution’s defaults, packaging choices, boot order, and image state produce a first boot that feels predictable instead of fragile. Raff already has a live guide on [VM provisioning models: cloud-init, custom images, and one-click apps](/learn/guides/vm-provisioning-models-cloud-init-custom-images-one-click), but this post is narrower on purpose. I want to focus on what changed when the same cloud-init intent met three different Linux families. > **Editor note:** Before publishing, add one real Aybars-tested observation here. This topic needs a genuine tested-and-verified signal, such as one specific first-boot difference you reproduced on Raff VMs across Ubuntu, Debian, and Rocky Linux. Your content guide is explicit that this should not be fabricated. ## The Important Lesson: “Supports cloud-init” Is Not Specific Enough The first useful lesson is that “supports cloud-init” is too broad to be operationally helpful. On paper, Ubuntu, Debian, and Rocky Linux can all participate in the same provisioning model. In practice, the thing that matters to operators is not whether cloud-init exists. It is whether the image behaves cleanly under the exact first-boot sequence your platform expects: user-data processing, key injection, hostname handling, package readiness, metadata access, and network availability. That difference matters because cloud-init is not a feature you admire in isolation. It is part of a chain. If one link in that chain is slightly off — networking comes up later than expected, package state is older than expected, image identity is not fully cleaned, or the default user behavior is inconsistent — the template can still “work” while creating more uncertainty than it should. I think that is the right frame for cloud-init testing. The goal is not to prove compatibility. The goal is to remove ambiguity from first boot. ## Ubuntu Usually Feels Like the Reference Case Ubuntu often feels like the baseline many people subconsciously expect cloud-init to match. That is not because other distributions are worse. It is because Ubuntu cloud images are so common in cloud documentation, examples, and user assumptions that many operators begin to treat Ubuntu behavior as the default shape of cloud-init itself. When something works smoothly there, it feels normal. When another distribution behaves differently, it feels like an exception even if that behavior is technically valid. That matters in template testing because Ubuntu can hide a bad habit: assuming that a template design proven once on Ubuntu will carry over to Debian or Rocky Linux without friction. In reality, Ubuntu often becomes the easiest place to build false confidence. ## Debian Often Looks Similar Until the Edges Matter Debian is close enough to Ubuntu that teams often expect a nearly identical first-boot experience. Sometimes that is true. Sometimes it is true only until your assumptions get more specific. This is where image hygiene, default package state, and the surrounding boot flow start to matter more. If your template depends on a certain package being present, a particular user expectation, or a certain timing assumption around initialization, Debian can expose how Ubuntu-specific your “generic” template really was. That is not a criticism of Debian. It is exactly why testing matters. A good cross-distribution cloud-init template should not rely too heavily on implied defaults. The more your provisioning logic depends on what “usually happens,” the more likely you are to discover that one distribution interprets “usually” a little differently than another. ## Rocky Linux Changes the Conversation More Than People Expect Rocky Linux often changes the testing mindset because it pushes the template conversation farther away from Debian-family assumptions. That is useful. It forces you to stop thinking only about user-data syntax and start thinking about the entire image context: package ecosystem, boot behavior, network interface expectations, service readiness, and whether the VM still feels predictable once the first cloud-init run has finished. In other words, Rocky Linux tends to expose whether your cloud-init template is actually cross-platform or simply cross-your-favorite-two-distros. That is one reason I like including Rocky Linux in template validation even when the expected customer usage is weighted toward Ubuntu. It is a good way to find assumptions that were never as portable as they looked inside the pipeline. ## Where First Boot Usually Breaks The most useful cloud-init failures are rarely dramatic. They are usually small breakpoints that make the VM feel less trustworthy than the template author intended. ### Metadata timing and network readiness If networking does not come up in the order your template expects, cloud-init can still run in a way that feels incomplete or inconsistent. This is especially important when the provisioning flow expects metadata-driven values to be available early and reliably. ### SSH key and user assumptions A cloud-init template that assumes too much about the default user model can become fragile across distributions. This is one of the fastest ways for a template to feel “fine in testing” and then generate first-login confusion later. ### Package and service timing If your first-boot logic expects package operations or service starts to behave identically across distributions, you may be treating the distro family as an implementation detail when it is actually part of the provisioning contract. ### Image state that was not cleaned properly This is one of the quietest causes of unreliable first boot. A template can pass a quick launch test while still carrying identity or initialization state that should not survive image publication. Rocky Linux’s image-builder perspective makes this especially clear: image defaults and generalization are part of reliability, not a cleanup step you can treat as secondary. The common thread across all of these is simple: first-boot reliability depends on more than cloud-init syntax. ## Image Defaults Matter More Than Template Authors Want to Admit I think this is the most important lesson in the whole topic. People like to talk about cloud-init as though the template itself is the main variable. In real environments, the underlying image defaults often matter just as much. If the base image is inconsistent, carries stale package assumptions, or boots with different service expectations than your template logic assumes, then the user-data layer ends up taking the blame for problems it did not create on its own. That is why cloud-init testing belongs next to image quality, not separate from it. A template is not floating above the operating system. It is landing on a very opinionated starting state. If that starting state differs between Ubuntu, Debian, and Rocky Linux — and it does — then the template author has to decide whether to normalize those differences or design around them explicitly. The worst option is pretending they are not there. ## What We Actually Want From a Reliable Cloud-Init Template For me, a reliable cloud-init template should do five things well: * process metadata and user-data without timing surprises * inject the correct user access path cleanly * behave predictably on first boot and not only after a reboot * avoid distro-specific assumptions unless they are declared clearly * fail in a way that is diagnosable when something goes wrong That last point matters more than teams admit. You do not need every cloud-init run to be perfect. You do need failures to be understandable. A template that fails transparently is much easier to improve than one that “sort of worked” and left the user with a machine that feels half-initialized. ## Why This Changes How I Think About Standardization This is where the practical value shows up. A lot of teams think standardization means reducing everything to one template. I think good standardization is more nuanced than that. Sometimes the more reliable strategy is not one universal template across all Linux families. Sometimes it is a shared provisioning intent with distro-aware implementation details. That approach usually produces fewer false assumptions and a cleaner first-boot experience. It also fits how real infrastructure evolves. Raff supports multiple operating systems and VM use cases, from Ubuntu and Debian to Rocky Linux, while also giving users platform features like Linux VMs, snapshots, backups, web console access, and private networking. That means reliability is not just about the distro. It is about how the distro, the image, the provisioning model, and the recovery model behave together once the VM is live. The current public product reference also makes it clear that Linux VMs are part of a broader stack that includes snapshots, backups, private networking, and custom OS support, which is exactly why template predictability matters so much in practice. The more distributions you want to support confidently, the less you can afford to mistake “same YAML” for “same outcome.” ## What This Means for You If you use cloud-init templates across multiple Linux distributions, the right question is not “does cloud-init work here?” The better question is “does first boot behave consistently enough here that I would trust this template in front of a real user?” That is the standard I would use. Test your templates across the distributions you actually intend to support, not just the one that was easiest to prototype. Pay close attention to metadata timing, SSH access, package assumptions, and whether the image was generalized properly before publishing. If you are thinking through provisioning models more broadly, start with our guide to [cloud-init, custom images, and one-click apps](/learn/guides/vm-provisioning-models-cloud-init-custom-images-one-click), then pair that with [Linux VMs](/products/linux-vm) as the practical deployment layer. That is the real lesson from cross-distro cloud-init testing: reliability does not come from cloud-init alone. It comes from how well the template and the image agree about what first boot is supposed to do. --- ### Golden Images vs Cloud-Init vs One-Click Templates for MSP Standardization URL: https://rafftechnologies.com/blog/golden-images-vs-cloud-init-vs-one-click-templates Published: 2026-04-21T00:00:00.000Z Description: Golden Images vs Cloud-Init vs One-Click Templates for MSP Standardization # Golden Images vs Cloud-Init vs One-Click Templates for MSP Standardization When managing client environments, **Managed Service Providers (MSPs)** face constant challenges related to **standardization**, **repeatability**, and **onboarding speed**. One of the most important decisions MSPs must make is how to streamline their server provisioning process. Whether you're creating a base image for your virtual machines (VMs), automating post-deployment tasks, or deploying an entire app stack in one go, it’s crucial to find the right method for your infrastructure. This post compares **Golden Images**, **Cloud-Init**, and **One-Click Templates**, highlighting the benefits and tradeoffs of each approach. Let’s dive into the details and see how they stack up for MSP standardization. ## 1. **Golden Images: The Traditional Approach** A **Golden Image** is a pre-configured VM image that contains the exact state you want to replicate across multiple instances. This image includes the OS, necessary packages, and configuration settings. It’s the most traditional approach to server standardization and has been used for years by MSPs for its reliability and simplicity. ### **Benefits of Golden Images:** - **Consistency:** Every new server deployed from a Golden Image is identical, ensuring repeatability. - **Simplicity:** Once an image is created, it can be quickly deployed across any number of machines with minimal setup. - **Speed:** You don’t have to reconfigure the server each time—it’s already “done.” ### **Drawbacks:** - **Manual Updates:** Whenever a software or configuration change is needed, the Golden Image must be updated and redeployed, leading to manual processes. - **Scalability Issues:** With large-scale operations, maintaining and updating Golden Images can become cumbersome. In essence, Golden Images are a great choice for smaller operations or environments where consistency is key, but for large-scale setups, this approach can start to feel limiting. ## 2. **Cloud-Init: Automating the First Boot** **Cloud-init** is a tool that allows for the automated configuration of servers at the first boot. It’s a standard in cloud environments like AWS, GCP, and Azure. Unlike Golden Images, Cloud-init allows for more dynamic provisioning. You can specify configuration settings such as networking, SSH keys, and software installation at runtime. ### **Benefits of Cloud-Init:** - **Flexibility:** Cloud-init scripts are executed at the first boot of the machine, allowing you to configure the server in real-time, tailored to each deployment. - **Automated Setup:** With Cloud-init, you can automatically configure the environment without having to manually intervene in each server’s setup. - **Scalability:** Cloud-init works particularly well in cloud environments, allowing MSPs to spin up hundreds or thousands of instances without manually creating Golden Images for each one. ### **Drawbacks:** - **Complexity:** Writing and managing Cloud-init scripts can get complicated as the configuration becomes more customized and varied. - **Dependence on Cloud Providers:** Cloud-init is tightly integrated with cloud providers, which can limit its usage in on-premise environments. Cloud-init offers much more flexibility than Golden Images, making it a popular choice for cloud-centric environments where servers need to be dynamically configured at boot. ## 3. **One-Click Templates: The Simplified Deployment Solution** **One-Click Templates** are pre-configured application stacks that can be deployed with just a single command or click. They go beyond the base OS setup and often include application installation, configuration, and even integration with other services. ### **Benefits of One-Click Templates:** - **Instant Deployment:** These templates are the fastest way to deploy fully functional applications, including all dependencies and configurations. - **Comprehensive Configuration:** One-click templates can configure everything, from the OS to the application level, including services, networking, and more. - **No Maintenance:** Unlike Golden Images, One-Click Templates are typically maintained by the platform, reducing the need for constant updates on your part. ### **Drawbacks:** - **Limited Customization:** While one-click templates are fast, they might not be as flexible as Cloud-init for custom configurations. - **Not Always Transparent:** You may not always have visibility into how certain settings are configured, which can cause issues for MSPs who need to maintain fine-grained control. One-click templates are fantastic for MSPs who need to deploy entire environments quickly and without hassle. They are particularly useful when you need a standardized environment quickly, like for testing or staging, but they might not be as flexible as Cloud-init for more complex use cases. ## **What’s Right for Your MSP?** As MSPs scale and handle more clients, the question of standardization becomes even more critical. Here’s a quick comparison: | **Method** | **Best For** | **Pros** | **Cons** | |--------------------|----------------------------------------------------|--------------------------------------------------------|-----------------------------------------| | **Golden Images** | Simple, repeatable deployments | Consistency, speed, reliability | Manual updates, scalability limits | | **Cloud-Init** | Dynamic cloud infrastructure | Flexibility, automated provisioning, scalability | Complexity, cloud-specific | | **One-Click Templates** | Fast, standardized full-stack deployments | Speed, simplicity, fully configured stacks | Limited customization, less control | ## **What This Means for You** For MSPs, the choice between **Golden Images**, **Cloud-init**, and **One-Click Templates** ultimately depends on your needs for **scalability**, **flexibility**, and **management complexity**. - **Golden Images** are best suited for smaller, predictable environments where changes are minimal. - **Cloud-init** is ideal for MSPs working with cloud infrastructures who need dynamic, real-time provisioning. - **One-Click Templates** are perfect for fast, repeatable app stack deployment but may lack flexibility for highly customized environments. At **Raff Technologies**, we support all three approaches through flexible **VM configurations**, **private networking**, and **automated scaling** to help MSPs deploy cost-effective, standardized environments across thousands of clients. --- ### Why SSH Key Setup Still Breaks for New Users (And How We Test It) URL: https://rafftechnologies.com/blog/why-ssh-key-setup-still-breaks Published: 2026-04-20T00:00:00.000Z Description: Why SSH Key Setup Still Breaks for New Users (And How We Test It) SSH key setup still breaks for new users for one simple reason: the setup itself is not hard, but the failure modes are unforgiving. One wrong username, one misplaced public key, or one permission bit that is too open can turn a five-minute security improvement into a lockout. On a fresh cloud VM, that feels much worse than it should. At Raff Technologies, this matters because SSH access is the first real trust boundary most users touch. Before you install Docker, open a firewall rule, or deploy an app, you need a login path that is secure and predictable. Our existing tutorial on [setting up SSH keys on Ubuntu 24.04](/learn/tutorials/set-up-ssh-keys-ubuntu-24-04) covers the happy path. This post is about the part that usually gets less attention: why the happy path falls apart for new users, and how to test it like a real onboarding flow instead of assuming it will work because the commands look right. SSH key authentication is a login method that uses a private key on your device and a matching public key on the server. OpenSSH reads allowed user keys from the configured `AuthorizedKeysFile`, which defaults to `.ssh/authorized_keys` in the user’s home directory. That sounds simple, but it means SSH key login depends on several things being true at the same time: the right user account, the right key pair, the right file path, and the right permissions. We already cover the correct setup flow in our SSH tutorial and server hardening tutorial. This post is narrower on purpose. I wanted to focus on the specific mistakes that keep turning “I added my key” into “why am I still getting `Permission denied (publickey)`?” > **Editor note:** Before publishing, add one short Aybars-tested box here with real internal observations, such as the top 3 failure cases reproduced on a fresh Ubuntu 24.04 VM and how long each took to resolve. ## The Biggest Problem Is Usually Not the Key New users often assume that an SSH key problem means key generation failed. In reality, the key pair is usually fine. The failure is more often around context: the wrong login user, the key being copied to the wrong account, or the client offering a different private key than the one the server expects. That is why SSH troubleshooting feels weirdly frustrating. The commands look familiar. The server is online. The key exists. But one tiny mismatch between those pieces is enough to make the entire login fail. If you zoom out, most SSH key onboarding issues fall into four buckets: * you are connecting as the wrong username * the matching public key is not in the target user’s `authorized_keys` * file ownership or permissions are too open * you disabled the fallback path before verifying the key path actually worked The reason this hits beginners especially hard is that all four can produce nearly the same emotional result: “SSH is broken.” ## Wrong Username Is More Common Than People Admit This is the easiest mistake to make and one of the least obvious when you are new. A lot of people generate a key correctly, copy it correctly, and still fail because they connect to the server as the wrong user. They log in as `root` when the key was installed for `sammy`, or they use a new sudo user while the public key still sits under another account’s home directory. OpenSSH does not care that the server has your public key somewhere. It cares whether the public key is present for the exact account you are trying to log in as. That sounds obvious after the fact, but for new users it is one of the most common reasons the key setup “looks right” and still fails. Current SSH troubleshooting docs from other cloud providers still call out this exact pattern because it keeps happening in practice. This is why I think SSH tutorials should always make the account boundary more explicit than they usually do. “Copy your key to the server” is incomplete advice. The real instruction is “copy your public key to the home directory of the exact account you will use over SSH.” ## Permissions Are Small Details With Big Consequences The second big trap is permissions. SSH is strict for good reasons. If the `.ssh` directory or the `authorized_keys` file is too open, OpenSSH can reject them because loose permissions undermine the trust model around key-based authentication. Troubleshooting guides still converge on the same basic fixes: restrictive permissions on the home directory, `.ssh`, and `authorized_keys`; correct ownership; and confirmation that the server is actually reading the expected file. This is also where beginners get tripped up by advice that is technically right but operationally incomplete. They are often told: * set `~/.ssh` to `700` * set `authorized_keys` to `600` * make sure the files are owned by the target user That advice is correct. But what is missing is the reason it matters. SSH is not only checking that the key exists. It is checking whether it can trust the place where that key lives. That is why permission errors feel confusing. The key itself may be perfectly valid. The login still fails because the server has decided the environment around the key is not safe enough. ## The Matching-Key Problem Is Usually Invisible Another common failure is using the wrong private key on the client. This is especially easy to do on laptops and workstations where multiple keys already exist. You may generate a new Ed25519 key, add the public half to the server, and then discover that your SSH client is still offering an older RSA key or a completely unrelated identity loaded in your agent. That makes the server-side setup look broken when the real issue is that the client never presented the matching key in the first place. This is why I like treating SSH onboarding as a two-sided test: 1. verify the server has the right public key for the right user 2. verify the client is actually offering the corresponding private key If you only test the server side, you can lose a surprising amount of time debugging the wrong machine. ## New Users Disable the Safety Net Too Early This is the mistake that turns a minor issue into a support problem. A lot of first-time users follow the secure instinct of disabling password authentication quickly. In principle, that is a good move. Raff’s own SSH key tutorial recommends verifying key-based auth and then disabling password login, and its conclusion explicitly points users to the Raff web console as an emergency fallback if they ever lock themselves out. :contentReference[oaicite:8]{index=8} But in practice, people often disable the fallback before they have tested enough things: * can I open a second SSH session before closing the first one? * can I log in with the new non-root user? * does the client use the correct identity automatically? * do I still have console-based recovery if SSH fails? This is where cloud onboarding needs a slightly different mindset from local Linux tutorials. On a VM, distance amplifies mistakes. A typo in `sshd_config` is no longer just a typo. It is potentially a lost access path. ## The Recovery Path Matters as Much as the Setup Path This is the part many guides treat as an afterthought, but I think it deserves equal weight. A good SSH onboarding flow does not just prove that the secure login path works. It also proves that recovery is available if it stops working. Other providers still document recovery consoles for exactly this reason, and Raff already exposes the same logic in its own SSH tutorial: if you lose SSH access, the browser-based web console gives you a way back in without depending on port 22. :contentReference[oaicite:9]{index=9} That changes the emotional shape of SSH hardening. You can be strict without being reckless. I think that is one of the biggest gaps in beginner SSH education. Too many people are taught only the “secure path” and not the “recoverable path.” In production, you need both. ## How I Would Test SSH Key Onboarding Properly If I were turning SSH key setup into a repeatable onboarding test, I would not stop at “the command completed.” I would test it like this: ### 1. Validate the identity path Confirm the target username before copying the key. Make sure the public key lands in the actual account that will be used for SSH. ### 2. Validate the file path Confirm the public key is in the expected `authorized_keys` file for that exact user, not just somewhere on the server. OpenSSH’s default lookup behavior is simple, but only if you keep the user-to-file mapping simple too. ### 3. Validate ownership and modes Check the ownership and permissions of the home directory, `.ssh`, and `authorized_keys`. Do this before touching `sshd_config`, not after the login fails. ### 4. Validate the client side Use verbose SSH output and confirm the client is offering the identity you think it is offering. When a machine has several keys, assumption is the enemy. ### 5. Validate recovery Before disabling passwords or closing the original session, confirm you still have a recovery path through the cloud console. That sequence is slower than “just follow the commands,” but it is much better onboarding. It turns SSH key setup from a checklist into a testable access workflow. ## Why This Still Matters on Small Teams Some people treat SSH key mistakes as beginner issues that disappear once a team gets serious. I do not think that is true. These failures keep showing up because small teams move quickly, reuse snippets, create users under time pressure, and harden servers while also trying to ship something else. The issue is not lack of intelligence. It is that SSH combines security, Linux permissions, user context, and remote recovery in one narrow path. That path is easy to get 95% right and still fail. That is exactly why this topic belongs on Raff’s blog rather than only in a step-by-step tutorial. Tutorials teach the correct path. Blog posts like this help explain why the correct path still breaks in real life. ## What This Means for You If you are new to cloud servers, the biggest improvement you can make is to stop treating SSH key setup as a single command sequence and start treating it as an access test. That means: * confirm the username first * confirm the matching key pair second * confirm file ownership and modes third * confirm recovery before you disable the old path If you want the clean setup flow, start with our tutorial on [setting up SSH keys on Ubuntu 24.04](/learn/tutorials/set-up-ssh-keys-ubuntu-24-04). If you are designing a broader access model, pair it with [Bastion Host vs VPN vs Public SSH](/learn/guides/bastion-host-vs-vpn-vs-public-ssh) and [Cloud Security Fundamentals](/learn/guides/cloud-security-fundamentals). And if you are still at the very start, launch a [Raff Linux VM](/products/linux-vm) and test your SSH path before you install anything else. That is still the safest order of operations. --- ### What We Check Before Publishing a One-Click App Template URL: https://rafftechnologies.com/blog/what-we-check-before-publishing-one-click-app-template Published: 2026-04-20T00:00:00.000Z Description: What We Check Before Publishing a One-Click App Template A one-click app template is only useful if it keeps its promise after the first click. At Raff Technologies, we do not treat “install completed” as the bar for publishing. We treat rerun safety, sane defaults, credential clarity, and recovery as part of the release criteria. That matters because a one-click deployment is not just a faster installer. It is a product surface. When someone launches an app template, they are trusting that the platform made a long list of decisions for them: which ports to expose, where data should live, how secrets are created, what happens on reboot, and whether the application is still understandable after the first login. We already explain the broader provisioning decision in our guide to [cloud-init, custom images, and one-click apps](/learn/guides/vm-provisioning-models-cloud-init-custom-images-one-click). This post is narrower on purpose. I want to focus on the part users do not always see: what we check before we feel comfortable putting a template in front of someone who expects it to work without a troubleshooting session. ## The First Install Is Not Enough The first successful install can be misleading. A template may work perfectly on a clean machine and still be risky to publish. The real question is whether it behaves predictably once reality begins: someone restarts the VM, reruns part of the installer, changes a domain later, or decides to move from “testing this” to “actually keeping this online.” That is why install idempotency matters so much. In practical terms, idempotency means a deployment process can be repeated without creating duplicate resources, broken state, or contradictory configuration. I do not expect every one-click template to be fully rerunnable from zero in every possible scenario. But I do expect it to fail cleanly, detect existing state properly, and avoid turning a second run into a repair job. A pattern that shows up often in template work is that the hardest problems are not in the main application. They are in the layer around it. The app starts, but the second run creates a second admin user. The service boots, but a reverse-proxy config gets duplicated. The container launches, but the volume path changes in a way the user does not notice until data disappears after an update. That is why “works once” is never enough. ## Default Ports Are Not Small Details Port choices look like implementation details until they collide with real usage. A one-click template is making an opinionated decision about exposure. If it binds directly to a common port, opens too much to the public internet, or assumes the user will never run another service on the same machine, the setup feels simple only until the second workload arrives. I think of default ports as a product decision, not a low-level technical choice. A good template should make it easy to understand: * which service is public * which service should stay internal * whether a reverse proxy is involved * what happens if the chosen port is already in use * how the user changes the port later without breaking the app This is where simple templates often become messy. The application itself is fine, but the network story is vague. That creates support questions that feel avoidable in hindsight. For one-click apps, I would much rather see a template make one clean exposure decision than try to be clever. A smaller number of explicit paths is easier to explain, easier to secure, and easier to recover when something goes wrong. If the deployment model benefits from isolation, that should be obvious from the start, especially when the app may later sit alongside other workloads on a [Linux VM](/products/linux-vm) or behind private networking. ## Credentials Should Be Clear, Not Clever Credential handling is one of the easiest ways to make a polished template feel unsafe. The user needs to know three things immediately after deployment: * what credential was created * where it is stored or shown * what they are expected to rotate or change first That sounds basic, but this is where one-click app experiences often fall apart. Some setups generate a password but bury it in a log. Others create multiple credentials without clearly separating app login, database access, and system-level access. The install technically works, but the first-login experience feels ambiguous. I prefer templates that are boring in the best possible way. If a secret is generated, it should be surfaced once, clearly. If the application creates an admin account, that path should be obvious. If there are post-deploy actions the user must take, those steps should be impossible to miss. The more “magic” a template uses around credentials, the more likely it is to confuse the exact person the template is supposed to help. This is also where the surrounding platform matters. If recovery or inspection is needed, the user should not have to guess how to get back into the machine. That is why I see browser-based recovery access as part of the quality story around app templates, not as a separate convenience feature. ## Upgrade Safety Starts on Day One A one-click template is easy to admire on launch day. The harder question is whether it still behaves like a product after the first update. For me, upgrade safety is not a future optimization. It is a publishing requirement. Before a template goes live, I want to know what happens when: * the app version changes * the container image changes * the service restarts * the VM reboots * a schema migration appears * the user expects their data to still be there afterward A template that hides all of that behind a clean first screen may look great in a demo, but it creates the wrong kind of surprise later. This is why storage paths, named volumes, service files, and config locations matter so much. They define whether the deployment can survive beyond the first session. A user should not need to reverse-engineer the app layout just to understand what must be backed up or what will persist after an upgrade. I think this is one of the biggest differences between “installer thinking” and “template thinking.” An installer tries to get software onto a machine. A publishable template should help the user keep that software alive, understandable, and recoverable. ## We Verify the First 15 Minutes, Not Just the First Click A lot of app-template QA focuses too narrowly on the deployment event itself. I think the more useful test is the first 15 minutes after deployment. That is where real clarity shows up. Can the user reach the app without guessing? Is the first-login path obvious? Are the credentials discoverable? Is the public endpoint where they expect it to be? Does the template leave behind a clean mental model of what just happened? I like to think of this as user-first verification rather than pure deployment verification. The deployment can be technically correct and still fail the user. A container starts, a service is active, and the health check turns green — but the person behind the screen is still confused about what to do next. That is not a good one-click experience. The templates that feel strongest are usually the ones that reduce explanation debt. They do not only work. They make their own structure legible. ## What We Treat as a Release Blocker There are a few issues I would treat as release blockers immediately. If the installer behaves unpredictably on a second run, that is a blocker. If the template exposes ports in a way that is hard to understand or easy to misuse, that is a blocker. If the initial credentials are unclear, inconsistently stored, or too easy to lose, that is a blocker. If a reboot changes behavior unexpectedly, if persistent data is not obviously persistent, or if the upgrade story is “we will figure that out later,” that is a blocker too. This may sound strict, but I think one-click products need that strictness. The entire value proposition is reduced friction. If the friction is merely postponed until five minutes later, the product has not actually done its job. ## Why This Matters More Than It Sounds It is easy to think of one-click apps as a convenience layer. I do not think that is quite right. They are a trust layer. When someone uses a one-click deployment, they are delegating decisions to the platform. They are accepting someone else’s opinions about app structure, networking, storage, defaults, and recovery. That is why template publishing standards matter so much. They determine whether the platform feels dependable or merely fast. On Raff, that matters because one-click applications sit inside a broader cloud experience built around virtual machines, storage, networking, snapshots, backups, and recovery paths. The template does not live on its own. It lives inside the user’s actual infrastructure decisions. That means the bar should be higher than “the app launched.” ## What This Means for You If you are using one-click apps, the most useful question is not “Can this install fast?” The better question is “Will this still make sense after I stop looking at the deployment screen?” That is the standard I would use when evaluating any template. Look for rerun safety. Look for clear defaults. Look for a visible credential story. Look for persistence that survives reboots and updates. And look for a deployment model that is still understandable once the first launch is over. If you want the broader framework behind that decision, start with our guide to [cloud-init, custom images, and one-click apps](/learn/guides/vm-provisioning-models-cloud-init-custom-images-one-click). If you are evaluating the product side of the experience, explore [Raff Apps](/products/raff-apps). And if recovery matters to your workflow, read how our [browser VNC console changes VM recovery](/blog/access-your-vm-anywhere-with-our-new-vnc-console). That is the real standard I would use for publishing a one-click app template: not just “it deploys,” but “it stays understandable after deployment.” --- ### What We Learned Benchmarking Caddy vs Nginx on Small Cloud VMs URL: https://rafftechnologies.com/blog/what-we-learned-benchmarking-caddy-vs-nginx Published: 2026-04-20T00:00:00.000Z Description: What We Learned Benchmarking Caddy vs Nginx on Small Cloud VMs When people compare Caddy and Nginx, the conversation usually gets pulled toward ideology. One side says Nginx is the battle-tested default. The other says Caddy makes HTTPS feel like it belongs in this decade. After looking at both through the lens that actually matters on a small VM, I think the more useful question is simpler: which one gets a real app online with less friction, less overhead, and fewer opportunities to create your own incident? At Raff Technologies, that is the part I care about most on small cloud VMs. A 1 GB or 2 GB machine does not give you much room for unnecessary complexity. On a bigger server, you can afford extra moving parts and still feel fine. On a smaller VM, every extra daemon, every manual TLS step, and every late-night certificate problem feels heavier than it should. We already have a broader conceptual guide on [Caddy vs Nginx](/learn/guides/caddy-vs-nginx-reverse-proxy), plus hands-on tutorials for [installing Caddy on Ubuntu 24.04](/learn/tutorials/install-caddy-ubuntu-24-04), [installing Nginx on Ubuntu 24.04](/learn/tutorials/install-nginx-ubuntu-24-04), and [securing Nginx with Let’s Encrypt](/learn/tutorials/secure-nginx-lets-encrypt-ubuntu-24-04). This post is narrower on purpose. I wanted to stay focused on what changes when the machine is small, the team is busy, and the reverse proxy is just one part of a real deployment. ## The Test That Actually Matters on a Small VM If you are serving millions of static requests per minute from a single node, the answer is easy: raw web server efficiency matters a lot, and Nginx has earned its reputation for a reason. But that is not the workload most small cloud VMs are running. Most small VMs are doing one of these jobs: * sitting in front of a single application * terminating HTTPS for an internal tool * serving a lightweight SaaS frontend * proxying traffic to Docker containers * exposing a staging environment * fronting an admin dashboard or API In those situations, I do not think the best first question is, “Which one wins the benchmark chart?” I think the better first question is, “Which one gets me to a safe, boring, maintainable default faster?” That is where the comparison becomes more interesting. > **Editor note:** Before publishing, add one small same-hardware results box here: 1 GB and 2 GB Raff VM, idle RSS, time to first HTTPS, static-file requests/sec, and reverse-proxy p95 latency. ## The First Surprise Was Not Performance The first surprise was that the practical difference showed up before any synthetic benchmark mattered. Caddy gets to a secure default very quickly. The biggest reason is not magic performance. It is the fact that HTTPS is part of the default experience, not a second project you remember to complete later. On a small VM, that changes the operational shape of the deployment immediately. With Caddy, the cleanest path is usually one service, one config file, and one domain pointed to the box. That sounds like a small convenience until you remember how many real deployments stall between “the app responds on port 3000” and “the app is actually online, encrypted, and renewable without babysitting.” Nginx can absolutely get you to the same destination. It has done that for years, and it does it well. But on smaller teams and smaller servers, the difference is that Nginx often asks you to think in two layers: first the web server, then the certificate workflow. That is not a flaw. It is just a different operating model. What changed my view on small VMs is this: setup friction is not only a productivity issue. It becomes a reliability issue. The more pieces you have to remember on day one, the more chances you create for day thirty to go wrong. ## Where Nginx Still Pulls Ahead This is the part where I do not think it helps to pretend both tools are equal at everything. They are not. Nginx still feels like the stronger default when you care about squeezing the most out of limited resources. If you are running on a very small machine and want the leanest possible footprint around a simple static or proxy workload, Nginx has a strong case. That matters most on the smallest VM sizes, where memory headroom is not theoretical. It is the difference between “everything feels fine” and “why is the box swapping under light load?” It also matters when the reverse proxy is doing more than simply passing traffic through. If your deployment needs more mature fine-grained control over request routing, traditional tuning patterns, or you already know the Nginx config model well enough to move quickly inside it, Nginx remains a very sensible choice. This is the trap I think people fall into: they hear that Caddy is simpler and assume that simplicity automatically makes Nginx obsolete. It does not. Simplicity is an advantage only when it solves a problem you actually have. If your problem is “I need the most familiar and efficient reverse proxy possible on a small machine,” Nginx is still hard to argue against. ## Why Caddy Feels Modern Faster What Caddy gets right is not just syntax. It is the order of operations. On small VMs, especially ones deployed by developers instead of full-time ops teams, the fastest path to a secure default often wins in practice. Caddy feels modern because it treats HTTPS as the baseline, not as a separate hardening task. That changes the emotional shape of deployment. You stop thinking, “I still need to finish TLS,” and start thinking, “The secure edge is already part of the service.” That matters more than many people admit. A lot of small-VM projects are not failing because their reverse proxy cannot handle enough traffic. They are failing because the deployment path becomes fragile: certificate renewal gets missed, redirects are inconsistent, the proxy config drifts from the app config, or the operator forgets which piece owns the public edge. Caddy reduces that risk by compressing more of the secure-by-default path into the server itself. I would also add that the configuration model helps more than benchmarks usually capture. On smaller teams, readability is a feature. A config you can scan in seconds is easier to maintain than one you have to mentally parse every time you open it. ## When the Simpler Config Wins There is a certain kind of workload where I would choose Caddy first without much debate. I would choose Caddy first for: * a single app on one VM * internal tools exposed to a team over HTTPS * dashboards and admin panels * lightweight APIs * prototypes that need to become production quickly * client proof-of-concept environments * small staging stacks where the point is to move cleanly, not to hand-tune everything In those cases, the simpler config is not just “nice.” It shortens the distance between deploying the app and trusting the deployment. That is a good trade. On Raff, this becomes especially practical because small workloads do not have to start on oversized infrastructure. If you are validating an app, a dashboard, or a lightweight service, you can start on a small [Linux VM](/products/linux-vm), keep the edge simple, and resize later if the workload grows. ## When I Would Still Pick Nginx First I would still pick Nginx first when the environment already speaks Nginx fluently. That includes: * teams with existing Nginx standards and templates * stacks that already depend on Nginx-centric patterns * memory-sensitive workloads on the smallest VM sizes * environments where you want maximum familiarity during debugging * situations where the reverse proxy layer will become more complex over time There is also a human factor here that is worth saying out loud: the best reverse proxy is often the one your team can operate confidently at 2 AM. If the team already knows Nginx deeply, switching to Caddy for elegance alone is not always a net win. Operational confidence is part of performance too. ## The Real Decision on a Small VM The most useful lesson from this comparison is that Caddy and Nginx are not competing only on throughput. They are competing on what kind of work you want the operator to do. Nginx asks for more explicit control and tends to reward that with lean performance and a mature operational model. Caddy asks for less ceremony and rewards that with faster secure defaults and less TLS-related friction. On a small cloud VM, that makes the choice feel less philosophical and more economic. If the machine is tiny and the app is simple, Nginx may buy you more breathing room. If the team is small and the goal is to get to a clean HTTPS deployment with fewer moving parts, Caddy may buy you something even more valuable: fewer chances to make a routine deployment messy. ## What This Means for You If you are deploying a single modern app and want the fastest path to a secure, readable reverse proxy, I would start with Caddy. If you are optimizing for the leanest footprint, already know Nginx well, or expect the edge layer to grow more complicated over time, I would start with Nginx. That is the practical answer. Not “Caddy is the future” and not “Nginx is always better.” Just this: on small cloud VMs, the right choice depends on whether your constraint is machine efficiency or operator attention. And in real deployments, both constraints are real. If you want the broader decision framework first, read our [Caddy vs Nginx guide](/learn/guides/caddy-vs-nginx-reverse-proxy). If you already know which direction you want to go, follow the setup path for [Caddy on Ubuntu 24.04](/learn/tutorials/install-caddy-ubuntu-24-04) or [Nginx on Ubuntu 24.04](/learn/tutorials/install-nginx-ubuntu-24-04), then add HTTPS with our [Let’s Encrypt for Nginx tutorial](/learn/tutorials/secure-nginx-lets-encrypt-ubuntu-24-04). If you still do not have the server yet, start with a [Raff Linux VM](/products/linux-vm) and keep the first deployment as simple as possible. That is usually where the best decisions get made. --- ### Why Small Teams Should Not Start With AWS by Default URL: https://rafftechnologies.com/blog/why-use-raff-instead-of-aws-a-better-way-to-launch-learn-and-build Published: 2025-05-12T00:00:00.000Z Description: Why Small Teams Should Not Start With AWS by Default ## Most startups should not start on AWS by default Most startups should not start on AWS by default. Not because AWS is weak, but because early teams usually need fast deployment, clear pricing, and infrastructure they can understand without turning cloud setup into a second product. For a lot of MVP-stage companies, AWS solves a later-stage problem before the current-stage problem is even clear. That is the real issue. AWS is one of the most capable cloud platforms in the world, but capability is not the same thing as fit. If your team is trying to launch an MVP, spin up a staging environment, run a client demo, or ship a small production app, the biggest risk is often not a lack of services. It is losing time and attention to infrastructure complexity before the product has earned it. At Raff Technologies, this is one of the patterns I keep hearing in conversations with smaller teams: they are not asking for a giant service catalog. They are asking whether they can launch quickly, know what they are paying for, and stay in control as the workload grows. That is a very different buying question from the one AWS was built to dominate. ## AWS is powerful, but power is not the same thing as a good starting point This is where I think a lot of startup infrastructure advice becomes misleading. AWS is powerful in exactly the ways a giant platform should be powerful. It has depth, breadth, regional scale, managed services, policy layers, and enough optionality to support companies at every stage. That is why it became the default answer in so many cloud conversations. But default is not the same as correct. For a small team, the cost of AWS is not only the invoice. It is the number of choices you have to make before useful work begins. Which service? Which instance family? Which storage shape? Which networking pattern? Which identity model? Which future abstraction do you need to plan around now so you do not regret the first decision later? A mature infrastructure team may see that as flexibility. A startup team often experiences it as overhead. That is why I think the better question is not “Is AWS powerful enough?” Of course it is. The better question is “Does this team need that much platform before it has even validated the product or workflow?” ## Startups usually need momentum first, not maximum optionality This is the part I care about most. A lot of MVP-stage teams think they are buying future-proofing when they start with a huge platform. What they are often buying is hesitation. They hesitate before launching a second environment. They hesitate before running a heavier test workflow. They hesitate before trying something temporary because they are not sure what it will cost or what it will touch. They hesitate because the infrastructure already feels like a system that must be respected, not a tool that helps them move. That is bad economics for an early product. At MVP stage, the company usually does not win because it made the most expandable infrastructure decision on day one. It wins because it learned quickly, shipped clearly, and avoided burning its best people on problems that did not matter yet. That is why I think small teams should optimize for: - understandable compute - clear pricing - simple deployment paths - practical storage - basic private networking when needed - and an upgrade path that grows with the workload instead of ahead of it That is a very different priority stack from “buy the cloud with the most services.” ## The wrong starting cloud creates hidden costs The biggest AWS cost for a small team is often not a billing line item. It is operational attention. A team without a dedicated platform engineer is already balancing product work, debugging, deployment, customer feedback, maybe sales demos, maybe internal tooling, maybe some support load. In that environment, cloud infrastructure should remove cognitive drag, not add it. But a broad platform can create drag in quiet ways: - onboarding takes longer - debugging requires more platform context - internal documentation gets heavier earlier - staging and production decisions become harder than they should be - pricing gets harder to explain to non-technical people - and every “simple” change turns into three architecture questions None of that means AWS is bad. It means the platform can ask for more operational maturity than an early team actually has. That mismatch is expensive, even when the invoice is still manageable. ## What small teams usually need first If I strip away the cloud branding and look at how early teams actually operate, the first needs are usually not exotic. They need: - one or two reliable environments - predictable VM-style compute - fast storage - a simple mental model for deployment - backups or snapshots when the workload becomes worth protecting - private networking only when the application or workflow really needs it - pricing they can explain without turning every deployment into a finance exercise That is why I still think a focused cloud platform is often the better first move. Start with the infrastructure you can understand. Use it to validate the product. Keep the architecture portable. Then add complexity when the workload proves it deserves more. That is a much healthier progression than starting with hyperscale assumptions and hoping the product catches up. ## When AWS is actually the right answer I do not think this should be an anti-AWS argument. That would be lazy. AWS is absolutely the right answer in some situations. If your team already knows AWS well, the learning curve cost is lower. If you need a specific managed service ecosystem from day one, the case changes. If your customer requirements already include enterprise security patterns, regional distribution, or provider-specific integrations, AWS may be the practical fit. If infrastructure itself is part of your competitive advantage, then platform depth can be worth the attention it demands. Those are real reasons. What I object to is not choosing AWS. It is choosing AWS automatically, before the workload or team has justified it. That is a very different position. ## The better startup question is not “Which cloud is best?” It is: **What is the simplest infrastructure that lets us ship confidently this quarter?** That question usually leads to better answers. If the honest answer is: - one app server - one database - one staging environment - basic storage - and a clear path to add more when the load increases then the best starting cloud is usually the one that makes that setup easiest to launch, easiest to price, and easiest to understand. If the honest answer is: - many managed services - broad internal platform patterns - strict provider integrations - or global infrastructure from the beginning then yes, AWS may be the right first decision. The problem is that a lot of startups answer the second question because it sounds more serious, even when they are actually living in the first one. ## Simplicity is not a step backward I think some founders worry that choosing a simpler cloud path means they are thinking too small. I see it differently. A simple starting point is often the more disciplined decision because it forces the team to earn complexity instead of inheriting it too early. That does not block growth. It usually improves it. A clean VM-based start is easier to reason about. A clean VM-based start is usually easier to migrate later than a stack built on too many provider-specific assumptions. A clean VM-based start gives the team better visibility into what the application actually needs before the architecture becomes expensive to change. That is not anti-scale. That is scale in the right order. ## What This Means for You If you are choosing cloud infrastructure for an MVP or an early SaaS product, I would keep the rule simple: Do not buy hyperscale complexity before your workload actually needs it. Start with the infrastructure your team can operate with confidence. Keep the architecture understandable. Let real usage, not startup anxiety, decide when you need more services, more abstraction, or more platform depth. For a lot of teams, that means starting with a straightforward [Linux VM](/products/linux-vm), understanding the actual pricing shape on the [pricing page](/pricing), and getting clearer about environment discipline with a guide like [Dev vs Staging vs Production in the Cloud](/learn/guides/dev-staging-production-cloud-environments). If your team is self-hosting tools or lightweight apps, a practical deployment path matters much more than platform prestige. That is the lens I would use. Not “Which cloud sounds strongest?” But “Which cloud helps this team move now without paying the complexity tax too early?” Because for most startups, the first cloud decision should not be about maximum possibility. It should be about minimum friction. --- ### Why We Include Unmetered Bandwidth on Every Plan URL: https://rafftechnologies.com/blog/why-we-include-unmetered-bandwidth-on-every-plan Published: 2026-03-26T00:00:00.000Z Description: Why We Include Unmetered Bandwidth on Every Plan The easiest cloud bill to trust is the one you can explain before it arrives. That sounds obvious, but it is surprisingly rare in infrastructure. Teams compare vCPU counts, RAM, and storage tiers in detail, then treat bandwidth as a footnote until the workload becomes real. By then, it is no longer a footnote. It is a source of hesitation, over-engineering, and sometimes outright fear about what a successful month might cost. That is one of the reasons we include unmetered bandwidth on every Raff plan. We did not make that decision because the phrase looks good on a pricing page. We made it because bandwidth overage billing creates the wrong behavior in the teams we are trying to help: they test less confidently, scale more cautiously, and design around invoice anxiety instead of application needs. ## The problem with bandwidth caps is not only financial Most people hear “unmetered bandwidth” and think “nice, that helps me save money.” Sometimes it does. But the bigger point is operational. A metered or tightly capped bandwidth model changes how teams behave. It makes them second-guess things they should be able to do comfortably: - serving more users after a launch - pushing more assets during a marketing campaign - shipping a media-heavy demo - running staging environments that mirror production - exposing APIs or dashboards without guessing whether normal usage will trigger a pricing surprise That is the real issue. A bandwidth cap is not just a number in the billing model. It is a design constraint that can show up before you are technically ready to think about it. From a risk perspective, that is unhealthy. Developers should spend their attention on performance, availability, and correctness. They should not have to translate every traffic spike into a pricing stress test. ## Why this matters more for smaller teams Large organizations usually have more tolerance for billing complexity. They may not like it, but they often have FinOps processes, multi-layer approvals, or internal controls that can absorb the mess. Smaller teams usually do not. Startups, solo developers, agencies, early product teams, and technical founders tend to operate with tighter margins and fewer people. In that environment, predictability matters more than elegance. A simple cost model is not a convenience feature. It is part of whether the platform feels usable under real pressure. This is why we think bandwidth policy belongs in the first infrastructure conversation, not the last one. If a team is trying to pick a cloud platform and can explain the compute price but not the traffic economics, that is already a warning sign. ## Unmetered is not the same thing as “infinite” This is an important distinction, and I would rather say it clearly than let the term become fuzzy. Unmetered bandwidth does not mean the laws of physics disappeared. It means the provider is not charging you in a granular transfer-based way that turns normal traffic growth into a line-item trap. It is about billing model and predictability, not fantasy infrastructure. That difference matters because the cloud industry often uses traffic language loosely. “Unlimited,” “unmetered,” and “included” are not always used with the same discipline. We prefer clarity here because vague promises create the same trust problem as vague pricing. The point is not to imply there are no network realities. The point is to remove a category of billing volatility that makes cloud decisions harder than they need to be. ## Why we think this is also a reliability decision My perspective on this is shaped by security and operational risk more than marketing. When teams fear traffic costs, they sometimes make defensive architecture decisions for the wrong reason. They avoid realistic staging. They reduce visibility. They compress or strip useful functionality too early. They hesitate to expose features because a successful response could feel financially ambiguous. That is not a stable way to operate. A safer infrastructure model is one where the normal, healthy use of the application does not feel like a billing threat. If users arrive, assets are served, and APIs are used, the team should be thinking about uptime, latency, and abuse prevention — not wondering whether this week’s traffic pattern quietly changed the business model. That is why I see unmetered bandwidth as partly a reliability choice. Predictable traffic economics reduce the chance that teams design around fear instead of engineering reality. ## Why we included it across every plan We made the decision across the plan lineup because the teams who benefit most from predictable bandwidth are often the teams least equipped to absorb surprises. If unmetered bandwidth only existed on premium tiers, it would fail the exact audience it is supposed to help. The early-stage team validating a product, the developer shipping a side project, the agency hosting a client build, and the startup trying to keep one environment simple all need predictability before they need sophistication. That logic is consistent with how Raff presents the platform publicly today. The pricing page highlights unmetered bandwidth alongside transparent pricing, 14-day money-back guarantee, and 24/7 support, while the broader site emphasizes fast deployment, Linux and Windows VM options, and modern AMD EPYC plus NVMe-backed infrastructure. Those signals all point in the same direction: reduce friction where smaller teams feel it most. ## What this changes in real infrastructure decisions When bandwidth is predictable, teams make cleaner decisions. They can choose a VM based on compute and memory needs instead of trying to compensate for a transfer cap they may or may not hit later. They can set up staging environments with fewer mental reservations. They can launch marketing pages, dashboards, internal tools, or early SaaS products without introducing bandwidth math into every deployment conversation. It also improves the way teams think about growth. A healthy cloud model should not punish success psychologically. If traffic starts rising because something worked, the primary questions should be: - do we need more application capacity? - do we need a caching layer? - do we need a reverse proxy or a load balancer? - do we need better monitoring? Those are good engineering questions. “Can we afford our users showing up?” is not. ## Where unmetered bandwidth does not replace good architecture This is also worth saying clearly. Unmetered bandwidth is not a substitute for proper design. You still need sensible application architecture, caching where appropriate, careful exposure of public services, and a realistic understanding of your workload. If you run a noisy design, a chatty application, or a badly optimized media path, unmetered bandwidth does not magically make that wise. It simply removes one billing distortion from the decision. In other words, the goal is not to encourage sloppy usage. The goal is to let teams optimize for performance and resilience without an avoidable transfer-metering penalty hanging over ordinary operations. ## This choice reflects who Raff is built for The strongest infrastructure decisions usually tell you who the product is trying to help. For us, unmetered bandwidth is part of a broader pattern. It sits alongside simple VM pricing, straightforward deployment, backups and snapshots, private networking, and a platform shape that makes sense for developers, startups, and smaller teams that need real infrastructure without hyperscale complexity. That does not mean Raff is the right fit for every workload. Some teams need larger service catalogs, more global regions, or deeper platform abstraction. That is a legitimate reason to choose another provider. But for the audience we care about, predictability is not a secondary feature. It is part of whether the platform feels usable and trustworthy in the first place. ## What This Means for You If you are evaluating cloud infrastructure, do not treat bandwidth policy as a minor footnote on the pricing page. Treat it as a product philosophy signal. A platform’s bandwidth model tells you a lot about how it expects customers to behave, what kinds of surprises it thinks are acceptable, and whether normal traffic growth will feel like progress or risk. That is why we include unmetered bandwidth on every Raff plan. It helps keep cloud decisions grounded in engineering reality instead of billing anxiety. If that matters to your team, start with [Raff pricing](/pricing), compare it to how you currently think about traffic costs, and then map that against the kind of workload you actually run on [Raff VMs](/products/raff-vm). If your architecture is starting to grow, pair that with our guide on [Load Balancing Explained](/learn/guides/load-balancing-explained) so your next scaling decision is driven by application needs, not invoice fear. --- ### Why We Think Pricing Simplicity Is a Product Feature URL: https://rafftechnologies.com/blog/why-we-think-pricing-simplicity-is-a-product-feature Published: 2026-04-19T00:00:00.000Z Description: Why We Think Pricing Simplicity Is a Product Feature ## Pricing is one of the first parts of the product people actually feel We think pricing simplicity is a product feature because pricing changes behavior. Not just buying behavior. Usage behavior. A lot of infrastructure companies still talk about pricing as if it lives outside the product, like it starts after the user has already made the technical decision. I do not think that is true. In cloud, the pricing model affects how confidently a team launches, tests, scales, duplicates environments, and explains spend internally. That means pricing is not just a finance topic. It is part of the user experience. At Raff Technologies, this is one of the ideas we keep coming back to. A product can be technically strong and still feel stressful to use if the pricing model is hard to predict. A team can like the dashboard, like the performance, and still hesitate before doing normal things because they do not trust what the bill will look like afterward. That hesitation is not a billing issue in isolation. It is a product issue. ## The problem is not only high pricing This is the first distinction I think matters. A pricing model can be expensive and still feel understandable. A pricing model can be cheap and still feel risky. That is why I do not think “simple pricing” means “lowest price wins.” It means the customer can build without doing mental accounting all day. If a team cannot answer basic questions like: - what this server will cost, - what changes the bill, - what happens when usage grows, - or whether a normal product decision might trigger an unexpected charge, then pricing is creating product friction. In cloud infrastructure, friction changes architecture. A founder delays a staging environment. A developer avoids spinning up something useful. A team underuses the platform because uncertainty feels more dangerous than limitation. That is not a finance-side effect. That is the product experience shaping engineering behavior. ## Confusing pricing makes teams build differently I think this is one of the least discussed truths in cloud. When pricing is too layered, too conditional, or too hard to explain, teams stop optimizing for what the product needs. They start optimizing for what the invoice might punish. That creates the wrong kind of discipline. Instead of healthy discipline like: - cleaning up unused environments, - sizing workloads properly, - or improving release safety, you get defensive discipline: - avoiding useful experiments, - delaying infrastructure upgrades, - treating growth like a billing risk, - or building around price anxiety instead of operational clarity. This is especially harmful for smaller teams. A large company may have enough budget, procurement support, and internal process to absorb pricing complexity for a while. A startup usually does not. For a startup, unclear pricing quickly becomes decision friction. And decision friction is expensive. That is why I think pricing simplicity is more than a trust signal. It is a productivity feature. ## The best pricing models reduce cognitive overhead This is the product design angle I care about most. Good infrastructure products do not only reduce technical effort. They reduce cognitive effort. You already ask a team to think about: - deployments, - environments, - reliability, - backups, - access, - monitoring, - performance, - and customer expectations. If pricing adds a second layer of complexity on top of all that, the product is increasing mental load right where teams need confidence. I think that is one reason pricing simplicity matters so much for cloud products. It reduces one of the most common silent costs in infrastructure: uncertainty. And uncertainty changes behavior more than most providers admit. A predictable platform feels safer to adopt. A predictable platform feels easier to explain internally. A predictable platform feels easier to grow on. That is product work. ## Simplicity is not a marketing word if it changes workflow A lot of companies use “simple” as branding. I am less interested in the word itself than in the effect. Does the pricing model make a startup more comfortable creating a staging environment? Does it make a small team less nervous about success? Does it make cloud infrastructure easier to budget without needing a specialist to decode the bill? Does it help an engineering lead explain spend to the founder without turning every technical choice into a finance conversation? If yes, simplicity is not just a message. It is functionality. That is why I see simple pricing in the same category as: - clean provisioning, - understandable VM sizing, - predictable networking behavior, - or clear backup options. All of those reduce hesitation. And infrastructure products become better when they reduce hesitation in the right places. ## Pricing should match how real teams actually use cloud This is where I think cloud pricing gets disconnected from reality. A lot of billing models make sense internally to the provider. They are easy to segment, meter, and package. But that does not mean they match how customers think or work. Real teams do not wake up asking: - which pricing dimension is easiest for the provider to calculate? They ask: - can I deploy this safely? - can I keep this environment alive without regret? - can I scale this without rethinking the whole platform? - can I trust that normal usage will stay normal on the bill too? That is why we think pricing should be evaluated like any other product design decision: not only by whether it is mathematically valid, but by whether it supports the customer’s real workflow. A pricing model that keeps people cautious in the wrong places is not helping the product, even if it looks sophisticated from the provider side. ## Why this matters even more for startups and small teams Smaller teams feel pricing friction faster. They do not have a separate finance team translating cloud cost into business language. They do not have endless room for duplicate environments, pricing surprises, or layers of managed overhead they cannot fully justify. They are making infrastructure choices while also shipping product, talking to customers, and trying not to run out of time. That is why startup-friendly infrastructure is not only about lower entry cost. It is also about lower uncertainty. A team should be able to understand the cost of getting started, the likely shape of growth, and the consequences of normal usage without feeling like every decision needs a billing risk assessment first. That is why I think pricing clarity is a product feature in exactly the same way onboarding clarity is a product feature. It changes whether the user feels ready to move. ## What this means for how we think about Raff This is one of the reasons we do not see pricing as separate from the rest of the product. If a pricing model makes a good infrastructure workflow feel stressful, then the product is not as strong as it looks. If the pricing model makes teams more confident to build, test, and scale, then it is doing real product work. That does not mean every pricing decision is easy. It does mean the standard should be clear. We should ask: - does this reduce billing anxiety or increase it? - does this help a team plan or make them hesitate? - does this reflect how smaller teams actually use cloud? - does this support trust, not just conversion? Those are product questions, not just commercial ones. And I think more infrastructure companies should treat them that way. ## What This Means for You If you are choosing infrastructure, I would look beyond the headline rate and ask a more useful question: **What kind of behavior does this pricing model push us toward?** Does it make your team more confident? Does it make testing easier or more stressful? Does it help you understand growth? Does it let you explain spend without turning every technical decision into a budgeting argument? If the answer is yes, that pricing model is doing more than billing. It is helping the product feel usable. And if the answer is no, even a technically strong platform can feel harder to adopt than it should. That is why we think pricing simplicity is a product feature. Not because it sounds good in a headline. Because in cloud, the way you charge people changes the way they build. --- ### Why One Good VM Still Beats a Fancy Stack for Early SaaS URL: https://rafftechnologies.com/blog/why-one-good-vm-still-beats-a-fancy-stack-for-early-saas Published: 2026-04-19T00:00:00.000Z Description: Why One Good VM Still Beats a Fancy Stack for Early SaaS ## Most early SaaS teams do not have a scaling problem They have a complexity problem. That is why I still think one good VM beats a fancy stack for a lot of early SaaS companies. Not forever. Not for every workload. Not because distributed systems are bad. But because most early teams are not losing time to a lack of orchestration. They are losing time to unclear environments, messy deploys, weak sizing decisions, fragile recovery, and infrastructure choices that were made for a future version of the company that has not actually arrived yet. At Raff Technologies, this is one of the patterns I keep coming back to: smaller teams usually get more leverage from infrastructure they can understand end to end than from infrastructure that looks advanced on a diagram. A clean VM setup with clear ownership, safe release habits, backups, and the right amount of headroom is often a better business decision than adopting a “modern stack” too early and then paying the operational tax for the next twelve months. ## A fancy stack often solves tomorrow’s problem by creating today’s This is the part I think startups underestimate. A fancy stack sounds responsible because it looks like preparation: - multiple services - multiple environments - managed layers everywhere - orchestration - extra network complexity - more tooling around deploys, observability, and service boundaries And sometimes that is exactly the right move. But the default assumption that “more advanced equals more ready” is where a lot of early SaaS teams go wrong. A fancier architecture usually means: - more places for config drift - more infrastructure to patch - more things to learn before debugging - more money tied up in duplication - more moving parts between code and customer value That trade can absolutely be worth it when the workload demands it. The problem is that most early SaaS products do not demand it yet. So instead of buying clarity, the team buys overhead. ## One VM is not “simple” if it is being used carelessly This is where I want to be precise. I am not arguing that early SaaS should stay naive. A single VM is only an advantage when it is used well: - the environment is understood - the deployment flow is repeatable - the database is handled responsibly - access is controlled - backups exist - recovery is not just a theory - the workload is actually sized correctly That last part matters more than people think. A badly sized single VM is not a clever startup move. It is just a small bottleneck with branding. But a well-sized VM with a clean release path, a clear boundary between staging and production, and good operational discipline can carry far more than many teams expect. This is one reason I keep seeing the same sequence make sense for early companies: - start with one well-run VM - make the environment predictable - separate staging when the risk becomes real - resize when the workload proves you need it - split services only when one box is genuinely becoming the wrong boundary That progression is not glamorous, but it is healthy. ## The wrong first upgrade is usually architectural When an early SaaS team starts feeling pain, the first instinct is often to upgrade the shape of the system. Maybe that means: - moving to multiple servers early - adding Kubernetes before deploy discipline exists - adopting managed services for everything - separating components before they are actual bottlenecks - or treating “future-proofing” as a reason to increase complexity immediately I think that is often the wrong first move. The better question is: **what is actually failing first?** If deploys are risky, fix the deploy path. If the server is undersized, fix the server size. If production and staging are blurred, fix the environment boundaries. If one workload is hurting another, then maybe it is time to split services. If one node truly becomes the wrong operational boundary, then yes, move beyond one VM. But the point is that architecture should follow proven pressure, not generalized anxiety. That is what early SaaS teams need most: infrastructure decisions made in response to real bottlenecks, not infrastructure decisions made to imitate a later-stage company. ## One good VM is often better for product velocity This matters just as much as cost. A lot of startup infrastructure conversations focus on scaling and reliability, which makes sense. But early SaaS also lives or dies on shipping speed. And a system the team understands well is usually a faster system to ship on. One good VM often wins here because: - the deployment path is shorter - the blast radius is easier to reason about - the team can debug issues without switching mental models constantly - cost is easier to understand - environment drift is lower - ownership is clearer That does not mean one VM is a permanent strategy. It means it is often the best **phase-appropriate** strategy. And phase-appropriate infrastructure is usually better for a startup than impressive infrastructure. ## Startups often buy reliability in the wrong order This connects to something I keep seeing more broadly. Teams do not usually fail early reliability because they stayed too simple for one month too long. They fail it because they added complexity before they added order. A bigger stack does not automatically create: - safer releases - clearer access control - better backups - better recovery - or stronger production discipline In many cases, it just makes the original weaknesses harder to see. That is why I think one good VM can be the more reliable choice in early SaaS. Not because it has more redundancy. But because it makes the real weaknesses visible sooner, and gives the team a chance to fix them before those weaknesses get hidden under platform layers. The less glamorous truth is that a clean environment, clear ownership, and safer release habits do more for early reliability than a lot of “serious” architecture ever will. ## The economics matter too This is where the blog gets intentionally contrarian. A lot of teams overpay for infrastructure not because they need more compute, but because they add more categories of infrastructure than their product currently benefits from. That can mean: - multiple always-on environments - premium managed layers before the workload is stable - orchestration before the team can operate it honestly - extra networking complexity before real private boundaries are needed - and duplicate services that exist mainly to create emotional comfort A single VM is often the better economic choice because it forces clearer thinking: - what actually needs to run, - what actually needs isolation, - what actually needs high availability now, - and what can still stay simple without increasing unacceptable risk. That does not only protect spend. It protects attention. And for an early SaaS team, attention is usually the scarcer resource. ## Simplicity is not anti-growth This is the objection I would expect. “If we stay on one VM too long, are we not just postponing the real architecture work?” Sometimes, yes. But postponing unnecessary complexity is not failure. It is often good judgment. The real mistake is not simplicity. The real mistake is staying simple **after the evidence changes**. If the product reaches the point where: - one server is clearly the bottleneck - environments need stronger separation - one workload is hurting another - uptime expectations require stronger traffic distribution - or the team truly needs a cluster model then the answer changes. But the answer should change because the workload changed, not because the startup wants to look more advanced. That is the distinction I care about most. ## What This Means for You If you are building an early SaaS product right now, I would ask a simple question: **Are you underbuilt, or just under-disciplined?** Those are very different problems. If your current setup is failing because one VM is truly the wrong boundary, that is useful evidence. Act on it. But if the real problems are: - messy releases - weak staging discipline - unclear secrets handling - no recovery confidence - or a server that is simply mis-sized then a fancier stack is probably not your first fix. For a lot of teams, the better move is still: - one well-run [Linux VM](/products/linux-vm) - a real staging boundary when it becomes necessary - clearer production access rules - backups that are actually usable - and infrastructure upgrades that happen one honest bottleneck at a time That is also why I think topics like [Choosing the Right VM Size](/learn/guides/choosing-right-vm-size), [Single-Server vs Multi-Server Architecture](/learn/guides/single-server-vs-multi-server-architecture), and [SaaS Infrastructure Cost Breakdown](/learn/guides/saas-infrastructure-cost-breakdown) matter so much. They look less advanced than Kubernetes debates, but for early SaaS they are often much more important. One good VM is not a rejection of growth. It is a refusal to pay the complexity tax before the business actually owes it. --- ### What We Learned from Teams Migrating Off Overcomplicated Setups URL: https://rafftechnologies.com/blog/what-we-learned-from-teams-migrating-off-overcomplicated-setups Published: 2026-04-19T00:00:00.000Z Description: What We Learned from Teams Migrating Off Overcomplicated Setups ## The problem was usually not scale A surprising number of teams do not migrate because they outgrew simple infrastructure. They migrate because they outgrew **complicated infrastructure that was solving the wrong problem**. That is one of the clearest patterns we keep seeing. A team comes in expecting the story to be about scale, performance, or some advanced architecture requirement. But when you look closely, the issue is often something else: too many layers, too many moving parts, too many decisions made for a future version of the company that never actually arrived. At Raff Technologies, that has changed the way I think about infrastructure maturity. A lot of smaller teams are not struggling because they stayed too simple. They are struggling because they became complex before complexity was economically or operationally justified. The most interesting part is that these setups often look impressive on paper. Multiple services. Multiple environments. Managed layers everywhere. Extra networking. Extra deployment steps. More dashboards. More “platform.” But the daily experience behind that architecture is usually less impressive: slower iteration, higher fixed cost, weaker clarity, and a team that no longer feels sure which parts of the system are actually necessary. That is why I think overcomplicated setups are one of the most expensive forms of startup infrastructure waste. Not because complexity is always bad. Because complexity is expensive when it arrives before the business has earned it. ## Most teams were not overpaying for compute This is the first thing that stands out. When people talk about cloud waste, they often imagine oversized servers, unused storage, or expensive managed services. Those absolutely matter. But in a lot of migrations, the bigger issue is not a single bad line item. It is the cost of a whole system that became harder to reason about. The team is paying for: - more environments than they really use, - more services than they can explain clearly, - more deployment steps than they can trust, - and more architecture than their product actually needs. That is a different kind of overpayment. It shows up in money, yes. But it also shows up in time, release confidence, and the number of operational questions that start with “Wait, why do we even have this?” That is where overcomplication becomes dangerous. It does not only raise the bill. It makes the system feel heavier than the stage of the company. And once that happens, every future infrastructure decision gets harder. ## The setups were often designed for hypothetical scale This is probably the most common pattern. A team builds for what they think a serious company should look like: - multiple layers of separation, - more managed services than they can operationally justify, - orchestration before orchestration is necessary, - duplicated environments before release discipline exists, - or service boundaries that make the diagram cleaner but the workflow slower. The intention is usually good. Nobody is trying to waste money on purpose. They are trying to avoid future pain. But in practice, that future-proofing often creates present-day drag: - longer deployment paths - harder debugging - weaker cost visibility - more idle infrastructure - and a system that the founding team no longer fully understands end to end That is the point where “planning ahead” turns into operational debt. I think this is one of the biggest traps in cloud infrastructure. Teams assume the responsible thing is to build for scale before scale exists. Sometimes that is right. But much more often, the responsible thing is to build for **clarity**, then scale in steps once the bottleneck is real. ## The expensive part was usually duplicated confidence One of the clearest patterns is environment sprawl. A team has: - production, - staging, - preview infrastructure, - extra internal testing environments, - duplicate service layers, - and sometimes multiple versions of the same workflow just because no one wants to break the original one. On paper, this looks like maturity. In practice, it is often duplicated uncertainty. The team is not paying for reliability. It is paying for several slightly different versions of the same risk. And because those environments drift over time, the extra infrastructure does not always produce extra confidence. It just produces extra overhead. That is why I think environment duplication is often misunderstood. More environments are not automatically safer. They are only safer when the release process, ownership, and purpose of each environment are clear. Otherwise, the startup is paying to maintain infrastructure that mostly exists to reassure the team emotionally, not to reduce a real operational risk. ## Managed services were often chosen too early This is another recurring theme. Managed services can absolutely be the right choice. They are often the right choice. But we also keep seeing teams that adopted managed layers before the workload was stable enough to justify the premium, or before the team even knew which part of the stack needed abstraction and which part just needed a better workflow. The result is usually one of these: - the service is convenient, but overbuilt for the actual workload - the service cost multiplies across environments faster than expected - the pricing model becomes harder to reason about than the workload itself - or the team is still doing workaround engineering on top of a product that was supposed to reduce operational effort That is the part people miss. A managed product is not expensive only when the monthly bill is high. It is expensive when the team pays a premium **and still carries awkwardness**. That is why managed services are not automatically the wrong decision, but they are also not automatically the mature decision. The mature decision is the one that matches the workload and the team’s actual operating reality. ## Complexity was often hiding weak fundamentals This is the most uncomfortable pattern, but probably the most important one. A lot of overcomplicated setups were not overcomplicated because the workload truly demanded it. They were overcomplicated because the basics underneath were still weak. Instead of fixing: - unsafe release workflows, - weak staging discipline, - poor secret handling, - unclear access control, - or fuzzy recovery planning, the team added more layers. This creates a strange effect. The system looks more advanced, but the core risks are still there. In some cases, they get harder to see because the architecture is now large enough to distract from them. I think this is one of the reasons simpler setups often feel so much better after migration. It is not only that the bill becomes easier to justify. It is that the real problems become visible again. And once the real problems are visible, the team can fix the right things in the right order. ## The teams that benefited most were not the smallest This is worth saying clearly. This is not just a story about tiny startups that should have stayed on one VM forever. Some of the strongest cases for simplification come from teams that were already real: - they had customers, - they had traffic, - they had production workflows, - and they had reasons to care about reliability. But they were still carrying infrastructure designed for a larger or more operationally mature version of themselves. That is why this topic matters. Simplification is not immaturity. Sometimes simplification is the most mature move a team can make. It means the company is finally willing to ask: - what is actually serving the product, - what is just serving our anxiety, - and what are we maintaining because it is useful versus because it once sounded right? Those are very different categories. ## What usually improved after migration The most immediate improvement was not always lower cost, even though cost often improved. The first big improvement was usually **clarity**. The team understood: - where the application actually ran, - what needed to stay private, - which environment did what, - where the bottleneck really lived, - and which services were truly essential. After that, other gains usually followed: - simpler deployment paths - easier debugging - fewer duplicate systems - better predictability in cost - and stronger confidence when making the next infrastructure decision That sequence matters. Cost reduction is nice. Operational confidence is better. Because once a team gets operational confidence back, it stops making infrastructure decisions from a place of fear. ## What This Means for You If your current setup feels heavier than your company stage, I would not start by asking how to optimize the bill. I would start by asking a more direct question: **What are we paying for that no longer creates confidence, speed, or control?** That usually leads to better answers. Look for: - environments that exist without a clear purpose - managed products that still require too many workarounds - service boundaries that make the system harder, not safer - duplicated infrastructure that adds cost but not clarity - and architecture choices made for a hypothetical future instead of a current bottleneck If you find those patterns, the answer may not be “scale harder.” It may be “simplify honestly.” For a lot of teams, the healthier progression is still: - start with clear foundations, - size for the workload you actually have, - keep environments intentional, - separate what truly needs separation, - and only add heavier architecture when the evidence is there. That is one reason the practical guides around [Choosing the Right VM Size](/learn/guides/choosing-right-vm-size), [Single-Server vs Multi-Server Architecture](/learn/guides/single-server-vs-multi-server-architecture), and [SaaS Infrastructure Cost Breakdown](/learn/guides/saas-infrastructure-cost-breakdown) matter so much. They are not “basic” topics. They are often the real decisions underneath infrastructure clarity. The teams that migrate off overcomplicated setups are usually not moving backward. They are moving from infrastructure that looks mature to infrastructure that is actually useful. And those are not always the same thing. --- ### Why Managed Services Are Not Always the Cheapest Decision URL: https://rafftechnologies.com/blog/why-managed-services-are-not-always-the-cheapest-decision Published: 2026-04-18T00:00:00.000Z Description: Why Managed Services Are Not Always the Cheapest Decision ## The cheapest infrastructure choice is often not the one with the lowest monthly price Managed services are not always the cheapest decision. They are often the easiest decision to justify at the beginning. The setup is faster, the operational burden looks lower, and the product page makes the trade-off feel obvious. For a small team, that can be exactly the right choice. But after a certain point, I think many teams stop comparing **service price** and start discovering **workflow price**. At Raff Technologies, we work close to the kinds of infrastructure decisions where this trade-off becomes visible. A managed product can reduce effort in the right environment. But it can also introduce a different cost profile: higher recurring spend, less control over behavior, more dependence on provider limits, and workflow decisions shaped by the service rather than by the workload itself. That is why I do not think the real question is “managed or self-managed?” The better question is: **what does this decision cost once your actual workflow, data shape, and operational habits are included?** ## The first mistake is comparing list price to server price This is the easiest trap to fall into. A team compares one managed database plan, one managed cache tier, or one managed platform product against the monthly cost of a VM. On paper, the VM looks cheaper. Then the conclusion comes quickly: self-managed is the bargain option. That comparison is incomplete. A managed service includes more than raw compute. It usually includes some mix of lifecycle management, backups, upgrades, built-in availability features, support expectations, or simplified operations. If you ignore those pieces, the comparison becomes unfair in one direction. But the reverse mistake is just as common. Some teams see a managed service as automatically cheaper because it reduces administration. That is also incomplete. A service can remove certain operational tasks while introducing new costs through pricing tiers, storage expansion, bandwidth rules, limited configurability, or an environment shape that no longer matches how the application actually behaves. So the honest comparison is not: **managed service price vs VM price** It is: **managed workflow vs self-managed workflow** That is a much harder comparison, but it is the only one that matters. ## Managed services are usually cheaper at the moment of adoption This is the part that makes the topic tricky. For many early workloads, managed services really are the cheaper decision in practice. Not because the monthly bill is lower, but because they save time at the exact stage when time matters more than optimization. If your team is small, your infrastructure knowledge is limited, and the workload is still changing every week, then paying more for simplicity can be the correct financial decision. A managed service can reduce setup friction, shorten time to production, and remove a class of mistakes your team is not ready to own yet. That is why I do not think the right message is “managed services are overpriced.” That is too shallow. The better message is: managed services are often cheaper **early**, but not always cheaper **over time**. The point where that changes depends on the workload. ## Where the cost starts to turn In my view, the cost balance starts shifting when one of four things happens. ### 1. The workload becomes predictable Managed services make a lot of sense when the environment is changing quickly. Once usage becomes stable, recurring managed premiums are easier to notice. A stable internal database, a predictable application stack, or a long-running service with known behavior is a very different financial case from an uncertain MVP. The more stable the workload becomes, the easier it is to ask whether the team is still paying extra for flexibility it no longer uses. ### 2. The team needs more control than the product shape allows This is where managed products become expensive in a less obvious way. Sometimes the issue is not the invoice. It is the fact that the service no longer fits the workflow: - limits are too rigid - configuration is too narrow - networking assumptions are awkward - scaling steps are coarse - operational visibility is weaker than expected Now the team is paying managed pricing while still doing workaround engineering. That is usually the moment when the “cheaper” story starts breaking. ### 3. The service multiplies across environments A single managed service can feel reasonable. Production plus staging plus preview plus regional duplication can feel very different. This is one of the least discussed cost multipliers in startup infrastructure. Teams often choose a managed product because one environment feels easy to justify. Later, the architecture becomes more responsible, which usually means more copies, more boundaries, and more supporting services. The managed convenience stays the same. The price shape does not. ### 4. The workload is simple, but the pricing is not This is my least favorite version of the problem. A team ends up running a straightforward workload on a service that has become financially complicated. The billing logic becomes harder to explain than the application itself. At that point, the service may still be operationally useful, but it is no longer honestly “simple.” That matters because pricing complexity is also workflow complexity. ## The hidden cost is often not infrastructure — it is fit A managed service becomes expensive fastest when it is a poor fit. That poor fit can show up as: - workarounds the team should not need - duplicated tooling around the service - awkward deployment steps - missing access patterns - or a mismatch between the application’s needs and the provider’s pricing logic This is why I do not trust generic advice like “always use managed databases” or “always self-host once you scale.” The right answer depends on what the service is actually doing for your team. A managed service is worth its premium when it removes real burden. It is not worth its premium when it removes one burden and creates three smaller ones that never make it onto the pricing page. ## Control has a cost too This is the part self-managed advocates often understate. Running your own service on a VM is not free just because the VM price is lower. You now own: - setup - patching - upgrades - recovery - monitoring - and the mistakes that come with each of those That means the right self-managed argument is never “it’s cheaper because the server costs less.” The right argument is: “it is cheaper **for this team and this workload** because the control we gain is worth more than the operational burden we take on.” That is a much more honest standard. ## What I would check before choosing managed vs self-managed If I were evaluating this the Aybars way, I would ask: ### Is the workload still changing fast? If yes, managed often keeps the team moving. ### Is the environment now stable and repetitive? If yes, self-managed becomes more worth testing seriously. ### Does the service fit the workflow cleanly? If not, the premium may no longer be justified. ### Are we paying for convenience we still use, or convenience we used six months ago? This is one of the best questions a growing team can ask. ### Can we operate the self-managed version responsibly? If not, the lower price is a trap, not a saving. That last one matters most. A self-managed stack that is cheaper but fragile is not really cheaper. ## What This Means for You If your team is trying to decide between managed and self-managed infrastructure, do not start with the sticker price. Start with the workload. Ask: - how stable it is - how much control you actually need - how many environments will carry the same cost model - and whether the service is reducing real effort or just delaying a decision For some teams, a managed service will absolutely be the right call. For others, the lower-friction choice at month one becomes the wrong economic choice by month twelve. The important thing is to evaluate the full shape of the decision, not just the line item. That is also why this topic connects naturally to the kinds of guides Raff already publishes around [Choosing the Right VM Size](/learn/guides/choosing-right-vm-size), [Single-Server vs Multi-Server Architecture](/learn/guides/single-server-vs-multi-server-architecture), and [SaaS Infrastructure Cost Breakdown](/learn/guides/saas-infrastructure-cost-breakdown). The cheapest choice is rarely the most obvious one. It is the one that fits the workload, the team, and the stage of the company at the same time. Managed services can be the right decision. They are just not automatically the cheapest one. --- ### Why We Think Pricing Simplicity Is a Product Feature URL: https://rafftechnologies.com/blog/why-pricing-simplicity-is-a-product-feature Published: 2026-04-18T00:00:00.000Z Description: Why We Think Pricing Simplicity Is a Product Feature ## Pricing changes product behavior more than most companies admit We think pricing simplicity is a product feature because pricing is one of the first ways a user experiences your platform. Not the landing page. Not the dashboard. Not the provisioning speed. The bill. Or more specifically: the mental model behind the bill. At Raff Technologies, we have written recently about transparent pricing, unmetered bandwidth, hourly flexibility, and why we moved beyond a pure pay-as-you-go model toward something simpler. Those posts were not separate opinions about billing. They were really the same argument seen from different angles: pricing shapes user behavior, and the wrong pricing model can make a good product feel stressful to use. That matters more in cloud than in most software categories. A confusing interface is annoying. A confusing invoice changes how people build. When pricing is noisy, layered, or hard to predict, teams start designing around cost anxiety instead of product needs. They test less freely. They delay experimentation. They become cautious in the wrong places. Sometimes they over-engineer early just to avoid a future billing surprise. Sometimes they under-use the platform they are already paying for because they no longer trust what “one more workload” might actually cost. That is why I do not see pricing as a finance-only topic. I see it as product design. ## A product feature is anything that changes how confidently people use the platform I think this is where cloud companies sometimes get the framing wrong. They treat pricing as something that sits outside the product, like a commercial wrapper added at the end. Build the infrastructure, launch the control panel, define the SKUs, then let pricing explain the rest. But from the customer side, that division does not really exist. If a team cannot predict what a workload will cost, that uncertainty becomes part of the product experience. If bandwidth overages make a team hesitate before shipping or scaling, that hesitation becomes part of the product experience. If billing rules are harder to understand than the infrastructure itself, that confusion becomes part of the product experience. So for me, the question is not: “Is our pricing page clear enough?” The better question is: “Does our pricing model help people use the platform the way they actually want to use it?” That is a product question. ## Complicated pricing creates the wrong kind of discipline One of the most common defenses of cloud pricing complexity is that it teaches customers discipline. I understand the logic. If every resource has a narrow billing rule, then maybe teams will architect more carefully, clean up faster, and avoid waste. Sometimes that is true. But I think the more common outcome is worse. What complicated pricing often creates is not healthy discipline. It creates defensive behavior. A team avoids a useful staging environment because they are worried it will quietly expand the monthly bill. A developer delays testing a heavier workflow because they are not sure how usage is being counted. A founder becomes more focused on invoice avoidance than deployment speed. A small company starts making infrastructure choices based on billing fear instead of operational fit. That is not discipline. That is hesitation. And hesitation is expensive in a growing company. A lot of early cloud waste does not come from people being careless. It comes from people being forced to make decisions inside pricing systems that were designed for provider optimization first and customer clarity second. That is exactly why our recent post on unmetered bandwidth matters to me. The point was not just that “unmetered” sounds attractive on a product page. The deeper point was that bandwidth overage billing creates the wrong behavior in the teams we want to help: less confidence, more caution, and more architecture shaped by invoice anxiety than by application logic. That is a product problem, not just a pricing one. ## Simplicity is not the same as “cheap” This part matters. When I say pricing simplicity is a product feature, I do **not** mean the product should always be the cheapest option on paper. Cheap is a number. Simple is a user experience. A product can be low-cost and still feel risky if the billing logic is unpredictable. A product can be more expensive and still feel easier to trust if the pricing model is clear, stable, and aligned with real usage. That is why I think pricing simplicity should be judged by questions like these: - Can a customer estimate cost before launching? - Can a team understand what changed when usage changes? - Can a founder explain the bill to the rest of the company? - Can a developer spin something up without wondering if one mistake will trigger a hidden penalty? - Can growth happen without every technical decision turning into a billing puzzle? If the answer to those questions is yes, pricing is doing product work. If the answer is no, pricing is adding friction no matter how competitive the headline rate looks. ## The best pricing models reduce cognitive overhead This is the real product lens. Good infrastructure products do not only reduce technical effort. They reduce **cognitive effort**. That is one reason simple provisioning matters. It is one reason clear VM sizing matters. It is one reason sane defaults matter. And it is one reason pricing matters. A team already has enough to think about: - architecture, - deployment, - performance, - security, - environments, - backups, - observability, - customer expectations. They should not also need a second mental model just to understand what the platform is going to charge them for acting normally. If billing logic becomes a second architecture problem, the product is creating unnecessary work. That is why I think pricing simplicity deserves to be discussed alongside UX, reliability, and documentation. It affects user confidence in exactly the same way those things do. ## This is especially true for startups and small teams Large enterprises can survive bad pricing experiences longer than startups can. They have procurement layers, finance teams, and sometimes enough infrastructure experience to normalize the pain. Smaller teams do not. For a startup, pricing clarity affects real operating behavior much faster: - how many environments they keep alive, - how safely they test, - how confidently they scale, - whether they adopt a workflow now or postpone it, - whether infrastructure feels like leverage or like a source of hesitation. That is why I keep coming back to the same principle in Raff’s writing: the product should help smaller teams move with confidence, not force them to think like billing analysts before they can behave like builders. Raff’s public posts on simple cloud power, transparent pricing, and cloud cost comparisons all point in that direction. They are really saying the same thing: clarity is useful, and useful products reduce uncertainty where uncertainty slows people down. ## Why this matters to how we think about Raff This is one of the reasons pricing decisions at Raff are never just spreadsheet decisions. They are workflow decisions. We think about questions like: - Will this make customers more confident or more cautious? - Does this pricing rule match how real teams use infrastructure? - Are we charging in a way that makes the product easier to adopt, or harder to trust? - Are we creating incentives for healthier usage, or just more confusing bills? That is also why recent Raff writing can talk, without contradiction, about hourly flexibility, transparent pricing, unmetered bandwidth, and a simpler subscription model. Those are not random billing experiments. They are different expressions of the same product philosophy: remove unnecessary billing anxiety and make the platform easier to understand. I think more cloud companies should say this more directly: **pricing is part of the interface.** It may live on a different page. It may be owned by a different team internally. But to the customer, it is still part of the product. ## What this means for you If you are building or choosing infrastructure, I think the right pricing question is not only: “How much does this cost?” It is also: “What kind of behavior does this pricing model push me toward?” Does it make you more confident to test? Does it help you understand growth? Does it let you explain spend clearly? Does it reduce fear around success? Does it make the platform feel easier to trust? If yes, that pricing model is doing real product work. And if it is not, then even a technically strong platform can feel harder to use than it should. That is why we think pricing simplicity is a product feature. Not because pricing is branding. Not because “simple” sounds good in a headline. But because the way a platform charges you changes the way you behave on it. And in cloud, behavior is everything. --- ### Most Teams Add Caching in the Wrong Order URL: https://rafftechnologies.com/blog/most-teams-add-caching-in-the-wrong-order Published: 2026-04-12T00:00:00.000Z Description: Most Teams Add Caching in the Wrong Order If your cloud app feels slow, do not start with Redis. Most teams do. They hear the word “cache,” think about database reads, and jump straight to the most technical-looking option in the stack. In practice, that is often the wrong first move. At Raff Technologies, we think about caching as a delivery and complexity decision before we think about it as a tooling decision. The real question is not “Which cache should we add?” It is “Where is repeated work happening, and what is the simplest layer that can eliminate it?” Caching for cloud apps is the practice of storing reusable responses, files, or computed results closer to where requests happen so your infrastructure does less repeated work. That sounds simple, but the confusion starts when four very different layers get lumped into one idea: browser cache, CDN cache, reverse proxy cache, and Redis. They are not interchangeable. They solve different problems, create different trade-offs, and belong at different stages of growth. What surprises me is how often smaller teams choose the most operationally expensive option first. They add Redis before fixing static asset headers. They talk about cache invalidation before checking whether their browser caching is doing anything useful at all. They introduce application-level complexity when their actual bottleneck is that every user keeps downloading the same files or forcing the origin to regenerate the same HTTP response. That is the wrong order. ## The Problem Is Not a Lack of Caches The problem is that many teams do not separate delivery caching from application caching. Delivery caching is everything that helps reusable content get served faster before your application has to do work again. That includes the browser, the edge, and the reverse proxy. Application caching is what happens when the request has already reached your app and you want to avoid repeating expensive logic, queries, or computation. Redis lives here. That distinction matters because the closer a cache is to the user, the less work your stack has to do overall. It also usually means less infrastructure to manage. In other words, the earlier you can stop repeated work in the request path, the better the outcome tends to be for a small team. This is why I think many teams start in the wrong place. They treat Redis like the default answer because it looks serious and scalable. But “serious” is not the same as correct. A better caching strategy starts with the simplest layer that can solve the problem safely. ## Browser Caching Is the Cheapest Win Most Teams Ignore If your app serves JavaScript bundles, CSS files, fonts, images, icons, or versioned frontend assets, browser caching is usually the first place to look. I like browser caching because it removes repeated work without adding a new service, a new dependency, or a new failure mode. You are not changing your architecture dramatically. You are simply telling the user’s browser not to keep fetching the same thing when nothing has changed. That sounds almost too obvious, which is probably why teams skip it. But obvious wins are often the highest-leverage wins. When browser caching is configured well, repeat visits feel faster, pages become lighter on the origin, and your infrastructure stops paying for waste it created itself. That matters even more for small products where every layer of extra complexity costs real engineering attention. This is also where I think teams confuse “performance work” with “infrastructure expansion.” Sometimes performance is not about adding something. Sometimes it is about removing unnecessary repetition. Browser caching does exactly that. If your frontend assets are stable and versioned properly, there is a strong chance this should be your first caching improvement, not your fourth. ## CDN Caching Matters When Distance and Repetition Start Hurting The next layer I would think about is the CDN. A CDN becomes valuable when you have public content that many users request repeatedly and you no longer want your origin doing the same job over and over. It helps when traffic is geographically spread out, when static assets are getting hit constantly, or when you want an additional layer between public traffic and your infrastructure. What I like about CDN caching is that it solves two practical business problems at the same time. First, it improves delivery for users who are physically farther away from your origin. Second, it reduces repeated traffic pressure on the origin itself. That second point matters more than many teams realize. Better caching is not only about shaving milliseconds. It is also about reducing avoidable load so your application servers do less useless work. Once you look at caching this way, the decision becomes clearer. A CDN is not just a speed feature. It is an origin-efficiency feature. This is especially relevant when your application serves a lot of public assets, image-heavy pages, documentation, landing pages, downloads, or static frontend bundles. In that situation, asking your origin to serve every request directly is usually a poor use of compute. At that point, I would rather see a team improve browser and CDN behavior than rush into application-level caching they may not yet need. ## Reverse Proxy Caching Is the Layer Many Teams Underestimate This is where the conversation gets more interesting. Reverse proxy caching sits in a useful middle position. It is not as globally distributed as a CDN, and it is not as application-specific as Redis. It is often the right answer when repeated HTTP work is still happening at the origin boundary and you want to stop your app from regenerating the same responses again and again. That can apply to semi-static pages, anonymous traffic patterns, public API responses with short freshness windows, or content that changes occasionally but not continuously. I think teams underestimate reverse proxy caching because they usually meet reverse proxies first through TLS termination, compression, routing, or security. Caching feels like a secondary feature. In reality, it can be one of the most practical ones. If your app mostly speaks HTTP and your repeated work is still in the request-response layer, reverse proxy caching often gives you the cleanest next step. It reduces application pressure without immediately forcing you into a dedicated in-memory cache tier with its own operational logic. For a lot of small teams running on a [Linux VM](/products/linux-vm), this is a smarter progression. Start with good asset caching. Add edge delivery where it matters. Then let the reverse proxy handle repeated shared responses before you move deeper into application caching. That is a much healthier order than jumping straight to Redis because it feels more advanced. ## Redis Is Powerful, but It Should Earn Its Complexity To be clear, I am not against Redis. Redis is excellent when the repeated work truly belongs inside the application path. If you are caching expensive query results, session state, computed fragments, queue-related state, rate-limiting counters, or short-lived objects your application needs constantly, Redis can be exactly the right choice. But this is the point: Redis should solve an application problem, not a delivery problem. If your real issue is that users keep downloading the same static assets, Redis is the wrong first answer. If your real issue is that your origin keeps serving identical public files, Redis is the wrong first answer. If your real issue is that repeated anonymous HTTP responses are hitting the app unnecessarily, Redis may still be too deep in the stack. The deeper you go, the more complexity you introduce. Redis brings real operational questions with it: How do you invalidate stale values? What is the TTL strategy? What happens on a miss? What happens when stale data is acceptable versus dangerous? What breaks if Redis is slow or unavailable? What belongs in Redis and what belongs in the database? Those are good questions when the payoff is real. They are not good questions to volunteer early if a simpler layer could have solved the problem with less risk. This is where I think teams should be more disciplined. Redis is powerful, but power is not the same thing as priority. ## The Better Order for Small Teams If I had to reduce our view into one rule, it would be this: Start with the cache layer closest to the user that can solve the problem safely. For many teams, the better order looks like this: 1. Browser caching for static, versioned assets 2. CDN caching for public delivery and origin offload 3. Reverse proxy caching for repeated shared HTTP responses 4. Redis for repeated application or database work Not every workload follows that exact sequence. Some applications genuinely need Redis early because their bottleneck is already deep in the application layer. But most small cloud apps do not need to start there. Most need to get the delivery side right first. I prefer this order because it keeps architecture proportional to the actual problem. It delays avoidable complexity, reduces wasted compute, and gives teams a much clearer model for deciding what belongs at the edge, what belongs at the origin boundary, and what belongs inside the app. That is not just a technical advantage. It is an operational one. Small teams do better when performance improvements make the system simpler to reason about, not harder. ## What This Means for You If you are reviewing performance on your cloud app right now, I would avoid the question “Should we add Redis?” until you answer a more important one: Where is the repeated work happening? If the waste is static asset delivery, fix browser caching first. If the waste is public content being fetched from the origin too often, add a CDN strategy. If the waste is repeated HTTP responses at the origin boundary, improve reverse proxy caching. If the waste is repeated application or database work, then Redis starts to make sense. That is the order I would trust for most small teams. If you are building on Raff, that usually means starting with a simple [Linux VM deployment](/products/linux-vm), keeping an eye on cost and usage through [Raff pricing](/pricing), using [Object Storage](/products/object-storage) when static files and assets should move off the main server, and considering [Load Balancers](/products/load-balancers) when traffic patterns become broader than a single-node setup should handle. The key point is this: caching should remove repeated work with the least new complexity possible. The teams that get this right do not necessarily use more caching tools. They use the right cache layer at the right time. And in my opinion, that is how cloud performance decisions should be made. --- ### Why Virtual Machines Still Matter for Beginners in 2026 URL: https://rafftechnologies.com/blog/what-is-a-virtual-machine-a-simple-guide-for-beginners-2025-edition Published: 2025-05-30T00:00:00.000Z Description: Why Virtual Machines Still Matter for Beginners in 2026 ## Virtual Machines Still Matter More Than People Think A lot of beginners first hear the term “virtual machine” and assume it belongs to a more technical world than their own. It sounds like something for infrastructure teams, cybersecurity labs, or cloud engineers working at large companies. But in reality, virtual machines are still one of the most practical tools a beginner can learn in 2026. Not because everyone suddenly needs to become a systems engineer. Because VMs solve a very simple problem that shows up surprisingly early: you need a clean, flexible computer environment that is not trapped inside your personal machine. ## The real question is not “What is a VM?” Yes, technically, a virtual machine is a software-based computer that runs on top of physical infrastructure through virtualization. That definition is correct, but it is not the most useful way to understand why VMs matter. The better question is: **What problem does a virtual machine solve for a beginner?** That is where things become much clearer. A VM gives you a separate environment where you can install tools, test code, try operating systems, run applications, and make mistakes without turning your main machine into a mess. That is the practical value. And that value is much more relevant now than it used to be, because modern developer and learning workflows are heavier than many beginners expect. ## Your laptop is not always the best place to learn everything This is one of the biggest mindset shifts people go through. At first, it feels logical to do everything on your personal computer: - install every framework there - try every package there - test every script there - keep every experiment there That works for a while. Then the machine starts collecting too much: - conflicting dependencies - old packages - broken configurations - half-finished experiments - tools you no longer need - project setups that interfere with one another That is when the local machine stops feeling like a clean starting point and starts feeling like a pile of history. A virtual machine helps because it gives you separation. Instead of turning your laptop into the home of every experiment, you create a dedicated environment that belongs to a specific purpose. That one change makes learning and building much calmer. ## A VM is basically controlled freedom This is the simplest way I explain it to beginners. A virtual machine gives you freedom with boundaries. You can: - install a different operating system - break something and rebuild it - test software without risking your main machine - run development tools in a dedicated environment - learn Linux even if your laptop runs Windows or macOS - experiment with cloud workflows earlier than you otherwise could That is why VMs are such a strong beginner tool. They let you explore without putting every consequence on the machine you depend on every day. That freedom matters because beginners do not only need “access to tools.” They need safe space to learn what those tools actually do. ## Why VMs are still relevant in 2026 Some people assume VMs matter less now because containers, cloud platforms, and AI tools get more attention. I do not see it that way. In fact, I think VMs are still highly relevant because the environment problem has not disappeared. It has actually become more important. Modern workflows involve more moving parts: - code editors - package managers - databases - Docker or container tools - local servers - testing environments - automation scripts - AI-generated code that still needs somewhere clean to run That is a lot for one personal machine to carry well. A VM gives those workflows a cleaner home. And if that VM lives in the cloud, the benefits get even bigger: - you can access it from anywhere - you are not limited by your laptop’s hardware - you can resize later - you can rebuild when needed - you start learning real infrastructure habits earlier That is why I think VMs are still foundational, not outdated. ## Beginners usually need VMs for practical reasons, not abstract ones Very few people wake up and say, “Today I want virtualization.” They usually arrive at VMs through a more practical problem. ### 1. Learning Linux safely This is one of the strongest starting points. If you want to learn Linux, a VM is one of the best ways to do it. You can work in a real Linux environment without replacing your main operating system. That makes it easier to explore the terminal, package installation, file permissions, SSH, and server basics without putting your everyday machine at risk. ### 2. Testing code without polluting your laptop A VM is a clean space for trying frameworks, packages, and development tools that you do not want permanently installed on your main machine. That matters much more than people think, especially once you start moving across multiple projects. ### 3. Running workloads your machine is not ideal for Some people simply need more RAM, more CPU headroom, or a more dedicated environment than their laptop gives them. A cloud VM helps because the compute does not depend entirely on local hardware. ### 4. Learning cloud and server basics properly If you want to understand deployment, SSH, server setup, networking, backups, or infrastructure more seriously, a VM is one of the best entry points. It teaches the habits that sit underneath a lot of modern cloud work. ### 5. Building portfolio projects or internal tools A VM gives your project a stable home outside your personal machine. That matters when you want something to stay online, be accessible remotely, or feel more like a real environment than a local experiment. ## The hidden benefit is reproducibility This is something beginners usually appreciate later. A good environment is not only one that works once. It is one that you can understand, rebuild, and explain. Virtual machines help with that because they encourage a cleaner mental model: - this machine is for this project - this OS is for this purpose - these tools live here - this setup can be repeated That is a big improvement over “everything lives somewhere on my laptop and hopefully still works.” The more serious your learning becomes, the more valuable reproducibility becomes too. ## Cloud VMs make this more accessible than it used to be Years ago, working with VMs often felt heavier for beginners. Now it is much more approachable. On Raff’s current Linux VM pages, the public positioning is already much clearer and more beginner-friendly than many older VM products used to be: - deployment in under 60 seconds - full root access and SSH - 9 Linux distributions available - snapshots and backups available - NVMe-backed infrastructure - a 14-day money-back guarantee instead of confusing “free tier” wording That matters because beginners do not only need infrastructure. They need infrastructure that feels reachable. If getting started feels too slow, too expensive, or too confusing, most people stop before they actually learn anything useful. This is one reason I think practical cloud VMs are such a strong entry point now. They remove a lot of friction from the first serious step. ## A beginner does not need the biggest cloud platform first I think this is another important point. A lot of people assume that once they want to learn cloud or servers, they should immediately jump into the largest and most complicated platform possible. I do not think that is the best starting point for most beginners. Beginners usually need: - a clean machine - a clear operating system choice - the ability to connect over SSH - enough performance to run their tools - pricing they can still understand - backups or snapshots when they make mistakes That is a much smaller requirement set than a full hyperscaler operating model. That is one reason platforms like Raff make sense in this part of the journey. The goal is not to overwhelm a beginner with every possible cloud service. The goal is to make the first real infrastructure step useful and understandable. ## A VM is often the bridge between learning and building This is why I still think VMs are so important. A virtual machine often becomes the first place where someone stops only reading about infrastructure and starts actually using it. You move from: - watching tutorials - reading docs - installing random tools locally to: - creating an environment - connecting to a server - managing files - configuring services - understanding what runs where - learning how systems behave over time That is a very important transition. It is the bridge between curiosity and actual skill. And for a lot of developers, students, and early builders, that bridge still starts with a VM. ## What This Means for You If you are a beginner, do not think of a virtual machine as an “advanced cloud product.” Think of it as a cleaner workspace. If your laptop is getting messy, if you want to learn Linux, if you want to test things safely, or if you want your project to live outside your personal machine, a VM is still one of the most useful tools you can learn in 2026. At Raff, that is exactly how I think these machines should feel: practical, fast to launch, and useful early. Start with a [Linux VM](/products/linux-vm), use [snapshots and backups](/products/data-protection) when you need a safety net, and add layers like [object storage](/products/object-storage) or [private cloud networks](/products/private-cloud-networks) only when the project starts needing them. That is the better way to grow. Not by making infrastructure feel bigger than it is. By making it useful sooner. --- ### The Best AI Tool in 2026 Still Needs the Right Cloud Environment URL: https://rafftechnologies.com/blog/which-ai-tool-should-developers-use-in-2026 Published: 2025-11-12T00:00:00.000Z Description: The Best AI Tool in 2026 Still Needs the Right Cloud Environment ## The Best AI Tool in 2026 Still Needs the Right Cloud Environment Developers spend a lot of time asking which AI tool is best. ChatGPT, Gemini, open models, coding assistants inside the IDE, agent-style workflows, API-first setups — the market keeps getting better, faster, and more crowded. That is a useful question. But I do not think it is the most important one anymore. The more important question is this: **What kind of environment are you giving that AI tool to work with?** Because the truth is simple: even the best AI assistant does not remove the need for clean infrastructure. It still needs somewhere to generate, test, run, deploy, isolate, store, and ship real work. That is where many teams still underestimate the problem. ## AI tools are getting better, but they do not replace execution environments The first phase of AI for developers was about surprise. People realized these tools could write boilerplate, explain code, generate functions, summarize docs, and accelerate debugging. That was a real shift, and it is still happening. Now we are in a different phase. The tools are no longer the novelty. They are becoming part of the workflow. That changes the question from: - Which model is smartest? - Which tool writes better code? - Which assistant feels faster? to: - Where does this code run? - How do we test it safely? - How do we keep environments isolated? - How do we avoid turning the local machine into a bottleneck? - How do we move from AI-generated output to actual deployment? That is why I think the AI conversation is maturing. The bottleneck is increasingly not only the model. It is the environment around the model. ## A lot of developer workflows still break at the same point This is something I think gets hidden by AI hype. A model can generate code in seconds. That does **not** mean the team can validate, test, deploy, and manage it cleanly in seconds. In fact, AI often increases the need for better infrastructure discipline because it increases output volume. Teams generate more experiments, more scripts, more prototypes, more automation, more side services, more containers, and more deployment attempts. That has consequences. Suddenly the local machine is carrying too much. The dev environment becomes messy. One project interferes with another. Dependencies drift. Reproducibility gets worse. Testing becomes uneven. The gap between “AI wrote this” and “this is production-ready” stays large. That is the point where cloud infrastructure becomes more important, not less. ## The real value is not only AI assistance — it is AI plus clean execution This is the frame I care about most. An AI tool on its own is not the full workflow. It is one layer inside the workflow. The stronger setup looks more like this: - AI helps generate or refine the work - cloud infrastructure gives the work a clean place to run - environments stay isolated - deployment becomes repeatable - storage, networking, and backups stay separate from the developer laptop - the team can move from idea to implementation without polluting the local machine That is why I do not think the “best AI tool” conversation is enough anymore. The more useful comparison is: **AI tool + weak environment** versus **AI tool + clean cloud environment** The second combination wins far more often. ## The wrong mental model is “AI means I need less infrastructure” For some reason, a lot of people still assume AI reduces the importance of infrastructure because the tool itself feels abstract. But that is backwards. AI reduces some effort at the code-generation layer. It does not eliminate the systems layer. If anything, it makes good infrastructure more valuable because teams can move faster only when the surrounding environment can keep up. Think about what modern developers are actually doing with AI now: - generating internal tools - testing API logic - spinning up containers - building automations - writing scripts that touch production services - experimenting with self-hosted tools - creating background workers - deploying staging builds more frequently That is not less infrastructure pressure. That is more. The tool may live in a browser tab or IDE extension, but the consequences of using it well live in the runtime environment. ## This is where local development starts to strain Local machines are still fine for many things. But the more AI gets integrated into daily work, the more developers start using it to create workloads that are better off outside the laptop. That includes: - isolated dev servers - test environments - reproducible Docker-based workflows - background services - scheduled tasks - file-heavy pipelines - automation jobs - self-hosted tools that should not live on personal hardware This is one of the reasons cloud infrastructure matters more in the AI era than some people expected. Not because AI itself needs a VPS to answer prompts. But because developers are using AI to create more things that need a stable place to run. That changes the architecture conversation. ## The best teams are not choosing one tool. They are building a better system Another reason the old “which AI tool wins?” frame is getting weaker is that many good teams are not choosing one winner at all. They are mixing tools. Maybe one assistant is better for brainstorming. Another is better for coding. Another is useful because it is open or self-hostable. Another fits a specific IDE or workflow better. That is fine. The mistake is thinking the model choice alone defines productivity. It does not. The stronger teams are doing something else: they are building a workflow where AI and infrastructure work together. That means: - clean compute - isolated environments - practical storage - sensible networking - repeatable deployment paths - enough flexibility to keep experimenting without chaos This is a much more useful maturity model than obsessing over which assistant won this month’s benchmark argument. ## Why this matters so much to us at Raff This topic is directly relevant to how we think about the platform. We are not trying to compete in the AI model layer. We are trying to build the environment layer that makes modern developer workflows more practical. That is why our stack matters in this conversation: - [Linux VMs](/products/linux-vm) for isolated development and deployment environments - [Windows VMs](/products/windows-vm) where Windows-based workflows matter - [S3-compatible object storage](/products/object-storage) for backups, artifacts, assets, and file-heavy workloads - [private cloud networks](/products/private-cloud-networks) to keep internal traffic cleaner - [data protection](/products/data-protection) when experiments start becoming real workloads - a broader direction toward [Kubernetes](/products/kubernetes) and [Raff Apps](/products/raff-apps) as the platform grows That is the operator perspective I think is missing from generic AI tool posts. The AI assistant is not the whole story. The environment you give it is what determines whether the output becomes useful, reproducible, and scalable. ## The more AI output you generate, the more environment discipline matters This is the part that gets more important every month. If AI helps you produce more code, more prototypes, more scripts, and more automation, then your environment quality becomes a force multiplier or a failure point. A weak setup gives you: - faster mess - more brittle experiments - more local clutter - more deployment inconsistency - more confusion between “prototype” and “real workload” A strong setup gives you: - clean isolation - safer testing - easier collaboration - better reproducibility - a clearer path from experiment to shipped system That difference matters much more than people think. And it is one of the reasons I believe the “tool choice” discussion is gradually becoming secondary to the “workflow quality” discussion. ## So which AI tool should developers use? My honest answer is: use the one that fits your workflow best. But do not stop the decision there. If the tool helps you think better, code faster, document more clearly, or automate more aggressively, that is great. But the real leverage comes when that output can move into a cloud environment that keeps your work organized and repeatable. That is why I think the strongest answer is no longer: “Use ChatGPT.” or “Use Gemini.” or “Use open models.” The stronger answer is: **Use the AI tool that fits your workflow — and pair it with infrastructure that keeps the workflow clean.** That is a much more durable strategy than chasing a single winner. ## What This Means for You If you are evaluating AI tools as a developer or small team, keep using the model comparison as one part of the decision. But do not mistake it for the whole decision. Ask a better second question: - Where will the generated code run? - How will we test it safely? - How will we keep environments isolated? - How will we handle files, artifacts, and backups? - How do we move from AI-assisted output to something stable enough to ship? That is where infrastructure becomes part of the productivity story. At Raff, that is exactly the layer we care about. We are building the cloud environment around the workflow: [cloud servers](/products/linux-vm), [object storage](/products/object-storage), [private networking](/products/private-cloud-networks), and the platform pieces that help teams build faster without turning speed into chaos. Because in 2026, the best AI tool is still not enough on its own. The teams that win are the ones that pair AI with the right environment. --- ### Should You Run Kubernetes on a VPS? A Practical View for Small Teams URL: https://rafftechnologies.com/blog/run-kubernetes-cluster-on-vps-step-by-step Published: 2026-03-12T00:00:00.000Z Description: Should You Run Kubernetes on a VPS? A Practical View for Small Teams ## Kubernetes on a VPS Sounds Simpler Than It Feels Kubernetes on a VPS is one of those ideas that sounds almost perfect the first time you hear it. Lower cost than a managed platform. Full control over the nodes. A real cluster you can shape around your workload. And if you are trying to learn Kubernetes properly, it feels more serious than a local lab and more practical than reading docs in isolation. I understand the appeal. I also understand why so many developers search for step-by-step guides on this topic. But after spending enough time around infrastructure decisions, I think the more useful question is not “Can you run Kubernetes on a VPS?” Of course you can. The more useful question is: **should you?** That is a much better filter for small teams, because Kubernetes is not only a deployment method. It is an operating model. And once you install it on your own VPS infrastructure, the responsibility does not stop at getting the cluster to say `Ready`. ## The real attraction is not Kubernetes itself Most people are not actually attracted to Kubernetes for its own sake. They are attracted to what they hope it will solve: - cleaner deployment workflows - better workload separation - easier scaling - more resilience than a single Docker host - a real path toward modern infrastructure practices - a way to learn orchestration without paying managed-cluster prices too early Those are all valid reasons. That is why this topic keeps coming up. There is a real middle ground between “everything on one VPS with Docker Compose” and “fully managed Kubernetes platform with a long bill and a bigger learning curve.” A self-hosted cluster on virtual machines can absolutely live in that middle ground. But that only works if the team is honest about what Kubernetes adds, not just what it promises. ## Where the tutorials usually stop too early This is the biggest problem with most Kubernetes-on-VPS content. A lot of guides stop at cluster creation. They explain: - control plane - worker nodes - join commands - maybe K3s versus kubeadm - maybe a sample Nginx deployment And then they act as if the hard part is over. It is not. That is the point where the real work starts. A cluster that boots is not automatically a platform you can trust. The moment you want to run anything meaningful, you run into the parts that actually define the experience: - how traffic enters the cluster - how services talk to one another - how storage persists beyond pod lifecycles - how you back up state - how you monitor failures - how you recover when a node disappears - how you handle secrets, certificates, and upgrades - how much operational time the team is willing to spend That is why I do not think “step-by-step” is the strongest frame for this topic anymore. The stronger frame is operational honesty. ## K3s changes the equation, but it does not remove responsibility If you are a small team and still want Kubernetes on VPS, K3s is usually the place I would start thinking first. That is not because kubeadm is bad. It is because K3s is much closer to the shape many VPS-based workloads actually need: lighter, faster to stand up, and better suited to smaller environments where you want real Kubernetes behavior without carrying every bit of upstream complexity from day one. That said, people sometimes hear “lightweight” and translate it into “easy.” That is not the same thing. K3s makes cluster setup more approachable. It does **not** make networking, storage, ingress, upgrade planning, observability, or disaster recovery disappear. It simply gives you a more realistic starting point if your goal is to run Kubernetes without turning a small VPS cluster into a full-time side job. If your main goal is deeper upstream learning, maximum configuration control, or a path closer to standard Kubernetes internals, kubeadm is still valid. But for most teams who are not trying to simulate enterprise platform engineering on day one, K3s is the more practical choice. ## The first serious problem is usually networking A lot of people think the challenge in Kubernetes is “installing Kubernetes.” It usually is not. The first serious challenge is traffic design. You still have to decide: - how public traffic gets in - how internal services communicate - how DNS maps to workloads - how you expose applications safely - which things should never be public in the first place That matters even more on VPS infrastructure, because small teams often start with simpler assumptions and then discover that “simple” public exposure can become messy very fast. This is one reason I still think private network design matters before orchestration excitement. If your cluster nodes are on separate public paths with no clean internal network strategy, you are adding friction to a system that already has enough moving parts. That is why I usually think of Kubernetes on a VPS as a **networking decision** at least as much as a compute decision. At Raff, this is exactly why [private cloud networks](/products/private-cloud-networks) matter so much in the larger platform story. East-west traffic should feel deliberate. Sensitive communication between services should not be an afterthought. If the internal traffic model is weak, Kubernetes does not fix that. It simply gives you a more complex place to experience the weakness. ## Storage is where “stateless dreams” meet reality The next place reality shows up is storage. A lot of small teams start with the mental model that their applications are mostly stateless. Then real workloads appear: - databases - uploads - build artifacts - CMS media - internal tools with local persistence - queues - application data that cannot disappear with a pod restart That is where Kubernetes gets much less theoretical. Persistent storage in Kubernetes is its own layer of design. It is not a footnote. It is one of the biggest reasons small clusters feel more fragile than expected when people rush past the storage conversation. If you are self-hosting on VPS infrastructure, this gets even more important. Your cluster is only as calm as its stateful workloads are recoverable. That is why I think storage planning should come much earlier in the conversation. Before a team gets excited about replicas and ingress rules, it should be able to answer simpler questions: - where does data live? - how does it persist? - how does it get backed up? - what happens if a node dies? - what gets restored first? This is also where platform building blocks around Kubernetes matter more than Kubernetes itself. [Block storage volumes](/products/volumes) and [data protection](/products/data-protection) are not glamorous talking points, but they are exactly the things that separate a demo cluster from a cluster that can survive a bad day. ## A lot of teams should not start with Kubernetes at all This is the part some infrastructure people do not like saying out loud. A surprising number of small teams should not begin with Kubernetes. Not because Kubernetes is bad. Not because it is overhyped. Not because orchestration is not useful. But because the timing is wrong. If you are running: - one application - one internal tool - one API and one database - one staging environment - one project where the main problem is still shipping product then a single well-structured VM is often the better first system. A clean VM setup with good process management, backups, private networking where needed, and disciplined deployment habits is still a very strong operating model. In many cases, it will teach you more useful discipline than rushing into orchestration early. This is one reason Raff continues to treat [Linux VMs](/products/linux-vm) as a foundation, not a transitional product we expect people to outgrow immediately. A lot of teams do not need Kubernetes first. They need infrastructure that is fast to deploy, easy to understand, and flexible enough to evolve when the workload earns more complexity. That is a healthier starting point than adopting Kubernetes just because it feels like the “real” thing. ## So when does Kubernetes on a VPS make sense? I think it makes sense when at least a few of these become true: - you are running multiple services that need cleaner orchestration - you want real pod scheduling and service abstraction - you need a learning environment closer to actual cluster operations - you are willing to own the operating model, not just the installation - your team has enough infrastructure curiosity to debug cluster behavior calmly - you understand that storage, ingress, and recovery are part of the project It also makes sense for teams that are consciously choosing a lower-cost orchestration environment before moving to something more managed later. That is a real use case. A VPS-based cluster can absolutely be a meaningful step in that journey. But it only works well when the team is using Kubernetes to solve a real workload or real learning need — not just to borrow the status of “running Kubernetes.” ## Why we think about this carefully at Raff This topic matters to us for a reason. We have [Kubernetes](/products/kubernetes) on the public roadmap because the demand is real. Teams do want container orchestration. They do want a cleaner path from VMs to more structured workload management. And we think that need deserves a serious platform answer. At the same time, we do not think every team should be pushed there too early. That is an important distinction. A lot of platforms behave as if “more orchestration” is always the next obvious step. We do not see it that way. We think infrastructure should grow in the order that keeps the operating model understandable. That usually starts with: - clear virtual machines - good networking boundaries - practical storage - backups and snapshots - enough flexibility to shape the workload properly Only then does Kubernetes become the right next question. That is why I see our current stack and roadmap as connected. [Linux VMs](/products/linux-vm), [private cloud networks](/products/private-cloud-networks), [block storage volumes](/products/volumes), [data protection](/products/data-protection), and the public Kubernetes direction are not random products. They are part of the same platform sequence. ## What I would tell a small team today If you are a small team thinking about Kubernetes on a VPS, my practical advice is this: ### Start with a clearer question than “How do I install it?” Ask: - What problem am I solving that a single VM cannot solve cleanly? - Do I need orchestration, or do I need better deployment discipline? - Am I willing to own the operational overhead? - Is the team trying to learn, or trying to simplify? Those answers will tell you much more than a cluster-install script ever will. ### If you are mostly learning Use K3s. Keep the cluster small. Do not pretend it is an enterprise platform. Learn ingress, storage, backups, and monitoring properly. ### If you are mostly shipping product Be stricter. A single VM may still be the stronger move. You can go very far with disciplined VM-based infrastructure before Kubernetes becomes necessary. ### If you are between those two states That is where VPS-based Kubernetes can make the most sense. Not as a badge. As a bridge. ## What This Means for You If you are evaluating Kubernetes on VPS infrastructure right now, do not make the decision based only on whether you can install a cluster. Make it based on whether the operating model matches your team. Kubernetes on a VPS is a real option. For the right workload, it can be a cost-effective, flexible, and educational path. But it becomes a good decision only when you are ready for the responsibilities that come with it: ingress, storage, monitoring, upgrades, backups, and recovery. At Raff, that is exactly how we think about the path forward. Start with infrastructure that is easy to understand. Use [Linux VMs](/products/linux-vm) when that is enough. Add [private cloud networks](/products/private-cloud-networks), [block storage volumes](/products/volumes), and [data protection](/products/data-protection) when the workload needs them. Then move toward [Kubernetes](/products/kubernetes) when orchestration becomes the right next layer, not just the most fashionable one. That is the cleaner way to grow. And if you are honest about what your workload really needs, it is usually the cheaper way too. --- ### Why We Shipped Object Storage Before Managed Databases URL: https://rafftechnologies.com/blog/why-we-shipped-object-storage-before-managed-databases Published: 2026-04-05T00:00:00.000Z Description: Why We Shipped Object Storage Before Managed Databases ## Why We Shipped Object Storage Before Managed Databases If you only look at feature checklists, managed databases probably seem like the more obvious thing to ship first. They are easy to market. Everyone understands the pitch. “We run PostgreSQL, MySQL, or Redis for you” is a very clean sentence. For a lot of cloud companies, that sounds like the natural milestone that proves the platform is becoming more serious. We did not see it that way. We shipped object storage first because we think infrastructure should be built in the order that makes the platform stronger, not just in the order that makes the homepage look more complete. And for us, object storage solved a more foundational problem earlier. ## The wrong way to build a cloud platform A lot of infrastructure roadmaps are shaped by optics. What looks good in a comparison table. What sounds more advanced in a launch post. What makes people say, “Okay, now this is a real cloud.” I understand the temptation. I really do. But we have tried to build Raff around a different principle: the next thing we ship should make the whole platform more useful, not just more crowded. If a feature introduces a lot of operational weight without improving the foundation underneath, it can make the platform look broader while actually making it weaker. That is the context behind this decision. We did not ask, “Which launch sounds bigger?” We asked, “Which layer makes more of the platform better right now?” For us, the answer was object storage. ## Object storage is more foundational than many people think Object storage sounds simple until you list the number of things that depend on it. Backups. Media files. Build artifacts. Static assets. User uploads. Exports. Logs. Generated files. Application blobs that should not live on the same disk as the VM that serves the app. That list cuts across a huge number of workloads. A team running one VM may already need it. A team running a web app almost certainly benefits from it. A team doing automation, CI, media handling, backup retention, or file-heavy application work starts needing it even faster. That is why we did not think of object storage as a side product. We thought of it as a platform layer. Once it exists, a lot of other things get cleaner. ## Managed databases are powerful, but they are not neutral This is the part people miss. Managed databases are not just “database hosting with nicer branding.” They are one of the most trust-sensitive infrastructure products you can ship. If you get a VM slightly wrong, a customer can often work around it. If you get object storage slightly rough around the edges, many users can still adopt it gradually. If you get a managed database wrong, the blast radius is much bigger. Because now you are taking responsibility for: - backups - recovery design - failover behavior - versioning - storage performance under real load - connection handling - maintenance windows - scaling expectations - the customer’s confidence that their data layer is safe That is not a feature I wanted to rush for the sake of sequence. We were not interested in launching a shallow managed database product just so we could say we had one. ## Object storage made more of Raff make sense immediately When we launched [object storage](/products/object-storage), it was not only about adding another SKU. It made the rest of the platform more coherent. A VM is useful on its own, of course. But modern applications should not force every kind of data onto the VM disk forever. Once object storage is in the platform, a more sensible application shape becomes possible: - your VM runs the application - your object store holds large files, assets, backups, and static data - your networking model gets cleaner - your recovery model gets cleaner - your architecture starts looking less like “everything on one server” and more like a real cloud system That is a more meaningful step than people sometimes realize. It is one reason I see object storage as infrastructure, not decoration. ## We wanted to launch a storage layer that people could use broadly There is another practical reason behind the decision. Object storage has a broader early-use footprint than managed databases for the kinds of teams Raff serves. A lot of users do not want us to run their primary database on day one. Not yet. They still want control. They are still testing. They are still deciding whether the workload belongs in a VM, a container, or a more opinionated managed layer later. But many of those same users absolutely do want: - a place to store backups - a place to keep media files - a place to serve static assets - a place to keep artifacts and exports - a simpler way to separate storage concerns from VM concerns That is a much wider adoption surface. And if you are building a young platform, that matters. It means the thing you ship first has a better chance of becoming part of many workloads instead of being reserved only for a narrower category of production users. ## S3 compatibility mattered a lot in this decision Another reason object storage came first is interoperability. We did not want to invent an awkward storage product that forced users into a Raff-specific habit just to do something basic. We wanted a storage layer that fit the way builders already work. That is why S3 compatibility matters so much. If the API is familiar, the integration story is easier. Existing tools make sense. Migration is easier. Scripts and workflows do not need to be reinvented. The product starts life as something useful, not something the user has to translate first. That is a strong platform move because it lowers friction immediately. And that is very different from shipping a feature that sounds impressive but still requires the user to adapt heavily to the platform. ## Shipping databases later was not hesitation. It was discipline. I want to be clear about that. Choosing not to ship managed databases first was not a sign that we underestimated them. It was the opposite. We respected the complexity enough not to rush it. A managed database service should not just exist. It should behave in a way that makes people trust it with something important. That means we needed the surrounding platform and operational assumptions to be ready for it. We needed the product direction to make sense. We needed to be honest about what should be foundational first. Object storage passed that test earlier. Managed databases are still an important part of the platform direction. They are already visible publicly on Raff’s site, and they are clearly part of where the platform is going. But I would rather launch them later and correctly than earlier and thinly. That is an easy decision for me. :contentReference[oaicite:2]{index=2} ## The order of launches says something about how we think This decision also says something broader about Raff. We are not trying to build the platform in the order that looks most dramatic in a pitch deck. We are trying to build it in the order that creates a stronger operating model. That means we care about the layers underneath: - virtual machines that are fast to launch and easy to reason about - networking that helps workloads stay cleanly separated - storage layers that let applications be structured properly - protection and recovery tools that make the platform safer to trust - higher-level services only when they are ready to carry real responsibility That is why [Linux VMs](/products/linux-vm), [private cloud networks](/products/private-cloud-networks), and [object storage](/products/object-storage) fit together so naturally already. They are not random product checkboxes. They are pieces of the same infrastructure logic. ## Managed databases are still important — just not first There is no anti-database message here. Managed databases are a very important product category. For many workloads, they are the right abstraction. They remove operational burden, standardize backups, simplify failover, and make scaling more approachable for teams that do not want to own every database operation themselves. That is exactly why they matter. And it is exactly why they deserved patience. If we had shipped managed databases first, before object storage, I think we would have been building the platform upside down. We would have been jumping to one of the most responsibility-heavy layers before establishing a storage primitive that many more workloads can use immediately and repeatedly. To me, that would have been the more shortsighted move. ## This is also about the kinds of teams we serve Raff is not being built only for giant platform teams. A lot of our users are developers, growing startups, lean engineering teams, and builders who need the cloud to be practical before it is theatrical. Those teams do not always need the biggest-looking launch first. They need the next useful layer first. A team with a VM and an app can benefit from object storage very quickly. A team with backups, uploads, artifacts, or static assets can use it almost immediately. A team trying to clean up how application data is shaped can use it without redesigning everything. That is a better first-use story. And if you are building a cloud platform that wants to be genuinely useful, not just loudly expanding, that matters a lot. ## What This Means for You If you are building on Raff, the practical takeaway is simple: we did not ship object storage before managed databases by accident. We shipped it first because we think good platform sequencing matters. A strong cloud platform is not only a list of products. It is a set of layers that make more sense together over time. Right now, that means you can already build around the pieces that are live and broadly useful: [Linux VMs](/products/linux-vm), [private cloud networks](/products/private-cloud-networks), [data protection](/products/data-protection), and [object storage](/products/object-storage). And as higher-level layers like managed databases arrive, they will sit on top of a platform that already makes more architectural sense. That is how we want Raff to grow. Not by shipping the loudest thing first. By shipping the right layer first. --- ### Why We Moved Beyond Pure Pay-As-You-Go Billing URL: https://rafftechnologies.com/blog/why-developers-are-switching-to-usage-based-cloud-platforms Published: 2025-11-13T00:00:00.000Z Description: Why We Moved Beyond Pure Pay-As-You-Go Billing When we first thought about pricing Raff, pure pay-as-you-go looked like the obvious answer. It sounded modern. It sounded developer-friendly. And on paper, it matched the way many builders want to think: spin things up, use what you need, pay only for what ran. At a conceptual level, I still understand why that model is attractive. But building a cloud company teaches you something quickly: a pricing model does not have to sound good only in theory. It has to work in real life — for customers, for support, for operations, and for the platform itself. That is exactly why we moved beyond pure pay-as-you-go billing. ## The original idea made sense at first In the early stage, pay-as-you-go felt aligned with the kind of users we care about. Developers want freedom. Startups want flexibility. Small teams do not want infrastructure commitments before they know what the workload will become. That logic is not wrong. In fact, I think it is one reason usage-based cloud products became attractive in the first place. They remove the feeling of being trapped. They make experimentation feel possible. They lower the psychological barrier to launching something new. For a young infrastructure company, that is a very tempting place to start. And it was tempting for us too. ## But a pricing model has to survive contact with reality This is the part that matters most. What looks elegant in a pitch or on a landing page does not always hold up once real usage patterns show up. We learned that the hard way. Pure pay-as-you-go sounds fair because it implies perfect alignment between usage and cost. But in practice, it also creates a different set of problems: - cost perception becomes harder to anchor - billing expectations become less stable - users think in short bursts, even when their workloads are not actually short-term - platform planning becomes harder - pricing conversations become more reactive than intentional And most importantly, it does not always match how customers actually behave. A surprising number of workloads are not “launch for 30 minutes and destroy.” They are persistent. They are ongoing. They are the kind of projects that need a machine, keep the machine, resize the machine, and build on top of it. Once we saw that pattern more clearly, it became obvious that pure pay-as-you-go was not the best long-term foundation for Raff. ## The real issue was not flexibility. It was clarity. This is where I think many infrastructure companies make the wrong distinction. They assume the only alternative to pay-as-you-go is rigidity. That is not how I see it. The real question is: **Does the pricing model help the customer understand what they are buying and what it will cost as the workload becomes real?** That is where pure usage billing can become weaker than it first appears. Yes, it feels flexible. But flexibility without enough structure can create a different kind of friction. Teams start asking: - What will this actually cost if we keep it running? - Is this still the right configuration for next month? - Are we optimizing for usage or just reacting to charges? - How do I explain this model internally if the workload becomes more permanent? That uncertainty is not always visible in the first week. But it becomes much more visible once the project is no longer a temporary experiment. ## We realized our customers needed something simpler One of the things I care about most at Raff is reducing unnecessary decision fatigue. Infrastructure is already full of choices: VM class, CPU, RAM, storage, backups, networking, regions, architecture, growth path. If the pricing model itself also becomes something the user has to constantly interpret, the platform starts consuming too much attention. That is why we moved toward a simpler subscription model. Today, Raff publicly frames pricing around clear terms: - monthly - 1-year - 2-year Longer commitments come with bigger savings, and customers receive a detailed invoice at the end of each billing cycle. The platform also supports automatic and manual payment modes, with credits and account balance applied first before charging the payment method. That is a much cleaner model for the kinds of teams we serve. It is easier to understand. It is easier to explain internally. And it is easier to build on when the workload becomes something serious rather than temporary. ## We did not reject flexibility — we changed where it lives This is important. Moving beyond pure pay-as-you-go does **not** mean we stopped caring about flexibility. It means we stopped putting all of that flexibility pressure on the billing model alone. Instead, we think flexibility should show up in more useful places: - clear VM options - monthly, yearly, and 2-year terms - easy upgrades and resize paths - backups and snapshots when workloads become important - practical infrastructure layers like [Linux VMs](/products/linux-vm), [object storage](/products/object-storage), and [private cloud networks](/products/private-cloud-networks) That is a healthier version of flexibility. Because what most users really need is not billing chaos in the name of freedom. What they need is a platform that lets them start cleanly, understand their costs, and still adapt as the workload grows. ## Why this shift made more sense for Raff specifically I also want to be honest about something: a pricing model is not only a customer-experience decision. It is also an operating decision. If you are building real infrastructure, the platform needs a model that supports reliability, product development, support, and clear financial expectations without turning every active workload into a micro-billing event. That matters even more when your goal is not just to rent compute, but to build a platform people can trust. Raff today is already broader than just “a VM with a price tag.” The current public platform includes: - [Linux VMs](/products/linux-vm) - [Windows VMs](/products/windows-vm) - [object storage](/products/object-storage) - [data protection](/products/data-protection) - [private networking](/products/private-cloud-networks) And the broader direction includes more platform layers over time. That kind of platform benefits from pricing that is simpler, more stable, and easier to reason about than pure raw usage billing. ## Customer behavior taught us more than theory did This is probably the biggest lesson. In theory, developers say they want maximum freedom. In practice, many of them want something slightly different: they want **freedom without billing anxiety**. That is not the same thing. They want to know: - what they are paying for - how long it will make sense - what happens if usage grows - whether the platform still feels affordable next month, not just today That is why transparent pricing matters so much to me now. Not as a slogan. As a product standard. The pricing page should make sense. The billing cycle should make sense. The upgrade path should make sense. The invoice should make sense. That is a better customer experience than a model that sounds modern but becomes harder to interpret once the workload stops being temporary. ## Why I still think the original instinct was useful Even though we moved away from pure pay-as-you-go, I do not think the original instinct was wrong. It taught us something valuable. It forced us to ask: “How do we keep infrastructure from feeling heavy, rigid, or commitment-driven too early?” That is still the right question. We just learned that the answer was not “charge everything in the most usage-granular way possible.” The better answer was: build a pricing model that stays clear, supports different commitment levels, and still feels fair to the kinds of teams Raff is built for. That is a more mature answer. And honestly, a more useful one. ## Where the current Raff model is stronger I think Raff’s current public pricing model is stronger for a few reasons. ### 1. It matches how many real workloads behave A lot of customer workloads are persistent enough that monthly or longer-term pricing is easier to plan around than raw pay-as-you-go. ### 2. It is easier to explain internally Founders, developers, and small teams do not want to become infrastructure accountants. Clear terms are easier to communicate. ### 3. It creates better long-term trust When pricing is simple, the platform feels more trustworthy. That matters a lot more than people think. ### 4. It still leaves room for flexibility Monthly plans still exist. Longer terms simply reward predictability with better value. That is a much more balanced model than pretending every workload should be priced like a short-lived experiment. ## What This Means for You If you are evaluating cloud infrastructure, I would encourage you to look beyond whether a provider says “pay-as-you-go” or “subscription.” That label alone does not tell you enough. Ask better questions: - Will this pricing still make sense once my workload becomes real? - Can I understand my billing model without overthinking it? - Does the platform feel flexible in the right places? - Am I buying freedom, or just buying uncertainty with a modern label? That is the more useful filter. At Raff, we started with one instinct, learned from how the platform and customers actually behaved, and changed direction. Today, the public model is much clearer: choose a term, know the structure, and build on infrastructure that is designed to stay understandable as you grow. If you want to evaluate that model directly, start with the [pricing page](/pricing), then compare it with the practical infrastructure layers around it: [Linux VMs](/products/linux-vm), [data protection](/products/data-protection), and [private cloud networks](/products/private-cloud-networks). That is where the current Raff story makes the most sense. Not pure pay-as-you-go. Not rigid long-term lock-in. A clearer middle ground that actually works. --- ### Why Virtual Dev Environments Are Moving to the Cloud URL: https://rafftechnologies.com/blog/virtual-dev-environments-and-platform-engineering-in-2025-the-end-of-works-on-my-machine Published: 2025-11-24T00:00:00.000Z Description: Why Virtual Dev Environments Are Moving to the Cloud If you have ever lost half a day to a broken local setup, you already understand why virtual dev environments are becoming more important. Not because developers suddenly forgot how to use their laptops. Because modern software projects got heavier, more distributed, and more fragile than the old local-first workflow was designed to handle. That shift matters a lot to me, because I think many small teams still underestimate how much speed they lose to environment drift. We talk about developer productivity as if it is mostly about better tools, faster AI assistance, or stronger deployment pipelines. In reality, a surprising amount of friction still starts earlier: one laptop behaves differently, one runtime version is off, one missing dependency turns into a debugging session, and the team loses momentum before real work even begins. That is exactly why cloud development environments are becoming more relevant. And it is one of the reasons Raff’s infrastructure direction matters beyond just “hosting a server.” ## The laptop stopped being the best home for everything For a long time, the default assumption was simple: your laptop is where development lives. Your editor, terminal, containers, database, package managers, background services, credentials, browser sessions, and half-finished experiments all pile into one machine, and somehow that machine is supposed to stay clean, stable, and reproducible across every project you touch. That was already imperfect years ago. Today, it breaks down much faster. Projects are more dependency-heavy. Teams are more distributed. Environments need to be easier to recreate. Security expectations are higher. Collaboration is more asynchronous. And many builders are moving across multiple contexts at once: client work, startup work, testing, staging, demos, internal tools, automation, and production debugging. At some point, the problem is no longer “my laptop is underpowered.” The problem becomes: **why is my personal machine still acting like the source of truth for the whole environment?** ## “Works on my machine” is still a very real tax People joke about this phrase because it is familiar. But the hidden cost is more serious than the joke. When every developer environment is slightly different, teams lose time to problems that should not exist: - different language versions - hidden local dependencies - mismatched Docker behavior - conflicting ports - weird package leftovers - onboarding docs that get longer every quarter - local fixes nobody remembers well enough to document properly That is not just a setup annoyance. It is an execution tax. And for small teams, that tax hurts more because there is less slack in the system. A larger company may absorb a broken half-day here and there without much visible damage. A small startup, freelancer, or bootstrapped team feels it immediately. That is one of the reasons I think cloud-based dev environments are not just a “nice future trend.” They are a practical fix for a very old bottleneck. ## Virtual dev environments are really about reproducibility A virtual dev environment is not magic. It is just a much healthier operating model. Instead of treating one developer’s local machine as the environment, you define the environment intentionally and launch it in infrastructure that is easier to reproduce. That environment can live on a VM, in a container workflow, or in a hybrid setup where the repo and tooling define how the machine should behave. That changes the question from: “Can I get this working on my machine?” to: “How quickly can we recreate this working environment anywhere?” That is a much better question. Because reproducibility helps with almost everything that small teams struggle with: - onboarding - handoffs - debugging - temporary workspaces - client-specific environments - testing risky changes - recovering from local machine chaos - keeping project state separate from personal state Once you think about it this way, cloud dev environments stop looking like an advanced enterprise pattern and start looking like basic operational hygiene. ## Platform engineering matters, but smaller teams need the lightweight version “Platform engineering” is one of those terms that gets bloated quickly. At enterprise scale, it can mean internal developer platforms, golden paths, service catalogs, policy controls, and teams dedicated to making infrastructure feel like a product. That is real. But smaller teams do not need the full ceremony to get the benefit. For a lean team, platform engineering often starts in a much simpler place: - one reproducible environment - one clean VM pattern - one defined repo setup - one shared way to launch and connect - one predictable base for development and testing That is still platform thinking. It is just platform thinking at the right size. And that distinction matters, because too many infrastructure conversations are framed as if you either need full enterprise internal-platform maturity or nothing at all. In practice, most useful improvements start much smaller. ## Why this fits Raff’s audience so well This is exactly the kind of problem Raff’s audience runs into. Not giant platform teams with dozens of specialized engineers. The people we care about most are usually much closer to the problem: - developers switching between projects - hackathon teams - startups trying to ship without environment friction - students and bootcamp learners - freelancers working across multiple stacks - QA and test engineers needing clean labs - technical founders who cannot afford to lose days to setup drift These are the users who get punished the most by bad environment habits. They do not have extra time. They do not always have expensive local hardware. They do not have room for avoidable delays before demos, deployments, or deadlines. That is one reason I care so much about environment reproducibility. The smaller the team, the more expensive setup chaos becomes. ## Why we built Raff around clean infrastructure building blocks At Raff, we did not approach this from the angle of “how do we sell developers more cloud?” We approached it from a simpler question: **How do we reduce the amount of friction between needing an environment and actually having one that works?** That is a different product mindset. It is one reason our [Linux VMs](/products/linux-vm) matter so much to this conversation. They deploy in under 60 seconds, support full root access, and are built to be usable starting points rather than complicated infrastructure puzzles. That sounds basic, but it matters because a development environment loses a lot of value if the setup path is already slow or constrained. It is also why [private cloud networks](/products/private-cloud-networks) matter. Once development environments become shared, repeatable, or tied to real services, networking starts to matter much earlier than many people expect. Isolation, security groups, and clean internal communication are not only production concerns. They become relevant whenever a workflow stops being “just one laptop.” And it is why [object storage](/products/object-storage) matters too. Once workflows become more real, data stops belonging only on the same machine that runs the code. Artifacts, backups, test data, static assets, and environment-related storage patterns need a cleaner home. That is the bigger point I want people to see. Virtual dev environments are not a side trend. They are one more example of why infrastructure is becoming more layered, more intentional, and more workflow-aware. ## The real win is not convenience. It is momentum. A lot of people describe virtual dev environments as “more convenient.” That is true, but it undersells the real value. The real value is momentum. Convenience sounds optional. Momentum is not. If your team can launch a clean environment faster, hand it to someone else faster, test changes without local contamination, and get new contributors productive sooner, that is not just a nicer developer experience. That is a more effective delivery process. And for small teams, speed of execution is one of the few advantages you can actually protect. That is why I think “works on my machine” is not a funny little relic. It is a sign that the team is still relying on a workflow model that no longer fits the shape of modern software work. ## Where this trend is going next I think the direction is becoming clearer, not fuzzier. Development environments are moving toward being: - defined as part of the project - easier to launch in the cloud - less dependent on personal hardware - more integrated with containers and repo context - more secure by default - closer to the rest of the infrastructure lifecycle This is also where the broader Raff platform direction becomes relevant. Raff Apps and Kubernetes are both signals that the platform is moving beyond raw server creation toward more productized application and orchestration layers. That matters because development environments, application environments, and deployment environments are gradually becoming less separate than they used to be. The old model was: every developer crafts a machine. The newer model is: every project can define one. That is a healthier direction. ## What This Means for You If your team is still depending almost entirely on personal laptops for serious project setup, I would suggest asking a better question. Not: “Can our current machines handle this?” Ask: “Should our workflow still depend this much on personal machines?” That is the more useful question. If onboarding feels heavier than it should, if projects are difficult to recreate, if environment drift keeps eating time, or if collaboration keeps bumping into machine-specific weirdness, that is usually a sign that part of your workflow wants to move into the cloud. It does not have to be everything. But it probably should not be nothing either. If you want to explore that shift through Raff, start with the practical layers: [Linux VMs](/products/linux-vm), [private cloud networks](/products/private-cloud-networks), [object storage](/products/object-storage), and the public [pricing page](/pricing). That will tell you a lot more about how the platform fits modern dev workflows than any generic “future of platform engineering” article ever could. That is how I think about this trend now. Not as a fancy enterprise idea. As the cleanest way for more builders to stop debugging their machines and start building on environments they can actually trust. --- ### Why We Made n8n Easy to Launch on Raff URL: https://rafftechnologies.com/blog/launch-n8n-in-minutes-on-raff-the-easiest-way-to-automate-your-workflows Published: 2025-12-01T00:00:00.000Z Description: Why We Made n8n Easy to Launch on Raff Automation tools are supposed to save time. Too often, they start by wasting it. That is the problem we wanted to solve with n8n on Raff. If you are a developer, operator, startup team, or even a solo builder, self-hosted automation is attractive for a simple reason: you want control. You want your workflows, your logic, your integrations, and your data to live in an environment you understand. But in practice, many people hit the same wall before they even build their first workflow: setup friction. Local Docker issues. Port conflicts. machine-specific weirdness. Environments that work once and break later. Laptops that go to sleep while workflows should still be running. That is exactly why we decided to make n8n easy to launch on Raff. ## The real problem was never n8n itself n8n is already a strong product. It is flexible, open-source, code-friendly when needed, and much more controllable than many hosted automation tools. It is one of the clearest examples of a tool that becomes more powerful the more technical your workflow gets. The problem is not the product. The problem is that too many people meet n8n through setup pain instead of through useful automation. That changes the first impression completely. Instead of thinking: “I can automate this process in an hour.” They end up thinking: “I guess I need to debug Docker, ports, volumes, reverse proxy, and persistence first.” That is not a workflow-automation problem. That is an infrastructure-experience problem. ## Why we thought this mattered at Raff At Raff, we try to pay attention to where builders lose momentum. That matters to me a lot, because in smaller teams momentum is one of the most important resources you have. If the first step feels heavier than it should, projects get delayed. Experiments get postponed. People settle for smaller workflows because the environment around the tool feels annoying. That is one of the reasons we built a dedicated [n8n VM offering](/products/n8n-vm) instead of expecting users to piece everything together themselves. This was a product decision, not just a packaging decision. We wanted the first experience of self-hosted automation to feel like: “my workflow is ready to start” not: “now I need a side quest in Linux setup.” ## Why n8n belongs on cloud infrastructure, not a laptop You *can* run n8n locally. For many people, that is where they start. And for lightweight testing, that is fine. But local-first automation breaks down quickly in real use. ### Workflows should not depend on your laptop being awake This is the most obvious issue. If your automations matter, they need to run continuously. Your laptop is not designed to be an always-on workflow system. It sleeps, reboots, disconnects, updates at the wrong time, and competes with everything else you are doing on the machine. An automation tool becomes much more useful when it lives in an environment designed to stay online. ### Clean environments matter more than people think A workflow platform becomes part of your operational stack. That means you want it in a stable, isolated environment — not mixed in with local development leftovers, temporary packages, random ports, and machine-specific quirks. This is one of those issues that seems small until you try to share the setup with a teammate or recreate it later. A cloud VM gives you a clean base. ### Self-hosted should still feel simple A lot of people hear “self-hosted” and assume complexity is part of the deal. I do not think that should be the standard. Control is good. Ownership is good. Customization is good. But none of those should require unnecessary setup pain if the platform around the tool is designed well. That is what we are trying to improve with n8n on Raff. ## What we actually built We did not build “automation hosting” as a vague concept. We built a practical way to get a real n8n instance running quickly on infrastructure that already makes sense for always-on automation. The current Raff n8n product page is built around a few points that matter directly: - your own n8n instance - no execution limits - full data ownership and control - support for custom nodes - cloud deployment without the usual setup hassle - protection options like snapshots and backups - infrastructure built on AMD EPYC, NVMe storage, and high-availability design Those details matter because they change what the user is actually buying. You are not just getting “a server with n8n on it.” You are getting a cleaner environment for automation work to live in. ## Why this is better than a generic VPS + manual setup story Could someone manually install n8n on a Linux VM? Of course. In fact, that option should absolutely exist for technical users who want full manual control. But the more interesting question is: **should that be the default experience for most users?** I do not think so. Because most people interested in n8n are not trying to become part-time infrastructure operators for fun. They are trying to automate work. That is why the default experience matters. The default should not force everyone through the longest path just to prove they are technical enough to deserve self-hosting. It should remove avoidable friction while keeping control where it matters. That is the balance we want. ## Where n8n fits in Raff’s broader platform story This is also important because I do not want people to think of Raff as “just a place to run n8n.” n8n is a great example of the kind of workload that fits our platform direction. Raff is being built around practical cloud layers: - [Linux VMs](/products/linux-vm) - [object storage](/products/object-storage) - [data protection](/products/data-protection) - [private cloud networks](/products/private-cloud-networks) - one-click and simplified application workflows through [Raff Apps](/products/raff-apps) That matters because automation does not live in a vacuum. Real workflows often touch: - APIs - databases - webhooks - internal services - backups - storage - networking boundaries - deployment environments So the real value is not only that n8n runs. It is that it runs on infrastructure that can still make sense as your workflows become more real and more important. ## What kinds of teams this actually helps I think this is especially useful for teams in the middle. Not giant enterprises with a platform team for every layer. Not purely no-code users who never want to think about infrastructure at all. I mean teams like: - developers automating GitHub, CI, alerts, and internal tools - startups connecting signup flows, CRM actions, and operations tasks - content teams pulling analytics and publishing workflows into one place - operators building approval systems or lightweight internal automations - technical founders who want self-hosted control without setup drag Those users do not need complexity for its own sake. They need a cleaner path from idea to working workflow. That is exactly where this product makes sense. ## The hidden value is momentum If I had to summarize the real benefit in one word, it would be: **momentum** A lot of infrastructure decisions are judged only by specs or pricing. Those matter, of course. But what gets underestimated is how much progress a team loses when the platform slows down the first useful action. With automation, that cost is even more visible. The value of n8n is not in “having n8n installed.” The value is in getting to actual workflows. If the infrastructure removes enough friction that a user gets from: “I should automate this” to “it’s already running” much faster, that is a real product advantage. And that is the part I care about most. ## What This Means for You If you are evaluating n8n right now, I would suggest asking a slightly different question. Not: “Can I install this?” Ask: “Where will this be easiest to keep running, easiest to trust, and easiest to build on later?” That is the more useful question. If you want local experimentation, local is fine. But if the workflows matter, if they need to run continuously, if you want cleaner setup, or if you are already thinking beyond a one-machine experiment, a cloud VM is usually the better home. That is why we built [n8n on Raff](/products/n8n-vm) the way we did. Not to make automation look more complicated. To make self-hosted automation feel more practical from the first click. --- ### Why Small Teams Should Stop Buying Cloud Like Enterprises URL: https://rafftechnologies.com/blog/raff-vs-big-cloud-providers-why-small-teams-need-a-developer-first-platform Published: 2025-08-12T00:00:00.000Z Description: Why Small Teams Should Stop Buying Cloud Like Enterprises Big cloud platforms are impressive. They are also often the wrong buying model for small teams. That is something I have become more convinced of over time, not less. If you are running a huge enterprise with multiple departments, dedicated infrastructure specialists, compliance layers, and a roadmap that depends on a broad catalog of managed services, hyperscalers make sense. They were built for that world. But most builders are not operating in that world. A startup with three engineers, a technical founder launching an MVP, a freelancer delivering client systems, a small SaaS team, or a growing business building internal tools does not need to buy cloud like a multinational company. And yet many still do — because the market trained them to think bigger automatically means better. I do not believe that. At Raff, one of the decisions we made early was not to build a miniature version of hyperscaler complexity. We built around the idea that most small teams need something more practical: a fast path to real infrastructure, pricing they can still explain later, and platform layers that make sense as the workload grows. ## The enterprise buying model leaks into everything One of the biggest problems in cloud right now is that enterprise assumptions leak into products that are also being sold to small teams. You can see it in the way some platforms are structured: - giant service catalogs - multiple pricing dimensions for a single workload - bandwidth rules that create invoice anxiety - setup flows that assume prior cloud fluency - architectural choices pushed too early, before the project even exists in a stable form From the inside, all of that may look like flexibility. From the buyer side, it often feels like friction. That is an important distinction. A product can be technically broad and still operationally wrong for the stage a team is in. In fact, that happens a lot. The platform is capable of everything, but the user only needs a small set of clean decisions to get moving. And when that gap is large enough, the “power” of the platform becomes a drag on the user. ## What small teams usually need first When people talk about cloud infrastructure, the conversation often gets pulled toward the largest possible use case. That is backwards. The right starting point is not: “What can this provider support at maximum scale?” It is: “What does my team need to launch, learn, test, and grow without unnecessary drag?” For most small teams, the early answer is simpler than cloud marketing makes it seem. They need: - a reliable virtual machine - clear pricing - enough performance headroom to run the stack - backups and recovery options that are easy to understand - networking that does not become messy the moment a second service appears - storage that fits the workload instead of forcing everything onto one disk - a platform that can become more capable later without becoming confusing now That is exactly the kind of problem we think about at Raff. Not “How do we look bigger?” But “How do we make practical infrastructure easier to start and easier to grow with?” ## Why we did not want Raff to feel like a small copy of big cloud There is a trap smaller infrastructure companies can fall into. They assume credibility comes from imitating the biggest names as closely as possible. Same language. Same product sprawl. Same complexity signals. Same feeling that the user should “graduate into” a complicated operating model as early as possible. We chose not to go that direction. Because if you are building for developers, startups, and growing teams, the goal should not be to recreate hyperscaler friction at smaller scale. The goal should be to remove the parts that make teams hesitate for the wrong reasons. That is why Raff’s foundation matters so much to me. We start with things that are immediately useful: - [Linux VMs](/products/linux-vm) - [Windows VMs](/products/windows-vm) - [object storage](/products/object-storage) - [private cloud networks](/products/private-cloud-networks) - snapshots and backups - pricing that stays understandable - infrastructure that feels like a tool, not a certification exam That is not a “less serious” cloud philosophy. I would argue it is a more honest one. ## VMs still matter — but they are not the whole story A lot of people first discover Raff through virtual machines, and that makes sense. VMs are still one of the most flexible ways to launch real workloads. You choose the operating system, control the stack, and shape the environment around the application instead of around a rigid hosting model. That is why VMs remain central. But if all people understand about Raff is “they rent VMs,” they are missing the real direction of the platform. The more useful view is this: VMs are the starting layer. The platform value comes from what sits around them. A VM becomes much more useful when it is surrounded by: - predictable billing - storage options beyond the root disk - data protection that is clear to operate - network isolation that does not feel bolted on - deployment workflows that can get simpler over time That is the difference between “server rental” and “cloud platform.” ## Storage is one of the clearest examples Traditional hosting tends to flatten storage into one simple idea: you have hosting space. Modern workloads do not behave that way. Application media, static assets, backups, build artifacts, logs, exports, and object-based application data do not all belong on the same server disk forever. If the platform makes you think that way, it is already encouraging the wrong architecture. That is one reason [object storage](/products/object-storage) matters so much in Raff’s shape. It changes how teams think about their applications. Instead of asking only: “Where is the server?” You start asking: “Which data belongs on the VM, and which belongs in a storage layer designed for scale and separation?” That is a healthier cloud model, and it becomes more important as the project becomes more real. ## Networking is where “small team cloud” often gets underestimated Another area where big-cloud thinking distorts the conversation is networking. Small teams are often told one of two incomplete stories: - either networking is too advanced to matter early - or they should immediately design as if they are operating a giant multi-region platform Neither is helpful. The truth is more practical. A lot of teams do not need advanced networking on day one. But once a stack becomes more than one public VM, networking matters quickly. Internal traffic matters. Environment separation matters. Isolation matters. Security boundaries matter. That is why [private cloud networks](/products/private-cloud-networks) are such an important part of Raff’s platform story. They let the platform grow beyond “a server with an IP” into something more structured and more operable. That matters for teams much earlier than many providers admit. ## The platform direction matters too Another reason I push back on the “just a VPS provider” label is that it ignores where Raff is going. The visible public direction already tells the story: - core VM infrastructure today - live object storage today - live private networking today - broader application and orchestration layers in the platform direction Two of those future-facing layers matter especially: - [Kubernetes](/products/kubernetes) - [Raff Apps](/products/raff-apps) I do not mention them because I think every small team needs them immediately. Most do not. I mention them because they show something important about how we think: the platform is being built to start simple and become more capable, not to trap users in a forever-basic hosting model. That is the difference I want people to see more clearly. ## Why the “small team discount cloud” framing is too narrow There is another misunderstanding I want to push against. Sometimes smaller platforms get framed as if they only exist to be a cheaper alternative. Price matters. A lot. But that is still too narrow. The better question is not: “Is this cloud cheaper?” It is: “Is this cloud shaped correctly for the team using it?” Because the wrong platform can be expensive even when the monthly line item looks reasonable. It becomes expensive in slower setup. In architectural confusion. In hidden billing tension. In overbuying complexity. In waiting to ship because the platform keeps asking the team to think like a bigger company than it is. That is why I think the best infrastructure for small teams is not the one with the biggest brand, the widest menu, or even the lowest advertised price. It is the one that helps the team move with the least unnecessary drag. ## What I think big cloud still gets right This is not an anti-hyperscaler argument. Big cloud providers are strong for real reasons. They earned that position. They are right when you need: - enormous global reach - very deep managed-service catalogs - specialized compliance patterns - extremely large-scale architecture options - procurement and enterprise alignment that smaller providers cannot match The mistake is not that those platforms exist. The mistake is assuming those strengths automatically make them the best first or second choice for teams that do not actually need that operating model yet. That is where I think the market still confuses size with fit. ## The more useful buying question If I could change one thing about how small teams evaluate cloud, it would be this: stop asking which provider looks the most complete in the abstract. Start asking which provider gives your team the shortest path from intent to working infrastructure — without creating long-term friction later. That is the better question. It forces you to evaluate: - whether the pricing model will still make sense once usage grows - whether the platform supports cleaner architecture as the stack expands - whether the product helps you launch now without making you rebuild later - whether the team can understand and operate it without becoming part-time infrastructure analysts That is exactly the lens I would use on Raff. ## What This Means for You If you are a small team, do not buy cloud the way an enterprise buys cloud. You do not need to prove sophistication by choosing the most complex platform in the room. You do not need to overbuy product surface just because it looks impressive on a comparison page. And you definitely do not need to accept billing models that make experimentation feel risky. What you need is a platform that helps you start cleanly and keeps making sense as the workload becomes more real. That is the standard I think infrastructure should be held to. If you want to evaluate Raff through that lens, start with the practical layers: [Linux VMs](/products/linux-vm), [object storage](/products/object-storage), [private cloud networks](/products/private-cloud-networks), and the public [pricing page](/pricing). Then ask whether that platform shape feels closer to the way your team actually works. That is a much more useful comparison than “big cloud versus small cloud.” For most small teams, the real question is simpler: Which platform helps us move now without making the next stage harder than it needs to be? --- ### Why More Modern Dev Workflows Start in the Cloud, Not on a Laptop URL: https://rafftechnologies.com/blog/why-cloud-v-ms-beat-local-machines-for-modern-dev-workflows Published: 2025-07-12T00:00:00.000Z Description: Why More Modern Dev Workflows Start in the Cloud, Not on a Laptop The local machine is still useful. It is just no longer the center of modern development work. That shift has been happening quietly for a while, and I think many teams feel it before they fully name it. Projects get heavier. Toolchains get messier. Environments drift. Teams work across locations, devices, and time zones. At some point, the laptop stops feeling like the best home for serious development and starts feeling like the narrowest part of the workflow. That is one of the reasons I think cloud VMs matter more than ever now. Not because local development is dead, but because more of the real work around modern software benefits from environments that are easier to reproduce, easier to resize, and easier to separate from personal hardware. ## The laptop was never meant to carry everything For a long time, developers got used to the idea that their main machine should do almost everything. Editor. Terminal. Containers. Databases. Background services. Build tools. Browsers. SSH keys. Test environments. Maybe even staging-like workloads. That model worked well enough when projects were smaller and stacks were simpler. But modern development is rarely that tidy. A single project might now involve: - application code - multiple services - Docker containers - a local database - a queue - background jobs - environment variables and secrets - different language runtimes - shared team conventions - production-like debugging needs Once all of that lands on one laptop, the machine stops being just a workspace. It becomes an operational dependency. That is where things start to break down. ## “It works on my machine” is still a real problem People joke about it because it is familiar. But the deeper problem is not the joke. It is the hidden cost. When each developer machine becomes its own unofficial environment, teams lose time to differences that should not matter: - slightly different OS versions - package drift - conflicting ports - toolchain mismatches - broken local dependencies - setup docs that grow longer every month That is not just an inconvenience. It is a drag on delivery. A cloud VM changes that because it gives the team a cleaner base to work from. You define the environment more deliberately, launch the same pattern again when needed, and reduce the number of invisible local differences shaping the result. That does not solve every engineering problem. But it removes one of the most common categories of avoidable friction. ## Cloud VMs make environments more reproducible This is probably the most important benefit, and it is still underrated. A good development environment is not only one that runs. It is one that can be recreated quickly. That matters for: - onboarding new developers - creating temporary environments for contractors - reproducing a bug on a clean system - isolating project-specific dependencies - testing without polluting a personal machine - preserving a known-good setup instead of rebuilding it from memory Once you start thinking this way, the value of cloud VMs becomes much clearer. You stop asking: “Can this run on my laptop?” And start asking: “How quickly can we recreate this environment if we need it again tomorrow?” That is a much healthier question for a modern team. ## Compute should adapt to the project, not the other way around Another reason cloud VMs are becoming more natural in development workflows is simple: projects change faster than laptops do. A machine you bought for general work last year may be fine for editing code and running a few services. But if the project suddenly needs more RAM, more CPU, a cleaner Linux base, or a better place to run containers and databases together, the laptop becomes the bottleneck. Cloud VMs change that relationship. Instead of shaping the project around fixed local hardware, you shape the environment around what the project needs right now. That flexibility matters more than people think. A team may not need a huge machine every day. But when they do need more headroom, the ability to launch it quickly matters. And when they no longer need it, they should not still be carrying that cost in physical hardware or personal machine complexity. That is one reason I think cloud infrastructure is becoming more attractive even for development work that is not “large scale” in the enterprise sense. ## Remote work made this shift more obvious Distributed work did not create the case for cloud VMs. It just made the weaknesses of local-only development much harder to ignore. When work happens across multiple locations and devices, local-machine dependency starts causing more friction: - environment mismatch between teammates - slower onboarding - difficulty resuming work across devices - more painful handoffs - less clean collaboration around setup and debugging A cloud VM does not magically solve collaboration. But it does make the environment easier to centralize, reproduce, and control. That is important. Because modern teams do not just need code collaboration. They need environment collaboration too. Once those environments become easier to share conceptually — even if each person still uses their own machine — the workflow gets cleaner. ## Safer experimentation is a bigger advantage than people expect There is another reason cloud VMs fit development work well: they are easier to treat as disposable. That matters whenever a developer wants to: - test something risky - try a new Linux distro or package setup - run a heavy toolchain - debug a strange environment issue - build a staging-like replica - spin up a project-specific machine that does not need to live forever On a personal laptop, risky experimentation carries emotional cost. You are not just changing an environment. You are changing **your machine**. That changes behavior. People test less boldly. They postpone experiments. They keep messy workarounds in place because the alternative feels annoying or risky. A cloud VM lowers that psychological cost because the environment can be treated more like infrastructure and less like identity. That is a powerful workflow improvement. ## The local machine becomes cleaner too One of the less obvious benefits of moving more dev work to cloud VMs is that it improves the local machine by removing what does not belong there. Instead of turning a laptop into a museum of half-used runtimes, abandoned containers, old databases, temporary scripts, and mismatched project dependencies, you can keep local work lighter and more focused. That leads to a healthier split: - your personal machine stays cleaner - project environments become more intentional - switching contexts becomes easier - onboarding becomes less personal and more repeatable That is good for productivity, but it is also good for reliability. A machine that carries less accidental infrastructure tends to create fewer avoidable surprises. ## Why this matters for small teams especially Large engineering organizations usually have enough operational structure that they can absorb some environment mess. Small teams do not. A startup with three engineers, a freelance developer working across clients, a technical founder building the product and the infrastructure, or a student team preparing a demo does not have extra process to waste. In those environments, environment friction hurts more. A broken setup is not just a broken setup. It is lost momentum. It is context switching. It is an extra half day. It is uncertainty right when someone was ready to build. That is why I think cloud VMs are especially powerful for smaller teams. Not because they need enterprise infrastructure. Because they need fewer invisible blockers. ## What this means for Raff At Raff, this way of thinking influences how we look at the platform. We do not think cloud VMs are only for “production later.” We think they are useful much earlier than that. A developer VM should be fast to launch, easy to understand, and flexible enough to support the real tools people use. That is why the basics matter so much: - current Linux distributions - fast deployment - full root access - snapshot and backup support - enough performance for real development work - pricing that does not feel punishing for experimentation The point is not just to rent a server. The point is to give builders an environment that feels more reproducible, more disposable, and more practical than trying to force every serious workload through one personal machine. That is also why I think [Linux VMs](/products/linux-vm) should be understood as part of a broader workflow, not just as infrastructure for production websites. They are also a clean place to build, test, isolate, and collaborate. ## The real shift is not technical — it is behavioral When I step back, I think the biggest reason cloud VMs are beating local-only development in more cases is not just that the infrastructure got better. It is that teams are thinking differently. They are becoming less attached to the idea that development must happen where the keyboard is. They are becoming more comfortable with the idea that the environment should be portable, reproducible, and shaped around the project rather than tied completely to one device. That is a healthier mental model. It leads to better setups. Cleaner handoffs. Less machine-specific weirdness. More flexibility in how teams work. And over time, I think that becomes one of the biggest quiet advantages in modern software delivery. ## What This Means for You If your team is still forcing every project to live entirely on local machines, I would suggest asking a more useful question. Not: “Can our laptops handle this?” Ask: “Should this workflow still depend this much on personal hardware?” That is the more important question. If the project keeps getting heavier, if onboarding is awkward, if local setups drift, if testing risky changes feels annoying, or if collaboration keeps bumping into environment issues, that is usually a sign that part of the workflow wants to move into the cloud. It does not have to be everything. But it should probably be something. If you want to evaluate that shift through Raff, start with the practical pieces: [Linux VMs](/products/linux-vm), the public [pricing page](/pricing), and the ways snapshots, backups, and clean VM provisioning can reduce development friction before production even becomes the main conversation. That is how I think about cloud VMs now. Not as a replacement for local machines in every case. As the better home for more of the work than most teams realize. --- ### Raff vs. Traditional Hosting: Why the Difference Is Bigger Than It Looks URL: https://rafftechnologies.com/blog/raff-vs-traditional-hosting-what-s-different-and-why-it-matters Published: 2025-07-01T00:00:00.000Z Description: Raff vs. Traditional Hosting: Why the Difference Is Bigger Than It Looks A lot of people still hear the word “hosting” and imagine the same thing everywhere. A server. Some specs. Maybe a control panel. Maybe a monthly bill. But that mental model is already outdated. At Raff, we are not trying to be a prettier version of traditional hosting. And we are not trying to be understood as “just another VPS provider” either. What we are building is a cloud platform that starts with practical infrastructure and grows with the teams using it. That difference matters more than it sounds. Because once you are actually building something real — a product, an internal tool, a test environment, a customer-facing app, an automation stack — the gap between “hosting” and usable cloud infrastructure becomes very obvious very quickly. ## Traditional hosting was built for a different era Traditional hosting products were built for simpler use cases. That does not mean they are useless. They still make sense for brochure sites, lightweight web pages, small CMS installs, and projects where the main requirement is “put this online cheaply.” But the model behind traditional hosting is usually optimized for: - fixed, long-term plans - shared environments - limited customization - panel-driven workflows - low operational flexibility That model worked well when most users just needed a place to serve a website. It is a much worse fit when you need infrastructure that behaves like part of your workflow. Developers, technical founders, SaaS teams, automation-heavy businesses, and modern product teams need more than a place to upload files. They need infrastructure they can launch quickly, shape around their stack, protect properly, and grow without hitting artificial walls. That is where traditional hosting starts to feel small. ## Raff was never meant to be “hosting with nicer branding” This is the point I think we need to communicate more clearly. Raff may be easy to discover through virtual machines, but that is only one layer of what we are building. Yes, VMs matter. They are still one of the cleanest, most flexible ways to launch and control infrastructure. Our [Linux VMs](/products/linux-vm) and [Windows VMs](/products/windows-vm) are an important part of the platform because they give builders a practical place to start. But the real idea behind Raff is bigger than renting a server. The idea is to give teams a cloud foundation that feels simple enough to start with and powerful enough to grow into. That means the right way to understand Raff is not: “a VPS provider with decent specs.” It is: “a cloud platform built around practical infrastructure layers.” That distinction changes everything. ## The difference starts with how you think about the workload Traditional hosting asks: “How do we fit your site into our model?” A cloud platform should ask: “How do we give your workload the building blocks it needs?” That is the mindset behind Raff. Sometimes that starts with a VM. Sometimes it expands into [object storage](/products/object-storage) for media, backups, static assets, or application data. Sometimes it means [private cloud networks](/products/private-cloud-networks) so workloads can communicate securely inside an isolated environment. Sometimes it means stronger data protection, snapshots, restore workflows, and cleaner deployment patterns. And that is exactly why calling Raff “just VPS hosting” misses the real product direction. ## VMs are the starting point, not the whole story Virtual machines are still one of the most useful infrastructure building blocks because they are flexible. You can choose the operating system. You can control the stack. You can deploy the software you actually want. You can adapt the environment to the way your team works. That is why VMs remain foundational to Raff. But the important part is what sits around them. A VM becomes much more valuable when it is part of a wider infrastructure model: - snapshots and backups - predictable billing - API-driven workflows - private networking - storage layers beyond the root disk - application deployment options that reduce setup overhead That is how a VM becomes part of a platform instead of just a rented box. ## Object storage changes what Raff means for real workloads One of the clearest signs that Raff is not just a hosting product is [S3-compatible object storage](/products/object-storage). Traditional hosting does not usually push you to think in storage layers. Everything tends to blur into “the hosting account.” Modern workloads do not work like that. Media files, build artifacts, backups, logs, database exports, static assets, and user uploads should not all be treated like they belong on the same server disk forever. That is exactly where object storage becomes important. Raff’s object storage is S3-compatible, built for scale, and positioned as a separate storage layer for exactly those use cases. That matters because it changes how teams can structure applications on the platform. You stop thinking only in terms of: “Where is my server?” And you start thinking in terms of: “How should my application be shaped?” That is cloud thinking, not traditional hosting thinking. ## Advanced networking is part of the platform story too Another major difference is networking. Traditional hosting often assumes the workload is simple enough that basic connectivity is enough. One server, one public endpoint, one narrow environment. That is not how more serious teams operate for long. Once a stack becomes real, networking starts to matter: which services can talk to each other, how isolation works, where internal traffic lives, how security boundaries are managed, how cleanly environments can be separated. That is why [private cloud networks](/products/private-cloud-networks) matter so much in Raff’s product direction. They make it possible to think beyond “one VM on the public internet” and start shaping real infrastructure: - isolated internal environments - multiple subnets - policy-driven communication - lower-latency internal traffic - better architecture hygiene as the system grows That is a very different category of value than shared hosting or basic VPS packaging. ## The platform is moving toward higher-level layers too Another reason I do not want Raff framed as “just a VPS host” is that the platform direction is already visible. There are two especially important layers here: - [Kubernetes](/products/kubernetes) - [Raff Apps](/products/raff-apps) Kubernetes matters because it signals where orchestration, container-based scaling, and more structured application operations fit into Raff’s future. Not every team needs Kubernetes on day one. In fact, many do not. But it matters that the platform is being built with that next stage in mind. Raff Apps matters for a different reason. It represents a simpler application layer on top of infrastructure — a step toward making deployment easier without hiding the infrastructure so completely that teams lose control. Today, the public positioning is around one-click deployable applications. Over time, that direction opens the door to a more abstracted application experience as well. That is why I think the right way to describe Raff is not: “hosting” and not even only: “VPS.” It is a cloud platform that starts from useful infrastructure and expands upward into more capable layers. ## Why this matters for builders right now This is not just a branding issue. It affects how people choose infrastructure. If you think Raff is only a VPS provider, you compare it too narrowly. You compare CPU, RAM, disk, maybe a few support details, and stop there. But that misses the real question: what kind of platform will this become for my team once the first deployment is already working? That is the question more builders should ask. Because many teams do not fail by picking the wrong first server. They create friction later by picking a platform that makes the next stage awkward. The right infrastructure decision is not only about what helps you launch. It is also about what still makes sense after growth begins. That is where the broader Raff platform story matters. ## Simplicity still matters — but simplicity is not the same as limitation One thing I care about a lot is that broader platform vision should not automatically mean more complexity. That is where many infrastructure products go wrong. They add more services, more pages, more terminology, more surface area — and the result is a platform that feels more “complete” internally but less usable from the customer side. That is not what we want. Raff should feel simple at the point where teams need simplicity most: the beginning. That means: - launching fast - understanding the offering quickly - knowing what the next step is - not needing a giant architecture diagram before shipping something useful But simplicity should not mean the platform stops there. The right product feels approachable on day one and still meaningful on day one hundred. That is the standard I care about. ## What I think people should understand about Raff now If I had to summarize the shift in one sentence, it would be this: **Raff is not trying to modernize traditional hosting. It is trying to make practical cloud infrastructure easier to start and clearer to grow with.** That is why the stack matters. VMs matter. Object storage matters. Backups and snapshots matter. Private networking matters. Upcoming orchestration and application layers matter. Each one is a sign that Raff is not being built around a narrow hosting model. It is being built around the way real teams move from: one machine, to one stack, to one product, to one actual infrastructure footprint. That is a very different direction. ## What This Means for You If you are evaluating infrastructure right now, I would suggest changing the filter you use. Do not just ask: “Is this cheaper than traditional hosting?” or “Is this just another VPS product?” Ask: “What kind of platform is this becoming?” “Will it still make sense after my first deployment?” “Can I start simple without being trapped in a small model later?” That is the better question. If you want to evaluate Raff through that lens, start with the foundations: [Linux VMs](/products/linux-vm), [object storage](/products/object-storage), [private cloud networks](/products/private-cloud-networks), and the public [pricing page](/pricing). Then look at the platform direction beyond the first machine. That is where the real difference is. Raff is not trying to be old hosting with newer words. It is trying to be the kind of cloud platform that gives builders a clean place to start — and a real place to grow. --- ### What July 2025 Taught Us About Where Cloud Infrastructure Is Heading URL: https://rafftechnologies.com/blog/what-s-new-in-cloud-and-infrastructure-july-2025-update Published: 2025-07-21T00:00:00.000Z Description: What July 2025 Taught Us About Where Cloud Infrastructure Is Heading July 2025 looked, on the surface, like just another month of big cloud headlines. More investment. More AI infrastructure talk. More regional policy noise. More pressure on providers to explain why they deserve to be trusted with workloads that are becoming more expensive, more sensitive, and more business-critical. But when I look back at that period now, I think it revealed something more important. It showed that cloud infrastructure is no longer judged only by raw scale. It is increasingly judged by a different combination: performance, control, pricing clarity, and how easy it is for teams to actually move. That matters a lot to us at Raff, because we are not trying to win by copying hyperscalers. We are trying to build infrastructure that makes more sense for the teams that need to move fast without getting buried in complexity. ## The cloud conversation changed in a meaningful way For years, the cloud market was dominated by one broad assumption: bigger platform equals better answer. That logic made sense for a long time. The largest providers offered the deepest service catalogs, the widest region footprints, and the most mature enterprise relationships. If you needed everything, they were the natural starting point. But by mid-2025, the market was showing signs of a different kind of maturity. Teams were asking sharper questions. Not just: “Who has the most services?” But: “Who gives us the right amount of infrastructure without unnecessary drag?” “Who helps us stay flexible as requirements change?” “Who keeps pricing understandable once the project becomes real?” “Who lets us keep more control without forcing us into a giant platform mindset?” That is not a small shift. That is the beginning of a healthier buying behavior. ## AI demand changed what people expect from infrastructure One of the clearest changes in 2025 was that AI stopped feeling like a side conversation and started changing infrastructure expectations directly. Even teams that were not building foundation models were affected by it. Why? Because AI changes the surrounding market in at least three ways: - it increases demand for high-performance compute - it makes storage and networking choices more visible - it raises expectations around scalability and response time In other words, AI does not only affect “AI companies.” It affects everyone buying infrastructure in a market where compute quality, deployment speed, and resource pricing matter more than before. That is part of why I do not think small teams can afford to treat infrastructure as an afterthought anymore. You do not need a giant platform. But you do need a platform whose economics and performance profile still make sense once your workload becomes more serious. ## Cloud buyers started caring more about control again Another signal that stood out in that period was the growing focus on control. Sometimes that appeared as sovereignty language. Sometimes it showed up as compliance pressure. Sometimes it was simply teams becoming less comfortable with being deeply dependent on one giant provider for everything. I think this is one of the most important long-term shifts. Because when buyers start caring more about control, they also start caring more about platform shape. They ask questions like: - Can I understand this pricing model clearly? - Can I move my workloads without rewriting everything? - Do I know where my infrastructure is running? - Can I choose simpler building blocks instead of being pushed into a giant stack? This is exactly where focused cloud platforms become more interesting. Not because they are “bigger.” Because they are often easier to reason about. At Raff, that way of thinking influences a lot of our decisions. We care about giving teams usable building blocks like [Linux VMs](/products/linux-vm), [private cloud networks](/products/private-cloud-networks), [object storage](/products/object-storage), and [clear pricing](/pricing) instead of asking them to decode a massive product tree before launching something practical. ## Multi-cloud stopped sounding theoretical Another thing July 2025 reinforced for me was that multi-cloud thinking became more practical and less philosophical. For a while, multi-cloud was often discussed like a strategy deck concept. Something enterprises talked about because it sounded sophisticated. But what many teams actually wanted was simpler: they wanted optionality. They wanted to know they were not trapped. They wanted to choose the right platform for the workload. They wanted APIs, workflows, and deployment paths that did not force them into one model forever. That does not mean every startup suddenly needs a true multi-cloud architecture. Most do not. But it does mean buyers increasingly value infrastructure that fits into a broader strategy instead of limiting it. That is a very different mindset from the old “pick one giant platform and accept everything that comes with it” approach. ## The real lesson was not about Europe, Oracle, or OpenAI alone One thing I try to be careful about with market commentary is overreacting to individual headlines. A single investment announcement is not the strategy. A single partnership is not the future. A single policy push is not the whole market. The more useful question is: What do these headlines reveal when you step back? For me, the July 2025 answer was this: the market was rewarding infrastructure that feels more intentional. Intentional about performance. Intentional about cost. Intentional about control. Intentional about where the platform is going. That is the part I think founders and operators should pay attention to. Because a lot of cloud buying mistakes happen when teams optimize for prestige instead of fit. The biggest brand is not always the best operational decision. The broadest service catalog is not always the best starting point. And the cheapest headline number is definitely not always the best long-term value. ## What this changed in how I think about Raff When I look at those signals through Raff’s lens, I do not interpret them as “the market will automatically come to smaller platforms.” That would be lazy thinking. The real takeaway is more demanding. If focused cloud platforms want to matter, they need to earn that position by being clearer, faster, and more practical than the alternatives for the people they serve. That is how I think about Raff. We are not trying to imitate hyperscalers at smaller scale. We are trying to build something different: a cloud platform where teams can start with the fundamentals, stay in control, and keep moving without unnecessary friction. That is why we care so much about things that are easy to underestimate: - launch speed - understandable VM classes - storage and backup clarity - private networking that feels usable - infrastructure you can actually explain to your team - pricing that does not become a puzzle once the workload grows To me, that is what “cloud value” really means. Not just how much raw compute you can rent. But how clearly the platform supports the way you actually build. ## Smaller teams should read market shifts differently If you are a small team, a founder, an indie builder, or an early engineering group, market headlines can be misleading. They make it sound like the only meaningful cloud decisions happen at giant scale. But most real infrastructure decisions are much more grounded than that. You are usually deciding things like: - what should we launch first? - how much should we spend before usage justifies more? - do we need more services, or just cleaner infrastructure? - is our current platform helping us move, or just asking us to learn its logic? That is why I think smaller teams should read cloud market updates through a different lens. Do not ask: “What are the giants investing in?” Ask: “What does this trend tell me about what good infrastructure should feel like for my team?” That is a more useful question. ## Simplicity is becoming a stronger competitive advantage I believe this more now than I did a year ago: simplicity is not the opposite of serious infrastructure. It is one of the strongest signs of serious product thinking. When the market gets noisier, simpler products often become more valuable. When infrastructure gets more expensive, pricing clarity becomes more valuable. When teams get stretched thin, understandable workflows become more valuable. That does not mean “fewer features at all costs.” It means every piece of the platform should justify itself. That standard matters to me because there is a lot of fake simplicity in cloud right now. Products that look easy at the top and become messy underneath. Pricing that looks friendly until the surrounding costs show up. Infrastructure that looks flexible until you try to grow inside it. Real simplicity is harder than that. Real simplicity holds up after the first launch. ## What This Means for You If you are watching cloud trends, do not treat them like entertainment. Use them to improve your buying filter. The real lesson from that period was not that the cloud got louder. It was that buyers started asking better questions about value, control, and fit. That is a good thing. If you are evaluating infrastructure now, I would start here: - Do I understand how this platform will feel after the first deployment? - Will pricing still make sense if the workload grows? - Does the platform give me clean building blocks or just a crowded menu? - Am I choosing something because it is right for my team, or because it is the default name everyone recognizes? If you want to evaluate Raff through that lens, start with the fundamentals: [Linux VMs](/products/linux-vm), [private cloud networks](/products/private-cloud-networks), [object storage](/products/object-storage), and the public [pricing page](/pricing). That will tell you much more about the platform than any generic cloud trend summary ever could. That is how I look at these market shifts now. Not as proof that smaller cloud platforms automatically win. But as proof that clarity, control, and practical value matter more than ever. --- ### How to Launch a Virtual Machine in Seconds (Without the Complexity of Traditional VPS Hosting) URL: https://rafftechnologies.com/blog/how-to-launch-a-virtual-machine-in-seconds-without-the-complexity-of-traditional-vps-hosting Published: 2025-07-13T00:00:00.000Z Description: How to Launch a Virtual Machine in Seconds (Without the Complexity of Traditional VPS Hosting) Most people do not delay launching a VM because they lack ambition. They delay because too many infrastructure products make the first step feel heavier than it should. That has always bothered me. If you are a developer, founder, freelancer, or small team, your first server should feel like momentum. It should feel like progress. It should not feel like you just enrolled in a part-time course on legacy hosting terminology, pricing traps, and unnecessary setup friction. That frustration is one of the reasons we built Raff the way we did. ## The real problem was never the virtual machine A virtual machine is not a hard concept. You choose a configuration. You pick an operating system. You launch it. You connect. You start building. That is the basic promise. But in practice, many traditional VPS experiences wrap that simple workflow in too much friction. Confusing dashboards. Pricing that feels low until you start adding the basics. Platform language written for people who already know the system. Product decisions that make sense internally, but not from the customer’s side. For experienced infrastructure teams, some of that complexity is tolerable. For everyone else, it creates drag. And drag matters more than many cloud companies admit. If your first infrastructure decision costs you an extra afternoon, interrupts a project sprint, or makes a founder postpone testing an idea until “later,” that is not a small UX issue. That is lost momentum. ## What small teams actually need from a first VM When I think about the teams we want to help at Raff, I do not start with the question, “How many features can we stack onto a VM page?” I start with a simpler question: What does someone actually need to get moving without second-guessing the platform? Usually, it comes down to a few things: - fast provisioning - clear resource choices - predictable pricing - full control once the machine is live - confidence that the platform can still grow with them later That is a very different mindset from building a product page around maximum complexity. Most small teams do not need the broadest possible infrastructure catalog on day one. They need a clean starting point. That is why I think the first VM experience matters more than many providers realize. It is the moment where a product either feels like an enabler or another obstacle. ## Why we wanted Raff to feel simpler We built Raff for builders. That means we care about the time between “I need a machine” and “I’m working.” Not in a marketing way. In a very practical way. If someone wants to launch a Linux server, test a product idea, host an internal tool, run a development environment, or give a team member a clean cloud workspace, they should be able to do that without feeling punished for not being a full-time infrastructure specialist. That is also why simplicity cannot just mean “fewer buttons.” Real simplicity means the product still gives you the things that matter: - root access - current operating systems - useful storage - network and security basics - pricing you can understand before you commit - enough flexibility to keep building after the first launch In other words, the goal is not to make cloud infrastructure look smaller than it is. The goal is to remove the parts that make people hesitate for the wrong reasons. ## Fast does not just mean technical speed When people talk about speed in cloud infrastructure, they often mean raw performance. That matters, of course. But there is another kind of speed that I think matters just as much, especially for smaller teams: decision speed. Can you understand the offer quickly? Can you choose without overthinking? Can you launch without opening six tabs first? Can you tell what your next step is once the machine is live? That kind of speed is underrated. A platform can be technically powerful and still slow the user down. And for a lot of early-stage teams, that kind of slowdown is more expensive than people think. It delays experiments. It delays deployments. It delays learning. It makes infrastructure feel like homework instead of leverage. That is not the feeling we want Raff to create. ## Simple should not mean limited This is the trap some infrastructure companies fall into. They assume that if you make the first step easier, the product will look less serious. I think the opposite is true. A serious infrastructure product should be able to do both: - feel approachable at the beginning - stay useful as the workload grows That is how I think about Raff. Yes, we want the first launch to feel straightforward. Yes, we want the platform to feel cleaner than traditional VPS experiences. But that does not mean we want people to outgrow it immediately. It means the platform should meet teams where they are and give them a path forward. That is why the broader structure matters. A VM is not just a VM decision forever. Teams eventually care about backups, networking, storage, access patterns, and how everything fits together once the first machine becomes two, then five, then something more operationally real. The first experience still matters. But the long-term shape matters too. ## What I think traditional VPS products still get wrong I think many traditional VPS products still assume that friction communicates seriousness. That if the dashboard feels dense enough, the platform will look more professional. That if pricing is fragmented enough, the offer will look more customizable. That if the setup takes longer, the buyer will assume they are dealing with something more “enterprise.” I do not believe that. I think clarity is more professional than clutter. I think understandable pricing is more credible than a cheap-looking number followed by five caveats. And I think a fast first deployment is not a shortcut — it is respect for the customer’s time. The teams we care about are not asking for less control. They are asking for less unnecessary friction between intent and execution. That is a very different problem to solve. ## The business side of this matters too There is also a business reason I care about this so much. Small teams do not just buy infrastructure with money. They buy it with attention. If your team spends too much time navigating the platform instead of using it, the infrastructure has already become more expensive than it looked on the pricing page. That is why simplicity is not just a design preference. It is an economic advantage. A VM that launches quickly, feels understandable, and gives you control without making every step heavier than necessary creates a different kind of value. It saves setup time. It reduces hesitation. It helps teams move from idea to execution faster. And for startups, builders, and lean operators, that speed of execution matters a lot. ## What this means for you If you are evaluating cloud infrastructure right now, I would suggest asking a different question. Not: “Which provider has the longest feature list?” Ask: “Which provider will let my team start cleanly and still make sense when we grow?” That is a more useful filter. If what you need today is a clear place to launch a server, get control quickly, and avoid unnecessary friction, start there. Do not overbuy complexity just because it looks impressive on a comparison table. And if that is the lens you want to use on Raff, begin with the basics: [Linux VMs](/products/linux-vm), [Windows VMs](/products/windows-vm), and the public [pricing page](/pricing). Then explore the rest of the platform once the first deployment is already doing useful work. That is how I think infrastructure should feel. Not intimidating. Not bloated. Not artificially complicated. Just ready when you are. --- ### What Benchmark Rankings Do and Don’t Tell You About Cloud Value URL: https://rafftechnologies.com/blog/what-benchmark-rankings-do-and-dont-tell-you Published: 2026-04-02T00:00:00.000Z Description: What Benchmark Rankings Do and Don’t Tell You About Cloud Value A benchmark result can make you proud. It can also make you careless. That is the part I think founders, operators, and buyers all need to be more honest about. Recently, Raff appeared near the top of a public value-focused VPS ranking. As a founder, I was genuinely happy to see that. Not because I think one benchmark “proves” everything about a cloud company, but because third-party testing matters. It is one thing for us to say we offer strong performance for the price. It is another thing for an independent benchmark platform to test plans side by side and show that we belong in the conversation. Still, I think this is where many providers — and many buyers — make the same mistake. They treat a benchmark ranking like a complete answer. It is not. A benchmark can tell you something real. Sometimes something very useful. But it cannot tell you everything that makes infrastructure valuable once it becomes part of a real team’s workflow. ## A Good Benchmark Measures One Layer of the Truth What I like about benchmark rankings is simple: they force reality into the room. Marketing pages can say almost anything. Every provider talks about performance. Every provider talks about reliability. Every provider says they are simple, scalable, affordable, or developer-friendly. A third-party benchmark changes the conversation because it gives you an external point of reference. That matters. It matters even more for a younger company like Raff. Established providers already have brand recognition. Newer platforms need a way to show, in public, that they can compete on the fundamentals. A solid ranking does that. It tells people, “This provider deserves a closer look.” That is valuable. But even the best benchmark is still measuring a defined testing environment, a defined time window, and a defined scoring model. In other words: it tells you something meaningful, but not everything meaningful. ## What Benchmark Rankings Usually Tell You Well The first thing benchmark rankings usually tell you well is whether a plan is competitive on raw public performance for the price. That is a very important signal. If a provider is expensive and underperforming, that should raise questions immediately. If a provider is cheap but still shows up strongly in web performance, network performance, disk I/O, or CPU categories, that is worth paying attention to. Benchmark rankings are especially useful for filtering out noise at the top of the funnel. If you are comparing ten providers, you probably do not want to manually trial every single one from scratch. A serious public benchmark can help you reduce that list to three or four worth investigating. That is a big service to the buyer. It also helps highlight where a provider’s strengths actually are. A plan may look great on web performance and network speed, while being only average on stability. Another may be incredibly consistent but not especially strong on price-weighted value. That kind of nuance is useful because not every workload cares about the same bottleneck. In that sense, rankings are not just about who is “best.” They help you understand what kind of provider you may be looking at. ## What Benchmarks Do Not Tell You About Cloud Value This is where I think the real buying conversation starts. Cloud value is not just “how much performance do I get for this monthly number?” Cloud value is also: - how predictable the bill remains after success - how easy it is to recover from mistakes - how cleanly the platform grows with your team - how much friction shows up when you move beyond a single VM - how much confidence you have when something breaks at the wrong time A benchmark does not capture most of that. ### 1. It Does Not Show the Full Cost Shape A benchmark can compare plan price against measured performance. What it usually does not show well is the full economic shape of the platform around that plan. That matters more than many people realize. A provider may look cheap in a benchmark and become expensive in practice because of transfer limits, backup costs, IP charges, volume pricing, or the way upgrades compound as your system grows. Another provider may look slightly more expensive at first glance, but become easier to budget because the pricing model is cleaner and the platform does not punish normal growth. This is one of the reasons I care so much about predictability. For small teams, “cloud value” is not only about finding the lowest possible number. It is about finding a number you can still explain three months later when traffic grows, environments multiply, and your architecture becomes more real. ### 2. It Does Not Show the Product Direction A benchmark tells you how a tested plan performs. It does not tell you where the platform is going. That matters because most teams do not stay frozen at the same infrastructure maturity level forever. You may start with a single VM. Then you need private networking. Then object storage. Then a cleaner application deployment workflow. Then maybe databases, orchestration, or a more programmable infrastructure model. If the provider only makes sense at the exact stage you are in today, that is not full cloud value. That is temporary convenience. This is also how I think about Raff internally. Yes, today many people may first notice Raff as a VPS provider. That is fair. Compute is where we started publicly. But the point is not to stop there. We already think in terms of infrastructure layers, not isolated server sales. That is why [Linux VMs](/products/linux-vm), [private cloud networks](/products/private-cloud-networks), [data protection](/products/data-protection), and [object storage](/products/object-storage) matter so much in the shape of the platform. It is also why the next layers matter. A strong benchmark result is encouraging, but it is only one signal that the foundation is worth building on. ### 3. It Does Not Show Operational Experience One of the biggest gaps in benchmark-driven buying is this: A benchmark cannot tell you how a platform feels to operate. It cannot tell you if the dashboard is clear or confusing. It cannot tell you whether backup and restore workflows feel obvious under pressure. It cannot tell you whether support replies with a copied script or with a useful answer. It cannot tell you how many little pieces of friction accumulate between “I launched a server” and “my team can rely on this.” For a solo developer, some of that friction is manageable. For a small team, it compounds. Every ambiguous billing rule, every awkward restore flow, every infrastructure decision that requires a support ticket instead of a product feature — these things create real cost. Not always in dollars first. Often in hesitation, delay, and mental overhead. That is part of cloud value too. ### 4. It Does Not Know Your Actual Workload This part is important enough to say plainly: No benchmark knows your application. A price-weighted value ranking can be directionally useful, but it is still a general test suite. Your actual workload may care more about one category than another. Maybe you are running a lightweight SaaS backend where web performance and network responsiveness matter a lot. Maybe you are running CI jobs and care more about consistent CPU behavior. Maybe you are serving large assets and care more about storage throughput and bandwidth model. Maybe you are hosting a stateful application where backup policy and restore simplicity matter more than any synthetic score. If you treat a benchmark as final truth rather than strong screening data, you will eventually optimize for the wrong thing. ## How I Think Small Teams Should Use Benchmark Rankings My advice is simple. Use benchmark rankings as a filter, not as a verdict. A good flow looks like this: 1. Use benchmark results to shortlist serious candidates. 2. Check whether the pricing model still makes sense after growth. 3. Look at backups, snapshots, networking, and storage — not just the VM. 4. Ask whether the platform matches the stage your team is entering, not just the stage you are leaving. 5. Run your own real-world test on the finalists. That last point matters a lot. The smartest infrastructure buyers I know do not stop at public rankings. They use them to save time, then they test the short list using their own application shape, their own deployment flow, and their own priorities. That is how you move from “interesting benchmark result” to “good long-term platform decision.” ## What This Ranking Meant to Me as a Founder From my perspective, a good public benchmark result is exciting for one main reason: it tells us the foundation is strong enough to earn attention. That is all. It does not mean “mission accomplished.” It does not mean “we won.” It does not mean benchmarks should replace product thinking. What it does mean is that the work underneath the platform is showing up in a way the market can independently observe. That matters. Because the real ambition behind Raff has never been to become “just another VPS provider with a decent score.” The ambition is to build a cloud platform that starts simple, stays understandable, and grows with the teams that use it. That is a much bigger challenge than posting a good benchmark image on social media. It means the fundamentals have to be there. It means the pricing has to remain understandable. It means the product layers beyond compute have to become real and useful. And it means we have to keep earning trust long after the benchmark page refreshes. That is how I think about it internally. A benchmark is not the destination. It is evidence that the road we are on is worth continuing. ## What This Means for You If you are evaluating cloud providers, do not ignore benchmark rankings. They are useful. They are healthy. They are one of the best ways to cut through vague marketing. But do not stop there. Ask harder questions: - What happens to my cost if this workload succeeds? - How easy is it to back up, restore, and isolate my infrastructure? - Does this provider make sense only for my first VM, or for my next stage too? - Am I buying a server, or choosing a platform direction? That is the difference between chasing a good-looking score and making a good infrastructure decision. If you want to evaluate Raff through that lens, start with the basics: our [Linux VM plans](/products/linux-vm), [private networking](/products/private-cloud-networks), [object storage](/products/object-storage), and [pricing](/pricing). Then compare those pieces against the providers on your shortlist — not just on benchmark charts, but on the parts of cloud value your team will actually feel every week. That is the standard I would use as a buyer. It is also the standard we are building toward as a company. --- ### Logs, Metrics, or Traces? What Small Teams Need First URL: https://rafftechnologies.com/blog/logs-metrics-traces-small-teams Published: 2026-03-31T00:00:00.000Z Description: Logs, Metrics, or Traces? What Small Teams Need First ## Most teams buy complexity before they buy clarity The observability conversation usually starts in the wrong place. A team launches an API, adds a worker, maybe plugs in Redis, and the first question becomes: “Should we set up logs, metrics, or traces?” The more honest question is simpler: when production feels wrong at 2:13 a.m., which signal will actually help you recover first? My view is not fashionable, but it is practical: most small teams should start with **metrics first**, add **structured logs second**, and only invest seriously in **traces** when the request path has become distributed enough to justify the extra instrumentation, storage, and mental overhead. That is not an argument against tracing. Tracing is powerful. In some architectures, it becomes essential. But the industry has a bad habit of turning “all three matter” into “you need all three immediately.” Those are not the same statement. At Raff, when we think about default operability for teams running on VMs, we bias toward telemetry that does three things well: it tells you something is wrong early, it narrows the blast radius quickly, and it stays understandable to a lean team without a dedicated observability engineer. That bias changes the order. ## What each signal is actually good at Before talking about order, it helps to strip the jargon out of the terms. **Metrics** tell you that something is changing over time. CPU climbs. Memory gets tight. Error rate jumps. Queue depth grows. P95 latency drifts upward. Metrics are compact, cheap to aggregate, and ideal for dashboards and alerts. **Logs** tell you what happened at a specific moment. A user failed authentication. A database connection timed out. A deploy changed an environment variable. A payment provider returned an unexpected response. Logs are rich, descriptive, and often messy. They explain events in detail, but they can drown you if you treat them like a primary alerting system. **Traces** tell you where time was spent across a request path. A trace follows a single transaction as it moves through your application and dependencies. It becomes especially useful when one request touches multiple services, queues, databases, and third-party APIs. That distinction matters because these signals solve different problems. Metrics answer: **Is the system healthy?** Logs answer: **What happened?** Traces answer: **Where in the path did it break or slow down?** If you try to use one signal for every question, you end up with a noisy stack and very little clarity. ## Why metrics should usually come first If I had to choose one signal for a small team starting from zero, I would choose metrics without hesitation. The reason is simple: metrics are the fastest route from “something feels off” to “this area needs attention.” They are lightweight enough to collect continuously, structured enough to alert on automatically, and broad enough to describe system health before you know the exact failure mode. That makes them your best first line of defense. A small team usually needs answers to a short list of questions before anything more advanced: - Is the server under resource pressure? - Is the application error rate rising? - Is request latency trending up? - Is the queue backing up? - Is the database responding more slowly than normal? - Did a deploy correlate with a sudden change? Metrics answer those questions cleanly. They also create the habit that matters most in operations: defining what “normal” looks like before something breaks. This is where a lot of teams go wrong. They install logging, skim a wall of text, and call that observability. It is not. It is exhaust. Without metrics, you are waiting to notice a problem reactively. With metrics, you can detect it proactively. That difference matters more than people think, especially when your infrastructure is still simple. If your application is running on one or two [Linux VMs](/products/linux-vm), one database, and a worker process, good metrics already cover a surprising amount of ground. CPU saturation, memory pressure, disk I/O, error rate, response time, queue depth, and restart frequency will tell you where to look long before a tracing system becomes necessary. ## Why logs come second — but not as raw noise Logs are the second layer because once metrics tell you **where** to look, logs usually tell you **why**. But there is a catch: logs only become useful at scale when they are structured and intentional. A lot of teams say they “have logs” when what they actually have is a terminal full of inconsistent strings written by different developers in different moods over six months. That is not observability. That is archaeology. If you want logs to work for you, you need to make them queryable. That means logging in a structured format, usually JSON, and attaching a consistent set of fields such as: - timestamp - level - service - environment - version - request ID - correlation ID - job ID where relevant Once you do that, logs stop being random narrative and start becoming evidence. This is also why I put logs after metrics, not before. Logs are rich, but they are expensive in every sense: storage, cardinality, indexing, retention, and human attention. They scale badly when your first question is “Is the system healthy?” They scale well when your first question is “What exactly happened inside the component metrics just pointed me toward?” That is the right relationship. Metrics tell you the API error rate doubled after the deploy. Logs tell you the payment adapter is throwing a null reference only in the `eu-west` environment. Metrics tell you queue latency spiked. Logs tell you one worker version is failing to deserialize a job payload. Metrics tell you the database is slow. Logs show the ORM suddenly issuing an N+1 query pattern. If metrics are your radar, logs are your incident notebook. ## When traces become worth the effort Now the controversial part. Tracing is powerful, but for many small teams it is not the first missing piece. It is the third one. If your system is still mostly one application, one worker tier, and one database, traces can absolutely help — but they are often not the thing standing between you and operational clarity. In that stage, poor metrics and poor logs are usually the bigger problem. Tracing becomes worth the effort when the system stops being legible as a single unit. That usually happens when requests begin crossing multiple boundaries: - service-to-service network calls - async queues and background jobs - third-party APIs with variable latency - separate ownership across domains - retries, fallbacks, and partial failure paths - multiple databases or datastores in one request lifecycle That is when traces stop being nice to have and start becoming operationally important. The reason is not just that traces are “cooler” or more modern. It is that distributed systems create failure paths that logs and metrics alone explain poorly. Once one user action fans out across multiple services, you need request-level visibility to understand where time went and which dependency introduced failure or latency. This is why tracing shines in microservices, queue-heavy applications, and integration-heavy systems. It is also why I do not recommend forcing it too early onto every small app. You end up instrumenting for a topology you do not actually have yet. There is another practical point here: tracing gets much better when it is correlated with logs. Once trace IDs, service names, environment tags, and version fields are shared consistently, traces and logs stop competing and start reinforcing each other. Until then, teams often blame tracing when the real problem is inconsistent telemetry design. ## The order I recommend for small teams on Raff If you are running a lean application on Raff today, this is the sequence I would recommend. ### 1. Start with infrastructure and application metrics Get basic host and app health visible first. Track CPU, RAM, disk, network, error rate, response latency, restarts, queue depth, and database latency if you can. Build a small dashboard. Add a few alerts that you will actually respect. Not fifty. A few. The goal is not “full observability.” The goal is knowing when the system moves outside normal behavior. ### 2. Add structured logs with correlation IDs Once metrics tell you where pain is appearing, structured logs let you investigate without guessing. Make logs machine-readable. Add request IDs. Make sure deploy version and environment are included. Keep log levels disciplined. Do not dump every debug detail into production forever and call that maturity. ### 3. Add traces when request paths earn them When the system starts crossing enough boundaries that cause-and-effect becomes blurry, add tracing deliberately. Not because a vendor told you the stack is incomplete without it. Because you now have a real problem tracing is good at solving. ### 4. Correlate the signals instead of treating them as separate products This is the maturity step that matters. Metrics should lead you to the incident. Logs should explain the event. Traces should expose the path. If they do not connect cleanly, you do not really have observability yet. You just have three storage systems. ## The mistake behind most observability waste Most waste in observability does not come from buying the wrong tool. It comes from solving the wrong stage problem. A team with one service, one queue, and one database buys a tracing-first stack because it sounds advanced. Meanwhile, they still have no reliable latency alert, no deploy markers in dashboards, no structured error logs, and no agreement on what “healthy” means. That team does not need more telemetry types. It needs clearer fundamentals. This is the same pattern we see in infrastructure more broadly. Teams often jump to the advanced version of the solution before the simpler version has actually failed. They start with Kubernetes when a VM would do. They split into microservices when a modular monolith would do. They instrument traces everywhere when metrics and logs would answer most incidents faster. I am not against any of those tools. I am against using them to skip the discipline of asking what problem exists right now. ## What This Means for You If your team is deciding what to monitor first, keep the sequence simple. Start with **metrics** because they tell you when the system leaves the healthy path. Add **structured logs** because they explain what happened inside that unhealthy window. Add **traces** when your architecture becomes distributed enough that request flow is no longer obvious from metrics and logs alone. That order is not anti-modern. It is pro-clarity. If you are building on Raff, begin with a lean VM setup you can understand, instrument, and improve over time. Our [Linux VM plans](/products/linux-vm) and public [pricing page](/pricing) make that staged approach straightforward. Then pair this post with [Single-Server vs Multi-Server Architecture](/learn/guides/single-server-vs-multi-server-architecture) and [Dev vs Staging vs Production](/learn/guides/dev-staging-production-cloud-environments), because observability quality is tightly tied to how you structure environments and failure domains. My rule of thumb is simple: do not instrument for the architecture you imagine you might have next year. Instrument for the one that can wake you up tonight. --- ### Cloud VMs for Hackathons: How to Launch Fast and Stay Focused URL: https://rafftechnologies.com/blog/cloud-vms-for-hackathons-how-to-launch-fast-and-stay-focused Published: 2025-07-05T00:00:00.000Z Description: Cloud VMs for Hackathons: How to Launch Fast and Stay Focused Hackathons are won in the first few hours more often than people admit. Not because the final pitch is decided that early, but because momentum is. If your team spends the beginning of a 24- to 72-hour sprint installing dependencies, fixing laptop-specific issues, and explaining local setup to every teammate, you start the event with less energy than the teams already building. That is why cloud VMs are such a practical hackathon tool. A cloud VM is a remote virtual machine that gives your team a clean, ready-to-code environment without depending on one person’s laptop, one operating system, or one fragile local setup. At Raff, we think that matters because hackathons reward focus, speed, and iteration far more than they reward infrastructure cleverness. ## The real enemy at a hackathon is setup drag Most hackathon teams think they are racing the clock against other teams. In practice, they are usually racing against wasted setup time. You see the same problems over and over: * one teammate is on Windows, another is on macOS, another is on Linux * Docker behaves differently on each machine * the backend needs more RAM than someone’s laptop can comfortably spare * a package that worked last week suddenly breaks on a fresh install * the team loses an hour just getting everyone into the same environment None of that wins points. None of it improves the product. It just burns the short window you were supposed to use for shipping. A cloud VM fixes that by giving you a neutral workspace. Instead of making the project adapt to everyone’s local machine, you make the environment consistent first and let the team build on top of that. ## Why hackathons pair so well with cloud VMs A hackathon project usually has three needs at the same time: speed, flexibility, and disposability. You need to move quickly because the deadline is measured in hours, not quarters. You need flexibility because the idea may change halfway through the event. And you need disposability because this environment may only matter for one weekend. That is exactly where virtual machines shine. A VM gives you a full operating system, root access, predictable resources, and a clean place to run the stack you actually want. If you need Docker, Node.js, Python, PostgreSQL, Redis, Nginx, or all of them together, you can build that environment once and let the team work against it. If the idea changes, you can resize, rebuild, or throw the machine away without dragging your personal device through the process. This is one reason we like the VM model so much for short sprints. It is flexible enough for serious work, but simple enough that you do not need an ops team to get moving. ## Why we think simple infrastructure wins hackathons This is where our product philosophy matters. At Raff, we have deliberately kept the platform centered on practical infrastructure building blocks instead of burying users under a giant service catalog on day one. For hackathon teams, that is usually the right trade-off. You do not need a long architecture workshop before you launch. You need a server, an operating system you already understand, enough resources to build and demo, and a pricing model you can explain without opening a second spreadsheet. That decision becomes even more important when the team is tired. The best hackathon infrastructure is not the most impressive on paper. It is the setup that disappears into the background fast enough for the team to keep building. ## What a strong hackathon VM setup looks like A good hackathon VM setup is not complicated. It usually looks like this: ### One shared development base Start with one machine that acts as the team’s consistent environment. This can be where the backend runs, where dependencies are installed, where the API is tested, or where the group stores the working stack everyone needs to reference. ### Clear separation between code and machine Use Git for the code and the VM for the environment. That sounds obvious, but it matters. The point is not to make the VM the only place your work exists. The point is to make it the cleanest place to run the work. ### Enough headroom to avoid laptop pain Hackathons often create awkward workloads: AI experiments, Docker containers, browser automation, background services, live demos, local databases, or image processing tasks. These are exactly the workloads that can make a personal laptop feel overloaded at the worst possible moment. ### Disposable by design The machine should feel temporary. That mindset helps you move faster. You are not designing a forever-environment. You are building a fast, useful workspace for a short, high-pressure sprint. ## Where hackathon teams usually lose time The time loss is rarely dramatic. It is cumulative. Ten minutes fixing package conflicts. Twenty minutes figuring out which Node version everyone has. Fifteen minutes explaining Docker setup to the one teammate who has never used it. Another fifteen minutes because one person’s laptop starts thermal throttling during a demo build. That is how half a day disappears. A cloud VM does not eliminate every problem, but it removes a category of problems that should never decide the outcome of a hackathon in the first place. If everyone can target the same environment from the start, you reduce the number of moving parts that have nothing to do with the idea you are trying to ship. ## When to use one VM and when to use two Not every team needs multiple machines. For many hackathons, one well-chosen VM is enough. It gives you a place to run the app, test the environment, and host a preview or demo without spreading the team too thin. Two VMs can make sense when: * one machine is for development or build tasks * the second is for demo or staging * you want to avoid breaking the pitch environment while still shipping changes * the team is splitting frontend and backend work and wants a cleaner boundary If you are unsure, start with one. Simpler setups usually win under time pressure. You can always grow from there if the project proves it needs more structure. If your team wants a better mental model for this, our guide on [dev, staging, and production environments](/learn/guides/dev-staging-production-cloud-environments) is useful because it explains when separate environments help and when they are unnecessary overhead. ## Choosing the right environment without overthinking it The fastest hackathon setup is usually the one closest to what your team already knows. If the team is comfortable on Ubuntu, use Ubuntu. If the app is containerized, bring Docker into the environment quickly. If you want a cleaner understanding of provisioning options, our guide on [VM provisioning models](/learn/guides/vm-provisioning-models-cloud-init-custom-images-one-click) is the right background read, but for a hackathon the answer is usually simple: pick the fastest path to a known-good machine. This is not the moment to optimize for theoretical perfection. It is the moment to choose a setup your team can trust under deadline pressure. That principle also applies to the architecture itself. If the project can run on one VM, do that. If you need a reverse proxy and one app process, keep it there. If you need separate services, use them because the project needs them, not because the diagram looks more impressive. ## Why cloud VMs beat “everyone just use your laptop” There is nothing wrong with local development. But hackathons create exactly the kind of messy, high-speed collaboration where local-only workflows become fragile. A VM gives you: * consistency across teammates * a place to run demos outside personal hardware * cleaner collaboration for backend services * fewer surprises from OS differences * a safer way to test realistic deployment behavior That last part matters more than people think. Hackathon teams often build something that works locally but behaves differently the moment it leaves the laptop. A cloud VM closes that gap early, which makes the final demo more reliable. If you want to understand the trade-offs more deeply, our guide on [Docker vs. virtual machines](/learn/guides/docker-vs-virtual-machines-when-to-use) is useful. In short, containers are great for packaging applications, but VMs are still the practical base layer when you need a full environment you can trust during a sprint. ## Cost matters, but predictability matters more Hackathon teams are usually cost-sensitive. Students, indie developers, small teams, and early-stage founders do not want a weekend project to turn into a platform surprise. That is why predictability matters so much. It is not enough for infrastructure to be affordable in theory. It needs to be understandable in practice. One reason we emphasize simple infrastructure at Raff is that short-term projects should not force long-term financial anxiety. If a team needs a VM for a sprint, they should be able to launch it, use it, and shut it down without spending the entire event wondering what the final bill will look like. That is the practical cloud-economics lesson behind hackathons: simple infrastructure helps teams stay creative because it removes operational doubt from the middle of the project. ## A realistic hackathon workflow on Raff A practical flow looks like this: 1- Choose one Linux VM as the shared project base. 2- Install the core runtime or container tooling the team needs. 3- Put the project in Git and use the VM as the common execution environment. 4- Test early from outside the machine, not just from localhost. 5- Protect the environment from last-minute chaos by deciding what changes are safe before the demo window. 6- Shut it down, snapshot it, or keep it if the project deserves another week of work. That is not glamorous infrastructure. It is useful infrastructure. And useful infrastructure is what wins these events. ## What This Means for You If your next hackathon matters, treat environment setup like part of the competition. You do not need a huge cloud architecture. You need a fast, consistent place to build, test, and demo without sacrificing the first hours of momentum to dependency issues and laptop limitations. For most teams, that means one simple cloud VM, a familiar Linux environment, and just enough structure to keep the build stable while the idea evolves. That is exactly the kind of workflow Raff is built to support. Start with [Raff pricing](/pricing), review the [Linux VM options](/products/linux-vm), and keep your next hackathon environment focused on one thing: helping your team ship more before the deadline hits. --- ### AI Workloads on Cloud Infrastructure: What Changes When the App Gets Heavier? URL: https://rafftechnologies.com/blog/ai-workloads-cloud-infrastructure-heavier-apps Published: 2026-03-17T00:00:00.000Z Description: AI Workloads on Cloud Infrastructure: What Changes When the App Gets Heavier? AI workloads do not stress infrastructure in the same way as a typical web app. As models get larger and requests become more complex, the bottleneck shifts from simple CPU and RAM scaling to a broader system problem involving compute, storage, networking, and scaling behavior. A traditional SaaS application becomes heavier in predictable ways: more users, more database queries, more background jobs. AI applications behave differently. A single request can consume significantly more memory, take longer to process, and introduce unpredictable latency. If you treat an AI app like a normal app with higher CPU usage, you will run into problems—usually in production. --- ## What Actually Gets “Heavier”? When teams say their AI workload is getting heavier, they usually mean one (or more) of the following: - The model size increases - Requests take longer to complete - Memory usage grows significantly - Traffic becomes bursty and unpredictable - Latency requirements become stricter This changes the core infrastructure questions: - How fast can the model load? - Can storage keep up with the workload? - Will cold starts hurt user experience? - Can the system scale without wasting money? - Do we need specialized compute? At this point, infrastructure stops being a background concern and becomes a product decision. --- ## Compute Stops Being Generic For most applications, scaling compute is straightforward: add more CPU and RAM. AI changes that. Some workloads still run well on CPUs: - Lightweight inference - Data preprocessing - API orchestration - Background jobs But as workloads grow heavier, compute becomes a strategic decision: - **CPU-first** → cheaper, simpler, good for early-stage AI features - **GPU-backed** → required for larger models or low-latency inference - **Hybrid setups** → separate application logic from model-serving infrastructure The key is separation. You don’t want expensive compute doing work that cheaper machines can handle. --- ## Storage Becomes a Performance Layer In traditional apps, storage is mostly about capacity. In AI workloads, storage directly affects performance. Large models, embeddings, and artifacts must be loaded quickly. Slow storage leads to: - Longer startup times - Higher latency - Poor scaling behavior Fast local storage (like NVMe SSDs) becomes important for: - Model loading - Temporary data - Caching As workloads grow, storage design becomes part of your performance architecture—not just a backend detail. --- ## Network and Latency Start to Matter More AI systems are rarely a single service. They often include: - Frontend/API layer - Inference service - Data or vector storage - Logging and monitoring systems This increases internal traffic. Two things start to matter: 1. **Latency between services** 2. **Reliability of internal communication** Private networking becomes valuable because it: - Keeps internal traffic secure - Reduces exposure to public internet latency - Improves consistency between services At small scale, you can ignore this. At larger scale, you cannot. --- ## Scaling Gets Slower and More Expensive Scaling a normal app is simple: > Add more instances → put them behind a load balancer AI workloads break this assumption. New instances may take time to become useful because they need to: - Load models - Initialize runtimes - Warm caches This creates new challenges: - Cold starts become visible to users - Autoscaling reacts slower - Idle capacity becomes expensive Scaling decisions now involve trade-offs: - Cost vs readiness - Latency vs utilization - Simplicity vs control Autoscaling is no longer just “add more servers”—it becomes workload-aware. --- ## Reliability Looks Different for AI Systems Heavier applications are not just more expensive—they are often more fragile. Common failure points include: - Model servers failing to start - Memory limits being exceeded - Latency spikes under load - Dependencies slowing down the entire request This shifts how you think about reliability: - Redundancy is essential - Health checks become critical - Failover must be tested - Backups must include more than just data Infrastructure alone does not guarantee reliability—system design does. --- ## A Practical Path for Growing AI Workloads Most teams don’t need to jump into complex infrastructure immediately. A realistic progression looks like this: | Stage | What Changes | Infrastructure Focus | |------|-------------|--------------------| | Early feature | Small models, low traffic | Simple CPU-based VMs | | Growth phase | More memory and longer requests | Stronger compute, better monitoring | | Production | Latency and uptime matter | Load balancing, private networking | | Heavy workloads | Large models and slow startup | Storage optimization, caching | | Mature system | Multiple services | Scaling strategy, failover design | The goal is not to over-engineer early—but to evolve architecture as pressure increases. --- ## What This Means in Practice The biggest shift with AI workloads is not just higher resource usage. It is **interdependence**. - Storage affects latency - Network affects reliability - Compute affects cost - Scaling affects user experience Everything becomes connected. That is why heavier AI applications require better infrastructure thinking—not just bigger machines. --- ## Conclusion When an AI application gets heavier, the problem is no longer just scaling a server. You are managing a system where compute, storage, networking, and scaling behavior all interact. The right approach is not to overbuild from day one, but to understand where the pressure is coming from: - Is it compute? - Is it storage? - Is it latency? - Is it scaling behavior? Once you identify the bottleneck, you can make smarter infrastructure decisions. That is how you build AI systems that are not just powerful—but reliable, efficient, and scalable. --- ### Why Raff Is a Solid VPS Choice for Growing Teams URL: https://rafftechnologies.com/blog/why-raff-is-a-solid-vps-choice Published: 2026-02-24T00:00:00.000Z Description: Why Raff Is a Solid VPS Choice for Growing Teams Choosing a VPS provider is not just about CPU, RAM, or the lowest monthly price. For most growing teams, the real questions are simpler: - How fast can we launch? - How easy is it to manage? - How quickly can we get help when something breaks? - Can this platform grow with us beyond a single virtual machine? That is where provider choice starts to matter. Some teams need a massive ecosystem. Others just need infrastructure that is fast to provision, easy to understand, and flexible enough to support real workloads without adding unnecessary complexity. For teams in that second group, **Raff** is a strong option. --- ## What Companies Actually Need From a VPS Provider When companies compare VPS providers, they usually care about a handful of practical things: - predictable pricing - fast provisioning - reliable performance - simple networking - automation options - responsive support - a clear migration path These are operational needs, not marketing features. A good VPS provider should reduce friction for engineering teams, not create more of it. That is especially true for startups, agencies, product teams, and lean engineering organizations that need to move quickly. --- ## Why Teams Switch VPS Providers in the First Place Companies rarely move infrastructure just because of raw specs. They move because day-to-day operations start getting painful. Common reasons include: - slow or clumsy provisioning workflows - support that is hard to reach when issues are urgent - confusing billing or bandwidth rules - weak automation options - migration that feels harder than it should be In other words, teams do not just buy servers. They buy **speed, clarity, and confidence**. --- ## Where Raff Stands Out Raff is a solid VPS choice because it focuses on the things modern teams actually use every day. ### 1. Fast deployment without unnecessary friction If your team needs infrastructure quickly, speed matters. Raff is built around fast VM provisioning and a simpler workflow for getting from account creation to a running server. That matters for: - urgent test environments - staging infrastructure - customer demos - new product environments - short feedback loops for engineering teams When infrastructure is fast to launch, teams spend less time waiting and more time shipping. --- ### 2. Strong support when infrastructure becomes urgent Support quality matters more than many teams realize. A VPS provider can look similar on a pricing page, but the real difference shows up when you need help under time pressure. Responsive support becomes critical when you are dealing with: - network issues - deployment problems - migration questions - production incidents - configuration uncertainty For growing teams, strong support reduces operational stress and shortens downtime. That is not a small advantage. It is part of the product. --- ### 3. Migration help lowers switching risk Migration is one of the biggest reasons companies stay with infrastructure they are no longer happy with. Even when pricing or experience is not ideal, teams often delay switching because they do not want to deal with: - moving workloads - recreating environments - reconfiguring networking - validating application behavior after migration That is why migration assistance matters. A provider that helps teams move workloads reduces one of the biggest barriers to adoption. --- ### 4. More than just a basic VPS dashboard A modern infrastructure platform should do more than let you click “Create VM.” Teams increasingly need: - automation through APIs - infrastructure as code - private networking - storage options - a path toward more advanced workloads Raff fits that direction well. It starts with virtual machines, but it also supports a broader infrastructure workflow for teams that want more control and flexibility over time. --- ## Raff Is Built for Teams That Want to Grow Without Replatforming Too Early One of Raff’s strongest positioning advantages is that it is not limited to “just another VPS.” Teams can start with simple virtual machines and still have room to expand their architecture over time. That matters for companies that expect to grow from: - one VM to multiple environments - manual deployment to API-driven automation - simple services to more structured infrastructure - direct server hosting to storage, networking, and orchestration needs If that sounds like your roadmap, a platform that already points in that direction is valuable. For example, if you are thinking about edge protection or proxying traffic in front of your infrastructure, you may also want to read [When Cloudflare Isn’t Enough: Why Developers Still Need a VPS](/blog/cloudflare-vs-vps-why-developers-still-need-a-server) and [How to Host Your App on a VPS with Cloudflare](/blog/host-app-on-vps-with-cloudflare). If your team is moving toward container orchestration, see [Should I Run Kubernetes on a VPS?](/blog/should-i-run-kubernetes-on-a-vps) and [How to Run a Kubernetes Cluster on a VPS (Step-by-Step)](/blog/run-kubernetes-cluster-on-vps-step-by-step). And if you are thinking about modern storage architecture, read [Why Use S3 with a VM? Object Storage Explained](/blog/why-use-s3-object-storage-with-vm). --- ## Who Raff Is a Good Fit For Raff makes the most sense for teams that want simplicity without giving up flexibility. That includes: - startups launching early production workloads - SaaS teams running APIs and backend services - agencies managing staging or client environments - developers running Docker-based applications - teams that want API-driven infrastructure workflows - companies that may later expand into Kubernetes, object storage, or more advanced networking This is especially valuable for teams that do not want a heavy platform experience on day one. --- ## Common Workloads That Fit Well on Raff A strong VPS platform should support real-world workloads, not just theoretical use cases. Examples include: - backend APIs - Docker containers - internal tools - staging environments - CI/CD runners - proof-of-concept environments - customer demo environments - Kubernetes test clusters - application workloads that need private networking That is the practical lens companies should use when evaluating a VPS provider. Not “Which platform has the longest feature list?” Instead: **Which platform helps us run our workloads with less friction?** --- ## Why “More Than VPS” Matters For many teams, the first purchase is a VM. But that is rarely where infrastructure stops. Over time, teams often need: - object storage for files and backups - private networks between workloads - automation through APIs and Terraform - a more structured way to run containers - a path toward Kubernetes That is why it is useful to choose a provider that can support both your current needs and your next layer of complexity. Raff’s direction makes sense for companies that want to start simple and grow deliberately. --- ## FAQ ### Is Raff only for basic VPS hosting? No. Raff starts with virtual machines, but it also fits teams that need automation, networking, and a broader infrastructure path as they grow. ### Can Raff help with migration? If your team is moving from another environment, migration help can reduce the operational burden of switching infrastructure and speed up onboarding. ### Is Raff a good fit for startups? Yes, especially for startups that want fast deployment, simpler infrastructure workflows, and a platform that can expand with their needs. ### Does Raff support teams that want automation? Yes. Teams that want infrastructure automation, repeatable workflows, and developer-friendly operations should care about API and infrastructure-as-code support from the beginning. --- ## Final Thoughts The best VPS provider is not always the one with the most features or the biggest name. It is the one that helps your team move faster with fewer operational headaches. For companies that care about: - fast infrastructure setup - responsive support - migration help - automation options - room to grow beyond a single VM Raff is a solid choice. If your team wants a VPS provider that feels practical, developer-friendly, and built for real workloads, Raff is worth serious consideration. --- ### How to Deploy a Production Docker Server on a VPS (2026 Guide) URL: https://rafftechnologies.com/blog/aws-ec2-vs-raff-vps-cost-comparison-2026 Published: 2026-03-04T00:00:00.000Z Description: How to Deploy a Production Docker Server on a VPS (2026 Guide) # AWS EC2 vs Raff VPS: Cost Comparison for Developers (2026) Choosing the right infrastructure is one of the first decisions developers make when launching a project. Two common options are **hyperscale cloud platforms like AWS EC2** and **modern VPS providers like Raff Technologies**. While both offer virtual servers, they are designed for different use cases. In this article, we compare **AWS EC2 and Raff VPS** in terms of pricing, simplicity, and developer experience. --- ## What is AWS EC2? Amazon EC2 (Elastic Compute Cloud) is one of the most widely used cloud computing services in the world. It allows developers to run virtual machines in Amazon’s global cloud infrastructure. AWS provides hundreds of instance types and integrates with many services such as: - managed databases - load balancers - serverless functions - monitoring tools Because of this ecosystem, AWS is extremely powerful — but it can also become complex and expensive for smaller workloads. --- ## What is Raff VPS? Raff Technologies provides **developer-friendly cloud VPS servers** designed to be simple, fast, and affordable. Instead of complicated billing models, Raff offers **clear monthly pricing** with high-performance infrastructure. Typical Raff VPS features include: - AMD EPYC CPUs - NVMe SSD storage - predictable pricing - instant VM deployment - built-in DDoS protection For many developers, this makes infrastructure easier to manage. --- ## Pricing Comparison Let’s compare a typical backend server configuration. | Provider | vCPU | RAM | Storage | Monthly Price | |--------|------|------|------|------| | AWS EC2 | 4 | 16 GB | EBS | ~$120+ | | Raff VPS | 4 | 8 GB | NVMe | $19.99 | AWS pricing may increase further depending on: - bandwidth usage - storage volumes - monitoring services - load balancers With VPS platforms like Raff, the pricing is typically **fixed and predictable**. --- ## Infrastructure Complexity AWS EC2 is part of a very large ecosystem. Launching a production workload often involves: - EC2 instances - VPC networking - EBS storage - load balancers - security groups - monitoring tools For large companies this flexibility is powerful. But for individual developers or startups, this complexity can slow things down. With a VPS platform like Raff, developers can simply: 1. Launch a server 2. SSH into the machine 3. Deploy their application This simplicity is one of the main reasons many developers choose VPS infrastructure. --- ## When AWS EC2 Makes Sense AWS is still a great choice when you need: - massive scalability - multi-region deployments - complex enterprise architecture - advanced managed services Large companies often rely on AWS because of its global infrastructure. --- ## When Raff VPS Makes More Sense A VPS solution like Raff is often ideal for: - SaaS startups - developer projects - backend APIs - Docker servers - self-hosted applications For many of these workloads, a single VPS can run production services reliably at a much lower cost. --- ## Final Thoughts AWS EC2 remains one of the most powerful cloud platforms available. However, many developers do not need the full complexity of hyperscale cloud infrastructure. Modern VPS platforms like **Raff Technologies** provide a simpler alternative — offering strong performance, predictable pricing, and fast deployment. For developers building new projects in 2026, the decision often comes down to this: **Use AWS when you need hyperscale infrastructure. Use a VPS like Raff when you want simplicity, performance, and predictable costs.** --- ### Hetzner vs Raff Technologies: A Real Cloud Platform Comparison for Developers (2026) URL: https://rafftechnologies.com/blog/hetzner-vs-raff-cloud-comparison Published: 2026-03-09T00:00:00.000Z Description: Hetzner vs Raff Technologies: A Real Cloud Platform Comparison for Developers (2026) Hetzner has long been known as one of the best price-to-performance infrastructure providers in the hosting industry. Many developers choose Hetzner when looking for affordable virtual machines and reliable infrastructure. However, depending on workflow and project requirements, developers sometimes look for alternatives that offer different advantages such as simpler deployment, higher RAM tiers at entry level, or developer-focused tooling. In this article we compare **Hetzner Cloud and Raff Technologies** across pricing, infrastructure features, and developer experience to help you decide which platform fits your needs. --- ## Entry-Level Pricing Comparison When comparing cloud providers, it’s important to compare **similar RAM tiers**, since memory often determines what workloads a server can handle. | Provider | CPU | RAM | Storage | Bandwidth | Price | |---|---|---|---|---|---| | Hetzner CPX11 | 2 vCPU | 2 GB | 40 GB NVMe | 1 TB | €4.99 (~$5.40) | | Hetzner CPX21 | 3 vCPU | 4 GB | 80 GB NVMe | 2 TB | €9.49 (~$10.30) | | Raff Starter VM | 2 vCPU | 4 GB DDR5 | 50 GB NVMe | Unmetered | $4.99 | ### Key Observations If we compare **similar RAM tiers (4 GB)**: - Hetzner: €9.49 (~$10.30) - Raff: $4.99 At this tier, Raff offers: - more memory at the entry price point - NVMe storage - DDR5 RAM - unmetered bandwidth Hetzner focuses on **very low starting prices**, which can be attractive for extremely lightweight workloads. --- # Higher Tier Pricing Comparison As applications grow, developers often move to larger instances with more memory and compute power. Below is a comparison of **mid-tier and higher-tier virtual machines**. --- ## 8 GB RAM Tier | Provider | CPU | RAM | Storage | Bandwidth | Price | |---|---|---|---|---|---| | Hetzner CPX31 | 4 vCPU | 8 GB | 160 GB NVMe | 3 TB | €16.90 (~$18.30) | | Raff VM | 4 vCPU | 8 GB DDR5 | 120 GB NVMe | Unmetered | $9.99 | --- ## 16 GB RAM Tier | Provider | CPU | RAM | Storage | Bandwidth | Price | |---|---|---|---|---|---| | Hetzner CPX41 | 8 vCPU | 16 GB | 240 GB NVMe | 4 TB | €32.90 (~$35.60) | | Raff VM | 8 vCPU | 16 GB DDR5 | 240 GB NVMe | Unmetered | $19.99 | --- ## 32 GB RAM Tier | Provider | CPU | RAM | Storage | Bandwidth | Price | |---|---|---|---|---|---| | Hetzner CPX51 | 16 vCPU | 32 GB | 360 GB NVMe | 5 TB | €65.90 (~$71.30) | | Raff VM | 16 vCPU | 32 GB DDR5 | 360 GB NVMe | Unmetered | $39.99 | --- ### Pricing Pattern As instance sizes increase, the **price-to-performance advantage becomes more noticeable**. Raff tends to provide: - more RAM per dollar - unmetered bandwidth - NVMe storage - modern DDR5 memory This can make a difference for workloads that require **higher memory or sustained traffic**. --- ## Platform Features Comparison Both Hetzner and Raff provide modern cloud infrastructure features used by developers building applications and services. | Feature | Raff | Hetzner | |---|---|---| | Virtual Machines | ✓ | ✓ | | NVMe Storage | ✓ | ✓ | | Block Storage / Volumes | ✓ | ✓ | | Object Storage (S3 Compatible) | ✓ | ✓ | | API Access | ✓ | ✓ | | API Keys | ✓ | ✓ | | Private Networking | ✓ | ✓ | | Firewalls | ✓ | ✓ | | Load Balancers | ✓ | ✓ | | Snapshots & Backups | ✓ | ✓ | | Kubernetes | ✓ | Self-managed | Both platforms support **API-driven infrastructure**, allowing developers to automate server provisioning and integrate infrastructure into CI/CD pipelines. --- ## Storage & Data Services Modern applications rely heavily on flexible storage options. ## Raff Storage Raff provides: - NVMe block storage volumes - snapshot support - scalable volume resizing - S3-compatible object storage - API-based automation These tools allow developers to run applications, databases, and microservices without manually managing storage infrastructure. --- ## Hetzner Storage Hetzner provides: - scalable block storage volumes - snapshot and backup capabilities - S3-compatible object storage - redundant data center infrastructure Hetzner storage systems are designed to support **large scale production environments**. --- ## Kubernetes & Container Workloads Many modern applications are built around containers and Kubernetes. Hetzner servers can run Kubernetes clusters using tools such as: - kubeadm - k3s - managed orchestration frameworks Raff also supports container-based workloads and Kubernetes environments for deploying scalable applications and microservices. --- ## Developer Experience The biggest difference between these platforms is **platform philosophy**. --- ## Hetzner Hetzner is primarily a **datacenter operator and infrastructure provider**. It is known for: - excellent hardware price-performance - dedicated servers - large infrastructure deployments - strong hosting reputation Many companies run **large production workloads and enterprise infrastructure** on Hetzner. --- ## Raff Technologies Raff focuses on **developer-centric cloud infrastructure** designed for quickly launching and running projects. Common Raff workloads include: - development environments - backend APIs - bots and automation tools - microservices - prototypes and side projects The platform is designed to help developers **spin up compute resources quickly without unnecessary infrastructure complexity**. --- ## Real Developer Use Cases Cloud machines are commonly used for a wide variety of developer workloads. --- ## Development Environments Many developers run **remote development environments** in the cloud. Examples include: - Node.js or Python development servers - Docker environments - CI/CD runners - temporary staging servers Both platforms can support these workflows effectively. --- ## Automation & Bots Developers often deploy servers for: - trading bots - Discord or Telegram bots - automation scripts - scheduled cron jobs These workloads usually require **reliable compute with minimal overhead**. --- ## Backend APIs Cloud servers are frequently used to host: - REST APIs - GraphQL services - webhook processors - authentication services These applications require **consistent compute resources and stable networking**. --- ## Learning Infrastructure Students and developers often deploy servers to learn: - Linux server administration - Docker - Kubernetes - infrastructure automation Entry-level servers provide an accessible environment for experimenting with these technologies. --- ## When to Choose Hetzner Hetzner may be the right choice if you need: - extremely low-cost entry servers - dedicated bare metal infrastructure - large scale deployments - enterprise infrastructure - global data center presence --- ## When Raff May Be the Better Choice Raff may be a better fit if you want: - higher RAM tiers at entry pricing - unmetered bandwidth - developer-focused cloud workflows - simple and fast infrastructure deployment - modern NVMe-based cloud machines --- ## Final Thoughts Both Hetzner and Raff are powerful cloud infrastructure platforms, but they focus on slightly different priorities. Hetzner focuses on **large-scale infrastructure and hardware efficiency**, while Raff focuses on **developer productivity and high-value compute resources for everyday workloads**. Choosing the right platform ultimately depends on how you build and run your applications. If you're exploring modern cloud platforms for development environments, backend services, automation workloads, or side projects, Raff may be worth considering alongside traditional providers. --- Learn more about Raff Technologies https://rafftechnologies.com --- ### Running Kubernetes on a High-Performance VPS: Is It Worth It in 2026? URL: https://rafftechnologies.com/blog/kubernetes-on-vps-is-it-worth-it-2026 Published: 2026-02-24T00:00:00.000Z Description: Running Kubernetes on a High-Performance VPS: Is It Worth It in 2026? Kubernetes is no longer reserved for enterprise giants. In 2026, startups, DevOps teams, indie hackers, and SaaS builders are running production workloads on Kubernetes every day. But one question keeps coming up: **Do you really need expensive managed cloud platforms to run Kubernetes — or can a high-performance VPS handle it just as well?** Let’s break it down. --- ## The Rise of Self-Managed Kubernetes Managed Kubernetes services (EKS, GKE, AKS) are powerful — but they come with: - Complex pricing models - Egress bandwidth costs - Hidden infrastructure charges - Vendor lock-in - Over-provisioned resources For many teams, especially startups and lean DevOps groups, these costs grow fast. That’s why more cloud-native teams are asking: > Can we run Kubernetes on a powerful VPS instead? In many cases, the answer is **yes**. --- ## When Running Kubernetes on a VPS Makes Sense Running Kubernetes on a high-performance VPS is worth it when: ### ✅ You want predictable pricing No surprise network fees. No multi-layered billing structures. ### ✅ Your workloads are containerized but not hyperscale Many applications don’t need multi-region distributed clusters. ### ✅ You value control and flexibility Full root access. Custom networking. Infrastructure the way you want it. ### ✅ You want better cost-performance ratio High-performance CPUs + NVMe storage can outperform entry-level managed nodes. --- ## What You Need for a Production-Ready Setup If you’re running Kubernetes on a VPS, you must choose the right foundation. ### 1️⃣ CPU Power Matters Kubernetes schedules containers across nodes. Weak CPUs cause: - Slow pod scheduling - Poor scaling - High latency under load Modern AMD EPYC processors provide strong multi-core performance for container-heavy workloads. --- ### 2️⃣ NVMe Storage Is Critical Containerized applications generate logs, volumes, cache, and databases. NVMe SSD provides: - Faster I/O - Lower latency - Better performance under load Compared to traditional SSD, NVMe can dramatically improve application responsiveness. --- ### 3️⃣ Sufficient RAM Kubernetes components (kubelet, etcd, controller manager) consume memory. A realistic minimum for production: - 8GB RAM for small clusters - 16GB+ for moderate workloads Under-provisioning memory is the most common mistake. --- ### 4️⃣ Network Stability & DDoS Protection Cloud-native apps often expose APIs publicly. Your VPS provider should offer: - DDoS protection - Stable bandwidth - Low-latency connectivity Without that, Kubernetes won’t save you. --- ## Cost Comparison: Managed Kubernetes vs VPS Let’s look at a simple example. ### Managed Cloud Setup: - Control plane fees - Worker node pricing - Network transfer fees - Load balancer fees Monthly cost can easily exceed $70–$120 for a modest setup. --- ### High-Performance VPS Setup: - 4 vCPU - 8 GB RAM - NVMe storage - Flat monthly pricing Often under $20–$30 per month. For early-stage startups and lean DevOps teams, that difference is massive. --- ## What Are the Trade-Offs? Running Kubernetes on a VPS does require: - Manual setup - Security configuration - Monitoring setup - Backup planning Managed services abstract these away. But for many technical teams, the extra control is worth it. --- ## Is It Worth It in 2026? If you: - Run a SaaS - Deploy microservices - Use CI/CD pipelines - Want predictable infrastructure cost - Don’t need multi-region enterprise scale Then yes — running Kubernetes on a high-performance VPS is absolutely worth it. It offers: - Better cost efficiency - Full infrastructure control - Strong performance - No vendor lock-in Cloud-native doesn’t have to mean enterprise pricing. --- ## Final Thoughts Kubernetes is about flexibility and scalability. A high-performance VPS gives you: - Dedicated resources - Transparent pricing - High-speed storage - Powerful CPUs For many teams in 2026, that’s more than enough. If you’re building modern cloud-native applications, consider whether you truly need managed cloud — or if a powerful VPS can deliver better value. --- Fast. Simple. Reliable. --- ### Docker vs Kubernetes: When to Use Which (2026 Guide) URL: https://rafftechnologies.com/blog/docker-vs-kubernetes-when-to-use-which-2026 Published: 2026-02-15T00:00:00.000Z Description: Docker vs Kubernetes: When to Use Which (2026 Guide) If you're building modern software in 2026, you've probably heard these two names everywhere: - **Docker** - **Kubernetes** They are at the heart of cloud-native development — but they solve different problems. And one of the most common questions developers ask is: **Should I use Docker or Kubernetes?** The answer is simple: Docker helps you *package* applications. Kubernetes helps you *run and manage* them at scale. Let’s break it down clearly. --- ## What Is Docker? Docker is a platform for building and running applications inside **containers**. A container packages everything your app needs: - code - runtime - dependencies - libraries So it runs the same everywhere: - your laptop - staging - production - any cloud VM Docker solves the classic problem: > “It works on my machine, but not on yours.” --- ### Docker Is Best For: ✅ Local development ✅ Packaging applications ✅ Running single services ✅ Simple deployments ✅ Consistent environments If you're a developer shipping an app quickly, Docker is usually step one. --- ## What Is Kubernetes? Kubernetes (K8s) is a container orchestration platform. Once you have many containers running across many machines, you need a system to manage them. Kubernetes automates: - deployments - scaling - load balancing - self-healing - service discovery Kubernetes solves the problem: > “How do I run containers reliably in production at scale?” --- ### Kubernetes Is Best For: ✅ Microservices architectures ✅ Production orchestration ✅ Auto-scaling workloads ✅ High availability systems ✅ Multi-service applications Kubernetes is what teams use when complexity grows. --- ## Key Difference: Packaging vs Orchestration Here is the simplest way to understand it: | Tool | Role | |------|------| | Docker | Builds and runs containers | | Kubernetes | Manages containers at scale | Docker is the container engine. Kubernetes is the container manager. They are not competitors — they work together. --- ## Do You Need Kubernetes? Not always. Kubernetes is powerful, but it introduces complexity. You should ask: - How many services do I run? - Do I need autoscaling? - Do I need high availability? - Do I have a platform team? If you're running one app or a small backend… A VM + Docker might be enough. --- ## When to Use Docker Only Docker alone is perfect when: ### You are building an MVP Startups often need speed, not orchestration. ### You run a single application A monolith or small API can run easily in Docker. ### You want simple deployments Docker Compose can handle multi-container setups without Kubernetes overhead. ### You are learning containers Docker is the entry point into cloud-native development. --- ## When Kubernetes Becomes Necessary Kubernetes makes sense when: ### You have many microservices Service-to-service networking becomes complex. ### You need autoscaling Traffic spikes require dynamic scaling. ### You want self-healing infrastructure Kubernetes restarts failed workloads automatically. ### You run production workloads across multiple nodes Kubernetes balances workloads across machines. ### You need standardized deployment across teams Kubernetes becomes a shared operational layer. --- ## Real-World Example ### Small Startup App - One backend API - One database - Few users Best choice: ✅ VM + Docker No need for Kubernetes. --- ### Scaling SaaS Platform - Multiple services - CI/CD pipelines - Thousands of users - High uptime requirements Best choice: ✅ Kubernetes + containers Kubernetes becomes worth it. --- ## Docker vs Kubernetes in 2026: The Modern Stack In 2026, most modern teams follow this progression: 1. Start with Docker 2. Deploy on VMs 3. Scale services 4. Adopt Kubernetes when needed Cloud-native maturity is a journey, not a starting requirement. --- ## Where Raff Fits In At Raff Technologies, we support developers at every stage: - simple VM deployments - Docker-based environments - cloud-native workflows - scalable infrastructure foundations Our mission is: **Fast. Simple. Reliable.** Whether you're running a single Docker container or preparing for Kubernetes workloads, Raff provides the compute power and simplicity modern teams need. --- ## Final Thoughts Docker and Kubernetes are both essential technologies — but for different reasons. Docker helps you ship applications consistently. Kubernetes helps you operate them reliably at scale. Start simple. Use Docker first. Adopt Kubernetes when your system demands orchestration. That’s the cloud-native way in 2026. --- ### Virtual Machine vs Docker: Which One Should Developers Use? URL: https://rafftechnologies.com/blog/virtual-machine-vs-docker Published: 2025-12-21T00:00:00.000Z Description: Virtual Machine vs Docker: Which One Should Developers Use? As modern development workflows evolve, developers are faced with an important architectural question: **Should you use a Virtual Machine or Docker?** Both technologies are widely used, both solve real problems, and both are often misunderstood. This confusion leads many developers to choose tools based on trends rather than technical fit. This guide breaks it down clearly — without hype. By the end of this article, you’ll understand: - What a Virtual Machine is - What Docker (containers) are - The key differences between VMs and Docker - When developers should use one, the other, or both together --- ## What Is a Virtual Machine? A **virtual machine (VM)** is a fully isolated computer created using software. Each VM includes: - Its own operating system - Allocated CPU, RAM, and storage - Complete isolation from other environments Virtual machines run on top of a **hypervisor**, which manages physical hardware and distributes resources. From a developer’s perspective, a VM behaves exactly like a real server. --- ## What Is Docker? **Docker** is a containerization platform. Instead of virtualizing hardware, Docker: - Shares the host operating system - Packages applications with their dependencies - Runs lightweight, isolated containers Containers start fast, use fewer resources, and are ideal for application-level isolation. Docker is not a virtual machine — it solves a different problem. --- ## Virtual Machine vs Docker: Core Differences | Feature | Virtual Machine | Docker | |------|---------------|--------| | Isolation | Full OS-level isolation | Process-level isolation | | Startup time | Minutes | Seconds | | Resource usage | Higher | Lower | | OS flexibility | Any OS per VM | Same OS kernel | | Security boundary | Stronger | Lighter | | Best use case | Infrastructure, full environments | Application packaging | --- ## Performance Comparison ### Virtual Machines - Dedicated resources - Predictable performance - Better for heavy workloads ### Docker - Extremely fast startup - Lower overhead - Shares host resources For CPU- or memory-intensive tasks, VMs often perform more reliably. For lightweight services, Docker wins on speed. --- ## Security & Isolation Virtual machines offer **stronger isolation**: - Separate kernels - Reduced blast radius - Better suited for multi-tenant environments Docker containers are secure when configured properly, but: - They share the host kernel - A misconfiguration can increase risk For sensitive workloads, VMs are often preferred. --- ## Resource Usage & Cost Docker containers: - Use fewer resources - Allow higher density - Reduce infrastructure cost Virtual machines: - Consume more memory and storage - Cost more per environment - Offer stronger guarantees Cost efficiency depends on workload, not just technology. --- ## Development Workflow Differences ### Virtual Machines Best for: - Full-stack development - Consistent team environments - Cloud-based development workspaces - CI/CD infrastructure ### Docker Best for: - Packaging applications - Microservices - Local development parity - Deployment pipelines Docker shines inside development workflows — not necessarily as the environment itself. --- ## When Developers Should Use Virtual Machines Use a VM when: - You need a full OS environment - You want strong isolation - You’re building cloud-based dev environments - You want production-like infrastructure - You support multiple projects or teams Virtual machines are ideal as **developer workspaces**. --- ## When Docker Makes More Sense Use Docker when: - You package applications - You deploy microservices - You need fast startup times - You want consistent app environments Docker is an excellent **application delivery tool**. --- ## Can Virtual Machines and Docker Be Used Together? Yes — and this is the most common modern setup. Typical architecture: - **Virtual Machine** → provides isolation and infrastructure - **Docker** → runs applications inside the VM This combines: - VM-level security - Docker-level speed and portability For most teams, this hybrid approach works best. --- ## Final Thoughts Virtual machines and Docker are not competitors — they are complementary tools. - Virtual machines solve **infrastructure and environment** problems - Docker solves **application packaging and deployment** problems Developers don’t need to choose one forever. They need to choose what fits the job. In modern cloud-native development, the strongest setups often use **both**. --- ### What Is a Virtual Machine? A Beginner-Friendly Guide (With Real Use Cases) URL: https://rafftechnologies.com/blog/what-is-a-virtual-machine Published: 2026-01-04T00:00:00.000Z Description: What Is a Virtual Machine? A Beginner-Friendly Guide (With Real Use Cases) Virtual machines are everywhere — from cloud platforms and software development to startups and students learning to code. Yet for many beginners, the term **virtual machine (VM)** still sounds complex or intimidating. This guide is written in plain language. No jargon. No assumptions. By the end of this article, you’ll understand: - What a virtual machine really is - How virtual machines work - Why people use virtual machines instead of physical computers - Real-world use cases for beginners, developers, and businesses --- ## What Is a Virtual Machine? A **virtual machine (VM)** is a computer created using software instead of physical hardware. It behaves like a real computer: - It has its own operating system (Windows, Linux, etc.) - It has CPU, RAM, and storage - You can install software, write code, and run applications The key difference? 👉 A virtual machine runs **inside another computer or in the cloud**, sharing physical hardware with other virtual machines. Think of it like this: - A physical computer is a house - A virtual machine is an apartment inside a large building Each apartment is isolated, secure, and independent — even though they share the same structure. --- ## How Does a Virtual Machine Work? At the core of every virtual machine is something called a **hypervisor**. The hypervisor: - Sits between the physical hardware and the virtual machines - Divides CPU, memory, and storage - Ensures each VM runs independently and securely There are two common environments: ### 1. Local Virtual Machines Installed on your own computer using tools like VirtualBox or VMware. Good for: - Learning - Testing software - Running multiple operating systems on one PC Limited by your computer’s power. ### 2. Cloud Virtual Machines Hosted in data centers and accessed over the internet. Good for: - Developers - Teams - Startups - Scalable workloads You rent computing power instead of buying hardware. --- ## Why Do People Use Virtual Machines? Virtual machines solve real, everyday problems. Here are the main reasons people choose VMs: ### 1. Cost Efficiency You don’t need to buy expensive hardware. With cloud virtual machines, you: - Pay only for what you use - Scale up or down instantly - Avoid maintenance costs ### 2. Flexibility Need Linux today and Windows tomorrow? With virtual machines, switching environments takes minutes — not hours or days. ### 3. Isolation & Security Each VM is isolated. If one crashes or gets compromised, others remain safe. ### 4. Speed Launching a new virtual machine can take less than a minute. No waiting for hardware deliveries. --- ## Real Use Cases for Virtual Machines Let’s move from theory to reality. ### Virtual Machines for Beginners & Students Students use virtual machines to: - Learn Linux without breaking their laptop - Practice programming - Run tools their local computer can’t handle A VM becomes a **safe playground** for learning. --- ### Virtual Machines for Developers Developers use virtual machines to: - Build and test applications - Run development environments - Compile code faster than on local machines Many developers now work entirely on cloud VMs and access them remotely. --- ### Virtual Machines for Startups & Small Teams Startups rely on virtual machines to: - Launch products quickly - Control infrastructure costs - Scale without hiring large IT teams Instead of investing in servers, they rent exactly what they need. --- ### Virtual Machines for Testing & Automation Quality assurance teams use VMs to: - Test software on different operating systems - Reproduce bugs - Run automated tests in parallel This saves time and improves reliability. --- ## Virtual Machine vs Physical Computer So, should you use a virtual machine or a physical computer? ### Choose a Virtual Machine if: - You need flexibility - You want to scale easily - You don’t want hardware maintenance - You work remotely ### Choose a Physical Computer if: - You need offline access - You run hardware-dependent workloads - You prefer full local control For many modern use cases, virtual machines are the smarter choice. --- ## Are Virtual Machines Hard to Use? For beginners, traditional VM platforms could feel complex. Modern cloud platforms have changed that. Today, launching a VM often means: 1. Choose your operating system 2. Select performance 3. Click launch No deep technical knowledge required. --- ## The Future of Virtual Machines As remote work, cloud computing, and AI workloads grow, virtual machines are becoming the default computing environment. They are: - Faster to deploy - Easier to manage - More cost-effective For individuals and businesses alike. --- ## Final Thoughts A virtual machine is simply a **computer without the hardware burden**. For beginners, it’s a safe learning environment. For developers, it’s a powerful workspace. For startups, it’s a scalable foundation. Once you understand virtual machines, you start seeing them everywhere — because they power much of the modern internet. If you’re curious to experience one firsthand, modern cloud platforms allow you to launch a virtual machine in minutes and start working immediately. --- ### Then vs. Now: From Retro PCs to Cloud VMs URL: https://rafftechnologies.com/blog/p0qgxdnny4txbr94qsjwhh8d Published: 2025-09-11T00:00:00.000Z Description: Then vs. Now: From Retro PCs to Cloud VMs # From Retro PCs to Cloud Virtual Machines — How Computing Evolved Computing has evolved dramatically over the last few decades. Once, everything depended on the power of the machine under your desk — limited storage, slow processors, and no way to scale. Today, with Cloud Virtual Machines (VMs), developers, startups, and businesses can access scalable, high-performance environments instantly. This post takes a quick look at that journey: from then (retro PCs) to now (cloud VMs). ## Then: The Retro Computer Era Back then, everything was local and limited. - You worked only on the hardware in front of you. - Upgrades meant buying new, expensive parts. - If the machine crashed, your work was at risk. - Sharing or scaling resources was nearly impossible. For developers and web hosters, this created real bottlenecks: slow build times, limited capacity, and no flexibility. ## Now: Cloud Virtual Machines Fast forward to today — the world runs on cloud infrastructure. With VMs, you’re no longer tied to local limitations. - **Scalable** → Start small and expand CPU, RAM, or storage in seconds. - **Secure** → Each VM is isolated, protecting your projects and clients. - **Accessible Anywhere** → Work from any location with an internet connection. - **Cost-Efficient** → Pay only for what you use, without investing in physical hardware. At Raff Technologies, we’ve made launching a VM as simple as clicking a button. Whether you’re a student testing Linux, a freelancer hosting client websites, or a startup preparing to scale, cloud VMs give you the freedom to build without limits. ## Conclusion The evolution from retro PCs to modern VMs shows just how far we’ve come. What used to be limited and local is now scalable, secure, and global. At Raff, we’re not just following this journey — we’re helping shape it. --- ### Why Web Hosters Should Use Virtual Machines URL: https://rafftechnologies.com/blog/n2il3yz5rtxai1spegns684i Published: 2025-09-07T00:00:00.000Z Description: Why Web Hosters Should Use Virtual Machines Web hosting has come a long way from simple shared servers. While shared hosting is still popular, many developers, freelancers, and agencies quickly run into its limitations: **slow performance, lack of control, and restricted scalability**. That’s where **Virtual Machines (VMs)** change the game. For web hosters, switching to VMs means **more freedom, better performance, and a smarter way to grow**. Let’s break down why. ## 1. Full Control Over Your Environment Shared hosting providers limit what you can install or configure. With a **VM**, you’re in charge: - Choose your operating system (Ubuntu, Debian, CentOS, Windows Server, etc.). - Pick your web server (Nginx, Apache, LiteSpeed). - Install the exact packages your projects require. Whether it’s **Ubuntu with Nginx** or **CentOS with Apache**, the setup is completely yours. This level of control lets you **fine-tune performance and security** to fit your clients’ needs — something shared hosting can’t offer. ## 2. Consistent Performance for Your Clients On shared hosting, resources are divided between hundreds of users. One busy neighbor site can affect everyone else. With a **VM**, you get **dedicated CPU, RAM, and storage**. That means: - Faster page loads - Stable uptime - Reliable performance even during traffic spikes Your clients’ websites stay smooth no matter what. ## 3. Scale as Your Business Grows Every successful hosting business faces a moment when clients need more. On shared hosting, this often means **migrating to a bigger plan** or even another server — a disruptive and time-consuming process. With **VMs**, scaling is simple: - Upgrade CPU, memory, or storage instantly - No moving data or risking downtime - Adjust resources as your clients scale You grow as your clients grow. ## 4. Stronger Security and Isolation Shared hosting environments expose you to higher risks. If one site on the server is compromised, the others can be too. A **VM keeps projects isolated**: - Each environment is separate and secure - Even if one site is attacked, others remain unaffected - You manage your own firewall rules, SSH keys, and security updates This isolation gives you **enterprise-grade safety** without the complexity. ## 5. Cost-Effective and Transparent Many hosting providers offer “Pro” plans that sound attractive but **bundle features you might never use**. With modern VM platforms like **Raff**, you: - Only pay for what you use - Avoid long-term contracts and surprise charges - Monitor usage in real-time Our pricing is simple: add credits, launch your VM, and scale as required. No hidden fees. No confusing billing. Just **straightforward, predictable costs**. ## Final Thoughts For web hosters, switching to VMs is like upgrading from a **rented apartment** to your **own house**. You get: - More control - More security - Better performance - The ability to expand without limits At **Raff Technologies**, we’re building a platform where hosting professionals — from freelancers to agencies — can **host smarter, faster, and with full transparency**. 👉 [Launch your first VM with Raff today](https://rafftechnologies.com) --- ### Google Bets Big on Cloud & AI: $9 Billion Expansion in Oklahoma URL: https://rafftechnologies.com/blog/cgrhb28spz3lmsimlzc76s7c Published: 2025-08-29T00:00:00.000Z Description: Google Bets Big on Cloud & AI: $9 Billion Expansion in Oklahoma # A Landmark Investment in Cloud Infrastructure Google has announced a massive **$9 billion investment in Oklahoma** to expand its AI and cloud computing infrastructure. This move includes building a new data center campus in **Stillwater**, expanding its existing **Pryor** campus, and launching education and workforce development programs. The investment signals just how critical **cloud services and artificial intelligence** have become to the global tech ecosystem. ## Why Oklahoma? Oklahoma’s central location, strong energy resources, and growing tech workforce make it a strategic hub for large-scale cloud deployments. By anchoring billions in infrastructure here, Google is not just adding servers — it’s fueling an entire regional cloud economy. Local officials estimate **thousands of jobs** will be created in construction, operations, and supporting industries. Beyond employment, investments in connectivity and renewable energy partnerships are expected to strengthen the state’s role in the digital future. ## The Global Cloud Race Heats Up Google’s bold expansion comes at a time when **AWS, Microsoft, and Oracle** are also doubling down on infrastructure spending worldwide. - **Amazon** recently pledged **$10 billion** for a North Carolina AI and data center campus. - **Oracle** is investing **€3 billion across Europe** to strengthen sovereign cloud capacity. This arms race is about more than storage and servers — it’s about **AI dominance**. Training and running large-scale models requires vast compute power, and whoever builds the biggest, fastest, and most efficient infrastructure will shape the future of **generative AI, machine learning, and cloud services**. ## What This Means for Developers and Businesses For businesses, these mega-investments translate into: - **Lower latency & better performance** as more regional data centers come online. - **Enhanced AI services** thanks to optimized GPU and TPU infrastructure. - **Competitive pricing pressure** as hyperscalers fight for market share. - **Local compliance & data residency options**, crucial for regulated industries. For developers, it means **faster experimentation**, more reliable cloud-native environments, and an ecosystem that is expanding opportunities from small startups to global enterprises. ## Raff’s Perspective At **Raff Technologies**, we see this as a clear signal: cloud is no longer optional — it’s the backbone of innovation. Whether you’re a freelancer, a student, or part of a growing team, the availability of **affordable, scalable compute power** has never been greater. Our mission is to make that power **accessible without the complexity and overhead** of traditional hosting. As hyperscalers like Google expand the frontier, Raff continues to provide developers and small teams with the tools to **build, learn, and scale on their own terms**. Google’s Oklahoma expansion is a reminder that the **cloud revolution** is still accelerating. With billions flowing into AI-ready infrastructure, the next five years will reshape how the world builds software, analyzes data, and interacts with technology. Stay tuned — the cloud wars are just getting started, and every developer stands to benefit. --- ### Why Every Developer Should Have Their Own Virtual Machine URL: https://rafftechnologies.com/blog/g1jn5c8gqgp2dx1o2nw1erf7 Published: 2025-08-19T00:00:00.000Z Description: Why Every Developer Should Have Their Own Virtual Machine In a world where developers are constantly pushing the boundaries of what’s possible, having the right tools can make all the difference. One of the most powerful yet underutilized tools is the **Virtual Machine (VM)** — and every developer should have one in their arsenal. Whether you’re building side projects, running complex workloads, or experimenting with new tech, a VM can give you freedom, flexibility, and firepower that your local machine simply can’t match. ## 1. Instant Access to High-Performance Resources Sometimes, your laptop just isn’t enough. Need more CPU power? Extra RAM? A GPU for training AI models? With a VM, you can scale your resources in minutes — no hardware upgrades, no waiting. 💡 **Example:** Running a large dataset training job on your local machine might take days. On a properly configured VM, you can get it done in hours. ## 2. Experiment Without Fear Developers love experimenting — but breaking your local setup is a pain. A VM lets you spin up an isolated environment, test whatever you want, and roll back instantly if things go wrong. - Try new frameworks without uninstalling half your system. - Test multiple OS configurations. - Run risky scripts in a safe sandbox. ## 3. Work from Anywhere, Seamlessly Your projects, tools, and setup shouldn’t be tied to a single device. A VM is accessible from anywhere with an internet connection, keeping your dev environment exactly the same across devices. - Switch from your desktop at home to a laptop on the road with zero disruption. - No more “it’s only configured on my main machine” excuses. ## 4. Collaboration Made Simple If you’re working in a team, VMs are a dream for consistency: - Share identical environments with teammates. - Avoid the “works on my machine” problem entirely. - Perfect for hackathons, startup teams, and open-source contributors. ## 5. Cost-Effective Scaling Why buy a high-end laptop for a one-time project? With a VM, you pay only for what you use. Spin up a powerful instance for a week, then shut it down when you’re done — and pay nothing while it’s off. ## 6. Real-World Use Cases Here’s how developers are already using VMs: - 🛠️ **Automation & Workflow Tools:** Running 24/7 processes like n8n or CI/CD pipelines. - 🌐 **Web App Hosting:** Deploy MVPs or prototypes before scaling. - 🎓 **Learning & Experimentation:** Practice Docker, Kubernetes, or advanced Linux setups without risk. - 🧪 **DevOps Testing:** Create replicas of production environments for safe debugging. A Virtual Machine isn’t just a tool — it’s a gateway to faster, safer, and more flexible development. With **Raff Technologies**, you can launch a powerful VM in minutes! 👉 [Start Building with Raff](https://rafftechnologies.com) --- ### Disruptive Innovations from Challenger Providers: How New Players Are Shaping the Cloud in 2025 URL: https://rafftechnologies.com/blog/fyx27p29uysz43xa8etzbun6 Published: 2025-08-07T00:00:00.000Z Description: Disruptive Innovations from Challenger Providers: How New Players Are Shaping the Cloud in 2025 # The Rise of Challenger Clouds — Why It’s Good for Developers For years, the cloud market was dominated by the “big three” — **Amazon Web Services, Microsoft Azure, and Google Cloud**. But **2025** is proving to be a turning point. Challenger providers are making headlines with bold innovations, disruptive pricing models, and tailored solutions for developers, startups, and AI-driven workloads. At **Raff Technologies**, we believe this disruption is healthy — driving choice, transparency, and innovation in ways that benefit everyone from solo developers to enterprise teams. ## Nvidia’s DGX Cloud Expansion **Nvidia’s DGX Cloud** continues to expand globally, offering AI researchers and enterprises unprecedented access to GPU clusters optimized for machine learning workloads. By providing plug-and-play AI infrastructure, Nvidia is narrowing the gap between raw computing demand and accessible supply, reshaping expectations for performance and scalability. **Why it matters:** As AI workloads grow exponentially, developers need cloud solutions that balance power and accessibility. Smaller players like **Raff** have an opportunity to provide leaner, faster-to-launch alternatives that don’t require billion-dollar budgets. ## Enfabrica’s EMFASYS: Cutting AI Memory Costs This month, **Enfabrica** unveiled **EMFASYS**, a system designed to lower the soaring costs of AI training by replacing expensive HBM (High Bandwidth Memory) with DDR5-based alternatives. Backed by Nvidia, Enfabrica’s approach could redefine the economics of AI development. **Why it matters:** Lowering infrastructure costs means more startups and indie developers can access advanced AI capabilities. **Raff’s transparent pricing** strategy aligns with this trend — empowering developers to innovate without hidden costs. ## CoreWeave and the Rise of AI-Focused Clouds **CoreWeave**, a specialized cloud provider, is gaining traction by offering GPU-heavy environments tailored specifically for AI and ML. Their rapid growth underscores the hunger for platforms that break away from traditional one-size-fits-all hosting. **Why it matters:** Specialized challengers highlight the demand for customizable solutions. At **Raff**, we’re building with the same spirit: giving developers a platform that’s powerful yet easy to launch, with pricing that scales fairly. ## The Bigger Picture: Why Challenger Clouds Matter Challenger providers aren’t just competing — they’re changing the rules. By rethinking cost structures, introducing specialized infrastructure, and prioritizing developer experience, they’re forcing the cloud giants to evolve. For developers and small teams, this shift is a win: - More choice in providers and configurations - Lower costs through innovative infrastructure - Better performance for AI-driven workloads - Greater transparency — a value we at **Raff** put front and center ## Conclusion: Where Raff Fits In At **Raff Technologies**, we see ourselves as part of this new wave of challengers. While we may not have the scale of Nvidia or the backing of giants, our strength lies in agility, transparency, and a relentless focus on developer needs. In a world where innovation moves fast, **Raff is here to ensure that you don’t just keep up — you stay ahead.** --- ### The Rise of AMD in the Cloud: What It Means for Your Virtual Machine URL: https://rafftechnologies.com/blog/wu7daaz4f7j260axgu4ewiz8 Published: 2025-08-04T00:00:00.000Z Description: The Rise of AMD in the Cloud: What It Means for Your Virtual Machine # The Rise of AMD — And What It Means for Your Virtual Machines In the past five years, **AMD** has gone from an underdog in the server CPU market to a **dominant force powering some of the most efficient and high-performance data centers in the world**. This shift has had a profound impact on **cloud computing** — especially for developers and teams who rely on **virtual machines** to run applications, test code, and build modern infrastructure. At **Raff Technologies**, we chose **AMD EPYC processors** as the backbone of our cloud VM platform — and for good reason. Here’s what the rise of AMD means for your virtual machine experience. ## 1️⃣ More Cores, More Power **AMD EPYC chips**, particularly the latest generations, offer significantly **higher core counts** than traditional server CPUs. For VM users, this translates to: - ⚡ Faster **parallel processing** - 🧑‍💻 Better **multitasking** - 🏗️ Higher **VM density per host** (without sacrificing performance) 💡 **Game-changer for developers:** Running **Docker containers, CI/CD pipelines, self-hosted apps**, and **full-stack environments** becomes smoother and faster. ## 2️⃣ Better Performance per Dollar One of AMD’s biggest advantages is **delivering excellent performance at a lower cost**. For developers, this means: - 🚀 Competitive pricing **without compromising on speed** - 💸 Infrastructure efficiency passed **directly to users** If you’ve been burned by **hidden costs** or **sluggish VM performance** on other platforms, you’ll feel the difference on a **Raff-powered AMD machine**. ## 3️⃣ Energy Efficiency = Sustainability + Savings AMD’s server-grade chips are built with **power efficiency in mind**. This is good not just for reducing our **data center energy footprint**, but also for: - 🌱 Lower cooling and operational costs - ♻️ Longer-lasting hardware and sustainable infrastructure When you launch a VM with us, you're not only getting **raw compute power** but also contributing to a **more sustainable cloud ecosystem**. ## 4️⃣ Industry Validation — AMD Is the New Standard It’s not just us. Major providers like **AWS, Azure, and Oracle Cloud** are integrating **AMD EPYC** into their infrastructure. That’s a clear signal: **AMD is no longer a niche option — it’s becoming the industry default for high-efficiency compute.** At **Raff**, we were early adopters because we believe in providing **developers with cutting-edge, affordable infrastructure**. ## 5️⃣ What This Means for You When you spin up a VM on Raff, you're getting: - 🔑 **Full root access** on AMD EPYC-backed machines - ⚡ **Faster provisioning** and quick boot times - 🛡️ **Reliable performance under load** - 💵 **Transparent pricing** based on real efficiency Whether you're: - Deploying production code - Running automation tools like **n8n** - Hosting APIs or databases - Learning and experimenting AMD gives your **virtual machine the muscle it needs** — without the noise or overhead. ## 🚀 Ready to Try It for Yourself? Launch your next VM on **AMD EPYC-powered infrastructure** at [rafftechnologies.com](https://rafftechnologies.com). Experience the rise of **better, faster, and more sustainable cloud computing**. --- ### What Can You Build with n8n? 10 Real Use Cases You Can Deploy Today URL: https://rafftechnologies.com/blog/w4rbnhj7kfhe4ww99w75jnal Published: 2025-07-28T00:00:00.000Z Description: What Can You Build with n8n? 10 Real Use Cases You Can Deploy Today # Why This Matters — Unlock the Power of n8n + Raff Most automation tools do the basics: move data from A to B, send a notification, post a tweet. But **n8n** is different — it gives you **control, flexibility, and real power**. When combined with **Raff’s one-click n8n VMs**, it becomes a **developer playground** for building custom agents, internal workflows, and full-stack automations — with or without code. Let’s explore what’s possible. ## 1️⃣ Gmail → Google Drive → Telegram: A Smart File Router When an email arrives with an attachment: - Save it to a specific Google Drive folder - Send a Telegram message with the file link ✅ Useful for: - Invoice collection - Content submissions - Remote collaboration ## 2️⃣ Webhook → Build Trigger → Slack Notify Connect your Git repo or CI/CD service. When a webhook fires: - Trigger a build - Notify the team on Slack - Log it to Google Sheets or Notion ✅ Perfect for: - DevOps teams - Side projects - Solo developers ## 3️⃣ Social Media Auto-Poster - Create a post in Airtable or Notion - Automatically publish it to X, LinkedIn, Instagram - Get analytics via webhook later ✅ Built for: - Content marketers - Indie founders - Personal branding ## 4️⃣ Stripe → Notion CRM → Email Every time a payment is made on Stripe: - Add the customer to a Notion database - Send them a personalized thank-you email - Notify your internal team on Slack ✅ Great for: - SaaS teams - Freelancers - Agencies ## 5️⃣ n8n as a Personal Assistant - Pull weather data in the morning - Combine with your calendar events - Send you a morning summary via WhatsApp or Email 💡 Build your own daily dashboard agent and tweak it however you want. ## 6️⃣ Auto Backup to S3 or Dropbox - Schedule a job every night - Export your database or app data - Upload it to cloud storage ✅ Useful for: - Data retention - Peace of mind - GDPR & compliance workflows ## 7️⃣ AI Workflows with OpenAI + Webhooks - Use webhooks to receive questions - Process them with GPT-4 - Return the answer to Slack, Telegram, or your custom frontend 🚀 Build intelligent agents, chatbots, or content generators. ## 8️⃣ Monitor Prices or Keywords - Use HTTP request nodes to scrape or ping APIs - Monitor product price changes or SEO rankings - Alert when thresholds are met ✅ Ideal for: - Growth hackers - Competitor monitoring - Product teams ## 9️⃣ Lead Capture + Auto Follow-up - Capture leads via Typeform or custom form - Add to CRM (HubSpot, Notion, Airtable) - Schedule follow-up emails at 24h and 72h ⚡ Helps small teams run big workflows **without touching code**. ## 🔟 Build Your Own SaaS Backend (Yes, Seriously) - Use n8n to handle incoming API requests - Route logic through various services - Store, transform, and trigger actions visually 💡 Many founders prototype their MVP backend logic this way before writing a single file. ## Why Use Raff for This? Because none of the above should take you hours to deploy. With **Raff**, you: - 🚀 Launch n8n in seconds - ⚡ Skip server setup - 📈 Scale workflows painlessly - 🔒 Keep full control (private, customizable, yours) You bring the logic — we bring the speed. ## Final Thought **n8n isn’t just an automation tool — it’s a creative engine** for developers, makers, and ambitious teams. With **Raff**, it’s easier than ever to go from **idea to automation fast**. 👉 [Start building now at rafftechnologies.com](https://www.rafftechnologies.com) --- ### 10 Things You Can Automate with Your Cloud VM URL: https://rafftechnologies.com/blog/icbq0v5en1152yactpst22ie Published: 2025-07-24T00:00:00.000Z Description: 10 Things You Can Automate with Your Cloud VM # 10 High-Impact Tasks You Can Automate With Your Raff Cloud VM Spinning up a VM is just the beginning. Once it’s live, the real magic happens when you use it as your own programmable, always-on machine. Whether you're a **developer**, **tester**, **freelancer**, or **indie builder**, here are 10 high-impact tasks you can automate with your Raff cloud VM. ## 1. Run Scheduled Jobs with Cron Use your VM like a reliable cloud-based task scheduler. Automate: - Daily database backups - Data scraping - Email summaries - Scripted deployments It’s as simple as setting up a `crontab` on your Linux instance. ## 2. Deploy GitHub Actions Runners Want full control over your CI pipeline? Set up a **self-hosted GitHub Actions runner** on your VM to: - Speed up workflows - Avoid GitHub's shared runners' timeouts - Run private scripts securely 💡 *Bonus: You can stop the VM when not in use to save costs.* ## 3. Auto-Build and Push Docker Images Use your VM to: - Pull the latest code from GitHub - Build Docker images - Push them to Docker Hub or your private registry Perfect for **staging environments** or **internal tooling**. ## 4. Self-Host Developer Tools Your Raff VM can automate the setup and uptime of tools like: - **JupyterLab** - **VS Code Server** - **Postgres / MongoDB** - **Jenkins / CI dashboards** - **Tailscale or WireGuard** for remote access Install once, run forever. ## 5. Webhooks and Lightweight API Services Want to automate Slack alerts, database updates, or webhook listening? Use **Flask**, **FastAPI**, or **Node.js** to deploy tiny HTTP endpoints that run 24/7 and automate your side-project workflows. ## 6. Mirror & Backup Git Repos Use **cron + shell scripts** to regularly mirror important Git repos to your private storage. Peace of mind, automated. ## 7. Host Your Portfolio or Resume API Set it once, forget it. You can host: - A static portfolio site - Your resume as a JSON API - A Notion-to-site mirror …and automate the refresh too — without needing Vercel or Netlify. ## 8. Monitor Your Personal or Client Websites Run tools like **Uptime-Kuma** or simple bash + `curl` scripts to: - Monitor your sites - Get downtime alerts via email or Telegram - Log response times Lightweight and powerful. ## 9. Convert Your VM Into a Discord/Telegram Bot Server Spin up bots that: - Respond to commands - Automate group tasks - Monitor mentions or RSS feeds Schedule their tasks, keep logs, and scale them easily. ## 10. Automate Learning or Research Workflows Use your VM to: - Download daily articles, papers, or podcasts - Summarize content with an LLM - Push notes to your **Obsidian**, **Notion**, or email inbox It becomes your **always-on second brain**. ## Final Thoughts **Raff** gives you a clean, powerful VM with no bloat, no overcomplication, and no surprise pricing. That means you're free to automate securely, affordably, and on your terms. 👉 [Launch your first VM today](https://rafftechnologies.com) --- ### Quantum Computing Meets Cloud: Preparing for the Next Tech Revolution URL: https://rafftechnologies.com/blog/x8dxh1o0edk4qmgq5pp2515l Published: 2025-07-14T00:00:00.000Z Description: Quantum Computing Meets Cloud: Preparing for the Next Tech Revolution # Preparing for the Quantum Future: Why Developers Should Start Now Quantum computing is no longer just the subject of academic research or science fiction. It is approaching a real-world tipping point. As **Nvidia CEO Jensen Huang** recently noted, quantum computing has reached an “inflection point” — a moment where research is rapidly translating into practical applications. While widespread quantum adoption may still be years away, one thing is clear: developers, cloud platforms, and infrastructure providers need to start preparing now. At **Raff Technologies**, we believe that the cloud must evolve alongside emerging compute paradigms — including quantum — and stay developer-first every step of the way. ## What Makes Quantum Computing Different? Quantum computers process information in fundamentally different ways from classical computers. Rather than using bits (0s and 1s), they use **qubits**, which can exist in multiple states simultaneously due to superposition and entanglement. This allows them to: - Solve specific classes of problems **exponentially faster** - Simulate **molecular and quantum systems** more accurately - Optimize complex systems far beyond traditional computing limits ## Why Developers Should Start Paying Attention Most developers won’t be writing code for quantum computers tomorrow — but preparing for the shift now can create opportunities. Here’s why: ### 1. Hybrid Models Will Become the Norm Many early applications will combine **quantum and classical computing**, requiring cloud platforms that support both environments flexibly. ### 2. Quantum APIs Are Already Emerging Frameworks like **Qiskit** (IBM), **Cirq** (Google), and **Braket** (AWS) are giving developers a sandbox to begin exploring quantum algorithms using simulators or real quantum processors via the cloud. ### 3. Cloud Infrastructure Will Need to Be Quantum-Ready Quantum jobs will require specialized orchestration. Developers and startups will increasingly look for platforms that support experimentation and simulation in a lightweight, affordable way. ## How the Cloud Plays a Role in the Quantum Future Quantum computers will not be personal devices. They will live in highly controlled environments accessed primarily through the cloud. Here’s what this means for infrastructure: - Developers need access to **quantum simulators** and hybrid architectures - Tooling must integrate easily with traditional languages and platforms - Workloads will need to scale elastically between classical and quantum layers - Pricing models must evolve to match short, intensive workloads ## Raff’s Vision: A Cloud Platform That Evolves With Developers While **Raff** does not (yet) offer quantum computing services, our infrastructure is designed to support rapid technological change: - We provide **on-demand, pre-configured environments** developers can adapt quickly - Our **flat-rate pricing** makes experimentation affordable and transparent - Our architecture is **flexible by design**, capable of integrating emerging APIs and toolkits as demand grows We believe platforms shouldn’t just support today’s workflows — they should prepare builders for what’s next. Quantum computing may still be early, but the developer ecosystem needs to start adapting today. The next wave of innovation will come not just from quantum breakthroughs but from making those breakthroughs accessible. At **Raff**, our mission is to stay out of the way and let developers build — whether it's with containers, machine learning, or eventually, quantum systems. 👉 [Visit rafftechnologies.com](https://rafftechnologies.com) to launch your dev environment in seconds — and prepare for what’s next. --- ## Tutorials ### How to Deploy a Multi-Container App with Docker Compose on Ubuntu 24.04 URL: https://rafftechnologies.com/learn/tutorials/deploy-multi-container-docker-compose-ubuntu-24-04 Description: Deploy a multi-container Docker Compose app on Ubuntu 24.04 with Node.js, PostgreSQL, Redis, secrets, health checks, private networking, backups, and persistence. Docker Compose lets you define a multi-container application in one `compose.yaml` file and manage the stack with commands such as `docker compose up`, `docker compose ps`, and `docker compose down`. In this tutorial, you will deploy a small Node.js API with PostgreSQL and Redis on a Raff Linux VM running Ubuntu 24.04. The database and cache stay on the internal Compose network, PostgreSQL uses a named volume for persistent data, the database password is mounted as a Compose secret instead of being hardcoded in YAML, and the application port is bound to localhost rather than exposed directly to the internet. This tutorial focuses on a single-host Docker Compose deployment. Docker's current documentation supports health-check-aware startup ordering through `depends_on` with `condition: service_healthy`, named volumes for persistent state, and the Compose plugin through the `docker compose` command. Docker also recommends using secrets rather than ordinary environment variables for sensitive values. See the [Docker Compose plugin installation guide](https://docs.docker.com/compose/install/linux/), [startup-order documentation](https://docs.docker.com/compose/how-tos/startup-order/), and [environment-variable guidance](https://docs.docker.com/compose/how-tos/environment-variables/set-environment-variables/) for the upstream behavior used here. You need Ubuntu 24.04, Docker Engine with the Compose plugin, SSH access with sudo privileges, and enough capacity for the application, PostgreSQL, and Redis you intend to run. ## Step 1 — Verify Docker Engine and the Compose Plugin Confirm Docker and Compose are installed: ```bash docker --version docker compose version ``` If `docker compose` is missing but Docker Engine is already installed from Docker's official repository, install the plugin: ```bash sudo apt update sudo apt install -y docker-compose-plugin ``` Docker's current Linux documentation treats `docker compose` as the supported plugin command. The old standalone `docker-compose` installation is retained only for backward compatibility. If Docker Engine itself is not installed, follow [How to Install Docker on Ubuntu 24.04](/learn/tutorials/install-docker-ubuntu-24-04) instead of mixing package sources. **Verify:** `docker info` should complete successfully and `docker compose version` should report an installed Compose plugin. ## Step 2 — Create the Project and Secret Directories Create a project directory: ```bash mkdir -p ~/task-api/src ~/task-api/secrets cd ~/task-api ``` Generate a random PostgreSQL password directly into a local secret file: ```bash openssl rand -hex 32 > secrets/postgres_password chmod 600 secrets/postgres_password ``` Prevent local secret material from being committed to Git: ```bash cat > .gitignore <<'EOF' secrets/ .env EOF ``` Do not paste the generated password into `compose.yaml`, shell history, screenshots, or support tickets. **Verify:** `stat -c '%a %n' secrets/postgres_password` should show mode `600`, and `wc -c secrets/postgres_password` should confirm the file is non-empty without printing the secret. ## Step 3 — Create the Node.js API Create the application package file: ```bash cat > src/package.json <<'EOF' { "name": "compose-task-api", "version": "1.0.0", "private": true, "main": "index.js", "dependencies": { "express": "^4.21.0", "pg": "^8.13.0", "redis": "^4.7.0" } } EOF ``` Create the API: ```bash cat > src/index.js <<'EOF' const fs = require('fs'); const express = require('express'); const { Pool } = require('pg'); const { createClient } = require('redis'); const app = express(); app.use(express.json()); const dbPassword = fs.readFileSync( process.env.POSTGRES_PASSWORD_FILE || '/run/secrets/postgres_password', 'utf8' ).trim(); const pool = new Pool({ host: process.env.POSTGRES_HOST || 'db', port: 5432, user: process.env.POSTGRES_USER || 'taskuser', password: dbPassword, database: process.env.POSTGRES_DB || 'taskdb' }); const redis = createClient({ url: `redis://${process.env.REDIS_HOST || 'cache'}:6379` }); redis.on('error', (err) => console.error('Redis error:', err.message)); app.get('/health', async (req, res) => { try { await pool.query('SELECT 1'); await redis.ping(); res.json({ status: 'ok' }); } catch (err) { res.status(503).json({ status: 'error' }); } }); app.get('/tasks', async (req, res) => { const cached = await redis.get('tasks'); if (cached) return res.json(JSON.parse(cached)); const { rows } = await pool.query( 'SELECT id, title, done, created_at FROM tasks ORDER BY id DESC' ); await redis.setEx('tasks', 30, JSON.stringify(rows)); res.json(rows); }); app.post('/tasks', async (req, res) => { const title = String(req.body.title || '').trim(); if (!title || title.length > 255) { return res.status(400).json({ error: 'title must contain 1-255 characters' }); } const { rows } = await pool.query( 'INSERT INTO tasks (title) VALUES ($1) RETURNING id, title, done, created_at', [title] ); await redis.del('tasks'); res.status(201).json(rows[0]); }); async function start() { await redis.connect(); await pool.query(` CREATE TABLE IF NOT EXISTS tasks ( id SERIAL PRIMARY KEY, title VARCHAR(255) NOT NULL, done BOOLEAN NOT NULL DEFAULT false, created_at TIMESTAMPTZ NOT NULL DEFAULT NOW() ) `); app.listen(3000, '0.0.0.0', () => { console.log('Task API listening on port 3000'); }); } start().catch((err) => { console.error(err); process.exit(1); }); EOF ``` The API verifies both PostgreSQL and Redis on `/health`, uses parameterized SQL for task creation, and reads the database password from a mounted secret file. **Verify:** Run `node --check src/index.js` if Node.js is installed on the host. If it is not, continue to the container build and use the container logs as the syntax/runtime check. ## Step 4 — Create the Application Dockerfile Create `src/Dockerfile`: ```bash cat > src/Dockerfile <<'EOF' FROM node:22-slim WORKDIR /app COPY package.json ./ RUN npm install --omit=dev && npm cache clean --force COPY index.js ./ EXPOSE 3000 USER node CMD ["node", "index.js"] EOF ``` The application runs as the image's non-root `node` user. The Dockerfile does not copy your project-level `secrets/` directory into the image. Create a Docker build ignore file: ```bash cat > src/.dockerignore <<'EOF' node_modules npm-debug.log EOF ``` **Verify:** Run `docker build -t task-api-check ./src`. The image build should finish successfully without copying secret files into the build context. ## Step 5 — Define the Multi-Container Compose Stack Create `compose.yaml`: ```bash cat > compose.yaml <<'EOF' services: app: build: ./src restart: unless-stopped environment: POSTGRES_HOST: db POSTGRES_USER: taskuser POSTGRES_DB: taskdb POSTGRES_PASSWORD_FILE: /run/secrets/postgres_password REDIS_HOST: cache secrets: - postgres_password ports: - "127.0.0.1:3000:3000" depends_on: db: condition: service_healthy restart: true cache: condition: service_healthy restart: true networks: - backend db: image: postgres:16-alpine restart: unless-stopped environment: POSTGRES_USER: taskuser POSTGRES_DB: taskdb POSTGRES_PASSWORD_FILE: /run/secrets/postgres_password secrets: - postgres_password volumes: - pgdata:/var/lib/postgresql/data healthcheck: test: ["CMD-SHELL", "pg_isready -U taskuser -d taskdb"] interval: 10s timeout: 5s retries: 5 start_period: 20s networks: - backend cache: image: redis:7-alpine restart: unless-stopped command: ["redis-server", "--appendonly", "yes"] volumes: - redisdata:/data healthcheck: test: ["CMD", "redis-cli", "ping"] interval: 10s timeout: 5s retries: 5 start_period: 10s networks: - backend secrets: postgres_password: file: ./secrets/postgres_password volumes: pgdata: redisdata: networks: backend: driver: bridge EOF ``` The database and Redis services have no `ports` section, so they are not published on the host. The API is published only on `127.0.0.1:3000`. Docker Compose waits for the PostgreSQL and Redis health checks because both dependencies use `condition: service_healthy`. **Verify:** Run `docker compose config -q` and `docker compose config --services`. Validation should pass and the service list should contain `app`, `db`, and `cache`. ## Step 6 — Start the Stack and Wait for Healthy Dependencies Build and start the application: ```bash cd ~/task-api docker compose up -d --build ``` Check the containers: ```bash docker compose ps ``` Review the application logs: ```bash docker compose logs --tail=100 app ``` Compose starts dependencies in order, but simple startup ordering alone does not mean a database is ready to accept connections. The health checks in this tutorial provide the readiness condition before the app is started. **Verify:** PostgreSQL and Redis should report healthy status, the app should be running, and the app log should contain `Task API listening on port 3000` without a repeating database or Redis connection error. ## Step 7 — Test the Application End to End Check the health endpoint from the VM: ```bash curl -fsS http://127.0.0.1:3000/health ``` Expected result: ```json {"status":"ok"} ``` Create a task: ```bash curl -fsS -X POST http://127.0.0.1:3000/tasks \ -H 'Content-Type: application/json' \ -d '{"title":"Deploy with Docker Compose"}' ``` Retrieve tasks: ```bash curl -fsS http://127.0.0.1:3000/tasks ``` The request path now exercises the application container, PostgreSQL service, Redis service, Compose network, secret mount, and database volume together. **Verify:** `/health` should return `status: ok`, the POST should return the created task, and the GET should return that task. ## Step 8 — Confirm Internal Services Are Not Published Publicly List listening host ports: ```bash sudo ss -lntp | grep -E ':(3000|5432|6379)\b' || true ``` Only the API's localhost mapping should appear: ```text 127.0.0.1:3000 ``` PostgreSQL port 5432 and Redis port 6379 should not be listening on the host merely because the containers use those ports internally. Inspect Compose port mappings: ```bash docker compose ps ``` For a public application, place Nginx or Caddy in front of `127.0.0.1:3000` and terminate HTTPS there instead of changing the API mapping to `0.0.0.0:3000`. See [How to Install Caddy on Ubuntu 24.04 as a Reverse Proxy](/learn/tutorials/install-caddy-ubuntu-24-04-reverse-proxy) or [How to Secure Nginx with Let's Encrypt](/learn/tutorials/secure-nginx-lets-encrypt-ubuntu-24-04). **Verify:** The host should not expose 5432 or 6379, and port 3000 should remain bound to `127.0.0.1`. ## Step 9 — Inspect Logs, Health, and Resource Usage Check service state: ```bash docker compose ps ``` View recent logs without following indefinitely: ```bash docker compose logs --tail=100 app docker compose logs --tail=100 db docker compose logs --tail=100 cache ``` View a current resource snapshot: ```bash docker compose stats --no-stream ``` Treat the output as a measurement of your current workload, not as a universal sizing rule. CPU and memory use vary with image versions, database state, traffic, query patterns, and application behavior. **Verify:** Services should remain running, PostgreSQL and Redis should remain healthy, and logs should not show unresolved repeating errors. :::cta Deploy Your Server Deploy a Raff Linux VM and use this tutorial to run a multi-container Docker Compose application with persistent data and private service networking. ::: ## Step 10 — Verify Named-Volume Persistence Create another task: ```bash curl -fsS -X POST http://127.0.0.1:3000/tasks \ -H 'Content-Type: application/json' \ -d '{"title":"Persistence test"}' ``` Remove the containers and Compose network without deleting volumes: ```bash docker compose down ``` Confirm the project volumes still exist: ```bash docker volume ls | grep -E 'pgdata|redisdata' ``` Recreate the stack: ```bash docker compose up -d ``` Wait for the health checks, then query the API: ```bash curl -fsS http://127.0.0.1:3000/tasks ``` A normal `docker compose down` does not delete named volumes. `docker compose down -v` does. **Verify:** The `Persistence test` task should still exist after the containers are recreated. ## Step 11 — Back Up PostgreSQL Before Updates or Destructive Changes Create a protected backup directory: ```bash mkdir -p ~/task-api/backups chmod 700 ~/task-api/backups ``` Create a PostgreSQL dump: ```bash cd ~/task-api docker compose exec -T db \ pg_dump -U taskuser -d taskdb \ > "backups/taskdb-$(date +%F-%H%M%S).sql" ``` Check that the file exists and is non-empty: ```bash ls -lh backups/ test -s "$(ls -1t backups/taskdb-*.sql | head -n 1)" && echo 'Database dump is non-empty' ``` A backup stored only on the same VM is not a complete disaster-recovery plan. Copy production backups to separate protected storage and test restore procedures before relying on them. **Verify:** A timestamped, non-empty SQL dump should exist before you perform an update or any command that may delete data. ## Step 12 — Update the Stack with a Controlled Recreate Before changing image tags or application code, create a fresh backup and review the relevant release notes. Pull service images: ```bash docker compose pull db cache ``` Rebuild the application image and recreate changed services: ```bash docker compose up -d --build ``` Check state and logs: ```bash docker compose ps docker compose logs --tail=100 app ``` Do not upgrade PostgreSQL to a new major version by simply changing `postgres:16-alpine` to another major tag while reusing the same data directory. PostgreSQL major-version upgrades require an appropriate upgrade or dump-and-restore procedure. **Verify:** The expected containers should be running after the recreate, the dependencies should be healthy, and `/health` should return `status: ok`. ## Step 13 — Troubleshoot Common Docker Compose Failures If Compose rejects the YAML, validate it: ```bash docker compose config -q ``` If the application exits, inspect its logs and dependency health: ```bash docker compose ps docker compose logs --tail=150 app docker compose logs --tail=150 db docker compose logs --tail=150 cache ``` If PostgreSQL never becomes healthy, check readiness directly: ```bash docker compose exec -T db pg_isready -U taskuser -d taskdb ``` If Redis is unhealthy: ```bash docker compose exec -T cache redis-cli ping ``` If the application cannot read the database secret, confirm the secret is mounted without printing it: ```bash docker compose exec -T app sh -lc 'test -s /run/secrets/postgres_password && echo secret-mounted' ``` If port 3000 cannot bind, identify the current listener: ```bash sudo ss -lntp | grep ':3000' ``` **Verify:** Fix one layer at a time in this order: Compose validation, dependency health, secret mount, application logs, then host port binding. ## Step 14 — Run the Final End-to-End Verification and Clean Up Safely Run the final checks: ```bash cd ~/task-api docker compose config -q docker compose ps curl -fsS http://127.0.0.1:3000/health curl -fsS http://127.0.0.1:3000/tasks sudo ss -lntp | grep -E ':(3000|5432|6379)\b' || true ls -lh backups/ ``` The deployment is complete when the Compose file validates, dependencies are healthy, the API can read PostgreSQL and Redis, data survives a normal container recreate, and only the intended localhost API port is published. To stop the application while keeping data: ```bash docker compose down ``` To restart later: ```bash docker compose up -d ``` Only use the following destructive command when you intentionally want to delete the project's named volumes and have verified any backups you need: ```bash docker compose down -v ``` Remove the project files only after confirming they are no longer needed: ```bash rm -rf ~/task-api ``` **Verify:** After a normal `down`, the named volumes should remain. After an intentional `down -v`, the Compose project volumes should be removed. ## Conclusion You now have a multi-container Docker Compose application running on Ubuntu 24.04 with a Node.js API, PostgreSQL, Redis, health-check-aware dependency startup, a mounted database secret, private service networking, named-volume persistence, backup steps, troubleshooting, and cleanup instructions. Raff [Linux VM](/products/linux-vm) plans start at $4.99 per month. Choose VM capacity from actual application, database, cache, traffic, and storage measurements rather than a fixed Compose-specific size. Docker Compose is a practical fit for single-host deployments; when your architecture requires scheduling workloads across multiple nodes, evaluate an orchestrator such as [Managed Kubernetes](/products/kubernetes) instead. --- ### How to Automate Rsync Backups with Cron on Ubuntu 24.04 URL: https://rafftechnologies.com/learn/tutorials/automate-backups-cron-rsync-ubuntu-24-04 Description: Automate rsync backups on Ubuntu 24.04 with cron, safe --delete dry runs, locking, retention, integrity checks, restore testing, and troubleshooting. Automating rsync backups with cron on Ubuntu 24.04 is useful for application files, configuration directories, and other file-based data that can be copied consistently. On a Raff Linux VM, a safe workflow is to test rsync manually, preview destructive options with `--dry-run`, create versioned restore archives, prevent overlapping runs, schedule the job with cron, and verify that a restore actually works. This tutorial deliberately separates three concepts that are often mixed together: an **rsync mirror** keeps a destination synchronized with the current source, a **versioned archive** gives you an older restore point, and an **off-server copy** protects against loss of the VM itself. A mirror alone is not enough for every recovery scenario, especially when `--delete` is enabled, because deletions at the source can be propagated to the destination. You will build a small backup workflow for `/srv/sample-app`, use rsync for the current mirror, create timestamped compressed archives for retention, verify checksums, schedule both backup and health-check jobs with cron, and perform a real restore test. The example is appropriate for file-based application data. Do not copy a live database data directory with rsync and assume it is transactionally consistent; use the database's supported dump, snapshot, or backup method first. Prerequisites: - A Raff Linux VM running Ubuntu 24.04 - SSH access with a non-root sudo user - Enough free disk space for the test backup and retained archives - No public firewall port is required for the local workflow ## Step 1 — Install rsync, cron, and Backup Utilities Install the tools used by the workflow: ```bash sudo apt update sudo apt install -y rsync cron tar gzip coreutils util-linux sudo systemctl enable --now cron ``` Check the installed tools and cron service: ```bash rsync --version | head -n 1 tar --version | head -n 1 flock --version | head -n 1 systemctl is-active cron ``` Do not depend on exact package patch versions in automation; Ubuntu updates can change them while keeping command behavior compatible. **Verify:** `rsync`, `tar`, and `flock` should report versions, and `systemctl is-active cron` should return `active`. ## Step 2 — Create Safe Test Data for the Rsync Backup Create a small application directory so every backup and restore step can be verified without touching production data: ```bash sudo mkdir -p /srv/sample-app/config sudo tee /srv/sample-app/app.txt > /dev/null <<'EOF' Raff rsync backup tutorial test file EOF sudo tee /srv/sample-app/config/settings.env > /dev/null <<'EOF' APP_NAME=raff-rsync-demo APP_ENV=production EOF sudo chown -R root:root /srv/sample-app sudo find /srv/sample-app -type d -exec chmod 750 {} + sudo find /srv/sample-app -type f -exec chmod 640 {} + ``` List the source tree: ```bash sudo find /srv/sample-app -maxdepth 3 -type f -print sudo cat /srv/sample-app/app.txt ``` For a real application, identify what can be copied while the application is running. Configuration files and immutable assets are usually straightforward; live database files, queues, and frequently changing application state may require an application-aware backup step. **Verify:** Both test files should exist and `app.txt` should contain `Raff rsync backup tutorial test file`. ## Step 3 — Create Backup, Log, and Restore Directories Create separate locations for the current rsync mirror, versioned archives, logs, and restore testing: ```bash sudo mkdir -p \ /var/backups/raff-rsync/mirror/sample-app \ /var/backups/raff-rsync/archives \ /var/backups/raff-rsync/logs \ /var/backups/raff-rsync/restore-test sudo chown -R root:root /var/backups/raff-rsync sudo chmod 750 /var/backups/raff-rsync sudo chmod 750 /var/backups/raff-rsync/{mirror,archives,logs,restore-test} ``` Inspect the structure: ```bash sudo find /var/backups/raff-rsync -maxdepth 2 -type d -print ``` Keeping backup data outside the source tree avoids recursive copies where a backup begins copying its own previous output. **Verify:** The `mirror`, `archives`, `logs`, and `restore-test` directories should exist under `/var/backups/raff-rsync`. ## Step 4 — Test the Rsync Backup Command with --dry-run The source path's trailing slash matters. This command copies the **contents** of `/srv/sample-app/` into the destination directory: ```bash sudo rsync -a --itemize-changes --dry-run \ /srv/sample-app/ \ /var/backups/raff-rsync/mirror/sample-app/ ``` The rsync `-a` option is archive mode: it recursively copies files and preserves common metadata such as permissions and timestamps. It does not automatically include every metadata class such as ACLs, extended attributes, or hard links. If those matter to your application, review and test options such as `-A`, `-X`, or `-H` for your destination filesystem. Now preview the behavior that will eventually keep the mirror exact: ```bash sudo rsync -a --delete-delay --itemize-changes --dry-run \ /srv/sample-app/ \ /var/backups/raff-rsync/mirror/sample-app/ ``` `--delete` and its variants remove destination files that no longer exist at the source. Rsync's own documentation recommends using `--dry-run` first because deletion options can be dangerous when source or destination paths are wrong. Do not enable deletion until you have verified both paths and the dry-run output. **Verify:** The dry run should show planned copies without changing the destination. Confirm that the source is `/srv/sample-app/` and the destination is `/var/backups/raff-rsync/mirror/sample-app/` before continuing. ## Step 5 — Create a Locked Rsync Backup Script Create `/usr/local/sbin/raff-rsync-backup.sh`: ```bash sudo tee /usr/local/sbin/raff-rsync-backup.sh > /dev/null <<'EOF' #!/usr/bin/env bash set -Eeuo pipefail umask 077 BACKUP_ROOT="/var/backups/raff-rsync" SOURCE_DIR="/srv/sample-app" MIRROR_DIR="${BACKUP_ROOT}/mirror/sample-app" ARCHIVE_DIR="${BACKUP_ROOT}/archives" LOG_DIR="${BACKUP_ROOT}/logs" LOG_FILE="${LOG_DIR}/backup.log" RETENTION_DAYS=7 STAMP="$(date -u +%Y%m%dT%H%M%SZ)" ARCHIVE_FILE="${ARCHIVE_DIR}/sample-app-${STAMP}.tar.gz" ARCHIVE_TMP="${ARCHIVE_FILE}.part" mkdir -p "$MIRROR_DIR" "$ARCHIVE_DIR" "$LOG_DIR" exec 9>/run/raff-rsync-backup.lock if ! flock -n 9; then printf '%s SKIP backup already running\n' "$(date -Is)" >> "$LOG_FILE" exit 75 fi trap 'rc=$?; printf "%s ERROR exit=%s line=%s\n" "$(date -Is)" "$rc" "$LINENO" >> "$LOG_FILE"; rm -f "$ARCHIVE_TMP"; exit "$rc"' ERR if [ ! -d "$SOURCE_DIR" ]; then printf '%s ERROR source missing: %s\n' "$(date -Is)" "$SOURCE_DIR" >> "$LOG_FILE" exit 1 fi printf '%s START source=%s\n' "$(date -Is)" "$SOURCE_DIR" >> "$LOG_FILE" rsync -a --delete-delay --itemize-changes \ "$SOURCE_DIR"/ \ "$MIRROR_DIR"/ >> "$LOG_FILE" 2>&1 tar -C "$(dirname "$SOURCE_DIR")" \ -czf "$ARCHIVE_TMP" \ "$(basename "$SOURCE_DIR")" gzip -t "$ARCHIVE_TMP" mv "$ARCHIVE_TMP" "$ARCHIVE_FILE" sha256sum "$ARCHIVE_FILE" > "${ARCHIVE_FILE}.sha256" find "$ARCHIVE_DIR" -maxdepth 1 -type f \ \( -name 'sample-app-*.tar.gz' -o -name 'sample-app-*.tar.gz.sha256' \) \ -mmin "+$((RETENTION_DAYS * 1440))" -delete printf '%s OK archive=%s\n' "$(date -Is)" "$ARCHIVE_FILE" >> "$LOG_FILE" EOF sudo chown root:root /usr/local/sbin/raff-rsync-backup.sh sudo chmod 750 /usr/local/sbin/raff-rsync-backup.sh ``` The script adds several safeguards missing from many basic rsync cron examples: - `set -Eeuo pipefail` stops on command and pipeline failures; - `flock` prevents a second backup from starting while the first is still running; - the archive is written to a `.part` file before being renamed into place; - `gzip -t` checks the compressed archive before it is accepted; - a SHA-256 file is written for later integrity verification; - retention uses minutes so the seven-day threshold is explicit; - logs contain START, OK, SKIP, or ERROR states. Check shell syntax before executing it: ```bash sudo bash -n /usr/local/sbin/raff-rsync-backup.sh ``` **Verify:** `bash -n` should exit without output or syntax errors, and the script should be owned by root with mode `750`. ## Step 6 — Run the First Rsync Backup Manually Never make cron the first execution of a new backup script. Run it manually: ```bash sudo /usr/local/sbin/raff-rsync-backup.sh ``` Check the log: ```bash sudo tail -n 20 /var/backups/raff-rsync/logs/backup.log ``` List the current mirror and versioned archives: ```bash sudo find /var/backups/raff-rsync/mirror/sample-app -maxdepth 3 -type f -print sudo ls -lh /var/backups/raff-rsync/archives/ ``` You should have both a current rsync mirror and a timestamped `.tar.gz` archive with a matching `.sha256` file. **Verify:** The log should end with an `OK archive=...` entry, the mirror should contain the two source files, and the archive directory should contain one `.tar.gz` plus its checksum file. ## Step 7 — Verify Backup Integrity and Restore a File Find the newest archive: ```bash LATEST_ARCHIVE="$(sudo find /var/backups/raff-rsync/archives \ -maxdepth 1 -type f -name 'sample-app-*.tar.gz' \ -printf '%T@ %p\n' | sort -nr | head -n 1 | cut -d' ' -f2-)" echo "$LATEST_ARCHIVE" ``` Verify its checksum: ```bash sudo sha256sum -c "${LATEST_ARCHIVE}.sha256" ``` Check that tar can read the full archive index: ```bash sudo tar -tzf "$LATEST_ARCHIVE" >/dev/null ``` Restore into a separate directory rather than overwriting the source: ```bash sudo rm -rf /var/backups/raff-rsync/restore-test/* sudo tar -xzf "$LATEST_ARCHIVE" \ -C /var/backups/raff-rsync/restore-test sudo cat /var/backups/raff-rsync/restore-test/sample-app/app.txt ``` Expected content: ```text Raff rsync backup tutorial test file ``` A successful copy is not enough evidence that recovery works. A restore test is the stronger check. **Verify:** `sha256sum -c` should report `OK`, `tar -tzf` should succeed, and the restored `app.txt` should contain the original text. :::cta Protect Your Server Pair file-level backups with an additional recovery layer when your production recovery plan requires protection beyond the same VM. ::: ## Step 8 — Create a Backup Health Check Create `/usr/local/sbin/raff-rsync-backup-check.sh`: ```bash sudo tee /usr/local/sbin/raff-rsync-backup-check.sh > /dev/null <<'EOF' #!/usr/bin/env bash set -Eeuo pipefail BACKUP_ROOT="/var/backups/raff-rsync" ARCHIVE_DIR="${BACKUP_ROOT}/archives" MIRROR_DIR="${BACKUP_ROOT}/mirror/sample-app" MAX_AGE_MINUTES=1440 LATEST_ARCHIVE="$(find "$ARCHIVE_DIR" \ -maxdepth 1 -type f -name 'sample-app-*.tar.gz' \ -mmin -"$MAX_AGE_MINUTES" \ -printf '%T@ %p\n' | sort -nr | head -n 1 | cut -d' ' -f2-)" if [ -z "$LATEST_ARCHIVE" ]; then echo "FAIL no archive newer than ${MAX_AGE_MINUTES} minutes" exit 1 fi sha256sum -c "${LATEST_ARCHIVE}.sha256" >/dev/null tar -tzf "$LATEST_ARCHIVE" >/dev/null test -f "$MIRROR_DIR/app.txt" echo "OK backup healthy: $LATEST_ARCHIVE" EOF sudo chown root:root /usr/local/sbin/raff-rsync-backup-check.sh sudo chmod 750 /usr/local/sbin/raff-rsync-backup-check.sh ``` Test it manually: ```bash sudo /usr/local/sbin/raff-rsync-backup-check.sh ``` The check confirms recency, checksum validity, archive readability, and the presence of the expected file in the rsync mirror. It does not replace a periodic restore test of the real application. **Verify:** The command should print `OK backup healthy:` followed by the newest archive path. ## Step 9 — Schedule the Rsync Backup with Cron Create a system cron file that runs the backup daily at 02:15 and the health check at 03:00: ```bash sudo tee /etc/cron.d/raff-rsync-backup > /dev/null <<'EOF' SHELL=/bin/bash PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin 15 2 * * * root /usr/local/sbin/raff-rsync-backup.sh 0 3 * * * root /usr/local/sbin/raff-rsync-backup-check.sh >> /var/backups/raff-rsync/logs/health.log 2>&1 EOF sudo chown root:root /etc/cron.d/raff-rsync-backup sudo chmod 644 /etc/cron.d/raff-rsync-backup ``` Files in `/etc/cron.d/` use the system-crontab format, which includes the user field after the five schedule fields. Ubuntu cron monitors these files for changes, so editing the file does not normally require restarting the cron daemon. Check the installed schedule: ```bash sudo cat /etc/cron.d/raff-rsync-backup sudo ls -l /etc/cron.d/raff-rsync-backup systemctl is-active cron ``` **Verify:** The cron file should be owned by root, not group- or world-writable, contain both jobs, and the cron service should be active. ## Step 10 — Verify Cron Timezone, Environment, and Logs Cron jobs run according to the server's configured timezone. Check it before assuming `02:15` means a particular local time: ```bash timedatectl show -p Timezone --value date ``` If the schedule must align with a business timezone, either configure the server timezone intentionally or calculate the cron schedule from the server timezone. Do not assume an interactive SSH shell and cron have the same environment. This tutorial defines an explicit `PATH` in `/etc/cron.d/raff-rsync-backup` and uses absolute script paths so the job does not depend on shell profile files. After the scheduled time passes, inspect logs: ```bash sudo tail -n 50 /var/backups/raff-rsync/logs/backup.log sudo tail -n 50 /var/backups/raff-rsync/logs/health.log sudo journalctl -u cron --since '24 hours ago' --no-pager ``` Cron can mail job output when a suitable mail system is configured, but minimal cloud servers often do not have one. Do not make silent cron mail your only backup-monitoring mechanism; retain logs and connect failures to your normal monitoring or alerting system in production. **Verify:** Confirm the timezone is the one you expect, the backup log contains an `OK` for the scheduled run, and the health log contains a successful check. ## Step 11 — Keep Rsync Mirrors Separate from Versioned and Off-Server Backups An rsync mirror is useful because later runs can transfer only what changed, but a mirror follows the current source state. If a file disappears from the source and a delete option is enabled, the destination copy can disappear too. That is why this tutorial also creates timestamped archives. For a production recovery plan, add an independent copy outside the VM as well. Options include: - a second Linux host reached through SSH and rsync; - object storage using a tool designed for S3-compatible storage, such as the [Raff Object Storage rclone workflow](/learn/tutorials/sync-files-raff-object-storage-rclone); - infrastructure-level protection through [Raff Data Protection](/products/data-protection), depending on your recovery requirements. If you use rsync over SSH, use key-based authentication suitable for automation, verify the remote host key, give the backup account only the access it needs, and test the exact command interactively before scheduling it. For databases, back up through the database's supported mechanism first. Do not rsync a live PostgreSQL or MySQL data directory and call the result a verified database backup. For PostgreSQL, use a database-aware dump or backup workflow before copying the resulting backup artifact off-server. **Verify:** Document where the independent copy lives and confirm that losing the source VM would not also destroy every retained recovery copy. ## Step 12 — Troubleshoot Rsync and Cron Backup Failures ### The rsync cron job works manually but not from cron Check the cron service, explicit PATH, file ownership, and recent cron logs: ```bash systemctl is-active cron sudo cat /etc/cron.d/raff-rsync-backup sudo ls -l /etc/cron.d/raff-rsync-backup sudo journalctl -u cron --since '2 hours ago' --no-pager ``` Cron does not run your interactive shell profile, so commands that depend on aliases, shell initialization, or an interactive SSH agent often fail when scheduled. ### Rsync wants to delete unexpected files Stop and run a dry run: ```bash sudo rsync -a --delete-delay --itemize-changes --dry-run \ /srv/sample-app/ \ /var/backups/raff-rsync/mirror/sample-app/ ``` If the output is not exactly what you expect, correct the source/destination paths before running the real command. ### The backup is skipped with exit code 75 Another run holds the lock. Check whether a backup process is legitimately still active: ```bash ps -ef | grep '[r]aff-rsync-backup.sh' sudo tail -n 20 /var/backups/raff-rsync/logs/backup.log ``` Do not remove a lock simply because a backup takes longer than usual; first determine whether the existing process is healthy or stuck. ### The checksum fails Keep the suspect archive for investigation and create a new backup rather than trusting it: ```bash sudo /usr/local/sbin/raff-rsync-backup.sh sudo /usr/local/sbin/raff-rsync-backup-check.sh ``` A checksum verifies that the archived bytes match the checksum recorded after creation. It does not prove that a changing application was captured at a transactionally consistent moment. ### The disk is filling with backups Inspect archive sizes and free space: ```bash sudo du -sh /var/backups/raff-rsync/* df -h /var/backups/raff-rsync ``` Adjust retention from measured storage usage and recovery requirements. Do not shorten retention blindly if it would remove the only recovery point you need. **Verify:** After correcting the problem, run both scripts manually and confirm the backup log ends with `OK` and the health check passes. ## Step 13 — Run the Final End-to-End Backup and Restore Test Make a controlled change to the source: ```bash echo 'second version' | sudo tee -a /srv/sample-app/app.txt >/dev/null ``` Run a fresh backup and health check: ```bash sudo /usr/local/sbin/raff-rsync-backup.sh sudo /usr/local/sbin/raff-rsync-backup-check.sh ``` Confirm the rsync mirror contains the change: ```bash sudo tail -n 2 /var/backups/raff-rsync/mirror/sample-app/app.txt ``` Restore the newest archive into the test directory: ```bash LATEST_ARCHIVE="$(sudo find /var/backups/raff-rsync/archives \ -maxdepth 1 -type f -name 'sample-app-*.tar.gz' \ -printf '%T@ %p\n' | sort -nr | head -n 1 | cut -d' ' -f2-)" sudo rm -rf /var/backups/raff-rsync/restore-test/* sudo tar -xzf "$LATEST_ARCHIVE" \ -C /var/backups/raff-rsync/restore-test sudo tail -n 2 /var/backups/raff-rsync/restore-test/sample-app/app.txt ``` Finally, confirm the cron schedule and services: ```bash systemctl is-active cron sudo cat /etc/cron.d/raff-rsync-backup sudo tail -n 10 /var/backups/raff-rsync/logs/backup.log ``` The workflow is complete only when the source change reaches the rsync mirror, a new archive is created, the checksum and health check pass, and the changed file can be restored from the archive. **Verify:** Both the mirror and restored archive should include `second version`, the health check should report `OK`, and cron should remain active with both scheduled jobs installed. ## Step 14 — Clean Up the Test Backup Workflow Safely Use this step only if you want to remove the tutorial's test data and schedule. First disable future runs: ```bash sudo rm -f /etc/cron.d/raff-rsync-backup ``` Confirm no backup script is currently running: ```bash ps -ef | grep '[r]aff-rsync-backup.sh' || true ``` Review what will be deleted: ```bash sudo du -sh /var/backups/raff-rsync sudo find /srv/sample-app -maxdepth 3 -type f -print ``` If these are only tutorial files and you have no archive you need to retain, remove them: ```bash sudo rm -f /usr/local/sbin/raff-rsync-backup.sh sudo rm -f /usr/local/sbin/raff-rsync-backup-check.sh sudo rm -rf /var/backups/raff-rsync sudo rm -rf /srv/sample-app ``` Do not adapt this cleanup command to a production path without separately confirming backups and retention requirements. **Verify:** `/etc/cron.d/raff-rsync-backup`, the two tutorial scripts, `/var/backups/raff-rsync`, and `/srv/sample-app` should be absent only when you intentionally completed cleanup. ## Conclusion You automated rsync backups with cron on Ubuntu 24.04, previewed deletion behavior with `--dry-run`, protected the job from overlapping runs, kept a current rsync mirror, created versioned compressed archives, verified checksums, tested a restore, checked cron timezone and logs, and documented the need for an independent off-server copy. The most important distinction is that **synchronization is not automatically the same as a complete backup strategy**. Rsync is excellent for efficient file copying and mirrors, but recovery planning also needs retained versions, restore testing, and a failure domain separate from the source server. For a broader recovery design, see [Cloud Server Backup Strategies](/learn/guides/cloud-server-backup-strategies). For off-server object storage, continue with [Sync Files to Raff Object Storage with rclone](/learn/tutorials/sync-files-raff-object-storage-rclone). For database workloads, use a database-aware backup workflow before copying backup artifacts. ## Sources - [rsync(1) official manpage](https://download.samba.org/pub/rsync/rsync.1) - [Ubuntu 24.04 cron(8) manpage](https://manpages.ubuntu.com/manpages/noble/man8/cron.8.html) - [Ubuntu crontab(5) manpage](https://manpages.ubuntu.com/manpages/noble/man5/crontab.5.html) - [GNU tar manual](https://www.gnu.org/software/tar/manual/) - Sources verified: 2026-09-04 --- ### How to Self-Host Plausible Analytics on Ubuntu 24.04 with Docker URL: https://rafftechnologies.com/learn/tutorials/self-host-plausible-analytics-ubuntu-24-04 Description: Self-host Plausible Analytics CE on Ubuntu 24.04 with Docker Compose, automatic HTTPS, protected secrets, health checks, backups, and safe upgrades. Plausible Community Edition (CE) can be self-hosted on Ubuntu 24.04 with Docker Compose, PostgreSQL, ClickHouse, persistent Docker volumes, and built-in HTTPS. For the current official quickstart, you do **not** need to install Nginx, Caddy, or Certbot just to get a trusted public TLS endpoint: Plausible CE can listen on ports 80 and 443 and manage Let's Encrypt certificates itself. This tutorial follows the current Plausible CE v3.2.1 deployment layout verified on September 4, 2026. It uses the repository's `compose.yml`, stores required settings in `.env`, adds public port mappings through `compose.override.yml`, keeps the upstream Compose file untouched for easier upgrades, and uses the dashboard-generated tracking snippet rather than the older hard-coded `/js/script.js` pattern. Plausible's official quickstart recommends at least 2 GB of RAM and a CPU with SSE 4.2 on x86 or NEON support on ARM because ClickHouse is part of the stack. Raff Technologies is the VM platform used by the original tutorial. The original workflow was tested on Ubuntu 24.04 LTS on a Raff 1 vCPU / 2 GB RAM VM (Tier 2). This revision re-verifies the upstream Plausible CE workflow and documentation; it does not claim a new end-to-end benchmark or capacity test. When you self-host Plausible, you are responsible for upgrades, backups, availability, monitoring, and recovery. Prerequisites: - Ubuntu 24.04 with at least 2 GB RAM recommended by Plausible CE - A CPU with SSE 4.2 support on x86 or NEON support on ARM - Docker Engine with the Docker Compose plugin - SSH access with sudo privileges - A domain such as `analytics.example.com` pointing to the VM - Public TCP ports 80 and 443 available for HTTPS ## Step 1 — Verify Ubuntu, Docker, CPU support, memory, DNS, and web ports Confirm the operating system: ```bash cat /etc/os-release ``` Check Docker and Compose: ```bash docker --version docker compose version ``` If Docker is not installed, use [How to Install Docker on Ubuntu 24.04](/learn/tutorials/install-docker-ubuntu-24-04) before continuing. Check memory: ```bash free -h ``` Check CPU flags on an x86 VM: ```bash lscpu | grep -i '^Flags' | grep -o 'sse4_2' || true ``` On ARM64 systems, inspect the feature line instead: ```bash lscpu | grep -i '^Flags\|^Features' ``` Plausible's current CE quickstart requires a CPU that supports SSE 4.2 or NEON because ClickHouse depends on those instruction sets. Check DNS in both address families: ```bash dig +short A analytics.example.com dig +short AAAA analytics.example.com ``` Check whether another service already owns ports 80 or 443: ```bash sudo ss -lntp | grep -E ':(80|443)\b' || true ``` A stale `AAAA` record can cause confusing HTTPS behavior even when the IPv4 `A` record is correct, so remove or correct IPv6 DNS if this server is not serving the hostname over IPv6. **Verify:** Ubuntu should report 24.04, Docker Compose should work, the VM should meet the Plausible CE memory/CPU requirements, DNS should resolve to this server, and ports 80/443 should be available for the deployment. ## Step 2 — Install the small host utilities used by this tutorial Install Git, OpenSSL, DNS tools, and curl: ```bash sudo apt update sudo apt install -y git openssl dnsutils curl ca-certificates ``` Do not reinstall Docker from a second package source if it is already working. Mixing Ubuntu's Docker packages with Docker's official repository packages can make future upgrades harder to reason about. Confirm Git and OpenSSL are available: ```bash git --version openssl version ``` **Verify:** `git --version` and `openssl version` should both return installed versions without errors. ## Step 3 — Clone a pinned Plausible Community Edition release Create a dedicated installation path owned by your administrative user: ```bash sudo install -d -o "$USER" -g "$USER" /opt/plausible-ce ``` Clone the current CE release used by this revision: ```bash git clone -b v3.2.1 --single-branch \ https://github.com/plausible/community-edition \ /opt/plausible-ce ``` Enter the project: ```bash cd /opt/plausible-ce ``` Inspect the files: ```bash ls -la git describe --tags --exact-match ``` The current repository layout includes `compose.yml`; older tutorials that expect `docker-compose.yml` or `plausible-conf.env` are describing an older CE setup. Pinning an exact release makes upgrades intentional rather than silently changing your application stack whenever a floating image tag moves. **Verify:** `/opt/plausible-ce/compose.yml` should exist and `git describe --tags --exact-match` should report `v3.2.1` for this revision. ## Step 4 — Create a protected Plausible environment file Move into the project directory: ```bash cd /opt/plausible-ce ``` Set a restrictive file-creation mask and generate the secret without printing it to the terminal: ```bash umask 077 SECRET_KEY_BASE="$(openssl rand -base64 48 | tr -d '\n')" ``` Create `.env`: ```bash cat > .env <` of your website. Do not copy the old generic pattern from outdated tutorials: ```text /js/script.js ``` Plausible introduced a newer site-specific tracking script model in October 2025. The current snippet is generated for the site and can reflect enabled tracking options. Using the dashboard-generated snippet avoids hard-coding a path that may not match the current tracker configuration. After adding the snippet, deploy the website change and load the site in a browser. Official current tracking guidance: [Add the Plausible tracking script](https://plausible.io/docs/plausible-script). **Verify:** View the website's rendered HTML or browser developer tools and confirm the exact Plausible snippet from the site's installation screen is present in the page ``. ## Step 10 — Verify analytics end to end from a real browser visit Open the tracked website in a normal browser session and navigate between a few pages. In browser developer tools, open **Network** and filter for your Plausible hostname. Confirm that the tracker script loads and that an analytics event request is sent when a pageview occurs. Then return to the Plausible dashboard and use its installation check or realtime view to confirm the visit is being received. This is a better production verification than posting a fabricated event with a forged `X-Forwarded-For` header or querying an internal ClickHouse table name. Internal schemas and tracker payloads can change between CE releases; the public tracker and dashboard are the interfaces your real site depends on. If the request is blocked, check browser extensions, Content Security Policy, the generated snippet, the site's domain setting, and the Plausible `BASE_URL` before changing database configuration. :::cta Deploy Your Analytics Server Launch a Raff Ubuntu VM and run Plausible Community Edition with Docker Compose and automatic HTTPS. ::: **Verify:** A real browser pageview should produce a request to your Plausible instance and appear in the site's Plausible dashboard or installation check. ## Step 11 — Use an external Caddy reverse proxy only when your topology needs one Starting with Plausible CE 2.1.2, an external reverse proxy is optional because Plausible can manage HTTPS itself. Keep the built-in HTTPS setup from the previous steps unless you already operate Caddy/Nginx as a shared edge or have another architectural reason to proxy Plausible. If you choose Caddy, change `.env` so Plausible listens on its internal HTTP port instead of managing public TLS: ```dotenv BASE_URL=https://analytics.example.com HTTP_PORT=8000 ``` Remove `HTTPS_PORT=443` from `.env`, then replace the direct-public override with a loopback mapping: ```yaml services: plausible: ports: - "127.0.0.1:8000:8000" ``` A minimal Caddy site is: ```caddyfile analytics.example.com { reverse_proxy 127.0.0.1:8000 } ``` Then validate and recreate Plausible before configuring/reloading Caddy: ```bash cd /opt/plausible-ce docker compose config -q docker compose up -d curl -I http://127.0.0.1:8000 ``` For the full Caddy edge workflow, use [How to Set Up a Caddy Reverse Proxy on Ubuntu 24.04](/learn/tutorials/install-caddy-ubuntu-24-04-reverse-proxy). Do not run the direct 80/443 Plausible mode and an external reverse proxy on the same public ports at the same time. **Verify:** Choose exactly one public-edge model: either Plausible owns 80/443 with built-in TLS, or the app listens on `127.0.0.1:8000` and your external proxy owns the public web ports. ## Step 12 — Back up PostgreSQL, ClickHouse, Plausible data, and configuration Self-hosted Plausible stores different classes of state in multiple persistent volumes. PostgreSQL stores account/site configuration, ClickHouse stores analytics data, and the Plausible service has its own persistent application-data volume. A PostgreSQL dump alone is therefore **not** a complete Plausible backup. Create a protected backup directory: ```bash cd /opt/plausible-ce STAMP="$(date +%F-%H%M%S)" BACKUP_DIR="/opt/plausible-ce/backups/$STAMP" mkdir -p "$BACKUP_DIR" chmod 700 /opt/plausible-ce/backups "$BACKUP_DIR" ``` Create a logical PostgreSQL dump while the stack is running: ```bash docker compose exec -T plausible_db \ pg_dump -U postgres plausible_db \ | gzip > "$BACKUP_DIR/plausible-postgres.sql.gz" ``` Capture the exact Docker volume names before stopping the services: ```bash DB_VOL="$(docker inspect "$(docker compose ps -q plausible_db)" --format '{{range .Mounts}}{{if eq .Destination "/var/lib/postgresql/data"}}{{.Name}}{{end}}{{end}}')" EVENT_VOL="$(docker inspect "$(docker compose ps -q plausible_events_db)" --format '{{range .Mounts}}{{if eq .Destination "/var/lib/clickhouse"}}{{.Name}}{{end}}{{end}}')" EVENT_LOG_VOL="$(docker inspect "$(docker compose ps -q plausible_events_db)" --format '{{range .Mounts}}{{if eq .Destination "/var/log/clickhouse-server"}}{{.Name}}{{end}}{{end}}')" APP_VOL="$(docker inspect "$(docker compose ps -q plausible)" --format '{{range .Mounts}}{{if eq .Destination "/var/lib/plausible"}}{{.Name}}{{end}}{{end}}')" ``` Stop the stack for a consistent volume-level archive: ```bash docker compose stop ``` Archive each named volume read-only: ```bash docker run --rm -v "$DB_VOL:/source:ro" -v "$BACKUP_DIR:/backup" \ alpine:3 tar -czf /backup/db-data.tar.gz -C /source . docker run --rm -v "$EVENT_VOL:/source:ro" -v "$BACKUP_DIR:/backup" \ alpine:3 tar -czf /backup/event-data.tar.gz -C /source . docker run --rm -v "$EVENT_LOG_VOL:/source:ro" -v "$BACKUP_DIR:/backup" \ alpine:3 tar -czf /backup/event-logs.tar.gz -C /source . docker run --rm -v "$APP_VOL:/source:ro" -v "$BACKUP_DIR:/backup" \ alpine:3 tar -czf /backup/plausible-data.tar.gz -C /source . ``` Back up the deployment configuration and restart: ```bash cp .env compose.override.yml "$BACKUP_DIR/" chmod 600 "$BACKUP_DIR/.env" docker compose start ``` Check the archives: ```bash gzip -t "$BACKUP_DIR/plausible-postgres.sql.gz" ls -lh "$BACKUP_DIR" ``` Keep at least one verified copy away from the VM. Raff [Data Protection](/products/data-protection) can provide an additional infrastructure-level recovery layer, and [Object Storage](/products/object-storage) can be used as an off-server destination for backup archives when your backup workflow supports it. **Verify:** The backup set should contain the PostgreSQL dump, archives for all persistent CE volumes, `.env`, and `compose.override.yml`; the stack should return to its previous running state after `docker compose start`. ## Step 13 — Upgrade Plausible CE with an exact version and a rollback plan Check the installed version first: ```bash cd /opt/plausible-ce git describe --tags --exact-match docker compose images ``` Before upgrading: 1. Create and verify a fresh backup. 2. Read the Plausible CE release notes and version-specific upgrade instructions. 3. Choose an exact target tag rather than following `latest` blindly. Fetch release tags: ```bash git fetch --tags origin ``` When you have deliberately chosen a newer target, replace the placeholder below with that exact release: ```bash TARGET=vX.Y.Z git fetch origin tag "$TARGET" git checkout "$TARGET" docker compose pull docker compose up -d ``` Then verify: ```bash git describe --tags --exact-match docker compose ps docker compose logs --tail=100 plausible curl -I https://analytics.example.com ``` Plausible recommends version pinning, with patch-version pinning providing the most control. Major releases can require additional migration steps, so an old image tag is not automatically a safe rollback after database migrations. Follow the target release notes rather than assuming every upgrade is reversible by changing an image tag. **Verify:** The intended exact release should be checked out, the databases should recover to healthy state, Plausible should run without migration loops, and the public HTTPS dashboard should still respond. ## Step 14 — Run the final checks and clean up safely when needed For the built-in HTTPS topology used by the main tutorial, run: ```bash cd /opt/plausible-ce docker compose config -q git describe --tags --exact-match docker compose ps stat -c '%a %n' .env curl -I http://analytics.example.com curl -I https://analytics.example.com ls -lh backups/ 2>/dev/null || true ``` Also confirm in the browser that: - the dashboard loads over trusted HTTPS; - the administrator can sign in; - the tracked site's current dashboard-generated snippet is installed; - a real page visit appears in Plausible; - no PostgreSQL or ClickHouse port is publicly exposed. To stop Plausible without deleting persistent data: ```bash docker compose down ``` A normal `docker compose down` keeps named volumes. To restart: ```bash docker compose up -d ``` Do **not** use this destructive command unless you intentionally want to remove the databases and analytics history and have already verified your backups: ```bash docker compose down -v ``` Remove `/opt/plausible-ce` only after you have decided that its configuration and local backup copies are no longer needed. **Verify:** After a normal `down`, the Plausible named volumes should remain. After restarting, the existing account, site configuration, and analytics history should still be present. ## Troubleshooting ### Automatic HTTPS does not obtain a certificate Check both DNS families and port ownership: ```bash dig +short A analytics.example.com dig +short AAAA analytics.example.com sudo ss -lntp | grep -E ':(80|443)\b' || true cd /opt/plausible-ce docker compose logs --tail=150 plausible ``` The hostname must resolve to the server and ports 80/443 must reach the Plausible container. Remove stale IPv6 DNS if the server is not actually reachable over that IPv6 address. ### Plausible or a database repeatedly restarts Check the full state and service-specific logs: ```bash cd /opt/plausible-ce docker compose ps docker compose logs --tail=150 plausible docker compose logs --tail=150 plausible_db docker compose logs --tail=150 plausible_events_db ``` Also confirm the VM has at least the 2 GB RAM recommended by the current CE quickstart: ```bash free -h docker stats --no-stream ``` Treat resource output as a measurement of your instance, not as a universal pageview-capacity estimate. ### The dashboard loads but tracking data does not arrive Use the current snippet copied from the site's installation settings. Then check the website's browser Network panel for the tracker script and event request. Common causes include: - an old or manually edited tracking snippet; - a restrictive Content Security Policy; - browser privacy/ad-blocking extensions; - the wrong site domain in Plausible; - a wrong `BASE_URL` after moving the analytics instance. Do not start by editing ClickHouse tables or fabricating events against an assumed internal schema. ### The external reverse proxy returns 502 If you intentionally selected the optional proxy topology, verify the loopback upstream first: ```bash curl -I http://127.0.0.1:8000 sudo ss -lntp | grep ':8000' ``` The override should map `127.0.0.1:8000:8000`, and `.env` should contain `HTTP_PORT=8000` without the direct `HTTPS_PORT=443` setup. ### WebSocket features fail behind Nginx Plausible's current community Nginx example includes an explicit `/live/websocket` WebSocket location with HTTP/1.1 upgrade headers. Do not describe the live connection as ordinary buffered HTTP or assume a generic proxy block handles every Nginx WebSocket case. Caddy's `reverse_proxy` handles WebSocket upgrades automatically. ### An upgrade fails after migrations start Stop making repeated image/tag changes. Read the release-specific upgrade notes, preserve the failing state and logs, and restore from your pre-upgrade backup when the documented recovery path requires it. Database migrations can make a simple image downgrade unsafe. ## Conclusion You now have Plausible Community Edition running on Ubuntu 24.04 with its current Docker Compose layout, a pinned CE release, protected secrets, built-in automatic HTTPS, current site-specific tracking, persistent PostgreSQL and ClickHouse data, a complete backup plan, and a controlled upgrade path. Plausible is designed for privacy-focused, cookieless aggregate web analytics, but your site's legal obligations depend on your jurisdiction, configuration, and any other trackers or personal-data processing you use. Self-hosting also moves the operational responsibility to you: keep CE updated, monitor storage and memory, protect the server, and test restores rather than assuming a VM snapshot or PostgreSQL dump alone covers the entire analytics stack. For adjacent workflows, use [Install Docker on Ubuntu 24.04](/learn/tutorials/install-docker-ubuntu-24-04), [Caddy Reverse Proxy on Ubuntu 24.04](/learn/tutorials/install-caddy-ubuntu-24-04-reverse-proxy), and Raff [Data Protection](/products/data-protection). ## Sources - [Plausible Community Edition — v3.2.1 Quick Start](https://github.com/plausible/community-edition/tree/v3.2.1) - [Plausible CE — Configuration](https://github.com/plausible/community-edition/wiki/Configuration) - [Plausible CE — Reverse Proxy](https://github.com/plausible/community-edition/wiki/reverse-proxy) - [Plausible CE — Upgrade](https://github.com/plausible/community-edition/wiki/upgrade) - [Plausible Docs — Add the tracking script](https://plausible.io/docs/plausible-script) - [Plausible Docs — Update your tracking script](https://plausible.io/docs/script-update-guide) - Plausible CE guidance re-verified: 2026-09-04 --- ### How to Install Open WebUI with Ollama on Ubuntu 24.04 URL: https://rafftechnologies.com/learn/tutorials/deploy-open-webui-ollama-ubuntu-24-04 Description: Install Open WebUI with Ollama on Ubuntu 24.04 using private Docker Compose networking, Caddy HTTPS, pinned versions, backups, and safe updates. Open WebUI with Ollama can run safely on one Ubuntu 24.04 server without exposing the Ollama API to the internet. The cleaner production pattern is to run **Open WebUI and Ollama as separate Docker Compose services on the same private Docker network**, publish only Open WebUI to `127.0.0.1:3000`, and let Caddy provide the public HTTPS endpoint. In this design, Open WebUI reaches Ollama at `http://ollama:11434` inside Docker; host port `11434` is never published. This tutorial uses Open WebUI **v0.11.1** and Ollama **0.33.3**, the current stable releases verified on September 4, 2026. Open WebUI's own production guidance recommends pinning a specific release instead of using the rolling `:main` or `:latest` image. A persistent `WEBUI_SECRET_KEY` is also set so container recreation does not invalidate sessions or encrypted integration data. Raff Technologies is the VM platform used by the original tutorial. The saved tested environment is Ubuntu 24.04.4 LTS on a Raff 8 vCPU / 16 GB RAM / 320 GB NVMe VM running CPU-only inference with `llama3.2:3b`. This revision updates the deployment architecture against current upstream documentation; it does not claim a new benchmark or a fresh end-to-end hardware test. Prerequisites: - An Ubuntu 24.04 VM with SSH and sudo access - Docker Engine with Docker Compose v2 - A domain such as `ai.example.com` pointed to the VM - Ports 80 and 443 available for Caddy - Enough RAM and storage for the Ollama model you choose ## Step 1 — Verify Ubuntu, Docker, DNS, memory, and free disk space Check the operating system: ```bash cat /etc/os-release ``` Verify Docker and Compose: ```bash docker --version docker compose version ``` If Docker is not installed, use [How to Install Docker on Ubuntu 24.04](/learn/tutorials/install-docker-ubuntu-24-04) before continuing. Check memory and storage: ```bash free -h df -h / ``` Check DNS in both address families: ```bash dig +short A ai.example.com dig +short AAAA ai.example.com ``` Check whether an existing service already owns the public web ports: ```bash sudo ss -lntp | grep -E ':(80|443)\b' || true ``` Model files can consume multiple gigabytes, and memory requirements vary substantially by model size, quantization, context length, concurrency, and whether inference runs on CPU or GPU. Do not size the VM from a universal "requests per second" or model-count claim. **Verify:** Ubuntu should report 24.04, Docker Compose should run, the domain should resolve to this VM, and you should have enough RAM/disk for the model you intend to pull. ## Step 2 — Create the Open WebUI and Ollama project directory Create a dedicated deployment directory: ```bash sudo install -d -o "$USER" -g "$USER" /opt/open-webui cd /opt/open-webui ``` Create a backup directory now so the path exists before the application contains important data: ```bash mkdir -p backups chmod 700 backups ``` Confirm ownership: ```bash ls -ld /opt/open-webui /opt/open-webui/backups ``` **Verify:** `/opt/open-webui` and `/opt/open-webui/backups` should exist and be writable by your administrative user. ## Step 3 — Create pinned version and secret settings Open WebUI's current production guidance recommends versioned image tags rather than rolling `:main`/`:latest` tags. Ollama also publishes versioned Docker images. Generate a persistent Open WebUI secret without printing it to the terminal: ```bash cd /opt/open-webui umask 077 WEBUI_SECRET_KEY="$(openssl rand -hex 32)" ``` Create `.env`: ```bash cat > .env < /dev/null <<'EOF' ai.example.com { reverse_proxy 127.0.0.1:3000 } EOF ``` Replace `ai.example.com` with the domain stored in `/opt/open-webui/.env`. Caddy's `reverse_proxy` supports WebSocket upgrades automatically, so you do not need to copy Nginx-style manual `Upgrade` and `Connection` header boilerplate. Format and validate the Caddyfile: ```bash sudo caddy fmt --overwrite /etc/caddy/Caddyfile sudo caddy validate --config /etc/caddy/Caddyfile ``` Reload Caddy: ```bash sudo systemctl reload caddy ``` Test both schemes: ```bash curl -I http://ai.example.com curl -I https://ai.example.com ``` **Verify:** HTTP should redirect to HTTPS, the HTTPS request should reach Open WebUI with a trusted certificate, and `127.0.0.1:3000` should remain the only host-side Open WebUI backend listener. ## Step 11 — Create the first Open WebUI administrator account Open: ```text https://ai.example.com ``` Create the first account. Current Open WebUI hardening guidance states that signup is open only until the first account is registered; that first user becomes the administrator and signup is then automatically disabled by default. Use a unique administrator password and avoid sharing the administrator account for normal multi-user access. ![Open WebUI dashboard after first login on Ubuntu 24.04](https://raff-images.s3.raffusercloud.com/open_webui_ollama_ubuntu_24_04_02_admin_dashboard_webp_8a5ddbf49c.png) The interface has changed across Open WebUI releases, so labels in an older screenshot may differ slightly from v0.11.1 even though the account workflow remains the same. **Verify:** You should be able to sign in over HTTPS, open the Admin area, and confirm the first account has administrator privileges. ## Step 12 — Verify the Ollama connection and chat with the model Open the Open WebUI administrator connection settings. In current releases, Ollama connections are managed under the administrator settings area. The backend connection for this Compose deployment is: ```text http://ollama:11434 ``` Open WebUI's current Docker guidance uses internal URLs that the backend container can actually reach; when two services share a Compose network, the service name is preferable to exposing Ollama on the host. ![Open WebUI Ollama connection settings showing a working local endpoint](https://raff-images.s3.raffusercloud.com/open_webui_ollama_ubuntu_24_04_03_ollama_connection_webp_04f2cd42bd.png) Return to chat and select: ```text llama3.2:3b ``` ![Open WebUI model selector with llama3.2 selected](https://raff-images.s3.raffusercloud.com/open_webui_ollama_ubuntu_24_04_04_model_selected_webp_5fd206c8be.png) Send a simple test prompt: ```text Reply with exactly: Open WebUI and Ollama are connected. ``` ![Open WebUI response from an Ollama model on a Raff Ubuntu 24.04 VM](https://raff-images.s3.raffusercloud.com/open_webui_ollama_ubuntu_24_04_05_successful_response_webp_01a3613167.png) :::cta Deploy Your AI Server Launch a Raff Ubuntu VM and use this private Docker Compose pattern for Open WebUI and Ollama. ::: **Verify:** The model should appear in the selector, the prompt should produce a response, and the browser should remain on the HTTPS Open WebUI domain throughout the request. ## Step 13 — Back up Open WebUI data, Ollama models, secrets, and proxy configuration Open WebUI stores users, chats, settings, uploads, and its local database under `/app/backend/data`. Ollama stores downloaded models under `/root/.ollama`. Both locations are persistent named volumes in this deployment. Create a timestamped backup directory: ```bash cd /opt/open-webui STAMP="$(date +%F-%H%M%S)" BACKUP_DIR="/opt/open-webui/backups/$STAMP" mkdir -p "$BACKUP_DIR" chmod 700 "$BACKUP_DIR" ``` Capture the exact volume names while the containers are running: ```bash WEBUI_VOL="$(docker inspect open-webui --format '{{range .Mounts}}{{if eq .Destination "/app/backend/data"}}{{.Name}}{{end}}{{end}}')" OLLAMA_VOL="$(docker inspect ollama --format '{{range .Mounts}}{{if eq .Destination "/root/.ollama"}}{{.Name}}{{end}}{{end}}')" ``` Stop the application stack for a consistent local-volume archive: ```bash docker compose stop ``` Archive both volumes: ```bash docker run --rm -v "$WEBUI_VOL:/source:ro" -v "$BACKUP_DIR:/backup" \ alpine:3 tar -czf /backup/open-webui-data.tar.gz -C /source . docker run --rm -v "$OLLAMA_VOL:/source:ro" -v "$BACKUP_DIR:/backup" \ alpine:3 tar -czf /backup/ollama-models.tar.gz -C /source . ``` Back up configuration and restart: ```bash cp .env compose.yaml "$BACKUP_DIR/" sudo cp /etc/caddy/Caddyfile "$BACKUP_DIR/Caddyfile" chmod 600 "$BACKUP_DIR/.env" docker compose start ``` Verify the archives: ```bash ls -lh "$BACKUP_DIR" tar -tzf "$BACKUP_DIR/open-webui-data.tar.gz" | head tar -tzf "$BACKUP_DIR/ollama-models.tar.gz" | head ``` Keep a protected copy away from the VM. Raff [Data Protection](/products/data-protection) can protect the infrastructure layer; application-aware backups are still valuable before upgrades and migrations. **Verify:** The backup set should contain both volume archives, `.env`, `compose.yaml`, and the Caddyfile, and the two containers should return to a running state after `docker compose start`. ## Step 14 — Update, troubleshoot, verify end to end, and clean up safely Before an update, create a fresh backup and review the release notes for both Open WebUI and Ollama. Open WebUI explicitly recommends pinned release tags for shared/production deployments. To upgrade, edit only the version values in `.env` after selecting exact target releases: ```bash cd /opt/open-webui nano .env ``` Then pull and recreate: ```bash docker compose pull docker compose up -d ``` Check versions and health: ```bash docker compose ps docker compose exec ollama ollama --version docker logs open-webui 2>&1 | head -n 30 curl -I https://ai.example.com ``` If Open WebUI cannot see Ollama, test Docker DNS and the API from the Open WebUI container: ```bash docker compose exec open-webui python3 -c \ "import urllib.request; print(urllib.request.urlopen('http://ollama:11434/api/tags', timeout=10).status)" ``` If Caddy returns 502, test the local Open WebUI backend: ```bash curl -I http://127.0.0.1:3000 docker compose logs --tail=120 open-webui sudo journalctl -u caddy -n 100 --no-pager ``` If the model does not appear: ```bash docker compose exec ollama ollama list docker compose logs --tail=120 ollama ``` If model responses are slow, inspect actual resource use instead of assuming a network problem: ```bash docker stats --no-stream free -h ``` For the final end-to-end check: ```bash cd /opt/open-webui docker compose config -q docker compose ps sudo ss -lntp | grep -E ':(80|443|3000|11434)\b' || true curl -I https://ai.example.com docker compose exec ollama ollama list ``` Expected architecture: ```text Internet | | HTTPS 443 v Caddy | | 127.0.0.1:3000 v Open WebUI container | | private Docker network: ollama:11434 v Ollama container ``` To stop the stack without deleting chats or models: ```bash docker compose down ``` Named volumes remain after a normal `down`. To restart: ```bash docker compose up -d ``` Do **not** run the following unless you intentionally want to delete Open WebUI data and downloaded Ollama models after verifying backups: ```bash docker compose down -v ``` **Verify:** Open WebUI should load over HTTPS, `llama3.2:3b` should answer a chat prompt, port 3000 should remain loopback-only, port 11434 should not be published on the host, and normal container recreation should preserve users, chats, and models. ## Conclusion You now have Open WebUI and Ollama on Ubuntu 24.04 using a private two-container Docker Compose architecture. Caddy handles public HTTPS, Open WebUI is reachable only through a loopback backend port, and Ollama is reachable only inside the Docker network. This avoids exposing the unauthenticated Ollama API merely to let a Dockerized UI reach it. The deployment also pins stable versions, keeps a persistent `WEBUI_SECRET_KEY`, preserves Open WebUI and Ollama data in named volumes, includes a complete backup set, and gives you a controlled upgrade path. The saved Raff test environment remains the original CPU-only 8 vCPU / 16 GB setup with `llama3.2:3b`; measure your own CPU, RAM, GPU, model size, context, and concurrency before choosing production capacity. For adjacent workflows, continue with [Install Docker on Ubuntu 24.04](/learn/tutorials/install-docker-ubuntu-24-04), [Caddy Reverse Proxy on Ubuntu 24.04](/learn/tutorials/install-caddy-ubuntu-24-04-reverse-proxy), or [Secure Ubuntu 24.04 Server](/learn/tutorials/secure-ubuntu-24-04-server). ## Sources - [Open WebUI — Quick Start](https://docs.openwebui.com/getting-started/quick-start/) - [Open WebUI — Environment Variable Configuration](https://docs.openwebui.com/reference/env-configuration/) - [Open WebUI — Hardening](https://docs.openwebui.com/getting-started/advanced-topics/hardening/) - [Open WebUI — Updating](https://docs.openwebui.com/getting-started/updating/) - [Open WebUI — Ollama connection](https://docs.openwebui.com/getting-started/quick-start/connect-a-provider/starting-with-ollama/) - [Ollama — Docker image](https://hub.docker.com/r/ollama/ollama) - [Ollama — FAQ](https://docs.ollama.com/faq) - [Ollama — llama3.2:3b](https://ollama.com/library/llama3.2:3b) - Open WebUI/Ollama guidance re-verified: 2026-09-04 --- ### How to Build a Remote Development VM with code-server and Tailscale URL: https://rafftechnologies.com/learn/tutorials/build-remote-development-vm-code-server-tailscale Description: Build a private remote development VM on Ubuntu 24.04 with code-server and Tailscale Serve, HTTPS, localhost binding, backups, and safe updates. A remote development VM can give you a persistent Linux workspace that you access from a browser without publishing your editor to the public internet. In this setup, **code-server stays bound to `127.0.0.1:8080`**, Tailscale connects the VM to your private tailnet, and **Tailscale Serve** terminates HTTPS and forwards only tailnet-authorized traffic to the local code-server process. Raff Technologies is the VM platform used by the original tutorial. The saved test environment is Ubuntu 24.04 LTS on a Raff 2 vCPU / 4 GB RAM VM. This revision keeps that tested-on record but updates the workflow against current upstream guidance on September 4, 2026. It pins code-server **4.133.0**, keeps code-server's own password authentication as a second layer behind Tailscale, uses the current `tailscale serve --bg` syntax, and avoids stale claims about hourly billing, unlimited bandwidth, or fixed VM sizing. This architecture is intentionally private. You do not need a public domain, Let's Encrypt, Nginx, Caddy, or an inbound firewall rule for port 8080. Your browser connects to the VM's private `*.ts.net` HTTPS URL through Tailscale, while code-server remains a loopback-only service. Tailscale access controls still apply to Serve, so a team can further restrict which tailnet users or devices may reach the development VM. Prerequisites: - An Ubuntu 24.04 VM with SSH and sudo access - A non-root Linux user for daily development - A Tailscale account/tailnet and a second device that can join it - Enough CPU, RAM, and disk for your actual development workload ## Step 1 — Verify Ubuntu, SSH access, resources, and existing listeners Confirm the operating system: ```bash cat /etc/os-release ``` Check memory and disk space: ```bash free -h df -h / ``` Check whether anything is already listening on code-server's default port: ```bash sudo ss -ltnp | grep ':8080' || true ``` Keep your current SSH session open while you configure Tailscale and code-server. If you later change firewall or SSH policy, a working fallback session reduces lockout risk. Do not treat the original 2 vCPU / 4 GB test VM as a universal sizing rule. A Node.js project, a large monorepo, local containers, compilers, language servers, and browser tabs can have very different resource requirements. **Verify:** Ubuntu should report 24.04, the VM should have enough free resources for your workload, and you should know whether port 8080 is already occupied before continuing. ## Step 2 — Install the baseline development utilities Update package metadata and install the tools used by this tutorial: ```bash sudo apt update sudo apt install -y \ git curl ca-certificates openssl build-essential unzip ``` Check the tools: ```bash git --version curl --version | head -1 openssl version ``` A full unattended `apt upgrade -y` is not required just to install code-server. Apply normal OS security updates according to your server maintenance policy, especially if the VM already runs other workloads. For a fresh server, complete your normal SSH and host-hardening baseline before making it a daily development machine. See [Secure Ubuntu 24.04 Server](/learn/tutorials/secure-ubuntu-24-04-server). **Verify:** Git, curl, and OpenSSL should return installed versions without errors. ## Step 3 — Install a pinned code-server release The code-server project documents its official `install.sh` as the easiest Linux installation method and supports an exact `--version` argument. The current stable release verified for this revision is **4.133.0**. Preview what the installer will do: ```bash curl -fsSL https://code-server.dev/install.sh | \ sh -s -- --dry-run --version=4.133.0 ``` Then install the pinned release: ```bash curl -fsSL https://code-server.dev/install.sh | \ sh -s -- --version=4.133.0 ``` Enable and start the packaged systemd service for your current user: ```bash sudo systemctl enable --now code-server@$USER ``` Check the installed version and service: ```bash code-server --version sudo systemctl is-active code-server@$USER ``` The official Debian/Ubuntu installation flow runs code-server through the `code-server@.service` template. Do not confuse that with a separate `systemctl --user` unit unless you deliberately created one yourself. **Verify:** `code-server --version` should report `4.133.0` for this revision and `code-server@$USER` should be active. ## Step 4 — Keep code-server on localhost with its own password authentication code-server's default configuration lives at: ```text ~/.config/code-server/config.yaml ``` Its secure default pattern is loopback binding plus password authentication. This tutorial keeps both instead of using Tailscale as the only authentication layer. Generate a new random password and write a restrictive config: ```bash umask 077 CODE_SERVER_PASSWORD="$(openssl rand -base64 24 | tr -d '\n')" mkdir -p ~/.config/code-server cat > ~/.config/code-server/config.yaml < ``` Tailscale may route a connection directly peer-to-peer or through a relay depending on NAT/firewall conditions. Either path can be valid; do not use the transport path alone as a health verdict. If your tailnet uses custom access controls, make sure your intended user/device is allowed to reach the VM. Tailscale Serve inherits the tailnet's access-control policy. **Verify:** The client should see the VM as an authorized tailnet device and should be able to reach it according to your tailnet policy. ## Step 8 — Publish localhost:8080 privately with Tailscale Serve Create a persistent private HTTPS reverse proxy: ```bash sudo tailscale serve --bg localhost:8080 ``` Check the active Serve configuration: ```bash sudo tailscale serve status ``` Current Tailscale documentation states that `--bg` keeps the Serve configuration active across device reboots and Tailscale restarts. The HTTPS endpoint is restricted to your tailnet; **Tailscale Serve is not Tailscale Funnel**. If HTTPS certificates are not yet enabled for your tailnet, the CLI may give you a consent/setup URL. Complete that one-time tailnet configuration and rerun the command if necessary. Tailscale Serve terminates HTTPS and proxies to the local HTTP backend. code-server itself can therefore keep `cert: false` on loopback. Do not run `tailscale funnel` for this tutorial. Funnel is intended for public internet exposure, which would change the security model. **Verify:** `sudo tailscale serve status` should show an HTTPS `*.ts.net` URL forwarding to `http://localhost:8080`. ## Step 9 — Sign in through the private HTTPS URL and verify browser features From a device that is signed into the authorized tailnet, open the HTTPS URL shown by: ```bash sudo tailscale serve status ``` Retrieve the code-server password on the VM when needed: ```bash awk -F': ' '/^password:/ {print $2}' ~/.config/code-server/config.yaml ``` Use that password to sign in. After login, verify more than the landing page: - open the Explorer panel; - open an integrated terminal; - create and save a test file; - reconnect after refreshing the page; - open a second tab and confirm the editor remains responsive. code-server depends on WebSockets for normal browser/editor communication. Tailscale Serve's HTTP reverse proxy handles the HTTPS frontend while forwarding to the local service, so you do not need an Nginx-style WebSocket header block here. :::cta Deploy Your Remote Development VM Launch a Raff Ubuntu VM and keep your browser IDE private with code-server and Tailscale. ::: **Verify:** The `*.ts.net` HTTPS URL should load only from an authorized tailnet device, code-server should request its password, and the integrated terminal/file editor should work after login. ## Step 10 — Create a clean workspace and understand code-server extensions Create a projects directory: ```bash mkdir -p ~/projects cd ~/projects ``` Clone a repository you are authorized to access. For a harmless public test: ```bash git clone https://github.com/octocat/Hello-World.git cd Hello-World git status ``` Open `~/projects/Hello-World` in code-server. You can install extensions from the Extensions view or CLI: ```bash code-server --install-extension ``` One important difference from Microsoft's desktop VS Code is the marketplace. Current code-server documentation states that it cannot use Microsoft's extension marketplace under Microsoft's marketplace terms; code-server uses Open VSX / compatible galleries instead. Some Microsoft-only or closed-source extensions may therefore be unavailable or behave differently. Extensions are stored under: ```text ~/.local/share/code-server/extensions ``` Editor settings and related state are also stored under `~/.local/share/code-server` by default. **Verify:** You should be able to open the cloned workspace, run `git status` from the integrated terminal, save a file, and install at least one extension that is available through code-server's supported extension gallery. ## Step 11 — Protect source code, Git credentials, and unpushed work A remote development VM often contains more sensitive material than a generic test server: source repositories, `.env` files, package-registry tokens, SSH agent access, Git credentials, and unpushed commits. Prefer short-lived or scoped credentials where your Git/package provider supports them. Avoid casually copying your laptop's long-lived private SSH key into the VM. If you use SSH-agent or GPG-agent forwarding, understand that a compromised remote account may be able to use the forwarded agent while the session exists. Keep project secrets out of Git: ```bash cd ~/projects/Hello-World git status --ignored ``` Review permissions on SSH/config directories if you use them: ```bash ls -ld ~/.ssh ~/.config/code-server 2>/dev/null || true ``` For team access, use separate Linux/tailnet identities rather than sharing one code-server password broadly. code-server itself is primarily a single-user tool; the Coder project recommends VM/workspace isolation when multiple users need independent environments. **Verify:** Sensitive `.env`/key material should not be tracked unintentionally, and the development VM should use credentials appropriate for a remote machine rather than a copy of every local secret. ## Step 12 — Back up code-server state and preserve source repositories correctly Treat Git remotes as the primary source backup for repositories: push commits you cannot afford to lose. Then protect the editor state and any non-Git workspace files separately. Create a protected backup directory: ```bash mkdir -p ~/backups chmod 700 ~/backups STAMP="$(date +%F-%H%M%S)" ``` Archive code-server configuration and editor state: ```bash tar -czf "$HOME/backups/code-server-state-$STAMP.tar.gz" \ -C "$HOME" \ .config/code-server \ .local/share/code-server ``` List the archive: ```bash tar -tzf "$HOME/backups/code-server-state-$STAMP.tar.gz" | head ``` Do not blindly archive entire development trees full of `node_modules`, build artifacts, caches, databases, or secrets. Back up non-Git project data intentionally according to what the project actually contains. Keep at least one recovery copy away from the VM. Raff [Data Protection](/products/data-protection) can provide an additional infrastructure-level recovery layer, but repository pushes and application-aware backups are still important for active development work. **Verify:** Important repositories should have their needed commits on a remote Git service, and the code-server state archive should be readable without errors. ## Step 13 — Update code-server and Tailscale without losing the private-access model Before upgrading, check the current versions: ```bash code-server --version tailscale version ``` For code-server, review the project's release notes and install the exact target version you chose. For example, this revision's pinned version can be reinstalled with: ```bash curl -fsSL https://code-server.dev/install.sh | \ sh -s -- --version=4.133.0 ``` After a future upgrade, restart and verify: ```bash sudo systemctl restart code-server@$USER sudo systemctl is-active code-server@$USER sudo ss -ltnp | grep ':8080' ``` For Tailscale installed from its official package source, use your normal APT update workflow: ```bash sudo apt update apt list --upgradable 2>/dev/null | grep -i tailscale || true ``` After upgrading Tailscale, confirm that Serve resumed: ```bash tailscale status sudo tailscale serve status ``` The security invariants should survive every update: code-server remains on `127.0.0.1:8080`, Serve remains private to the tailnet, and Funnel remains unused. **Verify:** After updates/restarts, the browser should still use the private HTTPS Serve URL and `ss` should still show code-server bound only to loopback. ## Step 14 — Run the final security check and roll back safely Run the final server-side checks: ```bash sudo systemctl is-active code-server@$USER tailscale status tailscale ip -4 sudo tailscale serve status sudo ss -ltnp | grep ':8080' stat -c '%a %n' ~/.config/code-server/config.yaml ``` From the client, confirm: 1. the `*.ts.net` HTTPS URL opens while Tailscale is connected; 2. code-server still requires its password; 3. a workspace and terminal work normally; 4. disconnecting the client from Tailscale makes the private Serve URL unreachable; 5. the VM's public IP on port 8080 does not expose code-server. To disable only the private Serve endpoint: ```bash sudo tailscale serve reset ``` To stop code-server: ```bash sudo systemctl disable --now code-server@$USER ``` To leave the tailnet when this VM no longer needs Tailscale: ```bash sudo tailscale down ``` Do not remove project files, editor state, Git credentials, or backups until you have verified what needs to be retained. If you later uninstall code-server, follow the uninstall path matching the installation method reported by the official installer. **Verify:** After Serve reset, the private HTTPS URL should stop serving code-server while SSH/admin access remains intact. If you re-enable the services, the original private architecture should return without opening public port 8080. ## Troubleshooting ### `code-server@$USER` is inactive Inspect the service log: ```bash sudo journalctl -u code-server@$USER -n 120 --no-pager ``` Then verify the YAML and port: ```bash cat ~/.config/code-server/config.yaml sudo ss -ltnp | grep ':8080' || true ``` A malformed config or another process already using port 8080 will prevent a normal start. ### Tailscale Serve shows a URL but the browser cannot connect Check the VM: ```bash tailscale status sudo tailscale serve status curl -I http://127.0.0.1:8080 ``` Then confirm the client device is logged into the same tailnet and permitted by your tailnet access controls. Serve does not make the service public. ### Tailscale asks you to enable HTTPS certificates Follow the consent/setup URL provided by the CLI. Serve HTTPS requires certificate support for the tailnet's `*.ts.net` names. After enabling it, rerun: ```bash sudo tailscale serve --bg localhost:8080 ``` ### The browser works but some editor actions disconnect Confirm the client is not aggressively blocking WebSockets and that you are using the Serve HTTPS URL rather than manually proxying code-server through another web server. Inspect code-server logs while reproducing the problem: ```bash sudo journalctl -fu code-server@$USER ``` ### An extension is missing from the marketplace code-server does not use Microsoft's official VS Code marketplace by default/under Microsoft's marketplace terms. Search Open VSX or the supported gallery, or install a trusted `.vsix` obtained from the extension project's official release channel when licensing and compatibility allow it. ### The VM works through Tailscale but public SSH is still open That is not automatically a code-server problem. Decide your SSH exposure separately. If you later move SSH to Tailscale-only access, test Tailscale SSH or normal SSH over the tailnet first and keep a provider console/recovery path before removing the existing public SSH rule. ## Conclusion You now have a remote development VM on Ubuntu 24.04 with code-server kept on `127.0.0.1:8080` and a private Tailscale Serve HTTPS endpoint for browser access. The setup keeps code-server password authentication enabled, respects tailnet access controls, avoids Tailscale Funnel, and does not require public port 8080, a public domain, or a separate reverse proxy. The workflow also accounts for code-server's supported extension marketplace, persistent editor state, Git/secrets hygiene, upgrades, backups, and rollback. The original Raff 2 vCPU / 4 GB test environment is preserved as historical test metadata; choose production resources from the actual languages, repositories, containers, compilers, and concurrency your development workflow uses. For adjacent hardening, continue with [Configure SSH Keys on Ubuntu](/learn/tutorials/configure-ssh-keys-ubuntu), [Set Up UFW Firewall on Ubuntu 24.04](/learn/tutorials/set-up-ufw-firewall-ubuntu-24-04), and [Secure Ubuntu 24.04 Server](/learn/tutorials/secure-ubuntu-24-04-server). ## Sources - [code-server — Install](https://coder.com/docs/code-server/install) - [code-server — FAQ and configuration](https://coder.com/docs/code-server/FAQ) - [code-server — Secure exposure guide](https://coder.com/docs/code-server/guide) - [code-server — Releases](https://github.com/coder/code-server/releases) - [Tailscale — Install on Linux](https://tailscale.com/docs/install/linux) - [Tailscale — Serve](https://tailscale.com/docs/features/tailscale-serve) - [Tailscale — Serve CLI reference](https://tailscale.com/docs/reference/tailscale-cli/serve) - [Tailscale — code-server integration](https://tailscale.com/docs/integrations/codeserver) - Upstream guidance re-verified: 2026-09-04 --- ### How to Set Up UFW Firewall on Ubuntu 24.04 URL: https://rafftechnologies.com/learn/tutorials/set-up-ufw-firewall-ubuntu-24-04 Description: Set up UFW on Ubuntu 24.04 without losing SSH access. Configure IPv4/IPv6 rules, ports, source restrictions, logging, rule order, and Docker caveats. UFW, short for Uncomplicated Firewall, is Ubuntu's standard command-line frontend for building a host-based firewall. A safe Ubuntu 24.04 baseline is straightforward: identify the SSH port you are actually using, allow that path **before** enabling UFW, keep the default inbound policy restrictive, open only the services the server needs, and verify the result from a second connection before closing your original SSH session. Raff Technologies is the VM platform used by the original tutorial. The saved tested-on record remains `Ubuntu 24.04 LTS on Raff 2 vCPU / 2 GB RAM Linux VM; UFW, OpenSSH, IPv6, logging, and Docker guidance reviewed in July 2026`. This revision re-verifies the firewall workflow against current Ubuntu, UFW, and Docker documentation on September 4, 2026 without claiming a new server-side test. The most important caveat is Docker: a normal UFW policy does **not reliably protect Docker-published container ports** because Docker creates its own NAT/firewall rules and can divert that traffic before UFW's normal host `INPUT` rules. For private container services, bind published ports to loopback or use Docker-aware/upstream filtering instead of assuming UFW will block them. Prerequisites: - An Ubuntu 24.04 VM with SSH access - A non-root user with sudo privileges - Knowledge of every service that must remain reachable - A second terminal or recovery path for SSH verification ## Step 1 — Inspect the current SSH, network, and firewall state Do not enable a firewall before you understand how you are currently connected. Check Ubuntu: ```bash cat /etc/os-release ``` Check UFW state: ```bash sudo ufw status verbose ``` List listening TCP and UDP sockets: ```bash sudo ss -tulpn ``` Ask OpenSSH for its effective configured port or ports: ```bash sudo sshd -T | awk '$1 == "port" {print $2}' ``` If you use a provider-side firewall, security group, VPN, Tailscale, or a nonstandard SSH port, document that path before changing UFW. Keep the current SSH session open throughout the initial enablement. A second connection will be your proof that the firewall did not lock you out. **Verify:** You should know the active SSH port, which applications are listening, whether UFW is already active, and which services must remain reachable. ## Step 2 — Install UFW and understand its installation defaults Install UFW if it is not already present: ```bash sudo apt update sudo apt install -y ufw ``` Check its version: ```bash ufw --version ``` Ubuntu's current UFW documentation states that UFW is initially disabled. Its installation defaults are already designed around a common server baseline: deny incoming traffic, deny forwarded/routed traffic, and allow outgoing traffic. This tutorial still sets the intended host defaults explicitly later so the final policy is easy to audit. UFW is a frontend for Linux netfilter. It is useful for host firewall rules, but it is not intended to replace every advanced packet-filtering or routing feature. **Verify:** `ufw --version` should return an installed version and `sudo ufw status` should return a valid status rather than `command not found`. ## Step 3 — Keep IPv6 firewalling aligned with the server's network configuration Check UFW's IPv6 setting: ```bash grep '^IPV6=' /etc/default/ufw ``` Ubuntu 24.04's UFW framework enables IPv6 support by default. A typical result is: ```text IPV6=yes ``` When IPv6 support is enabled, generic rules such as: ```bash sudo ufw allow 22/tcp ``` can create rules that apply to both IPv4 and IPv6. If your server has working IPv6 or an `AAAA` DNS record, keep IPv6 firewalling enabled and test both address families. Do not treat `IPV6=no` as a harmless way to ignore IPv6: current UFW framework documentation states that disabling IPv6 support changes how non-loopback IPv6 traffic is handled. Inspect the host addresses: ```bash ip -brief address ``` If the VM intentionally has no IPv6 service, document that choice at both the host and upstream network layers instead of leaving stale public IPv6 DNS/routes. **Verify:** You should know whether the VM is single-stack or dual-stack, and `/etc/default/ufw` should match that intended design. ## Step 4 — Allow the active SSH path before enabling UFW If SSH uses the normal OpenSSH profile on TCP 22, inspect the profile first: ```bash sudo ufw app info OpenSSH ``` Then add the rule: ```bash sudo ufw allow OpenSSH comment 'SSH administration' ``` If SSH uses a custom port, allow that exact port instead. Example: ```bash sudo ufw allow 2222/tcp comment 'SSH administration' ``` Do **not** add both rules unless sshd intentionally listens on both ports. You can preview the effect of a rule without applying it by using UFW's `--dry-run` option. For example: ```bash sudo ufw --dry-run allow 2222/tcp ``` Review rules that have been added from the command line: ```bash sudo ufw show added ``` This step is the critical lockout safeguard. UFW's own remote-management documentation recommends allowing the SSH port before `ufw enable` because enabling UFW rebuilds its chains and can interrupt existing remote connections. **Verify:** `sudo ufw show added` should contain an allow rule for the exact SSH path you are using before you enable the firewall. ## Step 5 — Set and review the default policies Apply a common application-server baseline: ```bash sudo ufw default deny incoming sudo ufw default allow outgoing sudo ufw default deny routed ``` The routed policy matters when the host forwards traffic between interfaces or networks. A normal standalone application VM generally does not need to be an IP router. Review the pending rules again: ```bash sudo ufw show added ``` Preview enablement without changing the live firewall: ```bash sudo ufw --dry-run enable ``` Default policy changes can affect existing rules, so make them deliberately rather than toggling defaults repeatedly on a production server. **Verify:** Your intended defaults should be deny incoming, allow outgoing, deny routed, and the SSH allow rule must still be present. ## Step 6 — Enable UFW and test a second SSH connection Enable the firewall: ```bash sudo ufw enable ``` UFW may warn that enabling it can disrupt existing SSH connections. Continue only because the correct SSH rule was added first. Check the live policy: ```bash sudo ufw status verbose ``` Then, **without closing the original session**, open a second terminal from your workstation and connect again: ```bash ssh your_user@your_server_ip ``` If SSH uses a custom port: ```bash ssh -p 2222 your_user@your_server_ip ``` Do not consider the firewall rollout successful until this new session works. :::cta Deploy Your Server Launch a Raff Ubuntu VM and apply a deny-by-default host firewall before exposing application services. ::: **Verify:** UFW should report `Status: active`, the correct defaults, and the new independent SSH session should connect successfully. ## Step 7 — Allow only the ports and application profiles the server needs To allow a public TCP port explicitly: ```bash sudo ufw allow 443/tcp comment 'HTTPS' ``` For a normal public web server using both HTTP and HTTPS: ```bash sudo ufw allow 80/tcp comment 'HTTP' sudo ufw allow 443/tcp comment 'HTTPS' ``` This is the core `ufw allow port` pattern: specify the port and protocol you actually need rather than opening a broad range. Applications can also install UFW profiles. List them: ```bash sudo ufw app list ``` For Nginx, inspect the profile before allowing it: ```bash sudo ufw app info 'Nginx Full' ``` Then, if it matches your intended ports: ```bash sudo ufw allow 'Nginx Full' ``` Do not keep duplicate numeric rules and application-profile rules without a reason. Application profiles live under `/etc/ufw/applications.d`, and UFW's current documentation supports `ufw app info`, `app list`, and `app update` for inspecting and maintaining them. For a complete web-server path, see [Install Nginx on Ubuntu 24.04](/learn/tutorials/install-nginx-ubuntu-24-04). **Verify:** `sudo ufw status numbered` should show only the public services you deliberately intend to expose. ## Step 8 — Restrict databases and admin services by source address Do not expose a database or administrative port to `Anywhere` merely because an application needs remote access. Allow PostgreSQL only from a private subnet: ```bash sudo ufw allow proto tcp from 10.0.0.0/24 to any port 5432 \ comment 'Private PostgreSQL' ``` Allow an admin service only from one trusted public address: ```bash sudo ufw allow proto tcp from 203.0.113.5 to any port 9090 \ comment 'Admin access' ``` `203.0.113.5` is a documentation example. Replace it with the real trusted source. For multi-VM workloads, combine a [Raff VPC](/products/vpc) with correct service binding. For example, a database can bind to its private address rather than `0.0.0.0`. UFW source filtering is an additional control, not a substitute for application authentication and correct bind addresses. **Verify:** Private/admin ports should be allowed only from the expected source IP or subnet, and the application itself should listen only on the intended interface. ## Step 9 — Use rule order deliberately because the first matching rule wins UFW rule order matters. Current UFW documentation states that the **first matching rule wins**, so a broad allow placed before a more specific deny can defeat the intended restriction. Display rules in order: ```bash sudo ufw status numbered ``` To insert a rule at a specific position: ```bash sudo ufw insert 1 deny from 203.0.113.25 ``` To place an address-family-specific rule before existing rules of the same IP type: ```bash sudo ufw prepend deny from 203.0.113.25 ``` Before inserting a production rule, preview it: ```bash sudo ufw --dry-run insert 1 deny from 203.0.113.25 ``` Use rule ordering to express actual policy, not as a substitute for simplifying an overly complicated ruleset. **Verify:** `sudo ufw status numbered` should place narrow exceptions/restrictions where they will be evaluated before broader rules that could otherwise match first. ## Step 10 — Rate-limit SSH only after the basic SSH policy is correct UFW supports a `limit` action for connection-rate limiting, commonly used for SSH: ```bash sudo ufw limit OpenSSH comment 'Rate-limited SSH' ``` For a custom port: ```bash sudo ufw limit 2222/tcp comment 'Rate-limited SSH' ``` Do not add a `limit` rule alongside a broad earlier `allow` rule for the same traffic and assume the later rule will win. Check the actual ordering. UFW's rate limiting is a basic brute-force mitigation, not a substitute for SSH keys, disabling unnecessary password authentication, account controls, or upstream DDoS protection. It can also affect legitimate automation or multiple users sharing one NAT address. For SSH-key setup, use [Configure SSH Keys on Ubuntu](/learn/tutorials/configure-ssh-keys-ubuntu). **Verify:** `sudo ufw status numbered` should show the intended `LIMIT` rule in an order where a broader prior `ALLOW` does not bypass it. ## Step 11 — Delete rules safely and understand IPv4/IPv6 deletion behavior Show numbered rules: ```bash sudo ufw status numbered ``` Delete a single numbered rule: ```bash sudo ufw delete 3 ``` Run `status numbered` again after every numbered deletion because rule numbers change. When IPv6 is enabled, a generic rule can produce both IPv4 and IPv6 entries. Deleting **one numeric entry** removes only that listed rule. If you want to remove the generic rule across the address families UFW created, delete it by repeating its original syntax: ```bash sudo ufw delete allow 443/tcp ``` Reload UFW after changes that require it: ```bash sudo ufw reload ``` Avoid `ufw reset` for routine cleanup. Reset disables the firewall and returns it to installation defaults, which means you must rebuild SSH and service rules. **Verify:** The unwanted rule should be gone from both the numbered status and, when relevant, its IPv4/IPv6 counterpart. ## Step 12 — Enable useful logging and inspect more than `ufw status` Enable low-level logging: ```bash sudo ufw logging low ``` UFW supports `off`, `low`, `medium`, `high`, and `full`. Current documentation warns that higher levels can generate substantial log volume, so `low` is a sensible default for a public server. Inspect recent kernel firewall events: ```bash sudo journalctl -k -g 'UFW' --since '15 minutes ago' ``` On systems where rsyslog writes a dedicated UFW file: ```bash sudo test -f /var/log/ufw.log && \ sudo tail -n 50 /var/log/ufw.log ``` Use UFW's reports for deeper inspection: ```bash sudo ufw show listening sudo ufw show raw ``` `ufw status` shows rules managed through the UFW CLI, but current UFW documentation notes that it does not show every rule loaded from `/etc/ufw/*.rules`. `ufw show raw` is the stronger view when you need the complete firewall state. **Verify:** Logging should be enabled at the intended level, `show listening` should correlate services with firewall rules, and `show raw` should return the complete live netfilter view UFW exposes. ## Step 13 — Do not assume UFW protects Docker-published ports This is the most common advanced UFW mistake on application servers. List Docker-published ports: ```bash docker ps --format 'table {{.Names}}\t{{.Ports}}' ``` A publication such as: ```text 0.0.0.0:8080->80/tcp ``` can be reachable even when UFW appears to deny TCP 8080. Docker's current documentation explains that Docker creates NAT/firewall rules for bridge networks and that published traffic can be diverted before it reaches the `INPUT` and `OUTPUT` chains UFW normally manages. For a service intended only for a host-side reverse proxy, publish it to loopback instead: ```text 127.0.0.1:8080:80 ``` or in Compose: ```yaml ports: - "127.0.0.1:8080:80" ``` For advanced source filtering of Docker bridge traffic, use filtering appropriate to the Docker firewall backend. With Docker's iptables backend, `DOCKER-USER` is the documented pre-Docker user chain. Docker 29 also has an **experimental nftables backend**, where there is no `DOCKER-USER` chain and custom nftables chains/tables are used instead. Do not set Docker's `iptables`/`ip6tables` options to `false` casually. Docker warns that disabling its firewall-rule management without a complete replacement policy is likely to break container networking. See [Install Docker on Ubuntu 24.04](/learn/tutorials/install-docker-ubuntu-24-04) for the container baseline. **Verify:** Private containers should not publish to `0.0.0.0` unnecessarily, and any public Docker ports must be treated as a separate firewall exposure rather than assumed protected by UFW. ## Step 14 — Run the final firewall audit and keep a safe rollback path Audit the live system: ```bash sudo ufw status verbose sudo ufw status numbered sudo ufw show listening sudo ss -tulpn sudo systemctl is-enabled ufw ``` The firewall is healthy when: - UFW is active; - incoming traffic is denied by default; - outgoing traffic is allowed unless you intentionally chose otherwise; - routed traffic is denied unless the VM is meant to forward packets; - SSH works from a fresh second connection; - public services have explicit rules; - private/admin services use source restrictions and/or private binding; - Docker-published ports have been audited separately; - IPv4 and IPv6 behavior match the server's actual network design. Test important public ports from another machine. A localhost `curl` does not prove that the same traffic is reachable from the internet. To temporarily disable UFW while preserving the configured rules: ```bash sudo ufw disable ``` To re-enable it after correcting a rule: ```bash sudo ufw enable ``` Use a full reset only when you intentionally want to rebuild the entire policy: ```bash sudo ufw reset ``` If you are locked out of SSH, use an existing open session or provider recovery console to correct the rule. Do not remove the last known-good remote-management path before a replacement has been tested. **Verify:** A fresh SSH session and every required application path should work, unnecessary ports should fail from an external client, and the rules should remain enabled across a reboot. ## Troubleshooting ### SSH stops accepting new connections after UFW is enabled Keep the original session open and check: ```bash sudo sshd -T | awk '$1 == "port" {print $2}' sudo ufw status numbered ``` Add the correct port if it is missing, then test a new session before closing the original one. ### `ufw status` says a Docker port is blocked but the container is reachable That can be expected with Docker port publishing. Inspect: ```bash docker ps --format 'table {{.Names}}\t{{.Ports}}' sudo ufw show raw ``` Bind private container ports to `127.0.0.1`, use an upstream firewall, or implement Docker-backend-aware filtering. ### A deny rule does not work Check rule ordering: ```bash sudo ufw status numbered ``` A broader allow may match first. Insert or prepend the specific restriction before the broad rule, then retest externally. ### IPv4 works but IPv6 behaves differently Check: ```bash grep '^IPV6=' /etc/default/ufw ip -6 address sudo ufw status numbered ``` Also verify public `AAAA` DNS and upstream IPv6 routing/firewall policy. ### Logging is filling the disk Reduce the level: ```bash sudo ufw logging low ``` or temporarily disable UFW-managed logging: ```bash sudo ufw logging off ``` `medium`, `high`, and `full` can be noisy on busy hosts. ### A custom rule is active but missing from `ufw status` Rules placed directly in `/etc/ufw/before.rules`, `after.rules`, or their IPv6 counterparts are not fully represented by normal `ufw status`. Inspect: ```bash sudo ufw show raw ``` ## Conclusion You now have a practical Ubuntu 24.04 UFW baseline that protects the active SSH path before enablement, denies unsolicited inbound traffic, handles IPv4 and IPv6 deliberately, opens only required ports, supports source-restricted access, respects first-match rule ordering, provides useful logging, and includes an external verification and rollback workflow. The key operational habit is to compare three views whenever the server changes: `ufw status numbered`, `ufw show listening`, and `ss -tulpn`. Firewall rules should evolve with the applications that are actually listening. Docker-published ports require a separate audit because Docker's own networking rules can bypass the assumptions behind ordinary UFW host filtering. For the next layer, continue with [Configure SSH Keys on Ubuntu](/learn/tutorials/configure-ssh-keys-ubuntu), [Secure Ubuntu 24.04 Server](/learn/tutorials/secure-ubuntu-24-04-server), and [Install Docker on Ubuntu 24.04](/learn/tutorials/install-docker-ubuntu-24-04). ## Sources - [Ubuntu Server — Firewall](https://ubuntu.com/server/docs/security-firewall/) - [Ubuntu 24.04 UFW framework manual](https://manpages.ubuntu.com/manpages/noble/man8/ufw-framework.8.html) - [Ubuntu UFW manual](https://manpages.ubuntu.com/manpages/resolute/man8/ufw.8.html) - [Docker — Packet filtering and firewalls](https://docs.docker.com/engine/network/packet-filtering-firewalls/) - [Docker — Docker with iptables](https://docs.docker.com/engine/network/firewall-iptables/) - [Docker — Docker with nftables](https://docs.docker.com/engine/network/firewall-nftables/) - Guidance re-verified: 2026-09-04 --- ### How to Harden an Ubuntu 24.04 Server URL: https://rafftechnologies.com/learn/tutorials/secure-ubuntu-24-04-server Description: Harden Ubuntu 24.04 with SSH keys, safe OpenSSH drop-ins, UFW, automatic security updates, AppArmor, access auditing, logging, and recovery checks. Ubuntu 24.04 is reasonably secure as a fresh installation, but production hardening is about reducing attack surface and making access, updates, network exposure, application confinement, logging, and recovery deliberate. A useful baseline does not come from copying a long list of random `sysctl` values or disabling every feature. It comes from verifying which users, services, ports, packages, and recovery paths your server actually needs. Raff Technologies is the VM platform used by the original tutorial. The saved tested-on record remains `Ubuntu 24.04 LTS on Raff 2 vCPU / 2 GB RAM Linux VM; OpenSSH, UFW, unattended-upgrades, Fail2Ban, and recovery guidance reviewed in July 2026`. This revision re-verifies the workflow against current Ubuntu Server documentation on September 5, 2026 without claiming a new end-to-end machine test. This tutorial hardens a general-purpose internet-connected Ubuntu server with a non-root administrator, tested SSH keys, safe OpenSSH drop-ins, a deny-by-default UFW policy, verified automatic security updates, service/account review, AppArmor, optional Fail2Ban, logging, and a tested recovery plan. It intentionally avoids hard-coded SSH cipher lists, cargo-cult kernel tweaks, and claims of CIS/FIPS/compliance. Those controls require workload-specific testing and, where applicable, the appropriate compliance tooling. Prerequisites: - An Ubuntu 24.04 server with working administrative access - A non-root sudo-capable account, or permission to create one - A second terminal for testing new SSH sessions - A provider console/rescue path or another recovery method - Knowledge of the applications and ports the server must keep ## Step 1 — Inventory the server before changing security controls Start by recording the server state you are about to change. Confirm Ubuntu: ```bash cat /etc/os-release uname -r ``` Check the current user and sudo capability: ```bash id sudo -v ``` List listening sockets: ```bash sudo ss -tulpn ``` List failed and enabled services: ```bash systemctl --failed systemctl list-unit-files --type=service --state=enabled ``` Check the current SSH port and effective authentication settings: ```bash sudo sshd -T | grep -E \ '^(port|permitrootlogin|passwordauthentication|kbdinteractiveauthentication|pubkeyauthentication) ' ``` Check UFW and AppArmor: ```bash sudo ufw status verbose sudo aa-status ``` Do not change a control until you know which production dependency it could affect. For example, an application may need a public listener, a backup agent may require outbound access, and a deployment system may rely on a specific SSH account. **Verify:** You should have a clear list of current administrators, listening ports, enabled services, SSH settings, firewall state, and whether AppArmor is loaded. ## Step 2 — Apply pending Ubuntu updates and plan required reboots Refresh package metadata and install the updates your maintenance policy allows: ```bash sudo apt update sudo apt upgrade ``` Review packages before accepting the upgrade on a production server instead of automatically using `-y` when you need change control. Check whether a reboot is required: ```bash if [ -f /var/run/reboot-required ]; then cat /var/run/reboot-required else echo "No reboot required" fi ``` If a reboot is required, schedule it when the workload can tolerate it and confirm the server returns healthy afterward. Review configured repositories: ```bash find /etc/apt/sources.list.d -maxdepth 1 -type f -print ``` Minimize third-party repositories. Ubuntu's current security guidance explicitly recommends avoiding unnecessary third-party package sources because every additional repository adds a software supply-chain and maintenance dependency. Do not remove packages just because they look unfamiliar. Package dependencies, cloud agents, networking, boot, and storage components can be critical even when they are not obvious application dependencies. **Verify:** `apt update` should complete successfully, required upgrades should be understood/applied according to policy, and you should know whether a reboot is pending. ## Step 3 — Use a dedicated non-root administrator and verify sudo access If your image already provides a non-root sudo account, keep it and verify it instead of creating another unnecessary administrator: ```bash id sudo whoami ``` The second command should return: ```text root ``` If you are currently administering the machine only as root, create a replacement account. Replace `deploy` with your chosen username: ```bash sudo adduser deploy sudo usermod -aG sudo deploy ``` Verify membership: ```bash id deploy ``` Then test the new account in a separate session before changing root SSH access: ```bash ssh deploy@your_server_ip sudo whoami ``` Use separate administrator identities where practical. Sharing one Linux account or one private key between several people makes revocation and log attribution harder. Review current sudo members: ```bash getent group sudo ``` **Verify:** At least one non-root administrator should have a tested SSH path and working `sudo`, and every sudo member should have a current operational reason for that access. ## Step 4 — Install and test SSH key authentication before disabling passwords Generate an Ed25519 key on the administrator's local computer if needed: ```bash ssh-keygen -t ed25519 -C "ubuntu-admin" ``` Copy only the public key to the server: ```bash ssh-copy-id your_user@your_server_ip ``` On the server, review key permissions: ```bash chmod 700 ~/.ssh chmod 600 ~/.ssh/authorized_keys chown -R "$USER":"$USER" ~/.ssh ``` Open a **new** terminal and verify key authentication: ```bash ssh your_user@your_server_ip ``` Do not disable password authentication, root login, or the old working access method until this separate key-based session succeeds. For key rotation, multiple administrators, and client configuration, use [Generate SSH Keys on Ubuntu 24.04](/learn/tutorials/set-up-ssh-keys-ubuntu-24-04). **Verify:** A new independent SSH session should authenticate with the intended public key and the account should still have working sudo access. ## Step 5 — Harden OpenSSH with an early drop-in and verify the effective configuration Ubuntu places this line near the top of `/etc/ssh/sshd_config`: ```text Include /etc/ssh/sshd_config.d/*.conf ``` OpenSSH uses the **first obtained value** for most directives. That means a late file name such as `99-hardening.conf` does not necessarily override an earlier snippet. Inspect existing snippets first: ```bash sudo ls -1 /etc/ssh/sshd_config.d/ sudo grep -RniE \ '^(PermitRootLogin|PasswordAuthentication|KbdInteractiveAuthentication|PubkeyAuthentication|MaxAuthTries|LoginGraceTime)' \ /etc/ssh/sshd_config /etc/ssh/sshd_config.d 2>/dev/null || true ``` Create an early local hardening snippet: ```bash sudo tee /etc/ssh/sshd_config.d/00-raff-hardening.conf > /dev/null <<'EOF' PermitRootLogin no PubkeyAuthentication yes PasswordAuthentication no KbdInteractiveAuthentication no MaxAuthTries 3 LoginGraceTime 30 EOF ``` Protect it with normal root-owned configuration permissions: ```bash sudo chown root:root /etc/ssh/sshd_config.d/00-raff-hardening.conf sudo chmod 644 /etc/ssh/sshd_config.d/00-raff-hardening.conf ``` Validate syntax: ```bash sudo sshd -t ``` Then verify **effective values**, which is more important than merely reading the file: ```bash sudo sshd -T | grep -E \ '^(permitrootlogin|pubkeyauthentication|passwordauthentication|kbdinteractiveauthentication|maxauthtries|logingracetime) ' ``` If your configuration uses `Match` blocks, evaluate the intended user/context as well: ```bash sudo sshd -T -C user="$USER",host="$(hostname)",addr=127.0.0.1 | \ grep -E '^(permitrootlogin|pubkeyauthentication|passwordauthentication|kbdinteractiveauthentication|maxauthtries|logingracetime) ' ``` Restart SSH only after validation: ```bash sudo systemctl restart ssh.service ``` Keep the original session open. Test a new key-based login again, then confirm a password-only attempt is rejected: ```bash ssh -o PreferredAuthentications=password \ -o PubkeyAuthentication=no \ your_user@your_server_ip ``` Do not hard-code custom `Ciphers`, `MACs`, or `KexAlgorithms` in a general baseline unless a defined security/compliance requirement calls for it. Ubuntu's OpenSSH defaults evolve with security updates; custom crypto lists need compatibility testing and long-term maintenance. **Verify:** `sshd -t` should pass, `sshd -T` should show the intended settings, a fresh key login should work, and password-only/root SSH access should not provide an unintended login path. ## Step 6 — Configure UFW without risking SSH lockout Determine the effective SSH port: ```bash sudo sshd -T | awk '$1 == "port" {print $2}' ``` If SSH uses the standard OpenSSH profile, inspect and allow it before enabling UFW: ```bash sudo ufw app info OpenSSH sudo ufw allow OpenSSH comment 'SSH administration' ``` For a custom SSH port, allow the actual port instead: ```bash sudo ufw allow 2222/tcp comment 'SSH administration' ``` Set a common application-server baseline: ```bash sudo ufw default deny incoming sudo ufw default allow outgoing sudo ufw default deny routed ``` Review before enabling: ```bash sudo ufw show added sudo ufw --dry-run enable ``` Then enable and inspect: ```bash sudo ufw enable sudo ufw status verbose ``` Open another new SSH connection before closing existing sessions. Only add application ports when a real service requires them. For example, a public web server may need TCP 80/443; a private database normally should not be opened to `Anywhere`. :::cta Deploy Your Hardened Server Launch a Raff Ubuntu VM and apply this layered security baseline before placing production workloads on it. ::: For source restrictions, IPv6, rule ordering, Docker caveats, and rollback, use [Set Up UFW Firewall on Ubuntu 24.04](/learn/tutorials/set-up-ufw-firewall-ubuntu-24-04). **Verify:** UFW should be active with deny-incoming/deny-routed defaults, the correct SSH rule should exist, and a second SSH connection should still succeed. ## Step 7 — Verify automatic security updates instead of overwriting Ubuntu defaults blindly Ubuntu Server uses `unattended-upgrades` for automatic security updates and current Ubuntu documentation states that security updates are applied automatically by default. Check whether the package is installed: ```bash dpkg -s unattended-upgrades 2>/dev/null | grep '^Status:' || true ``` Install it only if it is absent: ```bash sudo apt install -y unattended-upgrades ``` Inspect the periodic settings: ```bash apt-config dump | grep -E \ 'APT::Periodic::(Update-Package-Lists|Unattended-Upgrade)' ``` Inspect the timers that drive APT maintenance: ```bash systemctl list-timers apt-daily.timer apt-daily-upgrade.timer --all ``` Review the actual unattended-upgrades policy: ```bash sudo less /etc/apt/apt.conf.d/50unattended-upgrades ``` Test it without installing packages: ```bash sudo unattended-upgrade --dry-run --debug ``` Review recent service activity: ```bash sudo journalctl -u unattended-upgrades --since '7 days ago' --no-pager ``` Do not assume third-party repositories are included just because they exist in APT. Ubuntu's current documentation explicitly notes that adding a repository does not automatically make `unattended-upgrades` select packages from that origin. Automatic reboot behavior is workload-dependent. Do not enable unattended reboots blindly on a single production node; define a maintenance/redundancy strategy first. **Verify:** The APT timers should be scheduled, unattended security upgrades should be enabled according to your policy, the dry run should complete without configuration errors, and third-party origins should be consciously included or excluded. ## Step 8 — Remove or disable only services you have positively identified as unnecessary Audit listeners again: ```bash sudo ss -tulpn ``` Review enabled services: ```bash systemctl list-unit-files --type=service --state=enabled ``` Inspect a service before disabling it: ```bash systemctl status service-name systemctl cat service-name ``` Only after confirming it is not needed: ```bash sudo systemctl disable --now service-name ``` Review package cleanup candidates without immediately deleting them: ```bash sudo apt autoremove --dry-run ``` Do not use a generic hardening list to remove packages, disable IPv6, disable ICMP, turn off forwarding, or change kernel parameters without understanding the server role. Those actions can break containers, VPNs, routing, monitoring, clustering, cloud networking, and application dependencies. For each public listener, answer four questions: 1. Does the service need to run? 2. Does it need to listen on this interface? 3. Does it need a public firewall rule? 4. How is it authenticated and updated? **Verify:** Every remaining listening service and enabled boot service should have a documented operational purpose, and no unreviewed package/service should have been removed merely because it looked unfamiliar. ## Step 9 — Keep AppArmor enabled and inspect confinement status AppArmor is Ubuntu's mandatory access control system. Current Ubuntu documentation states that it is installed and loaded by default, and strongly recommends using it as a defense-in-depth layer. Check its state: ```bash sudo aa-status ``` Also check the profile-loading service: ```bash systemctl is-enabled apparmor.service systemctl status apparmor.service --no-pager ``` Review recent AppArmor denials: ```bash sudo journalctl -k -g 'apparmor="DENIED"' --since '24 hours ago' --no-pager ``` Do not disable AppArmor globally because one application fails. Ubuntu 24.04 integrates AppArmor more deeply into the kernel than older releases, and disabling it reduces the system's security posture. First determine which profile denied which operation, then make a narrow local profile adjustment when the application genuinely requires that access. Optional profile-management tools are available through: ```bash sudo apt install apparmor-utils ``` Do not force experimental profiles into enforcement on a production application without testing. `complain` mode is useful when developing or validating a profile; `enforce` mode blocks violations. **Verify:** `aa-status` should show AppArmor loaded with profiles present, and any `DENIED` events should be understood rather than worked around by disabling AppArmor wholesale. ## Step 10 — Audit administrator accounts, SSH keys, and stale access List users with interactive shells: ```bash awk -F: '$7 !~ /(nologin|false)$/ {print $1, $6, $7}' /etc/passwd ``` Review sudo access: ```bash getent group sudo ``` Find authorized-key files under normal home directories: ```bash sudo find /home -maxdepth 3 -type f -name authorized_keys -print ``` Review each administrative user's key file with line numbers, for example: ```bash sudo nl -ba /home/deploy/.ssh/authorized_keys ``` Disabling a user's Unix password does **not** revoke an already-authorized SSH public key. When removing access, audit both the account and its `authorized_keys`, active sessions, deployment systems, CI/CD credentials, API tokens, and any external identity source. If multiple people administer the server, use individual accounts/keys rather than one shared private key. Do not add an OpenSSH `AllowUsers`/`AllowGroups` rule until you have inventoried every required human and automation identity; an incomplete allowlist is a common lockout source. **Verify:** Every interactive account, sudo member, and authorized SSH key should map to a current owner or automation purpose, with stale access removed through a tested change process. ## Step 11 — Add Fail2Ban only when it solves a real log-based attack surface Fail2Ban is optional. It watches authentication/log events and temporarily blocks sources that repeatedly match failure patterns. It is not a substitute for SSH keys, firewall restrictions, timely updates, or upstream DDoS controls. If your public SSH service receives repeated authentication noise and Fail2Ban fits the threat model, use the dedicated tutorial: [Install Fail2Ban on Ubuntu 24.04 for SSH Protection](/learn/tutorials/install-fail2ban-ubuntu-24-04) At minimum, if Fail2Ban is already installed, verify the service and SSH jail: ```bash systemctl is-active fail2ban sudo fail2ban-client status sudo fail2ban-client status sshd ``` Review its recent logs: ```bash sudo journalctl -u fail2ban --since '24 hours ago' --no-pager ``` Do not infer security quality from raw ban counts. Internet scanning levels, SSH exposure, authentication methods, jail thresholds, and source networks all change how many bans a server records. **Verify:** If Fail2Ban is part of your design, it should be active with only intended jails; if it is not part of your design, SSH should still be protected by the stronger primary controls already configured. ## Step 12 — Review time, authentication logs, failed units, disk, and security signals Correct time is required for authentication, TLS validation, logs, package metadata, and incident reconstruction. Check synchronization: ```bash timedatectl status ``` Review SSH events: ```bash sudo journalctl -u ssh --since '24 hours ago' --no-pager ``` Review warning-or-higher system messages: ```bash sudo journalctl -p warning --since '24 hours ago' --no-pager ``` Check failed services: ```bash systemctl --failed ``` Check disk and inode pressure: ```bash df -h df -i ``` Review recent logins: ```bash last -a | head -n 20 ``` If your environment has centralized logging or monitoring, forward security-relevant events off the server so an attacker with root access cannot silently erase the only copy. Define alerts around unexpected service failures, disk exhaustion, authentication anomalies, newly exposed ports, and backup failures rather than relying on manual review alone. **Verify:** Time synchronization should be healthy, there should be no unexplained failed services or disk exhaustion, and suspicious authentication/system events should have an investigation path. ## Step 13 — Prepare backups and a recovery path before declaring the server hardened A security change can be correct and still cause an outage. A hardened server needs a recovery path that does not depend on the same control you might accidentally break. Before production use: - keep application/data backups on an appropriate schedule; - retain at least one recovery copy outside the VM; - protect backup credentials separately from application credentials; - test restoring critical data and configuration; - document the SSH port, UFW policy, administrator identities, and important service paths; - verify a provider console, rescue environment, or equivalent out-of-band path before removing the last known-good SSH method. Raff [Data Protection](/products/data-protection) can provide an infrastructure-level recovery layer. Application-aware backups remain necessary for databases and workloads that need consistency beyond a VM-level recovery point. Do not call a backup strategy complete merely because jobs report success. Restore testing is what proves that the backup is usable. **Verify:** You should know how to regain administrative access after an SSH/UFW mistake and how to restore the server's critical application data/configuration from a separate recovery copy. ## Step 14 — Run the final Ubuntu server hardening checklist Verify SSH syntax and effective settings: ```bash sudo sshd -t sudo sshd -T | grep -E \ '^(permitrootlogin|pubkeyauthentication|passwordauthentication|kbdinteractiveauthentication|maxauthtries|logingracetime) ' ``` Verify firewall and network exposure: ```bash sudo ufw status numbered sudo ufw show listening sudo ss -tulpn ``` Verify AppArmor: ```bash sudo aa-status ``` Verify automatic updates: ```bash systemctl list-timers apt-daily.timer apt-daily-upgrade.timer --all sudo unattended-upgrade --dry-run ``` Verify accounts and service health: ```bash getent group sudo systemctl --failed ``` Check pending package updates and reboot state: ```bash sudo apt update apt list --upgradable 2>/dev/null test -f /var/run/reboot-required && \ cat /var/run/reboot-required || \ echo "No reboot required" ``` Finally, test from another machine: 1. a fresh key-based SSH session works; 2. password-only SSH does not provide an unintended login path; 3. required public application ports work; 4. unnecessary ports are not reachable; 5. backup/recovery access is documented and tested. This tutorial is a practical baseline, not a certification. If your organization must meet CIS, FIPS, PCI DSS, HIPAA, SOC 2 controls, or another standard, map the applicable requirements to the actual system and use supported auditing/compliance tooling. Do not claim compliance simply because a generic server-hardening checklist was completed. **Verify:** The server should pass the final checks with no unexplained access, listeners, failed services, pending recovery gap, or security control that exists only on paper. ## Troubleshooting ### A new SSH session stops working after the hardening change Keep an existing session open and check: ```bash sudo sshd -t sudo sshd -T | grep -E \ '^(port|permitrootlogin|pubkeyauthentication|passwordauthentication|kbdinteractiveauthentication) ' sudo ufw status numbered ``` Inspect all snippets because an earlier file may have supplied the first value: ```bash sudo ls -1 /etc/ssh/sshd_config.d/ sudo grep -RniE \ '^(PermitRootLogin|PubkeyAuthentication|PasswordAuthentication|KbdInteractiveAuthentication)' \ /etc/ssh/sshd_config /etc/ssh/sshd_config.d 2>/dev/null ``` Correct the effective setting before restarting SSH again. ### `PasswordAuthentication no` appears in a file but `sshd -T` says `yes` OpenSSH normally uses the first obtained value for most directives. Another earlier snippet may already define the option. Inspect snippet order and use `sshd -T` as the authority for the effective configuration. ### UFW is active but a Docker container port is still reachable Docker-published traffic can bypass ordinary UFW host-filter assumptions. Inspect: ```bash docker ps --format 'table {{.Names}}\t{{.Ports}}' sudo ufw show raw ``` Bind private container ports to loopback or use Docker-aware/upstream filtering. The full Docker caveat is covered in the UFW tutorial. ### `unattended-upgrade --dry-run` does not include a third-party package That can be expected. Adding an APT repository does not automatically add its origin to the unattended-upgrades policy. Review `/etc/apt/apt.conf.d/50unattended-upgrades` and the third-party vendor's supported update approach before modifying allowed origins. ### AppArmor blocks an application Inspect the denial rather than disabling AppArmor: ```bash sudo journalctl -k -g 'apparmor="DENIED"' --since '1 hour ago' --no-pager ``` Identify the profile and operation, then make a narrow tested profile adjustment if the access is legitimately required. ### A security scanner demands many sysctl or SSH crypto changes Determine which benchmark/profile generated the finding and whether it applies to this server. Security benchmark recommendations can conflict with application functionality and distro defaults. Apply standards-driven changes through a tested compliance process rather than copying them into a general baseline. ## Conclusion You now have an Ubuntu 24.04 hardening baseline built around verified access and reduced attack surface: non-root administration, tested SSH keys, effective OpenSSH configuration checks, deny-by-default UFW, automatic security updates, service/account review, AppArmor confinement, optional Fail2Ban, security logging, and recovery planning. The most important operational habit is continuous verification. Re-run the listener, firewall, account, update, AppArmor, service-health, and backup checks after application deployments and access changes. Hardening is not a one-time state and it is not synonymous with compliance; it is an ongoing process of keeping the server's privileges and exposed surface aligned with what the workload actually requires. For adjacent procedures, use [Generate SSH Keys on Ubuntu 24.04](/learn/tutorials/set-up-ssh-keys-ubuntu-24-04), [Set Up UFW Firewall on Ubuntu 24.04](/learn/tutorials/set-up-ufw-firewall-ubuntu-24-04), and [Install Fail2Ban on Ubuntu 24.04](/learn/tutorials/install-fail2ban-ubuntu-24-04). ## Sources - [Ubuntu Server — Security suggestions](https://ubuntu.com/server/docs/explanation/security/security_suggestions/) - [Ubuntu Server — OpenSSH server](https://ubuntu.com/server/docs/how-to/security/openssh-server/) - [Ubuntu Server — User management](https://ubuntu.com/server/docs/how-to/security/user-management/) - [Ubuntu Server — Automatic updates](https://ubuntu.com/server/docs/how-to/software/automatic-updates/) - [Ubuntu Server — AppArmor](https://ubuntu.com/server/docs/how-to/security/apparmor/) - [Ubuntu Server — Firewall](https://ubuntu.com/server/docs/security-firewall/) - Upstream guidance re-verified: 2026-09-05 --- ### How to Deploy Uptime Kuma with Docker on Ubuntu 24.04 URL: https://rafftechnologies.com/learn/tutorials/deploy-uptime-kuma-docker-ubuntu-24-04 Description: Deploy Uptime Kuma 2 with Docker Compose on Ubuntu 24.04 using localhost-only port 3001, Caddy HTTPS, monitors, status pages, backups, and safe updates. Uptime Kuma is a self-hosted monitoring application for checking websites, APIs, network services, certificates, and other endpoints from your own server. A safer production pattern on Ubuntu 24.04 is to run Uptime Kuma with Docker Compose, keep its application port bound only to `127.0.0.1:3001`, and let Caddy expose the dashboard over public HTTPS. This avoids publishing the Uptime Kuma web service directly to every network interface. Raff Technologies is the VM platform used by the original tutorial. The saved tested environment remains `Ubuntu 24.04 LTS on Raff 1 vCPU / 2 GB RAM VM`. This revision updates the deployment against current Uptime Kuma v2 documentation and Uptime Kuma **2.5.3**, the latest stable release verified on September 5, 2026. It does not claim a new benchmark or a fresh end-to-end hardware retest. The official Uptime Kuma Docker documentation requires `/app/data` to live on a filesystem with working POSIX file locks and specifically warns about file-locking problems with storage such as NFS. This guide therefore keeps the data directory on local VM storage, backs it up before upgrades, and treats the backup as sensitive because it can contain monitoring configuration, users, notification credentials, and application history. Prerequisites: - An Ubuntu 24.04 VM with SSH and sudo access - Docker Engine and Docker Compose v2 - A domain such as `status.example.com` pointed to the VM - TCP 80 and 443 available for Caddy - A second administrative SSH session or recovery path before firewall changes ## Step 1 — Verify Ubuntu, DNS, Docker, ports, and local storage Confirm the operating system: ```bash cat /etc/os-release ``` Verify Docker and Compose: ```bash docker --version docker compose version ``` If Docker is not installed, use [How to Install Docker on Ubuntu 24.04](/learn/tutorials/install-docker-ubuntu-24-04) before continuing. Check the domain in both address families: ```bash dig +short A status.example.com dig +short AAAA status.example.com ``` Check whether another service already owns the public web ports: ```bash sudo ss -lntp | grep -E ':(80|443)\b' || true ``` Check free disk space and filesystem type for `/opt`: ```bash df -h /opt df -T /opt ``` Uptime Kuma's current install documentation warns that its data directory needs a filesystem with POSIX file-lock support. Keep `/app/data` on normal local storage for this deployment rather than an NFS-style mount. **Verify:** Ubuntu should report 24.04, Docker Compose should work, DNS should point to this VM, ports 80/443 should be available or intentionally owned by your reverse proxy, and `/opt` should be backed by suitable local storage. ## Step 2 — Create a dedicated Uptime Kuma project directory Create the deployment directory: ```bash sudo install -d -o "$USER" -g "$USER" /opt/uptime-kuma cd /opt/uptime-kuma ``` Create the local data and backup directories: ```bash mkdir -p data backups chmod 700 backups ``` The project will use: ```text /opt/uptime-kuma/ ├── compose.yaml ├── data/ └── backups/ ``` The `data` directory is mapped to `/app/data` in the container. Do not place it on unsupported network storage merely to make backups easier. **Verify:** `/opt/uptime-kuma`, `data`, and `backups` should exist and be writable by your administrative user. ## Step 3 — Pin Uptime Kuma 2.5.3 in Docker Compose Uptime Kuma's official Docker tags documentation recommends the `2` tag for the current v2 release line. This tutorial pins the exact stable release verified on September 5, 2026 so a later `docker compose pull` cannot silently move the tutorial to a newer application version. Create `compose.yaml`: ```bash cd /opt/uptime-kuma nano compose.yaml ``` Add: ```yaml services: uptime-kuma: image: louislam/uptime-kuma:2.5.3 container_name: uptime-kuma restart: unless-stopped ports: - "127.0.0.1:3001:3001" volumes: - ./data:/app/data ``` Do not use `louislam/uptime-kuma:latest` for a v2 deployment. Current upstream documentation marks `latest` as deprecated and notes that it points to the v1 line. Validate the Compose file: ```bash docker compose config -q docker compose config --services ``` Inspect the rendered port mapping: ```bash docker compose config | grep -A 8 -n 'ports:' ``` **Verify:** Compose validation should succeed, the service should be `uptime-kuma`, the image should be `2.5.3`, and host port 3001 should be bound to `127.0.0.1` rather than `0.0.0.0`. ## Step 4 — Pull the image and start Uptime Kuma Pull the pinned image: ```bash cd /opt/uptime-kuma docker compose pull ``` Start the stack: ```bash docker compose up -d ``` Check its state: ```bash docker compose ps ``` Inspect startup logs: ```bash docker compose logs --tail=100 uptime-kuma ``` Check the image actually in use: ```bash docker inspect uptime-kuma --format '{{.Config.Image}}' ``` **Verify:** The container should remain running without a restart loop, logs should not show repeated database/file-lock errors, and the inspected image should be `louislam/uptime-kuma:2.5.3`. ## Step 5 — Verify Uptime Kuma is reachable locally but not published publicly Test the local backend: ```bash curl -I http://127.0.0.1:3001 ``` An HTTP response such as `200`, `302`, or another valid application response confirms that the web service is listening. Inspect host listeners: ```bash sudo ss -lntp | grep ':3001' ``` The intended host-side listener is: ```text 127.0.0.1:3001 ``` Check Docker's published ports: ```bash docker compose ps ``` Because this Compose file publishes only to loopback, you do not need a public UFW rule for TCP 3001. This matters because Docker's published-port firewall rules can bypass assumptions based on ordinary UFW `INPUT` filtering. Binding a private backend to loopback is stronger than publishing `0.0.0.0:3001` and hoping a host firewall rule always protects it. **Verify:** Uptime Kuma should answer on `127.0.0.1:3001`, and there should be no `0.0.0.0:3001` or public IPv6 listener for the application port. ## Step 6 — Install Caddy for the public HTTPS endpoint Install prerequisites: ```bash sudo apt update sudo apt install -y debian-keyring debian-archive-keyring apt-transport-https curl ``` Add Caddy's official repository key: ```bash curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | \ sudo gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg ``` Add the stable repository: ```bash curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | \ sudo tee /etc/apt/sources.list.d/caddy-stable.list sudo chmod o+r /usr/share/keyrings/caddy-stable-archive-keyring.gpg sudo chmod o+r /etc/apt/sources.list.d/caddy-stable.list sudo apt update sudo apt install -y caddy ``` Uptime Kuma's reverse-proxy documentation recommends HTTPS for public deployments and notes that its application uses WebSockets. Caddy's `reverse_proxy` supports WebSocket upgrades automatically, so no Nginx-style manual `Upgrade`/`Connection` header boilerplate is needed here. For the full proxy workflow, see [Caddy Reverse Proxy on Ubuntu 24.04](/learn/tutorials/install-caddy-ubuntu-24-04-reverse-proxy). **Verify:** `caddy version` should return a version, and `systemctl is-active caddy` should report `active` unless another process is still occupying ports 80/443. ## Step 7 — Configure UFW without opening port 3001 Check UFW first: ```bash sudo ufw status verbose ``` If UFW is already active, confirm the SSH path you are using is allowed, then add public web traffic: ```bash sudo ufw allow 80/tcp comment 'HTTP for Caddy' sudo ufw allow 443/tcp comment 'HTTPS for Caddy' ``` Do **not** add a public rule for port 3001. If UFW is inactive, do not blindly run `ufw enable` over a remote connection. Configure and verify SSH access first using [Set Up UFW Firewall on Ubuntu 24.04](/learn/tutorials/set-up-ufw-firewall-ubuntu-24-04). If a provider-side firewall is also used, allow the required administration path and public TCP 80/443 there as well. **Verify:** SSH should still work from a fresh connection, public 80/443 should be permitted as intended, and there should be no deliberate public firewall rule for 3001. ## Step 8 — Reverse proxy Uptime Kuma through Caddy Back up the current Caddy configuration: ```bash sudo cp /etc/caddy/Caddyfile /etc/caddy/Caddyfile.bak ``` Configure the status hostname: ```bash sudo tee /etc/caddy/Caddyfile > /dev/null <<'EOF' status.example.com { reverse_proxy 127.0.0.1:3001 } EOF ``` Replace `status.example.com` with your real hostname. Uptime Kuma's current reverse-proxy documentation says it does not support being served from a normal URL subdirectory such as `/uptimekuma`; use a domain or subdomain instead. Format and validate: ```bash sudo caddy fmt --overwrite /etc/caddy/Caddyfile sudo caddy validate --config /etc/caddy/Caddyfile ``` Reload Caddy: ```bash sudo systemctl reload caddy ``` Test HTTP redirect and HTTPS: ```bash curl -I http://status.example.com curl -I https://status.example.com ``` **Verify:** HTTP should redirect to HTTPS, HTTPS should return an Uptime Kuma response with a trusted certificate, and Caddy should proxy to the loopback backend without a 502 error. ## Step 9 — Complete the first-run database and administrator setup Open: ```text https://status.example.com ``` Complete Uptime Kuma's first-run setup. For this single-node Docker deployment, keep the application data under the local `/app/data` mount and use the default/local database path presented by the installer unless you have a separately designed external database architecture. ![Uptime Kuma database setup screen on Ubuntu 24.04](https://raff-images.s3.raffusercloud.com/uptime_kuma_docker_ubuntu_24_04_01_database_setup_webp_ab1c8bf320.png) Create the administrator account with a unique strong password. ![Uptime Kuma dashboard after first login on Ubuntu 24.04](https://raff-images.s3.raffusercloud.com/uptime_kuma_docker_ubuntu_24_04_02_dashboard_webp_214882a499.png) Do not expose setup over raw HTTP on a public interface merely for convenience. Complete account creation through the HTTPS hostname. **Verify:** You should be able to log in through `https://status.example.com`, reach the dashboard, and confirm that subsequent container recreation does not return you to a fresh unconfigured instance. ## Step 10 — Add and verify an HTTP(s) monitor Create a new HTTP(s) monitor in the dashboard. A practical starter configuration is: ```text Monitor Type: HTTP(s) Friendly Name: Raff Website URL: https://rafftechnologies.com Heartbeat Interval: 60 seconds Retries: 0 Accepted Status Codes: 200-299 ``` Uptime Kuma v2 changed the default retry count for newly created monitors to `0`. Add retries only when they reflect the failure semantics you actually want; retries delay alerting and can hide short outages if configured too aggressively. ![Uptime Kuma HTTP monitor configuration screen](https://raff-images.s3.raffusercloud.com/uptime_kuma_docker_ubuntu_24_04_03_add_monitor_webp_27c995437c.png) Before blaming Uptime Kuma when a monitor stays down, test the target from the monitoring VM: ```bash curl -I https://rafftechnologies.com ``` Inspect application logs if needed: ```bash cd /opt/uptime-kuma docker compose logs --tail=100 uptime-kuma ``` **Verify:** The monitor should save successfully and eventually report `Up` when the target is reachable and its response matches your accepted status criteria. ## Step 11 — Configure notifications without leaking provider secrets Uptime Kuma supports multiple native notification providers and can also integrate with Apprise for additional services. Open the dashboard's notification settings, choose the provider you actually use, enter its credentials/webhook/token, and use Uptime Kuma's test action before attaching the notification to production monitors. Treat notification credentials as secrets. Avoid: - pasting webhook URLs or API tokens into public screenshots; - committing notification credentials to Git; - copying the Uptime Kuma `data` directory to an unprotected shared location; - sending full backups through chat or ticket systems without encryption/access controls. After adding the notification, attach it to the monitor and test a controlled notification path rather than creating a real outage on a production service. **Verify:** The provider's test notification should arrive at the intended destination, and no credential should be present in `compose.yaml`, shell history, or public documentation unless that provider explicitly requires an environment-based deployment design. ## Step 12 — Create a public status page with the correct expectations Create a status page from the Uptime Kuma dashboard and add only the monitors you intend to expose publicly. Uptime Kuma's current status-page documentation says status pages are intended for public users, cache results for **5 minutes**, and refresh on a **5-minute** cycle. They therefore should not be described as identical to the authenticated dashboard's live update behavior. You can use multiple status pages and, when needed, map a status page to a dedicated domain. If you use domain-based status pages behind a reverse proxy, make sure the proxy preserves the host information Uptime Kuma needs. Caddy does this appropriately in the normal reverse-proxy flow. Do not put internal hostnames, private IPs, customer names, incident notes, or sensitive infrastructure labels on a public status page unless disclosure is intentional. **Verify:** Open the status page in a private/incognito browser session and confirm that it shows only the intended services without exposing administrative controls or sensitive monitor details. ## Step 13 — Back up `/app/data` before updates or migrations Uptime Kuma v2 removed the old JSON backup/restore feature; current upstream migration guidance says backing up the **data directory** is the supported backup method. Create a timestamped backup directory: ```bash cd /opt/uptime-kuma STAMP="$(date +%F-%H%M%S)" BACKUP_DIR="/opt/uptime-kuma/backups/$STAMP" mkdir -p "$BACKUP_DIR" chmod 700 "$BACKUP_DIR" ``` Stop Uptime Kuma for a consistent filesystem-level copy: ```bash docker compose stop uptime-kuma ``` Archive the local data directory and Compose configuration: ```bash tar -czf "$BACKUP_DIR/uptime-kuma-data.tar.gz" -C /opt/uptime-kuma data cp compose.yaml "$BACKUP_DIR/" sudo cp /etc/caddy/Caddyfile "$BACKUP_DIR/Caddyfile" ``` Restart the application: ```bash docker compose start uptime-kuma ``` Inspect the archive: ```bash ls -lh "$BACKUP_DIR" tar -tzf "$BACKUP_DIR/uptime-kuma-data.tar.gz" | head ``` Keep a protected copy outside this VM. The backup can contain monitoring metadata and notification credentials, so access to the backup should be at least as restricted as access to the dashboard itself. Raff [Data Protection](/products/data-protection) can provide an infrastructure-level recovery layer, but an application-level `/app/data` backup remains valuable before Uptime Kuma upgrades and migrations. **Verify:** The backup should contain the complete local `data` directory plus Compose/Caddy configuration, Uptime Kuma should return to a running state, and at least one protected copy should exist away from the live VM. ## Step 14 — Update, troubleshoot, verify end to end, and roll back safely Before an application update, read the Uptime Kuma release notes and create a fresh backup. This tutorial pins `2.5.3`. To move to a later stable v2 release, edit only the image tag after reviewing the target release: ```bash cd /opt/uptime-kuma nano compose.yaml ``` Then pull and recreate: ```bash docker compose pull docker compose up -d --force-recreate ``` Check state and logs immediately: ```bash docker compose ps docker compose logs --tail=120 uptime-kuma docker inspect uptime-kuma --format '{{.Config.Image}}' ``` The official update workflow also uses `docker compose pull` followed by `docker compose up -d --force-recreate`. If you are still running Uptime Kuma v1 elsewhere, do **not** treat v1→v2 as an ordinary image update. Upstream calls it a major migration, requires a backup of the data directory, warns that migration can take significant time, and says the migration should not be interrupted. If Caddy returns 502: ```bash curl -I http://127.0.0.1:3001 sudo journalctl -u caddy -n 100 --no-pager docker compose logs --tail=100 uptime-kuma ``` If the monitor stays down: ```bash curl -I https://your-monitored-target.example docker compose logs --tail=100 uptime-kuma ``` If you forget the administrator password, upstream documents a container CLI reset path. Enter the container and run the reset tool, then choose a strong replacement password: ```bash docker exec -it uptime-kuma bash npm run reset-password ``` For the final end-to-end audit: ```bash cd /opt/uptime-kuma docker compose config -q docker compose ps sudo ss -lntp | grep -E ':(80|443|3001)\b' || true curl -I https://status.example.com sudo ufw status numbered ``` Expected architecture: ```text Internet | | HTTPS 443 v Caddy | | 127.0.0.1:3001 v Uptime Kuma 2.5.3 | v local /app/data ``` To stop the application without deleting monitoring data: ```bash docker compose down ``` The bind-mounted `/opt/uptime-kuma/data` directory remains. To start again: ```bash docker compose up -d ``` To remove Uptime Kuma permanently, first verify an external backup, then remove the stack and project data only when deletion is intentional. Do not casually delete `/opt/uptime-kuma/data` during troubleshooting. **Verify:** The dashboard should load over HTTPS, the admin can log in, the monitor should report correctly, notifications/status page should work as designed, port 3001 should remain loopback-only, the data directory should persist across container recreation, and a tested backup should exist before any version change. ## Conclusion You now have Uptime Kuma v2 running on Ubuntu 24.04 with Docker Compose, local persistent storage, loopback-only application exposure, Caddy HTTPS, a verified HTTP monitor, optional notifications and a public status page, plus a backup and controlled update workflow. The important operational boundaries are straightforward: keep `/app/data` on a filesystem with proper POSIX locks, do not publish port 3001 unnecessarily, treat the data backup as sensitive, and never upgrade a v1 deployment to v2 without following the dedicated migration process. Recheck the monitoring VM itself after major updates so the system responsible for reporting outages does not quietly become an unmonitored failure point. For adjacent procedures, use [Install Docker on Ubuntu 24.04](/learn/tutorials/install-docker-ubuntu-24-04), [Caddy Reverse Proxy on Ubuntu 24.04](/learn/tutorials/install-caddy-ubuntu-24-04-reverse-proxy), and [Set Up UFW Firewall on Ubuntu 24.04](/learn/tutorials/set-up-ufw-firewall-ubuntu-24-04). ## Sources - [Uptime Kuma — How to Install](https://github.com/louislam/uptime-kuma/wiki/%F0%9F%94%A7-How-to-Install) - [Uptime Kuma — Docker Tags](https://github.com/louislam/uptime-kuma/wiki/Docker-Tags) - [Uptime Kuma — Releases](https://github.com/louislam/uptime-kuma/releases) - [Uptime Kuma — Reverse Proxy](https://github.com/louislam/uptime-kuma/wiki/Reverse-Proxy) - [Uptime Kuma — How to Update](https://github.com/louislam/uptime-kuma/wiki/%F0%9F%86%99-How-to-Update) - [Uptime Kuma — Migration from v1 to v2](https://github.com/louislam/uptime-kuma/wiki/Migration-From-v1-To-v2) - [Uptime Kuma — Status Page](https://github.com/louislam/uptime-kuma/wiki/Status-Page) - [Uptime Kuma — Notification Methods](https://github.com/louislam/uptime-kuma/wiki/Notification-Methods) - Upstream guidance re-verified: 2026-09-05 --- ### How to Install OpenClaw on Ubuntu 24.04 with Telegram URL: https://rafftechnologies.com/learn/tutorials/deploy-openclaw-ai-agent-ubuntu-24-04 Description: Install OpenClaw on Ubuntu 24.04 with Telegram pairing, a loopback-only Gateway, secure credentials, SSH-tunneled Control UI, backups, and safe updates. OpenClaw is a self-hosted AI assistant that connects model providers, tools, messaging channels, and a local control Gateway. On an Ubuntu 24.04 VM, the safest baseline is to keep the Gateway on its default **loopback-only** bind, run it as the managed user service installed by OpenClaw, connect Telegram through long polling, and avoid opening the Gateway port to the public internet. Telegram does not need an inbound web port in this default mode. Raff Technologies is the VM platform used by the original tutorial. The saved tested environment remains `Ubuntu 24.04 LTS on Raff 2 vCPU / 4 GB RAM VM`. This revision re-verifies the deployment against current OpenClaw documentation on September 5, 2026 and pins **OpenClaw 2026.9.1**, the current npm `latest` release at verification time. It does not claim a new hardware benchmark or a fresh end-to-end retest. OpenClaw's Gateway listens on port `18789` and binds to loopback by default. Current upstream security guidance explicitly recommends keeping it on loopback where possible, using an SSH tunnel or Tailscale Serve for remote UI access, and never exposing an unauthenticated Gateway on `0.0.0.0`. This tutorial therefore does not add a public UFW rule for 18789. Prerequisites: - An Ubuntu 24.04 VM with SSH and sudo access - A non-root administrative user - A supported model-provider login or API key - A Telegram account - A Telegram bot token created with the real `@BotFather` - A second SSH session or recovery path before changing firewall/access settings ## Step 1 — Verify Ubuntu, resources, SSH, and network exposure Confirm the OS: ```bash cat /etc/os-release uname -r ``` Check memory and disk space: ```bash free -h df -h / ``` Confirm your current identity and sudo access: ```bash id sudo -v ``` List listening ports before installing anything: ```bash sudo ss -tulpn ``` Keep the current SSH session open while you work. Open a second SSH session now so you know the recovery path works before hardening or firewall changes. **Verify:** Ubuntu should report 24.04, sudo should work for the administrative user, and you should know which services/ports are already listening before OpenClaw is installed. ## Step 2 — Apply Ubuntu updates and check for a required reboot Update package metadata and review available upgrades: ```bash sudo apt update apt list --upgradable 2>/dev/null ``` Apply the updates according to your maintenance policy: ```bash sudo apt upgrade ``` Check whether a reboot is required: ```bash if [ -f /var/run/reboot-required ]; then cat /var/run/reboot-required else echo "No reboot required" fi ``` If a reboot is required, schedule it before installing the long-running Gateway service, then reconnect and confirm the VM is healthy. **Verify:** `apt update` should finish without repository errors, required security updates should be understood/applied, and any necessary reboot should be completed before continuing. ## Step 3 — Inspect and dry-run the official OpenClaw installer OpenClaw's current recommended Linux installer checks the operating system, verifies or installs a supported Node.js runtime, installs OpenClaw through npm by default, and can manage onboarding. On Linux it provisions the supported Node 24 LTS path when Node is missing; OpenClaw currently supports Node 22.22.3+, 24.15+, and 25.9+ and recommends Node 26 where appropriate. Download the official installer instead of immediately piping it into a shell: ```bash curl -fsSL --proto '=https' --tlsv1.2 \ https://openclaw.ai/install.sh \ -o /tmp/openclaw-install.sh ``` Inspect the beginning of the script and its help output: ```bash head -n 40 /tmp/openclaw-install.sh bash /tmp/openclaw-install.sh --help ``` Preview the exact install without changing the server: ```bash bash /tmp/openclaw-install.sh \ --dry-run \ --version 2026.9.1 \ --no-onboard ``` **Verify:** The script should come from `https://openclaw.ai/install.sh`, help output should display normal installer options, and the dry run should target OpenClaw `2026.9.1` without reporting an unsupported platform/runtime. ## Step 4 — Install OpenClaw 2026.9.1 and verify the CLI Run the inspected installer with an exact version pin and skip onboarding for now: ```bash bash /tmp/openclaw-install.sh \ --version 2026.9.1 \ --no-onboard \ --verify ``` Start a new shell if the installer updates your PATH, then check: ```bash openclaw --version node --version ``` The installer is preferred over `sudo npm install -g openclaw@latest` because it handles supported Node/runtime checks and avoids common root-owned npm-prefix problems on Linux. Remove the temporary installer copy when finished: ```bash rm -f /tmp/openclaw-install.sh ``` **Verify:** `openclaw --version` should report `2026.9.1`, and `node --version` should report a runtime supported by current OpenClaw requirements. ## Step 5 — Run onboarding and install the managed Gateway service Start OpenClaw's guided setup: ```bash openclaw onboard --install-daemon ``` During onboarding: - choose the model provider you actually use; - authenticate with the provider or enter its API key when prompted; - keep the Gateway on its normal local/loopback configuration; - install the managed daemon/service; - skip optional channels/skills/plugins you do not need yet; - keep workspace/state under your user account. Do not paste provider secrets into screenshots, tickets, shell commands, Git repositories, or public documentation. Use the OpenClaw prompt/configuration flow so credentials are stored in the application's supported state/auth stores. After onboarding: ```bash openclaw config validate openclaw doctor ``` **Verify:** Configuration validation should pass, `openclaw doctor` should not report an unresolved critical setup failure, and the managed Gateway service should be installed. ## Step 6 — Verify the Gateway service, loopback bind, and default port Check Gateway state: ```bash openclaw gateway status ``` Inspect the configured bind and port: ```bash openclaw config get gateway.bind openclaw config get gateway.port ``` If the values are not explicitly authored, OpenClaw's current defaults are loopback and port `18789`. Check the live listener: ```bash sudo ss -lntp | grep ':18789' || true ``` The intended security posture is a loopback listener such as: ```text 127.0.0.1:18789 ``` not a public `0.0.0.0:18789` listener. Check the managed user unit: ```bash systemctl --user status openclaw-gateway.service --no-pager ``` OpenClaw's Linux service flow uses a systemd **user** unit. `openclaw doctor` also checks systemd lingering so the Gateway can remain alive after logout. **Verify:** The Gateway should be running, port 18789 should be loopback-only, and the managed user service should be active without a restart loop. ## Step 7 — Apply a messaging-only tool baseline and run the security audit For a Telegram-first assistant that does not need arbitrary host command execution, start from a narrow tool posture: ```bash openclaw config set tools.profile messaging openclaw config set tools.exec.security deny openclaw config set tools.exec.ask always openclaw config set tools.elevated.enabled false ``` Validate the resulting configuration: ```bash openclaw config validate ``` Restart if OpenClaw tells you the changed settings require it: ```bash openclaw gateway restart ``` Run the security checks: ```bash openclaw security audit openclaw security audit --deep ``` Upstream recommends these audits after configuration changes and before expanding network/channel exposure. The deep audit adds live Gateway probes and additional runtime checks. This restrictive tool profile is a safe starting point, not a requirement for every OpenClaw workflow. If you later enable shell, browser, file-write, elevated, or automation tools, do so deliberately and re-run the audit. **Verify:** `openclaw config validate` should pass, the security audit should have no unexplained critical findings, and dangerous execution/elevated capabilities should remain disabled unless explicitly required. ## Step 8 — Protect OpenClaw state and secret-bearing files OpenClaw's current security checks expect private state permissions. Tighten the main state directory and config file: ```bash chmod 700 ~/.openclaw ``` If the config exists: ```bash chmod 600 ~/.openclaw/openclaw.json ``` Inspect without printing credential contents: ```bash stat -c '%a %n' ~/.openclaw stat -c '%a %n' ~/.openclaw/openclaw.json 2>/dev/null || true ``` OpenClaw state can include model auth profiles, channel credentials, pairing allowlists, session metadata/transcripts, and configuration. Do not sync `~/.openclaw` through a broad shared Dropbox/Drive/iCloud folder or copy it into public Git repositories. Run the built-in secret scan: ```bash openclaw secrets audit --check ``` **Verify:** `~/.openclaw` should be owner-only, the config should not be group/world-readable, and the secrets audit should not show an unexplained plaintext or unresolved-secret problem. ## Step 9 — Create a Telegram bot and store its token without printing it In Telegram, verify that the account is exactly: ```text @BotFather ``` Create a bot with: ```text /newbot ``` Save the token privately. OpenClaw's Telegram integration supports a config token, token file, or `TELEGRAM_BOT_TOKEN` environment fallback for the default account. This tutorial uses the environment fallback so the bot token is not copied into `openclaw.json`. Create/update OpenClaw's private environment file: ```bash mkdir -p ~/.openclaw touch ~/.openclaw/.env chmod 600 ~/.openclaw/.env sed -i '/^TELEGRAM_BOT_TOKEN=/d' ~/.openclaw/.env read -s -p "Telegram bot token: " TELEGRAM_BOT_TOKEN echo printf 'TELEGRAM_BOT_TOKEN=%s\n' "$TELEGRAM_BOT_TOKEN" >> ~/.openclaw/.env unset TELEGRAM_BOT_TOKEN ``` Register the Telegram channel using the environment value: ```bash openclaw channels add --channel telegram --use-env ``` Validate and restart if requested: ```bash openclaw config validate openclaw gateway restart ``` **Verify:** Telegram should appear as a configured channel, the token should not be visible in `openclaw config get` output, and `~/.openclaw/.env` should have mode `600`. ## Step 10 — Pair your Telegram DM with the Gateway Open the actual bot you created and send it a direct message such as: ```text /start ``` OpenClaw's default Telegram DM policy is **pairing**. Unknown senders receive a one-time pairing code; current upstream documentation says the code expires after one hour. On the VM, list pending Telegram pairings: ```bash openclaw pairing list telegram ``` Approve only the code associated with your own Telegram account: ```bash openclaw pairing approve telegram PAIRING_CODE ``` Do not change the DM policy to a globally open mode just to avoid pairing. If multiple people will message the bot, use explicit allowlists/pairing and treat each approved sender as delegated authority over whatever tools the agent is allowed to use. **Verify:** Your Telegram account should be approved, an unknown unapproved sender should not gain normal bot access, and `openclaw doctor` should not report an intentionally open DM policy. ## Step 11 — Send an end-to-end Telegram test message Run a final health check before messaging: ```bash openclaw gateway status openclaw doctor openclaw security audit ``` Then send the bot: ```text Reply with exactly: OpenClaw is running on Ubuntu 24.04. ``` The response proves the complete path: ```text Telegram -> OpenClaw channel -> Gateway -> model provider -> Gateway -> Telegram ``` ![OpenClaw AI agent responding through Telegram on Ubuntu 24.04](https://raff-images.s3.raffusercloud.com/openclaw_telegram_agent_response_ubuntu_24_04_webp_8de8d70bdd.png) The old screenshot may show an earlier OpenClaw UI/message format; use the successful Telegram round trip, current CLI status, and current logs as the authority for this revision. :::cta Deploy Your AI Agent VM Launch a Raff Ubuntu VM and run OpenClaw with a loopback-only Gateway, private credentials, and Telegram pairing. ::: **Verify:** The approved Telegram account should receive a valid model response, the Gateway should remain healthy, and no public port should have been required for Telegram long polling. ## Step 12 — Access the Control UI remotely through an SSH tunnel Do not expose the Control UI directly to the public internet. From your **local workstation**, open an SSH tunnel to the VM: ```bash ssh -N -L 18789:127.0.0.1:18789 your_user@your_server_ip ``` Keep that terminal running. On the VM, generate a short-lived browser handoff without trying to launch a GUI browser on the server: ```bash openclaw dashboard --no-open ``` If you need the current structured browser handoff data: ```bash openclaw dashboard --json ``` Then use the tunnel from your local browser. The base local endpoint is: ```text http://127.0.0.1:18789/ ``` Current OpenClaw dashboard guidance recommends localhost, Tailscale Serve, or an SSH tunnel. The `openclaw dashboard` command issues a short-lived one-time browser pairing/bootstrap rather than printing the shared Gateway secret in normal interactive output. **Verify:** The Control UI should load through the SSH tunnel while `sudo ss -lntp | grep 18789` still shows the Gateway only on loopback. ## Step 13 — Back up OpenClaw state before upgrades or major configuration changes Current OpenClaw includes a first-party backup command. Create a protected backup directory outside the live `~/.openclaw` tree: ```bash mkdir -p ~/Backups/openclaw chmod 700 ~/Backups/openclaw ``` Create and immediately verify a full archive: ```bash openclaw backup create \ --output ~/Backups/openclaw \ --verify ``` List the resulting archives: ```bash ls -lh ~/Backups/openclaw ``` You can separately verify an archive later: ```bash openclaw backup verify ~/Backups/openclaw/YOUR_BACKUP_FILE.tar.gz ``` The full backup can contain state, configuration, model/channel credentials, sessions, and workspaces. Treat it like a credential-bearing secret archive: restrict permissions, encrypt/protect remote copies, and do not upload it to a public repository. Raff [Data Protection](/products/data-protection) can add infrastructure-level recovery; the OpenClaw application backup remains valuable before application updates and migrations. **Verify:** `openclaw backup create --verify` should complete successfully and produce a protected archive outside the active OpenClaw state directory. ## Step 14 — Update, troubleshoot, audit, and remove OpenClaw safely Preview future updates first: ```bash openclaw update --dry-run openclaw update status --json ``` Before a significant update, create a verified backup. Then update through OpenClaw's supported updater: ```bash openclaw update ``` The updater detects the installation type, updates the package/channel, runs health checks, and restarts the managed Gateway when appropriate. After every update: ```bash openclaw --version openclaw config validate openclaw gateway status openclaw doctor openclaw security audit --deep ``` If Telegram stops responding: ```bash openclaw pairing list telegram openclaw logs --follow ``` If the Gateway is unreachable locally: ```bash openclaw gateway status --deep sudo ss -lntp | grep ':18789' || true ``` If configuration changes fail: ```bash openclaw config validate openclaw doctor --json ``` If you suspect secret leakage: ```bash openclaw secrets audit --check ``` Rotate any exposed provider key or Telegram token at its source; deleting shell history does not revoke a credential that has already been copied elsewhere. For removal, create a final backup first, then preview the uninstall: ```bash openclaw backup create --output ~/Backups/openclaw --verify openclaw uninstall --dry-run ``` To remove service, state, and workspace interactively: ```bash openclaw uninstall --all ``` The OpenClaw CLI itself is removed separately according to its installation method; for an npm-based install, use the supported uninstall guidance rather than deleting random files from `~/.openclaw` while the Gateway is still running. Final audit: ```bash openclaw gateway status openclaw security audit --deep sudo ss -lntp | grep -E ':(22|18789)\b' || true ``` Expected architecture: ```text Telegram | | outbound long polling / Bot API v OpenClaw Gateway 127.0.0.1:18789 | +--> model provider +--> approved messaging tools Admin browser | | SSH tunnel v 127.0.0.1:18789 ``` **Verify:** The Telegram bot should answer only approved users according to policy, the Gateway should remain loopback-only, the security audit should have no unexplained critical findings, and a verified backup should exist before any major update or removal. ## Conclusion You now have OpenClaw installed on Ubuntu 24.04 with its official installer, a managed Gateway service, a supported Node runtime, Telegram pairing, a messaging-first tool posture, private state permissions, remote Control UI access through an SSH tunnel, and a first-party verified backup workflow. The key security boundary is the Gateway. Telegram long polling does not require you to publish port 18789, and the Control UI should stay on localhost unless you deliberately adopt a secure remote-access design such as Tailscale Serve or a tightly controlled authenticated proxy. Every new skill, plugin, channel, browser capability, shell tool, or approved sender expands what the agent can do, so re-run `openclaw security audit --deep` whenever that authority changes. For adjacent procedures, continue with [Harden Ubuntu 24.04](/learn/tutorials/secure-ubuntu-24-04-server), [Set Up UFW Firewall](/learn/tutorials/set-up-ufw-firewall-ubuntu-24-04), or [Build a Remote Development VM](/learn/tutorials/build-remote-development-vm-code-server-tailscale). ## Sources - [OpenClaw — Getting Started](https://docs.openclaw.ai/start/getting-started) - [OpenClaw — Install](https://docs.openclaw.ai/install) - [OpenClaw — Installer internals](https://docs.openclaw.ai/install/installer) - [OpenClaw — Node.js requirements](https://docs.openclaw.ai/install/node) - [OpenClaw — Telegram](https://docs.openclaw.ai/telegram) - [OpenClaw — Gateway security](https://docs.openclaw.ai/gateway/security) - [OpenClaw — Gateway remote access](https://docs.openclaw.ai/gateway/remote) - [OpenClaw — Dashboard](https://docs.openclaw.ai/cli/dashboard) - [OpenClaw — Backup](https://docs.openclaw.ai/cli/backup) - [OpenClaw — Updating](https://docs.openclaw.ai/install/updating) - [OpenClaw npm package](https://www.npmjs.com/package/openclaw) - Guidance and current release re-verified: 2026-09-05 --- ### How to Install Coolify on Ubuntu 24.04 URL: https://rafftechnologies.com/learn/tutorials/install-coolify-ubuntu-24-04 Description: Install Coolify on Ubuntu 24.04 with the official installer, secure direct-access ports, configure HTTPS domains, deploy an app, and plan backups and updates. Coolify is a self-hosted deployment platform for running applications, databases, and services on infrastructure you control. On Ubuntu 24.04, the supported quick-install path is the official Coolify installer, which prepares Docker, creates the Coolify control-plane files under `/data/coolify`, configures server-management SSH keys, and starts the platform. Raff Technologies is the VM platform used by the original tutorial. The saved tested environment remains `Ubuntu 24.04 LTS on Raff 2 vCPU / 4 GB RAM Linux VM; installer, networking, backup, and update guidance reviewed against Coolify documentation in July 2026`. This revision re-verifies the workflow against current Coolify documentation on September 5, 2026 without claiming a new end-to-end machine test. The current documented minimum is 2 CPU cores, 2 GB RAM, and 30 GB of free storage. Treat that as an installation floor, not a production sizing guarantee. Builds, databases, image layers, application memory, persistent volumes, and deployment overlap can require substantially more resources. Coolify also needs several direct-access ports during initial setup; once a custom dashboard domain is working through Coolify's proxy, the direct dashboard/realtime/terminal ports can be closed according to the official firewall guidance. Prerequisites: - A fresh Ubuntu 24.04 LTS VM with at least 2 CPU cores, 2 GB RAM, and 30 GB free storage - SSH access and a tested recovery path - A domain or subdomain you control - Public TCP 80 and 443 available for Coolify's proxy - DNS access for the dashboard and application hostnames ## Step 1 — Verify Ubuntu, resources, storage, and existing listeners Confirm the operating system: ```bash cat /etc/os-release uname -m ``` Coolify's automatic installer supports Ubuntu LTS releases including 24.04 and 64-bit AMD64/ARM64 systems. Check CPU, memory, and free disk space: ```bash nproc free -h df -h / ``` Check filesystem usage under `/data` if it already exists: ```bash df -h /data 2>/dev/null || true ``` Inspect listeners before installing Coolify: ```bash sudo ss -tulpn ``` Pay particular attention to ports 80, 443, 8000, 6001, and 6002. Existing reverse proxies, web servers, Docker stacks, or manually managed applications can conflict with Coolify. Use a fresh server where practical. Coolify's own documentation recommends this to reduce conflicts with existing services and networking rules. **Verify:** Ubuntu should report 24.04 LTS on a supported 64-bit architecture, the server should meet the minimum resource floor, and you should know whether any process already occupies Coolify-related ports. ## Step 2 — Confirm SSH access and update Ubuntu safely Coolify manages its local and remote servers through SSH, so server access is part of the platform's control plane. Open a second SSH session before making firewall changes: ```bash ssh your_user@your_server_ip ``` Update package metadata and review upgrades: ```bash sudo apt update apt list --upgradable 2>/dev/null ``` Apply updates according to your maintenance policy: ```bash sudo apt upgrade ``` Check whether Ubuntu requests a reboot: ```bash if [ -f /var/run/reboot-required ]; then cat /var/run/reboot-required else echo "No reboot required" fi ``` Current Coolify quick-install documentation recommends running installation as root; it also documents `sudo` for users who are not logged in as root. Do not assume every non-root setup is fully supported simply because `sudo` can launch the installer. For general SSH hardening, see [Harden Ubuntu 24.04](/learn/tutorials/secure-ubuntu-24-04-server). **Verify:** A second SSH connection should work, `sudo` should be functional if you are not root, updates should complete without repository errors, and any required reboot should be handled before installation. ## Step 3 — Review Coolify's required ports before enabling or changing a firewall For a self-hosted Coolify server, current official firewall documentation lists these inbound ports when using direct IP access: ```text 22/tcp SSH, or your custom SSH port 80/tcp HTTP and certificate generation through the proxy 443/tcp HTTPS through the proxy 8000/tcp Direct Coolify dashboard access 6001/tcp Realtime dashboard communication for direct IP access 6002/tcp Coolify web terminal for direct IP access ``` Check them locally: ```bash sudo ss -lntp | grep -E ':(22|80|443|8000|6001|6002)\b' || true ``` If UFW is already active, confirm the real SSH port is allowed **before** adding Coolify rules. For initial setup, a straightforward rule set is: ```bash sudo ufw allow 80/tcp comment 'Coolify HTTP' sudo ufw allow 443/tcp comment 'Coolify HTTPS' sudo ufw allow 8000/tcp comment 'Coolify initial dashboard' sudo ufw allow 6001/tcp comment 'Coolify realtime direct access' sudo ufw allow 6002/tcp comment 'Coolify web terminal direct access' ``` Do not blindly enable UFW over SSH if it is currently inactive. Use the lockout-safe flow in [Set Up UFW Firewall on Ubuntu 24.04](/learn/tutorials/set-up-ufw-firewall-ubuntu-24-04). Docker creates its own firewall/NAT rules. Treat Docker-published application ports separately from ordinary UFW host rules; do not assume UFW alone will block every Docker-published port. **Verify:** The active SSH path must remain reachable, ports required for initial Coolify setup should be intentionally available, and no unrelated process should be unexpectedly bound to those ports. ## Step 4 — Run the official Coolify stable installer Install `curl` if needed: ```bash sudo apt update sudo apt install -y curl ``` Run the official stable installer documented by Coolify: ```bash curl -fsSL https://cdn.coollabs.io/coolify/install.sh | sudo bash ``` If you are already root, the documented command can run without `sudo`: ```bash curl -fsSL https://cdn.coollabs.io/coolify/install.sh | bash ``` The installer: - installs required command-line tools; - installs Docker Engine when needed; - configures Docker for Coolify; - creates files under `/data/coolify`; - creates SSH keys used by Coolify for server management; - starts the Coolify control plane. Docker installed through Snap is not supported. If the installer detects Snap Docker, remove that package and follow the supported Docker path before retrying. For production, use the normal stable installer/CDN path rather than forcing a GitHub release simply because it is newer. Coolify intentionally may delay CDN availability after a GitHub release for additional testing. **Verify:** The installer should complete without an unsupported-OS/Docker error and should print the initial Coolify URL, normally using TCP 8000. ## Step 5 — Verify the Coolify containers and initial dashboard listener Inspect the running containers: ```bash sudo docker ps --format 'table {{.Names}}\t{{.Status}}\t{{.Ports}}' ``` Check port 8000: ```bash sudo ss -lntp | grep ':8000' || true ``` If installation failed or the dashboard does not load, inspect all containers: ```bash sudo docker ps -a ``` Then inspect relevant logs using the actual container names returned by Docker, for example: ```bash sudo docker logs --tail=200 coolify 2>/dev/null || true ``` Coolify's troubleshooting documentation notes that an occupied TCP 8000 can cause installation problems, so re-check that port if the initial web UI is unavailable. **Verify:** Coolify control-plane containers should remain running rather than restart-looping, and the initial dashboard should answer at the URL printed by the installer. ## Step 6 — Create the first administrator account immediately Open the initial registration page: ```text http://your_server_ip:8000 ``` Create the first administrator account immediately. Coolify's installation documentation explicitly warns that if another person reaches the registration page before you, they may create the first account and gain control of the server. Use: - a unique administrator email; - a long password stored in a password manager; - an administrator identity that is not shared between multiple people; - a documented recovery path outside the VM. Sign out and back in before changing network access so you know the administrator credentials work. :::cta Deploy Your Coolify Server Launch an Ubuntu 24.04 VM and build a self-hosted Coolify deployment with your own applications, domains, and recovery plan. ::: **Verify:** The first admin account should exist, login should succeed in a fresh browser session, and the public registration flow should no longer offer unrestricted first-user creation. ## Step 7 — Configure a custom dashboard domain and HTTPS Create a DNS record such as: ```text coolify.example.com -> your_server_ip ``` Use an `A` record for IPv4. Add an `AAAA` record only when IPv6 really reaches this VM and is protected consistently. Check DNS from another network when possible: ```bash dig +short A coolify.example.com dig +short AAAA coolify.example.com ``` In Coolify's instance settings, configure the dashboard URL: ```text https://coolify.example.com ``` Coolify's integrated proxy then handles routing and TLS for the hostname. Verify HTTPS externally: ```bash curl -I https://coolify.example.com ``` Do not close the direct setup ports until the custom hostname is proven from a separate browser/network path and you retain SSH/recovery access. **Verify:** The dashboard should load over the custom HTTPS hostname with a trusted certificate, and administrator login should work through that hostname. ## Step 8 — Close direct dashboard, realtime, and terminal ports after the custom domain works Current Coolify firewall guidance states that when you use a custom domain through the integrated proxy, you can safely close direct-access ports **8000, 6001, and 6002**. Remove the broad UFW rules you added for initial setup: ```bash sudo ufw delete allow 8000/tcp sudo ufw delete allow 6001/tcp sudo ufw delete allow 6002/tcp ``` Review the final rules: ```bash sudo ufw status numbered ``` Keep: - the real SSH administration path; - 80/tcp when required for HTTP/certificate handling; - 443/tcp for HTTPS applications and the Coolify dashboard. If you deliberately need direct IP dashboard or web-terminal access, restrict the relevant port to a trusted source instead of leaving it open to `Anywhere`. Remember that Docker can publish application ports outside ordinary UFW expectations. Audit deployed application bindings with: ```bash sudo docker ps --format 'table {{.Names}}\t{{.Ports}}' ``` **Verify:** The custom HTTPS dashboard should continue working after 8000/6001/6002 are closed, SSH should remain available, and no application should expose an unintended host port. ## Step 9 — Create a project and deploy an application through the proxy In Coolify: 1. Create a **Project**. 2. Create or select an **Environment**. 3. Add an **Application**. 4. Choose a public repository, connected Git provider, Docker image, or another supported source. 5. Set the branch/build method. 6. Add required environment variables through Coolify. 7. Configure the application's internal listening port. For private repositories, grant the minimum repository access required by the integration. Remove stale source integrations when repositories or team ownership changes. Do not commit production secrets into Git merely because Coolify can deploy from the repository. Application credentials belong in protected environment/secret configuration and should have an owner and rotation process. **Verify:** Coolify should detect/build the source successfully, required variables should be configured outside the repository, and the deployed container should reach a healthy/running state. ## Step 10 — Attach an application domain and verify the deployment end to end Create another DNS record: ```text app.example.com -> your_server_ip ``` Configure that domain on the application in Coolify and route it through the platform proxy. Prefer domain-based proxy routing over manually publishing random host ports. Direct host-port publication increases attack surface and can bypass assumptions in your host firewall design. Test from outside the server: ```bash curl -I https://app.example.com ``` Inspect containers and host utilization: ```bash sudo docker ps sudo docker stats --no-stream free -h df -h / ``` There is no reliable fixed number of apps a Coolify VM can host. Capacity depends on application memory, build load, databases, background workers, traffic, image/cache growth, and the overlap between deployments. **Verify:** The application should respond through its HTTPS domain, there should be no unintended public database/admin ports, and CPU/memory/disk should retain enough headroom for future deployments. ## Step 11 — Configure Coolify instance backups and save the APP_KEY separately A Coolify **instance backup** protects Coolify's own database: projects, resources, settings, credentials metadata, and deployment history. It does **not** back up data inside your applications, databases, or persistent volumes. Open **Settings → Backup** in Coolify. Configure the instance backup if it is not already enabled, then trigger **Backup Now**. Current documentation supports local backup storage and S3-compatible copies. Do not leave the only usable backup on the same VM. Coolify encrypts stored secrets using `APP_KEY`, which is not part of the database backup. Save it separately: ```bash sudo grep '^APP_KEY=' /data/coolify/source/.env ``` Store the complete value in a password manager or another protected location outside the VM. Do not paste it into tickets, chat, screenshots, or public documentation. Also preserve the Coolify management keys on replacement-server migrations: ```bash sudo find /data/coolify/ssh/keys -maxdepth 1 -type f -ls ``` Raff [Object Storage](/products/object-storage) can be used as an off-server destination where Coolify's S3-compatible backup configuration is suitable. **Verify:** The instance backup execution should report success, at least one copy should exist outside the Coolify VM, and the `APP_KEY` should be stored securely and separately from the backup file. ## Step 12 — Back up application databases and persistent data separately Coolify instance backups do not contain your workload data. For supported database resources, current Coolify backup tooling can schedule engine-aware backups for PostgreSQL, MySQL, MariaDB, MongoDB, and ClickHouse and optionally copy them to S3-compatible storage. Create a separate plan for every stateful resource: - relational/document databases: scheduled database-aware backups; - uploaded files: filesystem/volume backups; - object storage: provider-specific backup/replication policy; - Redis/Dragonfly/KeyDB: their own persistence/backup method rather than assuming Coolify's scheduled database-backup workflow supports them; - external SaaS/managed databases: the external provider's recovery procedure. A successful backup file is not a restore test. Periodically restore a copy into a disposable environment and verify the application can read it. Raff [Data Protection](/products/data-protection) can add VM-level recovery, but do not rely on a VM recovery point as the only consistency mechanism for active databases. **Verify:** Every stateful workload should have a documented backup owner, schedule, off-server copy, retention policy, and at least one tested restore path. ## Step 13 — Update Coolify through the stable channel with a recovery point first Before updating Coolify: 1. Create a successful Coolify instance backup. 2. Confirm the separate `APP_KEY` copy is accessible. 3. Back up stateful application data. 4. Check free storage for replacement images and build cache. 5. Read the release notes/changelog for the target stable update. Coolify can update from the dashboard. The documented stable installer can also be re-run to update to the version currently made available through Coolify's CDN: ```bash curl -fsSL https://cdn.coollabs.io/coolify/install.sh | sudo bash ``` Do not assume the newest GitHub release is immediately the recommended CDN release. Coolify's release documentation states that CDN promotion may be delayed for testing and hotfixes. After an update, verify the control plane and workloads: ```bash sudo docker ps sudo docker stats --no-stream curl -I https://coolify.example.com curl -I https://app.example.com ``` Review a representative deployment path before declaring the upgrade complete. **Verify:** The dashboard should load, administrator login should work, proxy/TLS should function, existing applications should remain healthy, and at least one test deployment should complete successfully. ## Step 14 — Run the final security, capacity, and recovery audit Audit listening ports: ```bash sudo ss -tulpn ``` Audit Docker publications: ```bash sudo docker ps --format 'table {{.Names}}\t{{.Ports}}' ``` Audit UFW if you use it: ```bash sudo ufw status numbered ``` Audit resource headroom: ```bash free -h df -h / sudo docker system df ``` Confirm: - the custom Coolify dashboard uses HTTPS; - 8000/6001/6002 are not broadly public unless intentionally required; - SSH access remains restricted and recoverable; - public application traffic uses expected proxy routes; - databases/admin interfaces are not exposed without an explicit design; - Coolify's instance backup exists outside the VM; - the matching `APP_KEY` is stored safely; - application databases and volumes have separate backups; - at least one restore has been tested; - sufficient CPU, RAM, and disk headroom remains for builds and updates. A single Coolify server is still a single failure domain for its control plane and any workloads placed on it. Adding remote deployment servers can distribute workloads, but each stateful component still needs its own availability and recovery design. **Verify:** There should be no unexplained listener, public Docker port, missing off-server backup, lost encryption key, or capacity condition that would make the next deployment/update unsafe. ## Troubleshooting ### The installer finishes but port 8000 does not respond Check whether another service occupied the port or Coolify is restart-looping: ```bash sudo ss -tulpn | grep ':8000' || true sudo docker ps -a ``` Then inspect the actual Coolify container logs: ```bash sudo docker logs --tail=200 coolify 2>/dev/null || true ``` ### The custom dashboard domain returns a certificate or proxy error Check DNS and public ports: ```bash dig +short A coolify.example.com dig +short AAAA coolify.example.com sudo ss -lntp | grep -E ':(80|443)\b' || true sudo ufw status numbered ``` An incorrect `AAAA` record can break IPv6 clients even when IPv4 works. ### The dashboard works on 8000 but realtime updates or the web terminal fail When using **direct IP access**, current Coolify firewall guidance also requires 6001 for realtime communication and 6002 for web-terminal access. If you have already moved the dashboard behind a custom domain/proxy, use that architecture and close the direct ports instead of leaving all three public indefinitely. ### UFW says a Docker application port is blocked but it is still reachable Docker's own NAT/firewall rules can bypass ordinary UFW host `INPUT` assumptions. Check Docker publications: ```bash sudo docker ps --format 'table {{.Names}}\t{{.Ports}}' ``` Prefer routing public web applications through Coolify's proxy and avoid unnecessary direct host-port publishing. ### A Coolify instance backup succeeds but restore cannot decrypt credentials The database backup is not enough by itself. You need the matching `APP_KEY` from `/data/coolify/source/.env`. Without it, encrypted stored credentials cannot be recovered correctly. ### The new Coolify version is on GitHub but the dashboard does not offer it That can be expected. Coolify's release process intentionally separates GitHub release publication from CDN promotion. Wait for the stable CDN channel unless you have a tested reason to force a specific version. ## Conclusion You now have a current Coolify deployment workflow for Ubuntu 24.04: supported resource checks, the official installer, immediate administrator registration, correct direct-access firewall ports, a custom HTTPS dashboard domain, reduced exposure after proxy setup, an application deployment path, separate instance/workload backups, and a controlled stable-channel update process. The most important operational distinction is between the **Coolify control plane** and the **workloads Coolify manages**. Backing up Coolify does not back up application databases or volumes, and securing port 8000 does not automatically secure Docker-published application ports. Treat the control plane, Docker networking, every stateful service, and recovery credentials as separate layers that must all be verified. For adjacent procedures, use [Install Docker on Ubuntu 24.04](/learn/tutorials/install-docker-ubuntu-24-04), [Set Up UFW Firewall](/learn/tutorials/set-up-ufw-firewall-ubuntu-24-04), and [Harden Ubuntu 24.04](/learn/tutorials/secure-ubuntu-24-04-server). ## Sources - [Coolify — Installation](https://coolify.io/docs/get-started/installation) - [Coolify — Firewall](https://coolify.io/docs/knowledge-base/server/firewall) - [Coolify — Backup and Restore](https://coolify.io/docs/knowledge-base/how-to/backup-restore-coolify) - [Coolify — Instance Backup](https://next.coolify.io/docs/core/backup-and-recovery/instance-backup) - [Coolify — Instance Restore](https://next.coolify.io/docs/core/backup-and-recovery/instance-restore) - [Coolify — Database Backups](https://next.coolify.io/docs/databases/backups) - [Coolify — Release Guide](https://github.com/coollabsio/coolify/blob/v4.x/RELEASE.md) - Guidance re-verified: 2026-09-05 --- ### How to Install Ghost CMS on Ubuntu 24.04 with Nginx URL: https://rafftechnologies.com/learn/tutorials/deploy-ghost-cms-ubuntu-24-04-nginx Description: Install Ghost CMS on Ubuntu 24.04 with Nginx, Node.js 22, MySQL 8, Ghost-CLI, HTTPS, backups, rollback, and current Ghost 6 deployment guidance. Ghost is a publishing platform for websites, newsletters, memberships, subscriptions, and social-web publishing. For a conventional production VPS deployment, Ghost's current official guide supports Ubuntu 24.04 with Nginx, Node.js 22 LTS, MySQL 8.0 or 8.4, systemd, and Ghost-CLI. Raff Technologies is the VM platform used by the original tutorial. The saved tested environment remains `Ubuntu 24.04 LTS on Raff 2 vCPU / 2 GB RAM Linux VM; Ghost 6 stack requirements, Node.js 22, MySQL 8, Ghost-CLI, Nginx, and backup guidance reviewed in July 2026`. This revision re-verifies the workflow against current Ghost documentation on September 5, 2026. Ghost **6.61.0** is the latest upstream release observed at verification time; the commands below intentionally install the current supported Ghost 6 release through Ghost-CLI rather than claiming a fresh 6.61.0 machine retest. One important Ghost 6 deployment boundary has changed since older tutorials were written. Ghost-CLI remains an officially documented production install path for Ghost 6.x, but CLI installs do not self-host Ghost's native web analytics service. Social Web support uses Ghost's hosted ActivityPub service in this model. Ghost is moving toward an official Docker Compose deployment for the additional Ghost 6 services, and the Ghost platform team has announced that Ghost-CLI will be deprecated with Ghost 7. If you specifically need fully self-hosted analytics or ActivityPub, review the Docker Compose path instead of assuming this classic Nginx/MySQL/systemd layout includes those services. Prerequisites: - An Ubuntu 24.04 server with at least 1 GB RAM; 2 GB or more gives more operational headroom - A registered domain with DNS pointed to the server - SSH access and a non-root sudo user that is not named `ghost` - Public TCP 80 and 443 available for Nginx and Let's Encrypt - A protected place for database, mail, and recovery credentials ## Step 1 — Verify Ubuntu, DNS, resources, and existing listeners Confirm the OS and architecture: ```bash cat /etc/os-release uname -m ``` Check memory and free storage: ```bash free -h df -h / ``` Check the publication hostname: ```bash dig +short A blog.example.com dig +short AAAA blog.example.com ``` Publish an `AAAA` record only when IPv6 actually reaches this VM and is protected consistently. Inspect current listeners: ```bash sudo ss -tulpn ``` Ghost's official Ubuntu install expects a registered domain. Do not plan to use a raw IP address as the final Ghost URL; the Ghost-CLI install flow can error when an IP address is used as the site URL. **Verify:** Ubuntu should report 24.04, the server should meet the memory/storage floor, DNS should resolve to this server, and ports 80/443 should not be unexpectedly occupied by another production proxy. ## Step 2 — Create or verify a non-root sudo administrator Ghost-CLI must not be run as root. Also do not name the Linux administrator `ghost`, because that conflicts with Ghost-CLI's service-management model. If you are starting as root, create an administrative account such as `ghost-mgr`: ```bash adduser ghost-mgr usermod -aG sudo ghost-mgr su - ghost-mgr ``` Verify sudo: ```bash sudo whoami ``` Expected output: ```text root ``` Open a second SSH session with this account before firewall changes: ```bash ssh ghost-mgr@your_server_ip ``` For broader host hardening, use [Harden Ubuntu 24.04](/learn/tutorials/secure-ubuntu-24-04-server). **Verify:** The non-root user should be able to log in independently, run sudo, and keep a second recovery-capable SSH session open. ## Step 3 — Update Ubuntu and prepare the firewall without risking SSH lockout Update package metadata and review upgrades: ```bash sudo apt update apt list --upgradable 2>/dev/null ``` Apply updates according to your maintenance policy: ```bash sudo apt upgrade ``` Install the base packages used by the stack: ```bash sudo apt install -y ca-certificates curl gnupg ``` If UFW is already active, confirm your actual SSH port is allowed, then allow web traffic: ```bash sudo ufw allow 'Nginx Full' sudo ufw status numbered ``` If UFW is currently inactive, do not blindly enable it over a remote session. Use the lockout-safe process in [Set Up UFW Firewall on Ubuntu 24.04](/learn/tutorials/set-up-ufw-firewall-ubuntu-24-04). Check whether Ubuntu requests a reboot: ```bash if [ -f /var/run/reboot-required ]; then cat /var/run/reboot-required else echo "No reboot required" fi ``` **Verify:** Package operations should complete without repository errors, SSH should remain reachable from the second session, and public TCP 80/443 should be permitted when the firewall is active. ## Step 4 — Install Nginx and MySQL 8 Install the officially recommended web/database stack from Ubuntu's repositories: ```bash sudo apt install -y nginx mysql-server ``` Enable and start both services: ```bash sudo systemctl enable --now nginx mysql ``` Check them: ```bash systemctl is-active nginx mysql nginx -v mysql --version ``` Current Ghost production documentation supports **MySQL 8.0 or 8.4**. Do not substitute MariaDB or SQLite in this documented production Ghost-CLI layout simply because the application may run in other unsupported configurations. Do not expose MySQL port 3306 publicly on this single-server setup. **Verify:** Nginx and MySQL should both be active, MySQL should be an 8.x release supported by current Ghost documentation, and port 3306 should not be intentionally opened to the internet. ## Step 5 — Configure MySQL root authentication for Ghost-CLI setup Ubuntu commonly installs the local MySQL root account with socket authentication. Ghost's official production setup needs a MySQL username/password during installation so Ghost-CLI can create the publication database and a restricted Ghost database user. Open MySQL locally: ```bash sudo mysql ``` Current Ghost documentation uses `caching_sha2_password` for this step: ```sql ALTER USER 'root'@'localhost' IDENTIFIED WITH 'caching_sha2_password' BY 'replace_with_a_long_unique_password'; FLUSH PRIVILEGES; EXIT; ``` Store the new password in a password manager, then test it: ```bash mysql -u root -p ``` Exit after authentication succeeds: ```sql EXIT; ``` Older Ghost tutorials often used `mysql_native_password`. Do not copy that older authentication method into a new Ubuntu 24.04/Ghost 6 deployment when the current Ghost guide explicitly documents `caching_sha2_password`. During `ghost install`, let Ghost-CLI create a dedicated restricted database user. The running publication should not operate as MySQL root. **Verify:** `mysql -u root -p` should authenticate with the new credential, and you should have the credential stored outside the terminal/session before continuing. ## Step 6 — Install the required Node.js 22 LTS runtime system-wide Ghost's current compatibility documentation requires **Node.js 22 LTS**. Node 20 is unsupported for current Ghost 6, and Node 23+ is also unsupported. Install Node.js through the system-wide NodeSource path documented by Ghost: ```bash sudo apt-get update sudo apt-get install -y ca-certificates curl gnupg sudo mkdir -p /etc/apt/keyrings curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key \ | sudo gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg NODE_MAJOR=22 echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_${NODE_MAJOR}.x nodistro main" \ | sudo tee /etc/apt/sources.list.d/nodesource.list sudo apt-get update sudo apt-get install nodejs -y ``` Verify: ```bash node --version npm --version ``` For this Ghost-CLI production pattern, follow Ghost's documented system-wide Node installation instead of relying on a user-specific `nvm` runtime that may disappear from systemd's environment. **Verify:** `node --version` should report a supported Node 22.x release and should be available to the non-root Ghost administrator without sourcing an interactive version-manager shell. ## Step 7 — Install the current Ghost-CLI and verify its environment checks Install Ghost-CLI globally: ```bash sudo npm install ghost-cli@latest -g ``` Verify the CLI: ```bash ghost --version ghost help ``` Run its diagnostic checks where useful: ```bash ghost doctor ``` Ghost-CLI remains the official tool used by Ghost's classic Ubuntu production installation for Ghost 6.x. However, Ghost's platform team announced in August 2026 that Ghost 6.x will be the last major line usable with Ghost-CLI; Ghost 7 is planned to move the supported deployment model to the official Docker image/Compose environment. That future deprecation does not make this Ghost 6.x installation invalid today, but it should influence long-term migration planning. **Verify:** Ghost-CLI should run as the non-root administrator and should not report an unresolved Node/system compatibility error. ## Step 8 — Create the Ghost installation directory with correct ownership Create a dedicated directory: ```bash sudo mkdir -p /var/www/blog.example.com sudo chown ghost-mgr:ghost-mgr /var/www/blog.example.com sudo chmod 775 /var/www/blog.example.com cd /var/www/blog.example.com ``` Replace `ghost-mgr` and `blog.example.com` with your real account and hostname. Check ownership: ```bash pwd ls -ld . ``` Do not pre-create random `ghost` service users or manually chown internal Ghost paths before Ghost-CLI has performed its own Linux-user/service setup. **Verify:** The installation directory should be owned by the non-root administrator and should be the current working directory before you run `ghost install`. ## Step 9 — Install Ghost 6 through Ghost-CLI Run the production installer from the Ghost directory: ```bash ghost install ``` At the time this guide was re-verified, upstream's latest release was Ghost **6.61.0**. `ghost install` intentionally follows the current supported release instead of hard-coding that patch version into a long-lived install command. Use the interactive answers appropriate to your site: ```text Blog URL: https://blog.example.com MySQL hostname: localhost MySQL username: root MySQL password: the administrative password created earlier Ghost database name: ghost_prod Set up a Ghost MySQL user: Yes Set up NGINX: Yes Set up SSL: Yes Set up systemd: Yes Start Ghost: Yes ``` Ghost-CLI uses MySQL administrative access during setup, then can create a database account restricted to the Ghost database. If the setup is interrupted, use: ```bash ghost setup ``` If installation needs to be removed, prefer: ```bash ghost uninstall ``` over deleting directories manually, because the CLI can remove related artifacts cleanly. **Verify:** The install should complete without stack-check failures and should report a running Ghost instance using Nginx, SSL, systemd, and a restricted Ghost database user. ## Step 10 — Verify Ghost, systemd, Nginx, HTTP redirect, and HTTPS From the installation directory: ```bash cd /var/www/blog.example.com ghost status ghost doctor ghost version ``` Inspect the Ghost instances known to the CLI: ```bash ghost ls ``` Check Nginx: ```bash sudo nginx -t systemctl is-active nginx ``` Inspect Ghost's generated systemd unit(s): ```bash systemctl list-units 'ghost_*' --all ``` Test the public endpoints: ```bash curl -I http://blog.example.com curl -I https://blog.example.com ``` HTTP should redirect to HTTPS, and the HTTPS endpoint should return a valid Ghost response with a trusted certificate. **Verify:** `ghost status` should show the site running, `ghost doctor` should pass its critical checks, Nginx syntax should be valid, and the publication should load over HTTPS. ## Step 11 — Create the publication owner and understand the Ghost 6 service boundary Open: ```text https://blog.example.com/ghost ``` Create the publication owner account with a unique email address and strong password. Then configure the site title, design, staff, membership, and integrations. For newsletters, Ghost's native bulk email delivery is designed around Mailgun rather than ordinary SMTP. Treat newsletter provider configuration as a separate production dependency and keep its credentials out of screenshots/repos. For Ghost 6 specifically, understand what this **Ghost-CLI** deployment does and does not self-host: - The primary Ghost application runs on this VM. - Nginx, MySQL, Node.js, and systemd run on this VM. - Social Web features can use Ghost's hosted ActivityPub service. - Native web analytics is **not** self-hosted by this Ghost-CLI install. - Fully self-hosting the newer analytics/ActivityPub service set requires Ghost's Docker Compose deployment, which is still described as a developer-preview path for Ghost 6 and is planned to become the default with Ghost 7. **Verify:** The owner should be able to sign in, core publishing should work, and your team should understand whether the classic CLI architecture satisfies the specific Ghost 6 features you need. ## Step 12 — Protect Ghost configuration and inspect runtime state without exposing secrets Ghost's production config lives at: ```text /var/www/blog.example.com/config.production.json ``` Inspect metadata without printing its contents: ```bash stat -c '%a %U:%G %n' /var/www/blog.example.com/config.production.json ``` This file can contain database, mail, storage, and other sensitive configuration. Do not paste it into tickets, public repositories, or chat. Use Ghost-CLI for routine runtime inspection: ```bash ghost status ghost log ghost doctor ``` If Ghost fails under systemd and ordinary logs are insufficient, Ghost-CLI documents `ghost run` as a direct foreground debugging method: ```bash ghost run ``` Stop that foreground process after diagnosis and return to the managed service. **Verify:** `config.production.json` should not be broadly readable, normal administration should work through Ghost-CLI, and no secret-bearing configuration should have been copied into public logs or documentation. ## Step 13 — Create and verify an off-server Ghost backup From the Ghost installation directory: ```bash cd /var/www/blog.example.com ghost backup ``` Current Ghost-CLI documentation says this creates a zip backup containing: - content in JSON format; - a full members CSV export; - installed themes, including the active theme; - images, files, video, and audio media; - `routes.yaml`; - `redirects.yaml` or `redirects.json`. List the generated archive and inspect it without extracting over the live site: ```bash find . -maxdepth 2 -type f -name '*.zip' -printf '%TY-%Tm-%Td %TH:%TM %p\n' | sort -r | head unzip -l /path/to/ghost-backup.zip | head -n 40 ``` Move or copy a protected backup **off the VM**. Do not keep the only recovery copy on the same filesystem as the publication. Also preserve infrastructure recovery information separately: DNS ownership, mail provider access, SSH/recovery keys, and any secret-bearing server config required to rebuild the exact environment. The Ghost backup is a publication-data backup, not a substitute for every server credential and infrastructure setting. Raff [Data Protection](/products/data-protection) can provide a separate VM-level recovery layer, and Raff [Object Storage](/products/object-storage) can serve as an off-server location when your backup transfer tooling supports S3-compatible storage. **Verify:** A current Ghost backup archive should exist, its contents should be readable, and at least one protected copy should exist outside the live VM. ## Step 14 — Update Ghost and Node.js in the correct order with rollback available Check available Ghost updates: ```bash cd /var/www/blog.example.com ghost check-update ``` Create a backup before changing the application: ```bash ghost backup ``` For normal updates within Ghost 6.x: ```bash ghost update ``` Ghost-CLI supports rollback when an update goes wrong: ```bash ghost update --rollback ``` Do not update Node.js and Ghost in one uncontrolled step. Ghost's current Node documentation says to update Node first, then reinstall the **current Ghost version's dependencies** before attempting a Ghost version upgrade, because Ghost has binary dependencies compiled for the active Node version. When a supported Node change is required: ```bash ghost version ``` Update Node through the documented NodeSource repo, then reinstall the same Ghost version to rebuild dependencies: ```bash ghost update YOUR_CURRENT_GHOST_VERSION --force ``` Only after the current Ghost version is healthy on the new supported Node runtime should you perform the intended Ghost update. After any update: ```bash ghost doctor ghost status ghost version sudo nginx -t curl -I https://blog.example.com ``` **Verify:** The site should remain healthy on a supported Node version, the active Ghost version should be known, HTTPS should work, and a pre-update backup/rollback path should exist. ## Step 15 — Run the final security, maintenance, and migration-readiness audit Check Ghost and the host: ```bash cd /var/www/blog.example.com ghost status ghost doctor ghost ls systemctl --failed df -h / sudo ss -tulpn ``` Check the public site and Admin: ```bash curl -I https://blog.example.com curl -I https://blog.example.com/ghost/ ``` Confirm: - Ghost runs as a managed systemd service rather than an ad-hoc terminal process; - Node.js is still a supported 22.x runtime for the current Ghost 6 line; - MySQL is 8.0/8.4 and is not publicly exposed; - Nginx and TLS are healthy; - the owner/staff list contains only expected users; - `config.production.json` is treated as secret-bearing configuration; - a recent Ghost backup exists off-server; - mail/provider credentials have owners and rotation paths; - disk growth from images, media, logs, backups, and MySQL is monitored; - your team has explicitly chosen classic Ghost-CLI vs the newer Docker Compose architecture based on the Ghost 6 features you need; - migration planning acknowledges that Ghost-CLI is scheduled for deprecation with Ghost 7. Do not assume a classic single-instance Ghost-CLI VPS deployment automatically becomes a multi-node/high-availability design. Ghost's documented classic architecture is a single Ghost application with its supporting services; availability and recovery require a separate architecture decision. **Verify:** There should be no unsupported runtime, public MySQL listener, broken HTTPS path, missing off-server backup, unexplained failed service, or unplanned Ghost 7 migration dependency. ## Troubleshooting ### `ERROR: Unsupported version of Node` or exit status 231 Ghost requires Node.js 22 LTS for the current Ghost 6 production stack. Check: ```bash node --version ``` If necessary, replace the unsupported runtime with Node 22 through the documented NodeSource repository, then reinstall the current Ghost version's dependencies with `ghost update CURRENT_VERSION --force`. ### Ghost-CLI cannot authenticate to MySQL root Check whether the root account still uses socket-only auth: ```bash sudo mysql ``` For the current official Ghost Ubuntu setup, configure a password-backed `caching_sha2_password` root login for the setup step, test `mysql -u root -p`, then rerun `ghost setup` or `ghost install` as appropriate. ### SSL setup fails Verify DNS and public access: ```bash dig +short A blog.example.com dig +short AAAA blog.example.com sudo ss -lntp | grep -E ':(80|443)\b' || true sudo ufw status numbered ``` Then run from the Ghost install directory: ```bash ghost setup ssl ``` ### Ghost fails after a Node.js upgrade Ghost documents that Node upgrades require Ghost's binary dependencies to be reinstalled. Get the current Ghost version and force-reinstall that same version: ```bash ghost version ghost update YOUR_CURRENT_GHOST_VERSION --force ``` ### A Ghost update fails Run diagnostics/logs: ```bash ghost doctor ghost log ghost run ``` If the update changed the installed version and rollback is appropriate: ```bash ghost update --rollback ``` ### Native Ghost 6 web analytics is missing on the CLI install That is an architecture limitation, not necessarily a broken install. Current Ghost documentation says Ghost-CLI deployments do not support the self-hosted web analytics service. Review Ghost's newer Docker Compose deployment if that feature is a requirement. ## Conclusion You now have Ghost CMS running on Ubuntu 24.04 with the current supported classic production stack: Nginx, Node.js 22 LTS, MySQL 8.0/8.4, systemd, Ghost-CLI, HTTPS, application-level backups, and a controlled update/rollback workflow. The most important 2026 distinction is architectural. Ghost-CLI remains valid for Ghost 6.x, but it is no longer the long-term deployment direction for the project. The newer Ghost 6 services such as fully self-hosted web analytics require the Docker Compose architecture, and the Ghost platform team plans to deprecate Ghost-CLI with Ghost 7. Build new deployments with that migration boundary in mind rather than treating today's CLI stack as permanent. For adjacent procedures, use [Harden Ubuntu 24.04](/learn/tutorials/secure-ubuntu-24-04-server), [Set Up UFW Firewall](/learn/tutorials/set-up-ufw-firewall-ubuntu-24-04), and [Secure Nginx with Let's Encrypt](/learn/tutorials/secure-nginx-lets-encrypt-ubuntu-24-04). ## Sources - [Ghost — How to Install Ghost on Ubuntu](https://docs.ghost.org/install/ubuntu) - [Ghost — Supported Node Versions](https://docs.ghost.org/faq/node-versions) - [Ghost — Ghost CLI](https://docs.ghost.org/ghost-cli) - [Ghost — How to Update Ghost](https://docs.ghost.org/update) - [Ghost 6.0 release](https://ghost.org/changelog/6/) - [Ghost releases](https://github.com/TryGhost/Ghost/releases) - [Ghost Platform Team — Deprecating Ghost-CLI](https://forum.ghost.org/t/deprecating-ghost-cli-other-platform-updates/63595) - Guidance and current release re-verified: 2026-09-05 --- ### Deploy Vaultwarden on Ubuntu 24.04 with Docker Compose URL: https://rafftechnologies.com/learn/tutorials/deploy-vaultwarden-docker-ubuntu-24-04 Description: Deploy Vaultwarden on Ubuntu 24.04 with Docker Compose, Caddy HTTPS, locked-down signup/admin access, consistent backups, restores, and safe updates. Vaultwarden is a lightweight, Bitwarden-compatible password manager that you can self-host on your own server. On Ubuntu 24.04, a practical deployment is Docker Compose with Vaultwarden on a private Docker network and Caddy as the only public-facing container for HTTPS. Raff Technologies is the VM platform used by the original tutorial. The saved tested environment remains `Raff VM with 2 vCPU, 4 GB DDR5 RAM, 40 GB NVMe storage, Ubuntu 24.04 LTS, kernel 6.8.x`. This revision re-verifies the deployment guidance against current Vaultwarden documentation and releases on September 5, 2026 without claiming a new end-to-end machine test. This guide pins **Vaultwarden 1.37.2**, the current stable release at verification time. Vaultwarden's release notes specifically require 1.37.2 for compatibility with Bitwarden clients version 2026.8.0 and newer. The deployment also uses the modern integrated WebSocket path: notifications share Vaultwarden's normal HTTP port, so the old dedicated `3012` WebSocket port and `WEBSOCKET_ENABLED` setting are no longer part of the recommended setup. A password manager is security-critical infrastructure. Do not put real credentials into the vault until HTTPS works, the first account can sign in, public registration is disabled, the admin page is disabled unless intentionally required, and you have created an off-server backup. Prerequisites: - Ubuntu 24.04 with SSH and sudo access - A domain such as `vault.example.com` pointing to the VM - Public TCP 80 and 443 available for HTTPS - A tested recovery path before firewall changes - A secure off-server destination for Vaultwarden backups ## Step 1 — Verify Ubuntu, DNS, resources, and existing listeners Confirm the operating system and architecture: ```bash cat /etc/os-release uname -m ``` Check memory and free storage: ```bash free -h df -h / ``` Set the hostname you plan to use and verify DNS: ```bash export DOMAIN=vault.example.com dig +short A "$DOMAIN" dig +short AAAA "$DOMAIN" ``` Publish an `AAAA` record only when IPv6 really reaches this VM and is protected consistently. Inspect current listeners: ```bash sudo ss -tulpn ``` Ports 80 and 443 should be available for the Caddy reverse proxy. Vaultwarden itself will not publish a host port in this deployment. **Verify:** Ubuntu should report 24.04, DNS should point to this server, available memory/disk should be understood, and no unexpected service should already own TCP 80 or 443. ## Step 2 — Update Ubuntu and install Docker Engine with Compose v2 Update package metadata and review upgrades: ```bash sudo apt update apt list --upgradable 2>/dev/null ``` Apply updates according to your maintenance policy: ```bash sudo apt upgrade ``` Install the Docker repository prerequisites: ```bash sudo apt install -y ca-certificates curl gnupg sudo install -m 0755 -d /etc/apt/keyrings sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg \ -o /etc/apt/keyrings/docker.asc sudo chmod a+r /etc/apt/keyrings/docker.asc ``` Add Docker's official repository: ```bash sudo tee /etc/apt/sources.list.d/docker.sources >/dev/null < .env <<'EOF' DOMAIN=vault.example.com ACME_EMAIL=admin@example.com EOF chmod 600 .env ``` Replace both values with your real domain and certificate contact email. This main deployment intentionally does **not** define `ADMIN_TOKEN`; that keeps `/admin` disabled. If you later need the admin interface, use Vaultwarden's Argon2-hashed-token procedure rather than a plaintext token. **Verify:** `/opt/vaultwarden` should exist, `vw-data` and `backups` should not be group/world accessible, and `.env` should have mode 600. ## Step 5 — Create a pinned Vaultwarden 1.37.2 Docker Compose stack Create `compose.yaml`: ```bash cat > compose.yaml <<'EOF' services: vaultwarden: image: vaultwarden/server:1.37.2 container_name: vaultwarden restart: unless-stopped environment: DOMAIN: "https://${DOMAIN}" SIGNUPS_ALLOWED: "true" SHOW_PASSWORD_HINT: "false" IP_HEADER: "X-Real-IP" LOG_LEVEL: "warn" TZ: "Etc/UTC" volumes: - ./vw-data:/data networks: - vaultwarden_net caddy: image: caddy:2 container_name: vaultwarden-caddy restart: unless-stopped depends_on: - vaultwarden ports: - "80:80" - "443:443" environment: DOMAIN: "${DOMAIN}" ACME_EMAIL: "${ACME_EMAIL}" volumes: - ./Caddyfile:/etc/caddy/Caddyfile:ro - caddy_data:/data - caddy_config:/config networks: - vaultwarden_net networks: vaultwarden_net: driver: bridge volumes: caddy_data: caddy_config: EOF ``` Why pin Vaultwarden instead of using `latest`? A password-manager server update can include database migrations and client-compatibility changes. An exact stable tag makes the deployed version auditable and lets you review each future update deliberately. The Vaultwarden service has no `ports:` block, so it is reachable only from the Compose network. **Verify:** `grep -n 'vaultwarden/server' compose.yaml` should show `1.37.2`, and the Vaultwarden service should not publish any host port. ## Step 6 — Configure Caddy HTTPS and the modern WebSocket path Create `Caddyfile`: ```bash cat > Caddyfile <<'EOF' { email {$ACME_EMAIL} } {$DOMAIN} { encode zstd gzip header { Strict-Transport-Security "max-age=31536000" X-Content-Type-Options "nosniff" Referrer-Policy "same-origin" -Server } reverse_proxy vaultwarden:80 { header_up X-Real-IP {remote_host} } } EOF ``` Modern Vaultwarden WebSocket notifications are integrated into the normal HTTP server. Caddy's `reverse_proxy` supports WebSocket upgrades automatically, so do not add an old rule such as: ```text /notifications/hub -> vaultwarden:3012 ``` and do not add `WEBSOCKET_ENABLED=true`. Those belong to older Vaultwarden deployments. Validate the Compose model before starting it: ```bash sudo docker compose config >/dev/null && echo 'Compose config is valid' ``` **Verify:** The Caddyfile should proxy only to `vaultwarden:80`, Compose validation should pass, and there should be no reference to port 3012. ## Step 7 — Pull, start, and verify Vaultwarden 1.37.2 over HTTPS Pull the pinned images: ```bash cd /opt/vaultwarden sudo docker compose pull ``` Start the stack: ```bash sudo docker compose up -d ``` Inspect status and recent logs: ```bash sudo docker compose ps sudo docker compose logs --tail=100 vaultwarden sudo docker compose logs --tail=100 caddy ``` Verify the running Vaultwarden version: ```bash sudo docker compose exec vaultwarden /vaultwarden --version ``` Expected version: ```text vaultwarden 1.37.2 ``` Test HTTPS: ```bash DOMAIN=$(sed -n 's/^DOMAIN=//p' .env) curl -I "https://$DOMAIN" ``` Vaultwarden 1.37.2 is the current stable release at this revision and upstream specifically calls it required for Bitwarden clients 2026.8.0 and newer. **Verify:** Both containers should stay running, `/vaultwarden --version` should report 1.37.2, Caddy should obtain a trusted certificate, and the HTTPS endpoint should respond successfully. ## Step 8 — Create the first account and verify client login before storing real credentials Open: ```text https://vault.example.com ``` Create the first Vaultwarden account while `SIGNUPS_ALLOWED=true`. Use a unique, high-entropy master password. Do not assume the server can recover a forgotten master password; the password-manager design depends on client-side encryption. Establish your own recovery process before putting irreplaceable credentials in the vault. After account creation: 1. Sign out of the web vault. 2. Sign back in. 3. Connect one Bitwarden-compatible browser extension or desktop/mobile client to your self-hosted server URL. 4. Create a temporary test item. 5. Force/trigger a sync if needed. 6. Confirm the item appears in both the web vault and the client. Current Vaultwarden 1.37.2 release notes mention client compatibility changes around Bitwarden 2026.8.0+, so testing at least one real client is more meaningful than checking the browser page alone. **Verify:** The account should log in through HTTPS, at least one supported client should connect to the self-hosted URL, and a temporary item should synchronize successfully. ## Step 9 — Disable public registration immediately after onboarding Once the intended first account exists, change: ```yaml SIGNUPS_ALLOWED: "true" ``` to: ```yaml SIGNUPS_ALLOWED: "false" ``` using a controlled edit: ```bash cd /opt/vaultwarden sed -i 's/SIGNUPS_ALLOWED: "true"/SIGNUPS_ALLOWED: "false"/' compose.yaml sudo docker compose up -d ``` Verify the running environment: ```bash sudo docker compose exec vaultwarden printenv SIGNUPS_ALLOWED ``` Expected output: ```text false ``` Then open the registration page in a private/incognito browser and confirm an unknown visitor cannot create a new account. Do not repeatedly toggle public signups for routine user onboarding. For multi-user deployments, review Vaultwarden's invitation and organization controls rather than leaving anonymous registration enabled indefinitely. **Verify:** `SIGNUPS_ALLOWED` should report `false`, normal existing-user login should still work, and unauthenticated public signup should no longer be available. ## Step 10 — Keep the Vaultwarden admin page disabled unless you explicitly need it Because `ADMIN_TOKEN` is absent from this stack, the Vaultwarden admin interface should be disabled. Check it: ```bash DOMAIN=$(sed -n 's/^DOMAIN=//p' /opt/vaultwarden/.env) curl -sS "https://$DOMAIN/admin" | head ``` A disabled-admin response is the intended state for this guide. If you genuinely need `/admin`, do not use a plaintext token. Generate an Argon2 PHC hash with the exact Vaultwarden version you run: ```bash sudo docker run --rm -it vaultwarden/server:1.37.2 /vaultwarden hash ``` Vaultwarden's admin documentation recommends storing the resulting Argon2 hash as the `ADMIN_TOKEN` configuration value. How `$` characters must be quoted/escaped depends on whether you place the value directly in Compose YAML, a Compose `.env` file, another environment file, or a stack manager, so follow Vaultwarden's current **Enabling admin page** documentation for your exact configuration method. Also be aware that values saved through `/admin` are written to `/data/config.json` and can override environment variables on later starts. Do not mix GUI-managed configuration and Compose-managed configuration without understanding that precedence. If you no longer need the admin page, remove both the environment token **and** any persisted `admin_token` setting in `config.json` according to the official documentation, then restart Vaultwarden. **Verify:** For this tutorial's default architecture, `/admin` should stay disabled and the container logs should not report a plaintext `ADMIN_TOKEN` warning. ## Step 11 — Create a consistent Vaultwarden backup with the built-in SQLite backup command Vaultwarden's `/data` directory contains more than the database: attachments, Send data, RSA keys, configuration, and other persistent application state may also be present. Back up the full persistent dataset, but do not rely on a raw copy of an actively written SQLite database. First create Vaultwarden's built-in consistent SQLite snapshot: ```bash cd /opt/vaultwarden sudo docker compose exec vaultwarden /vaultwarden backup ``` This creates a timestamped file such as: ```text /data/db_20260905_120000.sqlite3 ``` Then stop Vaultwarden briefly so the non-database files are copied from a quiet state: ```bash sudo docker compose stop vaultwarden ``` Create an archive that includes the generated SQLite snapshot and the rest of `/data`, but excludes the live SQLite database/WAL/SHM files: ```bash BACKUP="backups/vaultwarden-$(date -u +%Y%m%d-%H%M%S).tar.gz" sudo tar \ --exclude='vw-data/db.sqlite3' \ --exclude='vw-data/db.sqlite3-wal' \ --exclude='vw-data/db.sqlite3-shm' \ -czf "$BACKUP" \ vw-data compose.yaml Caddyfile .env ``` Start Vaultwarden again: ```bash sudo docker compose start vaultwarden ``` Inspect the archive: ```bash sudo tar -tzf "$BACKUP" | head -n 40 sudo ls -lh "$BACKUP" ``` Copy the archive to a protected **off-server** location. Treat it as sensitive infrastructure data even though vault contents are encrypted. :::cta Protect Your Vaultwarden VM Run Vaultwarden on a Raff Ubuntu VM and keep a separate recovery copy with Data Protection or an off-server backup workflow. ::: **Verify:** The archive should contain a `db_*.sqlite3` snapshot plus persistent Vaultwarden files, Vaultwarden should be running again, and at least one protected backup copy should exist outside the VM. ## Step 12 — Test the restore procedure before you depend on the backup Do not overwrite production during a routine test. Restore into a disposable VM or isolated test directory first. For an actual recovery, stop the stack before replacing data: ```bash cd /opt/vaultwarden sudo docker compose down ``` Move the current data aside rather than deleting it immediately: ```bash sudo mv vw-data "vw-data.before-restore-$(date +%s)" sudo mkdir vw-data sudo chmod 700 vw-data ``` Extract your backup into a temporary directory and restore the saved `vw-data` contents. The built-in Vaultwarden backup file is named `db_*.sqlite3`; rename the intended snapshot to `db.sqlite3` in the restored data directory. Example after extraction: ```bash sudo cp /restore/vw-data/db_20260905_120000.sqlite3 \ /opt/vaultwarden/vw-data/db.sqlite3 ``` Make sure stale SQLite WAL/SHM files are absent when restoring a database created by Vaultwarden's backup/VACUUM process: ```bash sudo rm -f \ /opt/vaultwarden/vw-data/db.sqlite3-wal \ /opt/vaultwarden/vw-data/db.sqlite3-shm ``` Restore the other persistent files/directories from the archive, then start the stack: ```bash sudo docker compose up -d ``` Validate login, attachments, organization data, Send data if used, and client sync. A database-only restore is not enough when the original vault used attachments or other files under `/data`. Raff [Data Protection](/products/data-protection) can provide VM-level recovery, while [Object Storage](/products/object-storage) can be an off-server target when your backup transfer tooling supports S3-compatible storage. **Verify:** The restored test instance should start with the expected accounts/items, attachments should open when applicable, and a client should synchronize successfully against the restored server. ## Step 13 — Update Vaultwarden deliberately instead of tracking `latest` Before an update: 1. Read the Vaultwarden release notes and open compatibility issues. 2. Run the built-in database backup and create a full off-server archive. 3. Confirm a restore has been tested. 4. Note the exact current image tag. Check the currently running version: ```bash cd /opt/vaultwarden sudo docker compose exec vaultwarden /vaultwarden --version ``` When you decide to move from `1.37.2` to a reviewed newer stable version, change the `image:` tag in `compose.yaml`, then run: ```bash sudo docker compose pull vaultwarden sudo docker compose up -d vaultwarden ``` Verify the new version and logs: ```bash sudo docker compose exec vaultwarden /vaultwarden --version sudo docker compose logs --tail=200 vaultwarden ``` Then test: - web-vault login; - browser extension login/sync; - one mobile/desktop client if you use it; - item creation/edit/sync; - WebSocket/live notifications; - attachments and 2FA methods relevant to your users. If the new version fails and upstream permits rollback across that migration boundary, restore the previous pinned image **and** use the pre-update backup when required. Do not assume every database migration is safely reversible by changing only the Docker tag. **Verify:** The updated server should report the intended exact version and all clients/workflows you rely on should pass before the update is considered complete. ## Step 14 — Run the final security, exposure, and recovery audit Inspect containers and host ports: ```bash cd /opt/vaultwarden sudo docker compose ps sudo docker ps --format 'table {{.Names}}\t{{.Ports}}' sudo ss -tulpn ``` Review UFW if used: ```bash sudo ufw status numbered ``` Verify application settings: ```bash sudo docker compose exec vaultwarden printenv DOMAIN sudo docker compose exec vaultwarden printenv SIGNUPS_ALLOWED sudo docker compose exec vaultwarden /vaultwarden --version ``` Check HTTPS: ```bash DOMAIN=$(sed -n 's/^DOMAIN=//p' .env) curl -I "https://$DOMAIN" ``` Confirm all of the following: - Vaultwarden is the reviewed stable version you intended to run; - only Caddy publishes public 80/443; - no 3012 WebSocket port exists; - HTTPS works with a trusted certificate; - public registration is disabled; - `/admin` is disabled unless intentionally required and protected with an Argon2 token; - `SHOW_PASSWORD_HINT` remains false for a public deployment; - the server's database is not exposed as a public service; - a recent full backup exists off-server; - the restore process has been tested; - client sync works from at least one real Bitwarden-compatible client; - VM disk usage, Docker image growth, and backup retention are monitored. Expected architecture: ```text Internet | | 80/443 v Caddy | | private Docker network v Vaultwarden 1.37.2 :80 | +--> /data (SQLite + attachments + keys + persistent state) ``` **Verify:** There should be no unintended public application port, no anonymous signup path, no plaintext admin token warning, no missing off-server backup, and no unresolved client-sync failure. ## Troubleshooting ### New Bitwarden clients cannot log in or sync Check the server version first: ```bash sudo docker compose exec vaultwarden /vaultwarden --version ``` Vaultwarden 1.37.2 is required by upstream for Bitwarden clients 2026.8.0 and newer. Update to a compatible reviewed stable release before debugging client behavior on an older server. ### WebSocket/live sync is broken Do not add port 3012. Modern Vaultwarden handles WebSockets on the normal HTTP port. Check Caddy and Vaultwarden logs: ```bash sudo docker compose logs --tail=200 caddy sudo docker compose logs --tail=200 vaultwarden ``` Ensure the reverse proxy points to `vaultwarden:80` and supports normal WebSocket upgrades. Caddy's `reverse_proxy` does this automatically. ### `/admin` accepts no token or reports an insecure plaintext token The admin setting is named `ADMIN_TOKEN`. Generate an Argon2 hash using: ```bash sudo docker run --rm -it vaultwarden/server:1.37.2 /vaultwarden hash ``` Then follow Vaultwarden's current admin-page documentation for the correct quoting/escaping in your configuration method. If `data/config.json` exists, remember that GUI-saved settings can override environment variables. ### Backup exists but restored attachments are missing A database backup contains database state, not every file under `/data`. Restore the matching attachments and other persistent directories from the full backup archive as well as the SQLite snapshot. ### HTTPS certificate issuance fails Check DNS, ports, and Caddy logs: ```bash DOMAIN=$(sed -n 's/^DOMAIN=//p' /opt/vaultwarden/.env) dig +short A "$DOMAIN" dig +short AAAA "$DOMAIN" sudo ss -lntp | grep -E ':(80|443)\b' || true sudo docker compose logs --tail=200 caddy ``` An incorrect AAAA record can break IPv6 clients even when IPv4 works. ### Compose changes do not affect Vaultwarden settings Check logs for a message that settings are being overridden by `/data/config.json`. Values saved through the admin UI can take precedence over environment variables. Choose one configuration source deliberately instead of editing both independently. ## Conclusion You now have Vaultwarden running on Ubuntu 24.04 with Docker Compose, a pinned Vaultwarden 1.37.2 image, Caddy HTTPS, modern same-port WebSockets, public registration disabled after onboarding, the admin page disabled by default, and a backup/restore workflow that preserves both SQLite data and non-database files. The important security boundary is broader than the Docker container itself. A usable self-hosted password manager depends on TLS, client/server version compatibility, controlled account creation, protected recovery configuration, consistent backups, and proven restores. Treat every Vaultwarden upgrade as a reviewed change rather than silently following a mutable `latest` tag. For adjacent procedures, continue with [Install Docker on Ubuntu 24.04](/learn/tutorials/install-docker-ubuntu-24-04), [Set Up UFW Firewall](/learn/tutorials/set-up-ufw-firewall-ubuntu-24-04), and [Harden Ubuntu 24.04](/learn/tutorials/secure-ubuntu-24-04-server). ## Sources - [Vaultwarden GitHub repository](https://github.com/dani-garcia/vaultwarden) - [Vaultwarden 1.37.2 release discussion](https://github.com/dani-garcia/vaultwarden/discussions/7615) - [Vaultwarden Wiki — Using Docker Compose](https://github.com/dani-garcia/vaultwarden/wiki/Using-Docker-Compose) - [Vaultwarden Wiki — Proxy examples](https://github.com/dani-garcia/vaultwarden/wiki/Proxy-examples) - [Vaultwarden Wiki — Enabling admin page](https://github.com/dani-garcia/vaultwarden/wiki/Enabling-admin-page) - [Vaultwarden Wiki — Backing up your vault](https://github.com/dani-garcia/vaultwarden/wiki/Backing-up-your-vault) - [Vaultwarden WebSocket integration change](https://github.com/dani-garcia/vaultwarden/discussions/4023) - Guidance and stable release re-verified: 2026-09-05 --- ### How to Deploy Odoo on Ubuntu 24.04 with Docker Compose URL: https://rafftechnologies.com/learn/tutorials/deploy-odoo-docker-ubuntu-24-04 Description: Deploy Odoo 19 on Ubuntu 24.04 with Docker Compose, PostgreSQL 15, Caddy HTTPS, workers, database lockdown, matched backups, restores, and safe updates. Odoo is an open-source business application suite for CRM, sales, inventory, accounting, websites, manufacturing, and operations. On Ubuntu 24.04, one maintainable self-hosted pattern is Docker Compose with the official Odoo image, PostgreSQL, persistent volumes, and Caddy for HTTPS. Raff Technologies is the VM platform used by the original tutorial. The saved tested environment remains `Raff VM with 2 vCPU, 4 GB DDR5 RAM, 50 GB NVMe storage, Ubuntu 24.04 LTS`. This revision re-verifies the deployment guidance against current Odoo documentation and the official Docker image on September 5, 2026 without claiming a new end-to-end machine test. This guide updates the original Odoo 18 deployment to **Odoo 19.0**, the current supported on-premise major release. It pins the official Docker image to `odoo:19.0-20260817`, which is the current dated Odoo 19 image visible on Docker Hub at verification time. Odoo 19 supports PostgreSQL 13 or newer; the official Docker examples continue to use PostgreSQL 15, so this tutorial keeps PostgreSQL 15 as the database major version. The most important upgrade rule is that a same-major Odoo 19 bugfix/image update is not the same as a major database upgrade. Do **not** move an existing Odoo 18 database to Odoo 19 by changing only the Docker tag. Odoo documents major-version upgrades as database transformations that require the official upgrade process and, for customized databases, module migration work. Prerequisites: - Ubuntu 24.04 with SSH and sudo access - A domain such as `erp.example.com` pointing to the VM - Public TCP 80 and 443 available for HTTPS - A tested recovery path before firewall changes - A secure off-server destination for Odoo backups ## Step 1 — Verify Ubuntu, DNS, resources, and existing listeners Confirm the operating system and architecture: ```bash cat /etc/os-release uname -m ``` Check CPU, memory, and free disk space: ```bash nproc free -h df -h / ``` Set the Odoo hostname and verify DNS: ```bash export ODOO_DOMAIN=erp.example.com dig +short A "$ODOO_DOMAIN" dig +short AAAA "$ODOO_DOMAIN" ``` Publish an `AAAA` record only when IPv6 really reaches the VM and is protected consistently. Inspect existing listeners: ```bash sudo ss -tulpn ``` Ports 80 and 443 should be available for Caddy. Odoo ports 8069/8072 and PostgreSQL 5432 will remain inside the Docker network rather than being published publicly. **Verify:** Ubuntu should report 24.04, DNS should resolve to this server, resource headroom should be understood, and no unexpected production service should already occupy TCP 80 or 443. ## Step 2 — Install Docker Engine and Docker Compose v2 Update package metadata and install Docker repository prerequisites: ```bash sudo apt update sudo apt install -y ca-certificates curl gnupg sudo install -m 0755 -d /etc/apt/keyrings sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg \ -o /etc/apt/keyrings/docker.asc sudo chmod a+r /etc/apt/keyrings/docker.asc ``` Add Docker's official Ubuntu repository: ```bash sudo tee /etc/apt/sources.list.d/docker.sources >/dev/null < secrets/postgresql_password openssl rand -hex 32 > .odoo_master_password chmod 600 secrets/postgresql_password .odoo_master_password ``` Create the Compose environment file: ```bash cat > .env <<'EOF' ODOO_DOMAIN=erp.example.com ACME_EMAIL=admin@example.com EOF chmod 600 .env ``` Replace the domain and certificate email with your real values. The Odoo `admin_passwd` is not an ordinary user password. It protects database-management operations such as create, delete, dump, and restore. Odoo's own production documentation strongly recommends disabling the Database Manager on internet-facing systems after initial provisioning. **Verify:** Secret files and `.env` should be mode 600, the backup/secrets directories should not be group/world accessible, and you should have stored the generated master password in a password manager before continuing. ## Step 5 — Create the Odoo 19 and PostgreSQL 15 Compose stack Create `compose.yaml`: ```bash cat > compose.yaml <<'EOF' services: db: image: postgres:15 container_name: odoo-db restart: unless-stopped environment: POSTGRES_DB: postgres POSTGRES_USER: odoo POSTGRES_PASSWORD_FILE: /run/secrets/postgresql_password PGDATA: /var/lib/postgresql/data/pgdata secrets: - postgresql_password volumes: - odoo_db_data:/var/lib/postgresql/data/pgdata networks: - odoo_net healthcheck: test: ["CMD-SHELL", "pg_isready -U odoo -d postgres"] interval: 10s timeout: 5s retries: 10 odoo: image: odoo:19.0-20260817 container_name: odoo restart: unless-stopped depends_on: db: condition: service_healthy environment: HOST: db PORT: "5432" USER: odoo PASSWORD_FILE: /run/secrets/postgresql_password secrets: - postgresql_password volumes: - odoo_web_data:/var/lib/odoo - ./config/odoo.conf:/etc/odoo/odoo.conf:ro - ./addons:/mnt/extra-addons networks: - odoo_net caddy: image: caddy:2 container_name: odoo-caddy restart: unless-stopped depends_on: - odoo ports: - "80:80" - "443:443" environment: ODOO_DOMAIN: "${ODOO_DOMAIN}" ACME_EMAIL: "${ACME_EMAIL}" volumes: - ./Caddyfile:/etc/caddy/Caddyfile:ro - caddy_data:/data - caddy_config:/config networks: - odoo_net secrets: postgresql_password: file: ./secrets/postgresql_password networks: odoo_net: driver: bridge volumes: odoo_web_data: name: odoo_web_data odoo_db_data: name: odoo_db_data caddy_data: caddy_config: EOF ``` The official Odoo 19 image supports `PASSWORD_FILE`, so the PostgreSQL password does not need to be placed directly in Compose YAML. Neither Odoo nor PostgreSQL publishes a host port. **Verify:** `docker compose config` should parse the file, the Odoo image should be pinned to `19.0-20260817`, PostgreSQL should be major 15, and only the Caddy service should contain a `ports:` block. ## Step 6 — Configure Odoo proxy mode, workers, database management, and file permissions Create the initial Odoo configuration using the generated master password: ```bash cd /opt/odoo ODOO_MASTER_PASSWORD="$(cat .odoo_master_password)" cat > config/odoo.conf < /opt/odoo/Caddyfile <<'EOF' { email {$ACME_EMAIL} } {$ODOO_DOMAIN} { encode zstd gzip header { Strict-Transport-Security "max-age=31536000" X-Content-Type-Options "nosniff" Referrer-Policy "same-origin" -Server } @websocket path /websocket* reverse_proxy @websocket odoo:8072 { header_up X-Forwarded-Host {host} header_up X-Forwarded-Proto {scheme} header_up X-Real-IP {remote_host} } reverse_proxy odoo:8069 { header_up X-Forwarded-Host {host} header_up X-Forwarded-Proto {scheme} header_up X-Real-IP {remote_host} } } EOF ``` Odoo 19 documents port 8072 as the WebSocket/gevent port when multiprocessing is enabled; it is not used in the default threaded mode. Odoo also requires `proxy_mode` when it is intentionally deployed behind a trusted reverse proxy. Validate the Compose model: ```bash cd /opt/odoo sudo docker compose config >/dev/null && echo 'Compose config is valid' ``` **Verify:** `/websocket` should route to 8072, ordinary requests should route to 8069, and the Compose configuration should validate successfully. ## Step 8 — Start Odoo 19, PostgreSQL, and Caddy and verify the stack Pull the pinned/current images: ```bash cd /opt/odoo sudo docker compose pull ``` Start the stack: ```bash sudo docker compose up -d ``` Check containers and PostgreSQL readiness: ```bash sudo docker compose ps sudo docker compose exec -T db pg_isready -U odoo -d postgres ``` Verify Odoo's major version: ```bash sudo docker compose exec odoo odoo --version ``` Inspect recent logs: ```bash sudo docker compose logs --tail=100 odoo sudo docker compose logs --tail=100 caddy ``` Test HTTPS: ```bash ODOO_DOMAIN=$(sed -n 's/^ODOO_DOMAIN=//p' .env) curl -I "https://$ODOO_DOMAIN" ``` Before the first database exists, the browser should reach Odoo's database setup/selection flow over HTTPS. **Verify:** PostgreSQL should accept connections, Odoo should report version 19.0, all three containers should remain running, and the public domain should answer over trusted HTTPS. ## Step 9 — Create the first Odoo database through the initial setup screen Open: ```text https://erp.example.com ``` Retrieve the database-manager master password only when needed: ```bash sudo grep '^admin_passwd =' /opt/odoo/config/odoo.conf ``` Create the first database with a simple production-safe database name such as: ```text odoo_prod ``` Use a unique administrator email and strong application password. Leave demo data disabled for a production deployment. Preserve the existing tutorial screenshots as visual references for the database creation and Apps dashboard flows: ![odoo_sign_up.png](https://raff-images.s3.raffusercloud.com/odoo_sign_up_7ede2d6ab7.png) ![Odoo Apps dashboard after deployment](https://raff-images.s3.raffusercloud.com/odoo_home_9c87c82043.png) After creation, sign out and back in, then confirm the Apps dashboard loads. :::cta Deploy Your Odoo Server Launch an Ubuntu VM for Odoo and keep the application, PostgreSQL, HTTPS proxy, and recovery workflow under your control. ::: **Verify:** The production database should exist, the first administrator should be able to sign in through HTTPS, and the normal Apps dashboard should load successfully. ## Step 10 — Disable the public Database Manager and restrict Odoo to the production database Odoo explicitly recommends disabling the Database Manager on internet-facing systems. Save the real database name: ```bash cd /opt/odoo read -rp 'Production database name: ' ODOO_DB_NAME if ! [[ "$ODOO_DB_NAME" =~ ^[A-Za-z0-9_]+$ ]]; then echo 'Use only letters, numbers, and underscores.' exit 1 fi printf '%s\n' "$ODOO_DB_NAME" > .odoo_db_name chmod 600 .odoo_db_name ``` Append the production restrictions to the Odoo config: ```bash sudo sed -i 's/^list_db = .*/list_db = False/' config/odoo.conf sudo tee -a config/odoo.conf >/dev/null < Caddyfile <<'EOF' { email {$ACME_EMAIL} } {$ODOO_DOMAIN} { encode zstd gzip header { Strict-Transport-Security "max-age=31536000" X-Content-Type-Options "nosniff" Referrer-Policy "same-origin" -Server } @dbmanager path /web/database* respond @dbmanager 404 @websocket path /websocket* reverse_proxy @websocket odoo:8072 { header_up X-Forwarded-Host {host} header_up X-Forwarded-Proto {scheme} header_up X-Real-IP {remote_host} } reverse_proxy odoo:8069 { header_up X-Forwarded-Host {host} header_up X-Forwarded-Proto {scheme} header_up X-Real-IP {remote_host} } } EOF ``` Restart/reload the affected services: ```bash sudo docker compose restart odoo sudo docker compose exec caddy caddy reload --config /etc/caddy/Caddyfile ``` **Verify:** The normal Odoo login should still work, `/web/database/manager` should no longer be publicly accessible, and the config should contain `list_db = False`, an exact `db_name`, and an exact `dbfilter`. ## Step 11 — Verify the complete Odoo 19 application path and worker architecture Check the public application: ```bash cd /opt/odoo ODOO_DOMAIN=$(sed -n 's/^ODOO_DOMAIN=//p' .env) curl -I "https://$ODOO_DOMAIN/web/login" curl -I "https://$ODOO_DOMAIN/web/database/manager" ``` The login endpoint should respond normally. The database-manager request should be blocked by Caddy. Check containers and database readiness: ```bash sudo docker compose ps sudo docker compose exec -T db pg_isready -U odoo -d postgres sudo docker compose exec odoo odoo --version ``` Inspect recent Odoo logs for worker or proxy failures: ```bash sudo docker compose logs --tail=200 odoo ``` Complete an end-to-end browser check: 1. Sign in through `https://erp.example.com`. 2. Open the Apps dashboard. 3. Create a disposable record in a low-risk test area such as a test contact. 4. Refresh and confirm the record persists. 5. Open a second browser session and confirm the application remains responsive. 6. Delete the disposable record. **Verify:** HTTPS, normal login, PostgreSQL, Odoo 19, application writes, database-manager blocking, and the Docker stack should all work together without exposing 8069/8072/5432 publicly. ## Step 12 — Create a consistent PostgreSQL and Odoo filestore backup An Odoo recovery requires the PostgreSQL database **and** the matching filestore. Backing them up at unrelated times can produce a logically inconsistent restore, so briefly stop the Odoo application while taking both copies. ```bash cd /opt/odoo ODOO_DB_NAME="$(cat .odoo_db_name)" STAMP="$(date -u +%Y%m%d-%H%M%S)" sudo docker compose stop odoo ``` Dump PostgreSQL while the application is stopped: ```bash sudo docker compose exec -T db \ pg_dump -U odoo -Fc "$ODOO_DB_NAME" \ > "backups/odoo-db-${ODOO_DB_NAME}-${STAMP}.dump" ``` Archive the Odoo persistent volume, including the filestore: ```bash sudo docker run --rm \ -v odoo_web_data:/data:ro \ -v /opt/odoo/backups:/backup \ alpine:3.20 \ tar -czf "/backup/odoo-web-data-${ODOO_DB_NAME}-${STAMP}.tar.gz" \ -C /data . ``` Start Odoo again: ```bash sudo docker compose start odoo ``` Create a separate sensitive configuration bundle: ```bash sudo tar -czf "backups/odoo-config-${STAMP}.tar.gz" \ compose.yaml Caddyfile .env config secrets .odoo_db_name sudo chmod 600 backups/odoo-*.dump backups/odoo-*.tar.gz ``` Validate the artifacts: ```bash pg_restore -l "backups/odoo-db-${ODOO_DB_NAME}-${STAMP}.dump" | head sudo tar -tzf "backups/odoo-web-data-${ODOO_DB_NAME}-${STAMP}.tar.gz" | head ``` Copy all required recovery artifacts to protected off-server storage. Raff [Data Protection](/products/data-protection) can provide a separate VM recovery layer, while [Object Storage](/products/object-storage) can be used by S3-compatible backup tooling. **Verify:** A readable PostgreSQL custom-format dump, matching Odoo web-data archive, and protected configuration bundle should exist off-server, and Odoo should be running again after the backup window. ## Step 13 — Test an Odoo restore in an isolated environment A backup is not proven until it restores. Do not test by overwriting the live production instance. On a disposable recovery server or isolated Compose project: 1. Start the same Odoo 19 image and a compatible PostgreSQL 15 service. 2. Create an empty target database owned by the Odoo database role. 3. Restore the database dump with `pg_restore`. 4. Restore the matching `odoo_web_data` archive into the Odoo data volume. 5. Apply the matching configuration and database filter. 6. Start Odoo. 7. Sign in and verify business data plus attachments/documents. Example database restore pattern: ```bash createdb -U odoo odoo_prod pg_restore -U odoo -d odoo_prod /backup/odoo-db-odoo_prod-YYYYMMDD-HHMMSS.dump ``` In the Docker layout, run those commands inside the PostgreSQL container or with the appropriate host/network parameters. Do not restore an Odoo 18 database directly into an Odoo 19 runtime. A major-version database requires Odoo's upgrade process first. **Verify:** The isolated restore should start on the intended Odoo major version, the administrator should be able to sign in, attachments should open, representative records should exist, and no production DNS/SMTP/payment/webhook side effects should be triggered from the test environment. ## Step 14 — Update Odoo 19 safely and keep major upgrades separate For a bugfix update **within Odoo 19**, first create the full backup from Step 12 and review the current official Odoo 19 Docker tag. The official image is rebuilt regularly with newer Odoo 19 revisions. Update the pinned dated tag in `compose.yaml`, then pull and recreate only after review: ```bash cd /opt/odoo sudo docker compose pull odoo sudo docker compose up -d odoo ``` After any same-major update, verify: ```bash sudo docker compose exec odoo odoo --version sudo docker compose logs --tail=200 odoo sudo docker compose ps curl -I "https://$(sed -n 's/^ODOO_DOMAIN=//p' .env)/web/login" ``` A **major upgrade** such as Odoo 18 → 19 is different. Odoo describes it as an irreversible database transformation normally performed through the Odoo upgrade service/process. Customized modules may require their own upgrade scripts and rehearsal. Never perform a major upgrade by only changing `image: odoo:18...` to `image: odoo:19...` against the old database. Run the final exposure audit: ```bash sudo docker ps --format 'table {{.Names}}\t{{.Ports}}' sudo ss -tulpn sudo ufw status numbered ``` Confirm: - the Odoo major version is 19.0; - PostgreSQL is 13+ and this stack uses major 15; - only Caddy publishes public 80/443; - Odoo 8069/8072 and PostgreSQL 5432 are private; - `proxy_mode` is enabled because Odoo is behind Caddy; - `/websocket` routes to 8072 while multiprocessing is enabled; - Database Manager routes are blocked; - `list_db = False`, `db_name`, and `dbfilter` restrict the production database; - PostgreSQL and filestore backups are taken as a matched set; - at least one restore has been rehearsed; - custom addons are version-controlled and included in the upgrade plan; - same-major updates and major database upgrades are treated as different procedures. **Verify:** There should be no unintended public Odoo/PostgreSQL listener, no exposed Database Manager, no missing matched database/filestore backup, and no plan that treats a major Odoo migration as a simple Docker tag change. ## Troubleshooting ### Odoo starts but the browser shows a 502 error Check Odoo and Caddy: ```bash cd /opt/odoo sudo docker compose ps sudo docker compose logs --tail=200 odoo sudo docker compose logs --tail=200 caddy ``` Confirm the normal upstream is `odoo:8069` and the containers share `odoo_net`. ### WebSocket or live features fail after enabling workers Odoo 19 uses the gevent port 8072 for WebSocket traffic in multiprocessing mode. Confirm `workers` is greater than zero and Caddy routes `/websocket*` to `odoo:8072`. ```bash grep '^workers' /opt/odoo/config/odoo.conf grep -n '8072\|websocket' /opt/odoo/Caddyfile sudo docker compose logs --tail=200 odoo ``` ### Database creation returns Access Denied The database-management master password must match `admin_passwd` in the Odoo config: ```bash sudo grep '^admin_passwd =' /opt/odoo/config/odoo.conf ``` Do not confuse this with the PostgreSQL password or the Odoo application administrator password. ### Environment changes do not update the PostgreSQL password Changing `secrets/postgresql_password` does not automatically rotate the password stored inside an already initialized PostgreSQL database. Rotate the PostgreSQL role credential inside PostgreSQL and update the Compose secret as one controlled operation. Do not delete the database volume to solve a credential mismatch. ### The Database Manager is still reachable Check both layers: ```bash grep '^list_db\|^db_name\|^dbfilter' /opt/odoo/config/odoo.conf grep -n 'web/database' /opt/odoo/Caddyfile ``` Odoo recommends disabling database management in production and the reverse proxy can additionally block `/web/database*`. ### An Odoo 18 database fails after changing the image to Odoo 19 Restore the pre-change Odoo 18 runtime and backup. A major database version upgrade requires Odoo's upgrade process; changing the container image alone does not migrate the database schema/data safely. ## Conclusion You now have a current Odoo 19 deployment pattern for Ubuntu 24.04 using Docker Compose, PostgreSQL 15, Caddy HTTPS, multiprocessing workers, WebSocket routing, private application/database ports, production database filtering, matched PostgreSQL/filestore backups, restore testing, and a controlled update process. The main 2026 correction is version and lifecycle discipline: Odoo 19 is the current supported on-premise major, while Odoo 18 remains supported but should not be upgraded by swapping Docker tags. Treat infrastructure updates, Odoo 19 bugfix updates, and major database upgrades as separate change classes with separate recovery plans. For adjacent procedures, use [Install Docker on Ubuntu 24.04](/learn/tutorials/install-docker-ubuntu-24-04), [Set Up UFW Firewall](/learn/tutorials/set-up-ufw-firewall-ubuntu-24-04), and [Harden Ubuntu 24.04](/learn/tutorials/secure-ubuntu-24-04-server). ## Sources - [Odoo 19 — On-premise system configuration](https://www.odoo.com/documentation/19.0/administration/on_premise/deploy.html) - [Odoo 19 — Source install and PostgreSQL requirements](https://www.odoo.com/documentation/19.0/administration/on_premise/source.html) - [Odoo 19 — CLI reference](https://www.odoo.com/documentation/19.0/developer/reference/cli.html) - [Odoo — Standard and extended support](https://www.odoo.com/documentation/19.0/administration/supported_versions.html) - [Odoo — Bugfix updates vs database upgrades](https://www.odoo.com/documentation/19.0/administration/on_premise/update.html) - [Odoo official Docker image](https://hub.docker.com/_/odoo) - [Odoo 19 Docker entrypoint](https://github.com/odoo/docker/blob/master/19.0/entrypoint.sh) - Guidance and image tags re-verified: 2026-09-05 --- ### Self-Host Invoice Ninja on Ubuntu 24.04 with Docker Compose URL: https://rafftechnologies.com/learn/tutorials/self-host-invoice-ninja-docker-ubuntu-24-04 Description: Self-host Invoice Ninja 5.13.37 on Ubuntu 24.04 with Docker Compose, MySQL, Redis, Caddy HTTPS, built-in queues/scheduler, backups, restores, and safe updates. Invoice Ninja is a self-hosted invoicing and business workflow platform for invoices, quotes, expenses, clients, recurring billing, tasks, and payments. On Ubuntu 24.04, the current official Docker direction is the **Debian-based Invoice Ninja image** with MySQL, Redis, persistent application volumes, and a reverse proxy for HTTPS. Raff Technologies is the VM platform used by the original tutorial. The saved tested environment remains `Raff VM with 2 vCPU, 4 GB DDR5 RAM, 40 GB NVMe storage, Ubuntu 24.04 LTS`. This revision re-verifies the deployment guidance against current Invoice Ninja documentation, Docker files, and image tags on September 5, 2026 without claiming a new end-to-end machine test. This guide pins **Invoice Ninja 5.13.37**, the current Debian-image release at verification time. It also corrects an important operational detail that older tutorials often miss: the current Debian container includes **two Laravel queue workers and the Laravel scheduler under Supervisord**, so you do not need a separate host cron job or queue container when you use the current official Debian image as shown here. The application container remains private. Only Caddy publishes ports 80 and 443. MySQL, Redis, Nginx, PHP-FPM, queue workers, and the scheduler stay inside the Docker network. Prerequisites: - Ubuntu 24.04 with SSH and sudo access - A domain such as `billing.example.com` pointing to the VM - Public TCP 80 and 443 available for HTTPS - A tested recovery path before firewall changes - A secure off-server destination for Invoice Ninja backups ## Step 1 — Verify Ubuntu, DNS, resources, and existing listeners Confirm the operating system and architecture: ```bash cat /etc/os-release uname -m ``` Check memory, CPU, and free disk space: ```bash nproc free -h df -h / ``` Set your Invoice Ninja domain and verify DNS: ```bash export INVOICE_NINJA_DOMAIN=billing.example.com dig +short A "$INVOICE_NINJA_DOMAIN" dig +short AAAA "$INVOICE_NINJA_DOMAIN" ``` Only publish an `AAAA` record if IPv6 actually reaches this server and is protected consistently. Inspect current listeners: ```bash sudo ss -tulpn ``` Ports 80 and 443 should be available for Caddy. No Invoice Ninja, MySQL, or Redis port will be published directly on the host. **Verify:** Ubuntu should report 24.04, DNS should resolve to this VM, resource headroom should be understood, and no unexpected production service should already own TCP 80 or 443. ## Step 2 — Install Docker Engine and Docker Compose v2 Install Docker from Docker's official Ubuntu repository: ```bash sudo apt update sudo apt install -y ca-certificates curl gnupg sudo install -m 0755 -d /etc/apt/keyrings sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg \ -o /etc/apt/keyrings/docker.asc sudo chmod a+r /etc/apt/keyrings/docker.asc ``` Add the repository: ```bash sudo tee /etc/apt/sources.list.d/docker.sources >/dev/null < .initial_admin_password chmod 600 .initial_admin_password ``` Prompt for the administrator email: ```bash read -rp 'Initial Invoice Ninja admin email: ' IN_USER_EMAIL read -rp 'Invoice Ninja domain (for example billing.example.com): ' INVOICE_NINJA_DOMAIN read -rp 'ACME certificate email: ' ACME_EMAIL ``` **Verify:** `.initial_admin_password` should exist with mode 600, and the generated application/database secrets should not be written into shell history manually. ## Step 5 — Create a current Invoice Ninja 5.13.37 environment file Create `.env`: ```bash cat > .env < compose.yaml <<'EOF' services: app: image: invoiceninja/invoiceninja-debian:5.13.37 container_name: invoice-ninja-app restart: unless-stopped env_file: - ./.env volumes: - invoice_ninja_app_public:/var/www/html/public - invoice_ninja_app_storage:/var/www/html/storage depends_on: mysql: condition: service_healthy redis: condition: service_healthy networks: - invoice_ninja_net nginx: image: nginx:alpine container_name: invoice-ninja-nginx restart: unless-stopped volumes: - ./nginx:/etc/nginx/conf.d:ro - invoice_ninja_app_public:/var/www/html/public:ro - invoice_ninja_app_storage:/var/www/html/storage:ro depends_on: app: condition: service_healthy networks: - invoice_ninja_net mysql: image: mysql:8.4 container_name: invoice-ninja-mysql restart: unless-stopped environment: MYSQL_DATABASE: ${MYSQL_DATABASE} MYSQL_USER: ${MYSQL_USER} MYSQL_PASSWORD: ${MYSQL_PASSWORD} MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD} volumes: - invoice_ninja_mysql_data:/var/lib/mysql healthcheck: test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-u${MYSQL_USER}", "-p${MYSQL_PASSWORD}"] interval: 10s timeout: 5s retries: 10 networks: - invoice_ninja_net redis: image: redis:7.4-alpine container_name: invoice-ninja-redis restart: unless-stopped volumes: - invoice_ninja_redis_data:/data healthcheck: test: ["CMD", "redis-cli", "ping"] interval: 10s timeout: 5s retries: 10 networks: - invoice_ninja_net caddy: image: caddy:2 container_name: invoice-ninja-caddy restart: unless-stopped depends_on: - nginx ports: - "80:80" - "443:443" environment: INVOICE_NINJA_DOMAIN: ${INVOICE_NINJA_DOMAIN} ACME_EMAIL: ${ACME_EMAIL} volumes: - ./Caddyfile:/etc/caddy/Caddyfile:ro - invoice_ninja_caddy_data:/data - invoice_ninja_caddy_config:/config networks: - invoice_ninja_net networks: invoice_ninja_net: driver: bridge volumes: invoice_ninja_app_public: name: invoice_ninja_app_public invoice_ninja_app_storage: name: invoice_ninja_app_storage invoice_ninja_mysql_data: name: invoice_ninja_mysql_data invoice_ninja_redis_data: name: invoice_ninja_redis_data invoice_ninja_caddy_data: name: invoice_ninja_caddy_data invoice_ninja_caddy_config: name: invoice_ninja_caddy_config EOF ``` Invoice Ninja's older `invoiceninja/invoiceninja` image now carries a deprecation notice directing users to the Debian-based image. This guide therefore pins the current Debian release rather than using the mutable `latest` tag. **Verify:** The app image should be exactly `invoiceninja/invoiceninja-debian:5.13.37`, MySQL/Redis should have no `ports:` block, and only Caddy should publish ports 80/443. ## Step 7 — Create the internal Nginx and public Caddy reverse-proxy configuration Create the Nginx snippets used by the official Debian layout: ```bash cat > nginx/invoiceninja.conf <<'EOF' client_max_body_size 20M; client_body_buffer_size 20M; server_tokens off; fastcgi_buffers 32 16K; gzip on; gzip_comp_level 2; gzip_min_length 1M; gzip_proxied any; gzip_types *; EOF ``` Create the Laravel Nginx virtual host: ```bash cat > nginx/laravel.conf <<'EOF' server { listen 80 default_server; server_name _; root /var/www/html/public; index index.php; charset utf-8; add_header X-Frame-Options "SAMEORIGIN"; add_header X-Content-Type-Options "nosniff"; location / { try_files $uri $uri/ /index.php?$query_string; } location = /favicon.ico { access_log off; log_not_found off; } location = /robots.txt { access_log off; log_not_found off; } error_page 404 /index.php; location ~ \.php$ { fastcgi_pass app:9000; fastcgi_param SCRIPT_FILENAME $realpath_root$fastcgi_script_name; include fastcgi_params; } location ~ /\.(?!well-known).* { deny all; } } EOF ``` Create `Caddyfile`: ```bash cat > Caddyfile <<'EOF' { email {$ACME_EMAIL} } {$INVOICE_NINJA_DOMAIN} { encode zstd gzip header { Strict-Transport-Security "max-age=31536000" X-Content-Type-Options "nosniff" X-Frame-Options "SAMEORIGIN" Referrer-Policy "same-origin" -Server } reverse_proxy nginx:80 } EOF ``` Validate the Compose model: ```bash sudo docker compose config >/dev/null && echo 'Compose config is valid' ``` **Verify:** The Compose file should validate, Caddy should proxy only to the private Nginx service, and neither Nginx nor PHP-FPM should be directly exposed on the host. ## Step 8 — Start Invoice Ninja and verify the built-in health check Pull all images first: ```bash cd /opt/invoice-ninja sudo docker compose pull ``` Start the stack: ```bash sudo docker compose up -d ``` Inspect service state: ```bash sudo docker compose ps ``` The current Debian Invoice Ninja image includes an application health check that calls the internal `/health` route through PHP-FPM. Inspect the app health status: ```bash sudo docker inspect \ --format '{{.State.Health.Status}}' \ invoice-ninja-app ``` Check MySQL and Redis: ```bash DB_PASSWORD="$(sed -n 's/^DB_PASSWORD=//p' .env)" sudo docker compose exec -T mysql \ mysqladmin ping -h localhost -uninja -p"$DB_PASSWORD" sudo docker compose exec -T redis redis-cli ping ``` Test HTTPS: ```bash INVOICE_NINJA_DOMAIN="$(sed -n 's/^INVOICE_NINJA_DOMAIN=//p' .env)" curl -I "https://$INVOICE_NINJA_DOMAIN" ``` **Verify:** The app container should become `healthy`, MySQL should report alive, Redis should return `PONG`, Caddy should obtain a trusted certificate, and the public domain should respond over HTTPS. ## Step 9 — Verify the queue workers and scheduler managed by Supervisord The current Debian image starts three application-side process groups automatically: - PHP-FPM; - two `queue:work` processes; - one `schedule:work` process. Check Supervisord from inside the app container: ```bash sudo docker compose exec app supervisorctl status ``` Expected process names include: ```text php-fpm queue-worker_00 queue-worker_01 scheduler ``` You can also inspect the process list: ```bash sudo docker compose exec app ps aux | grep -E \ 'php-fpm|queue:work|schedule:work' | grep -v grep ``` This is why this Docker deployment does not need the host cron line commonly used by manual Invoice Ninja installations: ```text * * * * * php artisan schedule:run ``` Do not run a duplicate host scheduler unless you intentionally redesign the process model. **Verify:** PHP-FPM, both queue workers, and the scheduler should all report `RUNNING`. Recurring invoices and scheduled notifications depend on this scheduler/queue path, so do not consider the deployment production-ready if these processes are missing. ## Step 10 — Log in, rotate the bootstrap password, and remove bootstrap credentials Display the bootstrap email and temporary password only when needed: ```bash grep '^IN_USER_EMAIL=' /opt/invoice-ninja/.env sudo cat /opt/invoice-ninja/.initial_admin_password ``` Open: ```text https://billing.example.com ``` Use the existing tutorial screenshots as visual references: ![Invoice Ninja login page](https://raff-images.s3.raffusercloud.com/invoice_ninja_login_ubuntu_24_04_webp_d831aa8ccc.png) ![Invoice Ninja dashboard](https://raff-images.s3.raffusercloud.com/invoice_ninja_dashboard_ubuntu_24_04_webp_12a621bb7e.png) After the first successful login: 1. Change the administrator password in Invoice Ninja. 2. Sign out and sign back in with the new password. 3. Create one disposable test client. 4. Confirm the client persists after refresh. 5. Delete the disposable test client after verification. Remove the bootstrap variables from `.env`: ```bash cd /opt/invoice-ninja sed -i '/^IN_USER_EMAIL=/d;/^IN_PASSWORD=/d' .env rm -f .initial_admin_password sudo docker compose up -d app nginx ``` The official Debian image warns that if those variables are not explicitly set on first initialization, defaults can be used. They are useful for first-run bootstrap only and should not remain in the long-lived production configuration. :::cta Deploy Your Invoice Ninja Server Launch an Ubuntu VM and run Invoice Ninja with private database/cache services, HTTPS, persistent storage, and your own recovery workflow. ::: **Verify:** The rotated administrator credentials should work, bootstrap variables should be absent from `.env`, the temporary password file should be gone, and Invoice Ninja should remain healthy after the app container is recreated. ## Step 11 — Verify PDF generation, scheduler health, and outbound-email readiness Invoice Ninja's current Debian image includes Chrome/Chromium for Snappdf PDF generation. Create a disposable draft invoice or quote in the UI and preview/download its PDF. Do not send it to a real client during this test. Check application logs if PDF generation fails: ```bash sudo docker compose logs --tail=200 app ``` Verify scheduler and queue processes again: ```bash sudo docker compose exec app supervisorctl status ``` For the initial deployment, outbound mail intentionally remains logged rather than sent: ```bash grep '^MAIL_' /opt/invoice-ninja/.env ``` When you are ready to send real invoices and reminders, replace the mail settings with your SMTP provider's values and recreate the app container: ```bash sudo docker compose up -d app ``` Then send a test message to an address you control and confirm delivery before enabling real recurring workflows. **Verify:** A test PDF should render successfully, queue/scheduler processes should remain running, and SMTP should either remain intentionally disabled via `MAIL_MAILER=log` or be tested successfully with a real provider. ## Step 12 — Create a matched database, application-data, and configuration backup A recoverable Invoice Ninja deployment requires more than MySQL. Preserve: - the MySQL database; - the persistent `/var/www/html/storage` volume; - the persistent `/var/www/html/public` volume; - `.env`, Compose, Nginx, and Caddy configuration. To keep the application files and database closely aligned, stop the web/application path briefly while leaving MySQL available: ```bash cd /opt/invoice-ninja STAMP="$(date -u +%Y%m%d-%H%M%S)" DB_NAME="$(sed -n 's/^DB_DATABASE=//p' .env)" DB_USER="$(sed -n 's/^DB_USERNAME=//p' .env)" DB_PASSWORD="$(sed -n 's/^DB_PASSWORD=//p' .env)" sudo docker compose stop caddy nginx app ``` Create a consistent InnoDB dump: ```bash sudo docker compose exec -T mysql \ mysqldump \ --single-transaction \ --quick \ --routines \ --triggers \ -u"$DB_USER" -p"$DB_PASSWORD" "$DB_NAME" \ | gzip > "backups/invoice-ninja-db-${STAMP}.sql.gz" ``` Archive the persistent app volumes: ```bash sudo docker run --rm \ -v invoice_ninja_app_public:/app_public:ro \ -v invoice_ninja_app_storage:/app_storage:ro \ -v /opt/invoice-ninja/backups:/backup \ alpine:3.20 \ tar -czf "/backup/invoice-ninja-files-${STAMP}.tar.gz" \ -C / app_public app_storage ``` Create a sensitive configuration bundle: ```bash sudo tar -czf "backups/invoice-ninja-config-${STAMP}.tar.gz" \ compose.yaml Caddyfile nginx .env sudo chmod 600 backups/invoice-ninja-*.sql.gz backups/invoice-ninja-*.tar.gz ``` Start the application path again: ```bash sudo docker compose start app nginx caddy ``` Validate the archives: ```bash gzip -t "backups/invoice-ninja-db-${STAMP}.sql.gz" sudo tar -tzf "backups/invoice-ninja-files-${STAMP}.tar.gz" | head sudo tar -tzf "backups/invoice-ninja-config-${STAMP}.tar.gz" | head ``` Copy the backup set to protected **off-server** storage. Raff [Data Protection](/products/data-protection) can provide a VM-level recovery layer, while [Object Storage](/products/object-storage) can be used by S3-compatible backup tooling. **Verify:** The database dump, app-data archive, and configuration bundle should all be readable, Invoice Ninja should return to `healthy`, and at least one complete backup set should exist outside the VM. ## Step 13 — Test a restore in an isolated environment Do not prove backups by overwriting production. Restore into a disposable VM or isolated Compose project. A recovery test should use the same Invoice Ninja image tag first: ```text invoiceninja/invoiceninja-debian:5.13.37 ``` Restore sequence: 1. Start a clean MySQL-compatible service. 2. Restore `.env` and the Compose/proxy configuration. 3. Restore the `app_public` and `app_storage` volume contents. 4. Import the MySQL dump into the `ninja` database. 5. Start Redis and the Invoice Ninja app. 6. Allow the app entrypoint to perform its normal startup checks/migrations for that same version. 7. Start Nginx/Caddy on isolated test DNS. 8. Sign in and verify clients, invoices, attachments, PDFs, queue workers, and scheduler state. Example database import pattern: ```bash gunzip -c invoice-ninja-db-YYYYMMDD-HHMMSS.sql.gz \ | mysql -uninja -p ninja ``` Use the equivalent command inside the recovery MySQL container with the matching credentials. Disable or redirect SMTP, payment webhooks, and any external automation before starting a restored test copy so it cannot send real invoices or trigger real integrations. **Verify:** The restored instance should log in successfully, representative invoices/clients/files should exist, PDF generation should work, queue/scheduler processes should be running, and the test environment should not contact production customers or payment endpoints. ## Step 14 — Update Invoice Ninja safely and run the final exposure audit The current official Docker update guidance is to pull the new image and recreate the containers. For a **pinned** production deployment, first review the new release, change the app tag deliberately, and create a full backup from Step 12. Check the currently configured tag: ```bash grep 'invoiceninja/invoiceninja-debian' /opt/invoice-ninja/compose.yaml ``` When moving from `5.13.37` to a reviewed newer release, edit the exact image tag, then run: ```bash cd /opt/invoice-ninja sudo docker compose pull app sudo docker compose up -d app nginx caddy ``` The current Debian image entrypoint runs production migrations and cache/design update steps during startup. That is convenient, but it also means a database migration may happen when a new image starts. Do not assume that changing the image tag back is a complete rollback after a migration; keep the pre-update database/files backup until the new version is fully verified. After the update, check: ```bash sudo docker compose ps sudo docker inspect --format '{{.State.Health.Status}}' invoice-ninja-app sudo docker compose exec app supervisorctl status sudo docker compose logs --tail=200 app ``` Run the final host exposure audit: ```bash sudo docker ps --format 'table {{.Names}}\t{{.Ports}}' sudo ss -tulpn sudo ufw status numbered ``` Confirm all of the following: - Invoice Ninja uses the reviewed Debian image version; - only Caddy publishes public TCP 80/443; - Nginx, PHP-FPM, MySQL, and Redis remain private; - `APP_ENV=production`, `APP_DEBUG=false`, and `REQUIRE_HTTPS=true`; - bootstrap admin variables are removed; - the app health check reports `healthy`; - two queue workers are running; - the Laravel scheduler is running; - PDFs render with Snappdf; - SMTP is either intentionally disabled or tested; - a complete database/files/configuration backup exists off-server; - restore testing has been completed; - updates are backed up before the new image starts and runs migrations. **Verify:** There should be no unintended public database/cache/application listener, no leftover bootstrap password, no stopped scheduler/queue process, no untested PDF path, and no update plan that relies only on changing Docker tags for rollback. ## Troubleshooting ### The app container never becomes healthy Inspect the app and database logs: ```bash cd /opt/invoice-ninja sudo docker compose logs --tail=200 app sudo docker compose logs --tail=200 mysql sudo docker compose ps ``` The Debian image health check expects the internal `/health` route to return the Invoice Ninja API health response through PHP-FPM. ### Recurring invoices or reminders do not run Check the scheduler and queue workers first: ```bash sudo docker compose exec app supervisorctl status ``` The current Debian image should show two queue workers plus a scheduler. Do not add another host cron before confirming the built-in scheduler has actually failed. ### Invoice Ninja shows a 502 error Check the proxy/application chain: ```bash sudo docker compose ps sudo docker compose logs --tail=200 caddy sudo docker compose logs --tail=200 nginx sudo docker compose logs --tail=200 app ``` The expected path is Caddy → private Nginx → app PHP-FPM on port 9000. ### MySQL is unhealthy after changing `.env` Changing the password in `.env` does not automatically change the password stored inside an existing MySQL data volume. Rotate the MySQL account credential and `.env` together as one controlled operation. Do not delete the MySQL volume to fix a password mismatch unless you intentionally want to erase the database. ### PDF generation fails The current Debian image includes Chrome on amd64 and Chromium on arm64 and sets the Snappdf browser path automatically at container startup. Check app logs first: ```bash sudo docker compose logs --tail=200 app ``` Also verify `PDF_GENERATOR=snappdf` and that the application URL is reachable from the container. ### The app fails after an image update Stop the new application container and use the pre-update recovery set. Because the production entrypoint can run database migrations automatically, do not assume that simply restoring the old image tag is enough. Restore the pre-update database and matching app-data files when required. ## Conclusion You now have a current Invoice Ninja self-hosting pattern for Ubuntu 24.04 using the official Debian-based **5.13.37** image, MySQL, Redis, Nginx, Caddy HTTPS, built-in queue workers and scheduler, persistent application data, verified health checks, matched backups, restore testing, and a controlled update process. The major 2026 corrections are operational rather than cosmetic: avoid the deprecated older Docker image, avoid a mutable `latest` tag for production, understand that the Debian image already supervises queues and scheduling, and treat every image update as a potential database migration event that requires a proven pre-update recovery point. For adjacent procedures, continue with [Install Docker on Ubuntu 24.04](/learn/tutorials/install-docker-ubuntu-24-04), [Set Up UFW Firewall](/learn/tutorials/set-up-ufw-firewall-ubuntu-24-04), and [Harden Ubuntu 24.04](/learn/tutorials/secure-ubuntu-24-04-server). ## Sources - [Invoice Ninja — Self Host Installation](https://invoiceninja.github.io/docs/self-host/self-host-installation) - [Invoice Ninja — Environment Variables](https://invoiceninja.github.io/docs/self-host/env-variables) - [Invoice Ninja — Self Host Updating](https://invoiceninja.github.io/docs/self-host/self-host-updating) - [Invoice Ninja — Self Host Troubleshooting](https://invoiceninja.github.io/docs/self-host/self-host-troubleshooting) - [Invoice Ninja official Debian Docker files](https://github.com/invoiceninja/dockerfiles/tree/debian/debian) - [Invoice Ninja Debian Docker image](https://hub.docker.com/r/invoiceninja/invoiceninja-debian) - Version and Docker process model re-verified: 2026-09-05 --- ### How to Set Up WireGuard VPN on Ubuntu 24.04 for Private Access URL: https://rafftechnologies.com/learn/tutorials/set-up-wireguard-vpn-ubuntu-24-04 Description: Set up WireGuard on Ubuntu 24.04 for private split-tunnel access. Configure keys, AllowedIPs, UFW, keepalive, private SSH, peers, and verification. WireGuard can give a laptop or workstation a private route to an Ubuntu 24.04 server without turning that server into a full-tunnel internet gateway. In this tutorial, you will install WireGuard, create a `10.66.66.0/24` tunnel, add one client peer, keep normal client internet traffic outside the VPN, protect the UDP listener, verify the route and handshake, and test private SSH access before changing any public administration path. Raff Technologies is the VM platform used by the saved test environment. The existing test note remains `Ubuntu 24.04 LTS on Raff 1 vCPU / 2 GB RAM VM; Linux client for tunnel verification`. This revision updates the operational guidance against current Ubuntu Server and WireGuard documentation without claiming a new end-to-end test. This is a **split-tunnel** design. The client uses `AllowedIPs = 10.66.66.0/24`, so only traffic for the WireGuard subnet enters the tunnel. There is no IPv4 forwarding, NAT, or masquerading because the goal is private access to services on the WireGuard server itself. If you want all internet traffic to exit through the VM, use the separate full-tunnel tutorial. WireGuard's `AllowedIPs` setting is especially important: on transmit it selects which peer should receive traffic for a destination; on receive it also restricts which source addresses that peer is allowed to use. Ubuntu's current WireGuard documentation describes those routing and access-control roles explicitly. Prerequisites: - Ubuntu 24.04 with SSH and sudo access - A public IPv4 address or reachable DNS name for the WireGuard endpoint - A client with WireGuard support - UDP port `51820` reachable through the firewall protecting the VM - A VPN subnet that does not overlap the client or server networks ## Step 1 — Verify Ubuntu and choose a non-overlapping VPN subnet Confirm the server release and current routes: ```bash cat /etc/os-release ip -4 addr ip -4 route ``` This tutorial uses: ```text WireGuard interface: wg0 VPN subnet: 10.66.66.0/24 Server VPN address: 10.66.66.1/24 Client VPN address: 10.66.66.2/32 UDP listener: 51820 ``` Check whether the proposed subnet already appears in the server routing table: ```bash ip -4 route | grep '10\.66\.66\.0/24' || true ``` Run an equivalent route check on the client. If either side already uses `10.66.66.0/24`, choose a different RFC1918 subnet and use it consistently throughout the configuration. **Verify:** Ubuntu should report 24.04, the public endpoint should be known, and `10.66.66.0/24` should not conflict with an existing route on either peer. ## Step 2 — Install WireGuard from Ubuntu's package repository Install WireGuard: ```bash sudo apt update sudo apt install -y wireguard ``` The official WireGuard installation page uses `sudo apt install wireguard` for Ubuntu, and the standard Ubuntu kernel includes WireGuard support. Verify the userspace tools: ```bash wg --version wg-quick --help 2>&1 | head ``` Load the kernel module explicitly as a diagnostic check: ```bash sudo modprobe wireguard lsmod | grep '^wireguard' || true ``` A missing `lsmod` line after normal use is not by itself proof of failure on every kernel configuration; the functional checks later in the tutorial are what matter. **Verify:** `wg --version` and `wg-quick` should run successfully without installing a third-party VPN package or repository. ## Step 3 — Generate the server key pair without exposing the private key Create the WireGuard directory and a root-only server key: ```bash sudo install -d -m 700 /etc/wireguard sudo sh -c 'umask 077; wg genkey > /etc/wireguard/wg0.key' sudo sh -c 'wg pubkey < /etc/wireguard/wg0.key > /etc/wireguard/wg0.pub' ``` Set explicit permissions: ```bash sudo chown root:root /etc/wireguard/wg0.key /etc/wireguard/wg0.pub sudo chmod 600 /etc/wireguard/wg0.key sudo chmod 644 /etc/wireguard/wg0.pub ``` Display only the public key: ```bash sudo cat /etc/wireguard/wg0.pub ``` WireGuard's official quick start recommends creating private keys under a restrictive umask. Ubuntu's security guidance also recommends keeping private keys out of configuration text that might later be shared for troubleshooting. **Verify:** `/etc/wireguard/wg0.key` should be mode `600`; the public key may be displayed or copied, but the private key should never be printed, pasted into tickets, or committed to source control. ## Step 4 — Create the server configuration for private-only access Create `/etc/wireguard/wg0.conf` without embedding the server private key: ```bash sudo tee /etc/wireguard/wg0.conf >/dev/null <<'EOF' [Interface] Address = 10.66.66.1/24 ListenPort = 51820 PostUp = wg set %i private-key /etc/wireguard/%i.key SaveConfig = false EOF sudo chown root:root /etc/wireguard/wg0.conf sudo chmod 600 /etc/wireguard/wg0.conf ``` This server does **not** need: ```text net.ipv4.ip_forward = 1 MASQUERADE / NAT rules AllowedIPs = 0.0.0.0/0 ``` Those belong to routed or full-tunnel designs. Here, the client only needs to reach `10.66.66.1` and any service intentionally listening on that server address. Inspect only the non-secret configuration: ```bash sudo cat /etc/wireguard/wg0.conf ``` Because the private key is loaded from `/etc/wireguard/wg0.key`, this output does not expose it. **Verify:** The interface should use `10.66.66.1/24`, listen on UDP `51820`, load its private key from the protected key file, and contain no forwarding or NAT rule. ## Step 5 — Allow the WireGuard UDP listener without risking SSH lockout Check UFW state first: ```bash sudo ufw status numbered ``` If UFW is already active, allow WireGuard: ```bash sudo ufw allow 51820/udp comment 'WireGuard VPN' sudo ufw status numbered ``` If UFW is inactive, do **not** blindly enable it from a single remote SSH session. First follow the lockout-safe process in [Set Up UFW Firewall on Ubuntu 24.04](/learn/tutorials/set-up-ufw-firewall-ubuntu-24-04), verify your real SSH port is allowed, and keep a second SSH session open while testing. If another firewall protects the VM outside Ubuntu, allow UDP `51820` there as well. WireGuard does not use TCP `51820` in this configuration. **Verify:** UDP `51820` should be reachable through every firewall layer that protects the VM, while the existing SSH administration path should remain working. ## Step 6 — Generate the client key pair on the client device Generate client private keys on the client whenever possible so the private key never has to travel through the server. On an Ubuntu or Debian client: ```bash sudo apt update sudo apt install -y wireguard ``` Create a protected directory and client keys: ```bash mkdir -p ~/.config/wireguard-raff chmod 700 ~/.config/wireguard-raff umask 077 wg genkey > ~/.config/wireguard-raff/client.key wg pubkey < ~/.config/wireguard-raff/client.key \ > ~/.config/wireguard-raff/client.pub ``` Display only the client public key: ```bash cat ~/.config/wireguard-raff/client.pub ``` Check the private-key permissions: ```bash stat -c '%a %n' ~/.config/wireguard-raff/client.key ``` Windows, macOS, iOS, and Android users can generate the peer keys in the official WireGuard application and use the same tunnel addresses shown in this guide. **Verify:** The client private key should remain on the client with restrictive permissions; only the client public key should be copied to the server. ## Step 7 — Add the client peer and understand `AllowedIPs` On the server, paste the **client public key** into a temporary shell variable: ```bash CLIENT_PUBLIC_KEY='PASTE_CLIENT_PUBLIC_KEY_HERE' ``` Append the peer: ```bash sudo tee -a /etc/wireguard/wg0.conf >/dev/null </dev/null < "backups/manual/roles-${STAMP}.sql.gz" docker compose exec -T db \ pg_dump -U postgres -d postgres -Fc \ > "backups/manual/postgres-${STAMP}.dump" ``` If Storage is in use, coordinate a maintenance window or otherwise stop application writes while the database dump and Storage copy are taken so that database metadata and object files do not drift apart. Archive the self-hosted Storage data directory used by the official Docker bundle: ```bash tar -czf "backups/manual/storage-${STAMP}.tar.gz" \ volumes/storage ``` Archive the sensitive configuration and recorded release: ```bash tar -czf "backups/manual/config-${STAMP}.tar.gz" \ .env .supabase-version docker-compose.yml run.sh update.sh volumes/proxy 2>/dev/null || \ tar -czf "backups/manual/config-${STAMP}.tar.gz" \ .env .supabase-version docker-compose.yml run.sh volumes/proxy chmod 600 backups/manual/* ``` Validate the artifacts: ```bash gzip -t "backups/manual/roles-${STAMP}.sql.gz" pg_restore -l "backups/manual/postgres-${STAMP}.dump" | head tar -tzf "backups/manual/storage-${STAMP}.tar.gz" | head tar -tzf "backups/manual/config-${STAMP}.tar.gz" | head ``` Copy the complete recovery set off the VM. [Raff Object Storage](/products/object-storage) can be an off-server target for S3-compatible backup tooling, while [Data Protection](/products/data-protection) can provide an additional VM-level recovery layer. :::cta Protect Your Supabase Server Run Supabase on an Ubuntu VM and keep Postgres, Storage objects, configuration, and signing material in a separate recovery workflow. ::: **Verify:** Roles, database, Storage, and configuration archives should all be readable, protected, and copied to a separate failure domain. ## Step 12 — Rehearse a restore on an isolated test VM Do not prove backups by overwriting production. Use a disposable VM or isolated recovery project. Start from the **same self-hosted release** recorded in the backup's `.supabase-version`. Restore the configuration bundle, then keep application services stopped while you prepare the database. A same-version recovery pattern is: ```bash cd supabase-project docker compose up -d db ``` Restore roles: ```bash gunzip -c /backup/roles-YYYYMMDD-HHMMSS.sql.gz \ | docker compose exec -T db psql -U postgres -d postgres ``` Restore the custom-format database dump into the disposable database service: ```bash docker compose exec -T db \ pg_restore -U postgres -d postgres --clean --if-exists \ < /backup/postgres-YYYYMMDD-HHMMSS.dump ``` Restore the matching Storage archive into the recovery project before starting Storage/API services: ```bash tar -xzf /backup/storage-YYYYMMDD-HHMMSS.tar.gz -C . ``` Then start the stack: ```bash sh run.sh start ``` Validate Studio login, representative database rows, Auth users relevant to the test, and several Storage objects. Keep SMTP, OAuth callbacks, webhooks, and other external integrations disabled or redirected in a recovery rehearsal so the test copy cannot trigger production side effects. A logical database restore can be sensitive to major-version or self-hosted service differences. That is why the first recovery test should use the exact recorded self-hosted snapshot and why upgrades need a fresh backup after successful verification. **Verify:** The isolated instance should boot on the intended self-hosted release, Studio should work, representative data and Storage objects should be present, and no production integration should be triggered from the test environment. ## Step 13 — Update Supabase with the supported version-tracked workflow Check the installed base version: ```bash cd supabase-project cat .supabase-version ``` Create the full recovery set from Step 11 before applying an update. Preview the current update first: ```bash sh update.sh --dry-run ``` The dry run is most useful when `.supabase-version` records the deployment's real base version. Review breaking-change notices, new `.env` keys, and any merge conflicts. Apply the configuration update: ```bash sh update.sh ``` Then pull the tested image set and recreate the containers: ```bash sh run.sh pull sh run.sh recreate ``` Check the new recorded version and service health: ```bash cat .supabase-version docker compose ps ``` Do not assume `update.sh` protects application data: Supabase explicitly separates configuration backup from Postgres and Storage backup responsibilities. **Verify:** The update should complete without unresolved merge conflicts, `.supabase-version` should advance to the intended release, and every required service should return to healthy state. ## Step 14 — Run the final security, recovery, and exposure audit Check service health and the recorded release: ```bash cd supabase-project cat .supabase-version docker compose ps ``` Check public HTTPS: ```bash curl -I https://supabase.example.com/auth/v1/ curl -I https://supabase.example.com/rest/v1/ ``` Inspect host listeners and firewall rules: ```bash sudo ss -tulpn sudo ufw status numbered ``` Confirm all of the following: - Ubuntu meets the resources required by the services you enabled; - the deployment has a non-empty `.supabase-version`; - the self-hosted services are running as one reviewed snapshot rather than arbitrary image versions; - `.env` is mode 600 and protected off-server; - dashboard credentials are non-default; - secret/server-side and service-role keys are not present in frontend code; - HTTPS terminates at the intended reverse proxy; - Realtime traffic can pass through the proxy's WebSocket support; - internal database and API-gateway ports are not unintentionally public; - Postgres and Storage data are backed up separately from the configuration backup created by `update.sh`; - the recovery set includes `.env`, signing material, version metadata, database roles, database contents, and Storage objects; - at least one restore has been rehearsed on an isolated instance; - a new full backup exists after any successful upgrade. **Verify:** There should be no unhealthy service, default credential, exposed secret, accidental public database listener, missing Storage backup, or untested recovery path. ## Troubleshooting ### One or more containers never become healthy Run the bundled diagnostics: ```bash cd supabase-project sh tests/test-container-logs.sh sh run.sh logs storage ``` Also confirm the server still meets the documented CPU, RAM, and disk minimum. ### HTTPS returns certificate or proxy errors Check DNS and Caddy: ```bash dig +short A supabase.example.com docker logs supabase-caddy --tail=200 sudo ss -lntp | grep -E ':(80|443)\b' ``` The domain must resolve to the server and public 80/443 must reach the reverse proxy. ### OAuth redirects use the wrong URL Review the URL roles in `.env`: ```text SUPABASE_PUBLIC_URL=https://supabase.example.com API_EXTERNAL_URL=https://supabase.example.com/auth/v1 SITE_URL=https://app.example.com ``` `SITE_URL` is the application users return to, not automatically the Supabase host. ### Studio works but frontend requests fail Review the generated credentials: ```bash sh run.sh secrets ``` Use a publishable/anon client credential where appropriate and keep secret/service-role credentials on trusted backend systems only. Also check browser/network responses through the public HTTPS gateway rather than testing an internal container URL. ### `update.sh --dry-run` cannot show a meaningful diff Check `.supabase-version`: ```bash cat .supabase-version ``` Supabase documents that update merging needs a recorded base version. Older untracked installations require you to establish the correct base before a full three-way update preview can work safely. ### An update succeeded but data is missing Do not rely on `update.sh` configuration backups as a database recovery mechanism. Restore from the independent Postgres and Storage recovery set created before the update, on an isolated instance first if possible. ### A restore starts but Storage objects are missing The Postgres dump contains Storage metadata but not the object files themselves. Restore the matching `volumes/storage` archive as well as the database and configuration recovery set. ## Conclusion You now have a current Supabase self-hosting workflow for Ubuntu 24.04 using Supabase's version-tracked Docker Compose bundle, generated credentials, Caddy HTTPS, health checks, private database exposure, a real database/API verification, independent Postgres and Storage backups, isolated restore testing, and the supported `update.sh` upgrade path. The most important operational rule is to keep the deployment as a coordinated self-hosted snapshot and to separate **configuration updates** from **data protection**. `.supabase-version` tells the updater what configuration you started from; it does not replace database, Storage, secret, or recovery backups. For adjacent procedures, continue with [Install Docker on Ubuntu 24.04](/learn/tutorials/install-docker-ubuntu-24-04), [Set Up UFW Firewall](/learn/tutorials/set-up-ufw-firewall-ubuntu-24-04), and [Harden Ubuntu 24.04](/learn/tutorials/secure-ubuntu-24-04-server). ## Sources - [Supabase — Self-Hosting with Docker](https://supabase.com/docs/guides/self-hosting/docker) - [Supabase — Configure Reverse Proxy and HTTPS](https://supabase.com/docs/guides/self-hosting/self-hosted-proxy-https) - [Supabase — Update Your Self-Hosted Deployment](https://supabase.com/docs/guides/self-hosting/updating) - [Supabase — Accessing Postgres](https://supabase.com/docs/guides/self-hosting/accessing-postgres) - [Supabase — Self-Hosting](https://supabase.com/docs/guides/self-hosting) - Guidance re-verified: 2026-09-06 --- ### How to Install WireGuard on Ubuntu 24.04 as a Full-Tunnel VPN URL: https://rafftechnologies.com/learn/tutorials/install-wireguard-vpn-ubuntu-24-04 Description: Install WireGuard on Ubuntu 24.04 as a full-tunnel VPN. Configure IPv4 forwarding, NAT, DNS, UFW, AllowedIPs 0.0.0.0/0, and verify public egress. A WireGuard full tunnel routes a client’s IPv4 internet traffic through the VPN server instead of sending only private-network traffic through the tunnel. In this tutorial, you will install WireGuard on Ubuntu 24.04, configure a Raff Technologies Linux VM as the internet gateway, enable forwarding and masquerading, route the client with `AllowedIPs = 0.0.0.0/0`, configure DNS for the tunnel, and verify the public egress path end to end. [Raff Linux VMs](/products/linux-vm) provide the public IPv4 address, Ubuntu environment, and root-level networking control needed for this pattern. The saved test environment for this tutorial remains a Raff Ubuntu 24.04 VM with 1 vCPU and 2 GB RAM. The original full-tunnel workflow was tested there; the routing, DNS, firewall, and key-handling guidance was re-verified against current Ubuntu Server and WireGuard documentation on September 6, 2026 without claiming a new machine test. Ubuntu’s current WireGuard default-gateway documentation describes the same core design used here: the client sends `0.0.0.0/0` through WireGuard, while the gateway server enables IPv4 forwarding and masquerades the VPN subnet onto its public interface. > **IPv4 scope:** This tutorial creates an IPv4 full tunnel. `AllowedIPs = 0.0.0.0/0` does not cover IPv6. If the client has working IPv6, configure an IPv6 WireGuard path separately or disable that path before claiming all network traffic is tunneled. ### Full tunnel vs private-access WireGuard | Design | Client `AllowedIPs` | Server forwarding/NAT | Result | |---|---|---|---| | Full tunnel — this tutorial | `0.0.0.0/0` | Required | Client IPv4 internet traffic exits through the VPN server | | Private/split tunnel | VPN/private subnet only | Not required when accessing only the WireGuard server | Normal internet traffic stays on the client’s local connection | If you only need private SSH or service access, use [Set Up WireGuard on Ubuntu 24.04 for Private Access](/learn/tutorials/set-up-wireguard-vpn-ubuntu-24-04) instead. Keeping the two designs separate avoids adding forwarding and NAT when they are not needed. Prerequisites: - An Ubuntu 24.04 server with a public IPv4 address - SSH and sudo access with a working recovery path - A Linux, macOS, Windows, Android, or iOS WireGuard client - UDP port `51820` reachable through the firewall protecting the VM - A VPN subnet that does not overlap the client or server networks - A DNS resolver you want the client to use while the tunnel is active This tutorial uses: | Item | Value | |---|---| | Server WireGuard interface | `wg0` | | VPN subnet | `10.90.90.0/24` | | Server tunnel IP | `10.90.90.1/24` | | First client tunnel IP | `10.90.90.2/32` | | WireGuard listener | `51820/udp` | | Example DNS resolver | `1.1.1.1` | ## Step 1 — Verify Ubuntu, the public interface, and the VPN subnet Confirm the operating system and current IPv4 routes: ```bash cat /etc/os-release ip -4 addr ip -4 route ``` Find the interface Ubuntu uses for its default IPv4 route: ```bash OUT_IFACE="$(ip route show default | awk '/default/ {print $5; exit}')" printf 'Outbound interface: %s\n' "$OUT_IFACE" ``` Typical public-interface names include `eth0`, `ens3`, and similar names. Do not hardcode `eth0` before checking the real VM. Verify that the proposed WireGuard subnet does not already exist on the server: ```bash ip -4 route | grep '10\.90\.90\.0/24' || true ``` Run an equivalent route check on the client. If either side already uses `10.90.90.0/24`, choose another RFC1918 subnet and replace it consistently throughout the tutorial. **Verify:** Ubuntu should report 24.04, `OUT_IFACE` should resolve to the real public/default-route interface, and the proposed VPN subnet should not overlap an existing route. ## Step 2 — Install WireGuard on Ubuntu 24.04 Install WireGuard and the utilities used for the gateway rules, firewall check, and verification: ```bash sudo apt update sudo apt install -y wireguard iptables ufw curl ``` Verify the userspace tools: ```bash wg --version wg-quick --help 2>&1 | head ``` Load the kernel module as a diagnostic check: ```bash sudo modprobe wireguard lsmod | grep '^wireguard' || true ``` Ubuntu’s standard kernel includes WireGuard support, while the `wireguard` package provides tools such as `wg` and `wg-quick`. **Verify:** `wg --version` and `wg-quick` should run successfully before you create keys or interfaces. ## Step 3 — Generate the server key pair without embedding the private key in the config Create the WireGuard directory and generate a protected private key: ```bash sudo install -d -m 700 /etc/wireguard sudo sh -c 'umask 077; wg genkey > /etc/wireguard/wg0.key' sudo sh -c 'wg pubkey < /etc/wireguard/wg0.key > /etc/wireguard/wg0.pub' ``` Set explicit ownership and permissions: ```bash sudo chown root:root /etc/wireguard/wg0.key /etc/wireguard/wg0.pub sudo chmod 600 /etc/wireguard/wg0.key sudo chmod 644 /etc/wireguard/wg0.pub ``` Display only the public key: ```bash sudo cat /etc/wireguard/wg0.pub ``` Check file permissions without exposing the secret: ```bash sudo stat -c '%a %U:%G %n' \ /etc/wireguard/wg0.key \ /etc/wireguard/wg0.pub ``` The private key remains in `/etc/wireguard/wg0.key`. The server configuration will load it at interface startup rather than storing the private key directly inside text you may later inspect while troubleshooting. **Verify:** `/etc/wireguard/wg0.key` should be owned by root and mode `600`. Never paste or screenshot that private key. ## Step 4 — Enable IPv4 forwarding on the VPN gateway A full-tunnel server must forward packets from the WireGuard interface to the public network interface. Create a dedicated sysctl file: ```bash sudo tee /etc/sysctl.d/70-wireguard-routing.conf > /dev/null <<'EOF' net.ipv4.ip_forward = 1 EOF ``` Apply it immediately: ```bash sudo sysctl -p /etc/sysctl.d/70-wireguard-routing.conf ``` Verify the runtime value: ```bash sysctl net.ipv4.ip_forward ``` Expected output: ```text net.ipv4.ip_forward = 1 ``` Forwarding only allows the server to route packets. The next step adds the source-NAT rule required for the client’s private `10.90.90.0/24` address to reach the public internet through the server. **Verify:** `net.ipv4.ip_forward` must equal `1` before the server can act as an IPv4 gateway. ## Step 5 — Configure the WireGuard server with forwarding and scoped masquerading Detect the public interface again: ```bash OUT_IFACE="$(ip route show default | awk '/default/ {print $5; exit}')" printf '%s\n' "$OUT_IFACE" ``` Create `/etc/wireguard/wg0.conf`: ```bash sudo tee /etc/wireguard/wg0.conf > /dev/null < /etc/wireguard/wg0.key' sudo sh -c 'wg pubkey < /etc/wireguard/wg0.key > /etc/wireguard/wg0.pub' sudo chmod 600 /etc/wireguard/wg0.key sudo chmod 644 /etc/wireguard/wg0.pub ``` Display only the client public key: ```bash sudo cat /etc/wireguard/wg0.pub ``` Windows, macOS, Android, and iOS users can generate the peer keys in the official WireGuard application and use the same addresses and peer values shown below. **Verify:** Only the client public key should be copied to the server. The client private key remains protected on the client device. ## Step 8 — Add the client peer to the server On the server, paste the **client public key** into a temporary shell variable: ```bash CLIENT_PUBLIC_KEY='PASTE_CLIENT_PUBLIC_KEY_HERE' ``` Append the peer block: ```bash sudo tee -a /etc/wireguard/wg0.conf > /dev/null < /dev/null <<'EOF' [Interface] Address = 10.90.90.2/24 PostUp = wg set %i private-key /etc/wireguard/%i.key PostUp = resolvectl dns %i 1.1.1.1; resolvectl domain %i '~.' PostDown = resolvectl revert %i [Peer] PublicKey = SERVER_PUBLIC_KEY Endpoint = SERVER_PUBLIC_IP:51820 AllowedIPs = 0.0.0.0/0 PersistentKeepalive = 25 EOF sudo chmod 600 /etc/wireguard/wg0.conf ``` Replace both placeholders before continuing. `AllowedIPs = 0.0.0.0/0` tells `wg-quick` to send all IPv4 destinations through this peer. On Linux, `wg-quick` implements the default-route behavior with policy routing so the WireGuard endpoint itself remains reachable outside the tunnel. The `resolvectl` commands make `1.1.1.1` the DNS resolver for the WireGuard link and set `~.` so DNS queries prefer that link while the full tunnel is active. Replace `1.1.1.1` with another resolver if your policy requires one. `PersistentKeepalive = 25` is useful when the client sits behind NAT or a stateful firewall and needs to keep its mapping alive. WireGuard documents 25 seconds as a sensible interval for that case; omit it when you do not need persistent reachability. On Windows, macOS, Android, or iOS, use the official WireGuard application and set the peer to `AllowedIPs = 0.0.0.0/0`. Use the application’s DNS field for your selected resolver instead of the Linux `resolvectl` lines. **Verify:** The client configuration should have `10.90.90.2/24`, the real server endpoint, `0.0.0.0/0`, and a deliberate DNS path for the full tunnel. ## Step 11 — Bring up the client and verify the full-tunnel route Start the Linux client interface: ```bash sudo wg-quick up wg0 ``` Inspect its address and peer state: ```bash ip -brief addr show wg0 sudo wg show wg0 ``` Inspect the policy-routing rules that `wg-quick` created: ```bash ip rule list ip route list table 51820 2>/dev/null || true ``` A typical full-tunnel setup shows a dedicated policy-routing table containing a default route through `wg0`. If table `51820` is already in use on the client, `wg-quick` can choose another table number; the `ip rule` output reveals the active policy. Inspect DNS routing on the WireGuard link: ```bash resolvectl status wg0 ``` Expected state includes the configured resolver and a route-only domain of `~.`. **Verify:** `wg0` should be up with `10.90.90.2/24`; WireGuard policy routing should contain the IPv4 default route; and DNS should be assigned to the WireGuard link. ## Step 12 — Verify the full-tunnel VPN end to end From the client, reach the server’s tunnel address: ```bash ping -c 4 10.90.90.1 ``` Check the client’s public IPv4 address: ```bash curl -4s https://icanhazip.com ``` The result should match the VPN server’s public IPv4 address. Inspect the WireGuard handshake and transfer counters on the client: ```bash sudo wg show wg0 ``` On the server, inspect the peer as well: ```bash sudo wg show wg0 ``` A working peer should report a recent handshake and increasing transfer counters. Verify DNS still resolves while the tunnel is active: ```bash resolvectl query example.com getent hosts example.com ``` If the client has IPv6 connectivity, test that path separately: ```bash curl -6 --connect-timeout 5 https://icanhazip.com \ || echo 'No working IPv6 path' ``` If the IPv6 request succeeds, that traffic is outside this IPv4-only tunnel. Do not describe the setup as an all-protocol tunnel until IPv6 is handled explicitly. :::cta Deploy Your Server Deploy an Ubuntu 24.04 VM as the public endpoint for a WireGuard full-tunnel VPN. ::: **Verify:** The tunnel address should respond, the client public IPv4 should match the server, both peers should show a recent handshake, traffic counters should increase, and DNS should resolve through the configured tunnel DNS path. ## Step 13 — Verify reboot persistence The server interface is already enabled through `wg-quick@wg0`. During a safe maintenance window, reboot the server: ```bash sudo reboot ``` After reconnecting, verify: ```bash systemctl is-active wg-quick@wg0 ip -brief addr show wg0 sudo wg show wg0 sudo iptables -t nat -S POSTROUTING | grep '10.90.90.0/24' ``` Reconnect the client if needed: ```bash sudo wg-quick down wg0 2>/dev/null || true sudo wg-quick up wg0 ``` Repeat the egress check: ```bash curl -4s https://icanhazip.com ``` **Verify:** The server should recreate the WireGuard interface and NAT rule after reboot, and the client should again exit through the server’s public IPv4 address. ## Step 14 — Add or revoke client peers safely Give every client a unique key pair and a unique `/32` tunnel address, for example: ```text 10.90.90.2/32 laptop 10.90.90.3/32 phone 10.90.90.4/32 workstation ``` Add each public key as a separate `[Peer]` block in `/etc/wireguard/wg0.conf`. After saving a peer-only change, apply the saved WireGuard settings without dropping the interface: ```bash sudo bash -c 'wg syncconf wg0 <(wg-quick strip wg0)' sudo wg show wg0 ``` `wg syncconf` updates the runtime WireGuard configuration while preserving peer sessions as much as possible. If you changed interface-level settings such as addresses, routing hooks, or NAT commands rather than only peer data, use a controlled `wg-quick` restart during a maintenance window instead. To revoke a device, remove its peer block from the saved configuration and run the same `wg syncconf` command. Rotate a peer immediately if its private key may have been exposed. Do not reuse client private keys across devices. **Verify:** Every active device should have one unique public key and one unique tunnel address; revoked peers should disappear from `wg show wg0` after the sync. ## Cleanup and rollback Disconnect the Linux client: ```bash sudo wg-quick down wg0 ``` To stop the server tunnel without deleting its configuration: ```bash sudo systemctl disable --now wg-quick@wg0 ``` Confirm the interface and NAT rule are gone: ```bash ip link show wg0 2>/dev/null || echo 'wg0 is down' sudo iptables -t nat -S POSTROUTING | grep '10.90.90.0/24' \ || echo 'WireGuard NAT rule removed' ``` If the VM no longer needs to accept WireGuard connections, remove the matching UFW rule by rule number or exact rule only after confirming no client still depends on it. Keep `/etc/wireguard/wg0.key` if you intend to restore the same server identity. Securely destroy private keys only when the peer is permanently decommissioned. ## Troubleshooting ### No WireGuard handshake appears On the server, check the listener, firewall, and saved peer: ```bash sudo systemctl status wg-quick@wg0 --no-pager sudo wg show wg0 sudo ss -lun | grep ':51820' sudo ufw status numbered ``` On the client, verify that `Endpoint` uses the current server public IP/DNS name and UDP port `51820`. Confirm the client public key on the server and server public key on the client are not swapped or stale. ### The handshake works but internet access fails Check forwarding, the public interface, and NAT: ```bash sysctl net.ipv4.ip_forward OUT_IFACE="$(ip route show default | awk '/default/ {print $5; exit}')" printf 'Outbound interface: %s\n' "$OUT_IFACE" sudo iptables -S FORWARD | grep '10.90.90.0/24' sudo iptables -t nat -S POSTROUTING | grep '10.90.90.0/24' ``` Expected state includes `net.ipv4.ip_forward = 1`, the correct public interface, matching forwarding rules, and a scoped MASQUERADE rule. ### The client connects but DNS fails First verify raw IP connectivity: ```bash ping -c 2 1.1.1.1 ``` Then inspect the WireGuard DNS link: ```bash systemctl is-active systemd-resolved resolvectl status wg0 resolvectl query example.com ``` If raw IP works while DNS fails, the WireGuard tunnel and NAT path are functioning and the remaining problem is DNS configuration. ### The client still uses a local DNS resolver Inspect: ```bash resolvectl status ``` For the Linux configuration in this tutorial, the `wg0` link should have your selected resolver and route-only domain `~.`. Ubuntu’s current default-gateway documentation treats DNS routing as a separate part of preventing information from escaping the intended full-tunnel path. ### The client loses access to its local LAN That is a normal consequence of a full-tunnel default route. If the client must continue reaching a local printer, NAS, router, or private subnet, create deliberate route exceptions or use the [private-access WireGuard tutorial](/learn/tutorials/set-up-wireguard-vpn-ubuntu-24-04) instead. ### Some websites load slowly or not at all Check the tunnel handshake and try a path-MTU test before changing MTU blindly: ```bash sudo wg show wg0 ping -M do -s 1372 -c 3 1.1.1.1 ``` If large packets fail while smaller packets work, investigate the path MTU between the client and gateway. Set an explicit WireGuard `MTU` only after measuring a value that works for the actual network. ### `wg-quick up wg0` says the interface already exists Inspect it before deleting anything: ```bash ip link show wg0 sudo wg show wg0 ``` If it is the intended interface, bring it down cleanly and retry: ```bash sudo wg-quick down wg0 sudo wg-quick up wg0 ``` ### IPv4 is tunneled but IPv6 still exposes the client network This tutorial routes only `0.0.0.0/0`. Test IPv6 independently: ```bash curl -6 --connect-timeout 5 https://icanhazip.com ``` If it succeeds, either configure an IPv6 tunnel and gateway path or disable IPv6 on the client/network according to your policy. Do not add `::/0` until the server has the IPv6 addressing, forwarding, firewall, and routing needed to carry that traffic correctly. ## Conclusion You now have a WireGuard full-tunnel VPN on Ubuntu 24.04: the client uses `AllowedIPs = 0.0.0.0/0`, `wg-quick` installs the Linux policy-routing rules, the server forwards and masquerades the VPN subnet, and DNS is deliberately routed with the tunnel rather than left as an afterthought. This page should be used when the VM is meant to become the client’s IPv4 internet gateway. For private-only administration or service access, use [Set Up WireGuard on Ubuntu 24.04 for Private Access](/learn/tutorials/set-up-wireguard-vpn-ubuntu-24-04). For broader cloud-to-cloud or network-to-network designs, review [Raff VPC](/products/vpc). ## Sources - [Ubuntu Server — Using the VPN as the default gateway](https://ubuntu.com/server/docs/how-to/wireguard-vpn/vpn-as-the-default-gateway/) - [Ubuntu Server — Introduction to WireGuard VPN](https://ubuntu.com/server/docs/explanation/intro-to/wireguard-vpn/) - [Ubuntu Server — WireGuard VPN](https://ubuntu.com/server/docs/how-to/wireguard-vpn/) - [WireGuard — Quick Start](https://www.wireguard.com/quickstart/) - [WireGuard — Installation](https://www.wireguard.com/install/) - Guidance re-verified: 2026-09-06 --- ### How to Install Nextcloud on Ubuntu 24.04 URL: https://rafftechnologies.com/learn/tutorials/install-nextcloud-ubuntu-24-04 Description: Install Nextcloud 34 on Ubuntu 24.04 with Apache, MariaDB, PHP 8.3, HTTPS, Redis, cron, backup checks, and secure production guidance. In this tutorial, you will install Nextcloud on Ubuntu 24.04 with Apache, MariaDB, PHP 8.3, HTTPS, cron background jobs, APCu caching, Redis file locking, and an application-consistent backup check. Nextcloud is a self-hosted file sync, sharing, and collaboration platform. This tutorial uses the classic manual installation path on a [Raff Linux VM](/products/linux-vm): Ubuntu 24.04, Apache, MariaDB, PHP 8.3, Redis, and the official Nextcloud server archive. Nextcloud’s current administration manual still documents Ubuntu 24.04 as a supported platform and provides a dedicated Apache/MariaDB installation example for it. As of September 6, 2026, the current stable Nextcloud 34 maintenance release is **34.0.3**. This page intentionally follows the stable 34 branch rather than a prerelease branch. The previous Nextcloud 32 workflow was tested on a Raff Ubuntu 24.04 VM with 2 vCPU, 4 GB RAM, and 80 GB storage. The Nextcloud 34.0.3 installation, caching, cron, backup, and restore guidance in this revision was re-verified against current Nextcloud documentation; a fresh 34.0.3 end-to-end Raff machine test is still required before claiming a new full test pass. Prerequisites: - A Raff Ubuntu 24.04 VM with at least 2 vCPU and 4 GB RAM for this tutorial baseline - SSH access with a sudo-capable user and a recovery path in case firewall changes affect SSH - A domain or subdomain pointed to the VM public IPv4 address - Ports `80/tcp` and `443/tcp` available - A strong Nextcloud admin password and a separate strong MariaDB password stored in a password manager - Enough storage for the files you expect users to sync, plus backup headroom If you plan to keep user data on a separate [Raff Volume](/products/volumes), attach, format, mount, and verify that volume **before** Step 5, then use the mounted path as the Nextcloud data directory. Do not move a live data directory onto another filesystem casually after users have started storing files. ![Raff VM creation screen selecting Ubuntu 24.04 for a Nextcloud server](https://raff-images.s3.raffusercloud.com/nextcloud_ubuntu_24_04_00_raff_vm_ubuntu_selection_webp_e716a57cbc.png) > Replace `cloud.your-domain.com` with your real domain throughout the tutorial. ## Step 1 — Update Ubuntu 24.04 and verify the server Update the package index and installed packages: ```bash sudo apt update sudo apt upgrade -y sudo apt install -y curl wget bzip2 unzip ca-certificates dnsutils ufw snapd rsync ``` Verify the operating system and available resources: ```bash lsb_release -ds nproc free -h lsblk ``` Expected state includes Ubuntu 24.04 LTS, at least 2 vCPU, and about 4 GB RAM for this tutorial baseline. If the upgrade installed a new kernel and `/var/run/reboot-required` exists, reboot before continuing: ```bash if [ -f /var/run/reboot-required ]; then echo "Reboot required before continuing" fi ``` **Verify:** Ubuntu should report 24.04, the expected CPU/RAM/storage should be visible, and no pending reboot should be ignored before you build the application stack. ## Step 2 — Install Apache, MariaDB, PHP 8.3, Redis, and required modules Install the web server, database, PHP runtime, Redis, and the PHP modules used by Nextcloud: ```bash sudo apt install -y apache2 mariadb-server redis-server \ libapache2-mod-php8.3 \ php8.3 php8.3-cli php8.3-common php8.3-mysql php8.3-gd \ php8.3-curl php8.3-mbstring php8.3-intl php8.3-gmp \ php8.3-bcmath php8.3-xml php8.3-zip php8.3-imagick \ php8.3-apcu php8.3-redis ``` Enable and start the services: ```bash sudo systemctl enable --now apache2 sudo systemctl enable --now mariadb sudo systemctl enable --now redis-server ``` Verify service state and PHP modules: ```bash systemctl is-active apache2 systemctl is-active mariadb systemctl is-active redis-server php -v | head -n 1 php -m | grep -Ei 'curl|gd|mbstring|intl|gmp|xml|zip|imagick|apcu|redis|pdo_mysql' ``` Nextcloud 34 supports Ubuntu 24.04 and PHP 8.3. On a single-server installation, APCu is appropriate for local cache while Redis can handle distributed caching and transactional file locking. **Verify:** Apache, MariaDB, and Redis should all be active, PHP should report `8.3.x`, and the required PHP extensions should appear in the module list. ## Step 3 — Configure firewall access without risking SSH lockout Inspect UFW before changing its state: ```bash sudo ufw status verbose ``` If UFW is already active, allow HTTP and HTTPS: ```bash sudo ufw allow 'Apache Full' sudo ufw status numbered ``` If UFW is **inactive**, do not blindly run `ufw enable` from a single remote SSH session. First confirm the real SSH port used by the server, create the matching allow rule, and keep a second SSH session or console/recovery path available. The dedicated [UFW tutorial](/learn/tutorials/set-up-ufw-firewall-ubuntu-24-04) covers a lockout-safe activation sequence. For a server using the standard SSH port, the rule is commonly: ```bash sudo ufw allow OpenSSH ``` Only after confirming that the SSH rule matches your actual configuration should you enable UFW: ```bash sudo ufw enable sudo ufw status numbered ``` Confirm the domain resolves to the Raff VM: ```bash dig +short cloud.your-domain.com A ``` Compare the returned address with the VM public IPv4 address. Do not continue to certificate issuance until DNS points to the correct server. **Verify:** Your existing SSH administration path must still work, Apache HTTP/HTTPS must be permitted, and the domain must resolve to the correct VM. ## Step 4 — Configure MariaDB for Nextcloud and create the database Nextcloud requires the `READ COMMITTED` transaction isolation level for MySQL/MariaDB deployments and expects InnoDB. When binary logging is enabled, row-based logging is the compatible choice. Create a dedicated MariaDB configuration file: ```bash sudo tee /etc/mysql/mariadb.conf.d/60-nextcloud.cnf > /dev/null <<'EOF' [mysqld] transaction-isolation = READ-COMMITTED binlog_format = ROW innodb_file_per_table = 1 EOF ``` Restart MariaDB: ```bash sudo systemctl restart mariadb ``` Verify the database settings: ```bash sudo mariadb -NBe "SELECT @@tx_isolation, @@binlog_format, @@innodb_file_per_table;" ``` Expected values include: ```text READ-COMMITTED ROW 1 ``` Before running the next block, replace `REPLACE_WITH_A_STRONG_DATABASE_PASSWORD` with a unique password from your password manager: ```bash sudo mariadb <<'SQL' CREATE DATABASE IF NOT EXISTS nextcloud CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; CREATE USER IF NOT EXISTS 'nextclouduser'@'localhost' IDENTIFIED BY 'REPLACE_WITH_A_STRONG_DATABASE_PASSWORD'; GRANT ALL PRIVILEGES ON nextcloud.* TO 'nextclouduser'@'localhost'; FLUSH PRIVILEGES; SQL ``` Verify the database and account without exposing the password: ```bash sudo mariadb -e "SHOW DATABASES LIKE 'nextcloud';" sudo mariadb -e "SELECT User, Host FROM mysql.user WHERE User='nextclouduser';" ``` **Verify:** MariaDB should use `READ-COMMITTED`, database `nextcloud` should exist, and `nextclouduser@localhost` should be present. ## Step 5 — Download and install the stable Nextcloud 34 archive Download the current maintenance release from the stable Nextcloud 34 branch and its SHA-256 checksum file: ```bash cd /tmp curl -fLO https://download.nextcloud.com/server/releases/latest-34.tar.bz2 curl -fsSLo latest-34.tar.bz2.sha256 \ https://download.nextcloud.com/server/releases/latest-34.tar.bz2.sha256 ``` Verify the archive before extracting it: ```bash EXPECTED_SHA256="$(awk '{print $1}' latest-34.tar.bz2.sha256 | head -n 1)" ACTUAL_SHA256="$(sha256sum latest-34.tar.bz2 | awk '{print $1}')" test "$EXPECTED_SHA256" = "$ACTUAL_SHA256" \ && echo "Nextcloud checksum OK" \ || { echo "Checksum mismatch"; exit 1; } ``` Do not extract the archive if the checksum comparison fails. Confirm an existing installation will not be overwritten: ```bash test ! -e /var/www/nextcloud && echo "Install path is clear" ``` Extract the archive and move it into the Apache web directory: ```bash tar -xjf latest-34.tar.bz2 sudo mv nextcloud /var/www/nextcloud ``` Create a data directory outside the web root: ```bash sudo mkdir -p /var/nextcloud-data sudo chown -R www-data:www-data /var/www/nextcloud /var/nextcloud-data ``` If you mounted a separate Raff Volume for user data, use that mounted directory instead of `/var/nextcloud-data` and ensure it is owned by `www-data` before continuing. Check the downloaded Nextcloud version: ```bash sudo grep -E "OC_VersionString" /var/www/nextcloud/version.php ``` As of September 6, 2026, the stable release should report `34.0.3`. If a newer 34.x maintenance release is available when you run the tutorial, use the latest stable 34 maintenance release and review its changelog first. **Verify:** The checksum must match, `/var/www/nextcloud` must contain a stable `34.0.x` installation, and the application/data directories must be owned by `www-data`. ## Step 6 — Configure PHP 8.3 for Nextcloud Set practical limits for this tutorial baseline: ```bash PHP_INI="/etc/php/8.3/apache2/php.ini" sudo sed -i 's/^memory_limit = .*/memory_limit = 512M/' "$PHP_INI" sudo sed -i 's/^upload_max_filesize = .*/upload_max_filesize = 512M/' "$PHP_INI" sudo sed -i 's/^post_max_size = .*/post_max_size = 512M/' "$PHP_INI" sudo sed -i 's/^max_execution_time = .*/max_execution_time = 360/' "$PHP_INI" sudo sed -i 's/^max_input_time = .*/max_input_time = 360/' "$PHP_INI" ``` Give APCu a 128 MB cache allocation and enable APCu for CLI commands used by `occ`: ```bash sudo tee /etc/php/8.3/apache2/conf.d/99-nextcloud-apcu.ini > /dev/null <<'EOF' apc.shm_size=128M EOF sudo tee /etc/php/8.3/cli/conf.d/99-nextcloud-apcu.ini > /dev/null <<'EOF' apc.enable_cli=1 EOF ``` Restart Apache: ```bash sudo systemctl restart apache2 ``` Verify the values: ```bash php -i | grep -E 'memory_limit|apc.enable_cli|apc.shm_size' | head systemctl is-active apache2 ``` The 512 MB upload values here are examples for this deployment, not universal Nextcloud requirements. Size them to the file sizes and memory available on your VM. **Verify:** Apache should be active, the intended PHP limits should be visible, and APCu should be enabled for CLI use. ## Step 7 — Configure Apache for Nextcloud Create the virtual host: ```bash sudo tee /etc/apache2/sites-available/nextcloud.conf > /dev/null <<'EOF' ServerName cloud.your-domain.com DocumentRoot /var/www/nextcloud Require all granted AllowOverride All Options FollowSymLinks MultiViews Dav off SetEnv HOME /var/www/nextcloud SetEnv HTTP_HOME /var/www/nextcloud ErrorLog ${APACHE_LOG_DIR}/nextcloud_error.log CustomLog ${APACHE_LOG_DIR}/nextcloud_access.log combined EOF ``` Enable the site and required modules: ```bash sudo a2ensite nextcloud.conf sudo a2dissite 000-default.conf sudo a2enmod rewrite headers env dir mime ssl setenvif ``` Validate and reload Apache: ```bash sudo apache2ctl configtest sudo systemctl reload apache2 ``` Test the HTTP endpoint: ```bash curl -I http://cloud.your-domain.com ``` A `200`, `302`, or `303` response is acceptable before the installation wizard is completed. **Verify:** Apache should report `Syntax OK`, the Nextcloud site should be enabled, and the domain should return an HTTP response from this VM. ## Step 8 — Enable HTTPS with Certbot Install Certbot using its snap package: ```bash sudo snap install --classic certbot sudo ln -sf /snap/bin/certbot /usr/local/bin/certbot ``` Request the certificate and let Certbot configure Apache: ```bash sudo certbot --apache \ -d cloud.your-domain.com \ --redirect \ --agree-tos \ --no-eff-email \ -m admin@your-domain.com ``` Replace the example email address with one you control. Verify HTTPS and certificate renewal: ```bash curl -I https://cloud.your-domain.com sudo certbot renew --dry-run ``` **Verify:** HTTPS should respond successfully and the Certbot renewal simulation should complete without errors. ## Step 9 — Complete the Nextcloud web setup Open: ```text https://cloud.your-domain.com ``` The Nextcloud setup page should appear. ![Nextcloud setup page on Ubuntu 24.04](https://raff-images.s3.raffusercloud.com/nextcloud_ubuntu_24_04_01_setup_page_webp_377711610d.png) Create a strong Nextcloud administrator account. Do not reuse the MariaDB password. Use these database values: ```text Data folder: /var/nextcloud-data Database user: nextclouduser Database password: the password created in Step 4 Database name: nextcloud Database host: localhost ``` If you mounted a separate volume for the data directory, enter that verified mount path instead of `/var/nextcloud-data`. Complete the installation. After the dashboard appears, verify the server from SSH: ```bash cd /var/www/nextcloud sudo -u www-data php occ status sudo -u www-data php occ config:system:get trusted_domains ``` Expected state includes: ```text installed: true version: 34.0.x ``` If the domain is missing from `trusted_domains`, add it: ```bash sudo -u www-data php occ config:system:set trusted_domains 1 \ --value=cloud.your-domain.com ``` ![Nextcloud dashboard after first login on Ubuntu 24.04](https://raff-images.s3.raffusercloud.com/nextcloud_ubuntu_24_04_02_dashboard_webp_3acf1f034d.png) **Verify:** The dashboard should load over HTTPS, `occ status` should report `installed: true`, and the real hostname should be present in `trusted_domains`. ## Step 10 — Configure cron, APCu, and Redis file locking Configure Nextcloud background jobs to run with cron every five minutes under the web-server user: ```bash sudo -u www-data crontab -l 2>/dev/null | grep -v '/var/www/nextcloud/cron.php' | \ { cat; echo '*/5 * * * * php -f /var/www/nextcloud/cron.php'; } | \ sudo -u www-data crontab - ``` Run the job once and set cron mode: ```bash cd /var/www/nextcloud sudo -u www-data php -f cron.php sudo -u www-data php occ background:cron ``` Configure APCu as the local cache: ```bash sudo -u www-data php occ config:system:set memcache.local \ --value='\OC\Memcache\APCu' ``` Configure Redis for distributed caching and transactional file locking: ```bash sudo -u www-data php occ config:system:set memcache.distributed \ --value='\OC\Memcache\Redis' sudo -u www-data php occ config:system:set memcache.locking \ --value='\OC\Memcache\Redis' sudo -u www-data php occ config:system:set redis host --value=127.0.0.1 sudo -u www-data php occ config:system:set redis port --type=integer --value=6379 ``` Set a maintenance window start hour in UTC: ```bash sudo -u www-data php occ config:system:set maintenance_window_start \ --type=integer --value=1 ``` Verify the configuration: ```bash redis-cli ping sudo -u www-data php occ config:system:get memcache.local sudo -u www-data php occ config:system:get memcache.locking sudo -u www-data crontab -l ``` Expected state includes `PONG`, APCu local caching, Redis locking, and a cron job every five minutes. **Verify:** Redis must respond, Nextcloud must report the intended cache classes, and the `www-data` cron entry must exist. ## Step 11 — Verify Nextcloud end to end Open the Nextcloud admin overview: ```text Profile icon → Administration settings → Overview ``` ![Nextcloud administration overview showing setup checks](https://raff-images.s3.raffusercloud.com/nextcloud_ubuntu_24_04_03_admin_overview_webp_f408b3257c.png) Resolve warnings that are specific to your environment before storing important data. Open the **Files** app and upload a small file named: ```text raff-nextcloud-test.txt ``` Suggested content: ```text Hello from Nextcloud on a Raff Ubuntu 24.04 VM. ``` ![Nextcloud Files app showing an uploaded test file](https://raff-images.s3.raffusercloud.com/nextcloud_ubuntu_24_04_04_file_upload_webp_ca45658c3a.png) Confirm the browser reports a secure HTTPS connection. ![Browser HTTPS padlock for Nextcloud on Ubuntu 24.04](https://raff-images.s3.raffusercloud.com/nextcloud_ubuntu_24_04_05_https_padlock_webp_ba72800bd8.png) Run the server-side checks: ```bash systemctl is-active apache2 systemctl is-active mariadb systemctl is-active redis-server cd /var/www/nextcloud sudo -u www-data php occ status sudo -u www-data php occ config:system:get maintenance_window_start curl -I https://cloud.your-domain.com sudo ufw status numbered ``` End-to-end installation verification requires all of the following: - Apache, MariaDB, and Redis are active - Nextcloud reports `installed: true` - The installed version is in the stable `34.0.x` line - The dashboard loads over HTTPS - The admin overview opens - The test file uploads successfully - Cron, APCu, and Redis file locking are configured - The firewall preserves your administration path and permits the intended web traffic :::cta Deploy Your Server Deploy an Ubuntu 24.04 VM for your self-hosted Nextcloud server. ::: ## Step 12 — Create and verify an application-consistent Nextcloud backup A VM snapshot alone is not the same thing as an application-consistent Nextcloud backup. Nextcloud’s backup documentation requires the database, data directory, configuration, and relevant application/theme files to be recoverable together. Create a dated backup directory: ```bash STAMP="$(date +%Y%m%d-%H%M%S)" BACKUP_ROOT="/var/backups/nextcloud/$STAMP" sudo mkdir -p "$BACKUP_ROOT" echo "$BACKUP_ROOT" ``` Put Nextcloud into maintenance mode so files and database state do not continue changing during the backup: ```bash cd /var/www/nextcloud sudo -u www-data php occ maintenance:mode --on ``` Copy the entire Nextcloud application tree and data directory. Copying the application tree captures `config/` plus any installed custom app/theme files stored there: ```bash sudo rsync -Aax /var/www/nextcloud/ "$BACKUP_ROOT/nextcloud-app/" sudo rsync -Aax /var/nextcloud-data/ "$BACKUP_ROOT/nextcloud-data/" ``` If your data directory is on a separate mounted Raff Volume, replace `/var/nextcloud-data/` with that actual path. Dump the MariaDB database with a transaction-consistent dump and utf8mb4 support: ```bash sudo mariadb-dump \ --single-transaction \ --default-character-set=utf8mb4 \ nextcloud | sudo tee "$BACKUP_ROOT/nextcloud.sql" > /dev/null ``` Turn maintenance mode off after the backup commands complete: ```bash cd /var/www/nextcloud sudo -u www-data php occ maintenance:mode --off ``` If any backup command fails, correct the failure and explicitly check maintenance mode before allowing users back in: ```bash sudo -u www-data php occ maintenance:mode ``` Verify that the backup actually contains the critical components: ```bash sudo test -f "$BACKUP_ROOT/nextcloud-app/config/config.php" \ && echo "Config backup present" sudo test -d "$BACKUP_ROOT/nextcloud-data" \ && echo "Data backup present" sudo test -s "$BACKUP_ROOT/nextcloud.sql" \ && echo "Database dump present" sudo du -sh "$BACKUP_ROOT"/* ``` A successful command is only the first half of backup confidence. Periodically restore a backup into an isolated test environment instead of assuming it is recoverable. For a non-destructive **database restore check**, create a temporary database and import the dump there: ```bash RESTORE_DB="nextcloud_restore_test" sudo mariadb -e "DROP DATABASE IF EXISTS ${RESTORE_DB};" sudo mariadb -e "CREATE DATABASE ${RESTORE_DB} CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;" sudo mariadb "$RESTORE_DB" < "$BACKUP_ROOT/nextcloud.sql" sudo mariadb -NBe "SELECT COUNT(*) FROM ${RESTORE_DB}.oc_filecache;" ``` If the query returns a count, the SQL dump can at least be imported and read. This does **not** replace a full restore rehearsal: a real recovery test should also restore the matching application/configuration tree and data directory on a disposable VM, use the same Nextcloud version first, load the restored database, and verify user files in the web interface. Remove the temporary restore-test database when finished: ```bash sudo mariadb -e "DROP DATABASE IF EXISTS nextcloud_restore_test;" ``` If you later restore an older Nextcloud backup while synced clients contain newer state, review Nextcloud’s `maintenance:data-fingerprint` guidance before reconnecting clients. **Verify:** The backup is only considered minimally validated when `config.php`, the data directory, and a non-empty SQL dump exist together and the SQL dump imports successfully into an isolated test database. :::cta Explore Data Protection Add infrastructure-layer VM backups and snapshots alongside the application-consistent Nextcloud backup and restore checks you control inside the server. ::: ## Step 13 — Plan upgrades without treating the updater as a backup Before every Nextcloud upgrade, create a fresh application-consistent backup and verify that you can access it. Do not assume the built-in updater protects the live data directory and MariaDB database for you. Check the installed version and update status with: ```bash cd /var/www/nextcloud sudo -u www-data php occ status sudo -u www-data php occ update:check ``` Read the release notes for the target version before upgrading, especially when crossing a major release. Nextcloud does not support arbitrary downgrades, so your rollback plan should be a tested backup/restore path rather than “install the old package again.” **Verify:** Before an upgrade, you should know the current version, target version, backup location, and exact restore procedure. ## Cleanup and rollback For a temporary test deployment, prefer a reversible shutdown before permanent deletion. Enable maintenance mode and stop public access: ```bash cd /var/www/nextcloud sudo -u www-data php occ maintenance:mode --on sudo a2dissite nextcloud.conf sudo apache2ctl configtest sudo systemctl reload apache2 ``` Disable the Nextcloud background job: ```bash sudo -u www-data crontab -l 2>/dev/null | \ grep -v '/var/www/nextcloud/cron.php' | \ sudo -u www-data crontab - ``` Move the application and data directories to a dated holding location instead of deleting them immediately: ```bash STAMP="$(date +%Y%m%d-%H%M%S)" sudo mkdir -p "/var/backups/nextcloud-retired-$STAMP" sudo mv /var/www/nextcloud "/var/backups/nextcloud-retired-$STAMP/" sudo mv /var/nextcloud-data "/var/backups/nextcloud-retired-$STAMP/" ``` If the data directory is on a separate volume, do not run the second `mv`; unmount and preserve that volume according to your storage plan instead. Keep the MariaDB database until you have confirmed that no data or restore test is needed. Permanently delete the database, files, certificate, and storage only after you have a verified backup and intentionally decommission the instance. **Verify:** The public Nextcloud site should be disabled and the application/data should be retained somewhere recoverable until decommissioning is confirmed. ## Troubleshooting ### The setup page cannot connect to MariaDB Verify MariaDB, the database, the user, and the isolation level: ```bash systemctl is-active mariadb sudo mariadb -e "SHOW DATABASES LIKE 'nextcloud';" sudo mariadb -e "SELECT User, Host FROM mysql.user WHERE User='nextclouduser';" sudo mariadb -NBe "SELECT @@tx_isolation, @@binlog_format, @@innodb_file_per_table;" ``` If credentials are wrong, change the MariaDB user password deliberately and update the setup form. Do not reuse the Nextcloud administrator password. ### Apache returns an error or the site does not load Check the site, syntax, logs, and DNS: ```bash systemctl status apache2 --no-pager sudo apache2ctl configtest sudo a2query -s nextcloud dig +short cloud.your-domain.com A sudo tail -n 80 /var/log/apache2/nextcloud_error.log ``` Fix Apache or DNS before rerunning Certbot. ### Certbot cannot issue a certificate Check DNS and HTTP reachability first: ```bash dig +short cloud.your-domain.com A sudo ufw status numbered curl -I http://cloud.your-domain.com ``` The domain must resolve to the correct server and port 80 must be reachable for HTTP validation. ### Nextcloud reports an untrusted domain Add the hostname with `occ`: ```bash cd /var/www/nextcloud sudo -u www-data php occ config:system:set trusted_domains 1 \ --value=cloud.your-domain.com sudo -u www-data php occ config:system:get trusted_domains ``` ### The admin overview reports a database isolation warning Recheck the MariaDB runtime value: ```bash sudo mariadb -NBe "SELECT @@tx_isolation, @@binlog_format;" ``` The isolation level should be `READ-COMMITTED`. If it is not, verify `/etc/mysql/mariadb.conf.d/60-nextcloud.cnf` and restart MariaDB. ### The admin overview reports missing memory cache or file locking Verify Redis, APCu, and the Nextcloud configuration: ```bash redis-cli ping php -m | grep -Ei 'apcu|redis' cd /var/www/nextcloud sudo -u www-data php occ config:system:get memcache.local sudo -u www-data php occ config:system:get memcache.locking ``` For this single-server design, APCu handles local cache while Redis handles transactional file locking and distributed cache. ### Background jobs are not running Inspect the `www-data` crontab and run `cron.php` manually: ```bash sudo -u www-data crontab -l cd /var/www/nextcloud sudo -u www-data php -f cron.php sudo -u www-data php occ status ``` The cron entry should run `cron.php` every five minutes. ### Large uploads fail Verify PHP limits and data-directory ownership: ```bash PHP_INI="/etc/php/8.3/apache2/php.ini" grep -E '^(memory_limit|upload_max_filesize|post_max_size|max_execution_time|max_input_time)' "$PHP_INI" ls -ld /var/nextcloud-data ``` If the data directory uses a separate mounted volume, inspect that path instead. After PHP changes, restart Apache and retest the upload. ### The backup exists but the restore fails Make sure you are restoring the **matching** configuration, data directory, and database from the same backup point. A database dump by itself is not a complete Nextcloud recovery source, and a VM snapshot taken at an arbitrary moment is not proof of application consistency. For MariaDB restoration, Nextcloud’s documented pattern is to restore into a clean database and then import the dump. Test that workflow on a disposable server before you need it during an incident. ## Conclusion You now have a manual Nextcloud 34 installation on Ubuntu 24.04 with Apache, MariaDB configured for `READ COMMITTED`, PHP 8.3, HTTPS, cron background jobs, APCu local caching, Redis transactional file locking, and a verified application-consistent backup workflow. The installation URL remains useful for users who want direct control of the web server, database, PHP configuration, filesystem, and backup process. Before storing important data, complete the end-to-end checks and perform a full restore rehearsal on an isolated VM. Continue with [How to Secure Your Ubuntu 24.04 Server](/learn/tutorials/secure-ubuntu-24-04-server), [Automate Backups with cron and rsync on Ubuntu 24.04](/learn/tutorials/automate-backups-cron-rsync-ubuntu-24-04), and [Set Up UFW Firewall on Ubuntu 24.04](/learn/tutorials/set-up-ufw-firewall-ubuntu-24-04) for the surrounding operating practices. ## Sources - [Nextcloud — Download and install](https://nextcloud.com/install/) - [Nextcloud 34 Administration Manual — Example installation on Ubuntu 24.04 LTS](https://docs.nextcloud.com/server/stable/admin_manual/installation/example_ubuntu.html) - [Nextcloud 34 Administration Manual — System requirements](https://docs.nextcloud.com/server/stable/admin_manual/installation/system_requirements.html) - [Nextcloud 34 Administration Manual — Backup](https://docs.nextcloud.com/server/stable/admin_manual/maintenance/backup.html) - [Nextcloud 34 Administration Manual — Restoring backup](https://docs.nextcloud.com/server/stable/admin_manual/maintenance/restore.html) - Guidance re-verified: 2026-09-06 --- ### How to Self-Host n8n on Ubuntu 24.04 with Docker Compose URL: https://rafftechnologies.com/learn/tutorials/self-host-n8n-docker Description: Self-host n8n on Ubuntu 24.04 with Docker Compose, PostgreSQL, Nginx, HTTPS, safe firewall setup, backups, restore verification, and updates. To self-host **n8n with Docker Compose on Ubuntu 24.04**, run n8n with persistent storage and PostgreSQL, keep port `5678` bound to localhost, and publish the instance through an HTTPS reverse proxy. This tutorial builds that production-shaped baseline with Nginx, safe firewall handling, execution pruning, backups, and restore verification. Raff Technologies is used as the Ubuntu VM platform in the saved test environment. If you want the faster Raff path instead of operating the Compose stack manually, use the [n8n Marketplace deployment](/marketplace/n8n). If you want full control over the containers, database, proxy, and recovery process, continue with this tutorial on a [Raff Linux VM](/products/linux-vm). As of September 7, 2026, the current stable n8n release is **2.37.10**. n8n 2.38.3 is available as a pre-release, so this tutorial pins the stable `2.37.10` image instead of following a pre-release tag. The previous Raff workflow was reviewed on Ubuntu 24.04 in July 2026; the current n8n 2.37.10 configuration and documentation were re-verified for this refresh without claiming a new full machine retest. > **Important n8n 2.x change:** use `N8N_WEBHOOK_URL` behind a reverse proxy. The older `WEBHOOK_URL` variable is deprecated. n8n 2.x also uses task runners by default in internal mode, so you do not need the deprecated `N8N_RUNNERS_ENABLED=true` setting for this deployment. Prerequisites: - An Ubuntu 24.04 VM with SSH access through a non-root sudo user - Docker Engine and the Docker Compose plugin; see [Install Docker on Ubuntu 24.04](/learn/tutorials/install-docker-ubuntu-24-04) - A domain such as `n8n.example.com` pointed to the VM public IPv4 address - Ports `80/tcp` and `443/tcp` available for Nginx - A password manager or another protected place for the PostgreSQL password and n8n encryption key - A recovery path before changing firewall rules ## Step 1 — Verify Ubuntu, DNS, and Docker Update package metadata and install the host utilities used later: ```bash sudo apt update sudo apt upgrade -y sudo apt install -y curl ca-certificates openssl nginx ufw snapd dnsutils ``` If `/var/run/reboot-required` exists, reboot during a safe maintenance window before continuing: ```bash test -f /var/run/reboot-required && cat /var/run/reboot-required ``` Verify Ubuntu, Docker, and Compose: ```bash lsb_release -ds docker --version docker compose version ``` Confirm the domain resolves to this server: ```bash dig +short A n8n.example.com ``` Compare the returned address with the VM public IPv4 address in the Raff dashboard. **Verify:** Ubuntu should report 24.04 LTS, both Docker commands should succeed, and the n8n hostname should resolve to the intended VM before you request a public certificate. ## Step 2 — Create the n8n project and backup directories Create a dedicated project directory: ```bash sudo mkdir -p /opt/n8n/backups sudo chown -R "$USER":"$USER" /opt/n8n cd /opt/n8n ``` Check ownership: ```bash ls -ld /opt/n8n /opt/n8n/backups ``` **Verify:** both directories should exist and be writable by the administrative user managing this deployment. ## Step 3 — Create protected n8n secrets and environment settings Generate a strong PostgreSQL password and a separate n8n encryption key: ```bash openssl rand -base64 36 openssl rand -hex 32 ``` Store both values in a password manager. The exact n8n encryption key is required to decrypt saved credentials after a restore. Create `/opt/n8n/.env`: ```bash nano /opt/n8n/.env ``` Add: ```dotenv N8N_VERSION=2.37.10 N8N_DOMAIN=n8n.example.com GENERIC_TIMEZONE=UTC POSTGRES_DB=n8n POSTGRES_USER=n8n POSTGRES_PASSWORD=REPLACE_WITH_A_LONG_RANDOM_DATABASE_PASSWORD N8N_ENCRYPTION_KEY=REPLACE_WITH_THE_64_CHARACTER_HEX_VALUE ``` Protect the file: ```bash chmod 600 /opt/n8n/.env stat -c '%a %n' /opt/n8n/.env ``` Expected mode: ```text 600 /opt/n8n/.env ``` Do not print `.env` into public logs, tickets, screenshots, or shell transcripts shared with other people. **Verify:** `.env` should have mode `600`, the database password and encryption key should be different values, and a protected off-server copy of the encryption key should exist. ## Step 4 — Create the n8n Docker Compose stack Create `/opt/n8n/compose.yaml`: ```bash nano /opt/n8n/compose.yaml ``` Add: ```yaml name: n8n services: postgres: image: postgres:16-alpine restart: unless-stopped environment: POSTGRES_DB: ${POSTGRES_DB} POSTGRES_USER: ${POSTGRES_USER} POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} volumes: - postgres_data:/var/lib/postgresql/data healthcheck: test: ["CMD-SHELL", "pg_isready -U ${POSTGRES_USER} -d ${POSTGRES_DB}"] interval: 10s timeout: 5s retries: 10 n8n: image: docker.n8n.io/n8nio/n8n:${N8N_VERSION} restart: unless-stopped depends_on: postgres: condition: service_healthy ports: - "127.0.0.1:5678:5678" environment: DB_TYPE: postgresdb DB_POSTGRESDB_HOST: postgres DB_POSTGRESDB_PORT: 5432 DB_POSTGRESDB_DATABASE: ${POSTGRES_DB} DB_POSTGRESDB_USER: ${POSTGRES_USER} DB_POSTGRESDB_PASSWORD: ${POSTGRES_PASSWORD} N8N_ENCRYPTION_KEY: ${N8N_ENCRYPTION_KEY} N8N_HOST: ${N8N_DOMAIN} N8N_PORT: 5678 N8N_PROTOCOL: https N8N_EDITOR_BASE_URL: https://${N8N_DOMAIN}/ N8N_WEBHOOK_URL: https://${N8N_DOMAIN}/ N8N_PROXY_HOPS: 1 N8N_SECURE_COOKIE: "true" N8N_ENFORCE_SETTINGS_FILE_PERMISSIONS: "true" GENERIC_TIMEZONE: ${GENERIC_TIMEZONE} TZ: ${GENERIC_TIMEZONE} EXECUTIONS_DATA_PRUNE: "true" EXECUTIONS_DATA_MAX_AGE: 168 EXECUTIONS_DATA_PRUNE_MAX_COUNT: 10000 volumes: - n8n_data:/home/node/.n8n volumes: postgres_data: name: n8n_postgres_data n8n_data: name: n8n_data ``` This stack deliberately binds n8n to `127.0.0.1:5678`. The application port is not a public service; Nginx will be the public HTTPS entry point. n8n supports SQLite by default and PostgreSQL as an alternative database. This tutorial uses PostgreSQL because it gives the deployment an explicit database boundary and a straightforward `pg_dump` recovery workflow. PostgreSQL 16 remains an actively maintained branch and is a conservative container choice for this tutorial. Validate the resolved Compose configuration: ```bash cd /opt/n8n docker compose config >/tmp/n8n-compose-rendered.yaml ``` Confirm the services are present without printing resolved secrets: ```bash grep -E '^ (n8n|postgres):$' /tmp/n8n-compose-rendered.yaml ``` Remove the temporary rendered configuration because it contains resolved environment values: ```bash rm -f /tmp/n8n-compose-rendered.yaml ``` **Verify:** `docker compose config` should exit successfully and the rendered configuration should contain both `postgres` and `n8n` services. ## Step 5 — Start PostgreSQL and n8n Start the stack: ```bash cd /opt/n8n docker compose up -d ``` Check container state: ```bash docker compose ps ``` Review recent logs without printing environment files: ```bash docker compose logs --tail=100 postgres docker compose logs --tail=100 n8n ``` Verify the running n8n version: ```bash docker compose exec n8n n8n --version ``` Expected version: ```text 2.37.10 ``` Test the health endpoint locally: ```bash curl -i http://127.0.0.1:5678/healthz ``` Confirm the application port is loopback-only: ```bash ss -lntp | grep ':5678' ``` Expected listener includes: ```text 127.0.0.1:5678 ``` **Verify:** PostgreSQL should become healthy, n8n should run version 2.37.10, `/healthz` should respond locally, and port 5678 should not listen on `0.0.0.0`. ## Step 6 — Configure Nginx for n8n and forwarded headers Create the Nginx server block: ```bash sudo nano /etc/nginx/sites-available/n8n.example.com ``` Add: ```nginx server { listen 80; listen [::]:80; server_name n8n.example.com; client_max_body_size 50M; location / { proxy_pass http://127.0.0.1:5678; proxy_http_version 1.1; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Host $host; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_buffering off; proxy_read_timeout 300s; } } ``` n8n's current reverse-proxy guidance requires the last proxy in the request path to forward `X-Forwarded-For`, `X-Forwarded-Host`, and `X-Forwarded-Proto`. Because this tutorial has one Nginx proxy, the Compose configuration sets `N8N_PROXY_HOPS=1`. Enable the site: ```bash sudo ln -sfn /etc/nginx/sites-available/n8n.example.com \ /etc/nginx/sites-enabled/n8n.example.com sudo nginx -t sudo systemctl reload nginx ``` Test the HTTP route before requesting TLS: ```bash curl -I http://n8n.example.com ``` **Verify:** `nginx -t` should succeed and the hostname should reach Nginx while n8n itself remains bound only to localhost. ## Step 7 — Configure UFW without risking SSH lockout, then enable HTTPS First inspect the firewall instead of enabling it blindly: ```bash sudo ufw status verbose ``` Confirm the actual SSH listening port: ```bash sudo sshd -T | awk '/^port / {print $2}' ``` If UFW is already active, preserve the existing SSH rule and allow the Nginx web profile: ```bash sudo ufw allow 'Nginx Full' sudo ufw status numbered ``` If UFW is inactive, add a rule for the **actual SSH port** first. When SSH uses the normal port and the `OpenSSH` application profile matches your configuration: ```bash sudo ufw allow OpenSSH ``` If SSH uses a custom port, allow that port instead, for example: ```bash sudo ufw allow 2222/tcp ``` Then allow Nginx: ```bash sudo ufw allow 'Nginx Full' ``` Before enabling UFW from a remote server, open a second SSH session and confirm the allowed SSH path is correct. Only then enable the firewall: ```bash sudo ufw enable sudo ufw status numbered ``` Do not create a public allow rule for `5678/tcp`. Install Certbot using the snap package: ```bash sudo snap install --classic certbot sudo ln -sf /snap/bin/certbot /usr/local/bin/certbot ``` Request the certificate and redirect HTTP to HTTPS: ```bash sudo certbot --nginx --redirect -d n8n.example.com ``` Verify HTTPS and renewal: ```bash curl -I https://n8n.example.com sudo certbot renew --dry-run ``` **Verify:** the original and second SSH sessions should remain usable, HTTPS should succeed, renewal simulation should pass, and port 5678 should still have no public firewall rule. ## Step 8 — Create the owner account and verify public n8n URLs Open: ```text https://n8n.example.com ``` Create the first owner account using a unique password. Create a small workflow with a **Manual Trigger** and **Edit Fields** node, execute it, and confirm the result appears in the Executions view. Add a Webhook node and inspect both its test and production URLs. They should use the public HTTPS hostname rather than `localhost`, a container name, or port `5678`. Verify the non-secret public URL settings inside the container: ```bash cd /opt/n8n docker compose exec n8n env | \ grep -E '^(N8N_HOST|N8N_PROTOCOL|N8N_EDITOR_BASE_URL|N8N_WEBHOOK_URL|N8N_PROXY_HOPS)=' ``` Expected values include: ```text N8N_HOST=n8n.example.com N8N_PROTOCOL=https N8N_EDITOR_BASE_URL=https://n8n.example.com/ N8N_WEBHOOK_URL=https://n8n.example.com/ N8N_PROXY_HOPS=1 ``` **Verify:** the editor should load over HTTPS, a manual workflow should execute, and generated webhook URLs should use the public HTTPS domain. ## Step 9 — Run the built-in n8n security audit Run the n8n audit command: ```bash cd /opt/n8n docker compose exec n8n n8n audit ``` The security audit can report risks involving credentials, database usage, filesystem nodes, community/custom nodes, and instance settings. Treat the report as a review tool, not as a guarantee that the instance is secure. For production workflows: - remove unused credentials; - review community nodes before installation; - restrict who can edit workflows that can change customer, billing, infrastructure, or security state; - keep webhook authentication and authorization appropriate to the workflow; - use private network paths for internal services where possible. **Verify:** the audit should run successfully and each reported risk should be reviewed, accepted, or assigned for remediation. ## Step 10 — Configure execution retention and create recoverable backups The Compose configuration keeps pruning enabled and sets a seven-day age limit: ```dotenv EXECUTIONS_DATA_PRUNE=true EXECUTIONS_DATA_MAX_AGE=168 EXECUTIONS_DATA_PRUNE_MAX_COUNT=10000 ``` n8n currently enables execution pruning by default. Its documented defaults are 336 hours for age and 10,000 executions for count; this tutorial intentionally reduces the age window to seven days. Increase or decrease it only after deciding how much execution history you actually need. Load the protected environment only in the current shell: ```bash cd /opt/n8n set -a source .env set +a ``` Check PostgreSQL size and host storage: ```bash docker compose exec -T postgres \ psql -U "$POSTGRES_USER" -d "$POSTGRES_DB" \ -c "SELECT pg_size_pretty(pg_database_size(current_database()));" docker system df df -h / ``` Create a PostgreSQL dump: ```bash DUMP="backups/n8n-db-$(date +%F-%H%M%S).sql" docker compose exec -T postgres \ pg_dump -U "$POSTGRES_USER" -d "$POSTGRES_DB" \ > "$DUMP" ``` Verify that the dump is not empty: ```bash test -s "$DUMP" && echo "PostgreSQL dump created: $DUMP" ``` For a consistent archive of the n8n persistent volume, stop the n8n application container during a short maintenance window while leaving PostgreSQL running: ```bash docker compose stop n8n ``` Archive the volume: ```bash docker run --rm \ -v n8n_data:/data:ro \ -v /opt/n8n/backups:/backup \ alpine \ tar -czf "/backup/n8n-data-$(date +%F-%H%M%S).tar.gz" -C /data . ``` Start n8n again: ```bash docker compose start n8n curl -fsS http://127.0.0.1:5678/healthz ``` Also protect `compose.yaml`, `.env`, and the exact encryption key in an off-server backup location. A database dump without the matching encryption key is not a complete credential recovery plan. n8n documents external S3 binary storage as a Self-hosted Enterprise feature. Community deployments should not assume an S3 bucket can replace the local persistent storage model used here. **Verify:** the PostgreSQL dump and n8n data archive should be non-empty, n8n should become healthy after the maintenance window, and the encryption key should exist in a protected off-server copy. ## Step 11 — Test the PostgreSQL backup with an isolated restore A backup is more useful when you have evidence that it can be restored. Create a disposable PostgreSQL database inside the same PostgreSQL container: ```bash RESTORE_DB=n8n_restore_test docker compose exec -T postgres \ dropdb -U "$POSTGRES_USER" --if-exists "$RESTORE_DB" docker compose exec -T postgres \ createdb -U "$POSTGRES_USER" "$RESTORE_DB" ``` Restore the dump into the isolated database: ```bash cat "$DUMP" | docker compose exec -T postgres \ psql -U "$POSTGRES_USER" -d "$RESTORE_DB" ``` Confirm that application tables were restored without depending on a specific n8n internal table name: ```bash docker compose exec -T postgres \ psql -U "$POSTGRES_USER" -d "$RESTORE_DB" \ -c "SELECT count(*) AS public_tables FROM information_schema.tables WHERE table_schema='public';" ``` The count should be greater than zero. Remove the disposable database: ```bash docker compose exec -T postgres \ dropdb -U "$POSTGRES_USER" "$RESTORE_DB" ``` This test verifies the SQL dump can be imported. It does **not** prove that every credential is usable after a disaster; that also depends on restoring the same `N8N_ENCRYPTION_KEY` and the required n8n persistent data and configuration. **Verify:** the dump should import without a fatal SQL error, the restored database should contain public tables, and the disposable restore database should be removed afterward. ## Step 12 — Update n8n with a controlled rollback path Before an n8n update: 1. create fresh backups; 2. review n8n release notes and breaking changes; 3. choose an exact stable target version; 4. change the pinned `N8N_VERSION` instead of switching blindly to a pre-release. Edit `.env`: ```bash nano /opt/n8n/.env ``` Pull the chosen image and recreate n8n: ```bash cd /opt/n8n docker compose pull n8n docker compose up -d n8n ``` Check the version, logs, local health, and public endpoint: ```bash docker compose exec n8n n8n --version docker compose logs --tail=200 n8n curl -fsS http://127.0.0.1:5678/healthz curl -I https://n8n.example.com ``` Do not assume that image rollback alone can reverse every failed upgrade. Database migrations can make downgrades unsafe. Read the version-specific migration and release notes before depending on a previous image as the only rollback plan. **Verify:** the intended stable version should be running, the local health endpoint should pass, and the public HTTPS endpoint should remain available after the update. ## Step 13 — Verify the self-hosted n8n deployment end to end Run the final server checks: ```bash cd /opt/n8n docker compose ps docker compose exec n8n n8n --version curl -fsS http://127.0.0.1:5678/healthz curl -I https://n8n.example.com ss -lntp | grep ':5678' sudo nginx -t sudo ufw status numbered ls -lh /opt/n8n/backups docker compose exec n8n env | \ grep -E '^(N8N_HOST|N8N_PROTOCOL|N8N_EDITOR_BASE_URL|N8N_WEBHOOK_URL|N8N_PROXY_HOPS)=' ``` In the n8n UI, confirm all of the following: - The editor loads over HTTPS. - The owner account can sign in. - A manual workflow executes successfully. - The execution appears in the Executions view. - A Webhook node generates `https://n8n.example.com/...` URLs. - The security audit has been reviewed. - Port `5678` remains loopback-only. - A current PostgreSQL dump exists and has passed the isolated restore test. - The encryption key and recovery material are protected off-server. End-to-end verification is complete when the containers are healthy, the pinned stable n8n version is running, Nginx serves the editor over HTTPS, public webhook URLs are correct, the application port is private, and the backup has passed an isolated database restore. :::cta Deploy Your Server Deploy an Ubuntu 24.04 Linux VM and run this n8n Docker Compose stack with PostgreSQL, Nginx, and a tested recovery path. ::: ## Use the Raff Marketplace when you do not need to build the stack manually This tutorial is intentionally for teams that want to own the Docker Compose, PostgreSQL, Nginx, firewall, update, and recovery configuration themselves. If the goal is simply to get a self-hosted n8n instance running on Raff with less initial setup, use the [Raff Marketplace n8n deployment](/marketplace/n8n). Marketplace deployment reduces setup friction, but it does not remove responsibility for workflow design, credentials, n8n updates, monitoring, or recovery. For architecture decisions before deployment, read [n8n Self-Hosted: When Workflow Automation Makes Sense](/learn/guides/n8n-self-hosted-workflow-automation-guide). ## Cleanup and rollback For a reversible shutdown, stop the stack without deleting its persistent volumes: ```bash cd /opt/n8n docker compose stop ``` Disable public access through Nginx: ```bash sudo rm -f /etc/nginx/sites-enabled/n8n.example.com sudo nginx -t sudo systemctl reload nginx ``` Keep `/opt/n8n`, `n8n_data`, and `n8n_postgres_data` until you have confirmed that no workflow, credential, database record, or recovery material is needed. To restart later: ```bash cd /opt/n8n docker compose up -d ``` Do not use `docker compose down -v` unless you intentionally want to delete the persistent n8n and PostgreSQL volumes and have already verified the backups you intend to keep. ## Troubleshooting ### n8n does not start after changing the image version Check the exact version and logs: ```bash cd /opt/n8n grep '^N8N_VERSION=' .env docker compose ps docker compose logs --tail=200 n8n ``` Confirm the image tag is a published stable release. If the failure follows an upgrade, review the n8n release and migration notes before attempting a downgrade. ### n8n starts but the public URL does not load Check local health, Nginx, DNS, and the public route: ```bash curl -i http://127.0.0.1:5678/healthz sudo nginx -t systemctl is-active nginx dig +short A n8n.example.com curl -I http://n8n.example.com ``` Fix DNS or Nginx before rerunning Certbot. ### Webhook URLs contain localhost or port 5678 Verify the current n8n 2.x public URL settings: ```bash cd /opt/n8n docker compose exec n8n env | \ grep -E '^(N8N_HOST|N8N_PROTOCOL|N8N_EDITOR_BASE_URL|N8N_WEBHOOK_URL|N8N_PROXY_HOPS)=' ``` Use `N8N_WEBHOOK_URL=https://n8n.example.com/`, not the deprecated `WEBHOOK_URL`. For the single Nginx proxy in this tutorial, `N8N_PROXY_HOPS` should be `1`. Also verify Nginx forwards the required headers: ```bash sudo nginx -T 2>/dev/null | \ grep -E 'X-Forwarded-(For|Host|Proto)' ``` ### PostgreSQL is unhealthy Inspect its service state and logs: ```bash cd /opt/n8n docker compose ps postgres docker compose logs --tail=200 postgres ``` Load `.env` only when you need to run authenticated database checks. Do not paste the database password into public support channels. ### Restored credentials cannot be decrypted The PostgreSQL database does not contain everything needed to decrypt n8n credentials. Restore the exact `N8N_ENCRYPTION_KEY` used by the original instance and the required n8n persistent configuration before concluding that the database restore is bad. ### The database dump restores but the restored instance still fails A successful SQL import verifies the database backup, not the complete application recovery process. Check the encryption key, persistent n8n data, image version, environment configuration, reverse-proxy settings, custom nodes, and any external services required by the workflows. ### Disk usage grows faster than expected Check host, Docker, and PostgreSQL usage: ```bash cd /opt/n8n docker system df df -h / set -a source .env set +a docker compose exec -T postgres \ psql -U "$POSTGRES_USER" -d "$POSTGRES_DB" \ -c "SELECT pg_size_pretty(pg_database_size(current_database()));" ``` Review `EXECUTIONS_DATA_MAX_AGE` and `EXECUTIONS_DATA_PRUNE_MAX_COUNT` only after deciding how much historical execution data is actually required. ### Enabling UFW would risk losing SSH access Do not enable it from a single remote session until you know the real SSH port and have added the matching allow rule. Keep the current session open, open a second SSH session, and verify the access path before enabling UFW. If you cannot verify a recovery path, leave UFW activation for a controlled maintenance change. ## Conclusion You now have a current n8n Docker Compose pattern for Ubuntu 24.04: n8n 2.37.10 is pinned to a stable image, PostgreSQL stores application data, Nginx is the HTTPS entry point, `N8N_WEBHOOK_URL` supplies the public webhook base URL, forwarded headers match n8n's reverse-proxy requirements, and port 5678 remains private. The deployment also has a safer firewall procedure and a recovery workflow that goes beyond creating backup files: the PostgreSQL dump is restored into a disposable database and checked before it is trusted. For adjacent operations, continue with [Install Docker on Ubuntu 24.04](/learn/tutorials/install-docker-ubuntu-24-04), [Secure Nginx with Let's Encrypt](/learn/tutorials/secure-nginx-lets-encrypt-ubuntu-24-04), and [n8n Self-Hosted: When Workflow Automation Makes Sense](/learn/guides/n8n-self-hosted-workflow-automation-guide). ## Sources - n8n Docs — Docker and Docker Compose installation - n8n Docs — Configure webhook URLs with a reverse proxy - n8n Docs — Database configuration and supported databases - n8n Docs — Execution pruning and execution data management - n8n Docs — Security audit - n8n Docs — External storage for binary data - n8n GitHub releases — stable release channel - Guidance re-verified: 2026-09-07 --- ### Install Prometheus and Grafana on Ubuntu 24.04 URL: https://rafftechnologies.com/learn/tutorials/install-prometheus-grafana-ubuntu-24-04 Description: Install Prometheus 3.13 LTS, Node Exporter, and Grafana on Ubuntu 24.04 with localhost-only monitoring ports, SSH-tunneled dashboards, and end-to-end verification. To **install Prometheus on Ubuntu 24.04 with Grafana**, run Prometheus and Node Exporter as dedicated systemd services, keep their web interfaces private, install Grafana from its official stable APT repository, and verify that Grafana can query live host metrics from Prometheus. This tutorial uses a Raff Technologies Linux VM as the reference Ubuntu server. The single-VM design intentionally binds Prometheus, Node Exporter, and Grafana to `127.0.0.1`, so ports `9090`, `9100`, and `3000` are not exposed directly to the public internet. Administrators reach Grafana through an SSH tunnel. The previous version of this tutorial used Prometheus 3.5.5 LTS. That LTS line reached end of support on **July 31, 2026**. As of September 7, 2026, the supported Prometheus LTS line is **3.13**, and this tutorial pins **Prometheus 3.13.2 LTS**. Node Exporter remains at **1.12.1**. Grafana is installed from the official stable APT repository instead of being pinned to a manual package, so normal package maintenance can deliver stable Grafana updates. The original monitoring workflow was tested on a Raff Ubuntu 24.04 VM with 2 vCPU and 4 GB RAM. Prometheus 3.13.2, Node Exporter 1.12.1, and the current Grafana repository instructions were documentation-reviewed for this refresh; no new full machine retest is claimed. Prerequisites: - An [Ubuntu 24.04 Linux VM on Raff](/products/linux-vm) - SSH access with a non-root sudo user - SSH key authentication recommended - Enough disk capacity for your chosen Prometheus retention period - A recovery path before changing firewall rules ## Step 1 — Prepare Ubuntu 24.04 Update packages and install the utilities used in this tutorial: ```bash sudo apt update sudo apt upgrade -y sudo apt install -y curl wget tar gnupg ca-certificates ufw jq ``` If the upgrade requires a reboot, schedule it before continuing: ```bash test -f /var/run/reboot-required && cat /var/run/reboot-required ``` Check the operating system and current resources: ```bash lsb_release -ds nproc free -h df -h / ``` A 2 vCPU / 4 GB RAM VM is a practical starting point for this small single-node tutorial, but Prometheus storage and memory needs depend on scrape frequency, retention, target count, and metric cardinality. **Verify:** Ubuntu should report 24.04 LTS and the VM should have enough CPU, memory, and free disk for the monitoring workload you intend to retain. ## Step 2 — Create dedicated service users and Prometheus directories Create non-login accounts for Prometheus and Node Exporter: ```bash sudo useradd --system --no-create-home --shell /usr/sbin/nologin prometheus 2>/dev/null || true sudo useradd --system --no-create-home --shell /usr/sbin/nologin node_exporter 2>/dev/null || true ``` Create Prometheus configuration and data directories: ```bash sudo install -d -o prometheus -g prometheus /etc/prometheus sudo install -d -o prometheus -g prometheus /var/lib/prometheus ``` Check the accounts and ownership: ```bash getent passwd prometheus getent passwd node_exporter ls -ld /etc/prometheus /var/lib/prometheus ``` **Verify:** both service accounts should exist and the Prometheus directories should be owned by `prometheus`. ## Step 3 — Install Prometheus 3.13.2 LTS and verify the download Prometheus 3.13 is the current supported LTS line for this tutorial. Download the Linux AMD64 archive: ```bash cd /tmp PROMETHEUS_VERSION="3.13.2" PROMETHEUS_ARCHIVE="prometheus-${PROMETHEUS_VERSION}.linux-amd64.tar.gz" curl -fLO "https://github.com/prometheus/prometheus/releases/download/v${PROMETHEUS_VERSION}/${PROMETHEUS_ARCHIVE}" ``` Verify the SHA-256 checksum published by Prometheus: ```bash echo "0e8c4d46101bd025ea8265e377d2caabc57f488fc1be1c367f37db69ea41be6f ${PROMETHEUS_ARCHIVE}" | sha256sum -c - ``` Expected output: ```text prometheus-3.13.2.linux-amd64.tar.gz: OK ``` Extract and install the binaries: ```bash tar -xzf "$PROMETHEUS_ARCHIVE" cd "prometheus-${PROMETHEUS_VERSION}.linux-amd64" sudo install -m 0755 prometheus promtool /usr/local/bin/ ``` Verify both binaries: ```bash prometheus --version | head -n 1 promtool --version | head -n 1 ``` The output should report version `3.13.2`. **Verify:** the checksum should pass and both installed binaries should report Prometheus 3.13.2. ## Step 4 — Configure Prometheus to scrape itself and Node Exporter Create `/etc/prometheus/prometheus.yml`: ```bash sudo tee /etc/prometheus/prometheus.yml > /dev/null <<'EOF' global: scrape_interval: 15s evaluation_interval: 15s scrape_configs: - job_name: "prometheus" static_configs: - targets: ["127.0.0.1:9090"] - job_name: "node_exporter" static_configs: - targets: ["127.0.0.1:9100"] EOF ``` Set ownership and validate the configuration: ```bash sudo chown prometheus:prometheus /etc/prometheus/prometheus.yml promtool check config /etc/prometheus/prometheus.yml ``` **Verify:** `promtool` should report a successful configuration check and both localhost scrape targets should be present. ## Step 5 — Run Prometheus under systemd on localhost only Create the service unit: ```bash sudo tee /etc/systemd/system/prometheus.service > /dev/null <<'EOF' [Unit] Description=Prometheus Monitoring Wants=network-online.target After=network-online.target [Service] User=prometheus Group=prometheus Type=simple ExecStart=/usr/local/bin/prometheus \ --config.file=/etc/prometheus/prometheus.yml \ --storage.tsdb.path=/var/lib/prometheus \ --storage.tsdb.retention.time=15d \ --web.listen-address=127.0.0.1:9090 Restart=on-failure RestartSec=5 [Install] WantedBy=multi-user.target EOF ``` The explicit `15d` retention value makes the tutorial's starting policy visible instead of leaving it implicit. Change it only after checking disk growth and deciding how much incident history you need. Start Prometheus: ```bash sudo systemctl daemon-reload sudo systemctl enable --now prometheus ``` Check the service, readiness endpoint, and bind address: ```bash systemctl is-active prometheus curl -fsS http://127.0.0.1:9090/-/ready ss -lntp | grep ':9090' ``` Expected listener: ```text 127.0.0.1:9090 ``` **Verify:** Prometheus should be active and ready, with port 9090 bound only to localhost. ## Step 6 — Install Node Exporter 1.12.1 and verify its checksum Download Node Exporter: ```bash cd /tmp NODE_EXPORTER_VERSION="1.12.1" NODE_EXPORTER_ARCHIVE="node_exporter-${NODE_EXPORTER_VERSION}.linux-amd64.tar.gz" curl -fLO "https://github.com/prometheus/node_exporter/releases/download/v${NODE_EXPORTER_VERSION}/${NODE_EXPORTER_ARCHIVE}" ``` Verify the official Linux AMD64 checksum: ```bash echo "b51d8a76aa2a9156a55d501aca6276fae09e262259a5e4e831d2c2222f084e63 ${NODE_EXPORTER_ARCHIVE}" | sha256sum -c - ``` Extract and install the binary: ```bash tar -xzf "$NODE_EXPORTER_ARCHIVE" sudo install -m 0755 \ "node_exporter-${NODE_EXPORTER_VERSION}.linux-amd64/node_exporter" \ /usr/local/bin/node_exporter ``` Verify the version: ```bash node_exporter --version | head -n 1 ``` **Verify:** the checksum should pass and Node Exporter should report version 1.12.1. ## Step 7 — Run Node Exporter under systemd on localhost only Create the service unit: ```bash sudo tee /etc/systemd/system/node_exporter.service > /dev/null <<'EOF' [Unit] Description=Prometheus Node Exporter Wants=network-online.target After=network-online.target [Service] User=node_exporter Group=node_exporter Type=simple ExecStart=/usr/local/bin/node_exporter --web.listen-address=127.0.0.1:9100 Restart=on-failure RestartSec=5 [Install] WantedBy=multi-user.target EOF ``` Start the service: ```bash sudo systemctl daemon-reload sudo systemctl enable --now node_exporter ``` Check its metrics and listener: ```bash systemctl is-active node_exporter curl -fsS http://127.0.0.1:9100/metrics | head ss -lntp | grep ':9100' ``` **Verify:** Node Exporter should be active, its `/metrics` endpoint should return Prometheus-format metrics, and port 9100 should be bound only to localhost. ## Step 8 — Verify Prometheus is scraping both targets Wait for at least one scrape interval: ```bash sleep 20 ``` Inspect active targets: ```bash curl -fsS http://127.0.0.1:9090/api/v1/targets | \ jq -r '.data.activeTargets[] | [.labels.job, .health, .lastError] | @tsv' ``` Expected health values: ```text prometheus up node_exporter up ``` Confirm Prometheus has actual host metrics: ```bash curl -fsSG http://127.0.0.1:9090/api/v1/query \ --data-urlencode 'query=node_uname_info' | \ jq -r '.data.result | length' ``` The result should be greater than `0`. **Verify:** both scrape targets should report `up` and a Node Exporter query should return at least one result. ## Step 9 — Install Grafana from the official stable APT repository Install the repository prerequisites: ```bash sudo apt-get install -y apt-transport-https wget gnupg ``` Add the Grafana Labs signing key: ```bash sudo mkdir -p /etc/apt/keyrings sudo wget -O /etc/apt/keyrings/grafana.asc https://apt.grafana.com/gpg-full.key sudo chmod 644 /etc/apt/keyrings/grafana.asc ``` Add the stable repository: ```bash echo "deb [signed-by=/etc/apt/keyrings/grafana.asc] https://apt.grafana.com stable main" | \ sudo tee /etc/apt/sources.list.d/grafana.list ``` Install Grafana OSS: ```bash sudo apt-get update sudo apt-get install -y grafana ``` Keep Grafana private by binding it to loopback: ```bash sudo sed -i 's/^;\?http_addr =.*/http_addr = 127.0.0.1/' /etc/grafana/grafana.ini ``` Enable and start Grafana: ```bash sudo systemctl enable --now grafana-server ``` Check its health and listener: ```bash systemctl is-active grafana-server curl -fsS http://127.0.0.1:3000/api/health | jq ss -lntp | grep ':3000' ``` **Verify:** Grafana should be active, its health endpoint should respond, and port 3000 should be bound only to `127.0.0.1`. ## Step 10 — Review UFW safely without risking SSH lockout Because all three monitoring services are already loopback-only, you do not need public firewall rules for `3000`, `9090`, or `9100`. Inspect UFW before changing it: ```bash sudo ufw status verbose ``` Confirm the actual SSH listening port: ```bash sudo sshd -T | awk '/^port / {print $2}' ``` If UFW is already active, verify the existing SSH rule is correct and confirm no monitoring-port allow rules are present: ```bash sudo ufw status numbered ``` If UFW is inactive and you want to enable it, allow the **actual SSH path first**. For standard SSH with the OpenSSH profile: ```bash sudo ufw allow OpenSSH ``` For a custom SSH port, allow that port instead, for example: ```bash sudo ufw allow 2222/tcp ``` Keep your current SSH session open and create a second SSH session to verify access. Only after the second session succeeds should you enable UFW: ```bash sudo ufw enable sudo ufw status numbered ``` Do not add public allow rules for ports 3000, 9090, or 9100. **Verify:** SSH should remain reachable after the firewall change and the monitoring ports should still have no public UFW allow rules. ## Step 11 — Open Grafana through an SSH tunnel From your workstation, create a local tunnel: ```bash ssh -L 3000:127.0.0.1:3000 your-user@your-server-ip ``` Keep the SSH session open and browse to: ```text http://127.0.0.1:3000 ``` Grafana's documented first-login defaults are: ```text Username: admin Password: admin ``` Change the administrator password when prompted. ![Grafana login page on Ubuntu 24.04 after installation](/uploads/prometheus-grafana-ubuntu-24-04-01-grafana-login.webp) The screenshot is preserved from the original Raff-tested workflow. Labels or minor visual details may differ in newer stable Grafana releases, but the first-login flow remains the same. From the server, confirm all monitoring listeners are private: ```bash ss -lntp | grep -E ':3000|:9090|:9100' ``` **Verify:** Grafana should open through the SSH tunnel, and all three monitoring listeners should show `127.0.0.1`. ## Step 12 — Connect Grafana to Prometheus In Grafana, open: ```text Connections → Data sources → Add data source → Prometheus ``` Use this Prometheus server URL: ```text http://127.0.0.1:9090 ``` Click **Save & test**. ![Grafana Prometheus data source showing a successful connection](/uploads/prometheus-grafana-ubuntu-24-04-02-prometheus-data-source.webp) The screenshot is retained from the original tested setup; navigation labels can move between Grafana releases. Verify the same Prometheus API directly from Ubuntu: ```bash curl -fsSG http://127.0.0.1:9090/api/v1/query \ --data-urlencode 'query=up' | jq -r '.status' ``` Expected result: ```text success ``` **Verify:** Grafana should accept the data source and the local Prometheus query should succeed. ## Step 13 — Import a Node Exporter dashboard In Grafana, open: ```text Dashboards → New → Import ``` The original Raff-tested workflow used Grafana.com dashboard ID: ```text 1860 ``` Select your Prometheus data source and import the dashboard. ![Grafana dashboard import screen for Node Exporter Full](/uploads/prometheus-grafana-ubuntu-24-04-03-node-exporter-dashboard-import.webp) Dashboard 1860 is a community dashboard rather than part of Prometheus itself. If it changes or becomes unavailable, the monitoring stack is still valid. Create a simple Grafana panel with a direct PromQL query such as: ```promql 100 - (avg by(instance) (rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100) ``` **Verify:** either the imported dashboard or a manually created panel should return Node Exporter data from Prometheus. ## Step 14 — Verify Prometheus and Grafana end to end Open the Node Exporter dashboard through the SSH tunnel, use a recent time range such as **Last 15 minutes**, and refresh it. ![Grafana Node Exporter dashboard showing live server metrics](/uploads/prometheus-grafana-ubuntu-24-04-04-node-exporter-dashboard.webp) Run the final server checks: ```bash systemctl is-active prometheus systemctl is-active node_exporter systemctl is-active grafana-server prometheus --version | head -n 1 node_exporter --version | head -n 1 curl -fsS http://127.0.0.1:9090/-/ready curl -fsS http://127.0.0.1:9100/metrics >/dev/null curl -fsS http://127.0.0.1:3000/api/health | jq curl -fsS http://127.0.0.1:9090/api/v1/targets | \ jq -r '.data.activeTargets[] | [.labels.job, .health, .lastError] | @tsv' curl -fsSG http://127.0.0.1:9090/api/v1/query \ --data-urlencode 'query=node_uname_info' | \ jq -r '.data.result | length' ss -lntp | grep -E ':3000|:9090|:9100' sudo ufw status numbered ``` In Grafana, confirm that: - You can sign in through the SSH tunnel. - The Prometheus data source passes its connection test. - A Node Exporter dashboard or manual panel displays current host metrics. - The dashboard continues to update as new samples are scraped. End-to-end verification is complete when Prometheus 3.13.2, Node Exporter 1.12.1, and Grafana are active; both Prometheus targets are `up`; Grafana can query Prometheus; live host metrics appear in a dashboard; and ports 3000, 9090, and 9100 remain loopback-only. :::cta Deploy Your Server Deploy an Ubuntu 24.04 Linux VM and use this workflow to build a private Prometheus and Grafana monitoring stack. ::: ## Monitor additional VMs over private network paths The localhost design is intentionally limited to one server. To monitor additional Raff VMs, install Node Exporter on those target machines and make Prometheus reach them over a controlled private path such as a [Raff VPC](/products/vpc). Do not simply bind Node Exporter to `0.0.0.0:9100` and expose it publicly. Decide which interface should listen, restrict network access to the Prometheus server, and add TLS or authentication when the threat model requires it. For multiple production targets, also plan service discovery, alerting, retention, and Prometheus availability rather than treating this single-node tutorial as a complete observability architecture. ## Backup, recovery, and update planning Prometheus configuration is stored under: ```text /etc/prometheus ``` Prometheus time-series data is stored under: ```text /var/lib/prometheus ``` Grafana configuration and local state commonly live under: ```text /etc/grafana /var/lib/grafana ``` Preserve the Prometheus configuration and any Grafana dashboards, provisioning files, and local database state you need to rebuild the monitoring plane. Whether the full Prometheus TSDB must also be recoverable depends on your incident-history and compliance requirements. Raff [Data Protection](/products/data-protection) can provide infrastructure-level recovery for the VM, but snapshots do not replace a deliberate application recovery plan. If Prometheus history matters, define what data must survive and test the recovery process you choose. Before updating Prometheus or Node Exporter, review their release notes, update the pinned version and checksum together, restart the service, and rerun the final verification. Grafana installed through its stable APT repository follows normal package-maintenance updates. ## Troubleshooting ### Prometheus does not start Validate the configuration and inspect the service journal: ```bash promtool check config /etc/prometheus/prometheus.yml sudo journalctl -u prometheus -n 100 --no-pager ``` Check file access: ```bash sudo -u prometheus test -r /etc/prometheus/prometheus.yml && echo readable sudo -u prometheus test -w /var/lib/prometheus && echo writable ``` ### Node Exporter is down in Prometheus Check Node Exporter directly: ```bash systemctl is-active node_exporter curl -fsS http://127.0.0.1:9100/metrics | head ``` Then inspect Prometheus target errors: ```bash curl -fsS http://127.0.0.1:9090/api/v1/targets | \ jq -r '.data.activeTargets[] | [.labels.job, .health, .lastError] | @tsv' ``` ### Grafana does not open through the SSH tunnel Check the local Grafana listener on the server: ```bash systemctl is-active grafana-server curl -fsS http://127.0.0.1:3000/api/health | jq ss -lntp | grep ':3000' ``` Recreate the workstation tunnel: ```bash ssh -L 3000:127.0.0.1:3000 your-user@your-server-ip ``` Then browse to `http://127.0.0.1:3000`. ### Grafana cannot query Prometheus Check Prometheus readiness and query the API from the same host: ```bash curl -fsS http://127.0.0.1:9090/-/ready curl -fsSG http://127.0.0.1:9090/api/v1/query \ --data-urlencode 'query=up' | jq ``` For this same-VM deployment, the Grafana data source URL should remain `http://127.0.0.1:9090`. ### The dashboard opens but panels show no data Confirm that Node Exporter samples exist: ```bash curl -fsSG http://127.0.0.1:9090/api/v1/query \ --data-urlencode 'query=node_uname_info' | \ jq -r '.data.result | length' ``` A result greater than `0` proves that Prometheus has Node Exporter data. Then verify the Grafana panel uses the intended Prometheus data source and a time range that includes recent samples. ### Prometheus disk usage grows too quickly Check the TSDB and free disk space: ```bash sudo du -sh /var/lib/prometheus df -h / ``` Scrape frequency, target count, metric cardinality, and retention all affect disk usage. Do not reduce retention only to silence a disk alert; first decide how much monitoring history your incident and operations process actually requires. ### Enabling UFW could disconnect SSH Do not enable UFW from a single remote session until you have confirmed the actual SSH port and added the matching allow rule. Keep the current session open, verify a second SSH connection, and use a provider console or other recovery path when available. ## Cleanup and rollback For a reversible shutdown, stop the monitoring services without deleting data: ```bash sudo systemctl stop grafana-server prometheus node_exporter ``` Restart them later with: ```bash sudo systemctl start node_exporter prometheus grafana-server ``` For permanent decommissioning, back up any Grafana state and Prometheus data you need before removing packages, binaries, unit files, `/etc/prometheus`, `/var/lib/prometheus`, `/etc/grafana`, or `/var/lib/grafana`. Do not remove unrelated SSH or firewall configuration as part of monitoring cleanup. ## Conclusion You now have a current Prometheus and Grafana monitoring stack for Ubuntu 24.04. Prometheus 3.13.2 runs on the supported LTS line, Node Exporter supplies host metrics, Grafana queries Prometheus locally, and all three monitoring web interfaces stay bound to localhost. The workflow also avoids blind firewall activation, keeps the existing SSH-tunnel security model, and leaves a clear path to multi-VM monitoring over private networking when the single-host pattern is no longer enough. ## Sources - Prometheus documentation — downloads, LTS release cycle, configuration, and Node Exporter guide - Prometheus GitHub releases — Prometheus 3.13.2 and Node Exporter 1.12.1 checksums and release status - Grafana documentation — Debian/Ubuntu APT installation, server configuration, and first sign-in - Guidance re-verified: 2026-09-07 --- ### How to Deploy Next.js on Ubuntu 24.04 with PM2 and Nginx URL: https://rafftechnologies.com/learn/tutorials/deploy-nextjs-ubuntu-24-04-pm2-nginx Description: Deploy a Next.js app on Ubuntu 24.04 with Node.js 24 LTS, PM2, Nginx, HTTPS, loopback-only app ports, reboot persistence, and production checks. To **deploy a Next.js app on Ubuntu 24.04**, build the application with a supported Node.js LTS release, run the production server as a supervised process, bind it to localhost, and place Nginx in front for public HTTP/HTTPS traffic. This tutorial uses **Node.js 24 LTS**, **PM2**, **Nginx**, and Certbot to build that single-server production baseline. Raff Technologies is used as the Ubuntu VM platform in the saved test workflow. The Next.js application itself listens only on `127.0.0.1:3000`; Nginx is the public edge. This matches current Next.js self-hosting guidance, which recommends a reverse proxy rather than exposing the Next.js server directly to the internet. As of September 7, 2026, the current Node.js 24 LTS release is **24.20.0** and the current stable Next.js documentation version is **16.3.4**. Next.js 16.x is Active LTS, while 15.x is Maintenance LTS. Your production deployment should still use the Next.js version pinned by the application's lockfile rather than turning a server migration into an unplanned framework upgrade. The original workflow was tested on a Raff Ubuntu 24.04 VM with 1 vCPU and 2 GB RAM. Node.js 24.20.0 LTS, Next.js 16.3.4 self-hosting behavior, and PM2 startup guidance were documentation-reviewed for this refresh; no new full machine retest is claimed. Prerequisites: - A [Raff Linux VM](/products/linux-vm) running Ubuntu 24.04 - SSH access with a non-root sudo user - A Next.js application in a Git repository - A lockfile such as `package-lock.json` if you plan to use `npm ci` - A domain pointed to the VM for production HTTPS - Ports `80/tcp` and `443/tcp` available for Nginx - A recovery path before enabling or changing firewall rules ## Step 1 — Prepare Ubuntu, DNS, and UFW safely Update Ubuntu and install the base packages: ```bash sudo apt update sudo apt upgrade -y sudo apt install -y git curl ca-certificates nginx ufw dnsutils ``` Check whether the upgrade requires a reboot: ```bash test -f /var/run/reboot-required && cat /var/run/reboot-required ``` If a reboot is required, perform it during a safe maintenance window before continuing. Point your domain's `A` record to the VM's public IPv4 address. Add an `AAAA` record only when IPv6 is configured and reachable on this VM. Verify DNS: ```bash dig +short A your-domain.com ``` Inspect UFW before changing it: ```bash sudo ufw status verbose ``` Confirm the actual SSH port: ```bash sudo sshd -T | awk '/^port / {print $2}' ``` If UFW is already active, keep the existing SSH rule and allow Nginx: ```bash sudo ufw allow 'Nginx Full' sudo ufw status numbered ``` If UFW is inactive, allow the **actual SSH path first**. For standard SSH with the OpenSSH profile: ```bash sudo ufw allow OpenSSH ``` For a custom SSH port, allow that port instead, for example: ```bash sudo ufw allow 2222/tcp ``` Then allow Nginx: ```bash sudo ufw allow 'Nginx Full' ``` Keep the current SSH session open and successfully open a second SSH session before enabling an inactive firewall: ```bash sudo ufw enable sudo ufw status numbered ``` Do not use `ufw --force enable` as a shortcut around SSH-path verification. **Verify:** DNS should resolve to the intended VM, Nginx should be active, the actual SSH path should remain reachable, and UFW should allow only the public services you intend to expose. ## Step 2 — Install Node.js 24 LTS with NVM Node.js currently provides **24.20.0** as the latest v24 LTS release. Install NVM with the current installer shown by Node.js: ```bash curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.7/install.sh | bash ``` Load NVM into the current shell: ```bash export NVM_DIR="$HOME/.nvm" [ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh" ``` Install Node.js 24 and make it the default for this user: ```bash nvm install 24 nvm alias default 24 nvm use 24 ``` Check the installed versions: ```bash node --version npm --version nvm current ``` The exact patch can increase later, but on September 7, 2026 the current v24 LTS release is `v24.20.0`. **Verify:** `node --version` and `nvm current` should report the same Node.js 24 branch. ## Step 3 — Clone the Next.js application and install locked dependencies Create the application directory: ```bash sudo mkdir -p /var/www/nextjs sudo chown "$USER":"$USER" /var/www/nextjs cd /var/www/nextjs ``` Clone your repository: ```bash git clone https://github.com/your-username/your-nextjs-repo.git . ``` If the repository uses npm and contains `package-lock.json`, install the locked dependency graph: ```bash npm ci ``` Inspect the installed Next.js version: ```bash npm ls next ``` Next.js 16.x is the current Active LTS major. The official documentation is on 16.3.4 as of this refresh, but do not replace the application's tested lockfile version merely because a newer release exists. **Verify:** `package.json` and the expected lockfile should exist, `npm ci` should complete successfully, and `npm ls next` should resolve the project's installed Next.js version. ## Step 4 — Configure production environment variables Next.js supports both build-time and runtime environment variables. Variables prefixed with `NEXT_PUBLIC_` are exposed to the browser and are inlined into client JavaScript during `next build`, so never store secrets in a public variable. Create a production-local environment file if your application requires one: ```bash cd /var/www/nextjs nano .env.production.local ``` Example: ```dotenv DATABASE_URL=your_server_side_database_url APP_SECRET=your_server_side_secret NEXT_PUBLIC_APP_URL=https://your-domain.com ``` Protect it: ```bash chmod 600 .env.production.local ``` Check that local environment files are ignored by Git: ```bash grep -E '^\.env|\.env\*' .gitignore || true git status --short ``` Add an appropriate ignore rule if your repository does not already exclude the file. **Verify:** if `.env.production.local` exists, it should have mode `600`, secrets should not use the `NEXT_PUBLIC_` prefix, and the file should not be staged for commit. ## Step 5 — Build the Next.js production application Build the application with its required environment already in place: ```bash cd /var/www/nextjs npm run build ``` A successful build creates the `.next` directory. When troubleshooting, inspect the framework and environment instead of assuming every failed build is a VM-size problem: ```bash npx next info ``` Check the build output without running the build a second time: ```bash test -d .next && echo ".next build directory exists" test -f package.json && echo "package.json found" ``` **Verify:** `npm run build` should finish without a fatal error and `.next` should exist afterward. ## Step 6 — Test the Next.js production server on localhost only For this architecture, the application server should not be the public endpoint. Start it on loopback: ```bash cd /var/www/nextjs npm run start -- --hostname 127.0.0.1 --port 3000 ``` In a second SSH session, inspect the listener: ```bash sudo ss -lntp | grep ':3000' ``` The expected bind is: ```text 127.0.0.1:3000 ``` Test the local application: ```bash curl -I http://127.0.0.1:3000 ``` Stop the manual process with `Ctrl+C` after the test. **Verify:** the local HTTP request should succeed and port 3000 should not listen on `0.0.0.0`. ## Step 7 — Run Next.js with PM2 Install PM2 under the same Node.js/NVM user that owns the application process: ```bash npm install -g pm2 ``` Create `/var/www/nextjs/ecosystem.config.cjs`: ```bash nano /var/www/nextjs/ecosystem.config.cjs ``` Use one process as the baseline: ```javascript module.exports = { apps: [ { name: 'nextjs-app', cwd: '/var/www/nextjs', script: 'npm', args: [ 'start', '--', '--hostname', '127.0.0.1', '--port', '3000' ], instances: 1, exec_mode: 'fork', watch: false, env: { NODE_ENV: 'production' } } ] } ``` Start the process: ```bash cd /var/www/nextjs pm2 start ecosystem.config.cjs ``` Inspect status and recent logs: ```bash pm2 status pm2 logs nextjs-app --lines 50 --nostream ``` A single instance is intentional. Current Next.js self-hosting guidance says caches are local to each instance by default, and multi-instance App Router deployments require additional coordination for cache tags, shared cache state, deployment versions, and related behavior. For PM2-specific operations, see [How to Install PM2 and Deploy Node.js on Ubuntu 24.04](/learn/tutorials/deploy-nodejs-pm2-ubuntu-24-04). **Verify:** `nextjs-app` should be online, `curl -I http://127.0.0.1:3000` should succeed, and port 3000 should remain loopback-only. ## Step 8 — Configure PM2 reboot persistence Generate PM2's startup integration as the application user: ```bash pm2 startup ``` PM2 prints a customized `sudo env PATH=... pm2 startup systemd ...` command. Run the exact command it prints rather than copying a hard-coded path from another server. Save the process list: ```bash pm2 save ``` Find the generated systemd service: ```bash systemctl list-unit-files | grep '^pm2-' ``` PM2 documents that after changing the Node.js version, you should regenerate the startup integration so its PATH points to the current Node.js binary. **Verify:** the PM2 systemd service for your user should be enabled and `pm2 save` should complete successfully. ## Step 9 — Configure Nginx as the public reverse proxy Create the site configuration: ```bash sudo nano /etc/nginx/sites-available/nextjs ``` Add: ```nginx server { listen 80; listen [::]:80; server_name your-domain.com www.your-domain.com; location / { proxy_pass http://127.0.0.1:3000; proxy_http_version 1.1; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_buffering off; proxy_read_timeout 60s; proxy_connect_timeout 10s; } } ``` Next.js recommends a reverse proxy for self-hosting. App Router streaming also requires the proxy path not to buffer the response. `proxy_buffering off` provides that behavior at this Nginx layer. Do not invent a separate one-year cache rule for `/_next/static/`. Next.js already sets immutable caching headers for truly immutable hashed assets. Enable the site: ```bash sudo ln -sf /etc/nginx/sites-available/nextjs \ /etc/nginx/sites-enabled/nextjs sudo rm -f /etc/nginx/sites-enabled/default ``` Validate before reloading: ```bash sudo nginx -t sudo systemctl reload nginx ``` Test the proxy locally with the production Host header: ```bash curl -I http://127.0.0.1 -H 'Host: your-domain.com' ``` **Verify:** `nginx -t` should succeed and the Host-header request should return the Next.js application through Nginx. ## Step 10 — Enable HTTPS with Certbot Install Certbot and its Nginx plugin: ```bash sudo apt install -y certbot python3-certbot-nginx ``` Request a certificate after public DNS points to the VM and port 80 is reachable: ```bash sudo certbot --nginx --redirect \ -d your-domain.com \ -d www.your-domain.com ``` If you do not use `www`, omit it from DNS, Nginx, and Certbot. Inspect the certificate and test renewal: ```bash sudo certbot certificates sudo certbot renew --dry-run ``` For certificate troubleshooting, continue with [Secure Nginx with Let's Encrypt on Ubuntu 24.04](/learn/tutorials/secure-nginx-lets-encrypt-ubuntu-24-04). **Verify:** HTTP should redirect to HTTPS, the HTTPS request should succeed, and the renewal dry run should pass. ## Step 11 — Verify reboot persistence Save the final PM2 process list: ```bash pm2 save ``` Reboot during a maintenance window: ```bash sudo reboot ``` After reconnecting, verify PM2, the local app, and the public endpoint: ```bash pm2 status curl -I http://127.0.0.1:3000 curl -I https://your-domain.com ``` If the process did not return, inspect the PM2 service: ```bash systemctl list-units --type=service | grep pm2 systemctl --failed ``` **Verify:** `nextjs-app` should return as online after reboot, port 3000 should respond locally, and the public HTTPS endpoint should work without a manual `pm2 start`. ## Step 12 — Verify the Next.js deployment end to end Run the final checks: ```bash printf 'Node.js:\n' node --version printf '\nNext.js:\n' cd /var/www/nextjs npm ls next printf '\nPM2:\n' pm2 status printf '\nLocal Next.js:\n' curl -I http://127.0.0.1:3000 printf '\nListening socket:\n' sudo ss -lntp | grep ':3000' printf '\nNginx config:\n' sudo nginx -t printf '\nHTTP redirect:\n' curl -I http://your-domain.com printf '\nHTTPS response:\n' curl -I https://your-domain.com printf '\nFirewall:\n' sudo ufw status numbered ``` In the application and browser, confirm that: - the intended production build is being served; - PM2 reports `nextjs-app` as online; - Next.js listens only on `127.0.0.1:3000`; - Nginx passes its configuration test; - HTTP redirects to HTTPS; - HTTPS serves the application successfully; - port 3000 has no public UFW allow rule; - the application returns after reboot; and - streaming routes, if your app uses them, are not unintentionally buffered by Nginx. End-to-end verification is complete when the complete request path — browser → HTTPS/Nginx → loopback Next.js → PM2-managed process — works after a reboot without exposing the application port publicly. :::cta Deploy Your Server Launch an Ubuntu 24.04 Linux VM and use this Next.js deployment pattern with PM2, Nginx, HTTPS, and a private application port. ::: ## Update the Next.js application safely For the single-process baseline in this tutorial: ```bash cd /var/www/nextjs git pull --ff-only npm ci npm run build pm2 restart nextjs-app pm2 save ``` This sequence does not claim zero downtime. PM2 cluster reloads and multi-instance Next.js deployments require deliberate cache, version-skew, revalidation, and graceful-shutdown design. Before changing the Next.js major or minor version, inspect what the application actually uses: ```bash npm ls next npm outdated next || true ``` Test framework upgrades in staging before production. ## Roll back or remove the deployment For an application rollback, prefer a known-good Git revision and rebuild it using your normal release process: ```bash cd /var/www/nextjs git log --oneline -n 10 npm ci npm run build pm2 restart nextjs-app ``` To remove only this PM2 application: ```bash pm2 delete nextjs-app pm2 save ``` Remove the Nginx site: ```bash sudo rm -f /etc/nginx/sites-enabled/nextjs sudo rm -f /etc/nginx/sites-available/nextjs sudo nginx -t sudo systemctl reload nginx ``` Review certificates before deleting TLS material: ```bash sudo certbot certificates ``` Delete `/var/www/nextjs` only when source files, generated files, uploads, and environment configuration are no longer required. ## Troubleshooting ### npm run build fails Inspect the actual runtime and framework first: ```bash node --version npm --version npm ls next npx next info ``` Use the application's reported compiler, dependency, TypeScript, environment, or memory error rather than assuming every failure is caused by VM size. ### PM2 starts but Next.js immediately exits Inspect the logs: ```bash pm2 logs nextjs-app --lines 100 --nostream ``` Check that a production build exists and port 3000 is free: ```bash test -d /var/www/nextjs/.next && echo build-present sudo ss -lntp | grep ':3000' || true ``` ### Port 3000 listens on 0.0.0.0 Inspect the PM2 process: ```bash pm2 describe nextjs-app ``` Restart from the ecosystem file: ```bash cd /var/www/nextjs pm2 delete nextjs-app pm2 start ecosystem.config.cjs pm2 save ``` Verify `127.0.0.1:3000` is the intended listener. ### Nginx returns 502 Bad Gateway Verify the application first: ```bash pm2 status curl -I http://127.0.0.1:3000 pm2 logs nextjs-app --lines 50 --nostream ``` Then inspect Nginx: ```bash sudo nginx -t sudo tail -n 50 /var/log/nginx/error.log ``` A 502 usually means Nginx cannot reach the application or the upstream process is failing. ### Streaming responses are delayed Confirm Nginx buffering is disabled for the application location: ```bash sudo nginx -T 2>/dev/null | grep -n 'proxy_buffering' ``` The current Next.js self-hosting guidance requires buffering to be disabled somewhere in the proxy path for streaming responses to work as intended. ### The application does not return after reboot Inspect the generated PM2 integration: ```bash systemctl list-unit-files | grep '^pm2-' systemctl --failed ``` If Node.js was upgraded through NVM after PM2 startup integration was generated, recreate it: ```bash pm2 unstartup pm2 startup pm2 save ``` Run the exact `sudo` commands printed by PM2 when prompted. ### Multiple PM2 instances serve inconsistent cached data Return to one process while designing a shared cache and tag-invalidation strategy. Current Next.js self-hosting guidance notes that cache state is local per instance by default and `revalidateTag()` on one instance does not automatically invalidate every other instance. Set the ecosystem file back to: ```javascript instances: 1, exec_mode: 'fork' ``` Then restart the process. ## Conclusion You deployed a Next.js application on Ubuntu 24.04 using Node.js 24 LTS, PM2, Nginx, HTTPS, and a loopback-only application port. The deployment also verifies reboot recovery and keeps firewall activation separate from unsafe copy-paste shortcuts. The main production boundary is simple: Nginx owns the public edge, while `next start` stays private. When the architecture grows beyond one Next.js process, treat shared caching, cache-tag invalidation, deployment versioning, streaming, and graceful shutdown as explicit design requirements rather than assuming PM2 cluster mode solves them automatically. For adjacent operations, continue with [Install PM2 on Ubuntu 24.04](/learn/tutorials/deploy-nodejs-pm2-ubuntu-24-04), [Install Nginx on Ubuntu 24.04](/learn/tutorials/install-nginx-ubuntu-24-04), and [Secure Nginx with Let's Encrypt](/learn/tutorials/secure-nginx-lets-encrypt-ubuntu-24-04). ## Sources - Next.js Docs — Self-Hosting, support policy, and current 16.3.4 documentation - Node.js — v24.20.0 LTS download and release schedule - PM2 — startup scripts and saved process restoration - Guidance re-verified: 2026-09-07 --- ### FastAPI Deployment on Ubuntu 24.04 with Uvicorn and Nginx URL: https://rafftechnologies.com/learn/tutorials/deploy-fastapi-ubuntu-24-04 Description: Deploy FastAPI on Ubuntu 24.04 with Python 3.12, Uvicorn, systemd, Nginx, trusted proxy headers, HTTPS, safe UFW setup, and reboot verification. A reliable **FastAPI deployment on Ubuntu 24.04** uses four clear boundaries: a Python virtual environment for dependencies, Uvicorn for the ASGI application server, systemd for process supervision, and Nginx for the public HTTP/HTTPS edge. In this tutorial, Uvicorn listens only on `127.0.0.1:8000`; port 8000 is never opened to the internet. Raff Technologies is used as the Ubuntu VM platform in the saved test workflow. The original deployment was tested on a Raff Ubuntu 24.04 VM with 1 vCPU and 2 GB RAM. For this refresh, the current package and deployment guidance was re-verified rather than claiming a new full machine test. As of September 7, 2026, the latest PyPI releases verified for this guide are **FastAPI 0.141.1** and **Uvicorn 0.52.4**. Ubuntu 24.04 remains on the Python **3.12** branch; the Noble Updates package is currently based on Python `3.12.3`. For a real application, use the dependency versions you have tested and locked instead of upgrading production dependencies blindly during server setup. Prerequisites: - A [Raff Linux VM](/products/linux-vm) running Ubuntu 24.04 - SSH access with a non-root sudo user - A domain pointed to the VM if you want public HTTPS - Ports `80/tcp` and `443/tcp` available for Nginx - A recovery path before enabling or changing UFW - No public firewall rule for port `8000` ## Step 1 — Install Python, Nginx, and firewall tools Update Ubuntu and install the required packages: ```bash sudo apt update sudo apt upgrade -y sudo apt install -y python3 python3-venv python3-pip nginx ufw curl ``` Check the installed Python and Ubuntu package revision: ```bash python3 --version apt-cache policy python3.12 | sed -n '1,8p' ``` Ubuntu 24.04 uses Python 3.12 as its default Python branch. The exact Ubuntu package revision can increase through security and maintenance updates. Inspect UFW before changing it: ```bash sudo ufw status verbose ``` Confirm the SSH port the server is actually configured to use: ```bash sudo sshd -T | awk '/^port / {print $2}' ``` If UFW is already active, preserve the working SSH rule and allow Nginx: ```bash sudo ufw allow 'Nginx Full' sudo ufw status numbered ``` If UFW is inactive, allow the real SSH path first. For standard SSH with the OpenSSH profile: ```bash sudo ufw allow OpenSSH ``` For a custom SSH port, allow that port instead, for example: ```bash sudo ufw allow 2222/tcp ``` Then allow Nginx: ```bash sudo ufw allow 'Nginx Full' ``` Keep the current SSH session open and successfully open a second SSH session before enabling an inactive firewall: ```bash sudo ufw enable sudo ufw status numbered ``` Do not use `ufw --force enable` to bypass this safety check. **Verify:** Python should report 3.12.x, Nginx should be active, the actual SSH path should remain reachable, and UFW should allow only the public services you intend to expose. ## Step 2 — Create a dedicated FastAPI service user and application directory Create a system account that cannot log in interactively: ```bash sudo useradd --system --no-create-home --shell /usr/sbin/nologin fastapi ``` Create the application directory: ```bash sudo mkdir -p /srv/fastapi-app sudo chown -R fastapi:fastapi /srv/fastapi-app sudo chmod 750 /srv/fastapi-app ``` A dedicated service account limits what the application process can access compared with running it as root or as a general administrator account. **Verify:** ```bash getent passwd fastapi stat -c '%U:%G %a %n' /srv/fastapi-app ``` The account should use a non-login shell and `/srv/fastapi-app` should be owned by `fastapi:fastapi`. ## Step 3 — Create a virtual environment and install FastAPI with Uvicorn Create an isolated Python environment: ```bash sudo -u fastapi python3 -m venv /srv/fastapi-app/.venv ``` For this reproducible demo, install the versions verified during this refresh: ```bash sudo -u fastapi /srv/fastapi-app/.venv/bin/python -m pip install --upgrade pip sudo -u fastapi /srv/fastapi-app/.venv/bin/python -m pip install \ 'fastapi[standard]==0.141.1' \ 'uvicorn[standard]==0.52.4' ``` A real application should normally install from its tested requirements or lockfile instead. Keeping packages inside the virtual environment avoids modifying Ubuntu's externally managed system Python. For Python isolation details, see [Install pip on Ubuntu 24.04 and Use Python venv](/learn/tutorials/install-python-pip-ubuntu-24-04). **Verify:** ```bash sudo -u fastapi /srv/fastapi-app/.venv/bin/python -c \ 'import fastapi, uvicorn; print("FastAPI", fastapi.__version__); print("Uvicorn", uvicorn.__version__)' ``` The demo environment should report FastAPI `0.141.1` and Uvicorn `0.52.4`. ## Step 4 — Create a minimal FastAPI application and health endpoint Create `/srv/fastapi-app/main.py`: ```bash sudo tee /srv/fastapi-app/main.py > /dev/null <<'PY' from fastapi import FastAPI app = FastAPI(title="Example API") @app.get("/") async def root(): return {"status": "ok"} @app.get("/health") async def health(): return {"status": "healthy"} PY ``` Set ownership and permissions: ```bash sudo chown fastapi:fastapi /srv/fastapi-app/main.py sudo chmod 640 /srv/fastapi-app/main.py ``` **Verify:** ```bash sudo -u fastapi /srv/fastapi-app/.venv/bin/python -m py_compile \ /srv/fastapi-app/main.py ``` The command should exit without a syntax error. ## Step 5 — Test Uvicorn on localhost only Start the application manually before creating a service: ```bash cd /srv/fastapi-app sudo -u fastapi ./.venv/bin/uvicorn main:app \ --host 127.0.0.1 \ --port 8000 ``` In a second SSH session, inspect the listener: ```bash sudo ss -lntp | grep ':8000' ``` Test the health endpoint: ```bash curl -sS http://127.0.0.1:8000/health ``` Expected response: ```json {"status":"healthy"} ``` Stop the manual process with `Ctrl+C` after the test. **Verify:** Uvicorn should respond locally on `127.0.0.1:8000`, and `ss` should not show `0.0.0.0:8000`. ## Step 6 — Create a protected environment file Create a configuration directory outside the source tree: ```bash sudo install -d -m 750 -o root -g fastapi /etc/fastapi ``` Create an environment file: ```bash sudo tee /etc/fastapi/fastapi.env > /dev/null <<'EOF' APP_ENV=production APP_SECRET=replace-with-a-real-secret EOF ``` Restrict it: ```bash sudo chown root:fastapi /etc/fastapi/fastapi.env sudo chmod 640 /etc/fastapi/fastapi.env ``` Do not commit secrets to Git or place them in Nginx configuration. **Verify:** ```bash stat -c '%U:%G %a %n' /etc/fastapi/fastapi.env ``` The expected ownership is `root:fastapi` with mode `640`. ## Step 7 — Create the FastAPI systemd service Create `/etc/systemd/system/fastapi.service`: ```bash sudo tee /etc/systemd/system/fastapi.service > /dev/null <<'EOF' [Unit] Description=FastAPI application After=network.target [Service] Type=simple User=fastapi Group=fastapi WorkingDirectory=/srv/fastapi-app EnvironmentFile=/etc/fastapi/fastapi.env ExecStart=/srv/fastapi-app/.venv/bin/uvicorn main:app --host 127.0.0.1 --port 8000 --proxy-headers --forwarded-allow-ips=127.0.0.1 Restart=on-failure RestartSec=5 NoNewPrivileges=true PrivateTmp=true ProtectHome=true ProtectSystem=strict ProtectKernelTunables=true ProtectControlGroups=true RestrictSUIDSGID=true [Install] WantedBy=multi-user.target EOF ``` The proxy options are deliberately restrictive. FastAPI documents forwarded headers such as `X-Forwarded-For`, `X-Forwarded-Proto`, and `X-Forwarded-Host`, but the application server should trust them only from a known proxy. Here Nginx and Uvicorn run on the same VM, so the trusted proxy address is `127.0.0.1`. If your real application writes uploads, generated files, SQLite data, or other local state, grant only the required writable paths instead of weakening the entire systemd sandbox. Reload systemd and start the service: ```bash sudo systemctl daemon-reload sudo systemctl enable --now fastapi ``` **Verify:** ```bash sudo systemctl is-active fastapi sudo systemctl is-enabled fastapi curl -sS http://127.0.0.1:8000/health ``` The service should be active, enabled, and healthy on localhost. ## Step 8 — Inspect FastAPI service logs Read recent logs: ```bash sudo journalctl -u fastapi -n 50 --no-pager ``` Follow logs while troubleshooting: ```bash sudo journalctl -u fastapi -f ``` Inspect the exact unit and process state: ```bash sudo systemctl cat fastapi sudo systemctl show fastapi -p MainPID -p ExecMainStatus -p NRestarts ``` **Verify:** the journal should show a successful Uvicorn startup without a repeated crash/restart loop. ## Step 9 — Configure Nginx as the FastAPI reverse proxy Create the Nginx site: ```bash sudo tee /etc/nginx/sites-available/fastapi > /dev/null <<'EOF' server { listen 80; listen [::]:80; server_name your-domain.com; location / { proxy_pass http://127.0.0.1:8000; proxy_http_version 1.1; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Forwarded-Host $host; proxy_connect_timeout 10s; proxy_read_timeout 60s; } } EOF ``` `X-Forwarded-Host` is included explicitly because current FastAPI proxy guidance identifies host, protocol, and client-address forwarding as part of the original request information that may need to be preserved behind a proxy. Do not add WebSocket `Upgrade` headers unless your application actually serves WebSocket endpoints. Enable the site: ```bash sudo ln -sf /etc/nginx/sites-available/fastapi \ /etc/nginx/sites-enabled/fastapi sudo rm -f /etc/nginx/sites-enabled/default sudo nginx -t sudo systemctl reload nginx ``` For Nginx fundamentals, see [Install Nginx on Ubuntu 24.04](/learn/tutorials/install-nginx-ubuntu-24-04). **Verify:** ```bash curl -sS http://127.0.0.1/health -H 'Host: your-domain.com' sudo nginx -t ``` Nginx should return the FastAPI health response and the configuration test should pass. ## Step 10 — Decide whether FastAPI docs should be public FastAPI exposes Swagger UI at `/docs` and the OpenAPI schema at `/openapi.json` by default. Public developer APIs may intentionally expose them, while private APIs may restrict them. If documentation should remain public, the main Nginx proxy is enough. If it should be private, prefer application authentication or an intentional application configuration. A simple proxy-level deny can also hide the endpoints from public traffic: ```nginx location = /docs { return 404; } location = /openapi.json { return 404; } ``` Hiding documentation is not a replacement for API authentication and authorization. **Verify:** request `/docs` and `/openapi.json` from the public side and confirm the result matches your intended exposure policy. ## Step 11 — Enable HTTPS with Certbot Make sure DNS points to this VM and port 80 is publicly reachable, then install Certbot: ```bash sudo apt install -y certbot python3-certbot-nginx ``` Request the certificate and redirect HTTP to HTTPS: ```bash sudo certbot --nginx --redirect -d your-domain.com ``` Inspect the certificate and test renewal: ```bash sudo certbot certificates sudo certbot renew --dry-run ``` For ACME troubleshooting, use [Secure Nginx with Let's Encrypt on Ubuntu 24.04](/learn/tutorials/secure-nginx-lets-encrypt-ubuntu-24-04). **Verify:** ```bash curl -I http://your-domain.com/health curl -sS https://your-domain.com/health ``` HTTP should redirect to HTTPS and the HTTPS health endpoint should return `{"status":"healthy"}`. ## Step 12 — Add Uvicorn workers only after measuring the application FastAPI currently supports multiple worker processes directly through the FastAPI or Uvicorn CLI. Gunicorn is not required simply to use more CPU cores. For example, a two-worker Uvicorn command is: ```bash /srv/fastapi-app/.venv/bin/uvicorn main:app \ --host 127.0.0.1 \ --port 8000 \ --workers 2 \ --proxy-headers \ --forwarded-allow-ips=127.0.0.1 ``` Do not use a universal workers-per-CPU formula. Each worker is a separate process with its own application memory, database connections, and startup work. Measure CPU, memory, latency, throughput, and connection-pool pressure before changing the worker count. Older guides often use `uvicorn.workers.UvicornWorker` with Gunicorn. Uvicorn currently marks the built-in `uvicorn.workers` module as deprecated. If your organization chooses Gunicorn for process-management features, verify the current supported worker package and compatibility instead of copying that deprecated import path. **Verify:** after any worker-count change, confirm the expected process count, service health, and public endpoint: ```bash ps -ef | grep '[u]vicorn' sudo systemctl is-active fastapi curl -sS https://your-domain.com/health ``` ## Step 13 — Verify the FastAPI deployment end to end and after reboot Check the complete stack: ```bash printf 'Python:\n' python3 --version printf '\nFastAPI and Uvicorn:\n' sudo -u fastapi /srv/fastapi-app/.venv/bin/python -c \ 'import fastapi, uvicorn; print(fastapi.__version__, uvicorn.__version__)' printf '\nFastAPI service:\n' sudo systemctl is-active fastapi sudo systemctl is-enabled fastapi printf '\nLocal health:\n' curl -sS http://127.0.0.1:8000/health printf '\nListener:\n' sudo ss -lntp | grep ':8000' printf '\nNginx:\n' sudo nginx -t printf '\nHTTPS:\n' curl -sS https://your-domain.com/health printf '\nFirewall:\n' sudo ufw status numbered ``` Confirm that: - Python is on the intended Ubuntu 3.12 branch; - the virtual environment contains the dependency versions you tested; - `fastapi.service` is active and enabled; - Uvicorn listens only on `127.0.0.1:8000`; - Nginx passes its configuration test; - HTTPS serves the expected health response; - port 8000 has no public firewall rule; and - forwarded headers are trusted only from the intended proxy path. Then reboot during a maintenance window: ```bash sudo reboot ``` After reconnecting: ```bash sudo systemctl is-active fastapi nginx curl -sS http://127.0.0.1:8000/health curl -sS https://your-domain.com/health ``` End-to-end verification is complete when FastAPI and Nginx return automatically after reboot, the API is healthy over HTTPS, and Uvicorn remains private on loopback. :::cta Deploy Your Server Launch an Ubuntu 24.04 Linux VM and deploy FastAPI behind a private Uvicorn listener, systemd, Nginx, and HTTPS. ::: ## Update the FastAPI application safely Use your application's tested dependency file or lock process. With a requirements file, a simple deployment flow can be: ```bash sudo -u fastapi /srv/fastapi-app/.venv/bin/python -m pip install \ -r /srv/fastapi-app/requirements.txt sudo -u fastapi /srv/fastapi-app/.venv/bin/python -m compileall -q \ /srv/fastapi-app sudo systemctl restart fastapi ``` Check the service immediately after restart: ```bash sudo journalctl -u fastapi -n 50 --no-pager curl -sS https://your-domain.com/health ``` If the release fails, restore the previously tested code and dependency state before restarting again. ## Cleanup Stop future application starts: ```bash sudo systemctl disable --now fastapi sudo rm -f /etc/systemd/system/fastapi.service sudo systemctl daemon-reload ``` Remove the Nginx site: ```bash sudo rm -f /etc/nginx/sites-enabled/fastapi sudo rm -f /etc/nginx/sites-available/fastapi sudo nginx -t sudo systemctl reload nginx ``` Review certificates before deleting TLS material: ```bash sudo certbot certificates ``` Delete application files, secrets, and the service account only when you have confirmed nothing must be retained: ```bash sudo rm -rf /srv/fastapi-app sudo rm -rf /etc/fastapi sudo userdel fastapi ``` ## Troubleshooting ### `externally-managed-environment` appears during pip install You are probably installing into Ubuntu's system Python instead of the application virtual environment. Use: ```bash /srv/fastapi-app/.venv/bin/python -m pip install ``` Do not use `sudo pip install` as the normal fix. ### fastapi.service enters a restart loop Read the journal: ```bash sudo journalctl -u fastapi -n 100 --no-pager ``` Then test the exact Uvicorn command manually as the `fastapi` service user. ### Nginx returns 502 Bad Gateway Test Uvicorn directly: ```bash curl -v http://127.0.0.1:8000/health sudo systemctl status fastapi --no-pager sudo journalctl -u fastapi -n 50 --no-pager ``` If localhost works, inspect Nginx: ```bash sudo nginx -t sudo tail -n 50 /var/log/nginx/error.log ``` ### HTTPS redirects use the wrong scheme or host Confirm the Nginx forwarded headers and the Uvicorn trust boundary: ```bash sudo nginx -T 2>/dev/null | grep -E 'X-Forwarded-(For|Proto|Host)' sudo systemctl cat fastapi ``` Nginx should send the original request information, while Uvicorn should trust forwarded headers only from the intended proxy address. ### WebSockets fail through Nginx Only add WebSocket forwarding when your application actually has WebSocket endpoints. A WebSocket location needs `Upgrade` and `Connection` handling in addition to normal HTTP proxying; do not add those headers universally to a plain HTTP API. ### More workers make performance worse Reduce the worker count and measure again. Workers duplicate memory, database pools, and application startup resources. Worker count is an application-capacity decision, not a fixed CPU formula. ## Conclusion This FastAPI deployment keeps the public and application layers separate: Nginx owns ports 80 and 443, while Uvicorn stays on `127.0.0.1:8000` under systemd. The setup also uses a dedicated service account, a Python virtual environment, restricted proxy-header trust, HTTPS, reboot verification, and a lockout-safe UFW procedure. For adjacent operations, continue with [Install pip and Python venv on Ubuntu 24.04](/learn/tutorials/install-python-pip-ubuntu-24-04), [Install Nginx on Ubuntu 24.04](/learn/tutorials/install-nginx-ubuntu-24-04), and [Secure Nginx with Let's Encrypt](/learn/tutorials/secure-nginx-lets-encrypt-ubuntu-24-04). ## Sources - FastAPI — Server Workers and Behind a Proxy - Uvicorn — Deployment and release documentation - PyPI — FastAPI 0.141.1 and Uvicorn 0.52.4 release records - Ubuntu Packages — Python 3.12 for Ubuntu 24.04 Noble - Guidance re-verified: 2026-09-07 --- ### How to Install Node.js on Ubuntu 24.04 URL: https://rafftechnologies.com/learn/tutorials/install-nodejs-ubuntu-24-04 Description: Install Node.js 24 LTS and npm on Ubuntu 24.04 with NodeSource or nvm, then verify the runtime, native build tools, a localhost HTTP server, and Express. To **install Node.js on Ubuntu 24.04**, use a supported Node.js LTS release, verify which `node` binary your server is using, and keep installation testing local before exposing an application publicly. This tutorial installs **Node.js 24 LTS** and npm with NodeSource as the primary system-wide method, then shows nvm as a user-scoped alternative. Raff Technologies is used as the Ubuntu VM platform in the saved test workflow. As of September 7, 2026, the official Node.js download page lists **Node.js 24.20.0 LTS** and **npm 11.19.0**. Node.js 26 remains the Current release line. The Node.js project recommends Active LTS or Maintenance LTS releases for production applications. NodeSource currently supports Node.js 24 on Ubuntu 24.04 Noble. Its current `setup_24.x` script configures the `node_24.x` repository with the `nodistro` suite and supports `amd64` and `arm64`. The alternative nvm workflow uses the current **nvm 0.40.7** installer. The original Node.js 24 workflow was tested on a Raff Ubuntu 24.04 VM with 1 vCPU and 2 GB RAM. Current Node.js, npm, NodeSource, and nvm guidance was documentation-reviewed for this refresh; no new full machine retest is claimed. Prerequisites: - A [Raff Linux VM](/products/linux-vm) running Ubuntu 24.04 - SSH access with a non-root user that has sudo privileges - Outbound internet access for APT and npm downloads - A review of any existing Node.js installation before replacing it > **Choose one primary install method.** Use NodeSource when you want a system-wide runtime managed through APT. Use nvm when one user needs multiple Node.js versions or a user-scoped development environment. Installing both can make `command -v node` depend on shell state and PATH ordering. ## Step 1 — Prepare Ubuntu and check for an existing Node.js runtime Update package metadata and install the tools needed for the NodeSource setup: ```bash sudo apt update sudo apt install -y ca-certificates curl gnupg ``` Confirm Ubuntu 24.04: ```bash lsb_release -ds ``` Check whether Node.js or npm is already installed: ```bash node --version 2>/dev/null || echo "Node.js is not installed" npm --version 2>/dev/null || echo "npm is not installed" command -v node || true command -v npm || true ``` If an existing application depends on the installed runtime, stop here until you know how that application is started and how you will roll back. **Verify:** Ubuntu should report 24.04 LTS, and you should know whether an existing Node.js installation or PATH override is present. ## Step 2 — Add the NodeSource repository for Node.js 24 Download the NodeSource setup script to a file instead of piping it directly into a privileged shell: ```bash curl -fsSL https://deb.nodesource.com/setup_24.x \ -o /tmp/nodesource_setup.sh ``` Inspect the script before running it: ```bash sed -n '1,220p' /tmp/nodesource_setup.sh ``` Run the setup: ```bash sudo -E bash /tmp/nodesource_setup.sh ``` Refresh APT metadata and inspect the repository configuration: ```bash sudo apt update cat /etc/apt/sources.list.d/nodesource.sources apt-cache policy nodejs | sed -n '1,20p' ``` The current NodeSource script uses a source similar to: ```text URIs: https://deb.nodesource.com/node_24.x Suites: nodistro ``` Do not replace `nodistro` with `noble`; the current NodeSource repository uses the `nodistro` suite for this installation path. **Verify:** `/etc/apt/sources.list.d/nodesource.sources` should exist and `apt-cache policy nodejs` should show a NodeSource candidate for the Node.js 24 line. ## Step 3 — Install Node.js 24 LTS and npm Install the Node.js package: ```bash sudo apt install -y nodejs ``` Verify the runtime and package manager: ```bash node --version npm --version command -v node command -v npm ``` The exact NodeSource package can advance after this tutorial is published. On September 7, 2026, the current official Node.js LTS release is: ```text v24.20.0 ``` The official Node.js download page currently pairs that release with npm: ```text 11.19.0 ``` A NodeSource system-wide installation should normally resolve `node` and `npm` under `/usr/bin/`. **Verify:** `node --version` should report a supported v24 release, npm should run successfully, and the active binary paths should match the system-wide installation you intended. ## Step 4 — Install build tools for native npm modules Some npm dependencies contain native addons and may need a compiler toolchain when a compatible prebuilt binary is unavailable. Install Ubuntu's standard build toolchain: ```bash sudo apt install -y build-essential python3 ``` Verify the core tools: ```bash gcc --version | head -n 1 make --version | head -n 1 python3 --version ``` Not every Node.js project needs these tools, but having them available avoids a common failure mode when installing native npm dependencies. **Verify:** GCC, Make, and Python should all be available. ## Step 5 — Verify Node.js with a localhost-only HTTP server Create a test project: ```bash mkdir -p ~/hello-node cd ~/hello-node ``` Create `server.js`: ```bash cat > server.js <<'EOF' const http = require('node:http'); const host = '127.0.0.1'; const port = 3000; const server = http.createServer((req, res) => { res.writeHead(200, { 'Content-Type': 'text/plain; charset=utf-8' }); res.end('Hello from Node.js on Raff!\n'); }); server.listen(port, host, () => { console.log(`Server running at http://${host}:${port}/`); }); EOF ``` Start the server: ```bash node server.js ``` In a second SSH session, test it locally: ```bash curl -i http://127.0.0.1:3000 ``` Expected output includes: ```text HTTP/1.1 200 OK Hello from Node.js on Raff! ``` Confirm the listener is private: ```bash ss -lntp | grep ':3000' ``` The listening address should be `127.0.0.1:3000`, not `0.0.0.0:3000`. Stop the foreground process with `Ctrl+C` after testing. Do not create a public firewall rule for port 3000 just to make this installation test work. **Verify:** the local request should return `200 OK` and the Node.js process should listen only on loopback. ## Step 6 — Initialize npm and test an Express dependency Initialize the project: ```bash cd ~/hello-node npm init -y ``` Install Express locally: ```bash npm install express ``` Check the dependency: ```bash npm ls express ``` Create `app.js`: ```bash cat > app.js <<'EOF' const express = require('express'); const app = express(); const host = '127.0.0.1'; const port = 3000; app.get('/', (req, res) => { res.type('text/plain').send('Express is running on Node.js 24\n'); }); app.get('/health', (req, res) => { res.status(200).json({ status: 'ok' }); }); app.listen(port, host, () => { console.log(`Express listening on http://${host}:${port}`); }); EOF ``` Run the application: ```bash node app.js ``` From a second SSH session: ```bash curl http://127.0.0.1:3000/ curl http://127.0.0.1:3000/health ``` Expected responses include: ```text Express is running on Node.js 24 {"status":"ok"} ``` Stop the foreground process with `Ctrl+C`. **Verify:** `npm ls express` should succeed and both Express routes should return the expected response. ## Step 7 — Verify the Node.js installation end to end Run the final checks: ```bash printf 'Node.js:\n' node --version printf '\nnpm:\n' npm --version printf '\nBinary paths:\n' command -v node command -v npm printf '\nAPT candidate:\n' apt-cache policy nodejs | sed -n '1,20p' printf '\nBuild tools:\n' gcc --version | head -n 1 make --version | head -n 1 python3 --version printf '\nProject dependency:\n' cd ~/hello-node npm ls express printf '\nRuntime platform:\n' node -e "console.log(process.version, process.platform, process.arch)" ``` The installation is complete when: - Node.js reports a supported v24 LTS release; - npm runs successfully; - the active binaries are the intended system-wide NodeSource installation; - APT sees the NodeSource Node.js 24 repository candidate; - GCC, Make, and Python are available for native addons; - Express is installed locally in the test project; and - the earlier localhost HTTP tests succeeded without exposing port 3000 publicly. :::cta Deploy Your Server Launch an Ubuntu 24.04 Linux VM and install Node.js 24 LTS for your application environment. ::: ## Alternative — Install Node.js 24 with nvm Use nvm when a development user needs multiple Node.js versions or wants the runtime fully inside the user account. The official Node.js download page currently shows **nvm 0.40.7** for Linux installation. Download and inspect the installer: ```bash curl -fsSL https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.7/install.sh \ -o /tmp/nvm-install.sh sed -n '1,200p' /tmp/nvm-install.sh ``` Run it as your normal user: ```bash bash /tmp/nvm-install.sh ``` Load nvm into the current shell: ```bash export NVM_DIR="$HOME/.nvm" [ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh" ``` Install Node.js 24 and set it as the user's default: ```bash nvm install 24 nvm alias default 24 nvm use 24 ``` Verify: ```bash nvm --version node --version npm --version command -v node ``` With nvm, `command -v node` should resolve inside `~/.nvm/` rather than `/usr/bin/node`. For systemd services, do not assume an nvm-generated Node.js binary path remains stable after changing versions. Use a deliberately managed runtime path or update the service configuration as part of the runtime upgrade. ## Why Ubuntu 24.04's default Node.js package is not the primary method Ubuntu 24.04 Noble's base `nodejs` source package is from the Node.js **18.19.1** generation. Node.js 18 reached end of life on March 27, 2025. A fresh production deployment should therefore use a currently supported Active LTS or Maintenance LTS release instead of choosing Node.js 18 only because it is available in the base Ubuntu repository. ## Cleanup Remove only the tutorial project: ```bash rm -rf ~/hello-node ``` To remove the NodeSource-installed Node.js package: ```bash sudo apt remove -y nodejs ``` If you also want to remove the current NodeSource repository configuration, first inspect what exists: ```bash ls -l /etc/apt/sources.list.d/nodesource* ls -l /usr/share/keyrings/nodesource.gpg ``` The current `setup_24.x` script uses these paths: ```bash sudo rm -f /etc/apt/sources.list.d/nodesource.sources sudo rm -f /etc/apt/preferences.d/nodejs sudo rm -f /etc/apt/preferences.d/nsolid sudo rm -f /usr/share/keyrings/nodesource.gpg sudo apt update ``` Remove only files that belong to NodeSource on your server. If you used nvm, list installed versions first: ```bash nvm ls ``` Then uninstall only the version you no longer need: ```bash nvm uninstall 24 ``` Do not remove a runtime that an existing application or systemd service still depends on. ## Troubleshooting ### node --version does not report v24 Check the active binary and APT candidate: ```bash command -v node node --version apt-cache policy nodejs | sed -n '1,20p' ``` If the shell resolves a binary inside `~/.nvm/`, nvm may be overriding the system-wide NodeSource installation. ### The NodeSource repository is missing Check the current source file: ```bash cat /etc/apt/sources.list.d/nodesource.sources 2>/dev/null || true ``` Re-download and inspect the setup script if necessary: ```bash curl -fsSL https://deb.nodesource.com/setup_24.x \ -o /tmp/nodesource_setup.sh sed -n '1,220p' /tmp/nodesource_setup.sh ``` The current repository should use `node_24.x` with the `nodistro` suite. ### nvm: command not found Load nvm directly: ```bash export NVM_DIR="$HOME/.nvm" [ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh" nvm --version ``` If that works, open a new login shell and confirm your shell profile contains the nvm initialization lines. ### An npm package fails while compiling a native addon Check the build prerequisites: ```bash gcc --version make --version python3 --version ``` Then install the base toolchain if needed: ```bash sudo apt install -y build-essential python3 ``` Some packages also require their own development libraries; use the dependency's build documentation rather than weakening system permissions. ### npm reports permission errors for global packages Do not use broad fixes such as `chmod 777`. Prefer project-local dependencies, nvm for user-scoped global tools, or the installation method recommended by the CLI you are installing. ### The local HTTP test does not respond Check whether another process owns port 3000: ```bash ss -lntp | grep ':3000' ``` Inspect the Node.js process output and use another loopback port if needed. Do not expose a troubleshooting port publicly just to make the local check pass. ## Conclusion You installed Node.js 24 LTS and npm on Ubuntu 24.04 using a system-wide NodeSource repository, verified the active runtime and APT source, installed native-module build tools, and tested Node.js and Express on loopback only. For production application deployment, continue with [Deploy Node.js with PM2 on Ubuntu 24.04](/learn/tutorials/deploy-nodejs-pm2-ubuntu-24-04), [Install Nginx on Ubuntu 24.04](/learn/tutorials/install-nginx-ubuntu-24-04), or [Deploy Next.js with PM2 and Nginx](/learn/tutorials/deploy-nextjs-ubuntu-24-04-pm2-nginx). ## Sources - Node.js — Downloads and release schedule - NodeSource distributions — Ubuntu 24.04 / Node.js 24 support and current setup script - nvm — v0.40.7 release and installer - Ubuntu Packages — Node.js source package for Noble - Guidance re-verified: 2026-09-07 --- ### How to Set Up SSH 2FA (MFA) on Ubuntu 24.04 URL: https://rafftechnologies.com/learn/tutorials/set-up-ssh-mfa-ubuntu-24-04 Description: Set up SSH two-factor authentication on Ubuntu 24.04 with SSH keys plus TOTP, PAM, OpenSSH, safe rollback, recovery codes, and end-to-end login verification. To set up **SSH two-factor authentication (2FA) on Ubuntu 24.04**, require an SSH key as the first factor and a time-based one-time password (TOTP) as the second factor. This tutorial uses Ubuntu's `libpam-google-authenticator` package, OpenSSH keyboard-interactive authentication, explicit rollback files, and a second-session test so you do not close your only working administrative connection before MFA is proven. Raff Technologies is used as the Ubuntu VM platform in the saved test workflow. The resulting authentication sequence is: ```text SSH private key -> PAM TOTP challenge -> shell ``` This is both **SSH 2FA** and **SSH MFA**: the key is a possession factor and the rotating TOTP code is a separate possession factor generated from another secret. Password authentication is disabled in the OpenSSH layer for this design. Ubuntu 24.04 uses the OpenSSH **9.6p1** base line. On amd64, the current Noble security package verified on September 8, 2026 is `1:9.6p1-3ubuntu13.19`; Ubuntu package revisions can advance without changing the upstream `9.6p1` base shown by `ssh -V`. Ubuntu 24.04 currently provides `libpam-google-authenticator` version `20191231-2build1`. The original SSH key + TOTP workflow was tested on a Raff Ubuntu 24.04 VM with 1 vCPU and 2 GB RAM. OpenSSH, PAM, Ubuntu package versions, and Google Authenticator PAM behavior were documentation-reviewed for this refresh; no new full machine retest is claimed. Prerequisites: - A [Raff Linux VM](/products/linux-vm) running Ubuntu 24.04 - A non-root administrator account with sudo privileges - Working [SSH key authentication](/learn/tutorials/set-up-ssh-keys-ubuntu-24-04) for every interactive administrator who must retain access - A TOTP-compatible authenticator application - A tested out-of-band console or another recovery path - Awareness of any automation or service accounts that use SSH non-interactively > **Scope:** this tutorial configures **SSH key + TOTP**. It does not configure password + TOTP. If automation accounts rely on unattended SSH, do not enforce the policy globally until you have designed and tested an explicit exception or separate access path. ## Step 1 — Verify SSH key access and create rollback copies Keep the current SSH session open for the entire change. From a second terminal, confirm your SSH key already works: ```bash ssh your-user@your-server-ip ``` On the server, check the active user, SSH service, OpenSSH package, and effective SSH port: ```bash whoami systemctl is-active ssh ssh -V 2>&1 dpkg-query -W -f='${Version}\n' openssh-server sudo sshd -T | awk '/^port / {print $2}' ``` Back up the PAM and OpenSSH files before changing them: ```bash sudo cp --preserve=all /etc/pam.d/sshd /etc/pam.d/sshd.pre-mfa sudo cp --preserve=all /etc/ssh/sshd_config /etc/ssh/sshd_config.pre-mfa sudo install -d -m 700 /root/ssh-mfa-backup sudo cp -a /etc/ssh/sshd_config.d /root/ssh-mfa-backup/sshd_config.d ``` Verify the rollback copies: ```bash sudo ls -l /etc/pam.d/sshd.pre-mfa /etc/ssh/sshd_config.pre-mfa sudo test -d /root/ssh-mfa-backup/sshd_config.d \ && echo 'SSH drop-in backup exists' ``` Do not proceed if the second key-authenticated SSH session cannot connect or you do not have a usable recovery path. **Verify:** SSH key login should work in a second session and the PAM, main SSH configuration, and drop-in directory should all have rollback copies. ## Step 2 — Install the Google Authenticator PAM module Update APT metadata and install the Ubuntu package: ```bash sudo apt update sudo apt install -y libpam-google-authenticator ``` Check the installed package version: ```bash dpkg-query -W -f='${Package} ${Version}\n' libpam-google-authenticator ``` Ubuntu 24.04 Noble currently provides: ```text libpam-google-authenticator 20191231-2build1 ``` Find the PAM module without assuming a CPU architecture-specific library path: ```bash find /usr/lib -type f -name pam_google_authenticator.so -print ``` The package also installs the `google-authenticator` enrollment command: ```bash command -v google-authenticator ``` **Verify:** the package should be installed, `google-authenticator` should be available, and `pam_google_authenticator.so` should exist under `/usr/lib`. ## Step 3 — Enroll the administrator in TOTP Run enrollment as the same non-root user who will log in over SSH: ```bash google-authenticator -t -d -r 3 -R 30 -w 3 -e 5 ``` These options configure: - `-t`: time-based OTP rather than HOTP - `-d`: disallow reuse of a TOTP token - `-r 3 -R 30`: limit authentication attempts to 3 every 30 seconds - `-w 3`: accept the previous, current, or next 30-second TOTP window - `-e 5`: generate five emergency codes Scan the displayed QR code with your authenticator application and verify the generated code when prompted. Store emergency codes somewhere protected and separate from the VM. The command writes the user's TOTP secret and settings to: ```text ~/.google_authenticator ``` Set the expected permissions explicitly: ```bash chmod 600 ~/.google_authenticator ``` Verify ownership and mode without reading the secret: ```bash stat -c '%U %G %a %n' ~/.google_authenticator ``` Check time synchronization because TOTP depends on reasonably accurate clocks: ```bash timedatectl show -p NTPSynchronized --value ``` Expected output is normally: ```text yes ``` The PAM module requires the per-user secret file unless `nullok` is used. This tutorial intentionally does **not** use `nullok` because the final state requires TOTP for enrolled interactive administrators. **Verify:** the authenticator should generate matching TOTP codes, `.google_authenticator` should be owned by the login user with mode `600`, and the server clock should be synchronized. ## Step 4 — Enroll every interactive administrator before enforcement Each human administrator should create a separate TOTP secret under their own account: ```bash google-authenticator -t -d -r 3 -R 30 -w 3 -e 5 chmod 600 ~/.google_authenticator ``` For each administrator, verify that a secret file exists without displaying its contents: ```bash sudo stat -c '%U %a %n' /home/USERNAME/.google_authenticator ``` Do not share one TOTP secret between multiple people. Individual enrollment preserves user-level accountability and lets you rotate one person's second factor without affecting everyone else. Inventory non-human SSH accounts before enforcement: ```bash sudo awk -F: '$3 >= 1000 && $7 !~ /(nologin|false)$/ {print $1, $6, $7}' /etc/passwd ``` This command is only a starting point; service accounts can use different UID ranges or shells. Review actual SSH automation before changing the global policy. **Verify:** every human SSH administrator who must retain access should have an individual TOTP secret, and unattended SSH users should be identified before enforcement. ## Step 5 — Configure PAM for SSH key plus TOTP Ubuntu's default `/etc/pam.d/sshd` normally includes the standard password authentication stack through: ```text @include common-auth ``` For the specific **SSH key + TOTP** flow in this tutorial, leaving that line active can cause keyboard-interactive PAM authentication to request the Unix password as well as the TOTP code. That would create a different three-step flow. Edit the SSH PAM file: ```bash sudoedit /etc/pam.d/sshd ``` Comment the normal password-auth include and add the Google Authenticator module near the top: ```text # Standard Un*x authentication. # @include common-auth auth required pam_google_authenticator.so ``` Leave the existing `account`, `session`, and password-management sections unchanged. Verify only the relevant lines: ```bash sudo grep -nE 'common-auth|pam_google_authenticator' /etc/pam.d/sshd ``` Do **not** add `nullok`. The module documentation states that `nullok` permits a user without a secret file to pass this PAM module during rollout, which is not the mandatory-2FA result intended here. **Verify:** `@include common-auth` should be commented only in `/etc/pam.d/sshd`, while `auth required pam_google_authenticator.so` remains active. ## Step 6 — Configure OpenSSH to require key plus PAM TOTP Ubuntu's `/etc/ssh/sshd_config` includes `/etc/ssh/sshd_config.d/*.conf` near the start. OpenSSH generally uses the first obtained value for these single-valued directives, so use an early drop-in for the MFA policy: ```bash sudo tee /etc/ssh/sshd_config.d/00-raff-ssh-mfa.conf > /dev/null <<'EOF' PubkeyAuthentication yes PasswordAuthentication no KbdInteractiveAuthentication yes UsePAM yes AuthenticationMethods publickey,keyboard-interactive:pam PermitRootLogin no EOF ``` The required authentication chain is: ```text publickey,keyboard-interactive:pam ``` OpenSSH's `AuthenticationMethods` directive requires every comma-separated method in the selected list to succeed. Appending `:pam` to `keyboard-interactive` explicitly selects PAM as the keyboard-interactive device. Use `KbdInteractiveAuthentication` for new configuration. `ChallengeResponseAuthentication` is a deprecated alias. Validate syntax before reloading SSH: ```bash sudo sshd -t ``` No output means the syntax passed. Inspect the effective authentication policy: ```bash sudo sshd -T | grep -E \ '^(pubkeyauthentication|passwordauthentication|kbdinteractiveauthentication|usepam|authenticationmethods|permitrootlogin) ' ``` Expected values include: ```text pubkeyauthentication yes passwordauthentication no kbdinteractiveauthentication yes usepam yes authenticationmethods publickey,keyboard-interactive:pam permitrootlogin no ``` If those values differ, inspect all matching directives before reloading: ```bash sudo grep -RniE \ 'PubkeyAuthentication|PasswordAuthentication|KbdInteractiveAuthentication|UsePAM|AuthenticationMethods|PermitRootLogin' \ /etc/ssh/sshd_config /etc/ssh/sshd_config.d/ ``` **Verify:** `sshd -t` should return no error and `sshd -T` should show the intended key-plus-PAM authentication chain. ## Step 7 — Reload SSH while keeping the recovery session open Do not close the original working SSH connection. Reload OpenSSH: ```bash sudo systemctl reload ssh ``` Confirm the service remains active: ```bash systemctl is-active ssh ``` Re-check syntax and effective methods after reload: ```bash sudo sshd -t sudo sshd -T | grep -E \ '^(passwordauthentication|kbdinteractiveauthentication|authenticationmethods) ' ``` If the service or policy is wrong, use the still-authenticated recovery session to roll back before making another login attempt. **Verify:** SSH should remain active and the effective policy should still require `publickey,keyboard-interactive:pam`. ## Step 8 — Test SSH key plus TOTP from a new session From a separate terminal, connect with verbose authentication output: ```bash ssh -v your-user@your-server-ip ``` Expected sequence: 1. The SSH public key is accepted. 2. OpenSSH reports partial authentication success or continues to keyboard-interactive. 3. PAM asks for a verification code. 4. You enter the current TOTP code. 5. The shell opens without a Unix password prompt. After login, confirm the identity: ```bash whoami hostname ``` From the original recovery session, inspect recent SSH events: ```bash sudo journalctl -u ssh --since '-10 minutes' --no-pager | tail -n 80 ``` Ubuntu may also record authentication details in `/var/log/auth.log`: ```bash sudo tail -n 80 /var/log/auth.log 2>/dev/null || true ``` A successful test must require **both** the private key and a valid TOTP code. Key-only access should not complete authentication, and possession of a TOTP code without the matching SSH private key should not be enough. **Verify:** a new SSH session should open only after the SSH key and TOTP challenge both succeed, with no Unix password prompt. ## Step 9 — Verify recovery before closing the original session Confirm your out-of-band recovery path still works before closing the first SSH session. If your recovery policy permits consuming an emergency code for testing, test one from a controlled second session; emergency codes are single-use. Keep these rollback commands available in the original authenticated session: ```bash sudo cp --preserve=all /etc/pam.d/sshd.pre-mfa /etc/pam.d/sshd sudo cp --preserve=all /etc/ssh/sshd_config.pre-mfa /etc/ssh/sshd_config sudo rm -rf /etc/ssh/sshd_config.d sudo cp -a /root/ssh-mfa-backup/sshd_config.d /etc/ssh/sshd_config.d sudo sshd -t sudo systemctl reload ssh ``` Run rollback only from an already authenticated SSH or console session. Do not close the working recovery connection until a separate MFA login has succeeded. **Verify:** a separate key-plus-TOTP SSH session should work and you should have a usable recovery path before ending the original session. ## Step 10 — Verify SSH 2FA end to end Run the final server checks: ```bash printf 'OpenSSH package:\n' dpkg-query -W -f='${Version}\n' openssh-server printf '\nSSH syntax:\n' sudo sshd -t && echo 'sshd config OK' printf '\nEffective authentication policy:\n' sudo sshd -T | grep -E \ '^(pubkeyauthentication|passwordauthentication|kbdinteractiveauthentication|usepam|authenticationmethods|permitrootlogin) ' printf '\nTOTP secret permissions:\n' stat -c '%U %a %n' ~/.google_authenticator printf '\nSSH service:\n' systemctl is-active ssh ``` From a new client terminal, complete one more real login: ```bash ssh your-user@your-server-ip ``` End-to-end verification is complete when: - the SSH public key succeeds as the first factor; - a TOTP prompt is mandatory as the second factor; - no Unix password prompt appears; - `PasswordAuthentication` is disabled; - `KbdInteractiveAuthentication` and `UsePAM` are enabled; - `AuthenticationMethods` is `publickey,keyboard-interactive:pam`; - root SSH login is disabled; - `pam_google_authenticator.so` is required in `/etc/pam.d/sshd`; - `.google_authenticator` belongs to the user with mode `600`; - a second MFA-protected session works; and - the original recovery session is kept open until the new login path is proven. :::cta Deploy Your Server Deploy an Ubuntu 24.04 Linux VM and secure administrator access with SSH key plus TOTP authentication. ::: ## Troubleshooting ### SSH asks for a Unix password after the TOTP code Inspect the SSH PAM auth stack: ```bash sudo grep -nE 'common-auth|pam_google_authenticator' /etc/pam.d/sshd ``` For this key-plus-TOTP design, `@include common-auth` should be commented and `auth required pam_google_authenticator.so` should be active. ### The SSH key works but no TOTP prompt appears Inspect the effective OpenSSH values: ```bash sudo sshd -T | grep -E \ '^(kbdinteractiveauthentication|usepam|authenticationmethods) ' ``` Expected values are: ```text kbdinteractiveauthentication yes usepam yes authenticationmethods publickey,keyboard-interactive:pam ``` If the values differ, inspect the SSH configuration files in lexical order: ```bash sudo ls -1 /etc/ssh/sshd_config.d/ sudo grep -RniE \ 'KbdInteractiveAuthentication|AuthenticationMethods|PasswordAuthentication|UsePAM' \ /etc/ssh/sshd_config /etc/ssh/sshd_config.d/ ``` ### TOTP codes are rejected Check clock synchronization and secret-file ownership: ```bash timedatectl status stat -c '%U %G %a %n' ~/.google_authenticator ``` The PAM module expects the secret to be owned by the login user and, by default, readable only by that user. ### SSH reports Permission denied after the PAM change Keep the original session open and inspect syntax plus logs: ```bash sudo sshd -t sudo journalctl -u ssh --since '-10 minutes' --no-pager | tail -n 100 sudo tail -n 100 /var/log/auth.log 2>/dev/null || true ``` If needed, run the rollback commands from Step 9 and reload SSH. ### An automation account can no longer connect The global `AuthenticationMethods publickey,keyboard-interactive:pam` policy applies the TOTP requirement to SSH logins. Restore the previous policy if production automation is broken, then design a narrow `Match User` or `Match Group` exception and test it independently before enforcing MFA again. Do not create a broad bypass that accidentally exempts human administrators. ### A user lost the authenticator device Use a protected emergency code or the out-of-band console to regain access. After recovery, run `google-authenticator` again as that user to rotate the TOTP secret and replace the stored emergency codes. ## Cleanup and rollback If you decide to remove SSH 2FA, perform the rollback from an already authenticated SSH or console session and keep that session open while testing. Restore PAM: ```bash sudo cp --preserve=all /etc/pam.d/sshd.pre-mfa /etc/pam.d/sshd ``` Restore the original OpenSSH configuration and drop-in directory: ```bash sudo cp --preserve=all /etc/ssh/sshd_config.pre-mfa /etc/ssh/sshd_config sudo rm -rf /etc/ssh/sshd_config.d sudo cp -a /root/ssh-mfa-backup/sshd_config.d /etc/ssh/sshd_config.d ``` Validate before reloading: ```bash sudo sshd -t sudo systemctl reload ssh ``` Open another terminal and verify the intended pre-MFA login method before deleting `.google_authenticator` or the rollback files. **Verify:** the restored authentication path should work from a new session before the recovery connection is closed. ## Conclusion You configured **SSH two-factor authentication on Ubuntu 24.04** using an SSH key plus a TOTP challenge. OpenSSH requires the public key first, PAM validates the TOTP second, password authentication is disabled for this flow, and the original session remains available until the replacement access path has been tested. For the surrounding access controls, continue with [Set Up SSH Keys on Ubuntu 24.04](/learn/tutorials/set-up-ssh-keys-ubuntu-24-04), [Set Up UFW Firewall on Ubuntu 24.04](/learn/tutorials/set-up-ufw-firewall-ubuntu-24-04), [Install fail2ban on Ubuntu 24.04](/learn/tutorials/install-fail2ban-ubuntu-24-04), or use [Raff Security](/products/security) alongside host-level hardening. ## Sources - Ubuntu Packages — OpenSSH Server for Ubuntu 24.04 Noble - Ubuntu Packages — libpam-google-authenticator for Ubuntu 24.04 Noble - Ubuntu OpenSSH manual — `AuthenticationMethods`, `KbdInteractiveAuthentication`, `UsePAM`, and drop-in behavior - Google Authenticator PAM — enrollment options and secret-file permission rules - Guidance re-verified: 2026-09-08 --- ### How to Host an App on a VPS with Cloudflare and Nginx URL: https://rafftechnologies.com/learn/tutorials/host-app-on-vps-with-cloudflare Description: Host a Node.js app on an Ubuntu VPS behind Cloudflare with Nginx, proxied DNS, Full (strict) TLS, safe UFW rules, systemd, and reboot verification. To **host an app on a VPS with Cloudflare**, run the application on your Linux VM, keep its runtime port private, place Nginx in front, and proxy the public hostname through Cloudflare. The production request path in this tutorial is: ```text Visitor -> Cloudflare -> HTTPS to Nginx on the VPS -> 127.0.0.1:3000 -> Node.js app ``` Raff Technologies is used as the Ubuntu VM platform in the saved workflow. Cloudflare is **not** the VPS provider in this architecture: the VM runs at Raff (or another cloud/VPS provider), while Cloudflare provides DNS, the HTTP/HTTPS reverse-proxy layer, and edge security/performance features. As of September 8, 2026, Cloudflare recommends proxying A, AAAA, and CNAME records that serve web traffic and recommends **Full (strict)** SSL/TLS whenever possible. Node.js **24.20.0 LTS** is the current v24 LTS release, and the Node.js download page currently references **nvm 0.40.7** for Linux installation. The original article workflow was prepared for a Raff Ubuntu 24.04 VM with 2 vCPU and 4 GB RAM. Current Cloudflare proxy behavior, Full (strict), Node.js, nvm, and Certbot installation guidance were documentation-reviewed for this refresh; no new full Raff + Cloudflare end-to-end machine retest is claimed. Prerequisites: - A [Raff Linux VM](/products/linux-vm) running Ubuntu 24.04 - SSH access through a non-root sudo user such as `deploy` - A domain active in Cloudflare - Access to Cloudflare DNS and SSL/TLS settings - The VM's public IPv4 address - Ports 80 and 443 available for Nginx - A recovery path before enabling or changing firewall rules Use these placeholders throughout: | Placeholder | Replace with | |---|---| | `your_server_ip` | Your VM public IPv4 address | | `example.com` | Your root domain | | `www.example.com` | Your `www` hostname | | `deploy` | Your non-root deployment user | | `/opt/raff-node-app` | Application directory on the VM | ## Step 1 — Prepare the Ubuntu 24.04 VPS Connect to the VM: ```bash ssh deploy@your_server_ip ``` Confirm the OS and available resources: ```bash lsb_release -ds nproc free -h lsblk -o NAME,SIZE,FSTYPE,MOUNTPOINTS ``` Install the packages used by the tutorial: ```bash sudo apt update sudo apt upgrade -y sudo apt install -y curl ca-certificates git nginx ufw snapd dnsutils ``` Check whether the upgrade requests a reboot: ```bash test -f /var/run/reboot-required && cat /var/run/reboot-required ``` If a reboot is required, perform it during a safe maintenance window before proceeding with production traffic. **Verify:** Ubuntu 24.04 should be running, the non-root SSH account should work, and Nginx, UFW, `curl`, `dig`, and snapd should be available. ## Step 2 — Configure UFW without risking SSH lockout Inspect the firewall before changing it: ```bash sudo ufw status verbose ``` Determine the actual SSH port from the effective OpenSSH configuration: ```bash SSH_PORT="$(sudo sshd -T | awk '/^port / {print $2}')" echo "$SSH_PORT" ``` Allow the working SSH port and Nginx web traffic: ```bash sudo ufw allow "${SSH_PORT}/tcp" sudo ufw allow 'Nginx Full' sudo ufw default deny incoming sudo ufw default allow outgoing sudo ufw status numbered ``` Keep the current SSH session open and successfully open a **second SSH session** before enabling an inactive firewall. If UFW is currently inactive, enable it only after the second SSH session succeeds: ```bash sudo ufw enable ``` Check the rules again: ```bash sudo ufw status numbered ``` Do not use `ufw --force enable` as a shortcut around verifying the SSH path. Do **not** create a public allow rule for port `3000`; the application will listen only on loopback. **Verify:** the actual SSH port should remain reachable, Nginx ports 80/443 should be allowed, UFW should be active, and port 3000 should have no public allow rule. ## Step 3 — Install Node.js 24 LTS with nvm The official Node.js download page currently lists **v24.20.0 LTS** and **nvm 0.40.7**. Download the nvm installer to a file: ```bash curl -fsSL https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.7/install.sh \ -o /tmp/nvm-install.sh ``` Inspect it before execution: ```bash sed -n '1,220p' /tmp/nvm-install.sh ``` Run the installer as the non-root deployment user: ```bash bash /tmp/nvm-install.sh ``` Load nvm into the current shell: ```bash export NVM_DIR="$HOME/.nvm" [ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh" ``` Install Node.js 24 and make it the user's default: ```bash nvm install 24 nvm alias default 24 nvm use 24 ``` Verify: ```bash nvm --version node --version npm --version command -v node ``` On September 8, 2026, the official Node.js download page reports `v24.20.0` with npm `11.19.0`. **Verify:** nvm should report 0.40.7, Node.js should be on the supported v24 LTS line, and npm should run successfully for the deployment user. ## Step 4 — Create a localhost-only Node.js application Create the application directory: ```bash sudo mkdir -p /opt/raff-node-app sudo chown deploy:deploy /opt/raff-node-app cd /opt/raff-node-app ``` Initialize the sample project and install Express: ```bash npm init -y npm install express ``` Create `server.js`: ```bash cat > server.js <<'EOF' const express = require('express'); const app = express(); const host = '127.0.0.1'; const port = Number(process.env.PORT || 3000); app.get('/', (req, res) => { res.type('text/plain').send('Raff VPS app behind Cloudflare is running\n'); }); app.get('/health', (req, res) => { res.status(200).json({ status: 'ok' }); }); app.listen(port, host, () => { console.log(`App listening on http://${host}:${port}`); }); EOF ``` Run it temporarily: ```bash node server.js ``` From a second SSH session: ```bash curl -i http://127.0.0.1:3000/health sudo ss -lntp | grep ':3000' ``` Expected health body: ```json {"status":"ok"} ``` The socket should be bound to `127.0.0.1:3000`, not `0.0.0.0:3000`. Stop the foreground process with `Ctrl+C` after the check. **Verify:** `/health` should return HTTP 200 and the application should listen only on loopback. ## Step 5 — Run the Node.js app with systemd Resolve the exact Node.js binary for the deployment user: ```bash NODE_BIN="$(command -v node)" echo "$NODE_BIN" ``` Create the service with that absolute path: ```bash sudo tee /etc/systemd/system/raff-node-app.service > /dev/null < /dev/null <<'NGINX' server { listen 80; listen [::]:80; server_name example.com www.example.com; access_log /var/log/nginx/example.com.access.log; error_log /var/log/nginx/example.com.error.log; location / { proxy_pass http://127.0.0.1:3000; proxy_http_version 1.1; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Host $host; proxy_set_header X-Forwarded-Proto $scheme; proxy_connect_timeout 10s; proxy_read_timeout 60s; } } NGINX ``` Enable the site and disable the default site: ```bash sudo ln -sfn /etc/nginx/sites-available/example.com \ /etc/nginx/sites-enabled/example.com sudo rm -f /etc/nginx/sites-enabled/default ``` Validate and reload: ```bash sudo nginx -t sudo systemctl enable --now nginx sudo systemctl reload nginx ``` Test locally with the intended Host header: ```bash curl -i -H 'Host: example.com' http://127.0.0.1/health ``` **Verify:** `nginx -t` should succeed and Nginx should return the application's `/health` response while proxying to `127.0.0.1:3000`. ## Step 7 — Add proxied Cloudflare DNS records In Cloudflare DNS, create web records similar to: | Type | Name | Content | Proxy status | TTL | |---|---|---|---|---| | A | `@` | `your_server_ip` | Proxied | Auto | | CNAME | `www` | `example.com` | Proxied | Auto | Cloudflare currently allows A, AAAA, and CNAME records that resolve web traffic to be proxied and recommends proxying records that serve HTTP or HTTPS. A proxied record returns Cloudflare addresses to public DNS clients instead of directly returning the origin IP. Check from your local computer: ```bash dig +short example.com dig +short www.example.com ``` Then test HTTP: ```bash curl -I http://example.com ``` > **Important:** proxied DNS reduces direct origin exposure through current DNS answers, but it does not make a known origin IP unreachable. Historical DNS, mail records, or other services can still reveal an origin address unless you add separate origin protection. **Verify:** the web records should show `Proxied` in Cloudflare, DNS should return Cloudflare addresses, and HTTP should reach Nginx through the hostname. ## Step 8 — Install a trusted TLS certificate on the Nginx origin Cloudflare **Full (strict)** accepts an origin certificate that is unexpired, matches the hostname, and is issued by either a publicly trusted CA or Cloudflare Origin CA. This tutorial uses a publicly trusted Let's Encrypt certificate so the origin certificate can also be validated independently. Certbot currently recommends its snap package for most Linux users. Install it: ```bash sudo snap install --classic certbot sudo ln -sf /snap/bin/certbot /usr/local/bin/certbot ``` Request certificates and let Certbot update Nginx: ```bash sudo certbot --nginx --redirect \ -d example.com \ -d www.example.com ``` If you do not use `www`, omit it consistently from Cloudflare DNS, Nginx, and Certbot. Check the certificate and renewal path: ```bash sudo certbot certificates sudo certbot renew --dry-run sudo nginx -t ``` Test HTTPS: ```bash curl -I https://example.com ``` If validation fails, inspect DNS, Nginx, port 80, and the ACME challenge path first. Do not make `DNS only` the default troubleshooting step because gray-clouding a public web record exposes the origin address in DNS and removes Cloudflare's HTTP proxy for that hostname while it is disabled. **Verify:** Certbot should issue the certificate, `renew --dry-run` should pass, Nginx syntax should remain valid, and the site should respond over HTTPS. ## Step 9 — Set Cloudflare SSL/TLS to Full (strict) In the Cloudflare dashboard, open the zone's SSL/TLS settings and select: ```text Full (strict) ``` Cloudflare recommends Full (strict) whenever possible. In this mode both network legs are encrypted and Cloudflare validates the origin certificate presented by Nginx. Do not use Flexible for this architecture. Flexible leaves the Cloudflare-to-origin connection on HTTP and commonly creates confusing redirect behavior when the origin itself redirects HTTP to HTTPS. Test the public route: ```bash curl -I https://example.com curl -sI https://example.com | grep -Ei '^cf-ray:|^server:' ``` A proxied request normally includes a `cf-ray` response header. **Verify:** Full (strict) should be active, HTTPS should succeed, and the response should show evidence that traffic is passing through Cloudflare. ## Step 10 — Confirm the application port remains private On the VM: ```bash sudo ss -lntp | grep ':3000' sudo ufw status numbered ``` The application should still listen on: ```text 127.0.0.1:3000 ``` There should be no UFW allow rule for port 3000. From a machine outside the VPS, attempt the direct runtime port: ```bash curl --connect-timeout 5 http://your_server_ip:3000 ``` The connection should fail. **Verify:** the application should work through Nginx but should not be reachable directly on public port 3000. ## Step 11 — Check logs, resource headroom, and origin exposure Inspect application and Nginx logs: ```bash journalctl -u raff-node-app -n 50 --no-pager sudo tail -n 50 /var/log/nginx/example.com.access.log sudo tail -n 50 /var/log/nginx/example.com.error.log ``` Check basic resource headroom: ```bash free -h df -h / uptime ``` When Cloudflare proxies requests, Nginx sees Cloudflare edge IPs as the direct TCP clients by default. Cloudflare sends the original visitor address in the `CF-Connecting-IP` header. Do not blindly trust that header from arbitrary direct origin traffic; if your application needs the true visitor IP, configure Nginx's real-IP handling only together with Cloudflare's published trusted IP ranges and keep those ranges updated. Also understand the origin-protection boundary: proxied DNS does **not** by itself prevent someone who already knows the VPS IP from connecting directly to ports 80 or 443. Cloudflare recommends stronger controls such as restricting origin web traffic to Cloudflare IP ranges, authenticated origin mechanisms, or Cloudflare Tunnel where appropriate. Before production traffic, configure backups for application configuration and persistent data. If the application stores uploads, databases, queues, or other state, protect those components separately instead of treating one VM snapshot as the complete backup plan. See [Raff Data Protection](/products/data-protection) for infrastructure-level recovery options. **Verify:** logs should be readable, disk and memory should have headroom, and you should know whether direct origin access is intentionally allowed or will be restricted before production. ## Step 12 — Verify the Cloudflare VPS deployment end to end From your local computer, test the public path: ```bash printf 'HTTPS headers:\n' curl -I https://example.com printf '\nApplication health:\n' curl https://example.com/health printf '\nCloudflare marker:\n' curl -sI https://example.com | grep -Ei '^cf-ray:|^server:' ``` On the VM, verify the origin path: ```bash printf 'Nginx:\n' systemctl is-active nginx sudo nginx -t printf '\nApplication service:\n' systemctl is-active raff-node-app printf '\nLocal application:\n' curl http://127.0.0.1:3000/health printf '\nApplication socket:\n' sudo ss -lntp | grep ':3000' printf '\nFirewall:\n' sudo ufw status numbered ``` Confirm the expected chain: ```text Visitor -> Cloudflare proxied hostname -> HTTPS to Nginx on the Raff VM -> proxy to 127.0.0.1:3000 -> Node.js application ``` Finally, reboot during a safe test window: ```bash sudo reboot ``` After reconnecting: ```bash systemctl is-active nginx systemctl is-active raff-node-app curl https://example.com/health ``` End-to-end verification is complete when the proxied HTTPS hostname works, `/health` returns `{"status":"ok"}`, Full (strict) is active, Nginx and the application survive reboot, the Node.js process remains bound to `127.0.0.1:3000`, and port 3000 is not publicly allowed. :::cta Deploy Your Server Launch an Ubuntu 24.04 Linux VM and use Nginx plus Cloudflare as the public edge for your application. ::: ## Troubleshooting ### Nginx returns 502 Bad Gateway Test the local application before changing Cloudflare: ```bash systemctl status raff-node-app --no-pager journalctl -u raff-node-app -n 50 --no-pager curl -i http://127.0.0.1:3000/health ``` Then validate Nginx: ```bash sudo nginx -t sudo tail -n 50 /var/log/nginx/example.com.error.log ``` A 502 usually means Nginx cannot reach the local application or the application is failing. ### Cloudflare returns 521 A 521 response commonly means Cloudflare reached the origin network but the web server refused the connection. Check that Nginx is active, the origin IP is correct, and the firewall accepts the intended web traffic: ```bash systemctl is-active nginx sudo ss -lntp | grep -E ':80|:443' sudo ufw status numbered ``` ### Cloudflare returns 522 A 522 indicates an origin connection timeout. Check routing, firewall rules, current Cloudflare DNS content, and whether the VPS is reachable and has resource headroom. ```bash sudo ufw status numbered sudo ss -lntp | grep -E ':80|:443' free -h uptime ``` ### Cloudflare returns 526 With Full (strict), a 526 means Cloudflare could not validate the certificate presented by the origin. Inspect hostname coverage, expiry, and Nginx configuration: ```bash sudo certbot certificates sudo certbot renew --dry-run sudo nginx -t ``` ### HTTPS enters a redirect loop Confirm Cloudflare uses Full (strict), not Flexible, then inspect the redirect chain: ```bash curl -IL https://example.com ``` ### The app is reachable on public port 3000 Inspect the listener and firewall: ```bash sudo ss -lntp | grep ':3000' sudo ufw status numbered ``` The application should bind to `127.0.0.1:3000`. Remove an accidental public UFW rule only after identifying the exact numbered rule and confirming it is not used by another service. ### DNS returns the VPS address instead of Cloudflare addresses Check the web record's proxy status in Cloudflare. Proxied A, AAAA, and CNAME records return Cloudflare addresses; DNS-only records return the configured origin target directly. ```bash dig +short example.com ``` ### Node.js stops starting after an nvm upgrade Re-resolve the current binary: ```bash export NVM_DIR="$HOME/.nvm" [ -s "$NVM_DIR/nvm.sh" ] && . "$NVM_DIR/nvm.sh" command -v node node --version ``` Compare that path with the service: ```bash systemctl cat raff-node-app ``` Update `ExecStart` when the nvm-managed Node.js path changes, then run: ```bash sudo systemctl daemon-reload sudo systemctl restart raff-node-app ``` ## Optional hardening — reduce direct origin exposure For stronger origin protection, Cloudflare recommends blocking web traffic that does not come from Cloudflare IP ranges, or using an origin-protection design such as Cloudflare Tunnel where appropriate. Review Cloudflare's current published ranges before making firewall changes: ```bash curl -fsSL https://www.cloudflare.com/ips-v4 curl -fsSL https://www.cloudflare.com/ips-v6 ``` Do not copy a static IP list from an old tutorial into a long-lived firewall policy. Cloudflare states that trusted prefixes need to be kept current. If you choose to restrict ports 80 and 443 to Cloudflare ranges, add and verify every required allow rule **before** removing the broad Nginx web rule, keep SSH recovery access open, and rerun both public HTTPS and `certbot renew --dry-run` afterward. For correct visitor IP logging, pair the trusted Cloudflare ranges with Nginx's real IP module and `real_ip_header CF-Connecting-IP`; do not trust `CF-Connecting-IP` from unrestricted direct origin traffic. ## Cleanup and rollback To take the application offline while keeping its files: ```bash sudo systemctl disable --now raff-node-app ``` Disable the Nginx site: ```bash sudo rm -f /etc/nginx/sites-enabled/example.com sudo nginx -t sudo systemctl reload nginx ``` If permanently decommissioning the hostname, back up required data first, then remove only the application files, systemd unit, Nginx configuration, certificate material, and Cloudflare DNS records that belong to this deployment. Do not delete application data or certificates merely to troubleshoot a temporary proxy error. ## Conclusion You now have the production pattern for **hosting an application on a VPS with Cloudflare and Nginx**: Cloudflare proxies the public hostname, Nginx terminates the origin HTTPS connection, and the Node.js application stays private on `127.0.0.1:3000` under systemd. The important security boundary is that Cloudflare proxying and private application ports solve different problems. The runtime port stays local by design, while stronger protection against direct origin access requires an additional origin-control decision such as a Cloudflare IP allowlist or Tunnel. For related deployment work, continue with [Install Node.js on Ubuntu 24.04](/learn/tutorials/install-nodejs-ubuntu-24-04), [Install Nginx on Ubuntu 24.04](/learn/tutorials/install-nginx-ubuntu-24-04), and [Secure Nginx with Let's Encrypt on Ubuntu 24.04](/learn/tutorials/secure-nginx-lets-encrypt-ubuntu-24-04). ## Sources - Cloudflare DNS — Proxy status and proxy eligibility - Cloudflare SSL/TLS — Full (strict) mode requirements - Cloudflare Fundamentals — Origin protection and Cloudflare IP ranges - Cloudflare Support — CF-Connecting-IP and restoring visitor addresses - Node.js — v24.20.0 LTS download guidance - nvm — v0.40.7 release - Certbot — Nginx on Linux snap installation guidance - Guidance re-verified: 2026-09-08 --- ### How to Deploy Laravel 13 on Ubuntu 24.04 with Nginx and PHP-FPM URL: https://rafftechnologies.com/learn/tutorials/deploy-laravel-ubuntu-24-04-nginx Description: Deploy Laravel 13 on Ubuntu 24.04 with Nginx and PHP 8.3-FPM, HTTPS, safe permissions, production caches, queues, scheduler, and health checks. A production **Laravel deployment on Ubuntu 24.04** can run cleanly on Nginx and PHP-FPM when Nginx serves only Laravel's `public/` directory, PHP runs through the Ubuntu 24.04 PHP 8.3-FPM service, debug mode is disabled, production caches are built, and long-running workers are supervised and reloaded after deployments. Raff Technologies is the Linux VM platform used by the saved test workflow in this tutorial. The deployment path is: ```text Visitor -> Nginx -> public/index.php -> PHP 8.3-FPM -> Laravel 13 ``` Laravel 13 was released on March 17, 2026 and officially supports PHP 8.3 through PHP 8.5. Ubuntu 24.04's current `php8.3-fpm` package remains on the PHP 8.3 line; the amd64 Noble security/update revision verified on September 8, 2026 is `8.3.6-0ubuntu0.24.04.10`. Laravel's current production documentation recommends serving requests through `public/index.php`, ensuring `storage` and `bootstrap/cache` are writable by the web process, keeping `APP_DEBUG=false`, running `php artisan optimize`, and reloading long-running services after a new release. The original HTTP deployment path was tested on a Raff Ubuntu 24.04 VM; current framework, PHP/Nginx, queue, scheduler, and HTTPS guidance were documentation-reviewed for this refresh without claiming a new full end-to-end machine retest. Prerequisites: - A [Raff Linux VM](/products/linux-vm) running Ubuntu 24.04 - SSH and sudo access through a non-root administrator - A public IPv4 address - A Laravel project, or the fresh Laravel 13 application created below - A domain such as `laravel.example.com` for production HTTPS - Database credentials if the real application uses MySQL or PostgreSQL - A backup or rollback point before applying migrations to an existing production database - A recovery path before enabling or changing firewall rules Use these placeholders throughout the tutorial: | Placeholder | Replace with | |---|---| | `your_server_ip` | Your server's public IPv4 address | | `laravel.example.com` | Your Laravel domain | | `/var/www/laravel` | Laravel application directory | ![Architecture diagram showing Laravel on Ubuntu 24.04 with Nginx, PHP-FPM, HTTPS, and a database on a Raff VM](https://raff-images.s3.raffusercloud.com/deploy_laravel_ubuntu_24_04_nginx_architecture_webp_3b10063a5a.png) ![Deployment flow infographic for Laravel on Ubuntu 24.04 with Nginx and PHP-FPM](https://raff-images.s3.raffusercloud.com/deploy_laravel_ubuntu_24_04_nginx_deployment_flow_webp_ed8580dbb0.png) ## Step 1 — Verify Ubuntu 24.04 and define the deployment host Connect to the server: ```bash ssh your-user@your_server_ip ``` Confirm the operating system and architecture: ```bash cat /etc/os-release uname -m ``` Check available resources and disk space: ```bash nproc free -h df -h / ``` Set variables used in later checks: ```bash export APP_DIR=/var/www/laravel export APP_HOST=laravel.example.com ``` If DNS is already configured, verify it: ```bash dig +short A "$APP_HOST" || true ``` ![Terminal showing Ubuntu 24.04 verified on a Raff VM before Laravel deployment](https://raff-images.s3.raffusercloud.com/deploy_laravel_ubuntu_24_04_nginx_01_ubuntu_2404_verified_webp_58b01930eb.png) **Verify:** `/etc/os-release` should identify Ubuntu 24.04, the server should have enough disk and memory for the application workload, and SSH should remain available before any firewall change. ## Step 2 — Install Nginx, PHP 8.3-FPM, Composer, and Laravel extensions Laravel 13 requires PHP 8.3 or newer. Install Ubuntu 24.04's PHP 8.3 packages, Nginx, Composer, and common Laravel extensions: ```bash sudo apt update sudo apt install -y \ nginx composer curl unzip git ca-certificates dnsutils snapd \ php8.3-fpm php8.3-cli php8.3-common \ php8.3-curl php8.3-mbstring php8.3-xml \ php8.3-bcmath php8.3-zip php8.3-sqlite3 php8.3-intl ``` Applications using MySQL or PostgreSQL also need the matching PHP driver: ```bash sudo apt install -y php8.3-mysql # or sudo apt install -y php8.3-pgsql ``` Enable Nginx and PHP-FPM: ```bash sudo systemctl enable --now nginx sudo systemctl enable --now php8.3-fpm ``` Check versions, package revision, and required modules: ```bash nginx -v php -v composer --version dpkg-query -W -f='${Package} ${Version}\n' php8.3-fpm php -m | grep -Ei 'ctype|curl|dom|fileinfo|filter|hash|mbstring|openssl|pcre|pdo|session|tokenizer|xml' ``` ![Terminal showing Nginx, PHP 8.3, and Composer installed on Ubuntu 24.04](https://raff-images.s3.raffusercloud.com/deploy_laravel_ubuntu_24_04_nginx_02_nginx_php_composer_installed_webp_c514b91056.png) **Verify:** Nginx and `php8.3-fpm` should be active, PHP should report 8.3 or newer, Composer should run successfully, and Laravel's required PHP extensions should be loaded. ## Step 3 — Configure UFW without risking SSH lockout Inspect the firewall and determine the actual SSH port before changing anything: ```bash sudo ufw status verbose SSH_PORT="$(sudo sshd -T | awk '/^port / {print $2}')" echo "$SSH_PORT" ``` Allow the working SSH port and Nginx web traffic: ```bash sudo ufw allow "${SSH_PORT}/tcp" sudo ufw allow 'Nginx Full' sudo ufw default deny incoming sudo ufw default allow outgoing sudo ufw status numbered ``` Keep the current SSH session open. Before enabling an inactive firewall, open a **second SSH session** using the same real SSH port and verify that it works. If UFW is currently inactive, enable it only after the second session succeeds: ```bash sudo ufw enable ``` Check again: ```bash sudo ufw status numbered ``` Do not use `ufw --force enable` as a shortcut around validating SSH access. **Verify:** the real SSH port should remain reachable, Nginx HTTP/HTTPS traffic should be allowed, and a second SSH session should work before the original recovery session is closed. ## Step 4 — Create or deploy the Laravel 13 application Create the application directory and assign the deployment user as owner with `www-data` as the group: ```bash sudo mkdir -p /var/www/laravel sudo chown -R "$USER":www-data /var/www/laravel cd /var/www/laravel ``` For a fresh Laravel 13 sample application: ```bash composer create-project laravel/laravel . "^13.0" --prefer-dist ``` For an existing project, deploy your Git checkout or release artifact and install the versions recorded in `composer.lock`: ```bash composer install \ --no-dev \ --prefer-dist \ --no-interaction \ --optimize-autoloader ``` Do not run `composer update` as a routine production deployment step; production should normally install the dependency set already tested and committed in the lock file. Check the framework and web entry point: ```bash php artisan --version ls -l artisan public/index.php composer.lock ``` **Verify:** `php artisan --version` should report Laravel 13.x for the fresh sample, `public/index.php` should exist, and production deployments should use a committed `composer.lock`. ## Step 5 — Configure the production environment and protect .env If the project does not yet have an environment file, create it from its example: ```bash cd /var/www/laravel test -f .env || cp .env.example .env ``` Generate an application key only when one does not already exist: ```bash grep -q '^APP_KEY=base64:' .env || php artisan key:generate ``` Set the core production values: ```bash sed -i 's/^APP_ENV=.*/APP_ENV=production/' .env sed -i 's/^APP_DEBUG=.*/APP_DEBUG=false/' .env sed -i 's#^APP_URL=.*#APP_URL=https://laravel.example.com#' .env chmod 600 .env ``` For IP-only HTTP verification before DNS/TLS is ready, temporarily use: ```text APP_URL=http://your_server_ip ``` Do not overwrite an existing production `APP_KEY`; changing it can invalidate encrypted application data and sessions. Check only non-secret values: ```bash grep -E '^APP_ENV=|^APP_DEBUG=|^APP_URL=' .env stat -c '%a %n' .env ``` **Verify:** `APP_ENV=production`, `APP_DEBUG=false`, and the intended `APP_URL` should be present; `.env` should be mode 600; and an existing production key should remain unchanged. ## Step 6 — Configure the database, migrations, and writable directories For this reproducible sample, SQLite keeps the tutorial self-contained: ```bash cd /var/www/laravel sed -i 's/^DB_CONNECTION=.*/DB_CONNECTION=sqlite/' .env touch database/database.sqlite ``` For a real application, configure its MySQL or PostgreSQL connection instead. If you prefer the database lifecycle to be separate from the VM, Raff also offers [Managed PostgreSQL](/products/managed-databases/postgresql). Before applying migrations to an existing production database, take an application-consistent backup or snapshot appropriate to that database. Run migrations: ```bash php artisan migrate --force ``` Laravel's deployment documentation requires the web process to be able to write to `storage` and `bootstrap/cache`: ```bash sudo chown -R "$USER":www-data /var/www/laravel sudo chmod -R ug+rwX storage bootstrap/cache sudo find storage bootstrap/cache -type d -exec chmod g+s {} \; ``` For this tutorial's SQLite database, also allow the PHP-FPM group to write the database file and directory: ```bash sudo chgrp www-data database database/database.sqlite sudo chmod g+rwX database database/database.sqlite ``` Never use `chmod -R 777` on a Laravel application. Check migration state: ```bash php artisan migrate:status ``` **Verify:** migrations should succeed, Laravel's writable directories should be group-writable for `www-data`, and no broad world-writable permissions should be present. ## Step 7 — Configure Nginx to serve only Laravel's public directory Laravel's official Nginx deployment example routes requests through `public/index.php`. Serving the project root can expose `.env`, source code, logs, and configuration files. ![Diagram showing Laravel public directory structure and Nginx request flow](https://raff-images.s3.raffusercloud.com/deploy_laravel_ubuntu_24_04_nginx_public_directory_visual_webp_602c7cb427.png) Create the server block: ```bash APP_HOST="your_server_ip" APP_DIR="/var/www/laravel" sudo tee /etc/nginx/sites-available/laravel > /dev/null <> /dev/null 2>&1 ``` Verify it: ```bash crontab -l | grep 'artisan schedule:run' ``` If the application defines sub-minute tasks, Laravel documents `php artisan schedule:interrupt` as a deployment command so an already-running scheduler stops executing old code for the rest of that minute. **Verify:** applications that use scheduling should show expected tasks in `schedule:list` and exactly one intended `schedule:run` cron entry. ## Step 12 — Run Laravel queue workers under Supervisor when required Skip this step if the application does not use asynchronous queues. Install Supervisor: ```bash sudo apt install -y supervisor sudo systemctl enable --now supervisor ``` Determine the deployment user: ```bash DEPLOY_USER="$(id -un)" echo "$DEPLOY_USER" ``` Create a conservative single-worker configuration. Increase concurrency only after measuring workload and server capacity: ```bash sudo tee /etc/supervisor/conf.d/laravel-worker.conf > /dev/null </dev/null || true php artisan about --only=environment ``` **Verify:** reloadable processes should return under their process monitor, the new code should be active, and database changes should have an explicit recovery plan. ## Step 14 — Verify the Laravel production deployment end to end Set the final public URL: ```bash APP_TEST_URL="https://laravel.example.com" ``` If DNS/TLS is not yet part of the saved test state, use the HTTP IP endpoint instead: ```bash APP_TEST_URL="http://your_server_ip" ``` Test the application and built-in health route: ```bash curl -I "$APP_TEST_URL" curl -i "$APP_TEST_URL/up" ``` Check services and Nginx syntax: ```bash sudo systemctl is-active nginx sudo systemctl is-active php8.3-fpm sudo nginx -t ``` Check production configuration without printing secrets: ```bash cd /var/www/laravel grep -E '^APP_ENV=|^APP_DEBUG=|^APP_URL=' .env php artisan about --only=environment ``` Check writable paths and confirm the project root is not served directly: ```bash namei -l /var/www/laravel/storage namei -l /var/www/laravel/bootstrap/cache grep -R 'root ' /etc/nginx/sites-enabled/laravel ``` If queues or the scheduler are used, verify them too: ```bash sudo supervisorctl status 2>/dev/null || true crontab -l | grep 'artisan schedule:run' || true ``` ![Terminal showing HTTP 200 verification for Laravel on Ubuntu 24.04 with Nginx and PHP-FPM](https://raff-images.s3.raffusercloud.com/deploy_laravel_ubuntu_24_04_nginx_04_laravel_https_page_webp_097581235a.png) **Verify:** the home page and `/up` should return successfully, Nginx and PHP-FPM should be healthy, `APP_DEBUG=false` should remain active, Nginx should serve only `/var/www/laravel/public`, writable paths should be correct, and any configured scheduler or queue worker should be running under its intended production mechanism. :::cta Deploy Your Server Deploy an Ubuntu 24.04 Linux VM for Laravel with Nginx, PHP-FPM, HTTPS, health checks, and supervised background services. ::: ## Cleanup and rollback To take only the Laravel site offline without deleting application data: ```bash sudo rm -f /etc/nginx/sites-enabled/laravel sudo nginx -t sudo systemctl reload nginx ``` To stop queue workers managed by Supervisor: ```bash sudo supervisorctl stop 'laravel-worker:*' ``` Do not delete `.env`, uploaded files, database data, queue state, TLS material, or release backups until you have confirmed they are no longer required. To re-enable the site: ```bash sudo ln -sfn /etc/nginx/sites-available/laravel /etc/nginx/sites-enabled/laravel sudo nginx -t sudo systemctl reload nginx ``` ## Troubleshooting ### Nginx returns 403 or 404 Confirm the site root and entry point: ```bash grep -R 'root ' /etc/nginx/sites-enabled/laravel ls -l /var/www/laravel/public/index.php sudo nginx -t ``` The Nginx root should be `/var/www/laravel/public`, not `/var/www/laravel`. ### Nginx returns 502 Bad Gateway Check PHP-FPM and the configured socket: ```bash sudo systemctl status php8.3-fpm --no-pager ls -l /run/php/php8.3-fpm.sock grep fastcgi_pass /etc/nginx/sites-enabled/laravel ``` Restart only after confirming the service and socket path: ```bash sudo systemctl restart php8.3-fpm sudo systemctl reload nginx ``` ### Laravel returns 500 Server Error Inspect the application key, migrations, writable directories, and logs: ```bash cd /var/www/laravel grep '^APP_KEY=' .env php artisan migrate:status namei -l storage bootstrap/cache sudo test -f storage/logs/laravel.log && sudo tail -n 80 storage/logs/laravel.log ``` Do not regenerate an existing production `APP_KEY` just to troubleshoot an HTTP 500. ### /up returns HTTP 500 The built-in health route indicates whether Laravel booted successfully. Check PHP-FPM, Laravel logs, configuration, and any dependencies touched by application boot or custom `DiagnosingHealth` listeners: ```bash curl -i https://laravel.example.com/up sudo systemctl is-active php8.3-fpm sudo tail -n 80 /var/www/laravel/storage/logs/laravel.log ``` ### Queue jobs stop after a deployment Check Supervisor first: ```bash sudo supervisorctl status sudo tail -n 80 /var/www/laravel/storage/logs/worker.log ``` Laravel queue workers are long-lived. Use `php artisan reload` or `php artisan queue:restart` during deployment and ensure Supervisor restarts workers after they exit. ### Scheduled tasks never run Check Laravel's schedule and system cron entry: ```bash cd /var/www/laravel php artisan schedule:list crontab -l | grep 'artisan schedule:run' ``` The scheduler needs one server cron invocation every minute. Do not create a separate system cron entry for each Laravel task. ### Uploaded public files return 404 If the application uses Laravel's local public disk, create the documented storage link: ```bash cd /var/www/laravel php artisan storage:link ls -l public/storage ``` Laravel's public local disk stores files under `storage/app/public` and exposes them through the `public/storage` symlink. ### Certbot cannot validate the domain Check DNS, Nginx, and firewall reachability: ```bash dig +short A laravel.example.com curl -I http://laravel.example.com sudo nginx -t sudo ufw status numbered ``` The hostname must resolve to the server and port 80 must be publicly reachable for the normal HTTP validation flow. ## Conclusion You now have a current **Laravel 13 deployment on Ubuntu 24.04 with Nginx and PHP 8.3-FPM**. The application is served only from Laravel's `public` directory, debug output is disabled, production caches are built, HTTPS is available for the domain deployment, and `/up` provides a simple application boot health check. For applications with background work, the server is also prepared for Laravel's scheduler and Supervisor-managed queue workers. Laravel 13's `php artisan reload` command provides a framework-level way to terminate reloadable long-running services so their process monitors can restart them on the new release. For related server work, continue with [Set Up a LEMP Stack on Ubuntu 24.04](/learn/tutorials/set-up-lemp-stack-ubuntu-24-04), [Install MySQL on Ubuntu 24.04](/learn/tutorials/install-mysql-ubuntu-24-04), [Secure Nginx with Let's Encrypt](/learn/tutorials/secure-nginx-lets-encrypt-ubuntu-24-04), or [Set Up UFW Firewall](/learn/tutorials/set-up-ufw-firewall-ubuntu-24-04). ## Sources - Laravel 13 — Deployment - Laravel 13 — Release Notes - Laravel 13 — Queues - Laravel 13 — Task Scheduling - Laravel 13 — File Storage - Ubuntu 24.04 — php8.3-fpm package - Certbot — Nginx on Linux snap installation guidance - Guidance re-verified: 2026-09-08 --- ### How to Install Docker on Ubuntu 24.04 URL: https://rafftechnologies.com/learn/tutorials/install-docker-ubuntu-24-04 Description: Install Docker on Ubuntu 24.04 from Docker’s official APT repository. Add Docker Engine, Compose and Buildx, verify hello-world, and avoid common UFW exposure mistakes. To **install Docker on Ubuntu 24.04**, use Docker's official APT repository, install Docker Engine together with the Compose and Buildx plugins, verify the daemon with `hello-world`, and then run a loopback-only container test before you expose any production ports. Raff Technologies is used as the Ubuntu VM platform in the saved workflow for this tutorial. Docker currently supports Ubuntu Noble 24.04 LTS, and the official Ubuntu installation path uses the packages `docker-ce`, `docker-ce-cli`, `containerd.io`, `docker-buildx-plugin`, and `docker-compose-plugin`. As of September 8, 2026, **Docker Engine 29.8.0** is the current Engine 29 release and **Docker Compose v5.4.0** is the current Compose release. Your installed package revision can be newer when you follow this guide, so verify the actual APT candidate instead of treating a hard-coded patch version as permanent. The original workflow was tested on a Raff Ubuntu 24.04.4 VM with 2 vCPU and 2 GB RAM. Docker's Noble support, official APT setup, package names, Engine/Compose releases, non-root access model, and firewall guidance were re-verified for this refresh; no new full machine retest is claimed. Prerequisites: - A [Raff Linux VM](/products/linux-vm) running Ubuntu 24.04 - SSH access through a sudo-capable user - A recovery path before making firewall changes - Enough CPU, RAM, storage, and network capacity for the containers you plan to run - A backup plan if Docker, containerd, images, volumes, or containers already exist on the VM > **Fresh-server note:** the package-removal commands below are appropriate when you intentionally want Docker's official packages. On an existing Docker host, inventory workloads and persistent data before replacing packages. ## Step 1 — Update Ubuntu and install repository prerequisites Update APT metadata and install the packages used by Docker's official repository setup: ```bash sudo apt update sudo apt install -y ca-certificates curl ``` Apply current Ubuntu updates before deploying production workloads: ```bash sudo apt upgrade -y ``` Check the Ubuntu release: ```bash . /etc/os-release printf '%s\n%s\n' "$PRETTY_NAME" "$VERSION_CODENAME" ``` Expected values include: ```text Ubuntu 24.04 LTS noble ``` If the upgrade requires a reboot, handle it before building a long-running container workload: ```bash test -f /var/run/reboot-required && cat /var/run/reboot-required ``` **Verify:** the host should report Ubuntu 24.04 / Noble, APT should complete without repository errors, and any required reboot should be understood before continuing. ## Step 2 — Check for conflicting Docker packages before removing them Docker's Ubuntu documentation lists distribution-provided packages that can conflict with the official Docker Engine packages. First inspect what is installed: ```bash dpkg -l | grep -E 'docker|containerd|runc|podman' || true ``` On a fresh VM, remove conflicting packages when present: ```bash for pkg in docker.io docker-doc docker-compose docker-compose-v2 docker-buildx podman-docker containerd runc; do sudo apt remove -y "$pkg" 2>/dev/null || true done ``` Removing packages does not automatically prove that old Docker data is safe to delete. If `/var/lib/docker` or `/var/lib/containerd` already contains production state, stop and review the existing deployment before doing anything destructive. Check whether a Docker CLI remains installed: ```bash docker --version 2>/dev/null || echo 'Docker CLI not currently installed' ``` **Verify:** conflicting packages should be removed only when that is intentional, and an existing Docker data directory should never be deleted merely to make the tutorial output match. ## Step 3 — Add Docker's official Ubuntu APT repository Create the APT keyring directory: ```bash sudo install -m 0755 -d /etc/apt/keyrings ``` Download Docker's signing key: ```bash sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg \ -o /etc/apt/keyrings/docker.asc sudo chmod a+r /etc/apt/keyrings/docker.asc ``` Create Docker's deb822 repository source using the detected Ubuntu codename and CPU architecture: ```bash sudo tee /etc/apt/sources.list.d/docker.sources > /dev/null </dev/null && echo 'Docker daemon reachable' sudo docker ps ``` An empty `docker ps` list is normal on a new host. **Verify:** Docker should be active, enabled for normal boot, and reachable through `sudo docker` without a daemon connection error. ## Step 6 — Run Docker's hello-world verification Run Docker's official smoke-test image: ```bash sudo docker run --rm hello-world ``` Expected output includes: ```text Hello from Docker! ``` This verifies more than the CLI alone: Docker contacts the registry, downloads an image, creates a container, runs it, and returns its output. Confirm that the stopped test container was removed because `--rm` was used: ```bash sudo docker ps -a --filter ancestor=hello-world ``` **Verify:** the `hello-world` message should appear and the temporary container should not remain as a stopped workload. ## Step 7 — Run a loopback-only Nginx container test A container port does not need to be public just because you want to verify networking. Start Nginx bound only to the host loopback interface: ```bash sudo docker rm -f test-nginx 2>/dev/null || true sudo docker run -d \ --name test-nginx \ -p 127.0.0.1:8080:80 \ nginx:alpine ``` Check the published port: ```bash sudo docker ps --filter name=test-nginx sudo ss -lntp | grep ':8080' ``` The host-side listener should be limited to: ```text 127.0.0.1:8080 ``` Test it from the VM: ```bash curl -I http://127.0.0.1:8080 ``` Expected output includes an HTTP 200 response from Nginx. To inspect the page from your own computer without publishing 8080, create an SSH tunnel: ```bash ssh -L 8080:127.0.0.1:8080 your_user@your_server_ip ``` Then open: ```text http://localhost:8080 ``` ![Nginx container running with Docker on Ubuntu 24.04](https://raff-images.s3.raffusercloud.com/docker_nginx_container_ubuntu_24_04_webp_1a7b04939a.png) > **Docker firewall warning:** Docker documents that published container ports interact with Docker-managed packet-filtering/NAT rules and can bypass normal assumptions about UFW. For private services, bind explicitly to `127.0.0.1` or a private interface. For public services, review Docker-aware filtering and any upstream cloud firewall instead of assuming a UFW deny alone controls the published port. **Verify:** the Nginx container should be running, `curl` should return a valid response, and port 8080 should not be published on `0.0.0.0` or a public host address. ## Step 8 — Decide whether to enable non-root Docker access Docker requires `sudo` by default on a fresh Linux installation. For a trusted administrator on a dedicated VM, add the user to the Docker group only if that privilege model is acceptable: ```bash sudo usermod -aG docker "$USER" ``` Apply the group in a new login session, or temporarily in the current shell: ```bash newgrp docker ``` Test: ```bash docker ps ``` > **Security boundary:** membership in the `docker` group effectively grants root-level control over the host. Do not treat it as an ordinary low-privilege convenience group. On shared servers, continue using controlled sudo access or evaluate Docker's rootless mode for your use case. **Verify:** if you intentionally added the account to the Docker group, `docker ps` should work without `sudo`; otherwise continue using `sudo docker`. ## Step 9 — Verify Docker Engine and Compose end to end Run the final verification sequence: ```bash printf 'Docker Engine:\n' docker --version || sudo docker --version printf '\nDocker Compose:\n' docker compose version || sudo docker compose version printf '\nBuildx:\n' docker buildx version || sudo docker buildx version printf '\nDocker service:\n' systemctl is-active docker printf '\nAPT candidate:\n' apt-cache policy docker-ce | sed -n '1,8p' printf '\nNginx test container:\n' sudo docker ps --filter name=test-nginx printf '\nLoopback HTTP response:\n' curl -I http://127.0.0.1:8080 printf '\nPublished listener:\n' sudo ss -lntp | grep ':8080' ``` End-to-end verification is complete when: - Docker Engine, Compose, and Buildx all report versions; - the Docker service is active; - APT shows the intended Docker repository candidate; - `hello-world` completed successfully; - the Nginx test container is running; - `curl http://127.0.0.1:8080` succeeds; and - the test port is bound only to loopback. :::cta Deploy Your Server Launch an Ubuntu 24.04 Linux VM and use this verified Docker Engine and Compose installation workflow. ::: ## Basic Docker commands after installation Useful commands include: ```bash docker ps docker ps -a docker images docker pull nginx:alpine docker logs test-nginx docker exec -it test-nginx sh docker system df ``` For a Compose application: ```bash docker compose up -d docker compose ps docker compose logs -f docker compose down ``` Continue with [Deploy a Multi-Container App with Docker Compose](/learn/tutorials/deploy-multi-container-docker-compose-ubuntu-24-04) when you are ready to move from a single-container smoke test to an application stack. ## Troubleshooting ### docker: command not found Check the repository and package candidate: ```bash apt-cache policy docker-ce sudo apt update sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin ``` Then retry: ```bash docker --version ``` ### Cannot connect to the Docker daemon Check service state first: ```bash systemctl is-active docker sudo systemctl status docker --no-pager sudo journalctl -u docker -n 100 --no-pager ``` Start it only after reviewing the reported error: ```bash sudo systemctl start docker sudo docker ps ``` ### Docker Compose is unavailable Install or repair the plugin package: ```bash sudo apt update sudo apt install -y docker-compose-plugin docker compose version ``` Use `docker compose`, not an old standalone `docker-compose` binary, for this tutorial. ### A Docker port is reachable despite UFW Inspect Docker's published ports and actual listeners: ```bash sudo docker ps --format 'table {{.Names}}\t{{.Ports}}' sudo ss -lntp sudo ufw status numbered ``` For a private service, change the publication from a broad host bind such as `0.0.0.0:8080:80` to a loopback or private-interface bind such as: ```text 127.0.0.1:8080:80 ``` Then review Docker's current packet-filtering documentation before implementing host-level rules for production published ports. ### The Nginx test does not respond Inspect the container, logs, and port owner: ```bash sudo docker ps -a --filter name=test-nginx sudo docker logs test-nginx sudo ss -lntp | grep ':8080' curl -I http://127.0.0.1:8080 ``` If 8080 is already in use, recreate the test on another loopback port: ```bash sudo docker rm -f test-nginx sudo docker run -d --name test-nginx -p 127.0.0.1:8081:80 nginx:alpine curl -I http://127.0.0.1:8081 ``` ### Permission denied on /var/run/docker.sock Use sudo first: ```bash sudo docker ps ``` If Docker-group access is intentionally part of your administrator model, verify group membership after a new login: ```bash id docker ps ``` Do not loosen the Docker socket with broad filesystem permissions. ## Cleanup and uninstall Remove the temporary Nginx container: ```bash sudo docker rm -f test-nginx ``` Optionally remove only the test images you no longer need: ```bash sudo docker image rm hello-world nginx:alpine ``` To update Docker later, normally use the configured repository rather than reinstalling from scratch: ```bash sudo apt update sudo apt upgrade ``` To uninstall the Docker packages: ```bash sudo apt purge -y \ docker-ce docker-ce-cli containerd.io \ docker-buildx-plugin docker-compose-plugin docker-ce-rootless-extras sudo apt autoremove -y ``` Do **not** delete `/var/lib/docker` or `/var/lib/containerd` unless you have identified and backed up every image, container, volume, and persistent workload you need. Deleting those directories is destructive. If permanent removal is intentional after backup verification: ```bash sudo rm -rf /var/lib/docker /var/lib/containerd sudo rm -f /etc/apt/sources.list.d/docker.sources /etc/apt/keyrings/docker.asc sudo apt update ``` ## Conclusion You installed Docker Engine on Ubuntu 24.04 from Docker's official APT repository, added the official Compose and Buildx plugins, verified the daemon with `hello-world`, and ran an Nginx container without unnecessarily exposing the test service to the public internet. The main operational boundaries are simple: keep Docker packages on the intended repository lifecycle, treat Docker-group membership as root-equivalent privilege, and audit every published container port separately from ordinary UFW assumptions. Next, deploy a [multi-container app with Docker Compose](/learn/tutorials/deploy-multi-container-docker-compose-ubuntu-24-04), run [Uptime Kuma with Docker](/learn/tutorials/deploy-uptime-kuma-docker-ubuntu-24-04), or compare [Kubernetes vs Docker Compose for small teams](/learn/guides/kubernetes-vs-docker-compose-small-teams). For infrastructure planning, see [VPS for Docker Containers](/learn/guides/vps-for-docker-containers) and [Raff Linux VM plans](/products/linux-vm). ## Sources - Docker Docs — Install Docker Engine on Ubuntu - Docker Docs — Linux post-installation steps - Docker Docs — Docker Engine version 29 release notes - Docker Compose — Releases - Guidance re-verified: 2026-09-08 --- ### How to Install MySQL on Ubuntu 24.04 URL: https://rafftechnologies.com/learn/tutorials/install-mysql-ubuntu-24-04 Description: Install MySQL 8.0 on a Raff Ubuntu 24.04 VM. Secure root access and port 3306, create an app user, verify CRUD, and test backup and restore safely. In this tutorial, you will install MySQL 8.0 on a Raff Ubuntu 24.04 VM, secure local administration, create a dedicated application database and user, verify CRUD, protect port 3306, and prove a logical backup can be restored. Ubuntu 24.04's supported `mysql-server` package currently tracks **MySQL 8.0**. As of September 17, 2026, Ubuntu's Noble package path provides **MySQL 8.0.46**. This tutorial stays on Ubuntu's distro-managed package path rather than switching the server to Oracle's separate MySQL APT repository. Raff provides Linux VMs for self-hosted database workloads. If you want the database platform operated for you instead, compare this self-hosted path with [Raff Managed MySQL](/products/managed-databases/mysql). Prerequisites: - A [Raff Linux VM](/products/linux-vm) running Ubuntu 24.04 LTS - SSH access with a sudo-capable user - A tested recovery path before firewall or database changes - Enough disk space for live data plus at least one backup - An off-server destination for production backup copies The original workflow was tested on a Raff VM with **2 vCPU and 4 GB RAM**. This refresh re-verifies MySQL 8.0.46 package, authentication, networking, backup, and restore guidance against current upstream documentation without claiming a new full machine retest. No separate MySQL image is currently listed in Raff's content registry, so this tutorial uses the manual installation path. :::cluster ## Step 1 — Verify Ubuntu and the MySQL package candidate Confirm the operating system and architecture: ```bash cat /etc/os-release uname -m ``` Refresh package metadata: ```bash sudo apt update ``` Inspect the package candidate before installing: ```bash apt-cache policy mysql-server mysql-server-8.0 ``` On Ubuntu 24.04, the `mysql-server` metapackage resolves to the MySQL 8.0 line. At this revision, the current Ubuntu package is 8.0.46. Check CPU, memory, and disk headroom: ```bash nproc free -h df -h / ``` Do not copy a fixed production VM size from a tutorial. MySQL memory use depends on the buffer pool, connections, per-session buffers, temporary tables, query shape, and other processes on the server. **Verify:** Ubuntu reports 24.04, APT exposes a MySQL 8.0 candidate from Ubuntu repositories, and the VM has enough free storage for the database plus backup growth. ## Step 2 — Install MySQL Server from Ubuntu Install MySQL Server and UFW: ```bash sudo apt install -y mysql-server ufw ``` Verify the client and server versions: ```bash mysql --version sudo mysql -NBe 'SELECT VERSION();' ``` The exact Ubuntu package revision changes as security and maintenance updates are published. Confirm Ubuntu still owns the installed package path: ```bash apt-cache policy mysql-server-8.0 ``` Do not add Oracle's separate MySQL APT repository after installation unless you have a tested repository-migration and rollback plan. **Verify:** `mysql-server` installs successfully, `SELECT VERSION()` returns MySQL 8.0.x, and APT identifies Ubuntu's repository as the package source. ## Step 3 — Verify the service and port 3306 Confirm MySQL is active and enabled: ```bash systemctl is-active mysql systemctl is-enabled mysql sudo systemctl status mysql --no-pager ``` Check the server through its local Unix socket: ```bash sudo mysqladmin ping ``` Expected output: ```text mysqld is alive ``` Inspect listeners: ```bash sudo ss -lntp | grep ':3306' || true ``` Read the active bind address and port from MySQL: ```bash sudo mysql -NBe 'SELECT @@bind_address, @@port;' ``` **Verify:** the MySQL service is active and enabled, `mysqladmin ping` succeeds, and no unexpected public listener exists on TCP 3306. ## Step 4 — Verify local root administration Open the administrative client through sudo: ```bash sudo mysql ``` Inspect the local root account instead of assuming its authentication method: ```sql SELECT user, host, plugin FROM mysql.user WHERE user = 'root'; ``` Keep the administrative account restricted to localhost. MySQL supports socket peer-credential authentication for local administration, while application accounts should use their own credentials. Exit: ```sql EXIT; ``` Do not convert the root account into a remotely accessible application account. Create a separate least-privileged application user in Step 6. **Verify:** `sudo mysql` provides local administrative access, every root account is restricted to localhost, and no remote root path is required by the application. ## Step 5 — Run mysql_secure_installation Run MySQL's hardening utility: ```bash sudo mysql_secure_installation ``` Prompts can vary by package revision and account state. The important final state is: - no anonymous MySQL users; - no remotely accessible root account; - no `test` database; - password-strength validation enabled only when it fits your account policy. Verify the state directly: ```bash sudo mysql -NBe \ "SELECT user, host FROM mysql.user WHERE user = '';" sudo mysql -NBe \ "SELECT user, host FROM mysql.user WHERE user = 'root';" sudo mysql -NBe \ "SELECT schema_name FROM information_schema.schemata WHERE schema_name = 'test';" ``` The anonymous-user and test-database queries return no rows. Root remains local. **Verify:** anonymous users and the test database are absent, and no root account is available for remote application access. ## Step 6 — Create an application database and user Open MySQL as the local administrator: ```bash sudo mysql ``` Create a dedicated database: ```sql CREATE DATABASE raffapp CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci; ``` Create a local application account with a generated password: ```sql CREATE USER 'raffappuser'@'localhost' IDENTIFIED WITH caching_sha2_password BY RANDOM PASSWORD; ``` Store the generated password immediately in your secrets manager. It cannot be recovered later in plain text. Grant database-scoped privileges: ```sql GRANT ALL PRIVILEGES ON raffapp.* TO 'raffappuser'@'localhost'; ``` Inspect the account and grants: ```sql SHOW CREATE USER 'raffappuser'@'localhost'; SHOW GRANTS FOR 'raffappuser'@'localhost'; EXIT; ``` MySQL 8.0 uses `caching_sha2_password` as its default authentication plugin. Do not downgrade an application account to a legacy plugin to accommodate an obsolete connector. **Verify:** `raffappuser` uses `caching_sha2_password` and has privileges on `raffapp.*` rather than global administrative privileges. ## Step 7 — Run an authenticated CRUD test Connect as the application user: ```bash mysql -u raffappuser -p raffapp ``` Create a disposable table: ```sql CREATE TABLE tutorial_check ( id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, name VARCHAR(100) NOT NULL, status VARCHAR(32) NOT NULL, created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, PRIMARY KEY (id), UNIQUE KEY unique_name (name) ) ENGINE=InnoDB; ``` Insert, read, update, and delete a row: ```sql INSERT INTO tutorial_check (name, status) VALUES ('mysql-tutorial-test', 'created'); SELECT name, status FROM tutorial_check WHERE name = 'mysql-tutorial-test'; UPDATE tutorial_check SET status = 'verified' WHERE name = 'mysql-tutorial-test'; SELECT name, status FROM tutorial_check WHERE name = 'mysql-tutorial-test'; DELETE FROM tutorial_check WHERE name = 'mysql-tutorial-test'; DROP TABLE tutorial_check; EXIT; ``` The second `SELECT` returns `verified`. **Verify:** the non-root application account creates, reads, updates, and deletes data inside its own database without global administrative privileges. ## Step 8 — Keep MySQL off the public network Inspect the bind address and active listener: ```bash sudo mysql -NBe 'SELECT @@bind_address, @@port;' sudo ss -lntp | grep ':3306' || true ``` For an application on the same VM, keep MySQL local. Do not change the listener to `0.0.0.0` simply because a GUI or another tutorial expects public TCP access. Before changing UFW, open a second SSH session and inspect the current rules: ```bash sudo ufw status numbered ``` If UFW is already active, add a defense-in-depth deny only when it does not conflict with an intentional private-network rule: ```bash sudo ufw deny 3306/tcp ``` If UFW is inactive, follow [Set Up UFW Firewall on Ubuntu 24.04](/learn/tutorials/set-up-ufw-firewall-ubuntu-24-04) rather than enabling it blindly from one remote shell. **Verify:** MySQL does not listen on a public interface for the single-VM design and no public UFW rule permits TCP 3306. ## Step 9 — Allow one private app server with TLS Skip this step when the application and database share the same VM. For a separate application VM on [Raff VPC](/products/vpc), replace these example addresses with the real private IPs: ```text Database private IP: 10.0.0.5 Application private IP: 10.0.0.10 ``` Back up the server configuration: ```bash sudo cp /etc/mysql/mysql.conf.d/mysqld.cnf \ /etc/mysql/mysql.conf.d/mysqld.cnf.before-private-access ``` Edit the configuration: ```bash sudo nano /etc/mysql/mysql.conf.d/mysqld.cnf ``` Bind MySQL only to loopback plus the database VM's private address: ```ini bind-address = 127.0.0.1,10.0.0.5 ``` Validate and restart: ```bash sudo mysqld --validate-config sudo systemctl restart mysql systemctl is-active mysql ``` Create an account restricted to the application's exact private IP and require encrypted transport: ```bash sudo mysql ``` ```sql CREATE USER 'raffappuser'@'10.0.0.10' IDENTIFIED WITH caching_sha2_password BY RANDOM PASSWORD REQUIRE SSL; GRANT ALL PRIVILEGES ON raffapp.* TO 'raffappuser'@'10.0.0.10'; SHOW GRANTS FOR 'raffappuser'@'10.0.0.10'; EXIT; ``` Store the generated password securely. If UFW is active, allow only the application VM's private address: ```bash sudo ufw allow from 10.0.0.10 to 10.0.0.5 port 3306 proto tcp sudo ufw status numbered ``` From the application VM, require TLS: ```bash mysql \ --host=10.0.0.5 \ --user=raffappuser \ --password \ --ssl-mode=REQUIRED \ raffapp ``` Verify encryption inside the session: ```sql SHOW STATUS LIKE 'Ssl_cipher'; ``` The cipher value is non-empty. Use `VERIFY_CA` or `VERIFY_IDENTITY` when your application has a CA and certificate model it can validate. **Verify:** MySQL listens only on loopback plus the intended private address, UFW allows only the application VM, the MySQL account matches that source IP, and the remote session reports a TLS cipher. ## Step 10 — Create a consistent logical backup Create a protected root-owned backup directory: ```bash sudo install -d -m 700 /var/backups/mysql ``` Create a custom backup filename: ```bash STAMP="$(date -u +%Y%m%d-%H%M%S)" BACKUP_FILE="/var/backups/mysql/raffapp-${STAMP}.sql.gz" ``` Dump the InnoDB application database using a consistent transaction snapshot. `sudo tee` writes the compressed stream into the root-owned backup directory without weakening directory permissions: ```bash sudo mysqldump \ --single-transaction \ --quick \ --routines \ --triggers \ --events \ raffapp \ | gzip \ | sudo tee "$BACKUP_FILE" > /dev/null ``` Restrict the file: ```bash sudo chmod 600 "$BACKUP_FILE" ``` Validate the archive and inspect its beginning: ```bash sudo gzip -t "$BACKUP_FILE" sudo zcat "$BACKUP_FILE" | head ``` `--single-transaction` provides a consistent snapshot for transactional tables such as InnoDB without a long global read lock. Check storage engines separately if you inherit older non-transactional tables. Keep at least one production backup outside the database VM. Raff [Object Storage](/products/object-storage) can be used by S3-compatible backup tooling, while [Data Protection](/products/data-protection) provides an additional VM-level recovery layer. **Verify:** the compressed logical dump exists with mode 600, `gzip -t` succeeds, and your production recovery design includes an off-server copy. ## Step 11 — Restore into a disposable database Never test a restore by overwriting production. Create an isolated target: ```bash sudo mysql -e \ "CREATE DATABASE raffapp_restore_test CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci;" ``` Select the newest tutorial backup: ```bash LATEST_BACKUP="$(sudo ls -1t /var/backups/mysql/raffapp-*.sql.gz | head -n 1)" echo "$LATEST_BACKUP" ``` Restore the dump directly into the disposable database: ```bash sudo zcat "$LATEST_BACKUP" | sudo mysql raffapp_restore_test ``` Inspect the restored tables: ```bash sudo mysql -e \ "SHOW TABLES FROM raffapp_restore_test;" ``` For a production recovery rehearsal, also validate representative row counts and application behavior. Use a dedicated recovery VM or isolated MySQL instance when integrations or scheduled jobs could react to restored data. Remove only the disposable restore database after validation: ```bash sudo mysql -e 'DROP DATABASE raffapp_restore_test;' ``` **Verify:** the dump imports into `raffapp_restore_test`, expected tables appear, production `raffapp` remains untouched, and the disposable target can be removed cleanly. ## Step 12 — Apply MySQL updates safely Check for available MySQL package updates: ```bash apt list --upgradable 2>/dev/null | grep -E '^mysql|^libmysql' || true ``` Before a MySQL package update: 1. create a fresh database backup; 2. confirm an off-server copy exists; 3. review the Ubuntu changelog and upstream release notes; 4. verify disk headroom; 5. schedule a maintenance window when the workload requires it. Apply Ubuntu updates: ```bash sudo apt update sudo apt upgrade ``` Verify MySQL after package changes: ```bash systemctl is-active mysql sudo mysql -NBe 'SELECT VERSION();' sudo mysqladmin ping sudo journalctl -u mysql --no-pager -n 100 ``` Treat a move from Ubuntu's MySQL 8.0 packages to Oracle's separate APT repository as a migration, not a routine patch. **Verify:** MySQL is active on the expected package branch, local administration works, and the application authentication and CRUD path still succeeds after updates. ## Step 13 — Review configuration and recovery readiness Validate the active configuration: ```bash sudo mysqld --validate-config ``` Inspect key runtime values: ```bash sudo mysql -NBe \ "SELECT @@version, @@bind_address, @@port, @@require_secure_transport;" ``` List application storage engines: ```bash sudo mysql -NBe \ "SELECT TABLE_NAME, ENGINE FROM information_schema.TABLES WHERE TABLE_SCHEMA='raffapp';" ``` Review recent logs: ```bash sudo journalctl -u mysql --no-pager -n 100 sudo tail -n 100 /var/log/mysql/error.log ``` Check disk growth: ```bash df -h / sudo du -sh /var/lib/mysql /var/backups/mysql ``` Do not copy generic `innodb_buffer_pool_size`, `max_connections`, or durability values into production. Measure the workload first and change one documented setting at a time. **Verify:** configuration validation succeeds, application tables use the intended storage engine, logs show no unresolved startup or storage errors, and backup growth does not threaten live data capacity. ## Step 14 — Verify MySQL end to end Run the final service, account, network, and backup checks: ```bash echo 'Service:' systemctl is-active mysql systemctl is-enabled mysql echo 'Version:' sudo mysql -NBe 'SELECT VERSION();' echo 'Root account:' sudo mysql -NBe \ "SELECT user, host, plugin FROM mysql.user WHERE user='root';" echo 'Application accounts:' sudo mysql -NBe \ "SELECT user, host, plugin, ssl_type FROM mysql.user WHERE user='raffappuser';" echo 'Listener:' sudo ss -lntp | grep ':3306' || true echo 'Firewall:' sudo ufw status numbered echo 'Recent backups:' sudo ls -lh /var/backups/mysql/raffapp-*.sql.gz | tail ``` Confirm all of these are true: - Ubuntu 24.04 manages the installation through its MySQL 8.0 packages; - MySQL is active and enabled; - root administration is local-only; - anonymous users and the test database are absent; - the application uses a separate `caching_sha2_password` account; - application privileges are scoped to the application database; - TCP 3306 is not publicly exposed; - optional private access is restricted to an exact source IP and uses TLS; - a logical backup exists and has been restored into an isolated database; - package updates are backed up and verified. **Verify:** the installation passes every check above, including successful application CRUD from Step 7 and the isolated restore from Step 11. :::cta Deploy Your Server Deploy MySQL on a Raff VM. ::: ## Cleanup (optional) Use this section only when the database, users, firewall rules, and backup files were created solely for this tutorial. > **Warning:** The commands below can permanently delete the tutorial database, database users, and backups. Keep anything you need before continuing. Drop the tutorial database and local application user: ```bash sudo mysql <<'SQL' DROP DATABASE IF EXISTS raffapp; DROP USER IF EXISTS 'raffappuser'@'localhost'; DROP USER IF EXISTS 'raffappuser'@'10.0.0.10'; SQL ``` If you completed the private-access step, restore the saved listener configuration: ```bash if [ -f /etc/mysql/mysql.conf.d/mysqld.cnf.before-private-access ]; then sudo cp /etc/mysql/mysql.conf.d/mysqld.cnf.before-private-access \ /etc/mysql/mysql.conf.d/mysqld.cnf sudo mysqld --validate-config sudo systemctl restart mysql fi ``` Delete only the UFW rules you added for this tutorial: ```bash sudo ufw delete allow from 10.0.0.10 to 10.0.0.5 port 3306 proto tcp sudo ufw delete deny 3306/tcp ``` Remove tutorial backups if they are disposable: ```bash sudo rm -f /var/backups/mysql/raffapp-*.sql.gz ``` Verify the tutorial state is gone: ```bash sudo mysql -NBe \ "SELECT schema_name FROM information_schema.schemata WHERE schema_name='raffapp';" sudo mysql -NBe \ "SELECT user, host FROM mysql.user WHERE user='raffappuser';" sudo ufw status numbered ``` The database and application-user queries return no rows. ## Troubleshooting ### `mysql.service` is not found This usually means the MySQL server package is not installed or the installation did not complete. Inspect package state: ```bash dpkg -l | grep -E '^ii\s+mysql-server' apt-cache policy mysql-server mysql-server-8.0 ``` Install the Ubuntu package and verify the unit: ```bash sudo apt update sudo apt install -y mysql-server systemctl status mysql --no-pager ``` **Verify:** `systemctl status mysql` finds the unit and reports the installed service state. ### `mysql_secure_installation`: command not found Ubuntu's MySQL 8.0 server-core package contains `/usr/bin/mysql_secure_installation`. Verify the binary and package: ```bash command -v mysql_secure_installation || true dpkg -S /usr/bin/mysql_secure_installation 2>/dev/null || true dpkg -l | grep -E '^ii\s+mysql-server-core-8.0' ``` If the package is installed but the binary is missing, reinstall the matching Ubuntu package: ```bash sudo apt install --reinstall mysql-server-core-8.0 command -v mysql_secure_installation ``` **Verify:** the command resolves to `/usr/bin/mysql_secure_installation`. ### `Access denied for user 'root'@'localhost'` Confirm service health, package source, and the server log before attempting any root-account reset: ```bash systemctl is-active mysql apt-cache policy mysql-server-8.0 sudo tail -n 100 /var/log/mysql/error.log ``` If `sudo mysql` previously worked and stopped working after account changes, inspect what changed rather than applying a password-reset procedure written for another distribution or package source. MySQL can use socket-based authentication for tightly restricted local administrative accounts. ### MySQL does not start after editing `mysqld.cnf` Validate the configuration and inspect logs: ```bash sudo mysqld --validate-config sudo journalctl -u mysql --no-pager -n 100 sudo tail -n 100 /var/log/mysql/error.log ``` Restore the pre-change configuration if validation fails. ### The app cannot authenticate with caching_sha2_password Upgrade the application's MySQL connector or runtime. MySQL 8.0 uses `caching_sha2_password` by default. Do not weaken the account to a legacy authentication plugin as the first fix. ### A private remote connection times out Check the listener, firewall, and account host together: ```bash sudo mysql -NBe 'SELECT @@bind_address, @@port;' sudo ss -lntp | grep ':3306' sudo ufw status numbered sudo mysql -NBe \ "SELECT user, host, plugin, ssl_type FROM mysql.user WHERE user='raffappuser';" ``` The application VM's source IP must match the listener, UFW rule, and MySQL account host. ### A private connection is not encrypted Connect with `--ssl-mode=REQUIRED` or stronger, then run: ```sql SHOW STATUS LIKE 'Ssl_cipher'; ``` A non-empty value confirms TLS for the session. ### mysqldump or restore fails Confirm the database exists, inspect storage engines, and verify free disk space: ```bash sudo mysql -e 'SHOW DATABASES;' sudo mysql -e \ "SELECT TABLE_NAME, ENGINE FROM information_schema.TABLES WHERE TABLE_SCHEMA='raffapp';" df -h / ``` For larger databases or tighter recovery objectives, logical dumps may need to be combined with additional database-aware and infrastructure recovery controls. ## FAQ ### How do I install MySQL on Ubuntu 24.04? Run `sudo apt update` and `sudo apt install -y mysql-server`, then verify the service with `systemctl is-active mysql` and the server version with `sudo mysql -NBe 'SELECT VERSION();'`. ### What MySQL version does Ubuntu 24.04 install? Ubuntu 24.04 currently tracks MySQL 8.0. The current Noble package is MySQL 8.0.46 as of September 17, 2026. ### Why does `sudo mysql` work without a MySQL root password? MySQL supports socket peer-credential authentication for local administrative accounts. Verify the actual root plugin with `SELECT user, host, plugin FROM mysql.user WHERE user='root';`. ### Should I run mysql_secure_installation? Yes for this tutorial. Verify the resulting account and database state afterward instead of relying only on the interactive prompts. ### Should port 3306 be public? No. Keep MySQL local when the app shares the VM. For a separate app server, use private networking, an exact source-IP rule, and TLS. ### Which authentication plugin should app users use? Use `caching_sha2_password` with a current connector. It is the default authentication plugin in MySQL 8.0. ### Is mysqldump enough for production recovery? It can be one recovery layer. Production plans also need off-server copies, retention, restore testing, monitoring, and recovery objectives that match the workload. ## Conclusion You now have MySQL 8.0 running on a Raff Ubuntu 24.04 VM with local-only administration, a dedicated application account, verified CRUD, private-by-default networking, a protected logical backup, and an isolated restore test. For production planning, continue with [MySQL Hosting: Managed vs Self-Hosted](/learn/guides/mysql-hosting-managed-vs-self-hosted), [Set Up a LEMP Stack on Ubuntu 24.04](/learn/tutorials/set-up-lemp-stack-ubuntu-24-04), and [Set Up UFW Firewall on Ubuntu 24.04](/learn/tutorials/set-up-ufw-firewall-ubuntu-24-04). If you prefer to avoid host-level database operations, compare [Raff Managed MySQL](/products/managed-databases/mysql). ## Sources - [Ubuntu 24.04 mysql-server package](https://packages.ubuntu.com/noble-updates/mysql-server-8.0) - [MySQL 8.0 caching_sha2_password](https://dev.mysql.com/doc/refman/8.0/en/caching-sha2-pluggable-authentication.html) - [MySQL Secure Deployment Guide: Authentication](https://dev.mysql.com/doc/mysql-secure-deployment-guide/8.0/en/secure-deployment-configure-authentication.html) - [MySQL 8.0 mysql_secure_installation](https://dev.mysql.com/doc/refman/8.0/en/mysql-secure-installation.html) - [MySQL 8.0 mysqldump](https://dev.mysql.com/doc/refman/8.0/en/mysqldump.html) - Package and technical guidance re-verified: 2026-09-17 --- ### How to Install MongoDB on Ubuntu 24.04 URL: https://rafftechnologies.com/learn/tutorials/install-mongodb-ubuntu-24-04 Description: Install MongoDB 8.3 on Ubuntu 24.04 from the official repository. Enable authentication, secure port 27017, and verify backup and restore safely. To install MongoDB on Ubuntu 24.04, use MongoDB's official Community APT repository rather than Ubuntu's conflicting `mongodb` packages. This tutorial installs the current **MongoDB 8.3** release line, enables authorization, creates separate administrator and application users, keeps port 27017 private, and verifies backup and restore. MongoDB's current release notes identify **8.3 as the latest minor release**. The latest 8.3 patch listed on September 17, 2026 is **8.3.11**, released September 11 with security and reliability fixes. The commands below intentionally install the latest candidate available from the 8.3 repository instead of pinning an older patch. Raff Linux VMs can run self-hosted MongoDB when you need host-level control. The original workflow was tested on a Raff VM with **2 vCPU and 4 GB RAM**. Raff does not currently list MongoDB among its managed database engines, so this tutorial follows the self-hosted Linux VM path. Keep MongoDB local-only until authentication is configured and verified. Port `27017` should not be exposed publicly just to make a client connection easier. :::cluster ## Step 1 — Verify Ubuntu 24.04 and the architecture Confirm the operating system and architecture: ```bash . /etc/os-release printf '%s\n%s\n%s\n' "$PRETTY_NAME" "$VERSION_CODENAME" "$(dpkg --print-architecture)" ``` Expected Ubuntu values include: ```text Ubuntu 24.04 LTS noble ``` MongoDB publishes Community packages for Ubuntu 24.04 on x64 and ARM64 platforms. Before making package changes, check CPU, memory, and disk headroom: ```bash nproc free -h df -h / ``` **Verify:** the server reports Ubuntu 24.04 with codename `noble`, uses a supported 64-bit architecture, and has enough free disk for the dataset plus backups. ## Step 2 — Check for conflicting MongoDB packages Refresh package metadata and install repository prerequisites: ```bash sudo apt update sudo apt install -y gnupg curl ca-certificates ufw ``` Check for existing MongoDB packages: ```bash dpkg -l | grep -E '^ii[[:space:]]+(mongodb|mongodb-server|mongodb-server-core|mongodb-org)' || true ``` MongoDB's official package family is `mongodb-org`. Ubuntu-provided packages such as `mongodb` or `mongodb-server-core` can conflict with it. Do not remove an existing package blindly. First identify its data directory, configuration, installed version, and recovery path. If this is a fresh VM, the command should normally return no MongoDB server package. **Verify:** there is no unexplained existing MongoDB installation or data directory that could be overwritten by the new official package. ## Step 3 — Add the official MongoDB 8.3 repository Import MongoDB's release signing key: ```bash curl -fsSL https://pgp.mongodb.com/server-8.0.asc | \ sudo gpg -o /usr/share/keyrings/mongodb-server-8.0.gpg \ --dearmor ``` Create the Ubuntu 24.04 Noble repository file for MongoDB Community 8.3: ```bash echo "deb [ arch=amd64,arm64 signed-by=/usr/share/keyrings/mongodb-server-8.0.gpg ] https://repo.mongodb.org/apt/ubuntu noble/mongodb-org/8.3 multiverse" | \ sudo tee /etc/apt/sources.list.d/mongodb-org-8.3.list >/dev/null ``` Refresh package metadata: ```bash sudo apt update ``` Inspect the candidate and source: ```bash apt-cache policy mongodb-org | sed -n '1,20p' ``` Do not hard-code a patch version unless you intentionally maintain a package pinning policy. The 8.3 repository should provide the current supported 8.3 patch. **Verify:** `apt-cache policy mongodb-org` shows a non-empty candidate from `repo.mongodb.org` under the Noble `mongodb-org/8.3` repository. ## Step 4 — Install MongoDB Community Edition Install the official metapackage: ```bash sudo apt install -y mongodb-org ``` Verify the installed tools: ```bash mongod --version | sed -n '1,8p' mongosh --version mongodump --version | sed -n '1,5p' mongorestore --version | sed -n '1,5p' ``` Confirm package ownership: ```bash apt-cache policy mongodb-org mongodb-org-server mongodb-mongosh mongodb-database-tools | \ sed -n '1,40p' ``` **Verify:** `mongod` reports an 8.3-series server, `mongosh` and Database Tools are installed, and package policy points to MongoDB's official repository. ## Step 5 — Start MongoDB and verify the local listener Enable and start the service: ```bash sudo systemctl enable --now mongod ``` Verify systemd state: ```bash systemctl is-active mongod systemctl is-enabled mongod sudo systemctl status mongod --no-pager ``` Before authorization is enabled, confirm the fresh server responds locally: ```bash mongosh --quiet --eval 'db.runCommand({ ping: 1 })' ``` Inspect the listener and active network configuration: ```bash sudo ss -lntp | grep ':27017' || true sudo grep -nE '^[[:space:]]*(port|bindIp):' /etc/mongod.conf ``` A fresh package installation should remain bound to localhost during authentication bootstrap. **Verify:** `mongod` is active and enabled, local `ping` succeeds, and TCP 27017 is not listening on a public interface. ## Step 6 — Enable authorization while MongoDB is local-only Back up the configuration: ```bash sudo cp -a /etc/mongod.conf \ "/etc/mongod.conf.$(date -u +%Y%m%dT%H%M%SZ).backup" ``` Edit the configuration: ```bash sudo nano /etc/mongod.conf ``` Keep MongoDB on loopback and enable authorization: ```yaml net: port: 27017 bindIp: 127.0.0.1 security: authorization: enabled ``` Restart the service: ```bash sudo systemctl restart mongod systemctl is-active mongod ``` MongoDB's localhost exception allows the first administrator to be created from localhost while no users or roles exist. The exception closes after the first user or role is created. **Verify:** MongoDB restarts with authorization enabled, remains bound to `127.0.0.1`, and no user exists before the bootstrap step. ## Step 7 — Create the first administrator Generate a strong administrator password and store it in your secrets manager: ```bash MONGO_ADMIN_PASSWORD="$(openssl rand -hex 32)" printf 'Store this MongoDB admin password securely: %s\n' "$MONGO_ADMIN_PASSWORD" export MONGO_ADMIN_PASSWORD ``` Use the localhost exception to create the first administrator in the `admin` database: ```bash mongosh --quiet --host 127.0.0.1 --eval ' const adminDb = db.getSiblingDB("admin"); adminDb.createUser({ user: "raffadmin", pwd: process.env.MONGO_ADMIN_PASSWORD, roles: [ { role: "root", db: "admin" } ] }); // The localhost exception ends after this user is created. // Verify the account using the authenticated command below. ' ``` Remove the shell variable after storing the credential: ```bash unset MONGO_ADMIN_PASSWORD ``` Confirm unauthenticated user administration is now rejected: ```bash mongosh --quiet --host 127.0.0.1 \ --eval 'db.getSiblingDB("admin").getUsers()' ``` Authenticate as the administrator. Omitting the password value makes `mongosh` prompt securely: ```bash mongosh --quiet \ --host 127.0.0.1 \ --username raffadmin \ --authenticationDatabase admin \ --password \ --eval 'printjson(db.runCommand({ connectionStatus: 1 }).authInfo.authenticatedUsers)' ``` **Verify:** unauthenticated user-management commands fail and `raffadmin` authenticates successfully against `admin`. ## Step 8 — Create a database-scoped application user Generate a separate application password: ```bash MONGO_APP_PASSWORD="$(openssl rand -hex 32)" printf 'Store this MongoDB application password securely: %s\n' "$MONGO_APP_PASSWORD" export MONGO_APP_PASSWORD ``` Create the application account with `readWrite` only on `raffapp`: ```bash mongosh --quiet \ --host 127.0.0.1 \ --username raffadmin \ --authenticationDatabase admin \ --password \ --eval ' const appDb = db.getSiblingDB("raffapp"); appDb.createUser({ user: "raffappuser", pwd: process.env.MONGO_APP_PASSWORD, roles: [ { role: "readWrite", db: "raffapp" } ] }); printjson(appDb.getUser("raffappuser")); ' ``` Remove the shell variable: ```bash unset MONGO_APP_PASSWORD ``` Do not use the administrator credential in application configuration. The application account should authenticate against the database where it was created. **Verify:** `raffappuser` exists in `raffapp`, has only the required application role, and has no administrative role. ## Step 9 — Run an authenticated CRUD test Connect as the application user and test create, read, update, and delete operations: ```bash mongosh "mongodb://127.0.0.1:27017/raffapp" \ --quiet \ --username raffappuser \ --authenticationDatabase raffapp \ --password \ --eval ' const c = db.getSiblingDB("raffapp").tutorial_check; c.deleteMany({ name: "raff-mongodb-test" }); const inserted = c.insertOne({ name: "raff-mongodb-test", status: "created", createdAt: new Date() }); const created = c.findOne({ name: "raff-mongodb-test" }); const updated = c.updateOne( { name: "raff-mongodb-test" }, { $set: { status: "verified" } } ); const verified = c.findOne({ name: "raff-mongodb-test" }); const deleted = c.deleteOne({ name: "raff-mongodb-test" }); printjson({ insertedId: inserted.insertedId, createdStatus: created.status, modifiedCount: updated.modifiedCount, verifiedStatus: verified.status, deletedCount: deleted.deletedCount }); ' ``` Expected fields include `created`, `modifiedCount: 1`, `verified`, and `deletedCount: 1`. **Verify:** the non-admin application user completes CRUD operations only inside its assigned database. ## Step 10 — Keep port 27017 private Confirm the configured bind address and active listener: ```bash sudo grep -nE '^[[:space:]]*(port|bindIp):' /etc/mongod.conf sudo ss -lntp | grep ':27017' || true ``` For an application on the same VM, keep: ```yaml net: port: 27017 bindIp: 127.0.0.1 ``` Do not bind MongoDB to `0.0.0.0` simply to make Compass or another client convenient. Before changing UFW, open a second SSH session and inspect the current rules: ```bash sudo ufw status numbered ``` If UFW is already active and no private MongoDB rule is intended, add a defense-in-depth deny: ```bash sudo ufw deny 27017/tcp ``` If UFW is inactive, follow [Set Up UFW Firewall on Ubuntu 24.04](/learn/tutorials/set-up-ufw-firewall-ubuntu-24-04) rather than enabling it blindly from one remote shell. **Verify:** MongoDB listens only on loopback for this deployment and no public firewall rule permits TCP 27017. ## Step 11 — Create a logical backup with mongodump MongoDB Database Tools provide `mongodump` and `mongorestore` for logical BSON backups. For a standalone server, a live `mongodump` is not a transactionally consistent multi-collection point-in-time snapshot while writes continue. Quiesce writes or use an appropriate maintenance window when that consistency matters. Create a protected root-owned backup directory: ```bash sudo install -d -m 700 /var/backups/mongodb STAMP="$(date -u +%Y%m%d-%H%M%S)" BACKUP_FILE="/var/backups/mongodb/raffapp-${STAMP}.archive.gz" ``` Create a compressed archive. Running `mongodump` with `sudo` allows it to write into the protected backup directory while `--password` still prompts instead of placing the secret in command history: ```bash sudo mongodump \ --host 127.0.0.1 \ --username raffadmin \ --authenticationDatabase admin \ --password \ --db raffapp \ --archive="$BACKUP_FILE" \ --gzip ``` Restrict and inspect the archive: ```bash sudo chmod 600 "$BACKUP_FILE" sudo ls -lh "$BACKUP_FILE" ``` Back up the server configuration separately: ```bash sudo cp /etc/mongod.conf "/var/backups/mongodb/mongod.conf-${STAMP}" sudo chmod 600 "/var/backups/mongodb/mongod.conf-${STAMP}" ``` Keep production backup copies outside the database VM. Raff [Object Storage](/products/object-storage) can be used by S3-compatible backup tooling, while [Data Protection](/products/data-protection) provides an additional VM-level recovery layer. **Verify:** the archive and configuration backup exist with restrictive permissions, application writes were controlled when consistency required it, and production recovery includes an off-server copy. ## Step 12 — Restore-test into an isolated namespace Never test a backup by overwriting `raffapp`. Select the latest archive: ```bash LATEST_BACKUP="$(sudo find /var/backups/mongodb -maxdepth 1 -type f -name 'raffapp-*.archive.gz' -print | LC_ALL=C sort | tail -n 1)" # Stop here if no readable backup was selected. if [ -z "$LATEST_BACKUP" ] || ! sudo test -s "$LATEST_BACKUP"; then printf '%s\n' 'No non-empty backup found. Do not continue with restore.' >&2 false fi printf '%s\n' "$LATEST_BACKUP" ``` Restore `raffapp.*` into a disposable namespace: ```bash sudo mongorestore \ --host 127.0.0.1 \ --username raffadmin \ --authenticationDatabase admin \ --password \ --archive="$LATEST_BACKUP" \ --gzip \ --nsFrom='raffapp.*' \ --nsTo='raffapp_restore_test.*' ``` Inspect restored collections: ```bash mongosh --quiet \ --host 127.0.0.1 \ --username raffadmin \ --authenticationDatabase admin \ --password \ --eval ' const restoreDb = db.getSiblingDB("raffapp_restore_test"); printjson(restoreDb.getCollectionNames()); ' ``` For a production recovery rehearsal, also verify representative documents and indexes. Remove only the disposable restore database: ```bash mongosh --quiet \ --host 127.0.0.1 \ --username raffadmin \ --authenticationDatabase admin \ --password \ --eval 'printjson(db.getSiblingDB("raffapp_restore_test").dropDatabase())' ``` **Verify:** the archive restores into `raffapp_restore_test`, expected collections and documents are readable, and production `raffapp` remains untouched. ## Step 13 — Optionally allow one private application VM with TLS Use this only when the application and MongoDB run on separate VMs connected through [Raff VPC](/products/vpc). Authorization alone does not encrypt database traffic. Example design: ```text MongoDB private IP: 10.0.0.5 Application private IP: 10.0.0.10 Private DNS name in certificate SAN: mongo.internal.example ``` Use a CA you control to issue the MongoDB server certificate. Store the combined server certificate and private key plus the CA certificate at controlled paths: ```text /etc/mongodb/tls/server.pem /etc/mongodb/tls/ca.pem ``` Protect the files: ```bash sudo chown -R root:mongodb /etc/mongodb/tls sudo chmod 750 /etc/mongodb/tls sudo chmod 640 /etc/mongodb/tls/server.pem sudo chmod 644 /etc/mongodb/tls/ca.pem ``` This example uses SCRAM username/password authentication over required TLS, not client-certificate authentication. `allowConnectionsWithoutCertificates: true` permits clients without a client certificate; authorization and server-certificate validation remain enabled. Create the certificate files first and ensure the private DNS name resolves on both hosts. Before enabling a private listener, require an active firewall and review existing rules. If UFW is inactive, complete the linked UFW setup first while preserving SSH. Place the exact-source rule before the earlier blanket deny; remove any conflicting broad allow rule only after reviewing its purpose. ```bash sudo ufw insert 1 allow from 10.0.0.10 to 10.0.0.5 port 27017 proto tcp sudo ufw status numbered ``` Configure the private listener and required TLS in `/etc/mongod.conf`: ```yaml net: port: 27017 bindIp: 127.0.0.1,10.0.0.5 tls: mode: requireTLS certificateKeyFile: /etc/mongodb/tls/server.pem CAFile: /etc/mongodb/tls/ca.pem allowConnectionsWithoutCertificates: true security: authorization: enabled ``` Restart and verify: ```bash sudo systemctl restart mongod systemctl is-active mongod sudo ss -lntp | grep ':27017' ``` Recheck the firewall rules configured before enabling the private listener. Copy only the CA certificate to the application VM and connect using the DNS name represented in the certificate: ```bash mongosh "mongodb://mongo.internal.example:27017/raffapp" \ --tls \ --tlsCAFile /path/to/ca.pem \ --username raffappuser \ --authenticationDatabase raffapp \ --password \ --eval 'db.runCommand({ ping: 1 })' ``` Do not use `--tlsAllowInvalidCertificates` or `--tlsAllowInvalidHostnames` as a production shortcut. **Verify:** MongoDB listens only on loopback plus the intended private interface, UFW allows only the application VM, and the client connects with valid certificate verification. ## Step 14 — Apply updates and verify MongoDB end to end Check pending MongoDB packages: ```bash apt list --upgradable 2>/dev/null | grep -E '^mongodb-' || true ``` Patch updates within the configured release line can use the package manager. Major and minor release changes require the corresponding MongoDB upgrade procedure and Feature Compatibility Version review. Apply normal package updates: ```bash sudo apt update sudo apt upgrade ``` Verify package, service, listener, and firewall state: ```bash echo 'Package:' apt-cache policy mongodb-org | sed -n '1,14p' echo 'Version:' mongod --version | sed -n '1,8p' echo 'Service:' systemctl is-active mongod systemctl is-enabled mongod echo 'Listener:' sudo ss -lntp | grep ':27017' || true echo 'Firewall:' sudo ufw status numbered ``` Verify the administrator, application user, and FCV: ```bash mongosh --quiet \ --host 127.0.0.1 \ --username raffadmin \ --authenticationDatabase admin \ --password \ --eval ' printjson({ admin: db.getSiblingDB("admin").getUser("raffadmin"), app: db.getSiblingDB("raffapp").getUser("raffappuser"), fcv: db.adminCommand({ getParameter: 1, featureCompatibilityVersion: 1 }) }); ' ``` If you enabled `requireTLS`, replace `--host 127.0.0.1` in subsequent `mongosh`, backup, restore, and cleanup commands with `--host mongo.internal.example --tls --tlsCAFile /etc/mongodb/tls/ca.pem`. The hostname must resolve locally and match the certificate SAN. Plaintext commands will fail after this change. The deployment is complete when all of these are true: - MongoDB comes from the intended official 8.3 repository; - `mongod` is active and enabled; - authorization is enabled; - the localhost exception has closed; - administrator and application identities are separate; - the application user is scoped to `raffapp`; - public TCP 27017 is blocked; - optional private remote access uses exact source filtering and validated TLS; - a logical backup exists off-server; - an isolated restore test has succeeded; - package updates and release upgrades are treated as different operations. **Verify:** every final check above succeeds and the CRUD and restore tests still pass after maintenance. :::cta Deploy Your Server Run MongoDB on a Raff VM. ::: ## Cleanup (optional) Use this section only when the users, database, backups, firewall rules, and TLS configuration were created solely for this tutorial. > **Warning:** These commands can permanently delete tutorial data and credentials. Drop the application database as the administrator: ```bash mongosh --quiet \ --host 127.0.0.1 \ --username raffadmin \ --authenticationDatabase admin \ --password \ --eval 'printjson(db.getSiblingDB("raffapp").dropDatabase())' ``` Drop the application user if the database drop did not already remove it: ```bash mongosh --quiet \ --host 127.0.0.1 \ --username raffadmin \ --authenticationDatabase admin \ --password \ --eval ' const appDb = db.getSiblingDB("raffapp"); if (appDb.getUser("raffappuser")) printjson(appDb.dropUser("raffappuser")); ' ``` **Warning:** The next commands permanently delete all backups matching these tutorial filenames. Keep an off-server copy of anything you need. Run them only in a disposable tutorial environment: ```bash sudo find /var/backups/mongodb -maxdepth 1 -type f -name 'raffapp-*.archive.gz' -print -delete sudo find /var/backups/mongodb -maxdepth 1 -type f -name 'mongod.conf-*' -print -delete ``` Delete only the UFW rules you added for this tutorial: ```bash sudo ufw delete allow from 10.0.0.10 to 10.0.0.5 port 27017 proto tcp sudo ufw delete deny 27017/tcp ``` If you added private TLS solely for this tutorial, restore your timestamped `/etc/mongod.conf.*.backup` file before deleting certificate files. Do not remove `raffadmin` unless you are intentionally decommissioning this MongoDB instance and have another tested administrative and recovery path. ## Troubleshooting ### `mongodb-org` has no installation candidate Check the Ubuntu codename, repository file, and package candidate: ```bash . /etc/os-release echo "$VERSION_CODENAME" cat /etc/apt/sources.list.d/mongodb-org-8.3.list sudo apt update apt-cache policy mongodb-org ``` Expected signals include `noble`, `repo.mongodb.org`, `mongodb-org/8.3`, and a non-empty candidate. ### `gpg: no valid OpenPGP data found` Re-run the official key command exactly and verify the downloaded data before writing the keyring: ```bash curl -fsSL https://pgp.mongodb.com/server-8.0.asc | head ``` Then import it: ```bash curl -fsSL https://pgp.mongodb.com/server-8.0.asc | \ sudo gpg -o /usr/share/keyrings/mongodb-server-8.0.gpg \ --dearmor ``` If the first command returns an HTML error, proxy page, or empty response, fix that network or DNS problem before continuing. ### `mongosh: command not found` Verify the shell package: ```bash dpkg -l | grep mongodb-mongosh apt-cache policy mongodb-mongosh ``` Install or repair the package from the official repository: ```bash sudo apt update sudo apt install -y mongodb-mongosh mongosh --version ``` ### `mongod.service` is not found This usually means `mongodb-org-server` was not installed successfully. Check package state: ```bash dpkg -l | grep -E '^ii[[:space:]]+mongodb-org-server' apt-cache policy mongodb-org-server ``` Install the official metapackage if needed: ```bash sudo apt update sudo apt install -y mongodb-org sudo systemctl enable --now mongod ``` ### `mongodb-database-tools` cannot be located Confirm the 8.3 repository is active and inspect the package candidate: ```bash sudo apt update apt-cache policy mongodb-database-tools ``` If the candidate is empty, fix the repository or key error first. Do not add unrelated Ubuntu MongoDB packages to work around a broken official repository. ### Authentication fails after first-user creation The localhost exception closes after the first user or role exists. Authenticate with the correct authentication database: ```bash mongosh --quiet \ --host 127.0.0.1 \ --username raffadmin \ --authenticationDatabase admin \ --password \ --eval 'printjson(db.runCommand({ connectionStatus: 1 }).authInfo)' ``` For `raffappuser`, use `--authenticationDatabase raffapp`. ### MongoDB listens on a public interface Restore a local-only listener: ```yaml net: port: 27017 bindIp: 127.0.0.1 ``` Restart and verify: ```bash sudo systemctl restart mongod sudo ss -lntp | grep ':27017' ``` ### mongodump or mongorestore returns permission denied The backup directory in this tutorial is root-owned with mode 700. Run the backup and restore commands with `sudo` as shown in Steps 11 and 12, or use a separate protected directory owned by the dedicated backup operator. ### TLS connections fail after requireTLS Check file permissions, certificate SANs, listener state, and service logs: ```bash sudo ls -l /etc/mongodb/tls sudo ss -lntp | grep ':27017' sudo journalctl -u mongod --no-pager -n 100 ``` Use the hostname represented in the server certificate and the correct CA file. Do not bypass certificate or hostname validation to hide a trust-chain problem. ## FAQ ### How do I install MongoDB on Ubuntu 24.04? Add MongoDB's official 8.3 APT repository for Ubuntu Noble, run `sudo apt install -y mongodb-org`, then enable and verify the `mongod` service. ### What MongoDB version should I install on Ubuntu 24.04? MongoDB 8.3 is the current minor release line. As of September 17, 2026, the latest listed patch is 8.3.11. Install the current candidate from the official 8.3 repository. ### Does MongoDB support Ubuntu 24.04? Yes. MongoDB publishes Ubuntu 24.04 Community packages for supported 64-bit x64 and ARM64 platforms. ### Should MongoDB port 27017 be public? No. Keep it on loopback for same-VM applications. For a separate app VM, use private networking, exact source filtering, authorization, and validated TLS. ### Why is mongosh command not found? The MongoDB Shell is provided by the `mongodb-mongosh` package. Verify the official repository is configured, then install or repair that package with APT. ### How should I back up MongoDB? Use `mongodump` for a logical archive, keep an off-server copy, and prove recovery with `mongorestore` into an isolated namespace. Coordinate writes when standalone cross-collection consistency matters. ### Is MongoDB 8.0 to 8.3 a normal patch update? No. Patch updates stay inside the configured release line. Moving from 8.0 to 8.3 is a release upgrade that requires MongoDB's documented upgrade and FCV procedure. ## Conclusion You now have MongoDB 8.3 Community Edition on a Raff Ubuntu 24.04 VM with official packages, authorization, separate administrator and application users, authenticated CRUD, private-by-default networking, and an isolated backup restore test. MongoDB 8.3.11 is the latest 8.3 patch listed as of September 17, 2026. Keep routine patch maintenance separate from release upgrades, and review MongoDB's documented upgrade path before moving an existing deployment between release lines. Continue with [MongoDB Hosting](/learn/guides/mongodb-hosting), [MongoDB vs PostgreSQL](/learn/guides/mongodb-vs-postgresql), and [Set Up UFW Firewall on Ubuntu 24.04](/learn/tutorials/set-up-ufw-firewall-ubuntu-24-04). ## Sources - [MongoDB installation overview](https://www.mongodb.com/docs/manual/installation/) - [MongoDB 8.3 release notes](https://www.mongodb.com/docs/manual/release-notes/8.3/) - [MongoDB Community Ubuntu troubleshooting](https://www.mongodb.com/docs/manual/reference/installation-ubuntu-community-troubleshooting/) - [MongoDB localhost exception](https://www.mongodb.com/docs/manual/core/localhost-exception/) - [MongoDB SCRAM authentication](https://www.mongodb.com/docs/manual/tutorial/configure-scram-client-authentication/) - [MongoDB configuration options](https://www.mongodb.com/docs/manual/reference/configuration-options/) - [MongoDB 8.0 to 8.3 upgrade](https://www.mongodb.com/docs/manual/release-notes/8.3-upgrade-from-8.0-standalone/) - [mongodump](https://www.mongodb.com/docs/database-tools/mongodump/) - [mongorestore](https://www.mongodb.com/docs/database-tools/mongorestore/) - Package, security, backup, and upgrade guidance re-verified: 2026-09-17 --- ### How to Deploy Gitea with Docker Compose on Ubuntu 24.04 URL: https://rafftechnologies.com/learn/tutorials/deploy-gitea-ubuntu-24-04 Description: Deploy Gitea on Ubuntu 24.04 with Docker Compose, PostgreSQL, Nginx, HTTPS, SSH clone access, backups, upgrades, and verification steps. Gitea is a self-hosted Git server for teams that want repository hosting, pull requests, issues, releases, packages, webhooks, and other development workflows on infrastructure they control. In this tutorial, you will deploy Gitea on a Raff Technologies Linux VM with Docker Compose, PostgreSQL, Nginx, HTTPS, and SSH clone access. The web service stays bound to localhost behind Nginx, while Git-over-SSH uses a separate host port so it does not conflict with the VM's administrative SSH service. This guide follows Gitea's current Docker deployment model and uses the official `docker.gitea.com/gitea` image. At the time of this update, Gitea's official installation documentation uses the 1.27.3 release in its stable Docker examples. The official docs also recommend choosing a database early rather than relying on SQLite when you expect the instance to grow; this tutorial uses PostgreSQL for a multi-user setup. See the [Gitea Docker installation documentation](https://docs.gitea.com/installation/install-with-docker/) and [database preparation guidance](https://docs.gitea.com/installation/database-prep/) for the upstream reference. You need Ubuntu 24.04, Docker with Compose v2, Nginx, a domain such as `git.example.com`, SSH access with sudo privileges, and DNS pointing the domain to the VM. ## Step 1 — Confirm Docker, DNS, and the Ubuntu Host Check the Ubuntu release: ```bash cat /etc/os-release ``` Confirm Docker and Compose are available: ```bash docker --version docker compose version ``` Check that your Gitea hostname resolves to the VM: ```bash dig +short A git.example.com ``` If Docker is not installed yet, follow [How to Install Docker on Ubuntu 24.04](/learn/tutorials/install-docker-ubuntu-24-04). If Nginx is missing, use [How to Install Nginx on Ubuntu 24.04](/learn/tutorials/install-nginx-ubuntu-24-04). **Verify:** Ubuntu should report 24.04, `docker compose version` should work, and the DNS A record should return the VM's public IPv4 address. ## Step 2 — Create the Gitea Project and Protect Database Secrets Create a dedicated project directory: ```bash mkdir -p ~/gitea cd ~/gitea ``` Generate a strong PostgreSQL password: ```bash openssl rand -hex 32 ``` Create an environment file: ```bash nano .env ``` Add the generated password: ```dotenv POSTGRES_PASSWORD=replace_with_your_generated_password ``` Restrict the file so other local users cannot read it: ```bash chmod 600 .env ``` Do not commit this `.env` file to a Git repository. **Verify:** Run `stat -c '%a %n' .env`. It should show permission mode `600` for `.env`. ## Step 3 — Create the Docker Compose Stack Create the Compose file: ```bash nano compose.yaml ``` Add: ```yaml services: gitea: image: docker.gitea.com/gitea:1.27.3 container_name: gitea restart: unless-stopped environment: USER_UID: "1000" USER_GID: "1000" GITEA__database__DB_TYPE: postgres GITEA__database__HOST: db:5432 GITEA__database__NAME: gitea GITEA__database__USER: gitea GITEA__database__PASSWD: ${POSTGRES_PASSWORD} GITEA__server__DOMAIN: git.example.com GITEA__server__ROOT_URL: https://git.example.com/ GITEA__server__SSH_DOMAIN: git.example.com GITEA__server__SSH_PORT: "2222" volumes: - gitea_data:/data - /etc/timezone:/etc/timezone:ro - /etc/localtime:/etc/localtime:ro ports: - "127.0.0.1:3000:3000" - "2222:22" depends_on: db: condition: service_healthy db: image: postgres:16-alpine container_name: gitea-db restart: unless-stopped environment: POSTGRES_USER: gitea POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} POSTGRES_DB: gitea volumes: - postgres_data:/var/lib/postgresql/data healthcheck: test: ["CMD-SHELL", "pg_isready -U gitea -d gitea"] interval: 10s timeout: 5s retries: 5 volumes: gitea_data: postgres_data: ``` Replace every `git.example.com` value with your real hostname. Gitea supports PostgreSQL 12 and newer, so PostgreSQL 16 is within the supported range. The web port is published only on `127.0.0.1`; Nginx will be the public HTTP entry point. Host port `2222` carries Git-over-SSH and stays separate from the VM's normal SSH port 22. Check the rendered Compose configuration without printing secret values into a public log: ```bash docker compose config --services ``` **Verify:** The command should list exactly `gitea` and `db`, and `docker compose config -q` should exit without a validation error. ## Step 4 — Start Gitea and PostgreSQL Start the stack: ```bash docker compose up -d ``` Check container state: ```bash docker compose ps ``` Review recent logs: ```bash docker compose logs --tail=50 gitea docker compose logs --tail=50 db ``` Test the local Gitea HTTP endpoint: ```bash curl -I http://127.0.0.1:3000 ``` The first startup may take longer while the database initializes and Gitea prepares its data directory. **Verify:** `docker compose ps` should show the database healthy and Gitea running, while `curl -I http://127.0.0.1:3000` should return an HTTP response. ## Step 5 — Configure Nginx as the Public Reverse Proxy Create an Nginx server block: ```bash sudo nano /etc/nginx/sites-available/git.example.com ``` Add: ```nginx server { listen 80; listen [::]:80; server_name git.example.com; location / { client_max_body_size 512M; proxy_pass http://127.0.0.1:3000; proxy_http_version 1.1; proxy_set_header Connection $http_connection; proxy_set_header Upgrade $http_upgrade; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; } } ``` Gitea's reverse-proxy guidance requires the public `ROOT_URL` to match the external URL and expects the proxy to preserve the host and forwarded protocol. The upload-size limit prevents Nginx from rejecting larger web uploads with `413 Request Entity Too Large`. See the [official Gitea reverse proxy documentation](https://docs.gitea.com/administration/reverse-proxies/). Enable the site: ```bash sudo ln -s /etc/nginx/sites-available/git.example.com \ /etc/nginx/sites-enabled/git.example.com ``` Test and reload Nginx: ```bash sudo nginx -t sudo systemctl reload nginx ``` **Verify:** `sudo nginx -t` should report successful syntax, and `curl -I http://git.example.com` should reach the Gitea site through Nginx. ## Step 6 — Enable HTTPS and Open Only the Required Public Ports If UFW is active, first confirm administrative SSH is allowed: ```bash sudo ufw status sudo ufw allow OpenSSH ``` Allow HTTP/HTTPS and the Gitea SSH clone port: ```bash sudo ufw allow 'Nginx Full' sudo ufw allow 2222/tcp ``` Install Certbot and request a certificate: ```bash sudo apt install -y certbot python3-certbot-nginx sudo certbot --nginx --redirect -d git.example.com ``` Test renewal: ```bash sudo certbot renew --dry-run ``` Do not expose container port 3000 publicly; it should remain bound to localhost. **Verify:** `curl -I https://git.example.com` should complete over HTTPS, HTTP should redirect to HTTPS, and `sudo ss -ltnp` should show Gitea's web port bound to `127.0.0.1:3000` rather than `0.0.0.0:3000`. ## Step 7 — Complete the Gitea Installation and Create the First Administrator Open: ```text https://git.example.com ``` The Docker environment variables already provide the PostgreSQL connection values and public server URL. Confirm the database host is `db:5432`, database name is `gitea`, and the public site URL matches your HTTPS hostname. Create the initial administrator account with a strong unique password. After the installation finishes, sign in and review the site administration settings. For a private team instance, disable open registration after creating the accounts you need. Edit `compose.yaml` and add this environment variable to the `gitea` service: ```yaml GITEA__service__DISABLE_REGISTRATION: "true" ``` Apply the change: ```bash cd ~/gitea docker compose up -d gitea ``` Then open the sign-up page in a private browser session and confirm public registration is no longer available. Also require multi-factor authentication for administrator accounts and keep a separate day-to-day user account instead of using the administrator identity for normal Git work. **Verify:** You should be able to sign in as the administrator over HTTPS, reach the Site Administration area without a certificate warning, and confirm that open self-registration is disabled for a private team deployment. ## Step 8 — Configure and Test Git-over-SSH In Gitea, add your public SSH key under your user settings. From your workstation, test the dedicated Git SSH port: ```bash ssh -T -p 2222 git@git.example.com ``` The connection may report that interactive shell access is disabled; that is expected for a Git service. The important result is that the connection reaches Gitea rather than the VM's normal SSH daemon. If port 2222 is not reachable, check: ```bash sudo ufw status docker compose ps sudo ss -ltnp | grep 2222 ``` **Verify:** `ssh -T -p 2222 git@git.example.com` should reach the Gitea SSH service associated with your account. ## Step 9 — Create a Repository and Push the First Commit Create a repository in the Gitea web interface, for example `demo-repo`. Then clone it from your workstation using the SSH URL shown by Gitea: ```bash git clone ssh://git@git.example.com:2222/your_username/demo-repo.git cd demo-repo ``` Create a file and push a commit: ```bash printf '# Gitea test repository\n' > README.md git add README.md git commit -m "Add README" git push origin main ``` If the repository was created with a different default branch, use the branch name shown by Gitea instead of assuming `main`. **Verify:** Refresh the repository in the browser. The new commit and README should appear, proving that SSH authentication, repository storage, Git receive hooks, and the database are working together. :::cta Deploy Your Server Deploy a Raff Linux VM and use this tutorial to run a self-hosted Gitea Git server with Docker Compose, PostgreSQL, Nginx, and HTTPS. ::: ## Step 10 — Add a Consistent Backup Workflow Gitea contains repositories, configuration, application data, and database state. Gitea's official backup guidance recommends stopping the Gitea application while taking a consistency-sensitive backup so the database and repository state cannot change independently during the operation. See [Gitea Backup and Restore](https://docs.gitea.com/administration/backup-and-restore/). Create a backup directory: ```bash mkdir -p ~/gitea-backups BACKUP_DIR="$HOME/gitea-backups/$(date +%F-%H%M%S)" mkdir -p "$BACKUP_DIR" ``` Stop the application container but keep PostgreSQL available for the database dump: ```bash cd ~/gitea docker compose stop gitea ``` Dump PostgreSQL: ```bash docker compose exec -T db \ pg_dump -U gitea -d gitea > "$BACKUP_DIR/gitea-db.sql" ``` Back up the Gitea data volume: ```bash docker run --rm \ -v gitea_gitea_data:/data:ro \ -v "$BACKUP_DIR":/backup \ alpine \ tar -czf /backup/gitea-data.tar.gz -C /data . ``` Copy the non-secret deployment configuration: ```bash cp compose.yaml "$BACKUP_DIR/" ``` Do not copy a plaintext `.env` containing the PostgreSQL password into an off-server backup archive. If you need the secret file for disaster recovery, encrypt it before it leaves the VM: ```bash openssl enc -aes-256-cbc -salt -pbkdf2 \ -in .env \ -out "$BACKUP_DIR/gitea-env.enc" chmod 600 "$BACKUP_DIR/gitea-env.enc" ``` Use a strong encryption passphrase and store that passphrase separately from the backup. During recovery, decrypt the file only on the recovery host: ```bash openssl enc -d -aes-256-cbc -pbkdf2 \ -in gitea-env.enc \ -out .env chmod 600 .env ``` Start Gitea again: ```bash docker compose start gitea ``` The named volume is normally `gitea_gitea_data` when the Compose project directory is `~/gitea`. Confirm the real name with `docker volume ls` before using the backup command if you changed the project name. Store at least one backup away from the VM. Raff [Data Protection](/products/data-protection) can protect the server layer, and [Object Storage](/products/object-storage) can be used as an off-server destination for backup archives when your workflow supports S3-compatible storage. **Verify:** Confirm `gitea-db.sql`, `gitea-data.tar.gz`, `compose.yaml`, and `gitea-env.enc` exist in the timestamped backup directory and are non-empty. A backup is not proven until you can restore it, so schedule a recovery rehearsal on an isolated host. For the broader workflow, see [Docker Compose Backup and Restore Strategy](/learn/guides/docker-compose-backup-restore-strategy). ## Step 11 — Upgrade Gitea Safely Before an upgrade, read the Gitea changelog and create a backup. Gitea explicitly recommends having a backup even for production patch upgrades because startup can perform database migrations and an older binary may not be able to use a migrated database. Check the current version: ```bash docker exec gitea gitea --version ``` After reviewing the target release, edit `compose.yaml` and change the pinned image tag to the version you intend to run. Then pull the image: ```bash docker compose pull gitea ``` After your backup is complete, recreate the Gitea container: ```bash docker compose up -d gitea ``` Review startup logs and the reported version: ```bash docker compose logs --tail=100 gitea docker exec gitea gitea --version ``` Do not upgrade PostgreSQL to a new major version merely by changing `postgres:16-alpine` to another major tag. PostgreSQL major-version upgrades require a proper `pg_upgrade` or dump-and-restore workflow. **Verify:** The Gitea container should start without repeating migration errors, the expected version should be reported, and an existing repository should still open and accept a test fetch. ## Step 12 — Troubleshoot the Most Common Gitea Deployment Failures If Gitea cannot connect to PostgreSQL, inspect both services: ```bash docker compose logs --tail=100 gitea docker compose logs --tail=100 db ``` Confirm both services receive the same `POSTGRES_PASSWORD` through the Compose configuration and that the Gitea database host is `db:5432`, not `localhost:5432`. If generated links or clone URLs use the wrong scheme or hostname, verify: - `GITEA__server__ROOT_URL=https://git.example.com/` - the Nginx `Host` header - the Nginx `X-Forwarded-Proto` header If large uploads fail with HTTP 413, increase `client_max_body_size` deliberately based on your repository and package-upload policy rather than removing the limit entirely. If SSH clone URLs show the wrong port, confirm `GITEA__server__SSH_PORT` matches the public host port in Compose. **Verify:** After each fix, run `docker compose ps`, `curl -I https://git.example.com`, and `ssh -T -p 2222 git@git.example.com` to confirm the affected path is healthy. ## Step 13 — Run the Final End-to-End Verification Check containers: ```bash docker compose ps ``` Check the public HTTPS endpoint: ```bash curl -I https://git.example.com ``` Check the localhost-only backend: ```bash curl -I http://127.0.0.1:3000 ``` Check Git SSH access: ```bash ssh -T -p 2222 git@git.example.com ``` From a cloned test repository, verify a fetch: ```bash git fetch origin ``` Review recent errors: ```bash docker compose logs --tail=100 gitea docker compose logs --tail=100 db sudo tail -n 50 /var/log/nginx/error.log ``` **Verify:** The database should be healthy, Gitea should be running, HTTPS should load through Nginx, port 3000 should remain localhost-only, SSH authentication should reach Gitea, and an existing repository should fetch successfully. ## Step 14 — Clean Up or Roll Back the Test Deployment If you are keeping Gitea, remove only temporary test repositories or local clones you no longer need. To stop the deployment without deleting data: ```bash cd ~/gitea docker compose down ``` Named volumes remain after a normal `docker compose down`. To remove the Nginx site: ```bash sudo rm -f /etc/nginx/sites-enabled/git.example.com sudo rm -f /etc/nginx/sites-available/git.example.com sudo nginx -t sudo systemctl reload nginx ``` If this was only a disposable test and you intentionally want to destroy Gitea and PostgreSQL data, first verify your backups. Then run: ```bash cd ~/gitea docker compose down -v ``` The `-v` flag deletes the named volumes and therefore removes repositories, Gitea application data, and the PostgreSQL database for this Compose project. If you issued a Let's Encrypt certificate only for this retired hostname, inspect certificates first: ```bash sudo certbot certificates ``` Then delete only the relevant certificate: ```bash sudo certbot delete --cert-name git.example.com ``` **Verify:** For a non-destructive stop, `docker volume ls` should still show the data volumes. After an intentional destructive cleanup with `down -v`, the project containers and volumes should be gone. ## Conclusion You now have a self-hosted Gitea Git server on Ubuntu 24.04 with Docker Compose, PostgreSQL, Nginx, HTTPS, and Git-over-SSH. The deployment keeps the web backend off the public interface, separates Git SSH from administrative SSH, uses a dedicated database service, and includes backup, upgrade, troubleshooting, verification, and rollback procedures. Check [Raff pricing](/pricing) for current Linux VM sizes and billing terms. For a small Gitea team, start with at least 2 GB RAM and size upward based on repository activity, package storage, search/indexing, concurrent users, and CI workloads. If you are deciding how to run containerized services on a VPS, see [Docker VPS Hosting: What Developers Should Know](/learn/guides/vps-for-docker-containers) and [Self-Hosting Apps on Raff](/learn/guides/self-hosting-apps-on-raff). Keep CI runners separate when builds become resource-intensive so build jobs do not compete with the Git service and database for the same CPU, memory, and disk I/O. --- ### How to Install Portainer on Ubuntu 24.04 with Docker URL: https://rafftechnologies.com/learn/tutorials/deploy-portainer-docker-ubuntu-24-04 Description: Install Portainer CE on Ubuntu 24.04 with Docker, Nginx, trusted HTTPS, private admin access, backups, secure updates, and verification steps. Portainer provides a web interface for managing Docker containers, images, networks, volumes, and Compose stacks. In this tutorial, you will install Portainer Community Edition on a Raff Technologies Linux VM running Ubuntu 24.04, keep the management UI off the public Docker port, place it behind Nginx and Let's Encrypt, create the first administrator, manage the local Docker environment, deploy a test stack, back up Portainer's configuration, and verify the deployment end to end. Portainer has privileged access to the Docker daemon when you mount `/var/run/docker.sock`, so the Portainer administrator effectively has control over the Docker host. Treat the dashboard as an administrative interface, not a public application. This guide therefore binds Portainer's HTTPS port to localhost and publishes it through an authenticated administrator-facing hostname such as `portainer.example.com` instead of opening port 9443 directly to the internet. For production workloads, Portainer recommends its LTS release stream. As of September 2026, Portainer 2.45.0 LTS includes the fix for a critical Docker API authorization issue affecting earlier supported releases, so use the current `lts` image and verify the running version after deployment. You need Docker with Compose v2, Nginx, a domain pointed to the VM, and a non-root user with sudo privileges. ## Step 1 — Confirm Ubuntu, Docker, and DNS Check the operating system: ```bash cat /etc/os-release ``` Check Docker and Compose: ```bash docker --version docker compose version ``` Check that the management hostname resolves to the VM: ```bash dig +short A portainer.example.com ``` If Docker is not installed, follow [How to Install Docker on Ubuntu 24.04](/learn/tutorials/install-docker-ubuntu-24-04). Use Docker Engine installed through Docker's supported Linux installation path rather than the Ubuntu Snap package; Portainer's current Docker-on-Linux guidance warns that Docker installed via Snap can cause compatibility issues. If Nginx is missing, use [How to Install Nginx on Ubuntu 24.04](/learn/tutorials/install-nginx-ubuntu-24-04). **Verify:** Ubuntu should report 24.04, Docker Compose v2 should respond, the DNS A record should return the VM's public IPv4 address, and your Docker installation should not be the Snap-packaged variant. ## Step 2 — Create Persistent Portainer Storage Create the Docker volume that stores Portainer's configuration database and settings: ```bash docker volume create portainer_data ``` Inspect it: ```bash docker volume inspect portainer_data ``` This volume is separate from the Portainer container. Removing and recreating the container does not delete the configuration unless you also remove the volume. **Verify:** `docker volume inspect portainer_data` should return the volume metadata without an error. ## Step 3 — Deploy Portainer CE on the LTS Release Stream Run Portainer with its management HTTPS port bound only to localhost: ```bash docker run -d \ --name portainer \ --restart=always \ -p 127.0.0.1:9443:9443 \ -v /var/run/docker.sock:/var/run/docker.sock \ -v portainer_data:/data \ portainer/portainer-ce:lts ``` Portainer's official Docker installation uses port 9443 for the HTTPS UI. Port 8000 is optional and is only required when you use Edge Agent tunnel features, so this single-host deployment does not publish it. The Docker socket mount gives Portainer broad control over the Docker daemon. Anyone who gains Portainer administrator access can perform actions equivalent to administrative Docker access, so protect this service accordingly. Check the container: ```bash docker ps --filter name=portainer ``` Review startup logs: ```bash docker logs --tail=50 portainer ``` **Verify:** The container should be running and `sudo ss -ltnp | grep 9443` should show `127.0.0.1:9443`, not `0.0.0.0:9443`. ## Step 4 — Verify the Portainer Version Before Continuing Check the installed Portainer version: ```bash docker exec portainer /portainer --version ``` As of September 2026, do not run an affected 2.40.x through 2.44.x build. Portainer 2.45.0 LTS and 2.39.7 LTS contain the August 2026 fix for the Docker API authorization bypass. The `lts` tag should track the supported LTS stream, but verifying the actual running version prevents an unexpectedly stale local image from going unnoticed. If the version is stale, pull the LTS image and recreate Portainer: ```bash docker pull portainer/portainer-ce:lts docker stop portainer docker rm portainer ``` Then rerun the deployment command from Step 3. **Verify:** The reported version should be a supported, patched LTS release. At the time of this update, that means 2.45.0 LTS or a later patched release. ## Step 5 — Configure Nginx as the Public Entry Point Create an Nginx server block: ```bash sudo nano /etc/nginx/sites-available/portainer.example.com ``` Add: ```nginx server { listen 80; listen [::]:80; server_name portainer.example.com; location / { proxy_pass https://127.0.0.1:9443; proxy_http_version 1.1; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade"; proxy_ssl_verify off; proxy_read_timeout 600s; proxy_send_timeout 600s; } } ``` Portainer generates a self-signed certificate for its internal HTTPS listener by default. Because this upstream connection stays on loopback, Nginx can proxy to it while public users receive the trusted Let's Encrypt certificate configured in the next step. The Upgrade and Connection headers preserve WebSocket-based management paths such as interactive console sessions. `proxy_ssl_verify off` applies only to the local self-signed upstream connection in this configuration. Enable the site: ```bash sudo ln -s /etc/nginx/sites-available/portainer.example.com \ /etc/nginx/sites-enabled/portainer.example.com sudo nginx -t sudo systemctl reload nginx ``` **Verify:** `sudo nginx -t` should report successful syntax and `curl -I http://portainer.example.com` should reach the Nginx virtual host. ## Step 6 — Add HTTPS and Keep Portainer's Direct Port Private If UFW is active, make sure SSH remains allowed before changing firewall rules: ```bash sudo ufw status sudo ufw allow OpenSSH ``` Allow Nginx traffic: ```bash sudo ufw allow 'Nginx Full' ``` Do not add a public UFW rule for port 9443 because Docker is already binding it to localhost only. This keeps the direct Portainer backend private, but the Nginx hostname can still be reachable from the public internet. Treat that hostname as a privileged administrative endpoint; for higher-security environments, restrict it with a VPN, trusted-source IP policy, or another deliberate access-control layer. Install Certbot and request a certificate: ```bash sudo apt install -y certbot python3-certbot-nginx sudo certbot --nginx --redirect -d portainer.example.com ``` Test certificate renewal: ```bash sudo certbot renew --dry-run ``` **Verify:** `curl -I https://portainer.example.com` should complete over HTTPS, HTTP should redirect to HTTPS, and `sudo ss -ltnp | grep 9443` should still show the backend bound to localhost only. ## Step 7 — Create the First Administrator Within the Setup Window Open: ```text https://portainer.example.com ``` Create the first administrator. Portainer requires the initial password to be at least 12 characters. Use a unique password stored in a password manager. Portainer intentionally times out an uninitialized installation if the first administrator is not created within five minutes. If the instance reports that it timed out for security purposes, restart it: ```bash docker stop portainer docker start portainer ``` Then complete the initial setup promptly. After the administrator is created, Portainer should automatically detect the local Docker environment. Select **Get Started** to manage it. **Verify:** You should be able to sign in over the public HTTPS hostname and see the local Docker environment without a browser certificate warning. ## Step 8 — Inspect the Local Docker Environment Safely Open the local environment in Portainer and review: - Containers - Images - Networks - Volumes - Stacks Use the UI for routine inspection and lifecycle actions, but remember that Portainer is an administrative control plane. Avoid granting dashboard access merely as a substitute for application-level access. From the command line, compare what Docker sees: ```bash docker ps -a docker volume ls docker network ls ``` The resources shown by these commands should correspond with the Portainer dashboard. **Verify:** An existing Docker container should appear in both `docker ps -a` and the Portainer Containers view with matching state. ## Step 9 — Deploy and Remove a Test Docker Compose Stack In Portainer, open **Stacks** and create a stack named `portainer-test`. Use the web editor with: ```yaml services: web: image: nginx:alpine restart: unless-stopped ports: - "127.0.0.1:8080:80" ``` Deploy the stack. The test container is deliberately bound to localhost so you do not need to expose another public firewall port just to verify the stack workflow. Test it from the VM: ```bash curl -I http://127.0.0.1:8080 ``` Then remove the test stack from Portainer when the check is complete. Confirm cleanup: ```bash sudo ss -ltnp | grep 8080 || echo 'test port removed' ``` **Verify:** The local curl should return an Nginx HTTP response before cleanup, and port 8080 should no longer be listening after the test stack is removed. :::cta Deploy Your Server Deploy a Raff Linux VM and use this tutorial to install Portainer as a private Docker management UI behind Nginx and HTTPS. ::: ## Step 10 — Back Up the Portainer Configuration Portainer's built-in backup contains the configuration stored in its `/data` volume. It does not back up the application containers, Docker volumes, or databases that Portainer manages. In the Portainer UI, sign in as an administrator and open **Settings**. In **Back up Portainer**, download a configuration backup. Password-protect the archive if your operational process supports securely storing the backup password. For infrastructure recovery, protect Docker application state separately. Depending on your workloads, that can include database-native backups, volume backups, application configuration, and VM-level recovery points. Raff [Data Protection](/products/data-protection) can cover the VM recovery layer, while application-aware backups should remain part of the workload's own recovery design. After downloading the Portainer backup, store it somewhere other than the VM itself. For the broader workload-recovery model, see [Docker Compose Backup and Restore Strategy](/learn/guides/docker-compose-backup-restore-strategy). **Verify:** Confirm the Portainer backup archive exists off-server and that your separate application backup process covers any persistent Docker workloads you would need to restore. ## Step 11 — Update Portainer Without Losing Configuration Before updating, create a Portainer configuration backup from Step 10. Then pull the supported LTS image: ```bash docker pull portainer/portainer-ce:lts ``` Stop and remove only the Portainer container: ```bash docker stop portainer docker rm portainer ``` Recreate it with the same `portainer_data` volume: ```bash docker run -d \ --name portainer \ --restart=always \ -p 127.0.0.1:9443:9443 \ -v /var/run/docker.sock:/var/run/docker.sock \ -v portainer_data:/data \ portainer/portainer-ce:lts ``` Check the version and logs: ```bash docker exec portainer /portainer --version docker logs --tail=100 portainer ``` Your Portainer users and settings remain in `portainer_data`. Removing the Portainer container does not remove other Docker containers on the host. **Verify:** You should be able to log in with the existing administrator account, the local environment should still be present, and the reported Portainer version should match the intended patched LTS release. ## Step 12 — Troubleshoot Common Portainer Problems If the UI returns a proxy error, first confirm Portainer itself is running: ```bash docker ps --filter name=portainer docker logs --tail=100 portainer curl -kI https://127.0.0.1:9443 ``` If the local HTTPS request works but the public hostname fails, test Nginx: ```bash sudo nginx -t sudo tail -n 50 /var/log/nginx/error.log ``` If Portainer appears to be a fresh installation after an update, confirm the correct data volume is mounted: ```bash docker inspect portainer \ --format '{{range .Mounts}}{{println .Source "->" .Destination}}{{end}}' ``` You should see a mount ending in `-> /data` and the Docker socket mount ending in `-> /var/run/docker.sock`. If setup timed out before the first administrator was created, restart the container as shown in Step 7. **Verify:** The backend request, Nginx configuration, Docker mounts, and Portainer logs should all agree on the failure path before you change the deployment. ## Step 13 — Run the Final End-to-End Verification Check the container and version: ```bash docker ps --filter name=portainer docker exec portainer /portainer --version ``` Check that 9443 remains private: ```bash sudo ss -ltnp | grep 9443 ``` Check the public HTTPS path: ```bash curl -I https://portainer.example.com ``` Check recent logs: ```bash docker logs --tail=100 portainer sudo tail -n 50 /var/log/nginx/error.log ``` Finally, sign in through the browser and confirm the local environment shows the same containers as: ```bash docker ps -a ``` **Verify:** Portainer should be running on a patched LTS release, port 9443 should be localhost-only, the public hostname should use trusted HTTPS, the administrator should be able to sign in, and Docker resources should be visible in the local environment. ## Step 14 — Remove Portainer Without Accidentally Deleting Other Containers To remove only the Portainer container: ```bash docker stop portainer docker rm portainer ``` This does not remove the other application containers that Portainer was managing. Remove the Nginx site if it is no longer needed: ```bash sudo rm -f /etc/nginx/sites-enabled/portainer.example.com sudo rm -f /etc/nginx/sites-available/portainer.example.com sudo nginx -t sudo systemctl reload nginx ``` Keep `portainer_data` if you may reinstall Portainer later. If this is a disposable test and you intentionally want to erase Portainer's users and configuration, first verify your backup and then remove the volume: ```bash docker volume rm portainer_data ``` If the Let's Encrypt certificate is no longer needed, inspect certificates before deleting anything: ```bash sudo certbot certificates ``` Then delete only the retired hostname's certificate: ```bash sudo certbot delete --cert-name portainer.example.com ``` **Verify:** `docker ps -a` should show that your unrelated application containers still exist, while the Portainer container is gone. Remove `portainer_data` only when intentional configuration loss is acceptable. ## Conclusion You now have Portainer CE installed on Ubuntu 24.04 as a Docker management UI with persistent configuration, localhost-only backend exposure, Nginx, trusted HTTPS, a verified LTS release, a working local Docker environment, a tested Compose stack workflow, configuration backup, update instructions, troubleshooting, and cleanup steps. Raff [Linux VM](/products/linux-vm) plans currently start at $4.99 per month; check [Raff pricing](/pricing) for the latest sizes and billing terms. Portainer can share a VM with other Docker workloads, but size the server for the applications and databases you actually run rather than for the dashboard alone. For production host security, see [Docker Host Security Checklist for Production VMs](/learn/guides/docker-host-security-checklist-production-vms). If you are deciding how to run container workloads on a VPS, see [Docker VPS Hosting: What Developers Should Know](/learn/guides/vps-for-docker-containers). If you are building multi-container applications, continue with the [Docker Compose](/learn/tutorials/install-docker-compose-ubuntu-24-04) workflow or use [Gitea with Docker Compose](/learn/tutorials/deploy-gitea-ubuntu-24-04) as a more complete self-hosted application example. --- ### How to Install fail2ban on Ubuntu 24.04 for SSH Protection URL: https://rafftechnologies.com/learn/tutorials/install-fail2ban-ubuntu-24-04 Description: Install and configure fail2ban on Ubuntu 24.04 for SSH brute-force protection with systemd journal monitoring, safe ban testing, tuning, and rollback. fail2ban monitors authentication events and temporarily blocks source IP addresses that repeatedly match failure patterns. On an internet-facing Ubuntu server, it is useful as an additional SSH protection layer alongside SSH keys, restricted firewall rules, timely updates, and disabled password authentication where practical. In this tutorial, you will install fail2ban on a Raff Technologies Linux VM running Ubuntu 24.04, enable the SSH jail, use the systemd journal backend, tune retry and ban windows, validate the configuration, test a ban without locking yourself out, inspect logs, and cleanly roll the setup back if needed. Ubuntu 24.04 currently provides fail2ban 1.0.2-3ubuntu0.1 in the Noble Updates package line. The package supports systemd journal monitoring and works with modern firewall backends including nftables. This guide does not claim that every public server receives a fixed number of attacks or that fail2ban eliminates brute-force traffic; actual login noise varies by IP, exposure, SSH configuration, and time. fail2ban reduces repeated attempts from matching sources, but it should not replace SSH key authentication or firewall access controls. You need Ubuntu 24.04, SSH access using a non-root sudo user, and preferably SSH key authentication already working before you change ban rules. ## Step 1 — Confirm Ubuntu and Your SSH Access Path Check the operating system: ```bash cat /etc/os-release ``` Confirm the SSH service is active: ```bash systemctl is-active ssh ``` Before changing fail2ban settings, keep your current SSH session open and confirm you can open a second SSH session from your normal workstation. This gives you a recovery path if you make a configuration mistake. If you have not configured SSH keys yet, follow [How to Set Up SSH Keys on Ubuntu 24.04](/learn/tutorials/set-up-ssh-keys-ubuntu-24-04) first. **Verify:** Ubuntu should report 24.04, the SSH service should be active, and a second SSH session should connect successfully before you continue. ## Step 2 — Install fail2ban from the Ubuntu Repository Update package metadata and install fail2ban: ```bash sudo apt update sudo apt install -y fail2ban ``` Check the installed package version: ```bash apt-cache policy fail2ban ``` Ubuntu 24.04's current Noble Updates package is fail2ban 1.0.2-3ubuntu0.1, with Ubuntu security and maintenance revisions applied through package updates. You can verify the current Ubuntu package at [packages.ubuntu.com](https://packages.ubuntu.com/noble/fail2ban). Enable fail2ban at boot: ```bash sudo systemctl enable fail2ban ``` Do not assume the SSH jail is enabled simply because the service package is installed; jails are disabled by default unless distribution or local configuration enables them. **Verify:** `fail2ban-client --version` should report Fail2Ban 1.0.2, `apt-cache policy fail2ban` should show the current Ubuntu package revision, and `systemctl is-enabled fail2ban` should report `enabled`. ## Step 3 — Create a Local SSH Jail Override Do not edit `/etc/fail2ban/jail.conf` directly. Upstream fail2ban recommends putting local overrides in `jail.local` or `.local` files under `/etc/fail2ban/jail.d/`, so package upgrades can update defaults without overwriting your custom settings. Create a dedicated SSH override: ```bash sudo nano /etc/fail2ban/jail.d/sshd.local ``` Add: ```ini [sshd] enabled = true backend = systemd port = ssh bantime = 1h findtime = 10m maxretry = 5 ``` The `systemd` backend reads authentication events from the journal. When this backend is used, do not add a `logpath` directive; fail2ban's systemd backend uses the filter's `journalmatch` instead. This avoids depending on `/var/log/auth.log` being present on every Ubuntu installation. If SSH listens on a custom port, replace `port = ssh` with the actual port number. **Verify:** Run `sudo cat /etc/fail2ban/jail.d/sshd.local` and confirm the jail is enabled, the backend is `systemd`, and the SSH port matches the server's real SSH listener. ## Step 4 — Decide Whether Any Administrative IP Should Be Ignored fail2ban can exclude trusted addresses with `ignoreip`, but only add addresses or networks that are stable and under your control. Whitelisting a temporary hotel, mobile, ISP, or shared office address can create an unintended bypass later if that address is reassigned. If you have a stable administrative IP or VPN subnet, add it to a `[DEFAULT]` override: ```bash sudo nano /etc/fail2ban/jail.d/00-local-defaults.local ``` For example: ```ini [DEFAULT] ignoreip = 127.0.0.1/8 ::1 203.0.113.10 ``` Replace `203.0.113.10` with a stable source you actually control, or omit it entirely if you do not have one. Check your current public source address from the workstation you use for SSH and compare it with any configured `ignoreip` entry before testing bans. **Verify:** Run `sudo fail2ban-client -d | grep -i ignoreip` after the configuration test in the next step and confirm only intended trusted addresses are excluded. ## Step 5 — Validate the Configuration Before Restarting Test the full fail2ban configuration: ```bash sudo fail2ban-client -t ``` A successful test should end without a configuration error. If it fails, inspect the local files you just created before restarting the service. You can also inspect the resolved configuration for the SSH jail: ```bash sudo fail2ban-client -d | grep -A 20 "'sshd'" ``` Do not restart fail2ban after a failed configuration test. **Verify:** `sudo fail2ban-client -t` should report that the configuration is OK. ## Step 6 — Start fail2ban and Confirm the SSH Jail Restart fail2ban so the local SSH jail is loaded: ```bash sudo systemctl restart fail2ban ``` Check the service: ```bash systemctl is-active fail2ban ``` List active jails: ```bash sudo fail2ban-client status ``` Then inspect SSH specifically: ```bash sudo fail2ban-client status sshd ``` The SSH jail status shows currently failed attempts, total failures, current bans, total bans, and the banned IP list. A new server may legitimately show zero bans. **Verify:** `systemctl is-active fail2ban` should return `active`, and `sudo fail2ban-client status` should list `sshd` as an active jail. ## Step 7 — Confirm fail2ban Is Reading SSH Journal Events Inspect the SSH journal directly: ```bash sudo journalctl -u ssh --since '30 minutes ago' --no-pager ``` Then check fail2ban's SSH jail: ```bash sudo fail2ban-client status sshd ``` Review fail2ban service logs: ```bash sudo journalctl -u fail2ban -n 100 --no-pager ``` The jail may show zero failed attempts if no matching authentication failures occurred during the observation window. That is not itself an error. If the SSH jail is active but never sees events that are visible in the SSH journal, check the backend and filter configuration before changing retry thresholds. **Verify:** The SSH jail should remain active without repeated backend or journal errors in the fail2ban service log. ## Step 8 — Test the Ban Action Without Locking Yourself Out Do not intentionally enter bad SSH passwords repeatedly from your only administrative connection. First inspect the resolved SSH jail configuration so you know which ban action is active: ```bash sudo fail2ban-client -d | grep -A 40 "sshd" ``` You can also inspect the loaded jail actions directly: ```bash sudo fail2ban-client get sshd actions ``` Then use fail2ban's manual ban command with a documentation-only test address that is not your own source IP: ```bash sudo fail2ban-client set sshd banip 198.51.100.25 ``` Check the jail: ```bash sudo fail2ban-client status sshd ``` The test address should appear in the banned IP list. If the resolved action uses nftables, inspect the corresponding fail2ban rules or sets: ```bash sudo nft list ruleset | grep -i -A 8 f2b ``` If your system uses a different action backend, inspect that backend instead of assuming nftables. Do not assume a fail2ban ban must appear as a permanent UFW rule; fail2ban's active action can manage firewall state independently of the baseline rules shown by `ufw status`. Remove the test ban: ```bash sudo fail2ban-client set sshd unbanip 198.51.100.25 ``` **Verify:** The test IP should appear while banned, the loaded action should match the firewall mechanism you inspect, and the IP should disappear from `sudo fail2ban-client status sshd` after the unban command. ## Step 9 — Tune Ban Time and Retry Thresholds Conservatively The initial values in this guide are: ```ini bantime = 1h findtime = 10m maxretry = 5 ``` These mean that five matching failures within ten minutes trigger a one-hour ban. There is no universal ideal value. Shared administrator addresses, automation, monitoring systems, and users behind NAT can make aggressive thresholds more likely to block legitimate access. If repeated offenders are a problem, fail2ban supports incremental ban times. Add these settings under `[DEFAULT]` in `/etc/fail2ban/jail.d/00-local-defaults.local`: ```ini [DEFAULT] bantime.increment = true bantime.factor = 2 bantime.maxtime = 1d ``` After changing values, validate before restart: ```bash sudo fail2ban-client -t sudo systemctl restart fail2ban ``` **Verify:** `sudo fail2ban-client -t` should pass, and `sudo fail2ban-client get sshd bantime` should show the effective base ban duration in seconds. ## Step 10 — Manage Bans and Review Activity List SSH jail status: ```bash sudo fail2ban-client status sshd ``` Ban an address manually when there is a specific operational reason: ```bash sudo fail2ban-client set sshd banip 203.0.113.50 ``` Unban it: ```bash sudo fail2ban-client set sshd unbanip 203.0.113.50 ``` To inspect recent fail2ban activity through systemd: ```bash sudo journalctl -u fail2ban --since today --no-pager ``` Do not interpret raw ban counts as a security score. Higher or lower counts can result from IP exposure, scanning activity, logging configuration, retry thresholds, and whether password authentication is enabled. **Verify:** Manual ban and unban commands should change the SSH jail's banned IP list immediately. :::cta Deploy Your Server Deploy a Raff Linux VM and use this tutorial to add fail2ban SSH protection as one layer of a hardened Ubuntu 24.04 server. ::: ## Step 11 — Harden SSH Beyond fail2ban fail2ban reacts to matching failures; it does not remove the underlying SSH authentication surface. For administrative servers, prioritize SSH keys and disable password authentication only after confirming key-based login works from a second session. Check effective SSH settings: ```bash sudo sshd -T | grep -E 'passwordauthentication|permitrootlogin|pubkeyauthentication' ``` If you change SSH configuration, validate it before reload: ```bash sudo sshd -t ``` Then reload SSH only after a successful validation: ```bash sudo systemctl reload ssh ``` Keep your existing session open until you confirm a new session works. Combine this with [UFW firewall rules](/learn/tutorials/set-up-ufw-firewall-ubuntu-24-04), the broader [Ubuntu server hardening](/learn/tutorials/secure-ubuntu-24-04-server) checklist, [Cloud Security Fundamentals](/learn/guides/cloud-security-fundamentals), and [Cloud Firewall Best Practices](/learn/guides/firewall-best-practices-cloud-servers). **Verify:** A new SSH session should authenticate successfully using the intended method after any SSH hardening change. ## Step 12 — Troubleshoot Common fail2ban Problems If fail2ban will not start, test configuration first: ```bash sudo fail2ban-client -t sudo journalctl -u fail2ban -n 100 --no-pager ``` If `sshd` does not appear in the jail list, confirm: ```bash sudo cat /etc/fail2ban/jail.d/sshd.local sudo fail2ban-client status ``` If the jail starts but does not detect SSH failures, confirm SSH events exist: ```bash sudo journalctl -u ssh --since '30 minutes ago' --no-pager ``` For a jail using `backend = systemd`, do not configure `logpath`; fail2ban's documentation states that `logpath` is not valid for the systemd backend because journal matching is used instead. If bans are created but connectivity is unaffected, inspect the active action and firewall rules rather than assuming UFW must contain the ban: ```bash sudo fail2ban-client get sshd actions sudo nft list ruleset | grep -i -A 8 f2b ``` **Verify:** Resolve configuration errors first, then confirm the service, jail, log source, and firewall action in that order. ## Step 13 — Run the Final End-to-End Verification Check the service and jail: ```bash systemctl is-active fail2ban sudo fail2ban-client status sudo fail2ban-client status sshd ``` Validate the configuration again: ```bash sudo fail2ban-client -t ``` Confirm SSH is healthy: ```bash systemctl is-active ssh sudo sshd -t ``` Review recent fail2ban errors: ```bash sudo journalctl -u fail2ban -p warning --since today --no-pager ``` If you want one final action test, repeat the documentation-address ban and immediately remove it: ```bash sudo fail2ban-client set sshd banip 198.51.100.25 sudo fail2ban-client status sshd sudo fail2ban-client set sshd unbanip 198.51.100.25 ``` **Verify:** fail2ban and SSH should both be active, the `sshd` jail should be loaded, configuration validation should pass, and the manual test ban/unban should work without affecting your administrator IP. ## Step 14 — Roll Back or Remove fail2ban Safely To disable only the custom SSH jail while keeping fail2ban installed, move the local override out of the active configuration path: ```bash sudo mv /etc/fail2ban/jail.d/sshd.local \ /etc/fail2ban/sshd.local.disabled sudo fail2ban-client -t sudo systemctl restart fail2ban ``` Confirm the SSH jail is gone: ```bash sudo fail2ban-client status ``` To stop fail2ban entirely: ```bash sudo fail2ban-client unban --all sudo systemctl disable --now fail2ban ``` If you intentionally want to remove the package and its configuration: ```bash sudo apt purge -y fail2ban sudo apt autoremove -y ``` Do not remove or weaken SSH key authentication or firewall rules merely because fail2ban has been removed; those controls solve different problems. **Verify:** After a full removal, `systemctl status fail2ban` should report that the unit is unavailable or inactive, while SSH access should continue to work through your existing SSH configuration. ## Conclusion You now have fail2ban protecting SSH on Ubuntu 24.04 with a dedicated local jail override, systemd journal monitoring, explicit retry and ban windows, configuration validation, safe ban testing, activity inspection, troubleshooting, and rollback instructions. Raff [Linux VM](/products/linux-vm) plans currently start at $4.99 per month; check [Raff pricing](/pricing) for the latest sizes and billing terms. Treat fail2ban as one layer in the server security model: use SSH keys, minimize public ports, keep packages updated, validate SSH changes before reload, and maintain a recovery path for administrative access. --- ### How to Install Caddy Web Server on Ubuntu 24.04 URL: https://rafftechnologies.com/learn/tutorials/install-caddy-ubuntu-24-04 Description: Install Caddy web server on Ubuntu 24.04, serve a static site, enable automatic HTTPS, validate the Caddyfile, troubleshoot TLS, and roll back safely. Caddy is a web server that can serve static sites and manage HTTPS automatically when you configure a qualifying public domain. In this tutorial, you will install Caddy on a Raff Technologies Linux VM running Ubuntu 24.04, serve a static website from `/var/www`, point a domain to the server, enable ports 80 and 443, validate the Caddyfile, verify automatic HTTPS, inspect certificate and service state, and safely roll the setup back if needed. This page focuses on installing Caddy as a web server for a static site. Raff has a separate tutorial for [using Caddy as a reverse proxy](/learn/tutorials/install-caddy-ubuntu-24-04-reverse-proxy), so the two workflows do not need to duplicate each other. Caddy's official Ubuntu package installs a systemd service named `caddy`, and Caddy's automatic HTTPS can obtain and renew publicly trusted certificates for qualifying domain names while redirecting HTTP traffic to HTTPS. See the [official Caddy installation documentation](https://caddyserver.com/docs/install) and [Automatic HTTPS documentation](https://caddyserver.com/docs/automatic-https) for the upstream behavior used here. You need Ubuntu 24.04, a domain or subdomain whose active A and/or AAAA records point to the VM, SSH access with sudo privileges, and ports 80 and 443 available for Caddy. ## Step 1 — Confirm Ubuntu, DNS, and Existing Web Services Check the operating system: ```bash cat /etc/os-release ``` Check whether another service is already listening on ports 80 or 443: ```bash sudo ss -lntp | grep -E ':(80|443)\b' || true ``` Check every active public address record for the hostname: ```bash dig +short A your-domain.com dig +short AAAA your-domain.com ``` Replace `your-domain.com` throughout this tutorial with the real hostname you plan to serve. If an AAAA record exists, make sure it points to this server and that IPv6 traffic can actually reach Caddy. A stale AAAA record can send IPv6 clients and ACME validation to the wrong host. If Nginx or Apache is already serving production traffic on this VM, do not stop it blindly. Decide whether Caddy will replace it, coexist on different ports, or be deployed on another server before continuing. **Verify:** Ubuntu should report 24.04, every active A/AAAA record should resolve to an address that reaches this VM, and you should know whether ports 80 and 443 are already in use. ## Step 2 — Install Caddy from the Official Repository Caddy recommends using its official distribution package on supported production systems. Install the repository prerequisites: ```bash sudo apt update sudo apt install -y debian-keyring debian-archive-keyring apt-transport-https curl ``` Add the official stable signing key: ```bash curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | \ sudo gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg ``` Add the stable repository: ```bash curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | \ sudo tee /etc/apt/sources.list.d/caddy-stable.list ``` Make the APT files readable: ```bash sudo chmod o+r /usr/share/keyrings/caddy-stable-archive-keyring.gpg sudo chmod o+r /etc/apt/sources.list.d/caddy-stable.list ``` Install Caddy: ```bash sudo apt update sudo apt install -y caddy ``` The official Debian/Ubuntu package starts Caddy as a systemd service automatically. **Verify:** Run `caddy version` and `systemctl is-active caddy`. The version command should return a Caddy v2 release and the service should report `active`. ## Step 3 — Allow SSH, HTTP, and HTTPS Through the Host Firewall If UFW is already active, inspect the current rules first: ```bash sudo ufw status numbered ``` Make sure your actual SSH port is allowed before enabling or changing the firewall. For a standard SSH service on port 22: ```bash sudo ufw allow OpenSSH ``` Allow standard web traffic: ```bash sudo ufw allow 80/tcp sudo ufw allow 443/tcp ``` If UFW is currently inactive and you intend to enable it, confirm SSH access is allowed first, then enable it: ```bash sudo ufw enable ``` For normal public automatic HTTPS, Caddy's documentation expects the server to be externally reachable on ports 80 and 443. Port 80 is also used for automatic HTTP-to-HTTPS redirects. **Verify:** `sudo ufw status` should show your SSH rule plus inbound access for TCP 80 and 443 without removing any rules required by other services. ## Step 4 — Create a Read-Only Static Site for the Caddy Service Caddy's systemd documentation recommends serving static files from locations such as `/srv` or `/var/www` rather than user home directories. Create the site directory with root ownership: ```bash sudo install -d -o root -g root -m 755 /var/www/caddy-demo ``` Create a simple test page: ```bash cat <<'EOF' | sudo tee /var/www/caddy-demo/index.html > /dev/null Caddy on Ubuntu 24.04

Caddy is serving this site

This page is being served from Ubuntu 24.04.

EOF ``` Set the file to a normal world-readable static-file mode: ```bash sudo chmod 644 /var/www/caddy-demo/index.html ``` There is no need to make the entire tree writable by the `caddy` service account or apply `chmod -R 755` to every file. The service only needs read and directory-traversal permission for this static site. Do not place secrets, private keys, database dumps, `.env` files, repository metadata, or backup archives inside a public document root. Caddy's `file_server` can hide selected names as defense in depth, but upstream documentation explicitly notes that `hide` should not be treated as the security boundary for sensitive files. **Verify:** Run `namei -l /var/www/caddy-demo/index.html` and confirm the `caddy` service can traverse the directories and read the file through normal directory `755` and file `644` permissions. Also confirm the document root contains only files that are intended to be publicly served. ## Step 5 — Back Up and Write the Caddyfile Back up the packaged configuration before replacing it: ```bash sudo cp /etc/caddy/Caddyfile /etc/caddy/Caddyfile.bak ``` Edit the active file: ```bash sudo nano /etc/caddy/Caddyfile ``` Use this configuration: ```caddyfile your-domain.com { root /var/www/caddy-demo encode zstd gzip file_server { hide .git .env } } ``` The `root` directive defines the site root and `file_server` enables static-file serving. `encode zstd gzip` enables response compression when supported by the client. The `hide` entries make accidental requests for common repository/secret names return as not found, but sensitive files still belong outside the document root. Caddy's current documentation allows the simplified `root /path` syntax; older releases required `root * /path`, which is why older tutorials may show the wildcard form. **Verify:** Save the file and run `sudo caddy validate --config /etc/caddy/Caddyfile`. It should report a valid configuration before you reload the service. ## Step 6 — Format the Caddyfile and Reload Without Downtime Caddy can format the Caddyfile into its canonical style: ```bash sudo caddy fmt --overwrite /etc/caddy/Caddyfile ``` Validate again: ```bash sudo caddy validate --config /etc/caddy/Caddyfile ``` Reload the running systemd service: ```bash sudo systemctl reload caddy ``` Caddy's official service guidance recommends reloads for configuration changes instead of stopping the service, because a graceful reload avoids unnecessary downtime. Check recent service logs: ```bash sudo journalctl -u caddy -n 80 --no-pager ``` **Verify:** Configuration validation should succeed, `systemctl is-active caddy` should return `active`, and the recent journal should not show a repeating configuration or bind error. ## Step 7 — Verify Automatic HTTPS Test the HTTPS endpoint: ```bash curl -I https://your-domain.com ``` Then test the HTTP endpoint: ```bash curl -I http://your-domain.com ``` For a qualifying public hostname, Caddy automatically manages a trusted certificate and normally redirects HTTP to HTTPS. Certificate issuance can fail if DNS does not point to this server, ports 80/443 are unreachable, another service owns the ports, or the public CA cannot validate the hostname. ![caddy-ubuntu-24-04-01-https-static-site.webp](https://raff-images.s3.raffusercloud.com/caddy_ubuntu_24_04_01_https_static_site_webp_81a80245e5.png) **Verify:** The HTTPS request should return a successful HTTP response from your site, while the HTTP request should redirect to the HTTPS URL. ## Step 8 — Verify the Browser Certificate and Static Content Open: ```text https://your-domain.com ``` Confirm the test page loads and the browser reports a trusted HTTPS connection for the hostname. ![Caddy static website loading over HTTPS on Ubuntu 24.04](https://raff-images.s3.raffusercloud.com/caddy_ubuntu_24_04_02_browser_padlock_webp_05387b84ec.png) Check the exact page content from the terminal: ```bash curl -fsS https://your-domain.com | grep 'Caddy is serving this site' ``` **Verify:** The browser should show the expected hostname over trusted HTTPS, and the terminal command should return the test-page heading. ## Step 9 — Confirm Service, Ports, and Caddy Storage State Confirm Caddy is enabled at boot: ```bash systemctl is-enabled caddy ``` Check its listeners: ```bash sudo ss -lntp | grep -E ':(80|443)\b' ``` Check the service account: ```bash systemctl show caddy -p User -p Group ``` The packaged service runs as the `caddy` user and stores its application data, including certificate state, under the Caddy service user's data directory in `/var/lib/caddy`. Check that the data directory exists without printing private key material: ```bash sudo test -d /var/lib/caddy/.local/share/caddy && echo 'Caddy data directory present' ``` **Verify:** Caddy should be enabled, active, listening on the required web ports, running under the expected service account, and have its data directory present. :::cta Deploy Your Server Deploy a Raff Linux VM and use this tutorial to install Caddy on Ubuntu 24.04 with automatic HTTPS for a static website. ::: ## Step 10 — Add a Second Static Site Safely To host another domain on the same Caddy service, first point that domain to the VM and create a separate document root: ```bash sudo install -d -o root -g root -m 755 /var/www/site-two printf '

Second Caddy site

\n' | \ sudo tee /var/www/site-two/index.html > /dev/null sudo chmod 644 /var/www/site-two/index.html ``` Add another site block to `/etc/caddy/Caddyfile`: ```caddyfile site-two.example.com { root /var/www/site-two file_server } ``` Format, validate, and reload: ```bash sudo caddy fmt --overwrite /etc/caddy/Caddyfile sudo caddy validate --config /etc/caddy/Caddyfile sudo systemctl reload caddy ``` Each qualifying hostname can receive its own automatically managed certificate. **Verify:** `curl -fsS https://site-two.example.com` should return the second site's HTML after DNS and certificate issuance are ready. ## Step 11 — Troubleshoot Common Caddy Installation Problems If certificate issuance fails, check all active DNS address records: ```bash dig +short A your-domain.com dig +short AAAA your-domain.com ``` If an AAAA record exists, verify that IPv6 reaches this same Caddy host instead of an old or unrelated server. Check whether Caddy owns the web ports: ```bash sudo ss -lntp | grep -E ':(80|443)\b' ``` Check the firewall: ```bash sudo ufw status numbered ``` Check Caddy's journal: ```bash sudo journalctl -u caddy -n 120 --no-pager ``` If the site returns `403`, inspect path permissions instead of recursively making every file executable: ```bash namei -l /var/www/caddy-demo/index.html ls -l /var/www/caddy-demo/index.html ``` A typical static site can use directory mode `755` and regular file mode `644`, with root ownership, as long as Caddy can traverse the path and read the files. If Caddy fails after editing the configuration, validate it before another reload: ```bash sudo caddy validate --config /etc/caddy/Caddyfile ``` **Verify:** Identify whether the failure is DNS, port ownership, firewall, filesystem permission, or Caddyfile syntax before changing unrelated settings. ## Step 12 — Run the Final End-to-End Verification Check configuration and service state: ```bash sudo caddy validate --config /etc/caddy/Caddyfile systemctl is-active caddy systemctl is-enabled caddy ``` Check network listeners: ```bash sudo ss -lntp | grep -E ':(80|443)\b' ``` Check both HTTP paths: ```bash curl -I http://your-domain.com curl -I https://your-domain.com ``` Check the static page content: ```bash curl -fsS https://your-domain.com | grep 'Caddy is serving this site' ``` Review recent warnings or errors: ```bash sudo journalctl -u caddy -p warning --since today --no-pager ``` **Verify:** The Caddyfile should validate, the service should be active and enabled, ports 80 and 443 should be served by Caddy, HTTP should redirect to HTTPS, HTTPS should return the static page, and the journal should not show unresolved repeating errors. ## Step 13 — Roll Back or Remove the Demo Site If you want to keep Caddy but restore the original packaged configuration, validate the backup first: ```bash sudo caddy validate --config /etc/caddy/Caddyfile.bak ``` Then restore it and reload: ```bash sudo cp /etc/caddy/Caddyfile.bak /etc/caddy/Caddyfile sudo systemctl reload caddy ``` Remove only the demo content when it is no longer needed: ```bash sudo rm -rf /var/www/caddy-demo ``` If you intentionally want to uninstall Caddy completely: ```bash sudo systemctl disable --now caddy sudo apt purge -y caddy sudo apt autoremove -y ``` Before deleting `/var/lib/caddy`, remember that it contains Caddy-managed application state such as certificate data. Remove it only when you are intentionally decommissioning the service and do not need that state: ```bash sudo rm -rf /var/lib/caddy ``` Remove the repository files only if you no longer want the Caddy package source: ```bash sudo rm -f /etc/apt/sources.list.d/caddy-stable.list sudo rm -f /usr/share/keyrings/caddy-stable-archive-keyring.gpg ``` Remove firewall rules for 80/443 only if no remaining service on this VM needs them. **Verify:** If you restored the previous config, Caddy should remain active with that configuration. After a full uninstall, the Caddy service should no longer be active and your unrelated SSH/firewall access should remain intact. ## Conclusion You now have Caddy installed on Ubuntu 24.04 as a static web server with automatic HTTPS, a systemd-managed service, a validated Caddyfile, safe file permissions, HTTPS verification, multi-site expansion, troubleshooting, and rollback instructions. Raff [Linux VM](/products/linux-vm) plans currently start at $4.99 per month; check [Raff pricing](/pricing) for the latest sizes and billing terms. Size the VM for the application or sites you actually host rather than for Caddy alone. If you are still choosing a web-server stack, compare [Caddy Server vs Nginx](/learn/guides/caddy-vs-nginx-reverse-proxy) or review [VPS for Web Hosting](/learn/guides/vps-for-web-hosting). If your next goal is to put an application behind Caddy, continue with [How to Install Caddy on Ubuntu 24.04 as a Reverse Proxy](/learn/tutorials/install-caddy-ubuntu-24-04-reverse-proxy) instead of duplicating reverse-proxy configuration on this page. --- ### How to Connect Two Raff VMs with a Private VPC Network URL: https://rafftechnologies.com/learn/tutorials/connect-two-raff-vms-private-network Description: Connect two Raff VMs over a private VPC on Ubuntu 24.04. Verify private routing, firewall rules, service access, throughput tests, and safe cleanup. Connecting two Raff VMs over a private VPC lets the servers communicate on private IPv4 addresses instead of exposing every service on public interfaces. A typical use case is a public application VM talking to a database, cache, worker, or internal API over the VPC while only the public edge accepts internet traffic. This tutorial uses two Ubuntu 24.04 VMs in one Raff VPC. You will create or select a private CIDR, attach both VMs, identify the private interfaces without assuming they are named `eth1`, verify the Linux route that carries private traffic, allow only a temporary test flow through your firewalls, measure connectivity with `iperf3`, and then apply the same pattern to an application-to-database connection. Raff VPC provides private networking between attached resources. Check [Raff VPC](/products/vpc) for the current network features, CIDR support, traffic policy, and performance specifications rather than treating a tutorial as the source of truth for commercial or infrastructure limits. Actual throughput also depends on the VM, guest networking, protocol, CPU, and test method. Private-network isolation also does **not** mean application traffic is cryptographically encrypted, so continue using TLS or another secure protocol when your threat model requires encryption in transit. Prerequisites: - Two Raff VMs running Ubuntu 24.04 with SSH access - A non-root sudo user on both VMs - Access to Raff VPC/networking settings in the dashboard - A planned RFC 1918 CIDR that does not conflict with networks you may later connect through VPN or peering - UFW or another host firewall configured deliberately on both VMs The examples use `10.20.0.10` for **VM-A** and `10.20.0.11` for **VM-B**. Replace them with the private addresses assigned to your VMs. ## Step 1 — Choose a private CIDR before creating the VPC Raff VPC currently accepts private IPv4 CIDRs from `/16` through `/28` and can suggest a `/24` automatically. Use an RFC 1918 range and consider future networks before choosing it. Common private address space includes: ```text 10.0.0.0/8 172.16.0.0/12 192.168.0.0/16 ``` For this tutorial, use an example network such as: ```text 10.20.0.0/24 ``` Do not automatically reuse the same CIDR as your office LAN, client VPN pool, another cloud VPC, or a network you expect to peer later. Overlap can make future routing and VPN design harder. **Verify:** Record the CIDR you will use and confirm it does not overlap with any network that must later route to this VPC. ## Step 2 — Create the Raff VPC Open the VPC/networking section of the Raff dashboard and create a new VPC. Give it a descriptive name such as: ```text prod-app-vpc ``` Choose the CIDR from Step 1 or accept an appropriate auto-suggested range. Raff's current VPC model includes the managed gateway, DNS, and DHCP with the VPC, so attached VM interfaces can receive private addressing from the network. The exact dashboard labels can evolve, but the workflow is the same: create a VPC, choose or accept the CIDR, then wait until the VPC reports that it is ready before attaching workloads. **Verify:** The Raff dashboard should show the VPC as ready and display the expected CIDR, for example `10.20.0.0/24`. ## Step 3 — Attach VM-A and VM-B to the same VPC Attach both VMs to the VPC from the Raff dashboard. The two VMs must belong to the same private network for the direct private-IP test in this tutorial. Record the assigned private addresses. For example: ```text VM-A: 10.20.0.10 VM-B: 10.20.0.11 ``` Do not assume the private Linux interface will be named `eth1`. Modern Ubuntu guests may use predictable names such as `ens4`, `ens7`, or another device name depending on how the NIC is presented. If the dashboard exposes security groups for the VM or VPC, do not create a broad `allow any from the entire VPC` rule just for convenience. In later steps, permit only the temporary test flow or the actual service flow you need. **Verify:** Both VM detail views should show attachment to the same VPC and a private IPv4 address from the VPC CIDR. ## Step 4 — Identify the private interface and address on Ubuntu SSH to VM-A and list interfaces in compact form: ```bash ip -br addr ``` Then list IPv4 routes: ```bash ip -4 route ``` Repeat on VM-B. You are looking for the interface that owns each VM's VPC address. Example output might resemble: ```text ens3 UP 203.0.113.10/24 ens7 UP 10.20.0.10/24 ``` On VM-B, the private interface may similarly own `10.20.0.11/24`. Do **not** create a Netplan file simply because an old tutorial expected `eth1`. First verify the actual device, dashboard attachment, DHCP state, and existing Netplan configuration. Writing a guessed interface name or route into Netplan can break remote networking. Useful diagnostics are: ```bash networkctl list sudo netplan status --all ``` **Verify:** Each VM should show one interface with its expected private VPC address, regardless of the interface's device name. ## Step 5 — Verify that Linux routes peer traffic through the private NIC From VM-A, ask the kernel how it would reach VM-B: ```bash ip route get 10.20.0.11 ``` Expected structure: ```text 10.20.0.11 dev src 10.20.0.10 ``` From VM-B, check the reverse path: ```bash ip route get 10.20.0.10 ``` This test is more useful than assuming that any successful request used the VPC. It tells you which interface and source IP Linux selected for that destination. You can also inspect the neighbor table after traffic has been attempted: ```bash ip neigh show ``` **Verify:** `ip route get` on each VM should select the private interface and the VM's private source IP for the peer's private address. ## Step 6 — Allow only the temporary private-network test flow For a deterministic connectivity test, use `iperf3` on TCP port `5201`. Install it on both VMs: ```bash sudo apt update sudo apt install -y iperf3 ``` On VM-B, allow only VM-A's private IP to reach the test port through UFW: ```bash sudo ufw allow from 10.20.0.10 to any port 5201 proto tcp ``` If a Raff security group also filters private traffic, add an equivalent temporary inbound rule for TCP `5201` from `10.20.0.10/32` to VM-B. Keep the source specific rather than opening the port to the internet or the entire VPC without a reason. Check the host rule: ```bash sudo ufw status numbered ``` If UFW is currently inactive, do not enable it blindly on a remote server. Follow the [Ubuntu 24.04 UFW tutorial](/learn/tutorials/set-up-ufw-firewall-ubuntu-24-04) so SSH access is allowed before the firewall is enabled. **Verify:** VM-B should have a rule allowing TCP `5201` only from VM-A's private IP, and any Raff security-group rule should match the same intended source and destination. ## Step 7 — Test private connectivity with ping and iperf3 A ping can provide a quick reachability signal when ICMP is allowed: ```bash ping -c 4 10.20.0.11 ``` Do not treat a failed ping as proof that the VPC is broken; ICMP may be blocked while TCP traffic is allowed. For the application-layer test, start `iperf3` on VM-B and bind it specifically to the private address: ```bash iperf3 -s -B 10.20.0.11 ``` From VM-A, connect to VM-B's private address: ```bash iperf3 -c 10.20.0.11 ``` The output reports measured throughput for this specific test. Do not compare it with a fixed expected number from an old benchmark. A result is affected by VM CPU, guest networking, TCP behavior, concurrent load, and the test duration. While the test is active, you can confirm the connection endpoints on VM-B: ```bash ss -tnp | grep ':5201' ``` Stop the `iperf3` server with `Ctrl+C` when finished. **Verify:** `iperf3` should complete over `10.20.0.11`, and the connection should use the private source/destination addresses rather than the VMs' public IPs. ## Step 8 — Replace broad VPC access with service-specific rules The production goal is not “all private VMs trust each other.” The goal is to allow the exact application relationship you need. For example, if VM-A is an application server and VM-B runs PostgreSQL, allow only VM-A's private address to reach PostgreSQL on VM-B: ```bash sudo ufw allow from 10.20.0.10 to any port 5432 proto tcp ``` If MySQL is the backend instead: ```bash sudo ufw allow from 10.20.0.10 to any port 3306 proto tcp ``` Mirror that least-privilege rule in the Raff security group when a security group protects the VM. Then configure the application to use the database's **private** address, for example: ```dotenv DB_HOST=10.20.0.11 DB_PORT=5432 ``` The database service itself should also bind only to the interfaces it actually needs. Do not make a database publicly reachable merely because its firewall currently blocks the port. For PostgreSQL configuration and authentication, follow [Install PostgreSQL on Ubuntu 24.04](/learn/tutorials/install-postgresql-ubuntu-24-04) rather than copying database settings from a networking tutorial. **Verify:** The application VM should be able to reach the required service port over VM-B's private IP, while unrelated VPC sources should not gain access simply because they share the subnet. ## Step 9 — Keep private-network isolation separate from encryption Raff's current VPC documentation describes per-VPC layer-2 isolation and private addressing that is separated from other tenants and the public internet. That is a network isolation boundary. It is not a replacement for protocol-level security. Private IP traffic is not automatically equivalent to a WireGuard tunnel or TLS session. For credentials, database sessions, administration, or sensitive service-to-service traffic, use the encryption and authentication controls appropriate to the protocol and threat model. Examples include: - PostgreSQL or MySQL TLS for database connections; - HTTPS or mTLS for internal APIs where required; - SSH for administrative access; - WireGuard/IPsec when you need an encrypted tunnel between networks or endpoints. For client-to-server private access, see [Set Up WireGuard VPN on Ubuntu 24.04](/learn/tutorials/set-up-wireguard-vpn-ubuntu-24-04). **Verify:** Document which private flows rely only on VPC isolation and which also require application-layer or tunnel encryption. :::cta Create a Private Network Use Raff VPC to connect application, database, worker, and internal-service VMs over private IPs. ::: ## Step 10 — Run the final end-to-end VPC verification On VM-A, verify the route and private connection again: ```bash ip route get 10.20.0.11 ``` If your production service is PostgreSQL, test the private TCP port without authenticating to the database: ```bash nc -vz 10.20.0.11 5432 ``` Install `netcat-openbsd` first if `nc` is unavailable: ```bash sudo apt install -y netcat-openbsd ``` On VM-B, inspect listening sockets and confirm the service is not unintentionally bound to every public interface: ```bash sudo ss -lntp ``` Then review both firewall layers: ```bash sudo ufw status numbered ``` In the Raff dashboard, review the security group attached to VM-B and confirm it contains only the private flows you intend. The final architecture should resemble: ```text Internet | v VM-A public edge 10.20.0.10 | | private VPC v VM-B database/internal service 10.20.0.11 ``` **Verify:** The peer route should use the private NIC, the required service should work over the private IP, port `5201` should no longer be needed after testing, and public exposure should be limited to intentionally public services. ## Step 11 — Troubleshoot private VPC connectivity systematically ### The private IP does not appear in Ubuntu Check the dashboard attachment first, then inspect the guest: ```bash ip -br addr networkctl list sudo netplan status --all ``` Do not assume the NIC is `eth1`, and do not write a new Netplan file until you understand the existing network configuration. If the VPC attachment is present in Raff but the guest never receives DHCP configuration, gather these outputs before changing networking or contacting support. ### `ip route get` chooses the public interface Confirm both private IPs belong to the same VPC CIDR and inspect the full route table: ```bash ip -4 route ``` A conflicting or more-specific route from VPN software, custom Netplan, or another NIC can override the expected path. ### Ping fails but the route is correct ICMP may be filtered. Test the actual allowed TCP service instead: ```bash nc -vz 10.20.0.11 5201 ``` or run the `iperf3` test from Step 7. ### `iperf3` reports connection refused On VM-B, confirm the server is listening on the private address: ```bash ss -lntp | grep ':5201' ``` Then review UFW and the Raff security group: ```bash sudo ufw status numbered ``` ### The service works on the public IP but not the private IP The application may be bound only to its public address or localhost. Inspect listeners with: ```bash sudo ss -lntp ``` Configure that service to bind to the intended private address according to its own documentation, then restart and verify it. **Verify:** After fixing the identified layer, rerun `ip route get`, then the actual TCP test. Do not consider the issue solved based only on the presence of a private IP. ## Step 12 — Remove temporary test access and tools After `iperf3` testing, remove the temporary UFW rule from VM-B. First find its rule number: ```bash sudo ufw status numbered ``` Then delete only the TCP `5201` rule that you created for VM-A: ```bash sudo ufw delete ``` Remove the equivalent temporary Raff security-group rule if you created one. If `iperf3` was installed only for this test and is no longer needed: ```bash sudo apt remove -y iperf3 ``` Do **not** detach a production VPC or delete its CIDR merely to clean up the tutorial. Detaching the private NIC can break database, cache, internal API, monitoring, backup, or administrative paths that now depend on the private address. Only when this was a disposable lab and no dependencies remain should you detach the VMs and remove the VPC from the Raff dashboard. **Verify:** TCP `5201` should no longer be allowed or listening, while the production service-specific private rules you intentionally created should remain in place. ## Conclusion You connected two Raff VMs through a private VPC, identified their actual Ubuntu network interfaces, verified the kernel route that carries private traffic, tested TCP connectivity without exposing a test port publicly, and replaced broad subnet trust with service-specific firewall rules. The important production pattern is simple: use the VPC for private reachability, security groups and host firewalls for least-privilege access, and protocol-level encryption where the data requires it. Do not infer network performance from an old `iperf3` screenshot or treat a private IP as a substitute for authentication and TLS. For broader architecture decisions, continue with [VPC Architecture for Multi-VM Applications](/learn/guides/understanding-private-cloud-networks) and [Public vs Private Networking](/learn/guides/private-networking-public-vs-private-traffic). The current Raff VPC product details are available at [Raff VPC](/products/vpc). ## Sources - [Raff VPC](/products/vpc) - [VPC Architecture for Multi-VM Applications](/learn/guides/understanding-private-cloud-networks) - [RFC 1918 — Address Allocation for Private Internets](https://datatracker.ietf.org/doc/html/rfc1918) - Product and networking guidance verified: 2026-09-04 --- ### How to Back Up PostgreSQL to S3 with Restic on Ubuntu 24.04 URL: https://rafftechnologies.com/learn/tutorials/back-up-postgresql-raff-object-storage-restic Description: Back up PostgreSQL to S3-compatible Raff Object Storage with Restic on Ubuntu 24.04. Automate encrypted dumps, retention, checks, and restore tests. This tutorial builds an automated PostgreSQL backup to S3 workflow on Ubuntu 24.04. You will create a consistent custom-format dump with `pg_dump`, encrypt it with Restic, store it in [Raff Object Storage](/products/object-storage), apply retention, schedule backups with systemd, and prove recovery by restoring into a separate database. Raff Object Storage is S3-compatible at `https://s3.raffusercloud.com`. Check [Raff Object Storage](/products/object-storage) for the current region, pricing, included capacity, transfer allowances, and service commitments. Restic supports S3-compatible repositories, so the workflow uses the same repository model it documents for non-AWS S3 services. This is a **logical backup and restore** workflow. It is suitable when your recovery point objective can be met by scheduled dumps. It is not point-in-time recovery (PITR): PostgreSQL uses base backups plus WAL archiving for recovery to a specific point between backups. Prerequisites: * A Raff Linux VM running Ubuntu 24.04 * PostgreSQL installed and a database you can dump locally * SSH and sudo access * A private Raff Object Storage bucket with a scoped read-write S3 key * AWS CLI configured with a `raff` profile if you want to run the bucket verification command in Step 3 * Enough temporary disk space for one PostgreSQL dump * A password manager or another secure off-VM location for the Restic repository password > 📌 **Recovery rule:** A completed backup job is not proof of recoverability. The final step restores the latest recovery point into an isolated test database. The original workflow was tested on a Raff 2 vCPU / 4 GB RAM Ubuntu 24.04 VM. For this refresh, the PostgreSQL dump/restore behavior, Restic S3 configuration, password-file handling, retention, pruning, and repository checks were re-verified against current PostgreSQL and Restic documentation in September 2026. ## Step 1 — Install Restic and PostgreSQL client tools Update Ubuntu and install the required packages: ```bash sudo apt update sudo apt upgrade -y sudo apt install -y restic postgresql-client ``` Verify the tools: ```bash restic version pg_dump --version pg_restore --version ``` Check the PostgreSQL server version: ```bash sudo -u postgres psql -tAc 'SHOW server_version;' ``` Use a `pg_dump` client from the same PostgreSQL major version as the server when practical. PostgreSQL documents that `pg_dump` can dump older servers, but it cannot dump a server newer than its own major version. See the official [`pg_dump` reference](https://www.postgresql.org/docs/current/app-pgdump.html). **Verification:** `restic version`, `pg_dump --version`, and the server-version query should all complete successfully before you continue. ## Step 2 — Identify and validate the source database List the databases on the server: ```bash sudo -u postgres psql -c '\l' ``` This tutorial uses `raffapp`. Replace that name everywhere with your real database name. Create a temporary custom-format dump: ```bash sudo -u postgres pg_dump \ --format=custom \ --file=/tmp/raffapp-test.dump \ raffapp ``` Validate the archive catalog and confirm the file is non-empty: ```bash sudo -u postgres pg_restore --list /tmp/raffapp-test.dump | head test -s /tmp/raffapp-test.dump && echo 'Dump validation passed' ``` Remove the temporary archive: ```bash sudo rm -f /tmp/raffapp-test.dump ``` PostgreSQL separates SQL dumps, filesystem-level backups, and continuous archiving as different backup approaches. For this tutorial, `pg_dump` creates a portable logical archive that `pg_restore` can reconstruct later. See PostgreSQL's [Backup and Restore](https://www.postgresql.org/docs/current/backup.html) documentation. **Verification:** the archive catalog should be readable and `Dump validation passed` should print before the test file is removed. ## Step 3 — Prepare S3-compatible Raff Object Storage Use a dedicated private bucket for database backups. For example: ```text company-production-postgres-backups ``` Create a scoped access key that has read-write access only to the backup bucket. Raff Object Storage currently supports per-bucket grants, so the backup process does not need credentials for unrelated buckets. If your AWS CLI `raff` profile is already configured, verify access without uploading data: ```bash aws s3api head-bucket \ --bucket company-production-postgres-backups \ --endpoint-url https://s3.raffusercloud.com \ --profile raff ``` A successful `head-bucket` command returns no output. If you still need the CLI profile, follow [Raff Object Storage with AWS CLI](/learn/tutorials/raff-s3-object-storage-aws-cli) first. **Verification:** confirm the bucket is private, the backup key is scoped to it, and `head-bucket` completes without an access error. ## Step 4 — Store Restic credentials without putting the repository password in the environment Restic supports `RESTIC_PASSWORD_FILE` for automated jobs. Keeping the repository password in a root-only file avoids placing the password itself in the service environment. Generate a strong repository password into a protected file: ```bash openssl rand -base64 32 | \ sudo tee /etc/restic-postgres.password >/dev/null sudo chown root:root /etc/restic-postgres.password sudo chmod 600 /etc/restic-postgres.password ``` Copy that password into a password manager or another secure recovery location outside the VM: ```bash sudo cat /etc/restic-postgres.password ``` Create the environment file: ```bash sudo install -m 600 -o root -g root \ /dev/null /etc/restic-postgres.env sudo nano /etc/restic-postgres.env ``` Add the following values and replace the placeholders: ```bash RESTIC_REPOSITORY="s3:https://s3.raffusercloud.com/company-production-postgres-backups/postgresql/raffapp" RESTIC_PASSWORD_FILE="/etc/restic-postgres.password" AWS_ACCESS_KEY_ID="REPLACE_WITH_RAFF_ACCESS_KEY" AWS_SECRET_ACCESS_KEY="REPLACE_WITH_RAFF_SECRET_KEY" AWS_DEFAULT_REGION="us-east" PGDATABASE="raffapp" DUMP_DIR="/var/backups/postgresql-restic" ``` Restic documents the `s3:https://server/bucket` form for non-AWS S3-compatible services and supports an explicit region through `AWS_DEFAULT_REGION`. Raff's current Object Storage documentation identifies the service region as `us-east`. Check both files without printing their secrets: ```bash sudo stat -c '%A %U:%G %n' \ /etc/restic-postgres.env \ /etc/restic-postgres.password ``` **Verification:** both files should be owned by `root:root` with `-rw-------` permissions. ## Step 5 — Initialize the encrypted Restic repository Load the protected environment and initialize the repository: ```bash sudo bash -c ' set -a source /etc/restic-postgres.env set +a restic init ' ``` Do not run `restic init` again if the same repository path is already initialized. Verify repository access: ```bash sudo bash -c ' set -a source /etc/restic-postgres.env set +a restic snapshots ' ``` A new repository should open successfully and report that no snapshots exist yet. **Verification:** `restic snapshots` must open the repository without asking for a password or returning an S3 authentication error. ## Step 6 — Create a private local staging directory Create a directory that only PostgreSQL and root can use for the temporary logical dump: ```bash sudo install -d \ -m 700 \ -o postgres \ -g postgres \ /var/backups/postgresql-restic ``` Verify permissions: ```bash sudo stat -c '%A %U:%G %n' \ /var/backups/postgresql-restic ``` Expected ownership is `postgres:postgres` with mode `drwx------`. **Verification:** do not continue if another local user can read the staging directory. ## Step 7 — Create the PostgreSQL backup to S3 script Create the backup script: ```bash sudo nano /usr/local/sbin/postgres-restic-backup.sh ``` Add: ```bash #!/usr/bin/env bash set -Eeuo pipefail umask 077 ENV_FILE="/etc/restic-postgres.env" LOCK_FILE="/run/lock/postgres-restic-backup.lock" if [[ ! -r "$ENV_FILE" ]]; then echo "Cannot read $ENV_FILE" >&2 exit 1 fi set -a source "$ENV_FILE" set +a : "${RESTIC_REPOSITORY:?Missing RESTIC_REPOSITORY}" : "${RESTIC_PASSWORD_FILE:?Missing RESTIC_PASSWORD_FILE}" : "${AWS_ACCESS_KEY_ID:?Missing AWS_ACCESS_KEY_ID}" : "${AWS_SECRET_ACCESS_KEY:?Missing AWS_SECRET_ACCESS_KEY}" : "${AWS_DEFAULT_REGION:?Missing AWS_DEFAULT_REGION}" : "${PGDATABASE:?Missing PGDATABASE}" : "${DUMP_DIR:?Missing DUMP_DIR}" install -d -m 700 -o postgres -g postgres "$DUMP_DIR" DUMP_FILE="${DUMP_DIR}/${PGDATABASE}.dump" exec 9>"$LOCK_FILE" if ! flock -n 9; then echo "Another PostgreSQL backup is already running" >&2 exit 1 fi cleanup() { rm -f "$DUMP_FILE" } trap cleanup EXIT echo "Creating PostgreSQL archive" runuser -u postgres -- pg_dump \ --format=custom \ --file="$DUMP_FILE" \ "$PGDATABASE" test -s "$DUMP_FILE" runuser -u postgres -- pg_restore \ --list "$DUMP_FILE" >/dev/null echo "Backing up encrypted archive to Restic" restic backup "$DUMP_FILE" \ --tag postgresql \ --tag "$PGDATABASE" echo "Applying snapshot retention" restic forget \ --keep-daily 7 \ --keep-weekly 4 \ --keep-monthly 12 echo "Backup completed successfully" ``` The dump path stays stable from run to run. That matters because Restic's retention policy groups snapshots by host and path by default; a stable path lets the daily, weekly, and monthly policy operate on the same backup set instead of treating every timestamped filename as a different group. Make the script root-owned and executable, then check its syntax: ```bash sudo chown root:root /usr/local/sbin/postgres-restic-backup.sh sudo chmod 750 /usr/local/sbin/postgres-restic-backup.sh sudo bash -n /usr/local/sbin/postgres-restic-backup.sh ``` **Verification:** `bash -n` should return no output and exit successfully. ## Step 8 — Run and verify the first backup Run the script manually: ```bash sudo /usr/local/sbin/postgres-restic-backup.sh ``` List repository snapshots: ```bash sudo bash -c ' set -a source /etc/restic-postgres.env set +a restic snapshots ' ``` Inspect the latest snapshot contents: ```bash sudo bash -c ' set -a source /etc/restic-postgres.env set +a restic ls latest ' ``` Confirm the local dump was removed after Restic committed the snapshot: ```bash sudo find /var/backups/postgresql-restic \ -maxdepth 1 -type f -print ``` The final command should print no files after a successful run. **Verification:** you should see a new Restic snapshot containing `raffapp.dump`, while the staging directory is empty. ## Step 9 — Schedule nightly PostgreSQL backups with systemd Create the service: ```bash sudo nano /etc/systemd/system/postgres-restic-backup.service ``` Add: ```ini [Unit] Description=Back up PostgreSQL to Raff Object Storage with Restic Wants=network-online.target After=network-online.target postgresql.service [Service] Type=oneshot EnvironmentFile=/etc/restic-postgres.env ExecStart=/usr/local/sbin/postgres-restic-backup.sh User=root Group=root Nice=10 IOSchedulingClass=best-effort IOSchedulingPriority=7 PrivateTmp=true NoNewPrivileges=true ``` Create the nightly timer: ```bash sudo nano /etc/systemd/system/postgres-restic-backup.timer ``` Add: ```ini [Unit] Description=Run PostgreSQL Restic backup nightly [Timer] OnCalendar=*-*-* 02:30:00 Persistent=true RandomizedDelaySec=15m Unit=postgres-restic-backup.service [Install] WantedBy=timers.target ``` Enable it: ```bash sudo systemctl daemon-reload sudo systemctl enable --now postgres-restic-backup.timer ``` Verify the schedule and run the service once through systemd: ```bash systemctl list-timers postgres-restic-backup.timer sudo systemctl start postgres-restic-backup.service sudo journalctl -u postgres-restic-backup.service -n 100 --no-pager ``` `Persistent=true` causes a missed timer to run after the VM comes back online. **Verification:** the timer should show a next-run time and the manual systemd run should finish without an error in the journal. ## Step 10 — Schedule prune and repository checks separately The backup script removes old snapshot references with `restic forget`, but it deliberately does not prune repository data during every nightly backup. Restic warns that `prune` can take significant time and locks the repository, so run it during a separate maintenance window. Restic also recommends checking the repository after pruning. Create a maintenance service: ```bash sudo nano /etc/systemd/system/postgres-restic-maintenance.service ``` Add: ```ini [Unit] Description=Prune and check PostgreSQL Restic repository Wants=network-online.target After=network-online.target [Service] Type=oneshot EnvironmentFile=/etc/restic-postgres.env ExecStart=/usr/bin/restic prune ExecStart=/usr/bin/restic check User=root Group=root Nice=15 IOSchedulingClass=idle PrivateTmp=true NoNewPrivileges=true ``` Create a weekly timer: ```bash sudo nano /etc/systemd/system/postgres-restic-maintenance.timer ``` Add: ```ini [Unit] Description=Run weekly Restic repository maintenance [Timer] OnCalendar=Sun *-*-* 04:00:00 Persistent=true RandomizedDelaySec=30m Unit=postgres-restic-maintenance.service [Install] WantedBy=timers.target ``` Enable and verify it: ```bash sudo systemctl daemon-reload sudo systemctl enable --now postgres-restic-maintenance.timer systemctl list-timers postgres-restic-maintenance.timer ``` For larger repositories, schedule maintenance when it cannot overlap a backup window. **Verification:** the maintenance timer should be enabled and show its next weekly run. ## Step 11 — Restore the latest backup into a clean test database A PostgreSQL backup and restore process is complete only when the archive can be used by PostgreSQL again. Restore the latest Restic snapshot into a temporary directory: ```bash sudo rm -rf /var/tmp/postgres-restic-restore sudo install -d -m 700 -o root -g root \ /var/tmp/postgres-restic-restore sudo bash -c ' set -a source /etc/restic-postgres.env set +a restic restore latest \ --target /var/tmp/postgres-restic-restore ' ``` Locate the restored dump: ```bash RESTORED_DUMP="$(sudo find /var/tmp/postgres-restic-restore \ -type f -name 'raffapp.dump' -print -quit)" test -n "$RESTORED_DUMP" && test -s "$RESTORED_DUMP" printf '%s\n' "$RESTORED_DUMP" ``` Inspect the archive before executing it. PostgreSQL warns that restoring a dump executes commands contained in the source archive, so only restore archives from a trusted source: ```bash sudo -u postgres pg_restore \ --list "$RESTORED_DUMP" | head ``` Create an isolated recovery database: ```bash sudo -u postgres dropdb --if-exists raffapp_restore_test sudo -u postgres createdb raffapp_restore_test ``` Restore schema and data without requiring the original role ownership and grants: ```bash sudo -u postgres pg_restore \ --exit-on-error \ --no-owner \ --no-privileges \ --dbname=raffapp_restore_test \ "$RESTORED_DUMP" ``` Verify tables and run an application-specific integrity query: ```bash sudo -u postgres psql \ --dbname=raffapp_restore_test \ --command='\dt' ``` The structural test above does not recreate cluster-wide PostgreSQL roles or prove application semantics. For a production recovery runbook, also document required roles, extensions, secrets, and application-level checks. **Verification:** the restore must complete without `pg_restore --exit-on-error` stopping, the test database must contain the expected tables, and your application-specific integrity checks must pass. :::cta bucket Create a private S3-compatible Raff Object Storage bucket for encrypted, off-VM PostgreSQL recovery points. ::: ## Cleanup (Optional) Remove the restore-test database and temporary files: ```bash sudo -u postgres dropdb --if-exists raffapp_restore_test sudo rm -rf /var/tmp/postgres-restic-restore unset RESTORED_DUMP ``` To stop future backups and maintenance: ```bash sudo systemctl disable --now \ postgres-restic-backup.timer \ postgres-restic-maintenance.timer ``` Remove the local units and scripts only when you intend to retire the workflow: ```bash sudo rm -f \ /etc/systemd/system/postgres-restic-backup.service \ /etc/systemd/system/postgres-restic-backup.timer \ /etc/systemd/system/postgres-restic-maintenance.service \ /etc/systemd/system/postgres-restic-maintenance.timer \ /usr/local/sbin/postgres-restic-backup.sh sudo systemctl daemon-reload ``` Remove local credentials only after the Restic repository password and any required recovery credentials are stored safely elsewhere: ```bash sudo rm -f \ /etc/restic-postgres.env \ /etc/restic-postgres.password sudo rm -rf /var/backups/postgresql-restic ``` These cleanup commands do **not** delete the encrypted Restic repository from Object Storage. ## Troubleshooting ### Restic returns `Access Denied` Confirm the endpoint, region, bucket name, repository path, and scoped key permissions. You can safely print only the non-secret settings: ```bash sudo grep -E \ '^(RESTIC_REPOSITORY|RESTIC_PASSWORD_FILE|AWS_DEFAULT_REGION)=' \ /etc/restic-postgres.env ``` The Raff endpoint is `https://s3.raffusercloud.com` and the current region identifier is `us-east`. ### `pg_dump` reports a server version mismatch Compare the client and server versions: ```bash pg_dump --version sudo -u postgres psql -tAc 'SHOW server_version;' ``` Install a PostgreSQL client version that is the same major version as the server or newer. ### The timer runs but no new Restic snapshot appears Inspect the service and journal: ```bash sudo systemctl status postgres-restic-backup.service --no-pager sudo journalctl \ -u postgres-restic-backup.service \ -n 120 --no-pager ``` Then run `/usr/local/sbin/postgres-restic-backup.sh` manually to expose the first failing command. ### `restic prune` overlaps the nightly backup Move the maintenance timer to a wider low-traffic window. Pruning locks the repository, so a concurrent backup may have to wait or fail depending on timing. ### A restore succeeds but ownership or permissions differ This tutorial deliberately uses `--no-owner --no-privileges` for an isolated structural restore test. If production recovery requires original ownership and grants, recreate the required PostgreSQL roles first and test that recovery path separately. ### You need point-in-time recovery instead of nightly dumps A `pg_dump` archive represents the database at one backup point. For PITR, use PostgreSQL base backups plus continuous WAL archiving or a managed database service that provides the recovery objective you need. PostgreSQL documents this separately under [Continuous Archiving and Point-in-Time Recovery](https://www.postgresql.org/docs/current/continuous-archiving.html). ## Conclusion You now have a PostgreSQL backup to S3 workflow that creates a PostgreSQL-aware logical archive, encrypts it with Restic, stores it outside the source VM, applies retention, keeps expensive repository maintenance out of the nightly backup path, and proves the recovery path with an isolated restore test. For the broader recovery design, read [Database Backup Strategy for SaaS Apps](/learn/guides/database-backup-strategy-saas-apps) and [PostgreSQL Replication vs Backups vs Snapshots](/learn/guides/postgresql-replication-vs-backups-vs-snapshots). For the S3 client setup used here, see [Raff Object Storage with AWS CLI](/learn/tutorials/raff-s3-object-storage-aws-cli). Use [Raff Object Storage](/products/object-storage) for portable S3-compatible recovery points and [Raff Data Protection](/products/data-protection) as a separate VM-level recovery layer. Choose the backup frequency and recovery method from your actual RPO and RTO rather than from a generic schedule. --- ### How to Install PostgreSQL on Ubuntu 24.04 URL: https://rafftechnologies.com/learn/tutorials/install-postgresql-ubuntu-24-04 Description: Install PostgreSQL 18 on a Raff Ubuntu 24.04 VM. Add PGDG, create a database role, verify SCRAM, secure port 5432, and test backup and restore safely. In this tutorial, you will install PostgreSQL 18 on a Raff Ubuntu 24.04 VM, create an application database and role, verify SCRAM authentication, keep port 5432 private, and prove a logical backup can be restored. Ubuntu 24.04's standard `postgresql` package tracks PostgreSQL 16, while the official PostgreSQL Apt repository (PGDG) provides newer supported major versions. This procedure uses PGDG to install **PostgreSQL 18**. PostgreSQL 18.6 is the current maintenance release as of September 17, 2026, while Ubuntu 24.04 currently maintains PostgreSQL 16.15 on its distro package path. Raff provides Linux VMs for self-hosted database workloads. If you want the database platform operated for you instead, compare this self-hosted path with [Raff Managed PostgreSQL](/products/managed-databases/postgresql). Prerequisites: - A [Raff Linux VM](/products/linux-vm) running Ubuntu 24.04 LTS - SSH access with a sudo-capable user - A recovery or console path before firewall changes - A unique application database password stored outside source code - A backup plan before modifying an existing PostgreSQL installation The original workflow was tested on a Raff VM with **2 vCPU and 4 GB RAM**. This refresh re-verifies PostgreSQL 18.6 and Ubuntu 24.04 package guidance against current upstream documentation without claiming a new full machine retest. > **Ubuntu repository vs PGDG:** `sudo apt install postgresql` is valid and installs Ubuntu's maintained PostgreSQL 16 line on Ubuntu 24.04. Use PGDG when PostgreSQL 18 is the target. :::cluster ## Step 1 — Update Ubuntu and verify the release Update package metadata and installed packages: ```bash sudo apt update sudo apt upgrade -y ``` Install the packages used by the PGDG setup and later checks: ```bash sudo apt install -y curl ca-certificates postgresql-common ``` Verify the Ubuntu release: ```bash . /etc/os-release printf '%s\n%s\n' "$PRETTY_NAME" "$VERSION_CODENAME" ``` Expected values include: ```text Ubuntu 24.04 LTS noble ``` Check whether a reboot is required: ```bash if [ -f /var/run/reboot-required ]; then echo "Reboot required before continuing" else echo "No reboot required" fi ``` **Verify:** the host reports Ubuntu 24.04 with codename `noble`, package updates complete successfully, and any required reboot is handled before PostgreSQL installation. ## Step 2 — Add the official PostgreSQL Apt repository Add the PGDG repository using the helper shipped by `postgresql-common`: ```bash sudo /usr/share/postgresql-common/pgdg/apt.postgresql.org.sh ``` Verify the configured repository: ```bash grep -R "apt.postgresql.org" \ /etc/apt/sources.list.d/pgdg.list \ /etc/apt/sources.list.d/pgdg.sources 2>/dev/null ``` The output includes `apt.postgresql.org` and `noble-pgdg`. Confirm PostgreSQL 18 is available: ```bash apt-cache policy postgresql-18 | sed -n '1,14p' ``` A non-empty `Candidate` from the PGDG repository confirms the package is available. **Verify:** the configured source references `apt.postgresql.org`, targets `noble-pgdg`, and exposes a PostgreSQL 18 candidate package. ## Step 3 — Install PostgreSQL 18 Install the PostgreSQL 18 server and matching client: ```bash sudo apt install -y postgresql-18 postgresql-client-18 ``` Verify the client version: ```bash psql --version ``` Expected format: ```text psql (PostgreSQL) 18.x ``` List the PostgreSQL clusters managed by Ubuntu tooling: ```bash pg_lsclusters ``` A normal new installation includes an `18/main` cluster, commonly on port `5432`: ```text Ver Cluster Port Status Owner Data directory 18 main 5432 online postgres /var/lib/postgresql/18/main ``` Query the running server version: ```bash sudo -u postgres psql -tAc "SHOW server_version;" ``` PostgreSQL 18.6 is the current PostgreSQL 18 maintenance release as of September 17, 2026. Version 18.5 was not released because a regression was found before shipment. If another PostgreSQL major version already exists, inspect `pg_lsclusters` before changing ports, packages, or data directories. **Verify:** `psql` reports PostgreSQL 18.x, `pg_lsclusters` shows the intended cluster online, and `SHOW server_version` reports PostgreSQL 18.6 or a later supported 18.x maintenance release. ## Step 4 — Verify service health and local readiness Check the cluster-specific systemd unit: ```bash systemctl is-active postgresql@18-main systemctl is-enabled postgresql@18-main ``` Expected output: ```text active enabled ``` Check the local TCP endpoint: ```bash sudo -u postgres pg_isready -h 127.0.0.1 -p 5432 ``` Expected output: ```text 127.0.0.1:5432 - accepting connections ``` Read the data directory and active configuration file from PostgreSQL itself: ```bash sudo -u postgres psql -tAc "SHOW data_directory;" sudo -u postgres psql -tAc "SHOW config_file;" ``` **Verify:** the `18/main` service is active and enabled, `pg_isready` reports that PostgreSQL is accepting connections, and the server returns the expected 18/main paths. ## Step 5 — Create an application role and database Open `psql` as the local PostgreSQL administrator: ```bash sudo -u postgres psql ``` Create a dedicated login role and application database: ```sql CREATE ROLE raffappuser WITH LOGIN; CREATE DATABASE raffapp OWNER raffappuser; \password raffappuser ``` Enter a unique application password twice when prompted, then exit: ```sql \q ``` Verify the role: ```bash sudo -u postgres psql -tAc \ "SELECT rolname, rolcanlogin FROM pg_roles WHERE rolname = 'raffappuser';" ``` Expected output: ```text raffappuser|t ``` Verify database ownership: ```bash sudo -u postgres psql -tAc \ "SELECT datname || '|' || pg_get_userbyid(datdba) FROM pg_database WHERE datname = 'raffapp';" ``` Expected output: ```text raffapp|raffappuser ``` Do not use the `postgres` superuser from application code. **Verify:** `raffappuser` can log in and owns the `raffapp` database. ## Step 6 — Verify SCRAM authentication Find the active host-based authentication file: ```bash HBA_FILE="$(sudo -u postgres psql -tAc 'SHOW hba_file;' | xargs)" echo "$HBA_FILE" ``` Inspect the parsed HBA rules: ```bash sudo -u postgres psql -P pager=off -x -c \ "SELECT line_number,type,database,user_name,address,auth_method,error FROM pg_hba_file_rules ORDER BY line_number;" ``` Verify the password-encryption setting: ```bash sudo -u postgres psql -tAc "SHOW password_encryption;" ``` Expected output: ```text scram-sha-256 ``` Test the application role over TCP: ```bash psql -h 127.0.0.1 -U raffappuser -d raffapp -W \ -c "SELECT current_user, current_database();" ``` Expected output includes: ```text current_user | current_database --------------+----------------- raffappuser | raffapp ``` Do not change authentication to `trust` to work around a failed login. Inspect the matching `pg_hba.conf` rule and correct the underlying account or rule issue. **Verify:** `password_encryption` is `scram-sha-256`, localhost TCP requires authentication, and `raffappuser` connects successfully to `raffapp`. ## Step 7 — Keep PostgreSQL off the public network Check the configured listen addresses: ```bash sudo -u postgres psql -tAc "SHOW listen_addresses;" ``` For this single-VM deployment, expected output is: ```text localhost ``` Inspect active listeners: ```bash sudo ss -lntp | grep ':5432' ``` Expected listeners are loopback only, such as: ```text 127.0.0.1:5432 [::1]:5432 ``` If PostgreSQL listens on `0.0.0.0`, `[::]`, or a public interface, locate the active configuration file: ```bash CONFIG_FILE="$(sudo -u postgres psql -tAc 'SHOW config_file;' | xargs)" echo "$CONFIG_FILE" ``` Set: ```conf listen_addresses = 'localhost' ``` Restart and verify again: ```bash sudo systemctl restart postgresql@18-main sudo ss -lntp | grep ':5432' ``` Check UFW state without enabling it blindly from a remote shell: ```bash sudo ufw status verbose ``` If UFW is already active, confirm there is no broad public allow rule for `5432/tcp`. Add an explicit deny only when it does not conflict with an intentional private-network design: ```bash sudo ufw deny 5432/tcp sudo ufw status numbered ``` For an application on another VM, use [Raff VPC](/products/vpc), bind PostgreSQL only to the required private interface, and restrict `pg_hba.conf` to the application's private source range. **Verify:** PostgreSQL listens only on loopback for this tutorial and no firewall rule exposes TCP 5432 to the public internet. ## Step 8 — Run an authenticated CRUD test Create a temporary `PGPASSFILE` so automated checks do not put the application password in command history: ```bash read -rsp "PostgreSQL password: " DB_PASSWORD echo PGPASSFILE="$(mktemp)" chmod 600 "$PGPASSFILE" printf '127.0.0.1:5432:*:raffappuser:%s\n' "$DB_PASSWORD" > "$PGPASSFILE" unset DB_PASSWORD export PGPASSFILE ``` Run create, insert, update, and select operations: ```bash psql -h 127.0.0.1 -U raffappuser -d raffapp <<'SQL' CREATE TABLE tutorial_check ( id BIGSERIAL PRIMARY KEY, name TEXT NOT NULL UNIQUE, status TEXT NOT NULL, created_at TIMESTAMPTZ NOT NULL DEFAULT now() ); INSERT INTO tutorial_check (name, status) VALUES ('raff-postgresql-test', 'created'); UPDATE tutorial_check SET status = 'verified' WHERE name = 'raff-postgresql-test'; SELECT name, status FROM tutorial_check WHERE name = 'raff-postgresql-test'; SQL ``` Expected result includes: ```text name | status ----------------------+---------- raff-postgresql-test | verified ``` Confirm the application role owns the table: ```bash psql -h 127.0.0.1 -U raffappuser -d raffapp -tAc \ "SELECT tableowner FROM pg_tables WHERE schemaname='public' AND tablename='tutorial_check';" ``` Expected output: ```text raffappuser ``` Leave the test row and table in place for the restore test in the next step. **Verify:** the non-superuser application role creates, reads, updates, and owns its application table over authenticated TCP. ## Step 9 — Back up and restore the database Create a protected backup directory and a custom-format logical dump: ```bash BACKUP_DIR="$HOME/postgresql-tutorial-backup" mkdir -p "$BACKUP_DIR" chmod 700 "$BACKUP_DIR" pg_dump \ -h 127.0.0.1 \ -U raffappuser \ -d raffapp \ -F c \ -f "$BACKUP_DIR/raffapp.dump" ``` Confirm the dump is non-empty and readable: ```bash test -s "$BACKUP_DIR/raffapp.dump" && echo "Backup file is non-empty" pg_restore -l "$BACKUP_DIR/raffapp.dump" | head -n 20 ``` Create an isolated restore database: ```bash sudo -u postgres createdb -O raffappuser raffapp_restore_test ``` Restore the backup without replaying original ownership or privilege metadata: ```bash pg_restore \ -h 127.0.0.1 \ -U raffappuser \ -d raffapp_restore_test \ --no-owner \ --no-privileges \ "$BACKUP_DIR/raffapp.dump" ``` Query the restored row: ```bash psql -h 127.0.0.1 -U raffappuser -d raffapp_restore_test -c \ "SELECT name, status FROM tutorial_check WHERE name='raff-postgresql-test';" ``` Expected result: ```text raff-postgresql-test | verified ``` Remove only the disposable restore database and tutorial table: ```bash sudo -u postgres dropdb --if-exists raffapp_restore_test psql -h 127.0.0.1 -U raffappuser -d raffapp -c \ "DROP TABLE tutorial_check;" ``` Remove the temporary password file: ```bash rm -f "$PGPASSFILE" unset PGPASSFILE ``` A single `pg_dump` is not a complete production recovery strategy. For production recovery design, use [PostgreSQL Replication vs Backups vs Snapshots](/learn/guides/postgresql-replication-vs-backups-vs-snapshots). **Verify:** the backup is non-empty, `pg_restore` can read it, the isolated restore succeeds, and the restored row contains `verified`. ## Step 10 — Verify the complete PostgreSQL installation Run the final server checks: ```bash systemctl is-active postgresql@18-main pg_lsclusters sudo -u postgres pg_isready -h 127.0.0.1 -p 5432 sudo -u postgres psql -tAc "SHOW server_version;" sudo -u postgres psql -tAc "SHOW listen_addresses;" sudo ss -lntp | grep ':5432' ``` Verify the application role and database still exist: ```bash sudo -u postgres psql -tAc \ "SELECT rolname FROM pg_roles WHERE rolname='raffappuser';" sudo -u postgres psql -tAc \ "SELECT datname FROM pg_database WHERE datname='raffapp';" ``` The installation is complete when all of these conditions are true: - `postgresql@18-main` is active and enabled - `SHOW server_version` reports a supported PostgreSQL 18 maintenance release - `pg_isready` accepts local connections on port 5432 - `raffappuser` authenticates to `raffapp` - the authenticated CRUD test succeeded - the logical backup restored successfully into an isolated database - PostgreSQL listens only on loopback for this deployment - no public firewall rule exposes port 5432 **Verify:** all commands above complete successfully and the final state matches every item in the checklist. :::cta Deploy Your Server Deploy an Ubuntu VM for your PostgreSQL workload. Check the current VM product page for networking and bandwidth specifications. ::: ## Cleanup (optional) Use this cleanup only if `raffapp` and `raffappuser` were created solely for this tutorial. > **Warning:** The commands below permanently delete the `raffapp` database and its data. Back up anything you need before continuing. Terminate remaining sessions, drop the database, and then drop the role: ```bash sudo -u postgres psql <<'SQL' SELECT pg_terminate_backend(pid) FROM pg_stat_activity WHERE datname = 'raffapp' AND pid <> pg_backend_pid(); DROP DATABASE IF EXISTS raffapp; DROP ROLE IF EXISTS raffappuser; SQL ``` Verify removal: ```bash sudo -u postgres psql -tAc \ "SELECT datname FROM pg_database WHERE datname='raffapp';" sudo -u postgres psql -tAc \ "SELECT rolname FROM pg_roles WHERE rolname='raffappuser';" ``` Both queries return no rows. Do not purge PostgreSQL packages or delete `/var/lib/postgresql` unless you have identified every cluster on the VM and confirmed that none contains data you need. ## Troubleshooting ### `postgresql-18` has no installation candidate Check the Ubuntu codename and PGDG repository: ```bash . /etc/os-release echo "$VERSION_CODENAME" grep -R "apt.postgresql.org" /etc/apt/sources.list.d 2>/dev/null sudo apt update apt-cache policy postgresql-18 ``` If PGDG is missing, rerun the official repository helper: ```bash sudo apt install -y postgresql-common sudo /usr/share/postgresql-common/pgdg/apt.postgresql.org.sh ``` ### `sudo apt install postgresql` installed PostgreSQL 16 That is the expected Ubuntu 24.04 distro path. Ubuntu's `postgresql` metapackage tracks PostgreSQL 16. Use PGDG and install `postgresql-18` when PostgreSQL 18 is required. Check existing clusters before removing anything: ```bash pg_lsclusters ``` ### The `18/main` cluster is offline Inspect cluster state and logs: ```bash pg_lsclusters sudo systemctl status postgresql@18-main --no-pager sudo journalctl -u postgresql@18-main --no-pager -n 100 ``` Check for a port conflict: ```bash sudo ss -lntp | grep ':5432' ``` After correcting the reported issue, restart the service: ```bash sudo systemctl restart postgresql@18-main systemctl is-active postgresql@18-main ``` ### Password authentication fails Confirm the role can log in: ```bash sudo -u postgres psql -tAc \ "SELECT rolname, rolcanlogin FROM pg_roles WHERE rolname='raffappuser';" ``` Inspect parsed HBA rules: ```bash sudo -u postgres psql -P pager=off -x -c \ "SELECT line_number,type,database,user_name,address,auth_method,error FROM pg_hba_file_rules ORDER BY line_number;" ``` Reset the role password without putting it in shell history: ```bash sudo -u postgres psql ``` Then run: ```sql ALTER ROLE raffappuser WITH LOGIN; \password raffappuser \q ``` Retest: ```bash psql -h 127.0.0.1 -U raffappuser -d raffapp -W \ -c "SELECT current_user, current_database();" ``` ### PostgreSQL listens on a public interface Find the active configuration file: ```bash CONFIG_FILE="$(sudo -u postgres psql -tAc 'SHOW config_file;' | xargs)" echo "$CONFIG_FILE" ``` For this tutorial, set: ```conf listen_addresses = 'localhost' ``` Restart and verify: ```bash sudo systemctl restart postgresql@18-main sudo ss -lntp | grep ':5432' ``` ### `pg_restore` fails during the restore test Confirm the dump is a valid custom-format archive: ```bash file "$BACKUP_DIR/raffapp.dump" pg_restore -l "$BACKUP_DIR/raffapp.dump" | head ``` Confirm the disposable restore database exists and is owned by `raffappuser`: ```bash sudo -u postgres psql -tAc \ "SELECT datname || '|' || pg_get_userbyid(datdba) FROM pg_database WHERE datname='raffapp_restore_test';" ``` Drop and recreate only the disposable restore database before retrying if a previous failed restore left objects behind. ## FAQ ### Which PostgreSQL version is included with Ubuntu 24.04? Ubuntu 24.04's standard `postgresql` package tracks PostgreSQL 16. The current Ubuntu 24.04 PostgreSQL 16 security package is 16.15 as of September 17, 2026. ### What is the current PostgreSQL 18 version? PostgreSQL 18.6 is the current stable maintenance release as of September 17, 2026. PostgreSQL 19 remains a development release and is not the production target used here. ### Should PostgreSQL port 5432 be open to the internet? No. Keep PostgreSQL on `localhost` when the application shares the VM. For separate servers, use private networking and allow only required private source ranges. ### How should I create a PostgreSQL application user? Create a dedicated login role, make it owner of the intended application database when that model fits, and set its password with `\password` so the secret is not stored in shell history. ### Is `pg_dump` enough for production backups? Not by itself. Production recovery also needs retention, off-server copies, monitoring, restore testing, and, when required, WAL archiving and point-in-time recovery. ### Should I self-host PostgreSQL or use managed PostgreSQL? Self-host when you need host-level control and can own patching, backups, monitoring, upgrades, and incidents. Use managed PostgreSQL when reducing operational ownership matters more. ## Conclusion You now have PostgreSQL 18 running on a Raff Ubuntu 24.04 VM with a dedicated application role, SCRAM authentication, private-by-default networking, verified CRUD operations, and a restore-tested logical backup. For production planning, continue with [PostgreSQL for SaaS Apps](/learn/guides/postgresql-for-saas-apps), [PostgreSQL Replication vs Backups vs Snapshots](/learn/guides/postgresql-replication-vs-backups-vs-snapshots), and [Back Up PostgreSQL to Raff Object Storage with Restic](/learn/tutorials/back-up-postgresql-raff-object-storage-restic). If you prefer to avoid host-level database operations, compare [Raff Managed PostgreSQL](/products/managed-databases/postgresql). ## Sources - [PostgreSQL Linux downloads for Ubuntu](https://www.postgresql.org/download/linux/ubuntu/) - [PostgreSQL 18.6 release notes](https://www.postgresql.org/docs/release/18.6/) - [PostgreSQL versioning policy](https://www.postgresql.org/support/versioning/) - [PostgreSQL client authentication](https://www.postgresql.org/docs/18/client-authentication.html) - [PostgreSQL password authentication](https://www.postgresql.org/docs/18/auth-password.html) - [PostgreSQL pg_dump](https://www.postgresql.org/docs/18/app-pgdump.html) - [Ubuntu 24.04 PostgreSQL package](https://packages.ubuntu.com/noble/database/postgresql) - [Ubuntu 24.04 PostgreSQL 16 package](https://packages.ubuntu.com/noble/postgresql-16) - Technical guidance re-verified: 2026-09-17 --- ### Deploy an HTTP Function on Raff: Step-by-Step URL: https://rafftechnologies.com/learn/tutorials/deploy-http-function-raff Description: Deploy a Node.js HTTP Function on Raff, verify the live HTTPS URL, inspect logs, add environment variables, and confirm scale-to-zero and cost controls. Raff Functions can expose a standard HTTP handler through a live HTTPS URL without requiring a Raff-specific SDK or handler format. This tutorial uses Node.js because the built-in `http` module keeps the example portable and dependency-free. > This workflow was verified against the live Raff Functions product contract on September 21, 2026. It is not labeled "Tested on Raff" because this article was not produced from an independently recorded console deployment with engineer screenshots. ## What you will deploy You will deploy a small HTTP function that: - responds on `/`; - returns JSON; - reads a `name` query parameter; - uses Node.js standard `http`; - runs behind the HTTPS Function URL Raff assigns after deployment. Prerequisites: Node.js installed locally, a Raff account with Functions access, and permission to create and delete a test function. See [Raff Functions](/products/serverless-functions) for the product details. The example binds to `0.0.0.0` so the managed runtime can route requests. During local testing, use a trusted development environment and block inbound access to port 3000; do not expose the local test server publicly. Create a file named `server.js`: ```js const http = require("http"); const { URL } = require("url"); const server = http.createServer((req, res) => { const url = new URL(req.url, "http://localhost"); const name = url.searchParams.get("name") || "world"; res.writeHead(200, { "Content-Type": "application/json", }); res.end( JSON.stringify({ message: `Hello, ${name}!`, runtime: "node", }) ); }); const port = process.env.PORT || 3000; server.listen(port, "0.0.0.0", () => { console.log(`Listening on port ${port}`); }); ``` This is a standard Node.js HTTP server. It does not import a Raff-specific runtime package. ## Step 1 — Verify the function locally Run: ```bash node server.js ``` In a second terminal: ```bash curl "http://localhost:3000/?name=Raff" ``` Expected response: ```json {"message":"Hello, Raff!","runtime":"node"} ``` ### Verification Confirm that: - Node starts without an exception; - port 3000 is listening; - the endpoint returns HTTP 200; - the JSON changes when you change the `name` parameter. If the code does not work locally, fix that before deploying. ## Step 2 — Create a new Raff Function Open the Raff dashboard and go to **Functions**. Choose **New function**. The current Functions flow supports creating a function from a template, uploading or pasting code, or importing an AWS Lambda. For this tutorial, use the normal code path rather than Lambda migration. Give the function a short name such as: ```text hello-http ``` Raff assigns the final Function URL and adds a short random suffix so names do not collide across accounts. ### Verification Before deploying, confirm that the create screen shows: - your function name; - a supported runtime; - memory; - timeout; - scaling settings. The current product defaults shown by Raff are 256 MB memory, a 5-minute timeout, and scaling from 0 to 10. You can change these later, so do not over-tune a hello-world endpoint. ## Step 3 — Add the Node.js handler Select the Node.js runtime or use the in-dashboard editor/upload flow. Add the `server.js` file from Step 1. Raff Functions is designed around standard handlers. For Node.js, that means you can use normal Node HTTP code rather than a proprietary event object. If the deployment flow asks for an entry point, use the project entry point that starts `server.js`. ### Verification Review the code in the dashboard and confirm that: - the file is present; - the runtime is Node.js; - there are no Raff-specific imports; - the application listens on `process.env.PORT` when provided. ## Step 4 — Keep the first deployment simple For this endpoint, keep the default memory, timeout, and scale-to-zero behavior unless you have a reason to change them. A small HTTP handler usually does not need a long timeout or warm capacity. The goal of the first deployment is to verify the request path, not benchmark production settings. Raff Functions currently supports scale-to-zero, autoscaling, optional warm instances, and configurable memory and timeout settings. ### Verification Confirm that: - minimum scale remains 0 if you want scale-to-zero; - the current cost-control settings are visible on your account; - no unnecessary warm instance is enabled; - the timeout is comfortably above the few milliseconds this handler needs. ## Step 5 — Deploy the function Choose **Deploy**. Raff's current product flow builds standard handlers automatically, so Node.js workloads do not require a Dockerfile for a basic deployment. Wait for the deployment to reach a live state. The Function should receive an HTTPS URL similar in structure to: ```text https://hello-http-xxxxx.fn.raffusercloud.com ``` The suffix is assigned by the platform. ### Verification Copy the live URL and run: ```bash curl -i "https://YOUR-FUNCTION-URL/?name=Raff" ``` You should see: ```text HTTP/2 200 content-type: application/json ``` with a body similar to: ```json {"message":"Hello, Raff!","runtime":"node"} ``` This verifies both deployment and the public HTTP path. ## Step 6 — Test the live URL from more than one request Run several requests: ```bash curl "https://YOUR-FUNCTION-URL/?name=Alice" curl "https://YOUR-FUNCTION-URL/?name=Bob" curl "https://YOUR-FUNCTION-URL/" ``` Expected behavior: - Alice returns `Hello, Alice!`; - Bob returns `Hello, Bob!`; - no query parameter returns `Hello, world!`. ### Verification Check that every request returns HTTP 200 and valid JSON. This matters because a successful deployment alone does not prove the handler is parsing requests correctly. ## Step 7 — Check invocation logs Open the function's logs in the Raff dashboard. Raff Functions currently includes live log tailing and per-invocation observability. Recent requests can be correlated with their logs. Your code already logs: ```text Listening on port 3000 ``` For a production endpoint, add structured application logs for failures and important state transitions rather than logging secrets or full sensitive request bodies. ### Verification Send another request to the live URL and confirm that the dashboard shows recent invocation activity. Also check that the function's request count and error rate do not show an unexpected failure. ## Step 8 — Add an environment variable A function should not hard-code environment-specific configuration. Add an environment variable in the function configuration: ```text APP_ENV=production ``` Then update the response: ```js res.end( JSON.stringify({ message: `Hello, ${name}!`, runtime: "node", environment: process.env.APP_ENV || "development", }) ); ``` Redeploy the function. ### Verification Run: ```bash curl "https://YOUR-FUNCTION-URL/?name=Raff" ``` Expected body: ```json { "message": "Hello, Raff!", "runtime": "node", "environment": "production" } ``` For actual secrets, use masked-secret or scoped-binding features rather than placing credentials directly in source code. ## Step 9 — Verify scale-to-zero and cost controls Raff Functions pricing, metering dimensions, included usage, and account cost controls can change. Check the current Functions pricing and dashboard settings before making cost-sensitive decisions. For a low-traffic HTTP endpoint, scale-to-zero is usually the sensible starting point because idle instances should not remain allocated without a latency requirement. ### Verification Check the function configuration and confirm: - minimum scale is 0 unless you intentionally changed it; - the intended cost-control settings are configured; - memory and timeout match the workload; - no secret or credential is stored in source code. For latency-sensitive production APIs, test cold-start behavior with your actual code and dependencies before enabling warm instances. ## Step 10 — Run the final end-to-end verification Run: ```bash curl --fail-with-body -sS -i "https://YOUR-FUNCTION-URL/?name=FinalCheck" ``` Then verify all of the following: - the request returns HTTP 200; - JSON is valid; - the query parameter is reflected correctly; - the environment value is present; - the invocation appears in Raff logs; - the function has no unexpected errors; - the intended cost-control settings remain configured; - scale-to-zero remains configured if intended. Your first HTTP Function is now deployed and reachable through a live HTTPS URL. :::cta Deploy a Function Now Deploy an HTTPS handler on Raff. ::: ## When an HTTP Function is a good fit Use a Function when one request maps to a bounded unit of work, such as: - webhook receivers; - small JSON APIs; - image or document processing requests; - callbacks from another service; - asynchronous job submission; - internal utility endpoints. Use a persistent App Platform service or VM when the application depends on a continuously running process, many tightly coupled routes, long-lived connections, local process state, or a full operating-system environment. For the architecture decision, see [Serverless API Endpoint vs App Platform](/learn/guides/serverless-api-endpoint-vs-app-platform) and [Serverless Functions vs VMs](/learn/guides/serverless-functions-vs-vms-small-teams). ## Cleanup If this was only a test deployment: 1. remove any temporary environment variables; 2. delete or disable the Function in the dashboard; 3. confirm the live URL no longer serves the test endpoint; 4. review recent usage before removing the test project. Do not leave sample endpoints publicly reachable when they are no longer needed. --- ### How to Install Redis on Ubuntu 24.04 URL: https://rafftechnologies.com/learn/tutorials/install-redis-ubuntu-24-04 Description: Install Redis 7.0 on Ubuntu 24.04, configure ACL users, secure port 6379, set memory and persistence, and verify backup and restore safely. To install Redis on Ubuntu 24.04 using Ubuntu's distro-managed package path, run: ```bash sudo apt update sudo apt install -y redis-server redis-tools sudo systemctl enable --now redis-server redis-cli PING ``` A healthy fresh installation returns `PONG`. Ubuntu 24.04 currently maintains **Redis 7.0.15** through its security-updated distro packages. The current Ubuntu security package is `5:7.0.15-1ubuntu0.24.04.4`. Upstream Redis Open Source has moved to the **8.10** release line, so "current Redis version" depends on which package source you choose. Raff Linux VMs can run self-hosted Redis when you need host-level control. The original workflow was tested on a Raff VM with **1 vCPU and 2 GB RAM**. This refresh re-verifies the package, ACL, memory, persistence, backup, restore, and network guidance without claiming a new full machine test. If you want a managed Redis-compatible path instead, [Raff Managed Valkey](/products/managed-databases/valkey) removes host-level patching and database operations. Check the product page for current plans, included resources, limits, and any free-tier availability. Redis should stay reachable only by trusted clients. Keep port `6379` on loopback for a same-VM application, and use named ACL users instead of leaving the default unauthenticated user enabled. :::cluster ## Step 1 — Verify Ubuntu 24.04 and the Redis package candidate Confirm the operating system and architecture: ```bash . /etc/os-release printf '%s\n%s\n%s\n' "$PRETTY_NAME" "$VERSION_CODENAME" "$(dpkg --print-architecture)" ``` Expected Ubuntu values include: ```text Ubuntu 24.04 LTS noble ``` Refresh package metadata and inspect the candidate: ```bash sudo apt update apt-cache policy redis redis-server redis-tools ``` Ubuntu 24.04 remains on the Redis 7.0 branch. At this revision, the security-updated package is `5:7.0.15-1ubuntu0.24.04.4`. Check memory and disk headroom: ```bash free -h df -h / ``` Redis memory use is not just stored values. Account for key/value overhead, allocator overhead, client buffers, persistence, fork/copy-on-write behavior, and the operating system. **Verify:** the host reports Ubuntu 24.04/Noble, APT shows the Ubuntu Redis 7.0 package line, and the VM has enough memory and disk headroom for the intended workload. ## Step 2 — Install Redis Server and verify the service Install Redis, CLI tools, OpenSSL, and UFW: ```bash sudo apt install -y redis-server redis-tools openssl ufw ``` Enable and start the service: ```bash sudo systemctl enable --now redis-server ``` Verify package and binary versions: ```bash redis-server --version redis-cli --version apt-cache policy redis-server ``` Check service state: ```bash systemctl is-active redis-server systemctl is-enabled redis-server sudo systemctl status redis-server --no-pager ``` Test the initial local connection: ```bash redis-cli PING ``` Expected output: ```text PONG ``` **Verify:** `redis-server` is active and enabled, `PING` returns `PONG`, and APT shows Ubuntu as the installed package source. ## Step 3 — Keep Redis local-only and preserve protected mode Back up the configuration before editing it: ```bash sudo cp -a /etc/redis/redis.conf \ "/etc/redis/redis.conf.$(date -u +%Y%m%dT%H%M%SZ).backup" ``` Inspect the network settings: ```bash grep -nE '^[[:space:]]*(bind|protected-mode|port)[[:space:]]' \ /etc/redis/redis.conf ``` For a same-VM application, keep settings equivalent to: ```conf bind 127.0.0.1 -::1 protected-mode yes port 6379 ``` Do not replace the bind line with `0.0.0.0`. Redis is designed for trusted clients and should not be directly exposed to untrusted networks. Restart after a configuration change: ```bash sudo systemctl restart redis-server systemctl is-active redis-server sudo ss -lntp | grep ':6379' || true ``` **Verify:** Redis remains bound to loopback, protected mode stays enabled, and the service restarts cleanly. ## Step 4 — Configure named ACL users Redis 6 and later supports Access Control Lists. Use an external ACL file so application and administrative identities are separate and persistent. Create the ACL file while temporarily preserving the default local user: ```bash sudo install -o redis -g redis -m 600 /dev/null /etc/redis/users.acl echo 'user default on nopass ~* &* +@all' \ | sudo tee /etc/redis/users.acl >/dev/null sudo chown redis:redis /etc/redis/users.acl sudo chmod 600 /etc/redis/users.acl ``` Open `/etc/redis/redis.conf` and add: ```conf aclfile /etc/redis/users.acl ``` Do not define the same users in both `redis.conf` and the external ACL file. Restart and confirm the transition state works: ```bash sudo systemctl restart redis-server redis-cli PING ``` Generate separate passwords: ```bash ADMIN_PASSWORD="$(openssl rand -hex 32)" APP_PASSWORD="$(openssl rand -hex 32)" printf 'Redis admin password: %s\n' "$ADMIN_PASSWORD" printf 'Redis app password: %s\n' "$APP_PASSWORD" ``` Store both values in a secrets manager before continuing. Create the administrator and a restricted application user: ```bash redis-cli ACL SETUSER redisadmin \ reset on ">${ADMIN_PASSWORD}" '~*' '&*' +@all redis-cli ACL SETUSER raffapp \ reset on ">${APP_PASSWORD}" '~raffapp:*' \ resetchannels +@read +@write +ping -@dangerous redis-cli ACL SAVE ``` Authenticate as the new administrator, disable the unauthenticated default user, and persist the result: ```bash export REDISCLI_AUTH="$ADMIN_PASSWORD" redis-cli --user redisadmin PING redis-cli --user redisadmin ACL SETUSER default off redis-cli --user redisadmin ACL SAVE redis-cli --user redisadmin ACL LIST ``` Unauthenticated access should now fail: ```bash unset REDISCLI_AUTH redis-cli PING ``` Expected result includes: ```text NOAUTH Authentication required ``` Clear generated values after they are stored safely: ```bash unset ADMIN_PASSWORD APP_PASSWORD ``` **Verify:** the default user is off, `redisadmin` authenticates with administrative rights, `raffapp` exists with restricted key and command permissions, and `ACL SAVE` persists the users. ## Step 5 — Verify the application ACL and REDISCLI_AUTH workflow `REDISCLI_AUTH` lets `redis-cli` read the password from an environment variable instead of placing it directly in shell history or process arguments. Read the application password securely: ```bash read -rsp "Redis application password: " REDISCLI_AUTH echo export REDISCLI_AUTH ``` Authenticate as the application user and create a namespaced key: ```bash redis-cli --user raffapp PING redis-cli --user raffapp SET raffapp:health verified EX 300 redis-cli --user raffapp GET raffapp:health redis-cli --user raffapp TTL raffapp:health ``` Expected results include `PONG`, `OK`, `verified`, and a positive TTL. A key outside the permitted namespace should fail: ```bash redis-cli --user raffapp SET other:health blocked ``` A dangerous administrative command should also fail: ```bash redis-cli --user raffapp FLUSHALL ``` Remove the test key and clear the credential: ```bash redis-cli --user raffapp DEL raffapp:health unset REDISCLI_AUTH ``` Do not export `REDISCLI_AUTH` permanently in shell startup files. Set it only for the administrative session that needs it, then unset it. **Verify:** `raffapp` works only inside `raffapp:*`, dangerous commands are denied, and the password disappears from the environment after `unset REDISCLI_AUTH`. ## Step 6 — Configure maxmemory and an eviction policy Inspect current Redis memory state as the administrator: ```bash read -rsp "Redis administrator password: " REDISCLI_AUTH echo export REDISCLI_AUTH redis-cli --user redisadmin INFO memory | \ grep -E 'used_memory_human|maxmemory_human|maxmemory_policy|mem_not_counted_for_evict' ``` Open `/etc/redis/redis.conf` and set a deliberate memory ceiling. For the original 2 GB tutorial VM used purely as a cache, this is an example rather than a universal recommendation: ```conf maxmemory 1gb maxmemory-policy allkeys-lru ``` Common policy choices include: - `allkeys-lru` when any cache key may be evicted; - `allkeys-lfu` when frequently accessed keys should survive longer; - `volatile-lru` or `volatile-lfu` when only expiring keys are eviction candidates; - `noeviction` when writes should fail rather than silently evict data. Restart and verify persistence of the settings: ```bash sudo systemctl restart redis-server redis-cli --user redisadmin CONFIG GET maxmemory redis-cli --user redisadmin CONFIG GET maxmemory-policy unset REDISCLI_AUTH ``` **Verify:** `maxmemory` leaves headroom for the OS and Redis overhead, the eviction policy matches the workload, and both values survive restart. ## Step 7 — Choose and verify a persistence model Redis supports RDB snapshots, AOF, both, or no persistence. Choose based on the role of the data rather than enabling every option automatically. A practical starting model is: | Workload | Starting persistence choice | |---|---| | Rebuildable cache | RDB or no persistence | | Sessions with fallback | RDB with tested recovery | | Queue or important short-lived state | AOF, commonly `appendfsync everysec` | | Primary durable system of record | Re-evaluate architecture, replication, backups, and failure semantics explicitly | Inspect the current settings: ```bash read -rsp "Redis administrator password: " REDISCLI_AUTH echo export REDISCLI_AUTH redis-cli --user redisadmin CONFIG GET save redis-cli --user redisadmin CONFIG GET appendonly redis-cli --user redisadmin CONFIG GET appendfsync ``` If the workload requires AOF, edit `/etc/redis/redis.conf`: ```conf appendonly yes appendfsync everysec ``` Restart and verify: ```bash sudo systemctl restart redis-server redis-cli --user redisadmin CONFIG GET appendonly redis-cli --user redisadmin CONFIG GET appendfsync redis-cli --user redisadmin INFO persistence unset REDISCLI_AUTH ``` With `appendfsync everysec`, Redis documents that roughly up to about one second of writes may be lost in a failure. Local persistence is not a substitute for an off-server backup. **Verify:** persistence settings match the durability requirement and `INFO persistence` reports healthy RDB/AOF state after restart. ## Step 8 — Create a validated Redis 7 RDB backup Redis 8.10 introduced the newer `BACKUP` command family, but Ubuntu 24.04's distro Redis 7.0 package does not provide it. For this package line, create a completed RDB snapshot and copy the Redis configuration and ACL file with it. Create a protected backup directory: ```bash sudo install -d -m 700 /var/backups/redis ``` Authenticate as the administrator and read the active RDB location: ```bash read -rsp "Redis administrator password: " REDISCLI_AUTH echo export REDISCLI_AUTH REDIS_DIR="$(redis-cli --user redisadmin --raw CONFIG GET dir | tail -n 1)" RDB_FILE="$(redis-cli --user redisadmin --raw CONFIG GET dbfilename | tail -n 1)" printf 'RDB path: %s/%s\n' "$REDIS_DIR" "$RDB_FILE" ``` Trigger a background snapshot: ```bash redis-cli --user redisadmin BGSAVE ``` Wait for completion: ```bash while redis-cli --user redisadmin --raw INFO persistence \ | grep -q '^rdb_bgsave_in_progress:1'; do sleep 1 done redis-cli --user redisadmin INFO persistence | \ grep -E 'rdb_last_bgsave_status|rdb_last_save_time' ``` `rdb_last_bgsave_status` must be `ok`. Copy the completed RDB and configuration files: ```bash STAMP="$(date -u +%Y%m%d-%H%M%S)" sudo cp "$REDIS_DIR/$RDB_FILE" \ "/var/backups/redis/dump-${STAMP}.rdb" sudo tar -czf "/var/backups/redis/config-${STAMP}.tar.gz" \ /etc/redis/redis.conf \ /etc/redis/users.acl sudo chmod 600 \ "/var/backups/redis/dump-${STAMP}.rdb" \ "/var/backups/redis/config-${STAMP}.tar.gz" ``` Validate the snapshot: ```bash sudo redis-check-rdb "/var/backups/redis/dump-${STAMP}.rdb" ``` Clear the credential: ```bash unset REDISCLI_AUTH ``` Keep the complete backup set off-server. Raff [Object Storage](/products/object-storage) can be used by S3-compatible backup tooling, while [Data Protection](/products/data-protection) provides an additional VM-level recovery layer. **Verify:** the background save reports `ok`, `redis-check-rdb` validates the copied snapshot, configuration and ACL files are included, and production recovery includes an off-server copy. ## Step 9 — Restore-test the RDB in an isolated Redis instance A backup is not proven until it loads successfully. Prefer a disposable recovery VM. If you test on the same server, use a different loopback-only port and verify it is unused: ```bash sudo ss -lntp | grep ':6380' || true ``` The backup directory is root-only in this tutorial. Select and copy the latest RDB with `sudo`, then hand only the disposable copy to your current user: ```bash BACKUP_RDB="$(sudo find /var/backups/redis -maxdepth 1 -type f -name 'dump-*.rdb' -print | LC_ALL=C sort | tail -n 1)" # Stop here if no readable backup was selected. if [ -z "$BACKUP_RDB" ] || ! sudo test -s "$BACKUP_RDB"; then printf '%s\n' 'No non-empty backup found. Do not continue with restore.' >&2 false fi RESTORE_DIR="$(mktemp -d)" sudo cp "$BACKUP_RDB" "$RESTORE_DIR/dump.rdb" sudo chown "$USER":"$(id -gn)" "$RESTORE_DIR/dump.rdb" chmod 600 "$RESTORE_DIR/dump.rdb" ``` Start a disposable Redis process that listens only on loopback and does not create new persistence files: ```bash redis-server \ --port 6380 \ --bind 127.0.0.1 \ --protected-mode yes \ --dir "$RESTORE_DIR" \ --dbfilename dump.rdb \ --appendonly no \ --save "" \ --daemonize yes \ --pidfile "$RESTORE_DIR/redis.pid" \ --logfile "$RESTORE_DIR/redis.log" ``` Verify the recovered dataset: ```bash redis-cli -p 6380 PING redis-cli -p 6380 DBSIZE redis-cli -p 6380 INFO keyspace ``` For a production rehearsal, compare expected key counts and representative application keys rather than relying only on `PING`. Shut down and remove the disposable instance: ```bash redis-cli -p 6380 SHUTDOWN NOSAVE rm -rf "$RESTORE_DIR" ``` This temporary restore instance intentionally has no ACL because it is loopback-only and disposable. A real recovery server must restore the protected Redis configuration and ACL model before serving application traffic. **Verify:** the isolated process loads the RDB on port 6380, exposes the expected keyspace, shuts down cleanly, and leaves production Redis untouched. ## Step 10 — Protect Redis with UFW without risking SSH access Before changing UFW from a remote shell, open a second SSH session and inspect current rules: ```bash sudo ufw status numbered ``` If UFW is already active and Redis is local-only, add a deny rule if needed: ```bash sudo ufw deny 6379/tcp ``` If UFW is inactive, follow [Set Up UFW Firewall on Ubuntu 24.04](/learn/tutorials/set-up-ufw-firewall-ubuntu-24-04) rather than enabling it blindly from a single SSH session. Recheck the listener and firewall: ```bash sudo ss -lntp | grep ':6379' || true sudo ufw status numbered ``` **Verify:** port 6379 is not reachable through the public interface and SSH administration remains available after any firewall change. ## Step 11 — Optionally allow one private application VM with TLS Use this only when Redis and the application run on separate VMs connected through [Raff VPC](/products/vpc). Do not add a private Redis listener until the firewall is active and source-restricted. Example addresses: ```text Redis private IP: 10.0.0.5 Application private IP: 10.0.0.10 ``` Use certificates issued by a CA you control. Store them at protected paths such as: ```text /etc/redis/tls/ca.crt /etc/redis/tls/redis.crt /etc/redis/tls/redis.key ``` Protect the files: ```bash sudo chown -R root:redis /etc/redis/tls sudo chmod 750 /etc/redis/tls sudo chmod 640 /etc/redis/tls/redis.key sudo chmod 644 /etc/redis/tls/ca.crt /etc/redis/tls/redis.crt ``` Edit `/etc/redis/redis.conf`: ```conf bind 127.0.0.1 -::1 10.0.0.5 protected-mode yes port 6379 tls-port 6380 tls-cert-file /etc/redis/tls/redis.crt tls-key-file /etc/redis/tls/redis.key tls-ca-cert-file /etc/redis/tls/ca.crt tls-auth-clients no ``` Restart and verify listeners: ```bash sudo systemctl restart redis-server systemctl is-active redis-server sudo ss -lntp | grep -E ':6379|:6380' ``` Keep plaintext 6379 unavailable to the private network and allow only the application VM to the TLS listener: ```bash sudo ufw deny 6379/tcp sudo ufw allow from 10.0.0.10 to 10.0.0.5 port 6380 proto tcp sudo ufw status numbered ``` Copy only the CA certificate to the application VM, then authenticate with the restricted ACL user: ```bash read -rsp "Redis application password: " REDISCLI_AUTH echo export REDISCLI_AUTH redis-cli \ --tls \ --cacert /path/to/ca.crt \ --host 10.0.0.5 \ --port 6380 \ --user raffapp \ PING unset REDISCLI_AUTH ``` Do not create a public allow rule for either 6379 or 6380. **Verify:** the private TLS listener is reachable only from the approved application VM, the client validates the CA and authenticates as `raffapp`, and plaintext/public Redis access remains blocked. ## Step 12 — Apply Ubuntu patches and treat Redis 8.x as a planned upgrade Check for Ubuntu Redis updates: ```bash apt list --upgradable 2>/dev/null | grep -E '^redis' || true ``` Before patching Redis that contains important state: 1. create and validate a fresh backup; 2. copy it off-server; 3. review the Ubuntu security or changelog entry; 4. verify persistence health and free disk; 5. choose a maintenance window appropriate for the workload. Apply routine Ubuntu updates: ```bash sudo apt update sudo apt upgrade ``` Verify afterward: ```bash systemctl is-active redis-server redis-server --version apt-cache policy redis-server ``` Upstream Redis 8.10 includes capabilities that do not exist in Ubuntu's Redis 7.0 package, including the newer `BACKUP` command family. Moving from Ubuntu's distro package to Redis's upstream APT repository and a new major release should be treated as a planned migration with client, ACL, configuration, persistence, and rollback testing. **Verify:** routine patching keeps the intended Ubuntu package source, Redis restarts cleanly, and any 7.0-to-8.x move has a separate tested upgrade plan. ## Step 13 — Verify Redis end to end Check service, package, listener, and firewall state: ```bash echo 'Service:' systemctl is-active redis-server systemctl is-enabled redis-server echo 'Package:' apt-cache policy redis-server | sed -n '1,10p' echo 'Listeners:' sudo ss -lntp | grep -E ':6379|:6380' || true echo 'Firewall:' sudo ufw status numbered ``` Authenticate as the administrator: ```bash read -rsp "Redis administrator password: " REDISCLI_AUTH echo export REDISCLI_AUTH ``` Run the final Redis checks: ```bash redis-cli --user redisadmin PING redis-cli --user redisadmin ACL LIST redis-cli --user redisadmin CONFIG GET protected-mode redis-cli --user redisadmin CONFIG GET maxmemory redis-cli --user redisadmin CONFIG GET maxmemory-policy redis-cli --user redisadmin CONFIG GET appendonly redis-cli --user redisadmin INFO persistence | \ grep -E 'rdb_last_bgsave_status|aof_enabled|aof_last_write_status' redis-cli --user redisadmin INFO memory | \ grep -E 'used_memory_human|maxmemory_human|mem_not_counted_for_evict' unset REDISCLI_AUTH ``` The installation is complete when all of these are true: - Ubuntu 24.04 manages the intended Redis 7.0 package line; - the service is active and enabled; - public Redis access is blocked; - protected mode is enabled; - the unauthenticated default user is disabled; - administrator and application ACL users are separate; - the application user is constrained by key pattern and command permissions; - `maxmemory` and eviction behavior match the Redis role; - persistence matches the durability requirement; - the latest RDB backup validates successfully; - Redis configuration and ACL files are included in recovery copies; - an isolated restore test has succeeded; - optional cross-VM access is private, source-restricted, and encrypted; - a move to Redis 8.x is handled as a planned upgrade rather than an Ubuntu patch. **Verify:** all checks above succeed and the application ACL, persistence, backup, and isolated restore paths have been exercised successfully. :::cta valkey Run Redis or compare managed Valkey. ::: ## Cleanup (optional) Use this section only for resources created solely for this tutorial. Remove the tutorial application ACL user while keeping your administrator account: ```bash read -rsp "Redis administrator password: " REDISCLI_AUTH echo export REDISCLI_AUTH redis-cli --user redisadmin ACL DELUSER raffapp redis-cli --user redisadmin ACL SAVE unset REDISCLI_AUTH ``` **Warning:** The next commands permanently delete all backups matching these tutorial filenames. Keep an off-server copy of anything you need. Run them only in a disposable tutorial environment: ```bash sudo find /var/backups/redis -maxdepth 1 -type f -name 'dump-*.rdb' -print -delete sudo find /var/backups/redis -maxdepth 1 -type f -name 'config-*.tar.gz' -print -delete ``` Delete only the firewall rules you added for this tutorial: ```bash sudo ufw delete allow from 10.0.0.10 to 10.0.0.5 port 6380 proto tcp sudo ufw delete deny 6379/tcp ``` If you enabled the private TLS listener only for this tutorial, edit the current configuration: remove `10.0.0.5` from `bind`, set `tls-port 0`, and remove only the TLS certificate directives added in Step 11. Preserve `aclfile /etc/redis/users.acl`, memory and persistence settings. Do not restore the Step 3 backup: it predates ACL hardening. Restart Redis, verify loopback-only listeners, confirm authenticated access works, and confirm unauthenticated `PING` still fails. Do not delete `redisadmin` until you have another tested administrative access path. ## Troubleshooting ### `redis-server.service` is not found Verify that the Ubuntu server package is installed: ```bash dpkg -l | grep -E '^ii[[:space:]]+redis-server' apt-cache policy redis-server ``` Install and start it if necessary: ```bash sudo apt update sudo apt install -y redis-server sudo systemctl enable --now redis-server ``` ### `NOAUTH Authentication required` Authentication is working. Use the correct ACL username and password: ```bash read -rsp "Redis password: " REDISCLI_AUTH echo export REDISCLI_AUTH redis-cli --user redisadmin PING unset REDISCLI_AUTH ``` ### `REDISCLI_AUTH` is set but authentication still fails `REDISCLI_AUTH` supplies the password only. With named ACL users you still need `--user`: ```bash read -rsp "Redis application password: " REDISCLI_AUTH echo export REDISCLI_AUTH redis-cli --user raffapp PING unset REDISCLI_AUTH ``` Check the account definition as an administrator with `ACL GETUSER raffapp` if the username/password pair still fails. ### The application receives `NOPERM` Inspect the application ACL: ```bash redis-cli --user redisadmin ACL GETUSER raffapp ``` Grant only the key patterns, channel patterns, and command categories the application genuinely requires. Do not solve an ACL error by granting `+@all`. ### Redis uses more memory than expected Inspect memory and eviction configuration: ```bash redis-cli --user redisadmin INFO memory redis-cli --user redisadmin CONFIG GET maxmemory redis-cli --user redisadmin CONFIG GET maxmemory-policy redis-cli --user redisadmin --bigkeys ``` `maxmemory` limits the dataset used for eviction decisions. It does not guarantee that total process RSS stays below the same number. ### Redis cannot create an RDB snapshot Inspect persistence state, disk space, and logs: ```bash df -h / redis-cli --user redisadmin INFO persistence sudo journalctl -u redis-server --no-pager -n 100 ``` An AOF file does not remove the need for off-server backups and restore testing. ### Restore test returns permission denied The production backup directory is intentionally root-only. Use the `sudo ls`, `sudo cp`, and `chown` sequence in Step 9 to copy only the selected RDB into the disposable restore directory. ### TLS connections fail Check the TLS listener, file permissions, and service log: ```bash sudo ss -lntp | grep ':6380' || true sudo ls -l /etc/redis/tls sudo journalctl -u redis-server --no-pager -n 100 ``` Verify that the application trusts the CA that issued the server certificate and that the certificate identity matches the host the client uses. ## FAQ ### How do I install Redis on Ubuntu 24.04? Run `sudo apt update`, install `redis-server redis-tools`, enable `redis-server`, and verify the local service with `redis-cli PING`. ### What Redis version does Ubuntu 24.04 install? Ubuntu 24.04 maintains Redis 7.0.15. The current security-updated package is `5:7.0.15-1ubuntu0.24.04.4` at this revision. ### What is the current upstream Redis release line? Redis Open Source 8.10 is the current upstream release line in September 2026. It is separate from Ubuntu 24.04's distro-managed Redis 7.0 package path. ### Should I use requirepass or Redis ACL users? Use named ACL users for modern Redis. They let you restrict commands, keys, and channels per application instead of sharing one global password. ### Should Redis port 6379 be public? No. Keep it on loopback for same-VM applications. For another VM, use private networking, exact firewall source restrictions, ACL authentication, and TLS. ### What does REDISCLI_AUTH do? It lets `redis-cli` read the password from an environment variable. With named ACL users, still pass `--user`, and unset the variable after the administrative session. ### How should I back up Redis 7 on Ubuntu 24.04? Trigger `BGSAVE`, wait for a successful result, copy and validate the completed RDB, include `redis.conf` and the ACL file, keep an off-server copy, and restore-test it in isolation. ### Should I self-host Redis or use managed Valkey? Self-host when you need host-level control and can own patching, persistence, backup, monitoring, and incidents. Managed Valkey reduces that operational work while remaining Redis-compatible for common workloads. ## Conclusion You now have Redis 7.0 on a Raff Ubuntu 24.04 VM with named ACL users, private-by-default networking, deliberate memory and eviction settings, workload-appropriate persistence, validated RDB backups, and an isolated restore test. The package distinction matters: Ubuntu 24.04 currently maintains Redis 7.0.15 with security updates, while upstream Redis is on the 8.10 release line. Keep routine Ubuntu security updates separate from a deliberate repository and major-version migration. Continue with [Redis Hosting](/learn/guides/redis-hosting), [Redis Cache & Queue Strategy for SaaS Apps](/learn/guides/redis-cache-queue-strategy-saas-apps), and [Raff Managed Valkey](/products/managed-databases/valkey). ## Sources - [Ubuntu Redis security notice USN-8169-1](https://ubuntu.com/security/notices/USN-8169-1) - [Redis 8.10 release notes](https://redis.io/docs/latest/operate/oss_and_stack/stack-with-enterprise/release-notes/redisce/redisos-8.10-release-notes/) - [Redis security](https://redis.io/docs/latest/operate/oss_and_stack/management/security/) - [Redis ACL](https://redis.io/docs/latest/operate/oss_and_stack/management/security/acl/) - [Redis TLS](https://redis.io/docs/latest/operate/oss_and_stack/management/security/encryption/) - [Redis persistence](https://redis.io/docs/latest/operate/oss_and_stack/management/persistence/) - [Redis key eviction](https://redis.io/docs/latest/develop/reference/eviction/) - [Redis BACKUP command](https://redis.io/docs/latest/commands/backup/) - Package, security, and upstream release guidance re-verified: 2026-09-17 --- ### How to Install pip on Ubuntu 24.04 and Use Python venv URL: https://rafftechnologies.com/learn/tutorials/install-python-pip-ubuntu-24-04 Description: Install pip on Ubuntu 24.04, create a Python venv, fix externally-managed-environment errors, use requirements files, and install pipx safely. Ubuntu 24.04 uses Python 3.12 by default, but application dependencies should not be installed into the operating system's Python environment with a normal global `pip install`. Ubuntu follows the externally managed environment model defined by Python packaging standards, so the safe default is to install `python3-pip` and `python3-venv` with APT, create a project-specific virtual environment, and run pip inside that environment. On a [Raff Linux VM](/products/linux-vm) running Ubuntu 24.04, this keeps your project packages separate from files managed by the operating system. It also makes deployments easier to reproduce: each application can have its own `.venv`, dependency file, and package versions without changing Python packages required by system tools. This tutorial shows how to install pip on Ubuntu 24.04, create and verify a Python virtual environment, install packages safely, work with requirements files, use pipx for standalone Python command-line applications, troubleshoot `externally-managed-environment`, and clean up the test environment. It uses `python -m pip` inside the virtual environment so the pip command is tied to the Python interpreter you actually intend to use. Prerequisites: - A Raff Linux VM running Ubuntu 24.04 - SSH access with a non-root user that has sudo privileges - No public application port or firewall change is required for this tutorial ## Step 1 — Verify the Ubuntu 24.04 Python Version Check the default Python 3 interpreter: ```bash python3 --version ``` Ubuntu 24.04 defaults to Python 3.12. The exact patch version can change through Ubuntu updates, so do not depend on a hard-coded `3.12.x` patch number. Check which executable is being used: ```bash command -v python3 python3 -c 'import sys; print(sys.executable)' ``` On a standard Ubuntu installation, the system interpreter is normally under `/usr/bin/`. **Verify:** `python3 --version` should report Python 3.12.x and `sys.executable` should point to the intended system Python before you create a virtual environment. ## Step 2 — Install pip and venv with APT Refresh package metadata and install the Ubuntu packages for pip and virtual environments: ```bash sudo apt update sudo apt install -y python3-pip python3-venv ``` Check pip through the Python interpreter rather than relying only on a standalone `pip3` command: ```bash python3 -m pip --version ``` Also verify that the `venv` module is available: ```bash python3 -m venv --help >/dev/null && echo 'venv available' ``` Using APT here matters because Ubuntu manages the system Python installation. Avoid using `get-pip.py` to replace the distro-managed pip on a normal Ubuntu server. **Verify:** `python3 -m pip --version` should succeed and the venv check should print `venv available`. ## Step 3 — Understand the externally-managed-environment Error Ubuntu 24.04 marks its system Python as externally managed. Python packaging tools use this marker to avoid modifying packages owned by the operating system. Locate the marker without changing the system: ```bash python3 - <<'PY' import os import sysconfig path = os.path.join(sysconfig.get_path('stdlib'), 'EXTERNALLY-MANAGED') print(path) print('exists:', os.path.exists(path)) PY ``` On Ubuntu 24.04, a normal system-level command such as: ```bash python3 -m pip install requests ``` is expected to be rejected outside a virtual environment with an `externally-managed-environment` message. pip provides `--break-system-packages` as an explicit override, but that bypasses the protection. Do not use it as the normal application-dependency workflow. Use a virtual environment instead. **Verify:** The marker check should report that the externally managed marker exists on the distro-managed Python installation. ## Step 4 — Create a Python Virtual Environment on Ubuntu Create a project directory and a virtual environment named `.venv`: ```bash mkdir -p ~/my-python-project cd ~/my-python-project python3 -m venv .venv ``` Python's standard `venv` module creates an isolated Python environment for the project. Unless `--without-pip` is specified, venv bootstraps pip into the environment. Starting with Python 3.12, setuptools is no longer installed as a core venv dependency by default. Install it only when your project or build process actually requires it. Inspect the environment: ```bash ls -la .venv .venv/bin/python --version .venv/bin/python -m pip --version ``` Add the environment directory to Git ignore rules if this is a version-controlled project: ```bash printf '.venv/\n' >> .gitignore ``` **Verify:** `.venv/bin/python` and `.venv/bin/python -m pip` should both run successfully, and `.venv/` should be excluded from version control. ## Step 5 — Activate the venv and Verify Which Python and pip You Are Using Activate the environment in Bash: ```bash source .venv/bin/activate ``` Check the active executables: ```bash which python python --version python -m pip --version ``` The paths should now point inside `~/my-python-project/.venv/`. Using `python -m pip` is useful because it makes the relationship between the interpreter and pip explicit. It avoids accidentally invoking a pip executable from another Python installation on systems with multiple interpreters. You do not have to activate a venv to use it. Automation and systemd units can call its interpreter directly: ```bash ~/my-python-project/.venv/bin/python -m pip --version ``` **Verify:** `which python` and the pip output should both reference the `.venv` directory. ## Step 6 — Install and Verify a Python Package with pip With the virtual environment active, install a small test dependency: ```bash python -m pip install requests ``` Inspect the installed package: ```bash python -m pip show requests ``` Verify that Python can import it: ```bash python - <<'PY' import requests print('requests version:', requests.__version__) PY ``` Check the package location: ```bash python -c 'import requests; print(requests.__file__)' ``` The path should be inside `.venv`, not the system Python directories. This tutorial intentionally does not start a Flask development server or open a public firewall port. Installing pip and verifying a package does not require exposing an application to the internet. **Verify:** `requests` should import successfully and its file path should be inside your project's `.venv`. :::cta Deploy Your Server Launch a Raff Ubuntu VM and use isolated Python environments for development and application deployment. ::: ## Step 7 — Record and Reinstall Dependencies with a Requirements File For a simple pip-based project, you can record the current environment: ```bash python -m pip freeze > requirements.txt ``` Inspect the file: ```bash cat requirements.txt ``` A requirements file is one common way to reproduce an environment, but it is not the only dependency-management format in Python. Some projects use `pyproject.toml`, lock files, or another dependency tool. Commit the dependency files your project actually uses rather than treating `requirements.txt` as mandatory for every Python project. Test that pip can parse the file: ```bash python -m pip install -r requirements.txt ``` For deployment, review dependency changes before upgrading packages. Avoid a blind `pip install --upgrade` across every production dependency without testing the result. **Verify:** `requirements.txt` should contain the installed dependency set and `python -m pip install -r requirements.txt` should complete without changing the system Python. ## Step 8 — Use pipx for Standalone Python Command-Line Applications A virtual environment is appropriate for libraries used by a project. For standalone Python command-line applications that you want available from your shell, pipx is usually a better fit because it creates a separate environment for each application. Install pipx from Ubuntu's package manager: ```bash sudo apt update sudo apt install -y pipx ``` Add the pipx application directory to your user PATH: ```bash pipx ensurepath ``` You may need to open a new shell before the PATH change is visible. Check pipx: ```bash pipx --version pipx list ``` For example, a CLI package can be installed into its own managed environment with: ```bash pipx install httpie ``` Remove the example when you are finished: ```bash pipx uninstall httpie ``` Do not use pipx for libraries that your application imports. Those belong in the application's venv. **Verify:** `pipx --version` should succeed, and `pipx list` should show only the standalone applications you intentionally installed. ## Step 9 — Troubleshoot pip and venv on Ubuntu 24.04 ### `externally-managed-environment` If pip shows this error, confirm that you are outside a virtual environment: ```bash python3 -c 'import sys; print(sys.prefix); print(sys.base_prefix)' ``` If the two paths are equal, create or activate a venv: ```bash python3 -m venv .venv source .venv/bin/activate python -m pip install ``` Do not reach for `sudo pip install` or `--break-system-packages` as the default fix. ### `No module named venv` or venv creation fails Install the Ubuntu venv package: ```bash sudo apt update sudo apt install -y python3-venv ``` Then retry: ```bash python3 -m venv .venv ``` ### `pip: command not found` Use the interpreter-bound form first: ```bash python3 -m pip --version ``` If pip is missing from the Ubuntu system Python, install the package: ```bash sudo apt install -y python3-pip ``` Inside a venv, use: ```bash python -m pip --version ``` ### A package fails to build from source pip prefers a compatible wheel when one exists. If no wheel is available, a source build may require a compiler or development headers. Read the package's build documentation and install only the system dependencies it actually requires instead of installing a large build-tool bundle preemptively. ### The wrong Python receives the package Compare the interpreter and package location: ```bash which python python -c 'import sys; print(sys.executable)' python -m pip --version ``` All three should refer to the same virtual environment when it is active. **Verify:** After troubleshooting, `python -m pip --version` and an import test should both resolve inside the intended `.venv`. ## Step 10 — Run the Final End-to-End Verification From the project directory with the environment active, run: ```bash python --version python -m pip --version python -c 'import requests; print(requests.__version__)' python -c 'import requests; print(requests.__file__)' python -m pip check ``` `pip check` verifies whether installed packages have compatible declared dependencies. Confirm that the environment is isolated from the system interpreter: ```bash python - <<'PY' import sys print('prefix:', sys.prefix) print('base_prefix:', sys.base_prefix) print('isolated:', sys.prefix != sys.base_prefix) PY ``` Expected result: ```text isolated: True ``` You now have the core Ubuntu 24.04 Python workflow: APT manages the system Python packages, venv isolates application dependencies, and pip installs packages inside that venv. **Verify:** The import should succeed, `pip check` should report no broken requirements, and `isolated` should be `True`. ## Step 11 — Deactivate or Clean Up the Test Environment Leave the active virtual environment: ```bash deactivate ``` Confirm that your shell has returned to the system interpreter: ```bash command -v python3 python3 --version ``` If this was only a disposable test project, remove the entire project directory rather than trying to uninstall each virtual-environment package individually: ```bash rm -rf ~/my-python-project ``` Only run that command if the directory contains no source code or files you need to keep. If you want to rebuild a real project's venv, keep the source and dependency files, remove only `.venv`, and recreate it: ```bash rm -rf .venv python3 -m venv .venv source .venv/bin/activate python -m pip install -r requirements.txt ``` Virtual environments are designed to be disposable and recreated rather than copied between machines. **Verify:** The test `.venv` should be gone when cleanup is intended, while the Ubuntu system Python should continue to work normally. ## Conclusion You installed pip on Ubuntu 24.04 with `python3-pip`, created a Python 3.12 virtual environment with `venv`, installed packages without modifying the externally managed system Python, verified package isolation, recorded dependencies, and used pipx for standalone command-line applications. The key rule is simple: let APT manage the operating system's Python environment and let project-specific virtual environments manage application dependencies. If you see `externally-managed-environment`, treat it as a signal to check whether you should be using a venv rather than as an error to bypass automatically. For production Python deployments, continue with [Deploy Django with Gunicorn and Nginx](/learn/tutorials/deploy-django-nginx-gunicorn-ubuntu-24-04), [Deploy FastAPI with Nginx and systemd](/learn/tutorials/deploy-fastapi-ubuntu-24-04), or [Install Nginx on Ubuntu 24.04](/learn/tutorials/install-nginx-ubuntu-24-04). ## Sources - [Ubuntu 24.04 LTS release notes](https://documentation.ubuntu.com/release-notes/24.04/) - [Python Packaging User Guide — Externally Managed Environments](https://packaging.python.org/en/latest/specifications/externally-managed-environments/) - [Python 3.12 — Virtual Environments and Packages](https://docs.python.org/3.12/tutorial/venv.html) - [Python Packaging User Guide — Installing packages with pip and venv](https://packaging.python.org/en/latest/guides/installing-using-pip-and-virtual-environments/) - [pipx — Install pipx](https://pipx.pypa.io/latest/how-to/install-pipx.html) - Sources verified: 2026-09-04 --- ### How to Install Certbot for Nginx on Ubuntu 24.04 with Let's Encrypt URL: https://rafftechnologies.com/learn/tutorials/secure-nginx-lets-encrypt-ubuntu-24-04 Description: Install Certbot for Nginx on Ubuntu 24.04, issue a Let's Encrypt SSL certificate, redirect HTTP to HTTPS, test renewal, and troubleshoot common errors. Certbot is an ACME client that can request a free TLS certificate from Let's Encrypt, install it into an Nginx server block, configure an HTTP-to-HTTPS redirect, and renew the certificate automatically. On Ubuntu 24.04, the safest workflow is to verify DNS and Nginx first, keep port 80 reachable for HTTP-01 validation, install a current Certbot build, request the certificate with the Nginx plugin, and test renewal before treating HTTPS as complete. Raff users can apply this workflow to a [Linux VPS](/products/linux-vm) running Nginx on Ubuntu 24.04. The tutorial assumes your domain already resolves to the VM and Nginx serves the site over HTTP. If Nginx is not installed yet, complete [Install Nginx on Ubuntu 24.04](/learn/tutorials/install-nginx-ubuntu-24-04) first. Let's Encrypt recommends keeping port 80 open for general web servers and redirecting HTTP to HTTPS rather than blocking HTTP entirely. Certbot's current Nginx instructions also support having Certbot edit the Nginx configuration directly, then testing automatic renewal with `certbot renew --dry-run`. Prerequisites: - A Raff Linux VM running Ubuntu 24.04 - Nginx installed and serving the intended hostname over HTTP - A domain name with DNS records pointing to the VM - A non-root user with sudo privileges - Public access to TCP ports 80 and 443 ## Step 1 — Verify DNS Before Running Certbot Check the IPv4 records for every hostname you want on the certificate: ```bash dig +short A example.com dig +short A www.example.com ``` If the domain publishes IPv6, check the AAAA records too: ```bash dig +short AAAA example.com dig +short AAAA www.example.com ``` Each hostname included in the certificate request must resolve to this server. A stale AAAA record can send validation traffic to the wrong IPv6 host even when the A record is correct. Compare the DNS result with the VM's public address. If a hostname should not be used, do not include it in the Certbot command. **Verify:** All requested hostnames should resolve to the intended server, and any published AAAA record should reach the same Nginx deployment. ## Step 2 — Verify Nginx Serves the Domain Over HTTP Check the active Nginx configuration: ```bash sudo nginx -t ``` Confirm the site responds over HTTP: ```bash curl -I http://example.com ``` Inspect the server block if needed: ```bash sudo nginx -T 2>/dev/null | grep -A8 -B3 'server_name example.com' ``` The active server block should contain the hostname you plan to request with Certbot, for example: ```nginx server { listen 80; listen [::]:80; server_name example.com www.example.com; root /var/www/example.com/public; } ``` Certbot's Nginx plugin needs to identify the matching server block before it can install the certificate cleanly. **Verify:** `sudo nginx -t` should succeed and `curl -I http://example.com` should return an HTTP response from the intended Nginx site. ## Step 3 — Keep Ports 80 and 443 Reachable Check UFW status: ```bash sudo ufw status numbered ``` If UFW is active, allow SSH and the Nginx profile for HTTP and HTTPS: ```bash sudo ufw allow OpenSSH sudo ufw allow 'Nginx Full' ``` Review the result: ```bash sudo ufw status numbered ``` Do not close port 80 after enabling HTTPS when using the HTTP-01 validation path. Let's Encrypt recommends serving HTTP and redirecting it to HTTPS. Also verify that any upstream cloud firewall or network policy allows TCP 80 and 443 to this VM. **Verify:** The server remains reachable over SSH, HTTP reaches port 80, and HTTPS traffic is allowed on port 443. ## Step 4 — Install Certbot for Nginx on Ubuntu 24.04 Certbot's current Linux instructions support installing the Certbot snap maintained by the Certbot team. Avoid mixing multiple Certbot installation methods on the same server. First check for an existing installation: ```bash command -v certbot || true snap list certbot 2>/dev/null || true dpkg -l | grep -E 'certbot|python3-certbot-nginx' || true ``` If Certbot is already managing production certificates successfully, do not replace it only for this tutorial. Continue with the existing supported installation and verify renewal. For a new installation, make sure `snap` is available: ```bash command -v snap || sudo apt install -y snapd ``` Install Certbot: ```bash sudo snap install --classic certbot ``` Create the standard command path if needed: ```bash sudo ln -sf /snap/bin/certbot /usr/local/bin/certbot ``` Check the installed version and Nginx plugin: ```bash certbot --version certbot plugins | grep -A3 nginx ``` Do not depend on a specific Certbot version string in automation because the package is updated over time. **Verify:** `certbot --version` should succeed and `certbot plugins` should list the Nginx plugin. ## Step 5 — Request and Install a Let's Encrypt Certificate with Certbot and Nginx Request the certificate and let Certbot update the matching Nginx server block: ```bash sudo certbot --nginx --redirect \ -d example.com \ -d www.example.com ``` Certbot will ask for an email address and agreement to the Let's Encrypt terms. The `--redirect` option configures HTTP requests to redirect to HTTPS after successful issuance. If you use only the apex hostname, request only that name: ```bash sudo certbot --nginx --redirect -d example.com ``` Do not request hostnames that do not resolve to this server. After issuance, list managed certificates: ```bash sudo certbot certificates ``` Do not manually edit files inside `/etc/letsencrypt/live/` or `/etc/letsencrypt/renewal/`; Certbot manages those paths. **Verify:** `sudo certbot certificates` should list the requested hostname and `sudo nginx -t` should still pass. ## Step 6 — Verify HTTPS, the HTTP Redirect, and the Certificate Test HTTPS: ```bash curl -I https://example.com ``` Test the HTTP redirect: ```bash curl -I http://example.com ``` The HTTP response should redirect to the HTTPS URL, commonly with `301` or `308`. Inspect the certificate presented by Nginx: ```bash openssl s_client \ -connect example.com:443 \ -servername example.com \ /dev/null | openssl x509 -noout -subject -issuer -dates ``` Check that the certificate matches the hostname and has valid start and expiry dates. **Verify:** HTTPS should complete without a certificate error, HTTP should redirect to HTTPS, and the certificate dates should be valid. ## Step 7 — Test Certbot Automatic Renewal for Nginx Most Certbot installations include a scheduled renewal task. Check both common scheduling paths: ```bash systemctl list-timers --all | grep -i certbot || true sudo grep -R 'certbot renew' /etc/crontab /etc/cron.* 2>/dev/null || true ``` Run Certbot's renewal simulation: ```bash sudo certbot renew --dry-run ``` This tests the renewal path without replacing your active production certificate. Review managed certificate details again: ```bash sudo certbot certificates ``` You normally should not create an extra custom cron job when your Certbot installation already provides automatic renewal. **Verify:** `sudo certbot renew --dry-run` should complete successfully and a scheduled renewal mechanism should be present for the installation method in use. ## Step 8 — Add Security Headers Without Breaking the Site TLS does not automatically configure application security headers. Add only headers that match your application's requirements. Open the active HTTPS server block and add a conservative baseline inside the `server` block: ```nginx add_header X-Content-Type-Options "nosniff" always; add_header Referrer-Policy "strict-origin-when-cross-origin" always; add_header X-Frame-Options "SAMEORIGIN" always; ``` `X-Frame-Options: SAMEORIGIN` is not appropriate when the site must be embedded by another origin. Treat HSTS separately. Enable it only after HTTPS, redirects, certificate renewal, and every required hostname are working reliably. Start with a short test duration: ```nginx add_header Strict-Transport-Security "max-age=300" always; ``` Do not add `includeSubDomains` until every required subdomain supports HTTPS. Validate and reload: ```bash sudo nginx -t sudo systemctl reload nginx ``` Check the headers: ```bash curl -I https://example.com ``` **Verify:** `nginx -t` should pass, the site should remain reachable over HTTPS, and only the intended headers should appear. ## Step 9 — Troubleshoot Common Certbot and Nginx Errors ### Certbot cannot find a matching Nginx server block Confirm the hostname appears in an enabled server block: ```bash sudo nginx -T 2>/dev/null | grep -n 'server_name' ``` Correct `server_name`, then run: ```bash sudo nginx -t sudo systemctl reload nginx ``` ### The Nginx plugin is not installed Check available plugins: ```bash certbot plugins ``` With the Certbot snap, the Nginx plugin should be included. If Certbot comes from another installation method, follow the instructions for that method rather than mixing packages. ### HTTP-01 validation fails Check DNS and port 80: ```bash dig +short A example.com dig +short AAAA example.com sudo ss -ltnp | grep ':80' sudo ufw status numbered curl -I http://example.com ``` A wrong A/AAAA record, blocked port 80, or incorrect Nginx routing can all break validation. ### `/.well-known/acme-challenge/` returns 404 If a custom Nginx rule intercepts hidden paths or rewrites all requests, inspect the active configuration before retrying: ```bash sudo nginx -T 2>/dev/null | grep -n -E 'well-known|rewrite|return|location' ``` Fix the conflicting routing rule instead of repeatedly requesting new certificates. ### Certbot hits a Let's Encrypt rate limit Stop retrying the same broken production request. Fix DNS, firewall, or Nginx first. Use Certbot's dry-run or staging workflow while validating renewal behavior. ### Renewal works but Nginx serves an old certificate Check the certificate Certbot manages, validate Nginx, and reload it: ```bash sudo certbot certificates sudo nginx -t sudo systemctl reload nginx ``` Then inspect the live certificate again with `openssl s_client`. **Verify:** After troubleshooting, `sudo nginx -t`, `curl -I https://example.com`, and `sudo certbot renew --dry-run` should all succeed. ## Step 10 — Run the Final End-to-End HTTPS Verification Run the complete verification sequence: ```bash sudo nginx -t systemctl is-active nginx curl -I http://example.com curl -I https://example.com sudo certbot certificates sudo certbot renew --dry-run openssl s_client \ -connect example.com:443 \ -servername example.com \ /dev/null | openssl x509 -noout -subject -issuer -dates ``` The deployment is complete when Nginx configuration is valid, HTTP redirects to HTTPS, the HTTPS endpoint presents the expected certificate, and the renewal dry run succeeds. If this Nginx instance proxies a Node.js application, keep the application port private and let Nginx own the public HTTPS edge. See [Install PM2 and Deploy Node.js on Ubuntu 24.04](/learn/tutorials/deploy-nodejs-pm2-ubuntu-24-04) for that architecture. **Verify:** Every command above should succeed without certificate, redirect, Nginx syntax, or renewal errors. :::cta Deploy Your Server Run your HTTPS site on Raff. ::: ## Cleanup (optional) Do not delete a certificate that is still serving a production hostname. List Certbot-managed certificates first: ```bash sudo certbot certificates ``` If this was only a disposable test hostname, first inspect references while the certificate still exists: ```bash sudo grep -RFn '/etc/letsencrypt/live/example.com/' /etc/nginx ``` Remove or update only the decommissioned site's server block. Remove every reference to this certificate, then validate and reload before deleting it: ```bash sudo nginx -t && sudo systemctl reload nginx ``` Continue only after validation and reload succeed and no active service depends on the certificate. Then remove the certificate through Certbot: ```bash sudo certbot delete --cert-name example.com sudo nginx -t ``` Do not uninstall Certbot while it still manages certificates for other sites on the server. **Verify:** `sudo certbot certificates` should no longer list the deleted test certificate, and `sudo nginx -t` should still succeed. ## Conclusion You installed Certbot for Nginx on Ubuntu 24.04, requested a Let's Encrypt certificate, configured HTTP-to-HTTPS redirection, verified the live certificate, tested automatic renewal, and added a conservative security-header baseline. The most important production checks are simple: keep DNS correct, keep port 80 available for the HTTP-01 workflow, validate Nginx before reloads, do not mix Certbot installation methods casually, and treat `certbot renew --dry-run` as part of the deployment rather than an optional afterthought. For related setup work, continue with [Install Nginx on Ubuntu 24.04](/learn/tutorials/install-nginx-ubuntu-24-04), [Install PM2 and Deploy Node.js on Ubuntu 24.04](/learn/tutorials/deploy-nodejs-pm2-ubuntu-24-04), or [Install WordPress on Ubuntu 24.04 with Nginx](/learn/tutorials/install-wordpress-ubuntu-24-04-nginx). ## Sources - [Certbot — Nginx on Linux (snap)](https://certbot.eff.org/instructions?ws=nginx&os=snap) - [Certbot User Guide — Automated Renewals](https://eff-certbot.readthedocs.io/en/latest/using.html#automated-renewals) - [Let's Encrypt — Keep Port 80 Open](https://letsencrypt.org/docs/allow-port-80/) - Sources verified: 2026-09-04 --- ### Generate SSH Keys on Ubuntu 24.04: Ed25519 Setup Guide URL: https://rafftechnologies.com/learn/tutorials/set-up-ssh-keys-ubuntu-24-04 Description: Generate an SSH key on Ubuntu 24.04 with Ed25519, ssh-keygen, ssh-copy-id, ssh-agent, safe password disabling, troubleshooting, and key rotation. SSH key authentication uses a public and private key pair instead of relying on a reusable server password. The private key stays on your local computer, while the public key is added to the Ubuntu account you want to access. In this tutorial, you will generate an Ed25519 SSH key, copy it to Ubuntu 24.04, verify the correct identity is used, configure `ssh-agent`, disable password authentication safely, and rotate or revoke keys later. This workflow is written for a [Raff Linux VM](/products/linux-vm) running Ubuntu 24.04, but the OpenSSH key-management steps also apply to standard Ubuntu 24.04 servers. Keep a working SSH session or browser-console recovery path open before changing authentication settings. ## Step 1 — Check for Existing SSH Keys Run this on your local computer: ```bash ls -la ~/.ssh ``` Common key files include: ```text id_ed25519 id_ed25519.pub id_rsa id_rsa.pub ``` Do not overwrite an existing private key unless you intentionally want to replace it. You can create a separate key for Raff servers, a specific environment, or a specific team member. ## Step 2 — Generate an Ed25519 Key Pair Generate a new key on your local computer: ```bash ssh-keygen -t ed25519 -a 100 -C "raff-ubuntu-access" ``` When prompted for a file name, press Enter for the default path or choose a descriptive name such as: ```text ~/.ssh/raff_ed25519 ``` Set a passphrase for interactive administrator keys. The passphrase protects the private key if the local device or key file is copied. The two generated files have different roles: - `id_ed25519` or your custom filename is the private key. Do not upload or share it. - The matching `.pub` file is the public key. This is the file copied to servers. Ed25519 is the preferred default for modern OpenSSH systems. Use RSA only when a legacy system or policy specifically requires it. ## Step 3 — Inspect the Public Key and Fingerprint Display the public key: ```bash cat ~/.ssh/id_ed25519.pub ``` For a custom filename: ```bash cat ~/.ssh/raff_ed25519.pub ``` Display its fingerprint: ```bash ssh-keygen -lf ~/.ssh/id_ed25519.pub ``` Fingerprints help identify keys during audits and rotation without comparing the entire public-key string. ## Step 4 — Copy the Public Key to Ubuntu The simplest method is `ssh-copy-id`: ```bash ssh-copy-id your_user@your_server_ip ``` For a custom public key: ```bash ssh-copy-id -i ~/.ssh/raff_ed25519.pub your_user@your_server_ip ``` The command authenticates using the server's current access method and appends the public key to the user's `~/.ssh/authorized_keys` file. When `ssh-copy-id` is unavailable, use this fallback from your local computer: ```bash cat ~/.ssh/id_ed25519.pub | \ ssh your_user@your_server_ip \ 'umask 077; mkdir -p ~/.ssh; cat >> ~/.ssh/authorized_keys' ``` On the server, verify ownership and permissions: ```bash chmod 700 ~/.ssh chmod 600 ~/.ssh/authorized_keys chown -R "$USER":"$USER" ~/.ssh ``` ## Step 5 — Verify Key Authentication in a New Session Keep the original SSH session open and test a separate connection: ```bash ssh your_user@your_server_ip ``` When using a custom key, specify it explicitly: ```bash ssh -i ~/.ssh/raff_ed25519 your_user@your_server_ip ``` Use verbose output when troubleshooting: ```bash ssh -vv -i ~/.ssh/raff_ed25519 your_user@your_server_ip ``` Look for output showing that the client offered the intended public key and that authentication succeeded. Exact wording varies by OpenSSH version. Confirm the server stored the expected public key: ```bash nl -ba ~/.ssh/authorized_keys ``` Do not disable passwords until a new key-based session succeeds. :::cta Deploy Your Server Create an Ubuntu 24.04 Linux VM and provision it with SSH key access from the first login. ::: ## Step 6 — Load the Key into ssh-agent Start an agent in the current local shell when one is not already available: ```bash eval "$(ssh-agent -s)" ``` Add the key: ```bash ssh-add ~/.ssh/id_ed25519 ``` Or add the custom key: ```bash ssh-add ~/.ssh/raff_ed25519 ``` List loaded identities: ```bash ssh-add -l ``` The agent keeps the decrypted key available for the session so you do not have to re-enter its passphrase for every connection. Desktop operating systems may provide their own agent or secure key integration. ## Step 7 — Disable Password Authentication Safely Ubuntu's OpenSSH package includes `/etc/ssh/sshd_config.d/*.conf` near the start of the main configuration. For most `sshd_config` keywords, OpenSSH uses the **first value it obtains**, so a later file such as `99-something.conf` does not reliably override an earlier drop-in. Inspect the existing authentication settings first: ```bash sudo grep -RniE \ '^[[:space:]]*(PubkeyAuthentication|PasswordAuthentication|KbdInteractiveAuthentication|PermitRootLogin)[[:space:]]' \ /etc/ssh/sshd_config /etc/ssh/sshd_config.d 2>/dev/null ``` Create an early drop-in for the key-only policy: ```bash sudo nano /etc/ssh/sshd_config.d/00-raff-key-auth.conf ``` Add: ```text PubkeyAuthentication yes PasswordAuthentication no KbdInteractiveAuthentication no ``` Validate the complete configuration: ```bash sudo sshd -t ``` Check the effective values rather than assuming the drop-in won: ```bash sudo sshd -T | grep -E '^(pubkeyauthentication|passwordauthentication|kbdinteractiveauthentication) ' ``` The expected values are: ```text pubkeyauthentication yes passwordauthentication no kbdinteractiveauthentication no ``` If an effective value is still different, inspect the earlier matching directive and correct the file that wins. Do not keep adding higher-numbered drop-ins and assume the last filename overrides earlier settings. Reload the service only after `sshd -t` succeeds: ```bash sudo systemctl reload ssh ``` Keep the existing session open and test a new key-based connection. Then explicitly test that password-only authentication is rejected: ```bash ssh -o PreferredAuthentications=password \ -o PubkeyAuthentication=no \ your_user@your_server_ip ``` The connection should be denied rather than presenting a usable password login. **Verify:** a new key-based session succeeds, `sshd -T` reports password and keyboard-interactive authentication disabled, and a password-only test is rejected. ## Step 8 — Disable Root SSH Login After Sudo Access Works First confirm the regular account can run sudo: ```bash sudo whoami ``` The result should be `root`. Add the following to the same early drop-in file: ```bash sudo nano /etc/ssh/sshd_config.d/00-raff-key-auth.conf ``` Add: ```text PermitRootLogin no ``` Validate and reload again: ```bash sudo sshd -t sudo systemctl reload ssh ``` Test the normal administrative account in another terminal before closing the current session. Root-login restrictions and password restrictions should be applied only after the replacement access path is proven. ## Step 9 — Create a Local SSH Config Entry Create or edit the config file on your local computer: ```bash nano ~/.ssh/config ``` Add: ```text Host raff-production HostName your_server_ip User your_user IdentityFile ~/.ssh/raff_ed25519 IdentitiesOnly yes ServerAliveInterval 60 ``` Protect the file: ```bash chmod 600 ~/.ssh/config ``` Connect using the alias: ```bash ssh raff-production ``` `IdentitiesOnly yes` is useful when your agent contains several keys because it tells the client to use the configured identity rather than offering many unrelated keys. ## Step 10 — Add a Second Administrator Without Sharing Keys Each person should generate and control their own private key. Add only their public key to the appropriate server account. For a separate Linux account: ```bash sudo adduser secondadmin sudo usermod -aG sudo secondadmin sudo install -d -m 700 -o secondadmin -g secondadmin /home/secondadmin/.ssh ``` Add the person's public key to: ```text /home/secondadmin/.ssh/authorized_keys ``` Then set ownership and permissions: ```bash sudo chown secondadmin:secondadmin /home/secondadmin/.ssh/authorized_keys sudo chmod 600 /home/secondadmin/.ssh/authorized_keys ``` Separate accounts and keys make access review, revocation, and log attribution clearer. ## Step 11 — Rotate or Revoke an SSH Key List authorized keys with line numbers: ```bash nl -ba ~/.ssh/authorized_keys ``` Before removing an old key, add and test the replacement key in a separate session. Then edit the file: ```bash nano ~/.ssh/authorized_keys ``` Delete only the line belonging to the key being revoked. You can identify a public key's fingerprint by saving the line to a temporary file or by checking the original `.pub` file: ```bash ssh-keygen -lf ~/.ssh/raff_ed25519.pub ``` If a private key is lost or suspected to be copied, remove its public key from every server that trusts it. Changing the key's local passphrase does not revoke a copy that may already exist elsewhere. ## Step 12 — Troubleshoot Common SSH Key Problems ### The server still asks for a password Check the local key being offered: ```bash ssh -vv -i ~/.ssh/raff_ed25519 your_user@your_server_ip ``` Check server-side permissions: ```bash namei -l ~/.ssh/authorized_keys ``` The home directory must not be writable by unrelated users, `.ssh` should normally be `700`, and `authorized_keys` should normally be `600`. ### Too many authentication failures Specify the key and prevent the client from offering unrelated agent identities: ```bash ssh -o IdentitiesOnly=yes \ -i ~/.ssh/raff_ed25519 \ your_user@your_server_ip ``` ### OpenSSH ignores a configuration change Validate syntax and inspect effective settings: ```bash sudo sshd -t sudo sshd -T | grep -E '^(permitrootlogin|pubkeyauthentication|passwordauthentication|kbdinteractiveauthentication) ' ``` Review all drop-ins: ```bash sudo grep -RniE '^(PermitRootLogin|PubkeyAuthentication|PasswordAuthentication|KbdInteractiveAuthentication)' \ /etc/ssh/sshd_config /etc/ssh/sshd_config.d ``` ### You lose normal SSH access Use the Raff browser console to inspect SSH configuration, restore an authorized public key, or correct firewall rules. Keep a tested recovery method available before making remote-access changes. ## Conclusion You now have an Ed25519 SSH key, verified public-key authentication, optional agent and client configuration, disabled password access, and a safe process for adding, rotating, and revoking administrator keys. Continue with [How to Set Up UFW Firewall on Ubuntu 24.04](/learn/tutorials/set-up-ufw-firewall-ubuntu-24-04) and [How to Harden an Ubuntu 24.04 Server](/learn/tutorials/secure-ubuntu-24-04-server) to complete the initial security baseline. SSH key access is included with Raff Linux VMs. Check the [Raff pricing page](/pricing) for the current VM sizes and billing terms instead of relying on a hard-coded tutorial price. ## Sources - [Ubuntu 24.04 sshd_config manual](https://manpages.ubuntu.com/manpages/noble/man5/sshd_config.5.html) - [Ubuntu 24.04 ssh-keygen manual](https://manpages.ubuntu.com/manpages/noble/man1/ssh-keygen.1.html) --- ### How to Set Up an SFTP-Only User on Ubuntu 24.04 with Chroot URL: https://rafftechnologies.com/learn/tutorials/set-up-sftp-only-user-ubuntu-24-04 Description: Set up an SFTP-only user on Ubuntu 24.04 with OpenSSH chroot, internal-sftp, safe directory permissions, forwarding restrictions, and verification. An SFTP-only account on Ubuntu 24.04 lets a user transfer files over SSH without giving that account an interactive shell or unrestricted access to the server filesystem. The safest baseline is to use OpenSSH's built-in `internal-sftp`, place the user inside a root-owned chroot, give them a writable subdirectory inside that jail, and disable every SSH forwarding feature that the account does not need. This tutorial uses a group-based OpenSSH configuration so you can add more restricted users later without duplicating per-user `Match` blocks. It also fixes several common mistakes in older SFTP guides: assuming a writable chroot root is allowed, editing only the main `sshd_config`, leaving a `Match` block open inside `sshd_config.d`, restarting the wrong daemon blindly, and checking syntax without verifying the effective configuration that actually applies to the restricted user. Ubuntu's current OpenSSH documentation recommends modular files in `/etc/ssh/sshd_config.d/`, running `sshd -t` before a restart, and restarting `ssh.service` after normal server configuration changes. OpenSSH also requires every component of `ChrootDirectory` to be root-owned and not writable by other users or groups. `internal-sftp` is useful here because it runs inside `sshd` and does not require copying a shell, libraries, or device nodes into the jail. Raff Technologies is the Ubuntu VM platform used by the original tutorial. The original setup was tested on Ubuntu 24.04 LTS on a [Raff Linux VM](/products/linux-vm) with 2 vCPU / 4 GB RAM; the OpenSSH configuration and Ubuntu service guidance were re-verified on September 4, 2026. Prerequisites: - A Raff Linux VM running Ubuntu 24.04 - SSH access with a non-root sudo user - A second SSH session available while you change `sshd` settings - Port `22/tcp` or your existing SSH port allowed by the firewall - A test username that is not your current administrator account The examples use the restricted account `sftpclient` and group `sftponly`. ## Step 1 — Verify OpenSSH and keep your current admin session open Check that the OpenSSH server package is installed: ```bash dpkg -s openssh-server | grep -E '^(Status|Version):' ``` If it is not installed: ```bash sudo apt update sudo apt install -y openssh-server ``` Check the service: ```bash sudo systemctl is-active ssh.service ``` Check the server binary version: ```bash /usr/sbin/sshd -V 2>&1 | head -1 ``` Before changing anything, keep your current working SSH session open and, if possible, open a second administrator session. Do not test new SFTP rules by modifying the account you are currently using to administer the VM. Ubuntu's current OpenSSH server documentation warns that a bad SSH configuration can lock you out and recommends validating the configuration before restarting the service. **Verify:** `openssh-server` should be installed, `ssh.service` should be active, and you should still have a working administrator session that is not the SFTP test account. ## Step 2 — Back up the SSH configuration before editing it Create a timestamped backup of the main configuration and the current snippet directory: ```bash sudo cp -a /etc/ssh/sshd_config \ "/etc/ssh/sshd_config.backup.$(date +%Y%m%d-%H%M%S)" sudo cp -a /etc/ssh/sshd_config.d \ "/etc/ssh/sshd_config.d.backup.$(date +%Y%m%d-%H%M%S)" ``` Ubuntu includes this line near the top of its default server configuration: ```text Include /etc/ssh/sshd_config.d/*.conf ``` That means drop-in files are the preferred place for a small custom policy such as an SFTP-only group. Ubuntu also documents that OpenSSH generally uses the first value it obtains for most directives, which makes snippet ordering and Match scope worth checking rather than assuming. **Verify:** ```bash ls -ld /etc/ssh/sshd_config.backup.* /etc/ssh/sshd_config.d.backup.* | tail ``` A backup of both the main file and snippet directory should exist before you continue. ## Step 3 — Create the SFTP-only group and user Create the group: ```bash sudo groupadd --force sftponly ``` Create the restricted test user if it does not already exist: ```bash sudo useradd -m -s /bin/bash -G sftponly sftpclient ``` Set a password for the initial test: ```bash sudo passwd sftpclient ``` This tutorial does **not** rely on `/usr/sbin/nologin` to enforce SFTP-only behavior. The OpenSSH `Match Group` block will force `internal-sftp`, disable forwarding, and disable TTY allocation. This avoids mixing shell-policy behavior with SFTP subsystem testing and makes the actual SSH restriction explicit and testable. If the account already exists, add it to the group without removing its other memberships: ```bash sudo usermod -aG sftponly sftpclient ``` **Verify:** ```bash id sftpclient getent passwd sftpclient ``` The output should show membership in `sftponly`. Do not continue if you accidentally added your current administrator account to this group. ## Step 4 — Create a root-owned chroot with a writable upload directory OpenSSH checks `ChrootDirectory` ownership unconditionally. Every component of the chroot path must be root-owned and must not be writable by another user or group. Use the user's home directory as the jail root: ```bash sudo chown root:root /home/sftpclient sudo chmod 755 /home/sftpclient ``` Create a writable directory inside the jail: ```bash sudo mkdir -p /home/sftpclient/uploads sudo chown sftpclient:sftpclient /home/sftpclient/uploads sudo chmod 750 /home/sftpclient/uploads ``` The resulting model is: ```text /home/sftpclient root:root 755 <- chroot root /home/sftpclient/uploads sftpclient:* 750 <- writable area ``` Do not make `/home/sftpclient` user-writable and do not use `chmod 777`. OpenSSH's Ubuntu 24.04 man page states that all path components used for `ChrootDirectory` must be root-owned and not writable by any other user or group. **Verify:** ```bash namei -l /home/sftpclient stat -c '%U:%G %a %n' /home/sftpclient /home/sftpclient/uploads ``` The chroot root should be `root:root` and not group/other writable; the `uploads` directory should be writable by `sftpclient`. ## Step 5 — Create an isolated OpenSSH Match Group policy Create a dedicated snippet: ```bash sudo tee /etc/ssh/sshd_config.d/60-sftp-only.conf > /dev/null <<'EOF' Match Group sftponly ChrootDirectory %h ForceCommand internal-sftp -d /uploads DisableForwarding yes PermitTTY no PermitUserRC no Match all EOF ``` The important directives are: - `ChrootDirectory %h` — makes the user's real home directory the jail root; - `ForceCommand internal-sftp -d /uploads` — forces the in-process SFTP server and starts the user in the writable `/uploads` directory inside the jail; - `DisableForwarding yes` — disables TCP, agent, X11, and StreamLocal forwarding in one directive; - `PermitTTY no` — prevents TTY allocation; - `PermitUserRC no` — prevents execution of user SSH rc files; - `Match all` — ends the restricted Match scope before parsing continues. That final `Match all` is especially important in a drop-in file. Ubuntu loads `/etc/ssh/sshd_config.d/*.conf` from the main configuration, and a `Match` context continues until another `Match` directive or end of the full configuration stream. Ending the snippet with `Match all` prevents later global settings from accidentally remaining inside the `sftponly` Match context. You do not need to replace Ubuntu's global `Subsystem sftp ...` line for this design. `ForceCommand internal-sftp` directly forces the in-process SFTP server for matching users. **Verify:** ```bash sudo cat /etc/ssh/sshd_config.d/60-sftp-only.conf ``` The file should contain exactly one `Match Group sftponly` block followed by `Match all`. ## Step 6 — Validate both syntax and the effective Match configuration First run OpenSSH's syntax test: ```bash sudo sshd -t ``` No output means the syntax and host-key checks passed. Then inspect the effective configuration for `sftpclient`. `sshd -T` prints the resulting configuration, while `-C` applies Match rules for a simulated connection: ```bash sudo sshd -T \ -C user=sftpclient,host=localhost,addr=127.0.0.1,laddr=127.0.0.1,lport=22 \ | grep -E '^(chrootdirectory|forcecommand|disableforwarding|permittty|permituserrc) ' ``` Expected values include: ```text chrootdirectory %h forcecommand internal-sftp -d /uploads disableforwarding yes permittty no permituserrc no ``` This check is stronger than syntax validation alone because it proves that the `Match Group` policy actually applies to the account you intend to restrict. **Verify:** `sshd -t` should produce no error and `sshd -T -C ...` should show the SFTP-only settings above for `sftpclient`. ## Step 7 — Restart OpenSSH safely and verify administrator access first Ubuntu's current OpenSSH server documentation recommends applying normal `sshd` configuration changes with: ```bash sudo systemctl restart ssh.service ``` Do that only after `sshd -t` succeeds: ```bash sudo systemctl restart ssh.service ``` Immediately verify the service: ```bash sudo systemctl is-active ssh.service ``` Before closing your original SSH window, open a **new administrator SSH session** and make sure it works. Ubuntu 24.04 can use socket activation in some OpenSSH configurations, which matters particularly when changing listener settings such as `Port` or `ListenAddress`. This tutorial does not change those listener directives. For the Match policy used here, follow Ubuntu's documented `ssh.service` restart path and validate the actual result with a fresh connection. **Verify:** `ssh.service` should be active and a new administrator SSH connection should succeed before you test `sftpclient`. ## Step 8 — Test SFTP login, landing directory, upload, and download From another machine or another local terminal, connect with SFTP: ```bash sftp sftpclient@SERVER_IP ``` After authentication, confirm the working directory: ```text sftp> pwd ``` Because the Match policy uses `internal-sftp -d /uploads`, the user should start in: ```text Remote working directory: /uploads ``` Create a local test file before connecting, or use an existing harmless file. From the SFTP prompt: ```text sftp> put test-upload.txt sftp> ls -la sftp> get test-upload.txt test-download.txt ``` Confirm that the user cannot leave the jail: ```text sftp> cd / sftp> ls ``` The `/` visible to this user is the chroot root, not the real server filesystem root. Paths such as the server's real `/etc` are outside the jail. **Verify:** The user should land in `/uploads`, be able to upload/download there, and remain confined to the chroot filesystem. ## Step 9 — Verify shell commands, TTYs, and forwarding are blocked SFTP success is only half the test. Confirm that the same account cannot obtain a shell command channel: ```bash ssh sftpclient@SERVER_IP 'id' ``` Because `ForceCommand internal-sftp` replaces the requested command, this should not execute `id` as a shell command. Try an interactive SSH session: ```bash ssh sftpclient@SERVER_IP ``` The account should not receive a normal shell prompt. The `DisableForwarding yes` rule also blocks the account from being used for SSH forwarding. For example, a local forwarding request should fail rather than create a tunnel: ```bash ssh -N -L 15432:127.0.0.1:5432 sftpclient@SERVER_IP ``` Do not leave this command running if your client behaves unexpectedly; stop it with `Ctrl+C`. OpenSSH documents that `ForceCommand` alone does not disable other forwarding channels, which is why this tutorial also sets `DisableForwarding yes`. **Verify:** `sftpclient` should transfer files through SFTP but should not receive a shell, execute arbitrary SSH commands, allocate a TTY, or create SSH forwarding channels. ## Step 10 — Restrict network access when the SFTP client has a stable source IP SFTP uses SSH transport, so the network port is the server's SSH port — normally TCP `22` unless you deliberately changed it. If this SFTP account is used only from a known office, VPN, CI runner, or partner IP, firewall restriction adds a useful independent control. For example, with UFW and a stable client address `198.51.100.20`: ```bash sudo ufw allow from 198.51.100.20 to any port 22 proto tcp ``` Do **not** remove your broader administrator SSH rule until you have confirmed how all legitimate administrators connect. A firewall change can lock you out independently of the SFTP configuration. If your VM also uses a cloud-side security group, apply the same source-IP principle there when appropriate. For a complete firewall workflow, use [Set Up UFW Firewall on Ubuntu 24.04](/learn/tutorials/set-up-ufw-firewall-ubuntu-24-04). **Verify:** Review the firewall with `sudo ufw status numbered` and confirm it still permits every required administrator path as well as the intended SFTP client source. ## Step 11 — Monitor SFTP authentication and errors with journalctl Ubuntu's current server documentation uses the `ssh.service` journal for OpenSSH troubleshooting. Follow logs while you test: ```bash sudo journalctl -fu ssh.service ``` Or inspect recent entries: ```bash sudo journalctl -u ssh.service -n 100 --no-pager ``` Useful problems to look for include: - `bad ownership or modes for chroot directory` — a path component is not root-owned or is writable by another user/group; - authentication failures — password/key or account-policy problem; - `Connection closed` immediately after authentication — often a chroot, directory, or Match-policy problem; - missing `/uploads` — the forced start directory does not exist inside the jail. Do not depend on hard-coded `/var/log/auth.log` availability for every Ubuntu logging setup; the systemd journal is the most portable first check on current Ubuntu Server. **Verify:** A successful SFTP connection should appear in the SSH journal without a chroot ownership error or repeated authentication failure. ## Step 12 — Add another SFTP-only user without editing sshd_config again Create another user and add it to the same group: ```bash sudo useradd -m -s /bin/bash -G sftponly client2 sudo passwd client2 ``` Make the new home directory a valid chroot root: ```bash sudo chown root:root /home/client2 sudo chmod 755 /home/client2 ``` Create the writable directory: ```bash sudo mkdir -p /home/client2/uploads sudo chown client2:client2 /home/client2/uploads sudo chmod 750 /home/client2/uploads ``` No OpenSSH configuration edit is necessary because the group Match rule already exists. No service restart is required merely because a new user joined the group. Check that the effective Match configuration applies to the second user as well: ```bash sudo sshd -T \ -C user=client2,host=localhost,addr=127.0.0.1,laddr=127.0.0.1,lport=22 \ | grep -E '^(chrootdirectory|forcecommand|disableforwarding) ' ``` **Verify:** `client2` should inherit the same chroot, forced SFTP command, and forwarding restrictions without another `sshd_config` change. ## Step 13 — Run the final end-to-end SFTP security check Run the final checklist before using the account for real file transfers. On the server: ```bash sudo sshd -t sudo systemctl is-active ssh.service stat -c '%U:%G %a %n' /home/sftpclient /home/sftpclient/uploads sudo sshd -T \ -C user=sftpclient,host=localhost,addr=127.0.0.1,laddr=127.0.0.1,lport=22 \ | grep -E '^(chrootdirectory|forcecommand|disableforwarding|permittty|permituserrc) ' ``` From the client: ```bash sftp sftpclient@SERVER_IP ``` Inside SFTP: ```text pwd put test-upload.txt ls -la ``` In another client terminal: ```bash ssh sftpclient@SERVER_IP 'uname -a' ``` The SFTP operation should work, while the arbitrary SSH command should not run as a shell command. :::cta Deploy Your SFTP Server Launch a Raff Ubuntu VM and use OpenSSH chroot rules to provide restricted SFTP-only file access. ::: **Verify:** The final state is correct only when file transfer works, the user is confined to the jail, the chroot root is not user-writable, arbitrary SSH commands do not execute, forwarding is disabled, and normal administrator SSH access still works. ## Step 14 — Roll back or remove the SFTP-only setup safely To remove only the Match policy, first move the snippet out of the active `.conf` path: ```bash sudo mv /etc/ssh/sshd_config.d/60-sftp-only.conf \ /etc/ssh/60-sftp-only.conf.disabled ``` Validate before restarting: ```bash sudo sshd -t ``` Then apply the change: ```bash sudo systemctl restart ssh.service ``` If the restricted account is no longer needed, remove it only after confirming that uploaded files have been archived or transferred elsewhere: ```bash sudo userdel sftpclient ``` Do not use `userdel -r` until you have deliberately decided to delete `/home/sftpclient` and its uploaded files. If this was a disposable lab and the data is safe to delete: ```bash sudo rm -rf /home/sftpclient ``` Remove the group only when no remaining account depends on it: ```bash getent group sftponly sudo groupdel sftponly ``` **Verify:** `sudo sshd -t` should still pass, administrator SSH should work after the restart, and only the users/data you intentionally removed should be gone. ## Troubleshooting ### `fatal: bad ownership or modes for chroot directory` Inspect every component of the jail path: ```bash namei -l /home/sftpclient ``` `/`, `/home`, and `/home/sftpclient` must satisfy OpenSSH's chroot ownership rules. The jail root should be root-owned and not writable by other users/groups. Only directories inside the jail, such as `/uploads`, should be user-writable. ### SFTP authenticates and then disconnects immediately Run: ```bash sudo journalctl -u ssh.service -n 100 --no-pager ``` Then confirm the forced start directory exists: ```bash ls -ld /home/sftpclient/uploads ``` Also re-check the effective policy: ```bash sudo sshd -T \ -C user=sftpclient,host=localhost,addr=127.0.0.1,laddr=127.0.0.1,lport=22 \ | grep -E '^(chrootdirectory|forcecommand|disableforwarding) ' ``` ### The user can connect by SFTP but cannot upload to `/` That is expected. The chroot root must not be writable by the restricted user. Upload into `/uploads`, which is intentionally owned by `sftpclient`. ### The SFTP user unexpectedly gets a shell Check group membership: ```bash id sftpclient ``` Then check the effective OpenSSH policy with `sshd -T -C`. If the account is not in `sftponly` or the Match rule is not being applied, fix that before allowing the account to remain active. ### `sshd -t` fails after editing the snippet Do not restart OpenSSH. Read the exact syntax error, fix the file, and rerun: ```bash sudo sshd -t ``` Only restart `ssh.service` when the syntax test succeeds. ### SFTP works but SSH port forwarding also works The Match rule is either not applying or `DisableForwarding yes` is missing. Check the effective configuration with `sshd -T -C` and confirm: ```text disableforwarding yes ``` ## Conclusion You now have an SFTP-only OpenSSH account on Ubuntu 24.04 with a root-owned chroot, a writable upload directory, forced `internal-sftp`, forwarding disabled, no TTY allocation, explicit Match-scope termination, effective-configuration testing, service logs, end-to-end validation, and a rollback path. The two details that prevent most SFTP chroot failures are straightforward: keep the chroot root owned by root and non-writable by the restricted user, and verify the **effective** OpenSSH Match configuration instead of assuming a syntactically valid file is applying the rules you intended. For key-based administrator access, see [Configure SSH Keys on Ubuntu](/learn/tutorials/configure-ssh-keys-ubuntu). For host firewall policy, use [Set Up UFW Firewall on Ubuntu 24.04](/learn/tutorials/set-up-ufw-firewall-ubuntu-24-04). For broader host protection, continue with [Secure Ubuntu 24.04 Server](/learn/tutorials/secure-ubuntu-24-04-server). ## Sources - [Ubuntu Server — OpenSSH server](https://ubuntu.com/server/docs/how-to/security/openssh-server/) - [Ubuntu 24.04 sshd_config(5)](https://manpages.ubuntu.com/manpages/noble/man5/sshd_config.5.html) - [Ubuntu 24.04 sshd(8)](https://manpages.ubuntu.com/manpages/noble/man8/sshd.8.html) - [Ubuntu 24.04 sftp(1)](https://manpages.ubuntu.com/manpages/noble/man1/sftp.1.html) - OpenSSH guidance verified: 2026-09-04 --- ### How to Install MariaDB on Ubuntu 24.04 URL: https://rafftechnologies.com/learn/tutorials/install-mariadb-ubuntu-24-04 Description: Install MariaDB 10.11 on Ubuntu 24.04, secure local access and port 3306, create an app user, test backup and restore, and handle updates safely. To install MariaDB on Ubuntu 24.04, use Ubuntu's distro-managed MariaDB 10.11 package path: ```bash sudo apt update sudo apt install -y mariadb-server mariadb-client sudo systemctl enable --now mariadb sudo mariadb-secure-installation sudo mariadb -NBe 'SELECT VERSION();' ``` Ubuntu 24.04 Noble currently provides **MariaDB 10.11.14** through `noble-updates`. Upstream MariaDB has newer releases, including **12.3.3 LTS**, but moving from Ubuntu's 10.11 packages to a newer upstream major version is a migration decision, not a routine package update. [Raff Linux VMs](/products/linux-vm) can run self-hosted MariaDB when you need host-level control. The original workflow was tested on a Raff VM with **2 vCPU and 4 GB RAM**. This refresh re-verifies the current package, authentication, network, TLS, backup, and restore guidance without claiming a new full machine test. MariaDB and MySQL share protocol history, but they are separate database systems with different release cycles and upgrade rules. Treat a MySQL-to-MariaDB move as a database migration rather than a package rename. :::cluster ## Step 1 — Verify Ubuntu 24.04 and the MariaDB package Confirm the operating system and architecture: ```bash cat /etc/os-release uname -m ``` Refresh package metadata: ```bash sudo apt update ``` Inspect the MariaDB candidate: ```bash apt-cache policy mariadb-server mariadb-server-10.11 ``` Ubuntu 24.04 currently tracks MariaDB 10.11. The `noble-updates` package is 10.11.14 at this revision. Check resource and disk headroom: ```bash nproc free -h df -h / ``` Do not choose a production VM size from database size alone. MariaDB memory and I/O demand depends on the active working set, buffer pool, connection count, temporary tables, query shape, writes, and other services on the VM. **Verify:** Ubuntu reports 24.04, APT exposes a MariaDB 10.11 candidate from Ubuntu repositories, and the VM has enough free disk for live data plus backup growth. ## Step 2 — Install MariaDB Server and client tools Install the server, client, OpenSSL, and UFW: ```bash sudo apt install -y mariadb-server mariadb-client openssl ufw ``` Make sure the service is enabled and running: ```bash sudo systemctl enable --now mariadb ``` Verify the client and server versions: ```bash mariadb --version sudo mariadb -NBe 'SELECT VERSION();' ``` Confirm Ubuntu still owns the package path: ```bash apt-cache policy mariadb-server ``` Do not add MariaDB's upstream repository as an incidental update step. A move from Ubuntu's 10.11 packages to another repository or major version needs a tested migration plan. **Verify:** the package installs successfully, MariaDB is running, `SELECT VERSION()` returns 10.11.x, and APT identifies Ubuntu as the package source. ## Step 3 — Verify the service and port 3306 Check the service: ```bash systemctl is-active mariadb systemctl is-enabled mariadb sudo systemctl status mariadb --no-pager ``` Verify the local server through its Unix socket: ```bash sudo mariadb-admin ping ``` Expected output: ```text mysqld is alive ``` Inspect TCP listeners: ```bash sudo ss -lntp | grep ':3306' || true ``` Read the runtime bind address and port: ```bash sudo mariadb -NBe 'SELECT @@bind_address, @@port;' ``` **Verify:** MariaDB is active and enabled, `mariadb-admin ping` succeeds, and there is no unintended public listener on TCP 3306. ## Step 4 — Verify local root administration Open the local administrative client: ```bash sudo mariadb ``` Inspect the actual root account definition instead of assuming its authentication plugin: ```sql SHOW CREATE USER 'root'@'localhost'; SELECT User, Host FROM mysql.user WHERE User = 'root'; ``` MariaDB commonly uses `unix_socket` authentication for local root administration on Linux. Keep root restricted to localhost and use separate database accounts for applications. Exit: ```sql EXIT; ``` **Verify:** `sudo mariadb` works, the root account remains local-only, and no remote root account is needed by the application. ## Step 5 — Run mariadb-secure-installation Use MariaDB's current hardening command: ```bash sudo mariadb-secure-installation ``` The old MySQL-style command name may not exist. If `mysql_secure_installation` returns `command not found`, use `mariadb-secure-installation` on this MariaDB installation. Focus on the final state rather than memorizing prompt answers: - preserve local root administration; - remove anonymous users; - prevent remote root access; - remove the `test` database; - reload privileges when prompted. Verify the result directly: ```bash sudo mariadb -NBe \ "SELECT User, Host FROM mysql.user WHERE User = '';" sudo mariadb -NBe \ "SELECT User, Host FROM mysql.user WHERE User = 'root';" sudo mariadb -NBe \ "SELECT SCHEMA_NAME FROM information_schema.SCHEMATA WHERE SCHEMA_NAME = 'test';" ``` The anonymous-user and test-database queries should return no rows. **Verify:** anonymous accounts and the test database are absent, and every root account is local-only. ## Step 6 — Create an application database and user Generate an application password without putting a fixed password in the tutorial: ```bash DB_PASSWORD="$(openssl rand -hex 32)" printf 'Store this MariaDB password securely: %s\n' "$DB_PASSWORD" ``` Store the value in a secrets manager, then create the database and local account: ```bash sudo mariadb </dev/null <<'EOF' [mariadb] bind-address = 127.0.0.1,10.0.0.5 EOF ``` For production TLS, use a CA and server certificate your clients can validate. Store them at controlled paths such as: ```text /etc/mysql/tls/ca-cert.pem /etc/mysql/tls/server-cert.pem /etc/mysql/tls/server-key.pem ``` Protect the files: ```bash sudo chown -R root:mysql /etc/mysql/tls sudo chmod 750 /etc/mysql/tls sudo chmod 640 /etc/mysql/tls/server-key.pem sudo chmod 644 /etc/mysql/tls/ca-cert.pem /etc/mysql/tls/server-cert.pem ``` Add TLS configuration: ```bash sudo tee -a /etc/mysql/mariadb.conf.d/z-raff-private.cnf >/dev/null <<'EOF' ssl_ca = /etc/mysql/tls/ca-cert.pem ssl_cert = /etc/mysql/tls/server-cert.pem ssl_key = /etc/mysql/tls/server-key.pem require_secure_transport = ON EOF ``` Inspect effective startup options, then restart: ```bash mariadbd --print-defaults mariadbd --help --verbose >/dev/null sudo systemctl restart mariadb systemctl is-active mariadb ``` Verify TLS is active: ```bash sudo mariadb -e "SHOW GLOBAL VARIABLES LIKE 'have_ssl';" sudo mariadb -e "SHOW GLOBAL VARIABLES LIKE 'require_secure_transport';" ``` Create a remote account restricted to the application's exact private IP: ```bash REMOTE_DB_PASSWORD="$(openssl rand -hex 32)" printf 'Store this remote MariaDB password securely: %s\n' "$REMOTE_DB_PASSWORD" sudo mariadb < /dev/null sudo chmod 600 "$BACKUP_FILE" sudo gzip -t "$BACKUP_FILE" ) # Continue only if the block above exits successfully. ``` Restrict and validate the backup: ```bash sudo chmod 600 "$BACKUP_FILE" sudo gzip -t "$BACKUP_FILE" sudo zcat "$BACKUP_FILE" | head ``` `--single-transaction` provides a consistent snapshot for transactional tables such as InnoDB. It does not make concurrently written non-transactional tables consistent. Keep at least one production backup outside the database VM. Raff [Object Storage](/products/object-storage) can be used by S3-compatible backup tooling, while [Data Protection](/products/data-protection) provides an additional VM-level recovery layer. **Verify:** the dump exists with restrictive permissions, `gzip -t` succeeds, and your production recovery plan includes an off-server copy. ## Step 11 — Restore into a disposable database Never prove a backup by overwriting production. Create an isolated restore target: ```bash sudo mariadb -e \ "CREATE DATABASE raffapp_restore_test CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;" ``` Select the newest backup: ```bash LATEST_BACKUP="$(sudo find /var/backups/mariadb -maxdepth 1 -type f -name 'raffapp-*.sql.gz' -print | LC_ALL=C sort | tail -n 1)" # Stop here if no readable backup was selected. if [ -z "$LATEST_BACKUP" ] || ! sudo test -s "$LATEST_BACKUP"; then printf '%s\n' 'No non-empty backup found. Do not continue with restore.' >&2 false fi echo "$LATEST_BACKUP" ``` Restore it directly into the disposable database: ```bash ( set -o pipefail; sudo zcat "$LATEST_BACKUP" | sudo mariadb raffapp_restore_test ) ``` Inspect the restored tables: ```bash sudo mariadb -e \ "SHOW TABLES FROM raffapp_restore_test; SELECT name, status FROM raffapp_restore_test.tutorial_check WHERE name='mariadb-restore-marker';" ``` The restore must contain `mariadb-restore-marker` with status `verified`. An empty table listing is not a successful recovery test. For production recovery rehearsals, also validate representative row counts and application-level records. Remove only the disposable target after verification: ```bash sudo mariadb -e 'DROP DATABASE raffapp_restore_test;' ``` **Verify:** expected tables and data exist in `raffapp_restore_test`, production `raffapp` remains untouched, and the test target can be removed cleanly. ## Step 12 — Apply Ubuntu MariaDB updates safely Check for pending packages: ```bash apt list --upgradable 2>/dev/null | grep -E '^mariadb|^galera' || true ``` Before updating: 1. create a fresh logical backup; 2. confirm an off-server copy exists; 3. review the Ubuntu package changelog and MariaDB release notes; 4. check free disk space; 5. choose an appropriate maintenance window. Apply normal distro updates: ```bash sudo apt update sudo apt upgrade ``` Verify afterward: ```bash systemctl is-active mariadb sudo mariadb -NBe 'SELECT VERSION();' sudo mariadb-admin ping sudo journalctl -u mariadb --no-pager -n 100 ``` For normal Ubuntu package maintenance, remain on the distro-managed 10.11 branch. Do not turn a patch cycle into an upstream repository migration accidentally. **Verify:** MariaDB starts cleanly, remains on the expected Ubuntu 10.11 package path, and passes the application login and CRUD checks after updating. ## Step 13 — Treat MariaDB 12.3 LTS as a major-version migration MariaDB upstream currently lists **12.3.3** as the latest 12.3 LTS maintenance release. The upstream 10.11 series is also newer than Ubuntu's current Noble package, but Ubuntu 24.04 intentionally follows its own package lifecycle. Before moving from Ubuntu's 10.11 packages to a newer upstream LTS: - read the target-version upgrade notes; - inventory storage engines and plugins; - test application queries and connectors; - restore a current production backup in staging; - review changed or removed configuration options; - plan the repository transition; - plan `mariadb-upgrade` where required; - define rollback as restore onto the previous known-good version. Check whether `mariadb-upgrade` sees a requirement: ```bash sudo mariadb-upgrade --check-if-upgrade-is-needed; echo $? ``` Do not perform the major upgrade on the only production copy. **Verify:** a major-version move has a staging rehearsal, a verified backup, application compatibility checks, and a restore-based rollback plan before repositories or binaries change. ## Step 14 — Verify MariaDB end to end Run the final service, account, network, TLS, and recovery checks: ```bash echo 'Service:' systemctl is-active mariadb systemctl is-enabled mariadb echo 'Version:' sudo mariadb -NBe 'SELECT VERSION();' echo 'Root accounts:' sudo mariadb -NBe \ "SELECT User, Host FROM mysql.user WHERE User='root';" echo 'Application accounts:' sudo mariadb -NBe \ "SELECT User, Host FROM mysql.user WHERE User='raffappuser';" echo 'Listener:' sudo ss -lntp | grep ':3306' || true echo 'TLS:' sudo mariadb -NBe \ "SHOW GLOBAL VARIABLES LIKE 'have_ssl'; SHOW GLOBAL VARIABLES LIKE 'require_secure_transport';" echo 'Firewall:' sudo ufw status numbered echo 'Recent backups:' sudo find /var/backups/mariadb -maxdepth 1 -type f -name 'raffapp-*.sql.gz' -ls ``` Confirm all of these are true: - Ubuntu 24.04 manages the expected MariaDB 10.11 package branch; - the service is active and enabled; - root administration is local-only; - anonymous users and the test database are gone; - the application uses a separate database-scoped account; - TCP 3306 is not publicly exposed; - optional remote access is private, source-restricted, and encrypted; - a logical backup exists off-server; - a restore has succeeded in an isolated target; - routine patching stays on the Ubuntu package path; - a future major upgrade has a tested migration and rollback plan. **Verify:** the installation passes every check above, including the CRUD test from Step 7 and isolated restore from Step 11. :::cta Deploy Your Server Run MariaDB on a Raff VM. ::: ## Cleanup (optional) Use this section only when the database, users, firewall rules, TLS override, and backup files were created solely for this tutorial. > **Warning:** These commands can permanently delete tutorial data and credentials. Drop the tutorial database and users: ```bash sudo mariadb <<'SQL' DROP DATABASE IF EXISTS raffapp; DROP USER IF EXISTS 'raffappuser'@'localhost'; DROP USER IF EXISTS 'raffappuser'@'10.0.0.10'; SQL ``` Remove the tutorial private-network override only if you created it for this guide: ```bash sudo rm -f /etc/mysql/mariadb.conf.d/z-raff-private.cnf sudo systemctl restart mariadb ``` Delete only the UFW rules added by this tutorial: ```bash sudo ufw delete allow from 10.0.0.10 to 10.0.0.5 port 3306 proto tcp sudo ufw delete deny 3306/tcp ``` **Warning:** The next commands permanently delete all backups matching these tutorial filenames. Keep an off-server copy of anything you need. Run them only in a disposable tutorial environment: ```bash sudo find /var/backups/mariadb -maxdepth 1 -type f -name 'raffapp-*.sql.gz' -print -delete ``` Verify the database and users are gone: ```bash sudo mariadb -NBe \ "SELECT SCHEMA_NAME FROM information_schema.SCHEMATA WHERE SCHEMA_NAME='raffapp';" sudo mariadb -NBe \ "SELECT User, Host FROM mysql.user WHERE User='raffappuser';" ``` Both queries should return no rows. ## Troubleshooting ### `mysql.service` is not found MariaDB's systemd service is normally named `mariadb`, not `mysql`. Check the correct unit: ```bash systemctl status mariadb --no-pager ``` If it does not exist, verify the server package is installed: ```bash dpkg -l | grep -E '^ii\s+mariadb-server' apt-cache policy mariadb-server ``` Install it if necessary: ```bash sudo apt update sudo apt install -y mariadb-server ``` ### `mysql_secure_installation`: command not found Use MariaDB's current command: ```bash sudo mariadb-secure-installation ``` Verify it exists: ```bash command -v mariadb-secure-installation ``` ### `mariadb` client command is missing Install only the client when you do not need a local database server: ```bash sudo apt update sudo apt install -y mariadb-client mariadb --version ``` ### `sudo mariadb` returns access denied Inspect service health and the error log before attempting a root-account reset: ```bash systemctl is-active mariadb sudo journalctl -u mariadb --no-pager -n 100 sudo tail -n 100 /var/log/mysql/error.log ``` Confirm you are following MariaDB 10.11 guidance rather than a MySQL-specific recovery procedure. ### MariaDB does not start after a configuration change Inspect effective options and logs: ```bash mariadbd --print-defaults mariadbd --help --verbose >/dev/null sudo journalctl -u mariadb --no-pager -n 100 sudo tail -n 100 /var/log/mysql/error.log ``` If the failure followed `z-raff-private.cnf`, move that file out of the configuration directory and restart from the prior known-good state. ### A private remote connection times out Check all four layers: ```bash sudo mariadb -NBe 'SELECT @@bind_address, @@port;' sudo ss -lntp | grep ':3306' sudo ufw status numbered sudo mariadb -NBe \ "SELECT User, Host FROM mysql.user WHERE User='raffappuser';" ``` The client source address must match the listener, firewall rule, and MariaDB account host. ### TLS is configured but have_ssl is DISABLED Check certificate paths, permissions, and the error log: ```bash sudo ls -l /etc/mysql/tls sudo journalctl -u mariadb --no-pager -n 100 sudo tail -n 100 /var/log/mysql/error.log ``` Do not create a production remote path that depends on TLS until `have_ssl` reports `YES`. ### The backup command returns permission denied `/var/backups/mariadb` is root-owned in this tutorial. Use the `sudo tee` pipeline from Step 10 rather than normal shell redirection into that directory. ## FAQ ### How do I install MariaDB on Ubuntu 24.04? Run `sudo apt update` and `sudo apt install -y mariadb-server mariadb-client`, then enable the service and verify the server version. ### What MariaDB version does Ubuntu 24.04 install? Ubuntu 24.04 currently uses the MariaDB 10.11 branch. Noble-updates provides MariaDB 10.11.14 at this revision. ### Is MariaDB 10.11 still supported? Yes. MariaDB 10.11 remains a maintained long-term series, while Ubuntu 24.04 also maintains its own distro package lifecycle. ### Why does sudo mariadb work without a root password? MariaDB commonly uses local `unix_socket` authentication on Linux. Verify the actual root account definition with `SHOW CREATE USER` instead of assuming the plugin. ### Should MariaDB port 3306 be public? No. Keep it local for same-VM applications. For a separate app VM, use private networking, an exact source rule, and verified TLS. ### How do I install only the MariaDB client on Ubuntu? Run `sudo apt install -y mariadb-client`. This installs the command-line client without requiring a local MariaDB server. ### Is mariadb-dump enough for production recovery? It can be one layer. Production recovery also needs off-server copies, retention, restore testing, monitoring, and workload-specific RPO and RTO targets. ## Conclusion You now have MariaDB 10.11 running on Ubuntu 24.04 with local administration, a dedicated application account, verified CRUD, private-by-default networking, logical backups, and an isolated restore test. The important package distinction is clear: Ubuntu 24.04 currently provides MariaDB **10.11.14**, while upstream MariaDB has newer 10.11 maintenance releases and the newer **12.3 LTS** line. Keep routine distro patching separate from a deliberate major-version migration. For related production decisions, continue with [MySQL vs MariaDB for Production Apps](/learn/guides/mysql-vs-mariadb-production-apps), [Install MySQL on Ubuntu 24.04](/learn/tutorials/install-mysql-ubuntu-24-04), and [Set Up UFW Firewall on Ubuntu 24.04](/learn/tutorials/set-up-ufw-firewall-ubuntu-24-04). ## Sources - [Ubuntu 24.04 Noble updates: mariadb-server](https://packages.ubuntu.com/noble-updates/mariadb-server) - [MariaDB: 10.11 changes and improvements](https://mariadb.com/docs/release-notes/community-server/mariadb-10-11-series/what-is-mariadb-1011) - [MariaDB: mariadb-secure-installation](https://mariadb.com/docs/server/clients-and-utilities/deployment-tools/mariadb-secure-installation) - [MariaDB: unix_socket authentication](https://mariadb.com/docs/server/reference/plugins/authentication-plugins/authentication-plugin-unix-socket) - [MariaDB: remote client access](https://mariadb.com/docs/server/mariadb-quickstart-guides/mariadb-remote-connection-guide) - [MariaDB: enabling TLS](https://mariadb.com/docs/server/security/securing-mariadb/securing-mariadb-encryption/data-in-transit-encryption/data-in-transit-encryption-enabling-tls-on-mariadb-server) - [MariaDB Foundation: current releases](https://mariadb.org/mariadb/all-releases/) - Package and technical guidance re-verified: 2026-09-17 --- ### How to Use Raff S3-Compatible Object Storage with AWS CLI URL: https://rafftechnologies.com/learn/tutorials/raff-s3-object-storage-aws-cli Description: Use AWS CLI with Raff S3-compatible object storage on Ubuntu 24.04. Configure scoped credentials, transfer files, sync safely, and create presigned URLs. Raff Object Storage exposes an S3-compatible API, so you can use the AWS CLI for bucket operations, uploads, downloads, directory syncs, and presigned URLs by pointing commands at `https://s3.raffusercloud.com`. In this tutorial, you will configure a dedicated AWS CLI profile, use a bucket-scoped access key where possible, create and verify a bucket, transfer files, test a safe sync workflow, create a temporary download URL, and clean up test objects without exposing credentials. This tutorial targets Raff's current Object Storage feature set. Standard object operations, multipart uploads, presigned URLs, bucket policies and ACLs, and SigV4 authentication are supported. Versioning, lifecycle rules, Object Lock, cross-region replication, and static website hosting are not currently supported, so this guide does not depend on those features. See [Raff Object Storage](/products/object-storage) for the current compatibility and pricing matrix. AWS documents `--endpoint-url` as the option for overriding a service endpoint, and its current `aws s3` commands include `cp`, `ls`, `mb`, `rm`, `rb`, `sync`, and `presign`. AWS CLI v2 also requires an explicit signing region for presigned URLs. This tutorial uses the existing Raff-compatible signing value `us-east-1` and the Raff endpoint on every S3 command. ## Step 1 — Install and Verify AWS CLI v2 On Ubuntu 24.04, install the utilities needed for the official AWS CLI v2 installer: ```bash sudo apt update sudo apt install -y curl unzip ``` Download and install the current AWS CLI v2 package for x86_64 Linux: ```bash curl -fsSLo awscliv2.zip \ https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip unzip -q awscliv2.zip sudo ./aws/install rm -rf aws awscliv2.zip ``` If your VM uses ARM64, use AWS's ARM64 package instead of the x86_64 archive. AWS also provides a current install script and Snap package; follow the [official AWS CLI installation documentation](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html) if you need another architecture or update method. **Verify:** ```bash aws --version ``` The command should report AWS CLI `2.x` and exit without an error. ## Step 2 — Create a Scoped Raff Object Storage Access Key Open the Raff dashboard and go to **Object Storage**. Create or select the bucket you want this CLI profile to access, then create an access key with the narrowest permissions your workflow needs. For an upload/download workflow, prefer a key limited to the intended bucket with read-write access instead of sharing a full-access key across multiple applications. Raff currently supports bucket-scoped read and read-write grants for access keys. For the broader permission model, review [S3 Bucket Security: Credentials, Policies, and Private Access](/learn/guides/s3-bucket-security) before assigning a key to production automation. Record the access key ID and secret access key in a password manager when the secret is shown. Do not paste the secret into Git, source code, screenshots, shell scripts, tickets, or chat messages. **Verify:** You should have the endpoint `https://s3.raffusercloud.com`, an access key ID, a secret access key, and the name of the bucket or permission to create one. ## Step 3 — Configure a Dedicated AWS CLI Profile Set a restrictive shell umask before creating the credential files: ```bash umask 077 aws configure --profile raff ``` Enter: ```text AWS Access Key ID: YOUR_RAFF_ACCESS_KEY AWS Secret Access Key: YOUR_RAFF_SECRET_KEY Default region name: us-east-1 Default output format: json ``` AWS CLI stores profile credentials under `~/.aws/credentials` and non-secret profile settings under `~/.aws/config`. These files contain sensitive material and should only be readable by your user. Enforce restrictive permissions: ```bash chmod 700 ~/.aws chmod 600 ~/.aws/credentials ~/.aws/config ``` Do not print the credential file contents as a verification step. Instead, check the profile exists: ```bash aws configure list --profile raff ``` **Verify:** The profile should show a configured access key source and `us-east-1` region without displaying the full secret key. ## Step 4 — Test Authentication Against the Raff S3 Endpoint List buckets using Raff's custom endpoint: ```bash aws s3 ls \ --endpoint-url https://s3.raffusercloud.com \ --profile raff \ --region us-east-1 ``` If the scoped key can only access a specific bucket, a global bucket listing may be restricted. In that case, test the intended bucket directly: ```bash aws s3 ls s3://YOUR_BUCKET_NAME/ \ --endpoint-url https://s3.raffusercloud.com \ --profile raff \ --region us-east-1 ``` An empty bucket can produce no object lines while still returning successfully. **Verify:** The command should complete without an authentication or signature error. A permission-denied response is only acceptable when the key is intentionally scoped away from the attempted operation. ## Step 5 — Create a Bucket When Your Key Allows It Skip this step if you already have a bucket or your key is intentionally limited to an existing bucket. Choose a bucket name using lowercase letters, numbers, and hyphens. Avoid sensitive information in bucket names and avoid periods for better compatibility with HTTPS virtual-hosted addressing. Create the bucket: ```bash BUCKET="my-project-files-$(date +%Y%m%d)" aws s3 mb "s3://$BUCKET" \ --endpoint-url https://s3.raffusercloud.com \ --profile raff \ --region us-east-1 ``` AWS's general S3 naming guidance uses 3-63 characters, lowercase letters, numbers, periods, and hyphens, with names beginning and ending in a letter or number. Raff may enforce its own namespace availability, so use a name that is unlikely to collide. **Verify:** ```bash aws s3 ls "s3://$BUCKET/" \ --endpoint-url https://s3.raffusercloud.com \ --profile raff \ --region us-east-1 ``` The command should return successfully, even if the new bucket is empty. ## Step 6 — Upload, List, Download, and Compare an Object Create a small test object: ```bash printf 'Raff Object Storage verification\n' > /tmp/raff-s3-test.txt ``` Upload it: ```bash aws s3 cp /tmp/raff-s3-test.txt "s3://$BUCKET/raff-s3-test.txt" \ --endpoint-url https://s3.raffusercloud.com \ --profile raff \ --region us-east-1 ``` List the object: ```bash aws s3 ls "s3://$BUCKET/raff-s3-test.txt" \ --endpoint-url https://s3.raffusercloud.com \ --profile raff \ --region us-east-1 ``` Download it to a different local path: ```bash aws s3 cp "s3://$BUCKET/raff-s3-test.txt" /tmp/raff-s3-downloaded.txt \ --endpoint-url https://s3.raffusercloud.com \ --profile raff \ --region us-east-1 ``` Compare the files locally: ```bash cmp /tmp/raff-s3-test.txt /tmp/raff-s3-downloaded.txt \ && echo 'Upload/download verification passed' ``` **Verify:** The `cmp` command should print `Upload/download verification passed`. ## Step 7 — Sync a Directory Safely with a Dry Run First Create a small local directory: ```bash mkdir -p ~/raff-s3-sync-demo printf 'alpha\n' > ~/raff-s3-sync-demo/a.txt printf 'beta\n' > ~/raff-s3-sync-demo/b.txt ``` Preview the sync before transferring anything: ```bash aws s3 sync ~/raff-s3-sync-demo/ "s3://$BUCKET/sync-demo/" \ --dryrun \ --endpoint-url https://s3.raffusercloud.com \ --profile raff \ --region us-east-1 ``` If the preview is correct, run the sync: ```bash aws s3 sync ~/raff-s3-sync-demo/ "s3://$BUCKET/sync-demo/" \ --endpoint-url https://s3.raffusercloud.com \ --profile raff \ --region us-east-1 ``` AWS documents `sync` as recursively copying new and updated files from source to destination. Do not add `--delete` casually: that option can delete destination objects that no longer exist in the source. Also note that a sync is not a versioned backup. Raff Object Storage does not currently support object versioning, so overwriting the same key does not provide a built-in object-history recovery mechanism. **Verify:** ```bash aws s3 ls "s3://$BUCKET/sync-demo/" \ --recursive \ --endpoint-url https://s3.raffusercloud.com \ --profile raff \ --region us-east-1 ``` Both `a.txt` and `b.txt` should appear. ## Step 8 — Generate a Temporary Presigned Download URL Generate a one-hour presigned URL for the test object: ```bash PRESIGNED_URL="$(aws s3 presign "s3://$BUCKET/raff-s3-test.txt" \ --expires-in 3600 \ --endpoint-url https://s3.raffusercloud.com \ --profile raff \ --region us-east-1)" ``` AWS CLI currently supports presigned expiry values up to 604800 seconds, or seven days. Anyone who has a valid presigned URL can use it until it expires, so treat the URL like a temporary bearer credential. Test it without printing the full URL into shared logs: ```bash curl -fsS "$PRESIGNED_URL" -o /tmp/raff-s3-presigned.txt cmp /tmp/raff-s3-test.txt /tmp/raff-s3-presigned.txt \ && echo 'Presigned URL verification passed' ``` Unset the shell variable after the test: ```bash unset PRESIGNED_URL ``` **Verify:** The comparison should print `Presigned URL verification passed`. :::cta Explore Object Storage Create a Raff Object Storage bucket and connect your existing S3 tooling to `s3.raffusercloud.com`. ::: ## Step 9 — Use Public Read Only for Intentionally Public Objects Raff currently supports bucket policies and public-read access, but it does not currently support S3 static website hosting. Public-read should therefore be used only when the underlying objects are intentionally public, such as downloadable assets. Create a policy only for a bucket dedicated to public content. Replace `YOUR_PUBLIC_BUCKET` before running these commands: ```bash PUBLIC_BUCKET="YOUR_PUBLIC_BUCKET" cat > /tmp/raff-public-read-policy.json </dev/null || true ``` If your organization standardizes on Ubuntu packages, the distro package can still perform basic S3 copy/sync operations. Just do not assume an Ubuntu package version exposes every command documented by current rclone. **Verify:** You should know whether the machine already has rclone, which version it runs, and whether you intend to stay on Ubuntu's older package or use current upstream stable. ## Step 2 — Install the current stable rclone release Download the official installer to a local file instead of piping an unseen script directly into a privileged shell: ```bash curl -fsSLo /tmp/rclone-install.sh https://rclone.org/install.sh ``` Review the script before running it: ```bash less /tmp/rclone-install.sh ``` Install the current stable release: ```bash sudo bash /tmp/rclone-install.sh rm -f /tmp/rclone-install.sh ``` Verify the installed version: ```bash rclone version ``` The stable release page should match the major/minor version reported by the binary. **Verify:** `rclone version` should run successfully and report the current stable branch you intentionally installed. ## Step 3 — Create a protected rclone configuration file Because the tutorial later uses systemd, keep one explicit root-owned config path: ```bash sudo install -d -m 700 /etc/rclone sudo touch /etc/rclone/raff-rclone.conf sudo chmod 600 /etc/rclone/raff-rclone.conf ``` Start rclone's interactive configurator: ```bash sudo rclone config --config /etc/rclone/raff-rclone.conf ``` Create a new remote named `raffs3` with these values: ```text Storage type: s3 Provider: Other Use environment credentials: false Access key ID: YOUR_RAFF_ACCESS_KEY Secret access key: YOUR_RAFF_SECRET_KEY Region: us-east-1 Endpoint: https://s3.raffusercloud.com Location constraint: leave empty ACL: private Advanced config: yes force_path_style: false ``` Raff supports virtual-hosted-style S3 URLs, so `force_path_style = false` is intentional. Use bucket names without periods for the cleanest HTTPS virtual-host compatibility. Do not print the full config with `rclone config show`; that command can expose sensitive values. Verify only the remote name: ```bash sudo rclone listremotes --config /etc/rclone/raff-rclone.conf ``` Expected output includes: ```text raffs3: ``` If your installed rclone supports it, inspect a redacted view: ```bash sudo rclone config redacted raffs3 \ --config /etc/rclone/raff-rclone.conf ``` Double-check even redacted output before pasting it into support tickets. **Verify:** `/etc/rclone/raff-rclone.conf` should be mode `600`, `raffs3:` should exist, the endpoint should be Raff's HTTPS endpoint, region should be `us-east-1`, and `force_path_style` should be `false`. ## Step 4 — Test the existing bucket and scoped permissions Set the bucket name for this shell session: ```bash BUCKET="YOUR_BUCKET_NAME" ``` List that bucket directly: ```bash sudo rclone lsf "raffs3:${BUCKET}" \ --config /etc/rclone/raff-rclone.conf \ --max-depth 1 ``` An empty bucket can produce no object lines while still returning successfully. Do not treat a failed global bucket listing as an authentication failure if your key is intentionally bucket-scoped. Test the intended bucket path instead. Create a harmless prefix directory marker only if you need a write test: ```bash sudo rclone mkdir "raffs3:${BUCKET}/rclone-tutorial" \ --config /etc/rclone/raff-rclone.conf ``` **Verify:** The bucket-specific command should complete without signature errors. Permission-denied responses should only occur for operations the scoped key is intentionally not allowed to perform. ## Step 5 — Upload and download one file before using sync Create a small local test file: ```bash mkdir -p ~/raff-rclone-demo printf 'Raff Object Storage rclone verification\n' \ > ~/raff-rclone-demo/verify.txt ``` Upload it with `copyto` so the destination key is explicit: ```bash sudo rclone copyto \ ~/raff-rclone-demo/verify.txt \ "raffs3:${BUCKET}/rclone-tutorial/verify.txt" \ --config /etc/rclone/raff-rclone.conf \ --progress ``` List the object: ```bash sudo rclone lsl "raffs3:${BUCKET}/rclone-tutorial/verify.txt" \ --config /etc/rclone/raff-rclone.conf ``` Download it to a different local file: ```bash sudo rclone copyto \ "raffs3:${BUCKET}/rclone-tutorial/verify.txt" \ ~/raff-rclone-demo/verify-restored.txt \ --config /etc/rclone/raff-rclone.conf ``` Compare the files: ```bash cmp ~/raff-rclone-demo/verify.txt \ ~/raff-rclone-demo/verify-restored.txt \ && echo 'Upload/download verification passed' ``` **Verify:** The uploaded object should be listed, the restored file should download successfully, and `cmp` should report `Upload/download verification passed`. ## Step 6 — Use `rclone check` for integrity verification Rclone's S3 backend validates uploads with HTTP/S3 checksums and object metadata where available. For an additional comparison between local source and remote destination, use `rclone check`: ```bash sudo rclone check \ ~/raff-rclone-demo \ "raffs3:${BUCKET}/rclone-tutorial" \ --config /etc/rclone/raff-rclone.conf \ --one-way ``` The `--one-way` flag requires each local source object to match a remote object but ignores extra objects already present remotely. S3 ETags are not always plain MD5 hashes, especially for multipart uploads or objects written by other tools. If you need a full content verification independent of remote hash metadata, use: ```bash sudo rclone check \ ~/raff-rclone-demo \ "raffs3:${BUCKET}/rclone-tutorial" \ --config /etc/rclone/raff-rclone.conf \ --one-way \ --download ``` `--download` reads object data and can consume network/egress, so use it deliberately on large datasets. **Verify:** A normal `rclone check` should report no differences for files uploaded by this workflow; a targeted `--download` check should also complete without mismatch for the test data. ## Step 7 — Understand multipart uploads before tuning performance Rclone automatically uses multipart upload above its S3 upload cutoff. Multipart is required for large S3 objects and is already supported by Raff Object Storage. Do not blindly increase concurrency. Multipart memory consumption grows approximately with: ```text transfers × s3-upload-concurrency × s3-chunk-size ``` Inspect current S3 defaults supported by your installed rclone: ```bash rclone help backend s3 | \ grep -E 'upload-cutoff|chunk-size|upload-concurrency' -A2 ``` For most backup/file-transfer jobs, start with rclone defaults. Increase `--s3-upload-concurrency` or `--s3-chunk-size` only after measuring a large-file workload and checking memory headroom. Do not set `--s3-disable-checksum` or `--s3-no-head` just to make uploads appear faster; those options reduce integrity verification. **Verify:** The workflow should use default multipart/checksum behavior unless you have measured evidence and enough RAM to justify tuning it. ## Step 8 — Use `copy` for non-destructive uploads Create a small directory tree: ```bash mkdir -p ~/raff-rclone-demo/assets ~/raff-rclone-demo/logs printf 'asset\n' > ~/raff-rclone-demo/assets/app.txt printf 'log line\n' > ~/raff-rclone-demo/logs/app.log ``` Use `copy` when destination-only objects must not be deleted: ```bash sudo rclone copy \ ~/raff-rclone-demo \ "raffs3:${BUCKET}/copy-demo" \ --config /etc/rclone/raff-rclone.conf \ --progress ``` List the result: ```bash sudo rclone lsf "raffs3:${BUCKET}/copy-demo" \ --config /etc/rclone/raff-rclone.conf \ --recursive ``` `copy` uploads new/changed source files but does not remove extra destination objects. That makes it the safer default for one-way upload workflows. **Verify:** All source files should appear under `copy-demo`, and an unrelated destination-only object would remain untouched. ## Step 9 — Preview `sync` and cap destructive deletes `rclone sync` makes the destination match the source, including deleting destination objects that are absent from the source. Rclone's own documentation recommends testing destructive syncs with `--dry-run` or interactive mode first. Create a dedicated mirror source: ```bash mkdir -p ~/raff-rclone-mirror printf 'one\n' > ~/raff-rclone-mirror/one.txt printf 'two\n' > ~/raff-rclone-mirror/two.txt ``` Preview the first sync: ```bash sudo rclone sync \ ~/raff-rclone-mirror \ "raffs3:${BUCKET}/mirror-demo" \ --config /etc/rclone/raff-rclone.conf \ --dry-run \ --combined - ``` If the preview is correct, run the first real sync: ```bash sudo rclone sync \ ~/raff-rclone-mirror \ "raffs3:${BUCKET}/mirror-demo" \ --config /etc/rclone/raff-rclone.conf ``` Now remove one local file and preview again with a delete guard: ```bash rm ~/raff-rclone-mirror/two.txt sudo rclone sync \ ~/raff-rclone-mirror \ "raffs3:${BUCKET}/mirror-demo" \ --config /etc/rclone/raff-rclone.conf \ --dry-run \ --max-delete 10 \ --combined - ``` Only run the real destructive sync when the deletion list is expected. Because Raff Object Storage does not currently support object versioning, a deleted or overwritten destination key does not automatically leave a recoverable prior version. A mirror is therefore not the same thing as a historical backup. **Verify:** The dry run should explicitly show the planned delete, and no real delete should occur until you intentionally remove `--dry-run` after reviewing the output. ## Step 10 — Use immutable or timestamped backup objects for recovery history If your application already creates timestamped backup archives, upload them with `copy` rather than mirroring a mutable directory. Example local backup files: ```bash sudo install -d -m 700 /var/backups/app STAMP="$(date -u +%Y%m%dT%H%M%SZ)" echo 'example backup payload' | \ sudo tee "/var/backups/app/app-${STAMP}.tar" >/dev/null sudo chmod 600 "/var/backups/app/app-${STAMP}.tar" ``` Upload without deleting older remote backups: ```bash sudo rclone copy \ /var/backups/app \ "raffs3:${BUCKET}/backups/app" \ --config /etc/rclone/raff-rclone.conf \ --include 'app-*.tar' ``` List the backup prefix: ```bash sudo rclone lsl "raffs3:${BUCKET}/backups/app" \ --config /etc/rclone/raff-rclone.conf ``` Retention must be an explicit operational decision. Raff Object Storage does not currently support S3 lifecycle expiration, so do not imply that old objects will age out automatically. For retention policies and safe cleanup planning, see [S3 Lifecycle Policy: Retention, Versioning, and Cleanup](/learn/guides/s3-lifecycle-policy); it also explains the distinction between native S3 lifecycle features and application-managed retention. :::cta Protect Your Files with Object Storage Create a Raff Object Storage bucket and keep recovery copies outside the source VM using the S3-compatible endpoint. ::: **Verify:** The new timestamped backup object should exist remotely without deleting earlier backup objects, and your retention process should be documented separately. ## Step 11 — Restore into a clean directory and verify content Create a disposable restore directory: ```bash rm -rf ~/raff-rclone-restore-test mkdir -p ~/raff-rclone-restore-test ``` Restore the non-destructive copy demo: ```bash sudo rclone copy \ "raffs3:${BUCKET}/copy-demo" \ ~/raff-rclone-restore-test \ --config /etc/rclone/raff-rclone.conf ``` Compare source and restore: ```bash sudo rclone check \ ~/raff-rclone-demo \ ~/raff-rclone-restore-test \ --one-way ``` For recovery-critical data, inspect representative files and application-level validity, not just object counts. **Verify:** The restored directory should contain the expected files and `rclone check` should report no mismatches for the files you intended to recover. ## Step 12 — Optionally add client-side encryption with an rclone crypt remote Raff Object Storage already uses HTTPS in transit. If you also want rclone-managed client-side encryption before upload, wrap a dedicated S3 prefix with an rclone `crypt` remote. Create a dedicated underlying path such as: ```text raffs3:YOUR_BUCKET_NAME/encrypted-backups ``` Start the interactive configurator: ```bash sudo rclone config --config /etc/rclone/raff-rclone.conf ``` Create a new remote named `raffcrypt`: ```text Storage type: crypt Remote to encrypt: raffs3:YOUR_BUCKET_NAME/encrypted-backups Filename encryption: standard Directory name encryption: true Password: generate or enter a strong unique password Password2/salt: generate or enter a different strong value ``` Store the encryption password(s) outside the VM in a password manager or recovery record. Rclone notes that crypt passwords stored in the config are only lightly obscured unless the config itself is encrypted. Losing the crypt credentials can make the encrypted objects unrecoverable. Upload through the crypt remote: ```bash sudo rclone copy \ /var/backups/app \ raffcrypt: \ --config /etc/rclone/raff-rclone.conf ``` Verify encrypted data with `cryptcheck`, not normal checksum comparison against the wrapped S3 objects: ```bash sudo rclone cryptcheck \ /var/backups/app \ raffcrypt: \ --config /etc/rclone/raff-rclone.conf ``` Do not mix plaintext writes directly into the same underlying `encrypted-backups` prefix. **Verify:** `raffcrypt:` should list readable plaintext names through rclone, the raw `raffs3:.../encrypted-backups` path should contain encrypted objects, and the crypt credentials should be stored in a separate recovery location. ## Step 13 — Automate a non-destructive upload with systemd For automation, prefer `copy` of already-created backup artifacts over `sync` unless you truly want mirror semantics. Create the script: ```bash sudo tee /usr/local/sbin/rclone-raff-backup-upload.sh >/dev/null <<'EOF' #!/usr/bin/env bash set -euo pipefail CONFIG=/etc/rclone/raff-rclone.conf SOURCE=/var/backups/app DEST=raffs3:YOUR_BUCKET_NAME/backups/app /usr/bin/rclone copy "$SOURCE" "$DEST" \ --config "$CONFIG" \ --include 'app-*.tar' \ --log-level INFO \ --stats 30s /usr/bin/rclone lsf "$DEST" \ --config "$CONFIG" \ --max-depth 1 EOF sudo chown root:root /usr/local/sbin/rclone-raff-backup-upload.sh sudo chmod 750 /usr/local/sbin/rclone-raff-backup-upload.sh ``` Replace `YOUR_BUCKET_NAME` before running it. Test manually: ```bash sudo /usr/local/sbin/rclone-raff-backup-upload.sh ``` Create a oneshot service: ```bash sudo tee /etc/systemd/system/rclone-raff-backup-upload.service >/dev/null <<'EOF' [Unit] Description=Upload backup artifacts to Raff Object Storage with rclone Wants=network-online.target After=network-online.target [Service] Type=oneshot ExecStart=/usr/local/sbin/rclone-raff-backup-upload.sh EOF ``` Create a daily timer: ```bash sudo tee /etc/systemd/system/rclone-raff-backup-upload.timer >/dev/null <<'EOF' [Unit] Description=Run Raff Object Storage backup upload daily [Timer] OnCalendar=*-*-* 03:15:00 Persistent=true RandomizedDelaySec=15m Unit=rclone-raff-backup-upload.service [Install] WantedBy=timers.target EOF ``` Enable it: ```bash sudo systemctl daemon-reload sudo systemctl enable --now rclone-raff-backup-upload.timer ``` **Verify:** The script should succeed manually, `systemctl list-timers rclone-raff-backup-upload.timer` should show a next run, and the service should use `copy`, not an unreviewed destructive sync. ## Step 14 — Run the final end-to-end verification and clean up only test data Verify the remote, sample object, backup path, and timer: ```bash rclone version sudo rclone listremotes \ --config /etc/rclone/raff-rclone.conf sudo rclone lsl "raffs3:${BUCKET}/rclone-tutorial" \ --config /etc/rclone/raff-rclone.conf sudo rclone lsl "raffs3:${BUCKET}/backups/app" \ --config /etc/rclone/raff-rclone.conf systemctl list-timers rclone-raff-backup-upload.timer ``` Confirm the design: - endpoint is `https://s3.raffusercloud.com`; - signing region is `us-east-1`; - `provider = Other`; - `force_path_style = false`; - the config file is root-only; - `copy` is used for non-destructive backup upload; - `sync` is only used when mirror/delete semantics are intentional; - destructive syncs are previewed first; - recovery is tested into a clean directory; - `rclone check` or a targeted `--download` check is used when integrity assurance matters; - optional crypt credentials are stored independently; - no workflow depends on object versioning or lifecycle rules. Remove only tutorial test prefixes if you are certain they contain no production data: ```bash sudo rclone purge "raffs3:${BUCKET}/rclone-tutorial" \ --config /etc/rclone/raff-rclone.conf \ --dry-run ``` Review the output, then remove `--dry-run` only if the destination is correct. Do not purge `backups/app` unless those backup objects are disposable. **Verify:** The production bucket should retain all intended data, only explicitly reviewed tutorial objects should be removed, and at least one verified recovery path should remain documented. ## Troubleshooting ### `SignatureDoesNotMatch` or authentication errors Confirm the endpoint and signing region in the redacted config: ```bash sudo rclone config redacted raffs3 \ --config /etc/rclone/raff-rclone.conf ``` Expected values include: ```text provider = Other region = us-east-1 endpoint = https://s3.raffusercloud.com force_path_style = false ``` Do not paste unredacted credentials into support channels. ### Bucket access works in one tool but not rclone Check whether the bucket name contains periods and whether rclone is using virtual-hosted requests. For Raff, prefer DNS-safe bucket names without periods and keep `force_path_style = false`. ### `rclone sync` wants to delete unexpected files Stop. Keep `--dry-run` enabled and inspect `--combined -` output. Confirm source/destination direction, filters, and prefix spelling. Use `copy` instead if destination-only objects must survive. ### `rclone check` cannot use a useful remote hash Multipart objects and objects written by other clients may not expose an MD5-compatible ETag. Use a targeted `rclone check --download` when you need content verification independent of remote hash metadata. ### Large uploads consume too much RAM Reduce transfers, S3 upload concurrency, or chunk size. Multipart memory use scales with transfers × upload concurrency × chunk size. Return to defaults before tuning further. ### An interrupted upload leaves multipart data behind Inspect unfinished multipart uploads before deleting anything: ```bash sudo rclone backend list-multipart-uploads \ "raffs3:${BUCKET}" \ --config /etc/rclone/raff-rclone.conf ``` Rclone also supports cleanup of old unfinished multipart uploads. Preview cleanup with `--dry-run` or interactive mode before removing pending uploads. ### Encrypted backups cannot be opened Use the `raffcrypt:` remote and confirm you have the original crypt password and salt. Do not point a newly configured crypt remote with different credentials at existing encrypted objects and expect them to decrypt. ## Conclusion You configured current rclone for Raff S3-compatible Object Storage, kept credentials in a protected config, used the correct endpoint and signing region, verified upload/download integrity, separated `copy` from destructive `sync`, tested restores, accounted for multipart behavior, optionally added client-side crypt encryption, and automated non-destructive backup uploads with systemd. The most important operational rule is that object synchronization and backup history are different. Raff Object Storage does not currently provide object versioning or lifecycle expiration, so use immutable/timestamped backup objects and explicit retention when previous recovery points matter. Continue with [How to Use Raff S3-Compatible Object Storage with AWS CLI](/learn/tutorials/raff-s3-object-storage-aws-cli), [Automate Backups with Cron and Rsync on Ubuntu 24.04](/learn/tutorials/automate-backups-cron-rsync-ubuntu-24-04), and [Back Up PostgreSQL to Raff Object Storage with Restic](/learn/tutorials/back-up-postgresql-raff-object-storage-restic). ## Sources - [rclone downloads](https://rclone.org/downloads/) - [rclone S3 backend](https://rclone.org/s3/) - [rclone sync](https://rclone.org/commands/rclone_sync/) - [rclone check](https://rclone.org/commands/rclone_check/) - [rclone crypt](https://rclone.org/crypt/) - [Ubuntu 24.04 rclone package](https://packages.ubuntu.com/noble-updates/rclone) - [Raff Object Storage](/products/object-storage) - Package, S3, integrity, backup, and automation guidance re-verified: 2026-09-05 --- ### How to Install PM2 and Deploy Node.js on Ubuntu 24.04 URL: https://rafftechnologies.com/learn/tutorials/deploy-nodejs-pm2-ubuntu-24-04 Description: Install PM2 on Ubuntu 24.04 and deploy a Node.js app with cluster mode, graceful reloads, systemd startup, private ports, Nginx, and safe cleanup. PM2 is a production process manager for Node.js applications. On Ubuntu 24.04, you can install PM2 with npm, use it to keep Node.js processes running after SSH disconnects or crashes, restore applications after reboot with systemd, and run stateless applications across multiple workers with cluster mode. On a [Raff Linux VM](/products/linux-vm), you can run a Node.js application as a long-lived service with PM2 while keeping the application port private behind Nginx. This tutorial uses Node.js 24 LTS, a small Express application, PM2 cluster mode on the tested 2 vCPU VM, systemd startup persistence, graceful reload handling, and an Nginx reverse proxy. You will also verify that port 3000 listens only on `127.0.0.1`, so the Node.js process is not exposed directly to the internet. PM2 cluster mode can run multiple instances of a networked Node.js application on the same port, but PM2's current documentation explicitly recommends keeping clustered applications stateless. In-memory sessions, local worker state, and similar data should be moved to a shared service before scaling workers. PM2 also documents `reload` as a rolling reload path for clustered HTTP applications, with a fallback to a normal restart if the reload cannot complete. For that reason, this tutorial adds graceful shutdown handling instead of promising zero downtime under every failure condition. Node.js 24 is an LTS release as of September 2026. If Node.js is not installed yet, use the current [Node.js on Ubuntu 24.04 tutorial](/learn/tutorials/install-nodejs-ubuntu-24-04) before continuing. ## Step 1 — Verify Node.js 24 LTS and the Server User Run the application as a normal user with sudo privileges rather than as `root`. Check your user and Node.js installation: ```bash whoami node --version npm --version command -v node ``` The Node.js project currently lists Node.js 24 as an LTS line. Your exact patch version can be newer than the version available when this tutorial was updated. If `node --version` does not report `v24.x.x`, follow [How to Install Node.js on Ubuntu 24.04](/learn/tutorials/install-nodejs-ubuntu-24-04) and return here after the runtime is working. **Verify:** `whoami` should show your non-root deployment user, `node --version` should report `v24.x.x`, and `npm --version` should run without an error. ## Step 2 — Create a Production Application Directory Create a directory under `/srv` and give your deployment user ownership: ```bash sudo mkdir -p /srv/myapp sudo chown "$USER:$USER" /srv/myapp cd /srv/myapp ``` Initialize npm and install Express: ```bash npm init -y npm install express ``` Confirm the project files exist: ```bash ls -la npm ls express ``` For your own application, deploy the repository into `/srv/myapp` instead of creating this sample project. Keep secrets such as API keys and database passwords out of version-controlled files. **Verify:** `/srv/myapp/package.json` should exist and `npm ls express` should show Express installed without dependency errors. ## Step 3 — Create a Localhost-Only Express App with Graceful Shutdown Create `app.js`: ```bash cat > /srv/myapp/app.js <<'EOF' const express = require('express'); const app = express(); const host = '127.0.0.1'; const port = Number(process.env.PORT || 3000); app.get('/', (req, res) => { res.json({ message: 'Node.js is running under PM2', pid: process.pid, }); }); app.get('/health', (req, res) => { res.status(200).json({ status: 'ok', pid: process.pid }); }); const server = app.listen(port, host, () => { console.log(`Listening on http://${host}:${port}`); if (process.send) process.send('ready'); }); function shutdown(signal) { console.log(`${signal} received; closing HTTP server`); const forceExit = setTimeout(() => { console.error('Graceful shutdown timed out'); process.exit(1); }, 8000); forceExit.unref(); server.close((error) => { clearTimeout(forceExit); if (error) { console.error(error); process.exit(1); } process.exit(0); }); } process.on('SIGINT', () => shutdown('SIGINT')); process.on('SIGTERM', () => shutdown('SIGTERM')); EOF ``` PM2's graceful-shutdown guidance recommends handling the stop signal, stopping new connections, finishing active work, closing external resources, and then exiting. In a real application, add database, queue, or cache cleanup before `process.exit(0)`. **Verify:** ```bash node --check /srv/myapp/app.js ``` The command should exit with no syntax error. ## Step 4 — Test the Node.js App Before Adding PM2 Start the application in the foreground: ```bash cd /srv/myapp NODE_ENV=production PORT=3000 node app.js ``` In a second SSH session, test both routes: ```bash curl -fsS http://127.0.0.1:3000/ curl -fsS http://127.0.0.1:3000/health ``` Check the listening address: ```bash ss -lntp | grep ':3000' ``` The listener should be on `127.0.0.1:3000`, not `0.0.0.0:3000` or `[::]:3000`. Return to the first session and press `Ctrl+C`. The app should log that it received `SIGINT` and exit. **Verify:** Both local requests should succeed, the health route should return `"status":"ok"`, and port 3000 should be loopback-only. ## Step 5 — Install PM2 on Ubuntu 24.04 If Node.js was installed system-wide with the NodeSource method from the Raff Node.js tutorial, install PM2 globally with: ```bash sudo npm install -g pm2 ``` If your Node.js runtime is managed by nvm under your user account, run the same npm command without `sudo`: ```bash npm install -g pm2 ``` Do not mix a system-wide Node.js runtime and an nvm-managed PM2 installation unless you deliberately manage both paths. Verify PM2: ```bash pm2 --version command -v pm2 ``` If an existing application already has a `start` script in `package.json`, PM2 can run that npm script directly: ```bash pm2 start npm --name myapp -- start ``` For this tutorial we continue with an ecosystem file because it keeps the worker count, readiness, restart, and environment settings together. **Verify:** `pm2 --version` should return a version number and `command -v pm2` should resolve to the installation associated with your intended Node.js runtime. ## Step 6 — Create a PM2 Ecosystem File for the Tested 2 vCPU Setup Create the PM2 configuration: ```bash cat > /srv/myapp/ecosystem.config.js <<'EOF' module.exports = { apps: [ { name: 'myapp', script: './app.js', cwd: '/srv/myapp', instances: 2, exec_mode: 'cluster', wait_ready: true, listen_timeout: 10000, kill_timeout: 10000, restart_delay: 1000, watch: false, merge_logs: true, env: { NODE_ENV: 'production', PORT: 3000, }, }, ], }; EOF ``` The tested Raff VM has 2 vCPU, so this example uses two workers explicitly instead of `instances: 'max'`. On a 1 vCPU VM, set `instances: 1`. On larger machines, increase workers only after measuring your application and confirming that it is stateless. Do not put secrets in this ecosystem file if it is committed to source control. Use your deployment's secret-management method or a restrictive runtime configuration file that is excluded from Git. PM2's ecosystem-file reference documents `instances`, `exec_mode`, `wait_ready`, `listen_timeout`, `kill_timeout`, and restart controls. The combination here lets PM2 wait for the app's explicit `ready` message and gives the app time to finish requests during a reload. **Verify:** ```bash node --check /srv/myapp/ecosystem.config.js ``` The configuration should pass Node.js syntax validation. ## Step 7 — Run Node.js with PM2 Cluster Mode Start the ecosystem configuration: ```bash cd /srv/myapp pm2 start ecosystem.config.js ``` Check status: ```bash pm2 status pm2 describe myapp ``` Make several local requests: ```bash for i in 1 2 3 4 5 6; do curl -fsS http://127.0.0.1:3000/health echo done ``` On the tested 2-worker setup, the responses should normally show more than one process ID over repeated requests. Do not depend on a strict alternating order. If your application stores sessions or other state in process memory, do not enable multiple workers until that state has been moved to a shared store. **Verify:** `pm2 status` should show two `myapp` instances online on the tested 2 vCPU setup, and repeated health requests should succeed. ## Step 8 — Configure PM2 to Restore the App After Reboot Generate the startup hook as your normal deployment user: ```bash pm2 startup systemd ``` PM2 prints a `sudo` command containing the correct user, home directory, PM2 path, and Node.js path. Copy and run the exact command PM2 prints rather than copying a path from another server. Save the current process list: ```bash pm2 save ``` PM2's startup documentation uses the saved process list to resurrect applications after boot. Check the generated service: ```bash sudo systemctl is-enabled "pm2-$USER" sudo systemctl status "pm2-$USER" --no-pager ``` If you later change an nvm-managed Node.js version, PM2 recommends regenerating the startup hook because the Node.js path embedded in the service can change. **Verify:** The `pm2-$USER` service should be enabled, and `pm2 save` should complete successfully. ## Step 9 — Put Nginx in Front of the Private Node.js Port Install Nginx if it is not already present: ```bash sudo apt update sudo apt install -y nginx ``` Create a server block. Replace `your-domain.com` with your domain or the server address you use for testing: ```bash sudo tee /etc/nginx/sites-available/myapp > /dev/null <<'EOF' server { listen 80; server_name your-domain.com; location / { proxy_pass http://127.0.0.1:3000; proxy_http_version 1.1; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_read_timeout 60s; } } EOF ``` PM2 and Nginx solve different problems. PM2 keeps the Node.js process running and manages its workers; Nginx owns the public HTTP/HTTPS edge and proxies requests to the private application port. Using both keeps process management separate from public web traffic. Enable the site and validate Nginx before reloading: ```bash sudo ln -sfn /etc/nginx/sites-available/myapp /etc/nginx/sites-enabled/myapp sudo nginx -t sudo systemctl reload nginx ``` For HTTPS, continue with [Secure Nginx with Let's Encrypt on Ubuntu 24.04](/learn/tutorials/secure-nginx-lets-encrypt-ubuntu-24-04) after the HTTP proxy works. **Verify:** ```bash curl -fsS http://your-domain.com/health ``` The response should contain `"status":"ok"`. ## Step 10 — Confirm the Node.js Port Is Not Publicly Exposed Check the local listener again: ```bash ss -lntp | grep ':3000' ``` Expected listening address: ```text 127.0.0.1:3000 ``` Do not add a firewall rule that exposes TCP 3000 to the internet when Nginx is the intended public entry point. Only Nginx needs to accept public HTTP/HTTPS traffic for this architecture. You can also test locally that Nginx and the app are separate layers: ```bash curl -fsS http://127.0.0.1:3000/health curl -fsS http://your-domain.com/health ``` **Verify:** Both requests should succeed, while `ss` should still show the application itself bound only to `127.0.0.1:3000`. ## Step 11 — Test a Rolling Reload and Graceful Shutdown PM2 cluster mode supports rolling reloads for HTTP applications: ```bash pm2 reload myapp ``` Watch the application state: ```bash pm2 status pm2 logs myapp --lines 30 ``` The app's signal handler should allow active HTTP connections to finish before the worker exits. PM2's current cluster documentation states that `reload` keeps workers available one by one, but also notes that a failed reload can fall back to a normal restart. Treat reloads as a safer deployment mechanism, not as an unconditional availability guarantee. For applications with database or queue connections, close those resources inside the shutdown handler before exiting. **Verify:** The app should remain online after `pm2 reload myapp`, and a new request should succeed: ```bash curl -fsS http://127.0.0.1:3000/health ``` ## Step 12 — Check Logs, Restarts, and Runtime State Inspect the PM2 process details: ```bash pm2 status pm2 describe myapp ``` View recent logs without leaving a long-running terminal session: ```bash pm2 logs myapp --lines 50 --nostream ``` For interactive CPU and memory observation: ```bash pm2 monit ``` Exit the monitor when finished. Use the measurements from your own workload to decide worker count, memory thresholds, and VM sizing; this tutorial does not assume a universal requests-per-second or latency figure for Node.js applications. **Verify:** Both workers should remain online on the tested setup, restart counts should be understandable from your deployment actions, and recent logs should not show crash loops or binding errors. :::cta Deploy Your Server Launch a Raff Linux VM and use this tutorial to run a Node.js application behind PM2 and Nginx. ::: ## Step 13 — Run the Final End-to-End Verification Run the complete verification set: ```bash node --version pm2 --version pm2 status sudo systemctl is-enabled "pm2-$USER" sudo nginx -t ss -lntp | grep ':3000' curl -fsS http://127.0.0.1:3000/health curl -fsS http://your-domain.com/health ``` The deployment is complete when Node.js 24 LTS is active, PM2 shows the intended worker count online, the PM2 systemd startup unit is enabled, Nginx configuration is valid, the application listens only on loopback, and both the direct local health check and Nginx-proxied health check succeed. If you want to verify reboot recovery, schedule an appropriate maintenance window and reboot the VM. After reconnecting, run `pm2 status` and the health checks again rather than rebooting a production server casually during deployment. **Verify:** Every command above should complete successfully, and the Node.js listener must remain `127.0.0.1:3000`. ## Step 14 — Clean Up or Roll Back Safely If this was only a test deployment, remove the application from PM2 first: ```bash pm2 delete myapp ``` If other PM2 applications still run on the VM, save the remaining process list: ```bash pm2 save ``` If `myapp` was the last PM2 application and you intentionally want an empty resurrect list, PM2's startup documentation provides: ```bash pm2 cleardump ``` Remove the Nginx site and reload Nginx: ```bash sudo rm -f /etc/nginx/sites-enabled/myapp sudo rm -f /etc/nginx/sites-available/myapp sudo nginx -t sudo systemctl reload nginx ``` Remove the sample application only after confirming the path contains no production data: ```bash rm -rf /srv/myapp ``` Do not run `pm2 unstartup` or uninstall PM2 if the server hosts other PM2-managed applications. **Verify:** `pm2 status` should no longer list `myapp`, `nginx -t` should still succeed, and the removed site should no longer proxy to the sample application. ## Conclusion You installed PM2 on Ubuntu 24.04 and deployed a Node.js 24 application with explicit cluster sizing for the tested 2 vCPU VM, graceful shutdown handling, systemd startup persistence, and Nginx as the public reverse proxy. The application port stays on `127.0.0.1`, PM2 manages worker lifecycle, and the final checks verify both local application health and the Nginx path. The main production decisions should come from your own workload rather than generic performance numbers. Scale PM2 workers only when the app is stateless, measure CPU and memory before changing worker counts, keep secrets out of committed ecosystem files, and regenerate the PM2 startup hook when an nvm-managed Node.js path changes. For HTTPS, continue with the [Nginx Let's Encrypt tutorial](/learn/tutorials/secure-nginx-lets-encrypt-ubuntu-24-04). For the broader build, release, and rollback architecture, read [Application Deployment on a Linux VM](/learn/guides/application-deployment-linux-vm). --- ### How to Deploy Django with Gunicorn and Nginx on Ubuntu 24.04 URL: https://rafftechnologies.com/learn/tutorials/deploy-django-nginx-gunicorn-ubuntu-24-04 Description: Deploy Django on Ubuntu 24.04 with Gunicorn, Nginx, systemd, static files, secure environment variables, HTTPS settings, and end-to-end production checks. Deploying Django with Gunicorn and Nginx on Ubuntu 24.04 gives each layer one clear responsibility: Django handles application logic, Gunicorn runs the WSGI application, systemd manages the Gunicorn process, and Nginx handles public HTTP/HTTPS traffic and static files. You can use this pattern on a [Raff Linux VM](/products/linux-vm) without exposing Django's development server or a raw Gunicorn port to the internet. Django's production checklist explicitly says `manage.py runserver` is not designed for production and recommends a production WSGI or ASGI server instead. Gunicorn's deployment documentation recommends placing Gunicorn behind a proxy such as Nginx. The worker-count formula often quoted for Gunicorn is only a starting point; the correct count depends on CPU, memory, database connections, request behavior, and measured load. This tutorial creates a small Django app, keeps `SECRET_KEY` outside source control, runs Gunicorn as a non-root systemd service over a Unix socket, serves collected static files with Nginx, keeps the application port private, and finishes with HTTPS and Django's deployment checks. Prerequisites: - A Raff Linux VM running Ubuntu 24.04 - SSH access with a non-root sudo user - A domain such as `example.com` pointing to the VM - TCP ports 80 and 443 available for Nginx - No requirement to expose Gunicorn directly to the public internet ## Step 1 — Install Python and Nginx and Create a Django Service User Update package metadata and install the packages used by this deployment: ```bash sudo apt update sudo apt install -y python3-venv nginx curl ``` Create a dedicated non-login user for the Django application: ```bash sudo useradd --system \ --home /srv/mysite \ --create-home \ --shell /usr/sbin/nologin \ djangoapp ``` Create the application directory and give the service user ownership: ```bash sudo mkdir -p /srv/mysite/app sudo chown -R djangoapp:djangoapp /srv/mysite ``` Confirm Python and Nginx are available: ```bash python3 --version nginx -v systemctl is-active nginx ``` Do not depend on an exact Python patch version in automation; Ubuntu security updates can change it within the supported 3.12 series. **Verify:** Python should run, Nginx should report a version, and `systemctl is-active nginx` should return `active`. ## Step 2 — Create a Virtual Environment and Install Django and Gunicorn Create a virtual environment owned by the application user: ```bash sudo -u djangoapp python3 -m venv /srv/mysite/venv ``` Upgrade pip inside the virtual environment, not the system Python: ```bash sudo -u djangoapp /srv/mysite/venv/bin/python -m pip install --upgrade pip ``` For this demo, install Django and Gunicorn: ```bash sudo -u djangoapp /srv/mysite/venv/bin/python -m pip install django gunicorn ``` For an existing application, install its reviewed dependency file instead of blindly replacing versions: ```bash sudo -u djangoapp /srv/mysite/venv/bin/python -m pip install -r /srv/mysite/app/requirements.txt ``` Create a demo project: ```bash cd /srv/mysite/app sudo -u djangoapp /srv/mysite/venv/bin/django-admin startproject config . ``` Add a small health endpoint to `config/urls.py`: ```python from django.contrib import admin from django.http import JsonResponse from django.urls import path def health(_request): return JsonResponse({"status": "ok"}) urlpatterns = [ path("admin/", admin.site.urls), path("health/", health), ] ``` Confirm the packages and WSGI module import correctly: ```bash sudo -u djangoapp /srv/mysite/venv/bin/python -c 'import django, gunicorn, config.wsgi; print(django.get_version())' ``` **Verify:** Django should print a version and the command should exit without an import error. ## Step 3 — Store the Django Secret Outside the Project Django's deployment checklist recommends keeping `SECRET_KEY` secret and out of source control. Create a root-managed environment file that the service user can read: ```bash sudo install -m 640 -o root -g djangoapp /dev/null /etc/mysite.env ``` Generate a high-entropy secret without printing it to your terminal history: ```bash sudo sh -c 'printf "DJANGO_SECRET_KEY=%s\n" "$(python3 -c "import secrets; print(secrets.token_urlsafe(50))")" > /etc/mysite.env' sudo chown root:djangoapp /etc/mysite.env sudo chmod 640 /etc/mysite.env ``` Confirm the service account can read the file without displaying the secret: ```bash sudo -u djangoapp test -r /etc/mysite.env && echo readable ``` Do not commit `/etc/mysite.env` to Git or copy its value into the systemd unit. **Verify:** The command should print `readable`, and `stat -c '%U %G %a' /etc/mysite.env` should show `root djangoapp 640`. ## Step 4 — Configure Django for Production Edit `/srv/mysite/app/config/settings.py` and add `import os` near the top if it is not already present. Use production settings like these: ```python import os SECRET_KEY = os.environ["DJANGO_SECRET_KEY"] DEBUG = False ALLOWED_HOSTS = ["example.com", "www.example.com"] STATIC_URL = "static/" STATIC_ROOT = BASE_DIR / "staticfiles" ``` Do not use `ALLOWED_HOSTS = ["*"]` as a shortcut. Django recommends validating the expected hostnames in production. For an existing project, also review database credentials, email settings, caches, uploaded media, logging, and any environment-specific settings. Database passwords should be protected like `SECRET_KEY` rather than committed to the repository. Load the environment and run Django's basic system check: ```bash sudo -u djangoapp bash -c ' set -a . /etc/mysite.env set +a cd /srv/mysite/app ../venv/bin/python manage.py check ' ``` **Verify:** `manage.py check` should finish without configuration errors and `DEBUG` should be `False` in the production settings. ## Step 5 — Run Migrations and Collect Django Static Files Apply migrations and collect static assets under `STATIC_ROOT`: ```bash sudo -u djangoapp bash -c ' set -a . /etc/mysite.env set +a cd /srv/mysite/app ../venv/bin/python manage.py migrate ../venv/bin/python manage.py collectstatic --noinput ' ``` Django's production documentation expects static files to be collected and then served by a web server or another static-file service rather than by the development server. Check that the directory exists and contains files: ```bash sudo -u djangoapp find /srv/mysite/app/staticfiles -maxdepth 2 -type f | head ``` For a real application, back up the database before production migrations and use your application's tested release procedure instead of treating every migration as risk-free. **Verify:** Migrations should complete successfully and `staticfiles/` should contain collected assets. ## Step 6 — Test Django with Gunicorn on Localhost Before creating a service, test Gunicorn locally. Bind only to loopback so the raw WSGI server is not exposed publicly: ```bash sudo -u djangoapp bash -c ' set -a . /etc/mysite.env set +a cd /srv/mysite/app ../venv/bin/gunicorn \ --bind 127.0.0.1:8000 \ --workers 2 \ config.wsgi:application ' ``` In a second SSH session, send the expected host header: ```bash curl -H 'Host: example.com' http://127.0.0.1:8000/health/ ``` Expected output: ```json {"status": "ok"} ``` Django's `runserver` is a development server; the reason to move to Gunicorn is not that `runserver` is always single-threaded, but that Django explicitly says it is not designed for production. Stop the foreground Gunicorn test with `Ctrl+C` after verification. **Verify:** Gunicorn should return the health response on `127.0.0.1:8000`, and no public firewall rule should exist for port 8000. ## Step 7 — Run Gunicorn as a systemd Service over a Unix Socket Create `/etc/systemd/system/mysite-gunicorn.service`: ```ini [Unit] Description=Gunicorn for Django mysite After=network.target [Service] Type=notify NotifyAccess=main User=djangoapp Group=www-data WorkingDirectory=/srv/mysite/app EnvironmentFile=/etc/mysite.env RuntimeDirectory=mysite RuntimeDirectoryMode=0750 UMask=0007 ExecStart=/srv/mysite/venv/bin/gunicorn \ --workers 2 \ --access-logfile - \ --error-logfile - \ --bind unix:/run/mysite/gunicorn.sock \ config.wsgi:application ExecReload=/bin/kill -s HUP $MAINPID KillMode=mixed TimeoutStopSec=30 Restart=on-failure RestartSec=5 PrivateTmp=true NoNewPrivileges=true [Install] WantedBy=multi-user.target ``` Reload systemd and start the service: ```bash sudo systemctl daemon-reload sudo systemctl enable --now mysite-gunicorn ``` Check the service and socket: ```bash systemctl is-active mysite-gunicorn sudo ls -l /run/mysite/gunicorn.sock ``` Test the socket as the Nginx user: ```bash sudo -u www-data curl \ --unix-socket /run/mysite/gunicorn.sock \ -H 'Host: example.com' \ http://localhost/health/ ``` Gunicorn's current deployment documentation supports systemd-managed services and Unix sockets. `Type=notify` lets Gunicorn report readiness to systemd. **Verify:** The service should be `active`, the socket should exist under `/run/mysite/`, and the `www-data` curl command should return `{"status": "ok"}`. ## Step 8 — Configure Nginx for Django and Gunicorn Create `/etc/nginx/sites-available/mysite`: ```nginx server { listen 80; listen [::]:80; server_name example.com www.example.com; client_max_body_size 10m; location /static/ { alias /srv/mysite/app/staticfiles/; access_log off; expires 7d; add_header Cache-Control "public"; } location / { proxy_pass http://unix:/run/mysite/gunicorn.sock; proxy_http_version 1.1; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_redirect off; } } ``` This tutorial does not add WebSocket upgrade headers because standard Django through Gunicorn's WSGI worker is an HTTP WSGI deployment. If your application requires WebSockets or other ASGI behavior, use an ASGI deployment rather than copying WSGI settings blindly. Enable the site and remove the Ubuntu default only if it is not serving anything else: ```bash sudo ln -sfn /etc/nginx/sites-available/mysite /etc/nginx/sites-enabled/mysite sudo rm -f /etc/nginx/sites-enabled/default sudo nginx -t sudo systemctl reload nginx ``` On a dedicated single-site VM, you can also configure a separate default server that rejects unknown hostnames instead of forwarding them to Django. **Verify:** `sudo nginx -t` should succeed and Nginx should reload without errors. ## Step 9 — Set Static-File Permissions and Keep Gunicorn Private Nginx needs read and traverse permission for the collected static directory, but it does not need write access to your project: ```bash sudo chmod 755 /srv/mysite /srv/mysite/app sudo find /srv/mysite/app/staticfiles -type d -exec chmod 755 {} + sudo find /srv/mysite/app/staticfiles -type f -exec chmod 644 {} + ``` If UFW is active, allow SSH before making firewall changes, then allow Nginx: ```bash sudo ufw allow OpenSSH sudo ufw allow 'Nginx Full' sudo ufw status numbered ``` Do not add a public rule for port 8000. The persistent Gunicorn service uses a Unix socket and Nginx is the public edge. If your project has user-uploaded media, treat uploads as untrusted data and configure a separate media path carefully. Do not let Nginx execute uploaded content. **Verify:** UFW should allow the intended SSH and web ports, and there should be no public Gunicorn port. :::cta Deploy Your Server Launch an Ubuntu VM for a Django, Gunicorn, and Nginx application stack. ::: ## Step 10 — Verify Django, Gunicorn, Nginx, and Static Files End to End Test the application through Nginx: ```bash curl -H 'Host: example.com' http://127.0.0.1/health/ curl http://example.com/health/ ``` Expected application response: ```json {"status": "ok"} ``` Confirm an admin static file is served by Nginx: ```bash curl -I http://example.com/static/admin/css/base.css ``` Check the two services: ```bash systemctl is-active mysite-gunicorn nginx ``` Inspect recent logs if a request fails: ```bash sudo journalctl -u mysite-gunicorn -n 50 --no-pager sudo tail -n 50 /var/log/nginx/error.log ``` **Verify:** The public health endpoint should succeed, the static file should return a successful HTTP response, and both services should be active. ## Step 11 — Tune Gunicorn Workers from Measurements, Not a Fixed Formula Gunicorn documents `(2 × CPU cores) + 1` as a starting point, not a universal production rule. Too many workers can waste memory, increase database connections, and reduce throughput. This tutorial starts with two workers on the existing 2 vCPU test profile. Measure before changing it: ```bash ps -o pid,ppid,rss,%cpu,cmd -C gunicorn free -h uptime ``` Also watch: - request latency and error rate; - worker memory after normal traffic; - database connection usage; - CPU saturation; - timeout and restart events. If you change `--workers`, reload the unit definition and restart during a controlled deployment: ```bash sudo systemctl daemon-reload sudo systemctl restart mysite-gunicorn ``` For application-code deployments that are safe to reload, the unit also supports Gunicorn's HUP reload path: ```bash sudo systemctl reload mysite-gunicorn ``` Do not use a long `--timeout` to hide slow views. Fix slow database queries, external calls, or background jobs according to the workload. **Verify:** Worker count should fit available memory and database capacity without repeated OOM events, timeouts, or restarts. ## Step 12 — Add HTTPS and Enable Django's HTTPS Security Settings Before serving logins, admin sessions, password resets, or other sensitive traffic, enable site-wide HTTPS. Complete [Install Certbot for Nginx on Ubuntu 24.04 with Let's Encrypt](/learn/tutorials/secure-nginx-lets-encrypt-ubuntu-24-04) for certificate issuance and renewal testing. Because Nginx is the trusted proxy and this configuration explicitly sets `X-Forwarded-Proto`, add these settings after HTTPS is working: ```python SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https") SECURE_SSL_REDIRECT = True SESSION_COOKIE_SECURE = True CSRF_COOKIE_SECURE = True ``` Treat HSTS separately. After HTTPS and renewal are stable, start with a short test value before increasing it: ```python SECURE_HSTS_SECONDS = 300 ``` Do not enable `SECURE_PROXY_SSL_HEADER` when requests can bypass your trusted proxy or when an untrusted client can control the forwarded-protocol header. Run Django's deployment checks against the production environment: ```bash sudo -u djangoapp bash -c ' set -a . /etc/mysite.env set +a cd /srv/mysite/app ../venv/bin/python manage.py check --deploy ' ``` Review every warning rather than assuming one generic configuration is correct for every application. **Verify:** HTTPS should work, HTTP should redirect to HTTPS, secure cookies should be enabled, and `check --deploy` warnings should be understood and resolved where applicable. ## Step 13 — Test Reboot Persistence and the Final Production Path Reboot during a safe test window: ```bash sudo reboot ``` After reconnecting, check services: ```bash systemctl is-active mysite-gunicorn nginx ``` Run the public checks: ```bash curl -I https://example.com/ curl https://example.com/health/ curl -I https://example.com/static/admin/css/base.css ``` Confirm the Gunicorn socket exists again: ```bash sudo ls -l /run/mysite/gunicorn.sock ``` The intended request path is: ```text Browser → Nginx on 80/443 → Unix socket /run/mysite/gunicorn.sock → Gunicorn workers → Django WSGI application ``` **Verify:** Nginx and Gunicorn should start automatically, HTTPS should respond, static files should load, and the health endpoint should return `{"status": "ok"}` after reboot. ## Step 14 — Operate, Update, and Clean Up Safely Follow Gunicorn logs with journald: ```bash sudo journalctl -u mysite-gunicorn -f ``` Validate Nginx before every reload: ```bash sudo nginx -t && sudo systemctl reload nginx ``` Before dependency upgrades, review release notes and test the new environment. Do not run a blanket production `pip install --upgrade` without a tested dependency strategy. To stop the application without deleting data: ```bash sudo systemctl disable --now mysite-gunicorn ``` Disable the Nginx site if this hostname is being decommissioned: ```bash sudo rm -f /etc/nginx/sites-enabled/mysite sudo nginx -t sudo systemctl reload nginx ``` Only after backups and decommissioning are confirmed should you remove `/srv/mysite`, `/etc/mysite.env`, or the systemd unit. If the application uses a production database or uploaded media, back those up separately before removal. **Verify:** A stopped deployment should no longer serve the Django application, while unrelated Nginx sites and services should continue to work. ## Conclusion You deployed Django with Gunicorn and Nginx on Ubuntu 24.04 using a non-root service account, a Python virtual environment, a protected environment file, a systemd-managed Unix socket, collected static files, Nginx reverse proxying, HTTPS-aware Django settings, deployment checks, and reboot verification. The important production decisions are not a magic worker count or a synthetic requests-per-second number. Keep secrets out of source control, keep Gunicorn private, let Nginx own the public edge, tune workers from real CPU/memory/database behavior, and run `manage.py check --deploy` against your actual production settings. For related setup work, see [Install pip on Ubuntu 24.04](/learn/tutorials/install-python-pip-ubuntu-24-04), [Install Nginx on Ubuntu 24.04](/learn/tutorials/install-nginx-ubuntu-24-04), and [Install Certbot for Nginx on Ubuntu 24.04](/learn/tutorials/secure-nginx-lets-encrypt-ubuntu-24-04). For the full deployment lifecycle beyond this Django setup, read [Application Deployment on a Linux VM](/learn/guides/application-deployment-linux-vm). ## Sources - [Django 6.0 — How to use Django with Gunicorn](https://docs.djangoproject.com/en/6.0/howto/deployment/wsgi/gunicorn/) - [Django 6.0 — Deployment checklist](https://docs.djangoproject.com/en/6.0/howto/deployment/checklist/) - [Django 6.0 — Deploying static files](https://docs.djangoproject.com/en/6.0/howto/static-files/deployment/) - [Gunicorn — Deploying Gunicorn](https://gunicorn.org/deploy/) - [Gunicorn — Design and worker scaling](https://gunicorn.org/design/) - Sources verified: 2026-09-04 --- ### How to Install Nginx on Ubuntu 24.04 URL: https://rafftechnologies.com/learn/tutorials/install-nginx-ubuntu-24-04 Description: Install Nginx on Ubuntu 24.04, verify the current Ubuntu package, configure UFW safely, create a server block, test HTTP, and inspect logs. To **install Nginx on Ubuntu 24.04**, update APT, install Ubuntu's `nginx` package, verify the service locally, then configure public HTTP access only after checking your firewall and SSH path. This tutorial also creates a custom server block, inspects logs, and completes an end-to-end Nginx check. Raff Technologies is used as the Ubuntu VM platform in the saved test workflow. On Ubuntu 24.04 LTS (Noble), the distribution package remains on the **Nginx 1.24.0** base branch. As of September 7, 2026, Ubuntu's Noble updates/security package is **`1.24.0-2ubuntu7.17`**. The Ubuntu package revision matters because Canonical can deliver security fixes without changing the short upstream version shown by `nginx -v`. ![Diagram showing how a web request flows through an Ubuntu 24.04 VPS setup: user browser, VPS public IP, UFW firewall, Nginx, server block, and website files.](https://raff-images.s3.raffusercloud.com/nginx_ubuntu_24_04_vps_d00449b0e5.png) **Quick install:** install Nginx and verify it locally first: ```bash sudo apt update sudo apt install -y nginx systemctl is-active nginx curl -I http://127.0.0.1 ``` Do not treat firewall activation as part of a blind copy-paste quick start. If UFW is inactive, confirm your real SSH port and a recovery path before enabling it. Nginx can act as a web server, reverse proxy, load balancer, HTTP cache, and TCP/UDP proxy. For a normal Ubuntu 24.04 server, the distribution package is the simplest starting point because it follows Ubuntu's package lifecycle. If you specifically need a newer upstream Nginx release, a separate nginx.org repository path is covered later. If you are setting up Nginx as an application gateway rather than a static web server, first review [Reverse Proxy Guide for Cloud VMs](/learn/guides/reverse-proxy-cloud-vms) for upstream isolation, TLS, headers, and the difference between a proxy and a load balancer. Prerequisites: - A [Raff Linux VM](/products/linux-vm) running Ubuntu 24.04 - SSH access with a non-root sudo user - The VM's public IPv4 address - Port `80/tcp` available for the HTTP test - The actual SSH listening port known before changing UFW - A second SSH session or another recovery path before enabling a previously inactive firewall - A domain only if you plan to continue to production HTTPS The original installation workflow was tested on a Raff Ubuntu 24.04 VM with 2 vCPU and 2 GB RAM. Ubuntu's Nginx package, UFW guidance, and nginx.org Ubuntu support were re-verified on September 7, 2026; no new full machine retest is claimed. ## Step 1 — Update Ubuntu and install Nginx Update package metadata and current system packages: ```bash sudo apt update sudo apt upgrade -y ``` Install Nginx, UFW, and curl: ```bash sudo apt install -y nginx ufw curl ``` Check the Ubuntu release, the Nginx binary version, and the complete Ubuntu package revision: ```bash lsb_release -ds nginx -v 2>&1 dpkg-query -W -f='${Version}\n' nginx apt-cache policy nginx ``` On Ubuntu 24.04, the binary version should follow this pattern: ```text nginx version: nginx/1.24.0 (Ubuntu) ``` The package revision can be newer than the upstream base version. As of September 7, 2026, the Noble updates/security package is: ```text 1.24.0-2ubuntu7.17 ``` The exact Ubuntu revision may increase later as updates are published. **Verify:** Ubuntu should report 24.04 LTS, Nginx should be installed, and `apt-cache policy nginx` should show the candidate supplied by your configured Ubuntu repositories. ## Step 2 — Verify the Nginx service Nginx normally starts automatically after installation. Confirm that it is active: ```bash systemctl is-active nginx ``` Expected output: ```text active ``` Check boot enablement: ```bash systemctl is-enabled nginx ``` Expected output: ```text enabled ``` Inspect the service without opening an interactive pager: ```bash sudo systemctl status nginx --no-pager ``` Useful service commands are: ```bash sudo systemctl start nginx sudo systemctl stop nginx sudo systemctl restart nginx sudo systemctl reload nginx sudo systemctl enable nginx ``` Use `reload` after a successful `nginx -t` when applying configuration changes without a full service stop. **Verify:** `systemctl is-active nginx` should return `active`, and Nginx should be enabled for normal startup unless you intentionally manage it another way. ## Step 3 — Configure UFW without risking SSH lockout First inspect the current firewall state: ```bash sudo ufw status verbose ``` Then confirm the SSH port that `sshd` is actually configured to use: ```bash sudo sshd -T | awk '/^port / {print $2}' ``` List Nginx's UFW application profiles: ```bash sudo ufw app list ``` Expected profiles normally include: ```text Nginx Full Nginx HTTP Nginx HTTPS ``` If UFW is **already active**, preserve the working SSH rule and allow HTTP: ```bash sudo ufw allow 'Nginx HTTP' sudo ufw status numbered ``` If UFW is **inactive**, add an allow rule for the actual SSH port first. For standard SSH with a matching OpenSSH profile: ```bash sudo ufw allow OpenSSH ``` For a custom SSH port, allow that port instead, for example: ```bash sudo ufw allow 2222/tcp ``` Then add the Nginx HTTP rule: ```bash sudo ufw allow 'Nginx HTTP' ``` Before enabling UFW on a remote VM, keep the current SSH session open and successfully open a **second SSH session** through the allowed SSH path. If you cannot verify a recovery path, leave UFW activation for a controlled maintenance change. Only after the second SSH session works should you enable an inactive firewall: ```bash sudo ufw enable sudo ufw status numbered ``` Do not use `ufw --force enable` as a shortcut around this check. If you also use an upstream cloud firewall, allow TCP port `80` there for the public browser test. **Verify:** SSH should remain reachable, `Nginx HTTP` should be allowed when UFW is active, and you should still have a working administrative session after the change. ## Step 4 — Test the default Nginx page Test Nginx locally before relying on public networking: ```bash curl -I http://127.0.0.1 ``` Expected output includes: ```text HTTP/1.1 200 OK Server: nginx ``` Get the VM's public IPv4 address from the Raff dashboard or run: ```bash curl -4s https://icanhazip.com ``` Open the public address in a browser: ```text http://your_server_ip ``` ![Default Nginx welcome page running on Ubuntu 24.04](https://raff-images.s3.raffusercloud.com/nginx_default_page_ubuntu_24_04_webp_f0858d74f5.png) The public page confirms that the Nginx service, host networking, and firewall path all allow HTTP traffic to reach the server. **Verify:** both the local `curl` request and the browser request should reach the default Nginx page before you replace the default site. ## Step 5 — Create a custom Nginx server block Ubuntu packages use `/etc/nginx/sites-available/` for available site configurations and `/etc/nginx/sites-enabled/` for enabled symbolic links. Create a demo document root: ```bash sudo mkdir -p /var/www/raff-nginx-demo/html ``` Create the custom page: ```bash sudo tee /var/www/raff-nginx-demo/html/index.html > /dev/null <<'EOF' Nginx server block is working on Raff

Nginx server block is working on Raff

This page is served from an Ubuntu 24.04 Linux VM.

EOF ``` Create `/etc/nginx/sites-available/raff-nginx-demo`: ```bash sudo tee /etc/nginx/sites-available/raff-nginx-demo > /dev/null <<'EOF' server { listen 80 default_server; listen [::]:80 default_server; server_name _; root /var/www/raff-nginx-demo/html; index index.html; access_log /var/log/nginx/raff-nginx-demo.access.log; error_log /var/log/nginx/raff-nginx-demo.error.log; location / { try_files $uri $uri/ =404; } } EOF ``` Disable the default site and enable the demo server block: ```bash sudo rm -f /etc/nginx/sites-enabled/default sudo ln -sf /etc/nginx/sites-available/raff-nginx-demo \ /etc/nginx/sites-enabled/raff-nginx-demo ``` Validate the entire configuration before reloading: ```bash sudo nginx -t ``` Expected result includes: ```text nginx: the configuration file /etc/nginx/nginx.conf syntax is ok nginx: configuration file /etc/nginx/nginx.conf test is successful ``` Reload only after the test succeeds: ```bash sudo systemctl reload nginx ``` **Verify:** `nginx -t` should pass and Nginx should reload without an error. ## Step 6 — Verify the custom server block Check the custom page locally: ```bash curl -s http://127.0.0.1 | grep 'Nginx server block is working on Raff' ``` Expected output contains: ```text

Nginx server block is working on Raff

``` Check the public HTTP response: ```bash SERVER_IP="$(curl -4s https://icanhazip.com)" curl -I "http://$SERVER_IP" ``` Open the public IP again in a browser: ```text http://your_server_ip ``` ![Custom Nginx server block page on Ubuntu 24.04](https://raff-images.s3.raffusercloud.com/Nginx_server_block_is_working_on_Raff_658f202c47.png) For a production site, replace `server_name _;` with real domain names before configuring HTTPS. Only the intended public edge should be internet-facing; application and data services should use private traffic paths where possible. See [Public vs Private Traffic in Cloud Infrastructure](/learn/guides/private-networking-public-vs-private-traffic). **Verify:** the local request and public request should both return the custom server-block content. ## Step 7 — Review Nginx files and logs Important Ubuntu Nginx paths include: ```text /etc/nginx/nginx.conf /etc/nginx/sites-available/ /etc/nginx/sites-enabled/ /etc/nginx/conf.d/ /var/www/ /var/log/nginx/ ``` Files created in this tutorial include: ```text /var/www/raff-nginx-demo/html/index.html /etc/nginx/sites-available/raff-nginx-demo /etc/nginx/sites-enabled/raff-nginx-demo /var/log/nginx/raff-nginx-demo.access.log /var/log/nginx/raff-nginx-demo.error.log ``` Review recent requests: ```bash sudo tail -n 20 /var/log/nginx/raff-nginx-demo.access.log ``` Review errors: ```bash sudo tail -n 20 /var/log/nginx/raff-nginx-demo.error.log ``` Confirm which configuration files Nginx loaded: ```bash sudo nginx -T 2>/dev/null | grep -E 'configuration file|server_name|root ' ``` Use full `nginx -T` output carefully on shared systems because it can expose internal hostnames and configuration details. **Verify:** requests to the demo site should appear in the custom access log, while the error log should not contain unresolved configuration failures. ## Step 8 — Verify the Nginx setup end to end Run the final verification sequence: ```bash SERVER_IP="$(curl -4s https://icanhazip.com)" echo "Ubuntu package:" dpkg-query -W -f='${Version}\n' nginx echo "APT candidate:" apt-cache policy nginx | sed -n '1,6p' echo "Nginx binary:" nginx -v 2>&1 echo "Service:" systemctl is-active nginx echo "Boot status:" systemctl is-enabled nginx echo "Configuration:" sudo nginx -t echo "Firewall:" sudo ufw status numbered echo "Local HTTP response:" curl -I http://127.0.0.1 echo "Public HTTP response:" curl -I "http://$SERVER_IP" echo "Custom page:" curl -s http://127.0.0.1 | grep 'Nginx server block is working on Raff' ``` End-to-end verification is complete when: - the installed Ubuntu Nginx package matches the intended APT candidate; - `nginx -v` reports the Ubuntu Nginx 1.24.0 base branch; - the service is active and enabled; - `nginx -t` succeeds; - if UFW is active, the required HTTP and SSH paths are allowed; - local and public HTTP requests succeed; and - the custom server block returns the demo page. :::cta Deploy Your Server Launch an Ubuntu 24.04 Linux VM and use this Nginx setup for websites, reverse proxies, or application traffic. ::: ## Optional — Install a newer Nginx release from nginx.org Ubuntu's package is the recommended path when you want Ubuntu-managed updates and the Noble configuration layout. If you specifically need a newer stable or mainline Nginx release, nginx.org currently publishes official packages for Ubuntu 24.04. Do not casually mix Ubuntu's distribution packages and nginx.org packages on an existing production server. Packaging defaults and configuration layout differ. Install the repository prerequisites: ```bash sudo apt install -y curl gnupg2 ca-certificates lsb-release ubuntu-keyring ``` Import the official signing key: ```bash curl https://nginx.org/keys/nginx_signing.key | gpg --dearmor \ | sudo tee /usr/share/keyrings/nginx-archive-keyring.gpg >/dev/null ``` Verify the key before trusting it using the fingerprint shown by current nginx.org documentation. For the nginx.org stable repository: ```bash echo "deb [signed-by=/usr/share/keyrings/nginx-archive-keyring.gpg] \ https://nginx.org/packages/ubuntu $(lsb_release -cs) nginx" \ | sudo tee /etc/apt/sources.list.d/nginx.list ``` Pin nginx.org packages above distribution-provided packages only if that is intentionally the source you want: ```bash echo -e "Package: *\nPin: origin nginx.org\nPin: release o=nginx\nPin-Priority: 900\n" \ | sudo tee /etc/apt/preferences.d/99nginx ``` Update metadata and inspect the candidate before installing: ```bash sudo apt update apt-cache policy nginx ``` The Ubuntu package path used by the rest of this tutorial remains `1.24.0-2ubuntu7.17` in Noble updates/security as of September 7, 2026. ## Cleanup Remove the demo site only if you no longer need it: ```bash sudo rm -f /etc/nginx/sites-enabled/raff-nginx-demo sudo rm -f /etc/nginx/sites-available/raff-nginx-demo sudo rm -rf /var/www/raff-nginx-demo ``` Restore Ubuntu's default site if its configuration file still exists: ```bash if [ -f /etc/nginx/sites-available/default ]; then sudo ln -sf /etc/nginx/sites-available/default \ /etc/nginx/sites-enabled/default fi ``` Test and reload: ```bash sudo nginx -t sudo systemctl reload nginx ``` Remove the HTTP firewall rule only if the VM no longer needs port 80: ```bash sudo ufw delete allow 'Nginx HTTP' sudo ufw status numbered ``` Do not close port 80 when it is still required for a website, redirect, or ACME HTTP challenge. ## Troubleshooting ### The browser does not load the Nginx page Check the service, local response, firewall state, public IP, and port listener: ```bash systemctl is-active nginx curl -I http://127.0.0.1 sudo ufw status numbered curl -4s https://icanhazip.com sudo ss -lntp | grep ':80' ``` If local HTTP works but public HTTP does not, investigate UFW and any upstream cloud firewall before changing Nginx configuration. ### Why does Nginx still show 1.24.0 after apt upgrade? Ubuntu 24.04 can continue to report `nginx/1.24.0` while Ubuntu package revisions receive fixes. Check the full package version instead: ```bash dpkg-query -W -f='${Version}\n' nginx apt-cache policy nginx ``` If the installed package matches the intended Ubuntu candidate, the server can be current even though the short binary version remains 1.24.0. ### nginx -t reports a syntax error Run: ```bash sudo nginx -t ``` Correct the file named in the error, then validate again before reloading: ```bash sudo nginx -t sudo systemctl reload nginx ``` ### The default Nginx page still appears Check enabled sites: ```bash ls -l /etc/nginx/sites-enabled/ ``` Then make sure the custom site is enabled and the default site is not still taking the request: ```bash sudo rm -f /etc/nginx/sites-enabled/default sudo ln -sf /etc/nginx/sites-available/raff-nginx-demo \ /etc/nginx/sites-enabled/raff-nginx-demo sudo nginx -t sudo systemctl reload nginx ``` ### UFW does not show Nginx profiles Check the installed package and profile file: ```bash dpkg -s nginx ls -l /etc/ufw/applications.d/nginx sudo ufw app list ``` If necessary, allow HTTP directly: ```bash sudo ufw allow 80/tcp ``` ### Enabling UFW could disconnect SSH Do not enable the firewall from a single remote session until you know the real SSH port and have added the matching allow rule. Keep the current connection open and confirm a second SSH session works first. ### The site works over HTTP but shows Not Secure This tutorial intentionally stops at HTTP. Point a domain to the VM, replace the catch-all `server_name`, and continue with [Secure Nginx with Let's Encrypt on Ubuntu 24.04](/learn/tutorials/secure-nginx-lets-encrypt-ubuntu-24-04). ## How to uninstall Nginx from Ubuntu To update Nginx, you normally do not need to remove it: ```bash sudo apt update sudo apt upgrade ``` To remove Nginx and its package configuration: ```bash sudo systemctl stop nginx sudo apt purge -y nginx nginx-common sudo apt autoremove -y ``` `purge` removes Nginx configuration under `/etc/nginx`. Website files under `/var/www/` are separate and should only be removed when you no longer need them. ## Conclusion You installed Nginx on Ubuntu 24.04 through Ubuntu's supported repositories, verified the full Ubuntu package revision, configured HTTP access without blindly force-enabling UFW, created a custom server block, inspected logs, and completed an end-to-end web-server check. For Ubuntu 24.04, the important version distinction is between the Nginx 1.24.0 upstream base shown by `nginx -v` and Ubuntu's complete package revision. Ubuntu Noble currently publishes `1.24.0-2ubuntu7.17` in its updates/security repositories. Next, configure [free HTTPS with Let's Encrypt](/learn/tutorials/secure-nginx-lets-encrypt-ubuntu-24-04), build a [LEMP stack](/learn/tutorials/set-up-lemp-stack-ubuntu-24-04), or use [Docker on Ubuntu 24.04](/learn/tutorials/install-docker-ubuntu-24-04) for containerized applications behind Nginx. ## Sources - Ubuntu Packages — Nginx in Noble and Noble Updates - nginx.org — official Linux packages and supported Ubuntu versions - Ubuntu Server documentation — Nginx installation and firewall management - Guidance re-verified: 2026-09-07 --- ### How to Set Up a Caddy Reverse Proxy on Ubuntu 24.04 URL: https://rafftechnologies.com/learn/tutorials/install-caddy-ubuntu-24-04-reverse-proxy Description: Set up Caddy as a reverse proxy on Ubuntu 24.04 with automatic HTTPS, localhost-only upstreams, safe firewall rules, WebSockets, logs, and rollback. A Caddy reverse proxy on Ubuntu 24.04 can put a public HTTPS domain in front of an application that listens only on localhost. The production pattern is simple: keep your application on a private listener such as `127.0.0.1:8080`, let Caddy accept traffic on ports 80 and 443, and point a Caddyfile `reverse_proxy` directive at the local upstream. Caddy handles several details that older reverse-proxy tutorials often configure manually. For qualifying public hostnames, automatic HTTPS obtains and renews certificates and redirects HTTP to HTTPS. The `reverse_proxy` handler also manages the standard `X-Forwarded-For`, `X-Forwarded-Proto`, and `X-Forwarded-Host` headers by default, and WebSocket upgrades work without adding Nginx-style `Connection` or `Upgrade` header rules. This tutorial installs Caddy from its official Debian/Ubuntu repository, creates a localhost-only demo backend, validates DNS and firewall state without risking SSH lockout, configures the reverse proxy, verifies HTTPS and WebSockets behavior, enables structured access logging, tests a second upstream pattern, and includes a safe rollback path. The original tutorial was run on a [Raff Linux VM](/products/linux-vm). The original setup was tested on Ubuntu 24.04 LTS on a Raff 1 vCPU / 2 GB RAM VM; Caddy's current installation, reverse-proxy, automatic HTTPS, and systemd guidance were re-verified on September 4, 2026. Prerequisites: - A Raff Linux VM running Ubuntu 24.04 - SSH access with a non-root sudo user - A domain or subdomain whose DNS can point to the VM - Ports 80 and 443 available for Caddy - A backend application that can listen on localhost or a private network address The examples use `app.example.com` and a demo backend on `127.0.0.1:8080`. Replace them with your real hostname and application port. ## Step 1 — Check DNS, existing listeners, and SSH access before changing the firewall Confirm Ubuntu: ```bash cat /etc/os-release ``` Check whether another web server already owns ports 80 or 443: ```bash sudo ss -lntp | grep -E ':(80|443)\b' || true ``` Check the domain's IPv4 and IPv6 DNS records: ```bash dig +short A app.example.com dig +short AAAA app.example.com ``` If `dig` is unavailable: ```bash sudo apt update sudo apt install -y dnsutils ``` An `A` record should point to the VM's public IPv4 address. If an `AAAA` record exists, it must also point to working IPv6 service on this server; stale IPv6 DNS can break validation or client access even when IPv4 is correct. If Nginx, Apache, or another reverse proxy is already serving production traffic on ports 80/443, do not stop it blindly. Plan the migration or move Caddy to a different server before continuing. Also keep your current SSH session open while making network changes. **Verify:** Ubuntu should report 24.04, the intended hostname should resolve to this VM, and you should know which process currently owns ports 80 and 443 before installing Caddy. ## Step 2 — Install Caddy from the official Debian/Ubuntu repository Install the repository prerequisites: ```bash sudo apt update sudo apt install -y debian-keyring debian-archive-keyring apt-transport-https curl ``` Add Caddy's official stable signing key: ```bash curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | \ sudo gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg ``` Add the official stable repository: ```bash curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | \ sudo tee /etc/apt/sources.list.d/caddy-stable.list ``` Make the APT files readable and install Caddy: ```bash sudo chmod o+r /usr/share/keyrings/caddy-stable-archive-keyring.gpg sudo chmod o+r /etc/apt/sources.list.d/caddy-stable.list sudo apt update sudo apt install -y caddy ``` Caddy's official package automatically installs and starts `caddy.service` for Caddyfile-based configurations. Official installation instructions: [Caddy — Install](https://caddyserver.com/docs/install). **Verify:** ```bash caddy version systemctl is-active caddy systemctl is-enabled caddy ``` The version command should return a Caddy v2 release, and the service should be active and enabled unless another process is preventing it from binding to the required ports. ## Step 3 — Create a localhost-only demo backend Install Python for a temporary test backend: ```bash sudo apt install -y python3 ``` Create a small document root: ```bash sudo install -d -o root -g root -m 755 /srv/caddy-proxy-demo ``` Create a test page: ```bash cat <<'EOF' | sudo tee /srv/caddy-proxy-demo/index.html > /dev/null Caddy Reverse Proxy Test

Caddy reverse proxy is working

EOF ``` Start the demo server in the foreground from a second SSH session or terminal: ```bash python3 -m http.server 8080 \ --bind 127.0.0.1 \ --directory /srv/caddy-proxy-demo ``` Python's built-in HTTP server is only a disposable test upstream. Do not use it as the production application server. **Verify:** From the VM, run `curl -fsS http://127.0.0.1:8080 | grep 'Caddy reverse proxy is working'`. The command should return the heading. ## Step 4 — Confirm the backend is not exposed publicly Check the listener: ```bash sudo ss -lntp | grep ':8080' ``` The local address should be: ```text 127.0.0.1:8080 ``` not: ```text 0.0.0.0:8080 ``` Do not add a UFW or cloud firewall rule for port 8080 when Caddy and the application run on the same VM. The entire point of this topology is that the public client reaches Caddy, while Caddy reaches the application through loopback. A real Node.js, FastAPI, Django, Go, or other application should follow the same principle unless it intentionally lives on another private host. **Verify:** Port 8080 should listen only on `127.0.0.1`, and there should be no public firewall rule exposing TCP 8080. ## Step 5 — Back up the Caddyfile and configure the reverse proxy Back up the packaged configuration: ```bash sudo cp /etc/caddy/Caddyfile /etc/caddy/Caddyfile.bak ``` Replace the active configuration with the reverse-proxy site: ```bash sudo tee /etc/caddy/Caddyfile > /dev/null <<'EOF' app.example.com { reverse_proxy 127.0.0.1:8080 } EOF ``` That is enough for the basic proxy. Caddy's current `reverse_proxy` documentation says incoming headers are passed through by default, while Caddy sets or augments `X-Forwarded-For` and sets `X-Forwarded-Proto` and `X-Forwarded-Host` itself. Do not add boilerplate such as: ```text header_up X-Forwarded-For ... header_up X-Forwarded-Proto ... header_up Host ... ``` unless your application has a specific, documented requirement that differs from Caddy's defaults. **Verify:** `sudo cat /etc/caddy/Caddyfile` should show your real hostname and the intended localhost upstream. ## Step 6 — Format and validate the Caddyfile before reloading Format the configuration: ```bash sudo caddy fmt --overwrite /etc/caddy/Caddyfile ``` Validate it: ```bash sudo caddy validate --config /etc/caddy/Caddyfile ``` `caddy validate` does more than parse syntax; Caddy documents that it loads and provisions modules as if starting the configuration, without actually starting it. That makes it a useful check before changing the running service. Do not reload a configuration that fails validation. **Verify:** `caddy validate` should complete successfully without a configuration or provisioning error. ## Step 7 — Allow HTTP and HTTPS without enabling UFW blindly Check UFW first: ```bash sudo ufw status verbose ``` If UFW is already **active** and your SSH access is already safely allowed, add web traffic: ```bash sudo ufw allow 80/tcp sudo ufw allow 443/tcp ``` If UFW is **inactive**, do not run `ufw enable` merely because this tutorial uses Caddy. Enabling a firewall on a remote server without first validating your SSH rule can lock you out. Configure SSH deliberately first using [Set Up UFW Firewall on Ubuntu 24.04](/learn/tutorials/set-up-ufw-firewall-ubuntu-24-04), then enable it if host-level firewalling is part of your plan. If a Raff-side security group or another cloud firewall protects the VM, allow public TCP 80 and 443 there as well. For normal public automatic HTTPS, Caddy's documentation expects ports 80 and 443 to be externally reachable. Port 80 is also used for automatic HTTP-to-HTTPS redirects and can be used for ACME HTTP challenge validation; port 443 serves HTTPS and can be used for TLS-ALPN validation. **Verify:** If UFW is active, `sudo ufw status numbered` should preserve your working SSH access and allow TCP 80/443. The external firewall should also permit the intended public web traffic. ## Step 8 — Reload Caddy and verify automatic HTTPS Apply the validated configuration with a graceful reload: ```bash sudo systemctl reload caddy ``` Caddy recommends reloading rather than stopping the service for Caddyfile configuration changes. Check recent logs: ```bash sudo journalctl -u caddy -n 100 --no-pager ``` Test HTTPS: ```bash curl -I https://app.example.com ``` Test the HTTP redirect: ```bash curl -I http://app.example.com ``` For a qualifying public hostname with correct DNS and external reachability, Caddy automatically manages a publicly trusted certificate and normally redirects HTTP to HTTPS. **Verify:** HTTPS should reach the demo backend successfully, HTTP should redirect to HTTPS, and the Caddy journal should not show repeating certificate, DNS, bind, or upstream errors. ## Step 9 — Verify the full client → Caddy → backend path Check the backend directly from the VM: ```bash curl -fsS http://127.0.0.1:8080 | \ grep 'Caddy reverse proxy is working' ``` Then check the same content through public HTTPS: ```bash curl -fsS https://app.example.com | \ grep 'Caddy reverse proxy is working' ``` Inspect the listeners: ```bash sudo ss -lntp | grep -E ':(80|443|8080)\b' ``` The expected topology is: ```text Internet | | TCP 80 / 443 v Caddy | | 127.0.0.1:8080 v Application ``` :::cta Deploy Your Reverse Proxy Launch a Raff Ubuntu VM and put your application behind a Caddy reverse proxy with automatic HTTPS. ::: **Verify:** Caddy should own the public web ports, the application should remain on localhost, and the content returned through HTTPS should match the local upstream response. ## Step 10 — Use Caddy's built-in WebSocket proxying instead of manual upgrade headers Caddy's reverse proxy supports WebSockets directly. When the client sends an HTTP upgrade request, Caddy performs the upgrade and turns the connection into a bidirectional tunnel. For a WebSocket-capable application on port 3000, the normal configuration is still just: ```caddyfile ws.example.com { reverse_proxy 127.0.0.1:3000 } ``` You do not need Nginx-style boilerplate such as manually setting `Connection: upgrade` and `Upgrade: websocket` for the standard case. One operational detail matters: Caddy documents that active WebSocket connections are closed by default when the configuration is reloaded. Applications normally reconnect, but long-lived connection workloads can consider `stream_close_delay` or `stream_timeout` after measuring their actual behavior. **Verify:** For your real WebSocket application, connect through the HTTPS/WSS hostname and confirm messages flow in both directions without adding manual upgrade headers. ## Step 11 — Handle reverse-proxy headers and upstream trust deliberately When Caddy is directly internet-facing, its default forwarded-header behavior is usually the correct baseline. Caddy ignores client-supplied values for its managed `X-Forwarded-*` headers by default to reduce spoofing risk, then sets the forwarding information it knows itself. If another reverse proxy or CDN sits in front of Caddy, client IP handling changes. In that architecture, configure Caddy's `trusted_proxies` only for the actual proxy/CDN address ranges rather than trusting arbitrary incoming forwarded headers. Do not copy a broad `trusted_proxies private_ranges` or `0.0.0.0/0` rule without understanding which machine is the immediate peer. Your application also needs to be configured to trust proxy headers only from the Caddy hop when its framework requires explicit proxy trust. **Verify:** Document whether Caddy is the first public proxy. If another proxy exists in front, verify that only the known proxy address ranges are trusted for client-IP parsing. ## Step 12 — Proxy to HTTPS upstreams without disabling certificate verification If Caddy and the backend are on the same VM, loopback HTTP is often the simplest transport: ```caddyfile app.example.com { reverse_proxy 127.0.0.1:8080 } ``` If the upstream itself requires HTTPS and has a valid certificate, specify the HTTPS URL: ```caddyfile app.example.com { reverse_proxy https://backend.example.internal } ``` Current Caddy versions automatically handle the upstream `Host` value needed for normal HTTPS upstream certificate verification. Do **not** solve a private-certificate error by adding: ```text tls_insecure_skip_verify ``` Caddy's documentation explicitly states that this disables TLS handshake verification and is vulnerable to man-in-the-middle attacks. For an internal CA or self-signed upstream, establish trust with an appropriate `tls_trust_pool` and configure the correct TLS server name when necessary. **Verify:** If you use an HTTPS upstream, Caddy should connect without `tls_insecure_skip_verify`, and the backend certificate should validate against a trusted CA or explicitly configured trust pool. ## Step 13 — Add access logging and a second reverse-proxy site Caddy's site-level `log` directive enables HTTP access logging. Update the Caddyfile: ```caddyfile app.example.com { log reverse_proxy 127.0.0.1:8080 } api.example.com { log reverse_proxy 127.0.0.1:9000 } ``` Only add the second site when `api.example.com` actually points to this VM and a backend is listening on the configured address. Format, validate, and reload: ```bash sudo caddy fmt --overwrite /etc/caddy/Caddyfile sudo caddy validate --config /etc/caddy/Caddyfile sudo systemctl reload caddy ``` With the packaged systemd service, Caddy's output is available through the systemd journal: ```bash sudo journalctl -u caddy -n 100 --no-pager ``` Do not confuse access logs with application logs. Caddy can tell you that a request reached the proxy and what response it produced, while your upstream application still needs its own logs for application errors and business logic. **Verify:** The Caddyfile should validate after adding `log`, requests to the configured site should appear in Caddy's logs, and every hostname should map only to an upstream that actually exists. ## Step 14 — Run the final verification and roll back safely if needed Run the complete check: ```bash sudo caddy validate --config /etc/caddy/Caddyfile systemctl is-active caddy systemctl is-enabled caddy sudo ss -lntp | grep -E ':(80|443|8080)\b' curl -I http://app.example.com curl -I https://app.example.com curl -fsS https://app.example.com | \ grep 'Caddy reverse proxy is working' sudo journalctl -u caddy -p warning -n 50 --no-pager ``` The final state is healthy when Caddy is active and enabled, ports 80/443 terminate at Caddy, the backend remains private, HTTP redirects to HTTPS, the HTTPS response reaches the application, and there are no unresolved repeating errors. To roll back the Caddyfile, first validate the saved backup: ```bash sudo caddy validate --config /etc/caddy/Caddyfile.bak ``` Then restore it and reload: ```bash sudo cp /etc/caddy/Caddyfile.bak /etc/caddy/Caddyfile sudo systemctl reload caddy ``` Stop the temporary Python backend with `Ctrl+C` in the terminal where it is running, then remove the demo directory if it is no longer needed: ```bash sudo rm -rf /srv/caddy-proxy-demo ``` Do not remove ports 80/443 from the firewall if another production web service still needs them, and do not delete `/var/lib/caddy` casually because it contains Caddy-managed application state including certificate data. **Verify:** After rollback, `sudo caddy validate --config /etc/caddy/Caddyfile` should pass, Caddy should serve the intended previous configuration, and the temporary port 8080 listener should be gone. ## Troubleshooting ### Caddy returns `502 Bad Gateway` Test the upstream first: ```bash curl -v http://127.0.0.1:8080 sudo ss -lntp | grep ':8080' ``` If the local request fails, fix the application before changing Caddy. If the application works locally, inspect Caddy's journal: ```bash sudo journalctl -u caddy -n 120 --no-pager ``` ### HTTPS certificate issuance fails Check both address families: ```bash dig +short A app.example.com dig +short AAAA app.example.com ``` Then confirm ports 80/443 are reachable and owned by Caddy: ```bash sudo ss -lntp | grep -E ':(80|443)\b' sudo ufw status numbered ``` A stale `AAAA` record, blocked port, another web server, or DNS pointed at the wrong VM can all prevent normal public validation. ### Caddy fails after a configuration edit Validate before doing anything else: ```bash sudo caddy validate --config /etc/caddy/Caddyfile ``` Then inspect: ```bash sudo journalctl -u caddy -n 100 --no-pager ``` Do not repeatedly restart the service while the configuration is invalid. ### The backend sees the wrong client IP First decide whether a CDN/load balancer sits in front of Caddy. If Caddy is the first public proxy, do not add broad trusted-proxy rules. If another proxy is present, configure only its actual CIDRs with Caddy's `trusted_proxies` settings and configure your application framework's proxy trust accordingly. ### WebSockets disconnect when Caddy reloads Caddy supports WebSockets automatically, but current documentation notes that open WebSocket streams are normally closed when a config is unloaded during reload. If this is a problem for your workload, evaluate `stream_close_delay` or `stream_timeout` and test reconnect behavior before changing production settings. ### An HTTPS upstream works only with `tls_insecure_skip_verify` That means certificate trust or server-name verification is not configured correctly. Do not keep the insecure option in production. Install or reference the correct CA through `tls_trust_pool`, use the hostname that matches the backend certificate, or use trusted private HTTP when that is appropriate for the network and threat model. ## Conclusion You now have Caddy running as a reverse proxy on Ubuntu 24.04 with a localhost-only backend, automatic HTTPS, safe firewall handling, validated Caddyfile reloads, default forwarded-header behavior, native WebSocket support, access logging, upstream TLS guidance, end-to-end checks, and rollback instructions. The production baseline is intentionally small: `reverse_proxy 127.0.0.1:PORT` is often all the Caddyfile needs. Add manual headers, transport settings, health checks, or trusted proxies only when your actual topology requires them. Keeping the application off the public interface and validating every configuration before reload removes much of the unnecessary risk found in older reverse-proxy examples. For the architecture behind those decisions, see [Reverse Proxy Guide for Cloud VMs](/learn/guides/reverse-proxy-cloud-vms) on proxy placement, backend isolation, TLS termination, and when a managed load balancer is a separate concern. For a static Caddy site instead of a proxy, see [Install Caddy Web Server on Ubuntu 24.04](/learn/tutorials/install-caddy-ubuntu-24-04). For an Nginx-based edge, use [Install Nginx on Ubuntu 24.04](/learn/tutorials/install-nginx-ubuntu-24-04) and [Secure Nginx with Let's Encrypt](/learn/tutorials/secure-nginx-lets-encrypt-ubuntu-24-04). ## Sources - [Caddy — Install](https://caddyserver.com/docs/install) - [Caddy — Reverse proxy quick-start](https://caddyserver.com/docs/quick-starts/reverse-proxy) - [Caddy — reverse_proxy directive](https://caddyserver.com/docs/caddyfile/directives/reverse_proxy) - [Caddy — Automatic HTTPS](https://caddyserver.com/docs/automatic-https) - [Caddy — Keep Caddy Running](https://caddyserver.com/docs/running) - Caddy guidance verified: 2026-09-04 --- ### How to Install WordPress on Ubuntu 24.04 with Nginx URL: https://rafftechnologies.com/learn/tutorials/install-wordpress-ubuntu-24-04-nginx Description: Install WordPress on Ubuntu 24.04 with Nginx, PHP 8.3, MariaDB, secure permissions, and Let's Encrypt HTTPS on a Raff Linux VM step by step. WordPress runs well on Ubuntu 24.04 with Nginx, PHP-FPM, and MariaDB when you want full control over the web server, PHP runtime, database, files, TLS, and backups. In this tutorial, you will install WordPress on a Raff Technologies Linux VM, configure the Nginx WordPress server block, keep MariaDB local to the server, protect `wp-config.php`, enable HTTPS with Let's Encrypt, and verify the finished site end to end. Ubuntu 24.04's PHP 8.3 baseline matches WordPress's current recommended PHP requirement, and the MariaDB version available on Ubuntu 24.04 meets WordPress's modern database baseline. This guide uses a single-server WordPress VPS design: Nginx, PHP-FPM, MariaDB, and WordPress all run on the same VM. For a small site, start with at least 2 GB RAM; use more memory when plugins, backups, imports, WooCommerce, or traffic increase PHP and database load. You need a domain whose DNS can point to the VM, SSH access with a non-root sudo user, and a fresh or maintained Ubuntu 24.04 server. Keep the domain placeholder `example.com` until you replace it with your real hostname. ## Step 1 — Confirm DNS and Update Ubuntu Point the domain's A record to the public IPv4 address of your Raff Linux VM. Only add an AAAA record when IPv6 is configured and reachable on the same server. From your workstation, check the hostnames you plan to include in the certificate: ```bash dig +short A example.com dig +short A www.example.com dig +short AAAA example.com dig +short AAAA www.example.com ``` If you do not use `www.example.com`, do not add it to the Nginx `server_name` or Certbot command later. Only request names that actually resolve to this VM. Then connect over SSH and update Ubuntu: ```bash sudo apt update sudo apt upgrade -y ``` If the upgrade reports that a reboot is required, reboot before continuing and reconnect over SSH: ```bash sudo reboot ``` **Verify:** every hostname you plan to serve should resolve to the intended VM address, and `sudo apt update` should complete without repository errors. ## Step 2 — Install Nginx, MariaDB, PHP-FPM, and WordPress Extensions Install Nginx, MariaDB, PHP-FPM, and the PHP extensions commonly needed by WordPress: ```bash sudo apt install -y \ nginx \ mariadb-server \ php-fpm \ php-mysql \ php-curl \ php-gd \ php-intl \ php-mbstring \ php-soap \ php-xml \ php-zip \ php-imagick \ curl \ tar \ openssl ``` Enable the core services: ```bash sudo systemctl enable --now nginx mariadb php8.3-fpm ``` Check the installed versions: ```bash nginx -v php -v mariadb --version ``` WordPress currently recommends PHP 8.3 or newer, MariaDB 10.11 or newer or MySQL 8.0 or newer, plus HTTPS. Ubuntu 24.04's standard PHP-FPM service is `php8.3-fpm`; if you deliberately installed another PHP version, use that service and socket consistently in later steps. **Verify:** Run: ```bash systemctl is-active nginx mariadb php8.3-fpm ``` All three services should return `active`. ## Step 3 — Secure MariaDB Before Creating WordPress Data Run MariaDB's security helper: ```bash sudo mariadb-secure-installation ``` For a local single-server WordPress deployment, keep local administrative access protected, remove anonymous users, remove the test database, and disallow unnecessary remote root access. WordPress will use its own database user rather than the MariaDB root account. Check that MariaDB is listening locally: ```bash sudo ss -ltnp | grep 3306 || true ``` Do not open TCP port `3306` in UFW or another public firewall for this architecture. **Verify:** `sudo mariadb -e "SELECT VERSION();"` should return the database version, and there should be no public firewall rule exposing port `3306`. ## Step 4 — Create a Dedicated WordPress Database and User Generate a strong database password and save it in your password manager: ```bash openssl rand -hex 24 ``` Open the MariaDB shell: ```bash sudo mariadb ``` Create the database and a local-only user. Replace `use_a_unique_password` with the password you generated: ```sql CREATE DATABASE wordpress CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; CREATE USER 'wpuser'@'localhost' IDENTIFIED BY 'use_a_unique_password'; GRANT ALL PRIVILEGES ON wordpress.* TO 'wpuser'@'localhost'; FLUSH PRIVILEGES; EXIT; ``` Test the WordPress account: ```bash mariadb -u wpuser -p wordpress ``` Then run: ```sql SELECT DATABASE(), CURRENT_USER(); EXIT; ``` **Verify:** The query should show `wordpress` as the active database and `wpuser@localhost` as the current user. ## Step 5 — Download WordPress from the Official Source Download the current WordPress archive from WordPress.org: ```bash cd /tmp curl -fLO https://wordpress.org/latest.tar.gz ``` Extract it: ```bash tar -xzf latest.tar.gz ``` Create the site directory and copy the WordPress files: ```bash sudo mkdir -p /var/www/example.com/public sudo cp -a /tmp/wordpress/. /var/www/example.com/public/ ``` Confirm the expected core files exist: ```bash ls -l /var/www/example.com/public/wp-admin/index.php ls -l /var/www/example.com/public/wp-includes/version.php ``` You can inspect the downloaded WordPress version with: ```bash grep -m1 '\$wp_version =' /var/www/example.com/public/wp-includes/version.php ``` **Verify:** `wp-admin/index.php` and `wp-includes/version.php` should both exist, and the version file should contain a WordPress version value. ## Step 6 — Configure wp-config.php and Authentication Salts Create `wp-config.php` from the sample: ```bash sudo cp /var/www/example.com/public/wp-config-sample.php \ /var/www/example.com/public/wp-config.php ``` Open the file: ```bash sudo nano /var/www/example.com/public/wp-config.php ``` Set the database values created in Step 4: ```php define( 'DB_NAME', 'wordpress' ); define( 'DB_USER', 'wpuser' ); define( 'DB_PASSWORD', 'use_a_unique_password' ); define( 'DB_HOST', 'localhost' ); define( 'DB_CHARSET', 'utf8mb4' ); ``` Generate fresh WordPress authentication keys and salts from the official API: ```bash curl -s https://api.wordpress.org/secret-key/1.1/salt/ ``` Replace the placeholder authentication key and salt definitions in `wp-config.php` with the generated values. Disable the built-in plugin and theme file editors by adding this above the final stop-editing comment: ```php define( 'DISALLOW_FILE_EDIT', true ); ``` This removes a common code-editing path from the WordPress dashboard if an administrator account is compromised. **Verify:** Confirm the database constants exist without printing the password to your terminal history again: ```bash sudo grep -E "DB_NAME|DB_USER|DB_HOST|DISALLOW_FILE_EDIT" \ /var/www/example.com/public/wp-config.php ``` You should see the expected database name, user, host, and `DISALLOW_FILE_EDIT` setting. ## Step 7 — Apply Safer WordPress Ownership and File Permissions WordPress's hardening guidance recommends keeping application code writable by the administrative user and granting the web server write access only where the site actually needs it. Use your SSH user as the owner and `www-data` as the group: ```bash sudo chown -R "$USER":www-data /var/www/example.com ``` Keep the WordPress tree read-only to the web-server group by default: ```bash sudo find /var/www/example.com -type d -exec chmod 750 {} \; sudo find /var/www/example.com -type f -exec chmod 640 {} \; ``` Create the uploads directory and grant PHP-FPM group write access only there: ```bash sudo mkdir -p /var/www/example.com/public/wp-content/uploads sudo chown -R "$USER":www-data \ /var/www/example.com/public/wp-content/uploads sudo find /var/www/example.com/public/wp-content/uploads \ -type d -exec chmod 770 {} \; sudo find /var/www/example.com/public/wp-content/uploads \ -type f -exec chmod 660 {} \; ``` Keep plugin and theme code non-writable by the web-server group unless a specific, documented workflow requires otherwise. If a plugin needs a cache or temporary directory, grant write access to that directory only instead of recursively opening all of `wp-content`. Keep `wp-config.php` restricted: ```bash sudo chmod 640 /var/www/example.com/public/wp-config.php ``` Do not use `chmod 777` on WordPress files or directories. With this model, dashboard-based plugin, theme, or core updates may require your administrative deployment workflow rather than broad PHP-FPM write access to application code. **Verify:** Run: ```bash stat -c '%U %G %a %n' \ /var/www/example.com/public/wp-config.php \ /var/www/example.com/public/wp-content \ /var/www/example.com/public/wp-content/uploads ``` The WordPress code tree should remain non-writable by the web-server group, while `uploads` is explicitly writable by `www-data`. ## Step 8 — Configure Nginx for WordPress and Block PHP in Uploads Create the Nginx server block: ```bash sudo nano /etc/nginx/sites-available/example.com ``` Add: ```nginx server { listen 80; listen [::]:80; server_name example.com www.example.com; root /var/www/example.com/public; index index.php index.html; client_max_body_size 64M; access_log /var/log/nginx/example.com.access.log; error_log /var/log/nginx/example.com.error.log; location / { try_files $uri $uri/ /index.php?$args; } location = /wp-config.php { deny all; } location ~* /(?:uploads|files)/.*\.php$ { deny all; } location ~ /\.(?!well-known).* { deny all; } location ~ \.php$ { include snippets/fastcgi-php.conf; fastcgi_pass unix:/run/php/php8.3-fpm.sock; } location = /xmlrpc.php { deny all; } location ~* \.(css|gif|ico|jpeg|jpg|js|png|svg|webp|woff|woff2)$ { expires 7d; access_log off; } } ``` The `try_files` rule supports WordPress pretty permalinks. The uploads restriction prevents a `.php` file placed under common upload paths from being executed by PHP-FPM. The `xmlrpc.php` block is optional: remove it if you use Jetpack, the WordPress mobile app, remote publishing, or another XML-RPC-dependent integration. Enable the site and remove the default site symlink: ```bash sudo ln -s /etc/nginx/sites-available/example.com \ /etc/nginx/sites-enabled/example.com sudo rm -f /etc/nginx/sites-enabled/default ``` Test and reload Nginx: ```bash sudo nginx -t sudo systemctl reload nginx ``` **Verify:** `sudo nginx -t` should report that the configuration syntax is successful, and `curl -I http://127.0.0.1 -H 'Host: example.com'` should return an HTTP response from the new server block. ## Step 9 — Configure UFW Without Locking Out SSH Check UFW first: ```bash sudo ufw status ``` If UFW is active, allow the existing SSH path before changing web rules: ```bash sudo ufw allow OpenSSH sudo ufw allow 'Nginx Full' sudo ufw status ``` Do not open MariaDB port `3306` publicly for this single-VM WordPress setup. If UFW is currently inactive, review your SSH access and firewall policy before enabling it. Do not blindly enable a firewall on a remote server without confirming that your management path is allowed. **Verify:** When UFW is active, the status should allow SSH plus HTTP/HTTPS and should not contain a public MariaDB rule. ## Step 10 — Enable HTTPS with Let's Encrypt Install Certbot and its Nginx plugin: ```bash sudo apt install -y certbot python3-certbot-nginx ``` Request a certificate and configure an HTTP-to-HTTPS redirect for the hostnames that resolve to this VM: ```bash sudo certbot --nginx --redirect \ -d example.com \ -d www.example.com ``` If you do not use `www.example.com`, request only `-d example.com`. Certbot validation must succeed for every hostname included in the request. Check the certificate and renewal path: ```bash sudo certbot certificates sudo certbot renew --dry-run ``` For deeper certificate troubleshooting, use [How to Secure Nginx with Let's Encrypt on Ubuntu 24.04](/learn/tutorials/secure-nginx-lets-encrypt-ubuntu-24-04). **Verify:** Open `https://example.com` or run: ```bash curl -I https://example.com ``` The connection should complete over HTTPS, and an HTTP request should redirect to HTTPS after Certbot configures the site. ## Step 11 — Complete the WordPress Browser Installation Open: ```text https://example.com ``` Choose the site language and enter: - Site title - Administrator username - Strong administrator password - Administrator email address - Search-engine visibility preference Avoid predictable administrator usernames such as `admin`. Complete the installer, then sign in at: ```text https://example.com/wp-admin/ ``` After login, immediately review **Dashboard → Updates** and apply required WordPress, theme, and plugin updates using an update method compatible with the file-permission model from Step 7. **Verify:** You should be able to sign in to `/wp-admin/`, open the site homepage in another browser window, and load a WordPress page over HTTPS without a certificate warning. :::cta Deploy Your Server Deploy a Raff Linux VM and use this tutorial to build a self-managed WordPress VPS with Nginx, PHP-FPM, MariaDB, and HTTPS. ::: ## Step 12 — Verify WordPress, Nginx, PHP-FPM, and the Uploads Restriction Run the service checks: ```bash systemctl is-active nginx mariadb php8.3-fpm ``` Check the public HTTP and HTTPS behavior: ```bash curl -I http://example.com curl -I https://example.com curl -I https://example.com/wp-login.php ``` The HTTP request should redirect to HTTPS. The HTTPS homepage and login page should return a valid application response. Now test the Nginx uploads restriction with a temporary PHP probe: ```bash sudo mkdir -p /var/www/example.com/public/wp-content/uploads printf '%s\n' '' \ | sudo tee /var/www/example.com/public/wp-content/uploads/raff-php-test.php >/dev/null curl -i https://example.com/wp-content/uploads/raff-php-test.php sudo rm -f /var/www/example.com/public/wp-content/uploads/raff-php-test.php ``` You want Nginx to deny the request rather than execute the PHP file. Check recent service errors: ```bash sudo tail -n 50 /var/log/nginx/example.com.error.log sudo journalctl -u php8.3-fpm -n 50 --no-pager sudo journalctl -u mariadb -n 50 --no-pager ``` **Verify:** All three services should be active, HTTP should redirect to HTTPS, the WordPress homepage and login should load, and the uploads PHP probe should be denied. ## Step 13 — Configure Backups and Production Maintenance A working WordPress installation is not complete until you can restore both the database and site files. At minimum, back up: - the MariaDB `wordpress` database - `/var/www/example.com/public` - the Nginx site configuration - any external DNS or application configuration needed for recovery Create a manual database backup example: ```bash mkdir -p ~/backups mariadb-dump -u wpuser -p wordpress | gzip > ~/backups/wordpress.sql.gz ``` Create a file backup example: ```bash tar -czf ~/backups/wordpress-files.tar.gz \ /var/www/example.com/public ``` Store at least one backup away from the VM. Raff [Data Protection](/products/data-protection) can protect the server layer, while [Object Storage](/products/object-storage) can be used as an off-server destination when your backup workflow supports S3-compatible storage. A backup should not be considered reliable until you have tested restoring it. For ongoing maintenance: - keep Ubuntu, PHP, WordPress core, themes, and plugins patched - remove unused themes and plugins - use multi-factor authentication for administrator accounts - monitor disk usage before large imports or backup jobs - review Nginx, PHP-FPM, and MariaDB logs when application behavior changes - add caching only after measuring the actual bottleneck **Verify:** Confirm both backup files exist and are non-empty: ```bash ls -lh ~/backups/wordpress.sql.gz ~/backups/wordpress-files.tar.gz gzip -t ~/backups/wordpress.sql.gz ``` Then prove the database dump can be restored into a disposable database: ```bash sudo mariadb -e \ "DROP DATABASE IF EXISTS wordpress_restore_test; CREATE DATABASE wordpress_restore_test CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;" gunzip -c ~/backups/wordpress.sql.gz \ | sudo mariadb wordpress_restore_test sudo mariadb -e \ "SELECT COUNT(*) AS table_count FROM information_schema.tables WHERE table_schema='wordpress_restore_test';" ``` The table count should be greater than zero for a populated WordPress database. Remove only the disposable restore target after validation: ```bash sudo mariadb -e "DROP DATABASE wordpress_restore_test;" ``` For a production recovery rehearsal, also restore the WordPress files into an isolated path and verify the site against the restored database without touching production. ## Step 14 — Clean Up or Roll Back the Installation If the installation is working and you are keeping it, remove the downloaded archive and extracted temporary source: ```bash rm -rf /tmp/wordpress /tmp/latest.tar.gz ``` If you are abandoning this test installation, the following rollback is destructive. Back up anything you need first. Disable the Nginx site: ```bash sudo rm -f /etc/nginx/sites-enabled/example.com sudo nginx -t sudo systemctl reload nginx ``` Remove the site files only when you are certain they are no longer needed: ```bash sudo rm -rf /var/www/example.com ``` Drop the WordPress database and user: ```bash sudo mariadb ``` Then run: ```sql DROP DATABASE wordpress; DROP USER 'wpuser'@'localhost'; EXIT; ``` If you also want to remove the Let's Encrypt certificate for this hostname, review the installed certificates first: ```bash sudo certbot certificates ``` Then delete only the certificate name that belongs to this retired site: ```bash sudo certbot delete --cert-name example.com ``` **Verify:** After a full rollback, the Nginx site symlink should be absent, the site directory should be removed, and `SHOW DATABASES LIKE 'wordpress';` should return no WordPress database. ## Conclusion You now have WordPress running on Ubuntu 24.04 with Nginx, PHP 8.3, MariaDB, restricted configuration permissions, HTTPS, and an Nginx rule that blocks PHP execution from the uploads path. The installation also has a dedicated local database account, an explicit end-to-end verification flow, and a backup and rollback path. This setup is a practical WordPress VPS pattern when you want more control than shared hosting. Compare current [Raff Linux VM](/products/linux-vm) configurations and [Raff pricing](/pricing) for plan sizes and billing terms; for WordPress, start with at least 2 GB RAM and size upward based on PHP workers, database usage, plugins, imports, and traffic. If you are still deciding whether a VPS is the right operating model, read [WordPress VPS Hosting: When It Beats Shared and Managed Hosting](/learn/guides/wordpress-vps-hosting). For the underlying server stack, see [How to Set Up a LEMP Stack on Ubuntu 24.04](/learn/tutorials/set-up-lemp-stack-ubuntu-24-04), and use [Data Protection](/products/data-protection) or [Object Storage](/products/object-storage) as part of a tested backup strategy. ## Sources - [WordPress requirements](https://wordpress.org/about/requirements/) - [WordPress hardening](https://developer.wordpress.org/advanced-administration/security/hardening/) - [WordPress releases](https://wordpress.org/download/releases/) --- ### How to Set Up a LEMP Stack on Ubuntu 24.04 URL: https://rafftechnologies.com/learn/tutorials/set-up-lemp-stack-ubuntu-24-04 Description: Set up a LEMP stack on Ubuntu 24.04 with Nginx, PHP 8.3, MariaDB, secure database access, HTTPS, verification, and rollback steps. A LEMP stack combines Linux, Nginx, MariaDB or MySQL, and PHP-FPM to run PHP websites and applications. On Ubuntu 24.04, you can build the stack from the standard Ubuntu repositories without adding third-party package sources. This tutorial sets up a production-oriented LEMP stack on a Raff Technologies Linux VM, creates a dedicated local database user, connects Nginx to PHP-FPM, verifies PHP execution, adds a basic firewall and HTTPS path, and finishes with end-to-end checks and cleanup instructions. The current Ubuntu 24.04 package line uses PHP 8.3, and Ubuntu's Noble package repository provides MariaDB 10.11. You can verify those package baselines in the official [Ubuntu PHP package listing](https://packages.ubuntu.com/noble/php) and [Ubuntu MariaDB package listing](https://packages.ubuntu.com/noble/mariadb-server). This guide uses MariaDB, but the same LEMP architecture can use MySQL when your application requires it. You need an Ubuntu 24.04 server with at least 2 GB RAM, SSH access, and a non-root user with sudo privileges. A domain is optional for the initial stack test but required for the HTTPS step. ## Step 1 — Update Ubuntu and Confirm the Server Baseline Update package metadata and install available updates: ```bash sudo apt update sudo apt upgrade -y ``` Check the operating system release: ```bash cat /etc/os-release ``` If the upgrade reports that a reboot is required, reboot and reconnect before continuing: ```bash sudo reboot ``` **Verify:** `/etc/os-release` should identify Ubuntu 24.04, and `sudo apt update` should complete without repository errors. ## Step 2 — Install and Start Nginx Install Nginx: ```bash sudo apt install -y nginx ``` Enable it at boot and start it now: ```bash sudo systemctl enable --now nginx ``` Check the service and installed version: ```bash systemctl is-active nginx nginx -v ``` If UFW is already active, allow HTTP and HTTPS traffic only after confirming that your SSH rule is present: ```bash sudo ufw status sudo ufw allow OpenSSH sudo ufw allow 'Nginx Full' ``` For a deeper Nginx-only setup, see [How to Install Nginx on Ubuntu 24.04](/learn/tutorials/install-nginx-ubuntu-24-04). **Verify:** `systemctl is-active nginx` should return `active`, and `curl -I http://127.0.0.1` should return an HTTP response from Nginx. ## Step 3 — Install and Secure MariaDB Install MariaDB from the Ubuntu repositories: ```bash sudo apt install -y mariadb-server ``` Enable and start the service: ```bash sudo systemctl enable --now mariadb ``` Run MariaDB's security helper: ```bash sudo mariadb-secure-installation ``` For a single-server LEMP stack, keep local administrative access protected, remove anonymous users and the test database, and avoid unnecessary remote root access. Applications should never connect using the MariaDB root account. Check the database version: ```bash sudo mariadb -e "SELECT VERSION();" ``` Do not expose MariaDB port `3306` publicly for this architecture. **Verify:** `systemctl is-active mariadb` should return `active`, and the version query should return a MariaDB 10.11 release from the Ubuntu 24.04 package line. ## Step 4 — Install PHP-FPM and Common PHP Extensions Install PHP-FPM, the CLI, MySQL/MariaDB support, and common PHP modules: ```bash sudo apt install -y \ php-fpm \ php-cli \ php-mysql \ php-curl \ php-gd \ php-intl \ php-mbstring \ php-xml \ php-zip \ php-bcmath ``` Ubuntu 24.04's standard PHP branch is 8.3. Check the CLI version and PHP-FPM service: ```bash php -v systemctl is-active php8.3-fpm ``` Confirm the PHP-FPM Unix socket exists: ```bash ls -l /run/php/php8.3-fpm.sock ``` If you deliberately install another PHP branch later, update both the service name and Nginx socket path consistently. **Verify:** `php -v` should report PHP 8.3.x on the standard Ubuntu 24.04 package line, `php8.3-fpm` should be active, and `/run/php/php8.3-fpm.sock` should exist. ## Step 5 — Create a Dedicated Database and Application User Generate a strong password and save it in a password manager: ```bash openssl rand -hex 24 ``` Open MariaDB: ```bash sudo mariadb ``` Create an application database and local-only user. Replace `use_a_unique_password` with the generated password: ```sql CREATE DATABASE example_app CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; CREATE USER 'example_user'@'localhost' IDENTIFIED BY 'use_a_unique_password'; GRANT ALL PRIVILEGES ON example_app.* TO 'example_user'@'localhost'; FLUSH PRIVILEGES; EXIT; ``` Test the application account: ```bash mariadb -u example_user -p example_app ``` Then run: ```sql SELECT DATABASE(), CURRENT_USER(); EXIT; ``` **Verify:** The query should show `example_app` and `example_user@localhost`. Keep port `3306` closed to the public internet. ## Step 6 — Create the Website Directory This tutorial uses `example.com`. Replace it with your domain if you have one. Create the document root: ```bash sudo mkdir -p /var/www/example.com/public sudo chown -R "$USER":www-data /var/www/example.com sudo find /var/www/example.com -type d -exec chmod 750 {} \; sudo find /var/www/example.com -type f -exec chmod 640 {} \; ``` Create a basic HTML page: ```bash cat <<'EOF' | sudo tee /var/www/example.com/public/index.html >/dev/null LEMP stack ready

Nginx is serving the LEMP site

EOF ``` **Verify:** Run `ls -ld /var/www/example.com/public` and confirm that the directory exists, then confirm `index.html` is present with `ls -l /var/www/example.com/public/index.html`. ## Step 7 — Configure the Nginx Server Block for PHP-FPM Create the site configuration: ```bash sudo nano /etc/nginx/sites-available/example.com ``` Add: ```nginx server { listen 80; listen [::]:80; server_name example.com www.example.com; root /var/www/example.com/public; index index.php index.html; access_log /var/log/nginx/example.com.access.log; error_log /var/log/nginx/example.com.error.log; location / { try_files $uri $uri/ =404; } location ~ \.php$ { include snippets/fastcgi-php.conf; fastcgi_pass unix:/run/php/php8.3-fpm.sock; } location ~ /\.(?!well-known).* { deny all; } } ``` Enable the site and remove the default site symlink: ```bash sudo ln -s /etc/nginx/sites-available/example.com \ /etc/nginx/sites-enabled/example.com sudo rm -f /etc/nginx/sites-enabled/default ``` Test before reloading: ```bash sudo nginx -t sudo systemctl reload nginx ``` Never reload Nginx after a failed `nginx -t` check. **Verify:** `sudo nginx -t` should report successful syntax, and this request should return the site response: ```bash curl -I http://127.0.0.1 -H 'Host: example.com' ``` ## Step 8 — Verify PHP Processing Without Leaving phpinfo() Exposed Create a temporary PHP test file: ```bash cat <<'EOF' | sudo tee /var/www/example.com/public/health.php >/dev/null "$DB_TEST" <<'PHP' PDO::ERRMODE_EXCEPTION] ); echo "database-ok\n"; PHP ``` Replace `use_a_unique_password` with the application database password, then verify the file permissions before running it: ```bash stat -c '%a %U:%G %n' "$DB_TEST" php "$DB_TEST" ``` The file mode should be `600`, and PHP should print: ```text database-ok ``` Remove the temporary file immediately: ```bash rm -f "$DB_TEST" unset DB_TEST ``` Because the test runs outside the public web root and the temporary file is restricted to its owner, the database credential is not intentionally exposed over HTTP or to unrelated local users. **Verify:** PHP prints `database-ok`, the temporary file was mode 600 while it existed, and the file is removed after the test. ## Step 10 — Add HTTPS When the Domain Points to the VM If you have a public domain, verify every hostname you plan to include in the certificate before running Certbot: ```bash dig +short A example.com dig +short A www.example.com dig +short AAAA example.com dig +short AAAA www.example.com ``` Only keep hostnames that resolve to this VM. If you do not use `www.example.com`, remove it from the Nginx `server_name` and from the Certbot request. Install Certbot and its Nginx plugin: ```bash sudo apt install -y certbot python3-certbot-nginx ``` Request a certificate and redirect HTTP to HTTPS for the hostnames that resolve correctly: ```bash sudo certbot --nginx --redirect \ -d example.com \ -d www.example.com ``` If you use only the apex hostname, request only `-d example.com`. Certbot validation must succeed for every hostname in the request. Check the certificate and renewal process: ```bash sudo certbot certificates sudo certbot renew --dry-run ``` For certificate troubleshooting, use [How to Secure Nginx with Let's Encrypt on Ubuntu 24.04](/learn/tutorials/secure-nginx-lets-encrypt-ubuntu-24-04). **Verify:** `curl -I https://example.com` should complete over HTTPS, and `curl -I http://example.com` should redirect to HTTPS after Certbot updates the Nginx configuration. :::cta Deploy Your Server Deploy a Raff Linux VM and use this tutorial to build a LEMP stack with Nginx, PHP-FPM, and MariaDB on Ubuntu 24.04. ::: ## Step 11 — Run the Final End-to-End LEMP Verification Check all three services: ```bash systemctl is-active nginx mariadb php8.3-fpm ``` Test the site locally through the configured hostname: ```bash curl -I http://127.0.0.1 -H 'Host: example.com' ``` Check recent service and site errors: ```bash sudo journalctl -u nginx -n 30 --no-pager sudo journalctl -u mariadb -n 30 --no-pager sudo journalctl -u php8.3-fpm -n 30 --no-pager sudo tail -n 30 /var/log/nginx/example.com.error.log ``` Confirm MariaDB is not intentionally exposed through UFW: ```bash sudo ufw status ``` For production workloads, measure actual PHP-FPM worker memory and database usage before tuning process limits. A fixed `pm.max_children` value is not portable across WordPress, Laravel, Drupal, custom PHP applications, and different plugin or request profiles. **Verify:** Nginx, MariaDB, and PHP-FPM should all be active; the configured site should return an HTTP response; logs should not show a repeating fatal configuration error; and port `3306` should not have a public firewall rule. ## Step 12 — Clean Up or Roll Back the LEMP Test Site If you are keeping the stack, there is nothing else to remove after the temporary PHP and database test files from Steps 8 and 9 are deleted. If this was only a test and you want to remove the example site, first disable the Nginx site: ```bash sudo rm -f /etc/nginx/sites-enabled/example.com sudo nginx -t sudo systemctl reload nginx ``` Remove the example files only if they are no longer needed: ```bash sudo rm -rf /var/www/example.com sudo rm -f /etc/nginx/sites-available/example.com ``` Drop the test database and user: ```bash sudo mariadb ``` Then run: ```sql DROP DATABASE example_app; DROP USER 'example_user'@'localhost'; EXIT; ``` If you issued a Let's Encrypt certificate specifically for this retired test domain, inspect certificates before deleting anything: ```bash sudo certbot certificates ``` Then delete only the certificate that belongs to the retired hostname: ```bash sudo certbot delete --cert-name example.com ``` **Verify:** After a full rollback, the Nginx site symlink and document root should be gone, and `SHOW DATABASES LIKE 'example_app';` should return no test database. ## Conclusion You now have a complete LEMP stack on Ubuntu 24.04 with Nginx serving the application, PHP-FPM handling PHP requests, and MariaDB using a dedicated local application account. The stack has explicit Nginx, PHP, database, firewall, HTTPS, end-to-end verification, and rollback paths rather than stopping after package installation. Review [Raff Linux VM](/products/linux-vm) configurations and [Raff pricing](/pricing) for current server sizes and terms. For a LEMP stack that runs Nginx, PHP-FPM, and MariaDB on one server, start with at least 2 GB RAM and size upward based on PHP concurrency, database usage, application complexity, and traffic. If you are deciding whether this stack belongs on a VPS, continue with [VPS for Web Hosting: What Small Teams Should Know](/learn/guides/vps-for-web-hosting). If you need database lifecycle management separated from the VM, compare this architecture with [managed versus self-hosted databases](/learn/guides/managed-vs-self-hosted-databases). For a concrete application deployment on top of this stack, continue with [WordPress on Ubuntu 24.04 with Nginx](/learn/tutorials/install-wordpress-ubuntu-24-04-nginx). --- ## Guides ### Long-Running Serverless Functions for AI, ETL, and Batch Jobs URL: https://rafftechnologies.com/learn/guides/long-running-serverless-functions-ai-etl-batch Description: Learn when to use long-running serverless functions for AI, ETL, batch, cron, and storage events, and when Raff VM is a better fit. Long-running serverless functions are functions designed for workloads that need minutes or hours to complete instead of a short request-response window. For small teams, this matters because not every background task fits into a tiny handler. AI inference, document processing, file conversion, ETL jobs, exports, imports, streaming tasks, and data cleanup can run longer than a normal web request. Traditionally, teams moved those jobs to a VM or worker server because their serverless platform had strict duration limits or pricing that became difficult to forecast. Raff Technologies gives teams another option with [Raff Functions](/products/serverless-functions): run event-driven jobs as functions with timeouts up to 1 hour by default and up to 24 hours on request. The same product also supports HTTP live URLs, timezone-aware cron schedules, one-off future runs, object-storage events, standard handlers, logs and metrics, and pricing based on memory plus active CPU. This guide explains when a long-running serverless function makes sense, when a VM or worker server is still better, and how to design AI, ETL, and batch jobs so they remain observable, retryable, and cost-aware. If you are still comparing deployment models, read [Serverless Functions vs VMs: What Small Teams Should Choose](/learn/guides/serverless-functions-vs-vms-small-teams) and [Serverless Function Pricing: CPU, Memory, Requests, and Egress](/learn/guides/serverless-function-pricing-cpu-memory-egress) first. ## Long-running functions change the serverless decision Serverless functions are often associated with short tasks: webhooks, API handlers, cron jobs, and quick file events. ![Diagram showing AI ETL batch file processing cron and object storage workloads running on long-running Raff Functions](https://raff-images.s3.raffusercloud.com/long_running_functions_workload_map_webp_4d3de92f99.png) That is still a strong use case. But many real SaaS tasks do not finish in a few seconds. Examples include: - AI inference - ETL jobs - Batch imports - CSV processing - PDF generation - Image or media processing - Large report exports - Data enrichment - Web scraping jobs - Scheduled database cleanup - Object-storage file processing - Long third-party API syncs - Streaming or chunked responses - Customer data migration tasks When serverless duration is too short, teams often create a second system: a worker VM, queue worker, batch container, or Kubernetes job. That can be the right decision, but it also adds another operational layer. Long-running functions reduce that pressure. If a job is event-driven, isolated, and can write progress or output to a durable service, it may not need a full worker server. The question is not only "Can a function run this long?" The better question is: > Can this long task run safely as an isolated, observable, retryable function? If yes, long-running functions can simplify the architecture. ## The quick decision framework Use this table before choosing a long-running function, VM, worker, or Kubernetes job. | Workload | Better default | Why | |---|---|---| | AI inference triggered by request or event | Long-running function | Event-driven and bounded | | Nightly ETL job | Function or worker VM | Depends on runtime, duration, and dependencies | | Always-on queue worker | VM or Kubernetes | Constant work may fit capacity-based compute | | Large file conversion after upload | Function | Storage event can trigger isolated processing | | Long report export | Function | Output can be written to object storage | | Continuous stream processor | VM or Kubernetes | Persistent process may be cleaner | | One-time migration | Function if bounded; VM if manual control is needed | Choose by debugging and runtime needs | | Webhook with heavy downstream processing | Function plus queue/worker | Return quickly and process separately | | CPU-heavy batch job all day | VM or Kubernetes | Always-on compute may be easier to forecast | | Short scheduled cleanup | Function | Cron trigger and scale-to-zero fit well | | Complex multi-step workflow | Function chain, queue, or workflow tool | Needs state and failure handling | | Job needing SSH debugging | VM | Full server access helps investigation | A useful rule: > Use a long-running function when the task is event-driven and bounded. Use a VM when the environment must stay alive. Long duration alone does not decide the architecture. Workload shape does. ## Good long-running function candidates A long-running function works best when the job has a clear input, clear output, and clear completion point. ### AI inference AI inference can take longer when models, prompts, files, or external APIs are involved. A function can receive the request, run the inference step, write the result to a database or object storage, and return a status or output. ```text Trigger ↓ Raff Function ↓ AI inference or model/API call ↓ Database status + Object Storage output ``` This is useful when inference is occasional, user-triggered, or bursty. ### ETL jobs ETL tasks extract data, transform it, and load it somewhere else. A function can run on a schedule or one-off trigger, process a bounded dataset, and write results to a database or object storage. ```text Cron schedule ↓ Function extracts data ↓ Function transforms records ↓ Database or Object Storage receives output ``` This works best when the ETL job can be chunked or bounded. ### File processing after upload Object-storage events are a natural trigger for long-running functions. ```text File uploaded ↓ Object Storage event ↓ Function processes file ↓ Output saved to Object Storage ↓ Metadata saved to database ``` Examples: - Resize images - Convert PDFs - Parse CSV files - Generate thumbnails - Extract metadata - Validate uploaded files - Compress or transform assets ### Batch exports and reports Large reports should not block the main application server. A function can generate the report, store it in object storage, and update the database when the report is ready. ```text User requests export ↓ Function generates file ↓ Object Storage stores report ↓ Database stores status and download link ``` This keeps the web app responsive while the longer job runs independently. ## When a VM or worker is still better Long-running functions do not replace every worker server. ![Decision diagram comparing long-running Raff Functions with Raff VM for bounded jobs and always-on workers](https://raff-images.s3.raffusercloud.com/long_running_functions_vs_vm_decision_webp_76f096910d.png) Use a VM, worker VM, or Kubernetes worker when the job needs: - Constant processing - Always-on queue consumption - SSH debugging - Complex system packages - Heavy local dependencies - Persistent local state - Long-lived TCP connections - Custom networking - GPU or specialized host access - Manual inspection during runtime - Several processes coordinating together - A stable filesystem across jobs - Capacity-based cost control A constant worker may be cleaner on a [Raff VM](/products/raff-vm): ```text Raff VM ↓ Worker process ↓ Queue ↓ Managed Database + Object Storage ``` That pattern is still valid when work is continuous. If the worker is busy all day, usage-based function execution may not be the simplest or cheapest operating model. A long-running function is strongest when the workload starts from a clear trigger and can finish independently. A VM is strongest when the service itself needs to keep running. :::cta Deploy a Raff VM Use Raff VM when long-running work needs SSH access, custom packages, persistent services, or always-on worker capacity. ::: ## Design long-running functions around durable state Long-running functions should not keep important state only in memory. A job may run for minutes or hours. During that time, the platform, network, external API, database, or code path can fail. The function needs a way to resume, retry, or at least explain what happened. ![Architecture diagram showing Raff Function with Managed Database for job state and Object Storage for input and output files](https://raff-images.s3.raffusercloud.com/long_running_function_durable_state_architecture_webp_85fde9f792.png) Use durable state for: - Job status - Job ID - Input location - Output location - Start time - Last progress marker - Failure reason - Retry count - User/account ownership - Result metadata - Audit trail A simple model: ```text Database = job status and metadata Object Storage = input and output files Function = execution logic ``` That keeps the function stateless enough to retry and observable enough to debug. A good job table might track: | Field | Purpose | |---|---| | job_id | Unique job identifier | | account_id | Tenant or customer owner | | status | queued, running, succeeded, failed | | input_uri | Object storage path or source reference | | output_uri | Result file path | | progress | Optional percentage or step marker | | attempts | Retry count | | error_message | Safe failure summary | | started_at | Runtime visibility | | finished_at | Completion visibility | The function should not be the only place that knows whether the job succeeded. ## Store files and artifacts outside the function Long-running functions often handle files. Do not depend on local function storage as the final home for generated files, uploads, or artifacts. Use [Raff Object Storage](/products/object-storage) for durable outputs. Good object-storage outputs include: - Generated PDFs - Exported CSV files - Processed images - Model output files - ETL artifacts - Validation reports - Import logs - Compressed archives - Transformed media - Batch results A clean file-processing pattern: ```text Input file in Object Storage ↓ Function reads input ↓ Function writes output ↓ Database stores metadata ``` This makes the job easier to retry. If a function fails after writing partial output, the database can mark the job failed and the next run can decide whether to overwrite, resume, or write a new object. For related storage decisions, read [App Uploads: VM Disk vs Object Storage for SaaS Teams](/learn/guides/app-uploads-vm-disk-vs-object-storage). ## Make long-running jobs idempotent Idempotency means the same job can run more than once without creating duplicate or corrupted results. This is important for long-running functions because retries can happen. Users may click the same action twice. External APIs may send duplicate events. A function may fail after doing part of the work. A job may be restarted manually. A long-running job should answer: - Can the same job ID run twice safely? - Can the same input file be processed twice? - Can the output object be overwritten safely? - Does the database update use a unique key? - Are duplicate webhooks ignored? - Are partial outputs cleaned up? - Can the job resume from a checkpoint? - Is a failed job distinguishable from an unfinished job? Common idempotency techniques: | Technique | Use | |---|---| | Job IDs | Prevent duplicate job creation | | Unique database constraints | Prevent duplicate records | | Output paths with versioning | Avoid overwriting the wrong file | | Status transitions | Control running, succeeded, failed states | | Checkpoints | Resume large jobs | | Input hashes | Detect repeated file processing | | Retry counters | Prevent infinite retries | A long-running function should be designed as if it may run again. That mindset prevents many production issues. ## Break very large work into chunks A single long-running function can be useful, but not every job should be one huge run. If a task processes 5 million rows, thousands of files, or a large customer dataset, chunking may be safer. Chunking helps with: - Retry behavior - Partial progress - Memory control - Parallelism - Cost visibility - Failure isolation - Time-window control - Debugging A chunked pattern: ```text Parent job ↓ Create chunk jobs ↓ Function processes each chunk ↓ Database tracks progress ↓ Final function merges or marks complete ``` Chunking is useful for: - Large CSV imports - Customer data migrations - ETL batches - Backfills - Image sets - Search index rebuilds - Report generation - AI batch inference Do not chunk too early for small jobs. Chunk when the job size makes retries or progress tracking important. A good rule: > If restarting from zero would hurt, add checkpoints or chunks. ## Use cron for scheduled long-running jobs Cron triggers are useful when long work happens on a schedule. Raff Functions supports timezone-aware cron schedules, which can fit recurring jobs such as: - Nightly ETL - Daily reports - Weekly summaries - Hourly syncs - Cleanup jobs - Expired subscription checks - Data warehouse exports - Cache refreshes - Security scans - Scheduled file processing A scheduled long-running function should still be bounded. Before running it daily, define: - Expected runtime - Maximum runtime - Input size - Output location - Failure notification path - Retry behavior - Duplicate-run prevention - Whether overlapping runs are allowed - Whether the job can skip if the last run is still active For example: ```text Daily 02:00 ↓ Check whether previous job is still running ↓ Create new job record ↓ Process dataset ↓ Write output ↓ Mark job succeeded or failed ``` Cron is simple. Production cron needs guardrails. ## Use object-storage events for file-driven jobs Object-storage events are useful when work should start after a file arrives. Examples: - User uploads a video - Customer uploads a CSV - App writes a PDF for processing - Backup archive lands in a bucket - External system drops files into a prefix - Image upload needs thumbnails - Import folder receives a new file A good pattern: ```text Object uploaded to bucket prefix ↓ Raff Function starts ↓ Function validates file ↓ Function processes file ↓ Function writes output to Object Storage ↓ Function updates database status ``` Use prefix filters to avoid triggering functions on every object in a bucket. For example, input files can land under: ```text incoming/ ``` and outputs can be written to: ```text processed/ ``` This prevents output files from retriggering the same function by accident. File-driven jobs should also validate file type, size, tenant ownership, and expected schema before processing. ## Logs and metrics are part of long-running function design Long-running functions need more than "it failed." A job that runs for 20 minutes should produce enough visibility to answer: - When did it start? - What input did it process? - Which customer/account owned the job? - Which step is running? - How many records were processed? - What external dependency was slow? - What failed? - Was the failure safe to retry? - Did the function write any output? - How long did each phase take? Raff Functions includes logs and metrics for every invocation, with live log tail, search and level filters, 14-day retention, count, p50, p95, and error rate per function. For long-running jobs, log at important boundaries: ```text job_started input_validated chunk_started chunk_completed output_written database_updated job_completed job_failed ``` Avoid logging sensitive data. Log identifiers, counts, timings, and safe error summaries. Good logs make long-running functions safer because the team can understand progress without SSH access. ## Cost planning for long-running functions Long-running functions need cost planning before launch. The main cost inputs are: - Invocation count - Average duration - Memory setting - Active CPU time - Optional warm instance behavior - Retry frequency - Data read and write patterns - Whether work can be chunked Raff Functions bills memory and active CPU. Requests and egress are free. That means the cost conversation should focus on runtime size and compute behavior. Ask: - Is the job CPU-heavy or I/O-heavy? - Does more memory reduce runtime? - Does the job wait on external APIs? - Can the job be split into smaller chunks? - How often will it run? - What happens during retries? - What spend cap should protect the account? - Would a VM be cheaper if the job runs constantly? A long-running function can be cost-effective for bursty or scheduled jobs. A VM may be cleaner for work that runs all day. For the full pricing discussion, read [Serverless Function Pricing: CPU, Memory, Requests, and Egress](/learn/guides/serverless-function-pricing-cpu-memory-egress). :::cta View Raff Pricing Compare Raff Functions and Raff VM pricing before choosing a long-running function or always-on worker. ::: ## Security and access should be scoped per job Long-running functions often touch sensitive systems: databases, object storage, customer files, internal APIs, or third-party credentials. Do not give every function broad access. Use scoped access for: - Database credentials - Object storage buckets - API tokens - Environment variables - Customer-specific data - Internal service endpoints A file-processing function should not automatically have access to every bucket. A reporting function should not automatically have write access to unrelated systems. An ETL function should not expose credentials through logs. Raff Functions supports bindings to Raff Managed Databases and Raff Object Storage with scoped credentials. Use those bindings to keep each function's access focused on what the job actually needs. For production, also define: - Who can deploy the function - Who can view logs - Who can change triggers - Who can rotate credentials - Who owns the spend cap - Who receives failure alerts Long-running jobs often have wider impact than small handlers. Treat their access accordingly. ## A practical Raff architecture for long-running functions A strong Raff architecture keeps compute, state, and files separated. ```text HTTP / cron / object-storage event ↓ Raff Function ↓ Raff Managed Database = job status and durable records ↓ Raff Object Storage = input and output files ↓ Raff VM or Kubernetes = optional always-on workers ``` This architecture gives each layer a clear job: | Layer | Responsibility | |---|---| | Raff Function | Executes the event-driven task | | Managed Database | Stores status, metadata, records, and progress | | Object Storage | Stores files, artifacts, and outputs | | Raff VM | Runs persistent workers or full server environments | | Kubernetes | Runs orchestrated services when cluster coordination is needed | A small team does not need all layers on day one. Start with the simplest version: ```text Raff Function ↓ Database ↓ Object Storage ``` Add a VM or Kubernetes only when the workload becomes constant, complex, or coordination-heavy. ## Common mistakes to avoid ### Treating a long function like a web request A job that runs for minutes or hours needs status tracking, progress, and failure handling. Do not make users wait on a browser tab for a long operation. ### Storing output only inside the function Generated files should go to object storage. Job metadata should go to a database. The function should not be the final storage layer. ### Forgetting retries and duplicate runs Long-running jobs can fail after partial progress. Design job IDs, status transitions, idempotent writes, and retry rules before production. ### Processing huge datasets as one block If restarting from zero would be painful, split the work into chunks. Chunking improves retry behavior and progress visibility. ### Running constant work as functions without checking cost If the job runs all day, a VM or Kubernetes worker may be simpler and easier to forecast. ### Logging too much or too little Logs should show progress and failures without exposing secrets or customer data. Log job IDs, step names, counts, timings, and safe summaries. ### Giving every function broad credentials Scope credentials to the database, bucket, API, or service the function actually needs. Long-running jobs often have more access than small handlers, so access control matters. ## Long-running functions should simplify the workload A long-running function is useful when it removes operational weight without hiding complexity. Use long-running Raff Functions for AI inference, ETL, file processing, scheduled jobs, imports, exports, and batch work when the task is event-driven, bounded, observable, and writes durable state to the right layer. Use [Raff VM](/products/raff-vm) or Kubernetes when the workload is constant, needs a full server environment, requires SSH debugging, or depends on persistent local services. The safest pattern is simple: let [Raff Functions](/products/serverless-functions) execute the task, let [Raff Managed Databases](/products/managed-databases) store job state and records, and let [Raff Object Storage](/products/object-storage) store files and artifacts. Then choose the model your team can operate reliably for the next 6-12 months. :::cta Explore Raff Functions Use Raff Functions for long-running AI, ETL, batch, cron, and object-storage jobs that should run independently. ::: --- ### Cron Jobs on Serverless Functions vs Cron on a VM URL: https://rafftechnologies.com/learn/guides/serverless-cron-jobs-vs-vm-cron Description: Learn when to run cron jobs on serverless functions or VMs, with examples for scheduled tasks, reports, syncs, retries, and Raff Functions. Cron jobs on serverless functions vs cron on a VM is really a question about ownership, reliability, visibility, and workload shape. A cron job is a scheduled task. It might run every minute, every hour, every night, every Monday, or on a custom business schedule. Small teams use cron jobs for cleanup, billing checks, reports, API syncs, cache refreshes, imports, exports, and background maintenance. The problem is not cron itself. The problem is where the scheduled work should live. For Raff Technologies users, there are two clean paths: use [Raff Functions](/products/serverless-functions) when the scheduled job is event-driven, bounded, stateless, and should run only when needed; use [Raff VM](/products/raff-vm) when the scheduled job depends on a full server environment, local packages, SSH debugging, persistent services, or existing VM-based application code. This guide explains when serverless cron is the better fit, when VM cron is still the simpler choice, and how to design scheduled jobs so they do not silently become production risk. If you are still comparing the broader models, read [Serverless Functions vs VMs: What Small Teams Should Choose](/learn/guides/serverless-functions-vs-vms-small-teams) first. ## Cron jobs are simple until they become production infrastructure Cron starts as a convenience. A developer adds one scheduled script: ```text 0 2 * * * run-nightly-cleanup ``` Then the product grows. Soon the server has jobs for: - Daily reports - Subscription checks - Invoice generation - Email digests - Expired session cleanup - Cache refreshes - Third-party API syncs - Failed webhook retries - CSV imports - Object storage cleanup - Data warehouse exports - Search index updates - Security checks - Backup verification At that point, scheduled work is no longer a small helper. It is part of the production system. A production cron job needs answers: - Where does it run? - Who owns it? - What happens if it fails? - What happens if it runs twice? - What happens if the previous run is still active? - Where are logs stored? - How is success measured? - How are credentials scoped? - How is runtime cost controlled? - Should this be a function, VM job, worker, or queue? The scheduling syntax is the easy part. The operating model is the real decision. ## The quick decision framework Use this table before deciding between serverless cron and VM cron. ![Decision matrix comparing serverless cron jobs on Raff Functions with cron jobs on Raff VM](https://raff-images.s3.raffusercloud.com/serverless_cron_vs_vm_cron_decision_matrix_webp_05a2249837.png) | Scheduled job | Better default | Why | |---|---|---| | Short cleanup task | Serverless function | Runs only when needed | | Nightly API sync | Serverless function | Scheduled, bounded, easy to isolate | | Daily report generation | Serverless function | Output can go to object storage | | Job that needs local app files | VM cron | Runs inside existing server environment | | Job that needs SSH debugging | VM cron | Direct server inspection helps | | Job that runs every minute all day | Depends | Function if bounded; VM if effectively always-on | | Job that uses custom system packages | VM cron | Full OS control is easier | | File processing after upload | Function trigger or cron function | Better separated from app server | | Database maintenance script | VM or managed database tooling | Depends on access and risk | | Long ETL job | Long-running function or worker VM | Choose by duration, dependencies, and control | | Queue retry processor | Worker VM or function | Depends on retry pattern and volume | | Security scan | Function or VM | Depends on target and required tools | A useful rule: > Use serverless cron when the schedule starts a bounded task. Use VM cron when the task depends on the server environment. Cron should not be chosen because "the VM already exists." It should be chosen because it is the right place for that scheduled workload. ## Serverless cron is best for bounded scheduled work Serverless cron is a good fit when a job has a clear start, clear finish, and no need to keep a server alive between runs. Good examples include: - Send daily email digest - Sync an external API every hour - Clean expired temporary records - Refresh a cached summary - Generate a weekly report - Check failed webhook retries - Rotate short-lived tokens - Run a scheduled import - Process small batches - Create invoice drafts - Validate uploaded files on a schedule - Update usage counters - Export data to object storage The architecture is simple: ```text Cron schedule ↓ Raff Function ↓ Managed Database / Object Storage / API ``` The function runs because the schedule fires. It finishes. Then it disappears until the next run. That has clear benefits: - No idle server process - No shared app-server resources - Separate logs per invocation - Easier isolation from the main app - Lower risk of cron jobs slowing web traffic - Clear trigger ownership - Better fit for spiky or occasional scheduled tasks Raff Functions supports timezone-aware cron schedules, so jobs can be configured around the business schedule instead of only server-local assumptions. :::cta Explore Raff Functions Use Raff Functions for scheduled jobs that should run independently without keeping a VM process alive. ::: ## VM cron is still useful when the server environment matters VM cron is not outdated. It is still the right choice when the scheduled task belongs inside a full server environment. Use VM cron when the job needs: - Local application code - Existing server packages - Shell scripts already deployed on the VM - Full filesystem access - SSH debugging - Custom binaries - Local Docker Compose services - Internal tools installed on the server - Server-level network configuration - A job that coordinates with local services - Always-on worker behavior - Manual inspection during incidents A VM cron pattern looks like this: ```text Raff VM ↓ cron schedule ↓ local script or app command ↓ database / files / external API ``` This can be the simplest solution for early SaaS apps. If the app already runs on one VM and the job is closely tied to that app environment, server cron may be easier to maintain than creating a separate function too early. The risk is that VM cron can become invisible. Jobs may run on a server that only one developer understands. Logs may live in local files. Failures may not alert anyone. Scripts may accumulate without ownership. Jobs may compete with the web app for CPU, memory, or disk. VM cron is fine. Hidden VM cron is not. ## Scheduled work should not slow the main app One of the strongest reasons to move cron jobs into functions is isolation. On a single VM, scheduled jobs can compete with the main application: ```text Web app ↓ shares CPU / memory / disk with Cron jobs ``` This is usually fine for small tasks. It becomes risky when jobs are CPU-heavy, memory-heavy, or unpredictable. Warning signs: - Web requests slow down during scheduled jobs - Nightly reports increase CPU or disk load - API syncs cause memory spikes - Cleanup jobs lock database rows - Cron scripts produce large logs - File exports fill local disk - Several jobs start at the same time - The team avoids running jobs during business hours - Cron failures are discovered by customers When scheduled work starts affecting user experience, separate it. A serverless cron function can run outside the main app server: ```text Raff Function ↓ scheduled job ↓ database / object storage ``` A worker VM can also be the right separation layer: ```text App VM ↓ Worker VM with cron or queue processor ↓ database / object storage ``` The right choice depends on whether the work is occasional and bounded or constant and environment-heavy. ## Cron jobs need idempotency Idempotency means a job can run more than once without creating duplicate or corrupted results. This matters for both function cron and VM cron. ![Checklist infographic showing production cron job requirements including idempotency overlap control logs retries credentials and durable output](https://raff-images.s3.raffusercloud.com/production_cron_safety_checklist_webp_17a92fd6e1.png) Scheduled tasks can run twice because: - A retry happens - A developer manually reruns a job - A deployment restarts a worker - Two environments share the same schedule - The previous run has not finished - The schedule was copied into another service - A time-zone or daylight-saving change creates confusion A cron job should answer: - Can this job run twice safely? - Does it use a unique job ID? - Does the database prevent duplicate records? - Can it resume from a checkpoint? - Does it know if a previous run is still active? - Does it skip, queue, or overlap when a prior run is active? - Does it write output with a stable or versioned path? - Does it update status only after output is complete? For example, invoice generation should not create duplicate invoices if it runs twice. A report export should not overwrite the wrong file. A cleanup job should not delete data outside the expected window. A safe pattern: ```text Create job record ↓ Check if job already completed ↓ Run work ↓ Write output ↓ Mark job complete ``` Cron is scheduling. It is not correctness. The application must handle correctness. ## Overlapping jobs are a real production risk A job that runs every 5 minutes may take 7 minutes during peak load. Now the next scheduled run starts while the previous run is still active. That can cause: - Duplicate processing - Database lock contention - API rate-limit issues - Object overwrite conflicts - Excess memory use - Confusing logs - Incorrect status - Higher function cost - Slower app performance Before production, decide how overlapping runs should behave. | Overlap policy | What it means | Good for | |---|---|---| | Skip | If previous run is active, do nothing | Cleanup jobs, periodic syncs | | Queue | Run after current job finishes | Important sequential jobs | | Parallelize | Allow multiple runs | Independent chunks or per-tenant jobs | | Fail fast | Mark as failed and alert | Jobs that should never overlap | | Lock | Use database or distributed lock | Critical jobs with strict exclusivity | For small teams, skip or lock is often enough. A simple database lock or job status check can prevent many incidents: ```text if existing_job.status == "running": skip new run else: start new run ``` For high-volume background processing, a queue may be better than cron alone. Cron can create jobs, while workers process them. For related background-work design, read [Cron Jobs vs Queues vs Workflow Automation](/learn/guides/cron-jobs-queues-workflow-automation-background-work). ## Logs and metrics decide whether cron is trustworthy A scheduled job without logs is a guess. A production cron job should show: - When it started - When it finished - Whether it succeeded - Whether it failed - How long it ran - Which input it processed - How many records changed - Which external API failed - Whether it retried - Whether it skipped because another run was active - Which output file or record was produced VM cron often fails here because logs are stored in local files or shell output. That can work, but only if the team has a consistent pattern. Function cron can make this easier because each invocation has its own runtime logs and metrics. Raff Functions includes logs and metrics for every invocation, with live log tail, search and level filters, 14-day retention, invocation count, p50, p95, and error rate per function. That is useful for scheduled jobs because the team can answer: ```text Did the 09:00 job run? Did it fail? How long did it take? Did it get slower this week? Did error rate change? ``` Cron is only reliable if the team can observe it. ## Credentials should be scoped to the scheduled task Cron jobs often need privileged access. They may read customer records, call billing APIs, write reports, delete old data, rotate credentials, or access object storage. That makes credential scope important. Do not give every scheduled job broad credentials. A report job may need read access to specific database tables and write access to a specific object-storage prefix. A cleanup job may need write access to a narrow set of records. A sync job may need one external API token. Good credential rules: - Use separate credentials per job when possible - Avoid sharing root credentials - Keep secrets out of code - Rotate credentials when ownership changes - Do not print secrets in logs - Scope object-storage keys to the required bucket or prefix - Scope database users by job responsibility - Remove credentials when a job is retired Raff Functions can bind to Raff Managed Databases and Raff Object Storage with scoped credentials. VM cron can also be secured, but the team must manage server-level files, environment variables, secret rotation, and access control carefully. Scheduled jobs are often trusted. That is exactly why they should be scoped. ## Store files in object storage, not the cron environment Scheduled jobs often create files: - Daily reports - CSV exports - Invoices - Backup summaries - Import results - PDF reports - Data validation logs - Generated artifacts - Compressed archives Do not treat the function runtime or app VM as the final file store. Use [Raff Object Storage](/products/object-storage) for durable files and use the database for metadata. A clean scheduled-report pattern: ```text Cron schedule ↓ Function or VM job generates report ↓ Object Storage stores file ↓ Database stores status and output_uri ``` This keeps files separate from compute. It also makes retry behavior clearer. If the job fails, the database can mark the job failed. If the job succeeds, the database can point to the exact output object. For related reading, use [App Uploads: VM Disk vs Object Storage for SaaS Teams](/learn/guides/app-uploads-vm-disk-vs-object-storage). ## Cost planning for scheduled work Cron cost depends on job frequency, duration, and resource use. A job that runs once per day for 10 seconds is very different from a job that runs every minute for 45 seconds. For function cron, estimate: - Runs per month - Average duration - Memory setting - Active CPU behavior - Retry frequency - Whether the job overlaps - Whether it needs warm instances - Whether it produces large files For VM cron, estimate: - VM size - Whether the VM already runs the main app - CPU/memory pressure during jobs - Whether jobs force a larger VM - Disk usage from logs or files - Operations time - Whether a separate worker VM is needed A simple comparison: | Job shape | Cost-friendly model | |---|---| | Runs once per day | Function | | Runs once per hour | Function | | Runs every minute but finishes quickly | Depends | | Runs constantly | VM or Kubernetes worker | | Uses heavy CPU for hours daily | Compare both | | Needs full app environment | VM | | Triggers on file upload | Function | | Produces files | Function or VM + object storage | Raff Functions bills memory and active CPU, with requests and egress free. Raff VM uses capacity-based pricing. Choose based on how the scheduled work behaves, not only on which tool feels newer. :::cta View Raff Pricing Compare Raff Functions and Raff VM pricing before deciding where scheduled jobs should run. ::: ## A practical Raff cron architecture A small team can use a staged approach. ![Raff architecture diagram showing cron schedules running on Raff Functions with Managed Database Object Storage and VM cron option](https://raff-images.s3.raffusercloud.com/raff_scheduled_jobs_architecture_webp_b1e204e8d1.png) ### Stage 1: VM cron inside one app server Early on, one VM may be enough. ```text Raff VM ↓ App + cron jobs ↓ Database ``` This is simple, but watch for resource contention and invisible failures. ### Stage 2: Move files and durable outputs out Scheduled jobs should write durable files to object storage. ```text Raff VM cron ↓ Database status ↓ Object Storage output ``` This prevents local disk from becoming a hidden dependency. ### Stage 3: Move bounded scheduled jobs into functions When cron jobs are independent and bounded, move them to Raff Functions. ```text Raff Function ↓ Managed Database ↓ Object Storage ``` This isolates scheduled work from the main app server. ### Stage 4: Use worker VMs for constant background work If scheduled work becomes constant or queue-based, move it to a worker VM. ```text App VM ↓ Worker VM ↓ Managed Database + Object Storage ``` This keeps the main app responsive while preserving full server control for background processing. ### Stage 5: Use Kubernetes only when coordination justifies it If many services, workers, schedules, and environments need orchestration, Kubernetes may become useful. ```text Kubernetes workloads ↓ CronJobs / workers / services ↓ Managed Database + Object Storage ``` Do not jump to Kubernetes only because cron jobs grew. First separate the workload cleanly. ## Serverless cron checklist Use this checklist before moving scheduled jobs to production. - [ ] The job has one clear owner. - [ ] The schedule is documented. - [ ] The time zone is explicit. - [ ] The job can run twice safely or has a lock. - [ ] Overlap behavior is defined. - [ ] Failure behavior is defined. - [ ] Retry behavior is defined. - [ ] Logs show start, finish, duration, and result. - [ ] The job writes durable state to a database if needed. - [ ] Generated files go to object storage. - [ ] Credentials are scoped. - [ ] Secrets are not logged. - [ ] Runtime cost is estimated. - [ ] Spend cap or usage guardrail is set. - [ ] The job can be disabled safely. - [ ] There is a manual rerun process. - [ ] The job does not slow the main app. - [ ] The team knows when to use a VM worker instead. The difference between a harmless cron job and a production incident is usually not syntax. It is the missing operating rules. ## Common mistakes to avoid ### Letting cron jobs become invisible If nobody knows which jobs run, when they run, and where they log, the system is fragile. Document schedules and owners. ### Running heavy jobs on the main app VM If scheduled work slows user-facing traffic, move it to a function, worker VM, or separate system. ### Ignoring time zones A job that runs at the wrong business hour can break billing, reports, notifications, or customer workflows. Use explicit time-zone configuration. ### Allowing overlapping runs accidentally Jobs that run longer than their schedule interval can overlap. Use locks, skip rules, or queues. ### Storing reports on local disk Generated files should live in object storage with metadata in a database. Local disk should not become the hidden archive. ### Using broad credentials Scheduled jobs often have powerful access. Scope credentials to the exact database, bucket, API, or action the job needs. ### Assuming function cron is always cheaper Serverless cron is strong for bounded scheduled work. VM cron or a worker VM may be better for constant, heavy, or environment-dependent work. ## Cron should run where the workload belongs Cron is only the trigger. The real decision is where the scheduled work should execute. Use [Raff Functions](/products/serverless-functions) for scheduled jobs that are bounded, independent, event-driven, and do not need a full server environment. Use [Raff VM](/products/raff-vm) when the job depends on local packages, SSH debugging, persistent services, Docker Compose, or a full application server. The clean Raff pattern is simple: scheduled job logic runs in the right compute layer, durable state lives in [Raff Managed Databases](/products/managed-databases), and generated files live in [Raff Object Storage](/products/object-storage). That keeps cron from becoming a hidden operational risk. Start with the simplest place that keeps the job observable, safe to retry, and easy to operate for the next 6-12 months. :::cta Explore Raff Functions Use Raff Functions for timezone-aware cron jobs that should run independently from your main app server. ::: --- ### Webhooks on Serverless Functions: When to Use Functions Instead of VMs URL: https://rafftechnologies.com/learn/guides/serverless-functions-for-webhooks Description: Learn when to use serverless functions for webhooks, when VMs are better, and how to design webhook retries, logs, security, and storage. Webhooks on serverless functions are useful when an external system needs to notify your application without sending that traffic directly to your main app server. A webhook is an event delivered over HTTP. Payment processors, Git platforms, CRMs, email providers, monitoring tools, automation platforms, and internal systems use webhooks to tell your app that something happened. The receiving endpoint should validate the event, return quickly, store enough state, and move heavier work out of the request path. For Raff Technologies users, [Raff Functions](/products/serverless-functions) is a strong fit for webhook handling because each function can have an HTTP live URL with automatic TLS, logs and metrics for each invocation, standard handlers, free requests and egress, and a spend cap on by default. A [Raff VM](/products/raff-vm) is still the better fit when the webhook handler depends on a full server environment, local app code, Docker Compose, persistent services, or SSH debugging. This guide explains when to put webhooks on serverless functions, when to keep them on a VM, and how to design webhook architecture so retries, duplicate events, secrets, logs, and downstream work do not become production risk. If you are still comparing the broader models, read [Serverless Functions vs VMs: What Small Teams Should Choose](/learn/guides/serverless-functions-vs-vms-small-teams) first. ## Webhooks are event-driven by nature A webhook starts because something happened somewhere else. ![Architecture diagram showing external webhooks received by Raff Functions with validation database state and downstream processing](https://raff-images.s3.raffusercloud.com/webhook_serverless_function_architecture_53cb6e875a.png) Examples: - A payment succeeded - A subscription failed - A GitHub pull request opened - An email bounced - A CRM contact changed - A monitoring alert fired - A form was submitted - A customer uploaded a file - A marketplace order changed - An automation workflow reached a step - A third-party API finished a task This is exactly the kind of workload serverless functions are designed to handle. A webhook does not usually need a full server. It needs an HTTP endpoint that can receive the event, validate it, store it, and trigger the next step. A clean webhook pattern looks like this: ```text External service ↓ Webhook endpoint ↓ Validate signature ↓ Store event or status ↓ Trigger background work ↓ Return quickly ``` The endpoint should not try to do everything during the request. If the downstream work is heavy, move it to a queue, another function, a worker VM, or a background workflow. A webhook endpoint is often small, but it can have a large production impact. That is why isolation, visibility, and retry design matter. ## The quick decision framework Use this table before deciding where a webhook should run. ![Decision diagram comparing webhooks on Raff Functions with webhooks on Raff VM](https://raff-images.s3.raffusercloud.com/serverless_webhooks_vs_vm_webhooks_decision_641f48bcd0.png) | Webhook situation | Better default | Why | |---|---|---| | Lightweight event receiver | Serverless function | Event-driven and isolated | | Payment webhook | Serverless function with durable database writes | Needs fast acknowledgement and idempotency | | Git or CI webhook | Serverless function | Triggered by external event, easy to isolate | | CRM or form webhook | Serverless function | Usually bounded and HTTP-based | | Email delivery callback | Serverless function | High-volume callbacks should not hit the main app | | Webhook starts heavy processing | Function plus queue or worker | Return quickly, process separately | | Webhook needs local app files | VM | Depends on full server environment | | Webhook needs SSH debugging | VM | Direct inspection may matter | | Webhook shares Docker Compose services | VM | Local service dependencies are easier | | Webhook traffic is constant and heavy | Function or VM, compare cost | Workload shape decides | | Webhook needs custom system packages | VM or Dockerfile function | Choose based on dependency complexity | | Webhook writes files | Function plus object storage | Files should not live in the function runtime | A useful rule: > Use a function when the webhook is an event boundary. Use a VM when the webhook is tightly coupled to the server environment. Most webhook receivers are event boundaries. That makes serverless functions a natural starting point. ## Why serverless functions fit webhook receivers A webhook endpoint has a few simple responsibilities: 1. Receive the HTTP request 2. Validate the sender 3. Store or update durable state 4. Trigger any downstream work 5. Return a response quickly This maps well to serverless functions. With Raff Functions, a webhook can run as a standard HTTP handler. Raff Functions supports HTTP live URLs with automatic TLS, standard handlers such as Python FastAPI / ASGI, Node.js standard `http`, JavaScript Web Fetch, TypeScript, Go `net/http`, and a Dockerfile escape hatch for other languages. That matters because webhook code should be easy to understand and easy to move. A handler that looks like normal application code is easier to test, maintain, and migrate later. Serverless functions are especially useful for webhooks because they can: - Stay isolated from the main app server - Scale with webhook bursts - Avoid keeping a server awake for occasional events - Produce per-invocation logs and metrics - Return quickly - Use scoped credentials - Trigger downstream work - Reduce pressure on the main app VM - Keep third-party event traffic separate from user traffic :::cta Explore Raff Functions Use Raff Functions for webhook endpoints that should run independently from your main app server. ::: ## When webhooks should stay on a VM A function is not always the right home. Keep webhook handling on a VM when the endpoint depends heavily on the server environment. Use a VM when the webhook handler needs: - Existing local application code - Docker Compose services - Local queues or services - Custom binaries - Full filesystem access - SSH debugging - Persistent local state - Long-lived processes - Internal server-only tools - Complex network configuration - Manual inspection during incidents - Tight coupling to the main app routing layer A VM-based webhook pattern looks like this: ```text External service ↓ Nginx or app server on Raff VM ↓ Application route ↓ Database / queue / local service ``` That can be the simplest architecture when the app is early and webhook traffic is low. If the entire app already runs on one Raff VM, adding one webhook route to the same app may be perfectly reasonable. The risk appears when external event traffic starts affecting the user-facing app. If webhook retries, signature verification, third-party spikes, or downstream processing slow the main app, isolate the webhook. ## Return quickly and process later Webhook senders usually expect a fast response. If your endpoint takes too long, the sender may retry. If the sender retries while your app is still processing the previous event, duplicate work can happen. A safer pattern is: ```text Webhook request ↓ Validate sender ↓ Write event record ↓ Return 2xx response ↓ Process asynchronously ``` The asynchronous step can be: - Another function - A queue worker - A worker VM - A scheduled retry job - A background task - A workflow tool The key is to separate acknowledgement from heavy processing. Do not make the webhook request wait while you: - Generate reports - Send many emails - Process files - Run long AI inference - Sync large datasets - Call several slow APIs - Perform large database updates - Build export files For long work, use [Long-Running Serverless Functions for AI, ETL, and Batch Jobs](/learn/guides/long-running-serverless-functions-ai-etl-batch) or move the work to a worker VM. A webhook should normally say: "I received the event." It should not do the entire business workflow inside the HTTP request. ## Validate signatures before trusting events Webhook endpoints must not trust every incoming request. Most webhook providers support a signing mechanism, shared secret, token, or header-based verification. The endpoint should validate that the request came from the expected sender before processing it. A webhook validation flow: ```text Receive request ↓ Read signature header ↓ Reconstruct signed payload ↓ Verify with secret ↓ Reject if invalid ↓ Process if valid ``` For production, define: - Which header contains the signature - Which secret verifies the request - Whether timestamps are checked - Whether replay protection is needed - What status code invalid requests receive - Whether invalid requests are logged - Whether logs avoid exposing secrets - How secrets are rotated Do not put webhook secrets directly in code. Use environment variables or secret management. Raff Functions supports environment variables and masked secrets, so the handler can read configuration without exposing it in the source file. Signature validation should happen before any database write that changes state. ## Idempotency prevents duplicate webhook damage Webhook duplicates are normal. A provider may retry after a timeout. A network issue may hide the response. A user may trigger the same event twice. A deployment may process the same stored event again. A failed function may be retried. The endpoint must treat duplicate events as expected. Idempotency means the same event can be processed more than once without causing duplicate or corrupted results. Use these techniques: | Technique | Use | |---|---| | Store provider event ID | Detect duplicates | | Unique database constraint | Prevent duplicate inserts | | Status transitions | Avoid repeating completed work | | Idempotency key | Link repeated requests to one action | | Output path versioning | Prevent overwriting wrong artifacts | | Retry counter | Stop infinite loops | | Event log table | Keep audit trail | | Job table | Track downstream processing | A simple webhook event table can store: | Field | Purpose | |---|---| | event_id | Provider event ID | | provider | Stripe, GitHub, CRM, email vendor, etc. | | event_type | Kind of event | | account_id | Tenant or customer owner | | received_at | Arrival time | | status | received, processing, completed, failed | | attempts | Processing attempts | | payload_hash | Duplicate detection | | error_message | Safe failure summary | A webhook handler should check whether the event already exists before creating new business records. For example: ```text if event_id already exists: return success else: store event and continue ``` Duplicate protection is not optional for payment, billing, order, account, or subscription webhooks. ## Store the event before doing heavy work A reliable webhook handler should save the event or the important state before doing slow work. This creates a recovery path. If the function fails after receiving the webhook, the system can still know what arrived. If downstream work fails, a scheduled retry job or worker can inspect failed events and retry them safely. A good pattern: ```text Validate request ↓ Write event record ↓ Return response ↓ Process event ↓ Update event status ``` This is better than doing all work in memory. For example, a billing webhook should not only update subscription state directly. It should also record the provider event ID and processing status. That gives the team an audit trail if a customer asks why their subscription changed. Raff Managed Databases can store webhook events, job status, and durable business records. Raff Object Storage can store larger payloads, generated files, exports, or artifacts when the webhook leads to file work. The function should execute the logic. Durable state should live in the database or object storage layer. ## Use object storage for webhook artifacts Some webhooks lead to files. Examples: - A form submission includes an attachment - A document-signing provider sends a completed PDF - A media provider sends a processed file - A report needs to be generated after an event - A customer uploads a file through a third-party service - A marketplace sends order documents - An import job starts after a webhook Do not store those files inside the function runtime. A clean pattern: ```text Webhook arrives ↓ Function validates event ↓ Function stores metadata in database ↓ Function stores files/artifacts in Object Storage ``` Use [Raff Object Storage](/products/object-storage) for: - Attachments - Generated reports - Provider payload archives - Export files - Signed documents - Processed media - Import artifacts - Debug-safe event samples - Long-term audit files The database should store metadata and object paths, not the full file body unless there is a specific reason. For the storage decision, read [App Uploads: VM Disk vs Object Storage for SaaS Teams](/learn/guides/app-uploads-vm-disk-vs-object-storage). ## Logs and metrics make webhook failures visible Webhook failures can be hard to see because they happen between systems. A customer may say a payment succeeded, but the app did not update. A CRM may show a contact changed, but your product did not receive it. An email provider may retry events, but your app may not show why. A webhook endpoint needs visibility. Track: - Invocation count - Error rate - p50 and p95 latency - Invalid signature count - Duplicate event count - Retry count - Event type distribution - Provider response status - Database write failures - Slow downstream calls - Failed processing status Raff Functions includes logs and metrics for every invocation, with live log tail, search, level filters, 14-day retention, count, p50, p95, and error rate per function. For webhook logs, use safe structured messages: ```text webhook_received provider=stripe event_id=evt_123 type=invoice.paid webhook_validated provider=stripe event_id=evt_123 webhook_duplicate provider=stripe event_id=evt_123 webhook_processing_started event_id=evt_123 webhook_processing_completed event_id=evt_123 duration_ms=214 webhook_processing_failed event_id=evt_123 reason=database_timeout ``` Do not log secrets, full payment details, tokens, or sensitive customer payloads. Good webhook logs should help the team answer what happened without exposing private data. ## Retry behavior should be designed Webhooks involve at least two retry systems: 1. The provider may retry delivery. 2. Your system may retry downstream processing. Those should not be confused. Provider retries are about delivery. Your system retries are about business processing. A good design separates them: ```text Provider retry ↓ Function receives duplicate event ↓ Event ID already exists ↓ Return success ``` and: ```text Stored event has failed processing status ↓ Retry worker or function runs later ↓ Processing succeeds or fails again ``` Decide: - Which errors should return non-2xx? - Which errors should return 2xx but mark processing failed? - How many internal retries are allowed? - What backoff strategy is used? - Who is alerted after final failure? - How are failed events replayed? - Can one event block others? - Can processing run twice safely? For many webhooks, the endpoint should return quickly after storing the event. If processing fails after that, handle retries internally. This avoids making the third-party provider responsible for your internal processing workflow. ## Security boundaries matter more for public endpoints A webhook URL is public by design. That means it needs stronger boundaries than an internal-only function. Use these controls: - Validate signatures or tokens - Reject unknown providers - Use HTTPS - Keep secrets out of code - Avoid logging sensitive payloads - Rate-limit where appropriate - Store only necessary payload data - Scope database credentials - Scope object-storage credentials - Use separate functions for unrelated providers - Monitor invalid request patterns - Disable retired webhook endpoints - Rotate secrets after incidents or ownership changes Raff Functions provides HTTP live URLs with automatic TLS, masked secrets, and scoped bindings to Raff Managed Databases and Raff Object Storage. Use those features to keep each webhook narrow. A payment webhook should not share the same broad credentials as a file-processing webhook. A CRM webhook should not have access to unrelated object-storage buckets. A Git webhook should not have database write access unless it actually needs it. Small teams often move fast by using one credential everywhere. That becomes dangerous when the endpoint is public. ## Pricing for webhook functions Webhook cost depends on invocation volume, duration, memory, and active CPU. Webhooks are often short and I/O-heavy. They validate a signature, write a database record, maybe call one API, and return. That can fit usage-based serverless pricing well. Raff Functions bills memory and active CPU. Requests and egress are free. That matters for webhooks because retries and event bursts can increase request counts quickly. Estimate: - Events per month - Retry rate - Average duration - Memory setting - Active CPU time - Whether downstream work happens inside the request - Whether the function calls slow external APIs - Whether payloads are large - Whether heavy work is moved out of the request path A webhook that only validates and stores an event is usually easier to forecast than one that performs long downstream processing during the request. For cost planning, read [Serverless Function Pricing: CPU, Memory, Requests, and Egress](/learn/guides/serverless-function-pricing-cpu-memory-egress). :::cta View Raff Pricing Compare Raff Functions and Raff VM pricing before deciding where public webhook traffic should run. ::: ## A practical Raff webhook architecture A strong Raff webhook architecture keeps the public endpoint isolated and durable state outside the function. ```text External provider ↓ Raff Function webhook URL ↓ Signature validation ↓ Raff Managed Database = event state and business records ↓ Raff Object Storage = files and artifacts ↓ Worker VM or function = downstream processing ``` Each layer has a job: | Layer | Responsibility | |---|---| | Raff Function | Receives, validates, stores, and acknowledges webhook | | Managed Database | Stores event IDs, status, metadata, and business records | | Object Storage | Stores files, attachments, reports, or artifacts | | Worker VM or another function | Handles slow downstream processing | | Logs and metrics | Shows delivery, latency, errors, and retry behavior | This pattern works for: - Billing webhooks - Git provider webhooks - Email delivery callbacks - CRM event callbacks - Form submissions - Marketplace events - Automation workflows - Monitoring alerts Start with one function per provider or per major event family. Avoid one giant webhook function that handles every provider and every event type unless there is a strong reason. ## When to use one function or multiple webhook functions A team can handle webhooks in one function or split them. Use one webhook function when: - Events come from one provider - Event types are closely related - Shared validation logic is useful - Traffic is low - The code remains easy to understand - The same credentials and data access are needed Use multiple webhook functions when: - Providers are unrelated - Security boundaries differ - Credentials should be separate - One provider has high traffic - Event handling logic is large - Different teams own different integrations - Different runtime settings are needed - Failure isolation matters A practical split: ```text billing-webhook git-webhook email-webhook crm-webhook file-event-webhook ``` This keeps ownership clear. Do not split too early into dozens of tiny functions if the team cannot operate them. Split when security, traffic, ownership, or complexity justify it. ## Webhook readiness checklist ![Checklist infographic showing webhook production safety requirements including signatures idempotency retries logs scoped credentials and durable state](https://raff-images.s3.raffusercloud.com/production_webhook_safety_checklist_aa4017d055.png) Before launching a production webhook function, check: - [ ] The webhook provider is identified. - [ ] The endpoint uses HTTPS. - [ ] Signature or token validation is implemented. - [ ] Secrets are stored outside code. - [ ] Invalid signatures are rejected. - [ ] Provider event ID is stored. - [ ] Duplicate events are handled safely. - [ ] The endpoint returns quickly. - [ ] Heavy work is moved out of the request path. - [ ] Event status is stored in a database. - [ ] Files and artifacts go to object storage. - [ ] Retry behavior is defined. - [ ] Internal processing failures are visible. - [ ] Logs do not expose secrets or sensitive payloads. - [ ] Metrics are reviewed after launch. - [ ] Credentials are scoped per function. - [ ] The function has an owner. - [ ] The spend cap is reviewed. - [ ] There is a manual replay process for failed events. - [ ] The team knows when to move work to a VM worker. Production webhooks are small endpoints with large consequences. Treat them accordingly. ## Common mistakes to avoid ### Doing too much inside the webhook request Validate, store, and acknowledge quickly. Move heavy work to a function, queue, worker VM, or background process. ### Skipping signature validation A public URL must not trust every incoming request. Verify the sender before changing data. ### Ignoring duplicate events Webhook providers can retry events. Store event IDs and make processing idempotent. ### Storing only in memory If the function fails, in-memory state disappears. Store event status and durable records in a database. ### Logging sensitive payloads Webhook payloads can contain customer, payment, or private integration data. Log identifiers and safe summaries, not secrets. ### Using one broad credential for every webhook Public endpoints should have narrow credentials. Scope database and object-storage access to what each function needs. ### Keeping webhook traffic on the main app when it causes incidents If webhook spikes or retries slow the customer-facing app, isolate the endpoint. Serverless functions are often a cleaner boundary. ## Webhooks should be isolated, fast, and durable Webhook handlers look small, but they sit at an important boundary between your app and external systems. Use [Raff Functions](/products/serverless-functions) when the webhook is event-driven, should scale independently, should return quickly, and does not need a full server environment. Use [Raff VM](/products/raff-vm) when the webhook depends on local application code, Docker Compose, SSH debugging, custom packages, or persistent server-side services. The strongest Raff pattern is to receive the webhook in a function, validate the sender, store event state in [Raff Managed Databases](/products/managed-databases), store files or artifacts in [Raff Object Storage](/products/object-storage), and move heavy processing into a follow-up function, queue, or worker VM. That keeps webhook traffic away from the main app, makes failures visible, and gives the team a safer retry path. :::cta Explore Raff Functions Use Raff Functions for public webhook endpoints that need fast acknowledgement, logs, metrics, scoped credentials, and independent scaling. ::: --- ### Portable Serverless Handlers: Avoiding Lambda Lock-In URL: https://rafftechnologies.com/learn/guides/portable-serverless-handlers-avoid-lock-in Description: Learn how portable serverless handlers reduce Lambda lock-in, keep functions easier to move, and support standard runtimes on Raff Functions. Portable serverless handlers are function handlers written in standard application formats instead of provider-specific request and response shapes. For small teams, portability matters because the first serverless decision is rarely the last one. A webhook may start on one platform, move into a VM, become a worker, run behind a container, or later move into Kubernetes. If the function code is tied too tightly to one provider's handler signature, event format, SDK, deployment model, or logging system, a simple move can become a rewrite. Raff Technologies designed [Raff Functions](/products/serverless-functions) around standard handlers: Python FastAPI / ASGI, Node.js standard `http`, TypeScript, JavaScript Web Fetch, Go `net/http`, and a Dockerfile escape hatch for other runtimes. The goal is simple: write code that looks like normal application code, not a proprietary function format. This guide explains what serverless lock-in looks like, how portable handlers reduce migration risk, when provider-specific code is still acceptable, and how small teams should structure serverless functions so they can move between Raff Functions, VMs, containers, and other infrastructure without rebuilding the application from scratch. If you are still deciding whether a workload belongs on Functions or a VM, read [Serverless Functions vs VMs: What Small Teams Should Choose](/learn/guides/serverless-functions-vs-vms-small-teams) first. ## Serverless lock-in usually starts small Serverless lock-in does not usually start as a big architectural decision. ![Comparison diagram showing proprietary serverless handlers versus portable standard handlers](https://raff-images.s3.raffusercloud.com/portable_handler_vs_proprietary_handler_webp_d22d3da3ed.png) It starts with one handler: ```python def lambda_handler(event, context): ... ``` or one platform-specific request object, one proprietary event payload, one storage binding, one logging API, one deployment file, or one local development workaround. That may be fine for a prototype. But if the function becomes important, those small choices become migration work. Lock-in can appear in several layers: | Layer | What lock-in looks like | |---|---| | Handler format | Function depends on a provider-specific event and response structure | | Runtime assumptions | Code only works inside one hosted runtime | | Trigger format | HTTP, cron, queue, and storage events use non-portable shapes | | SDK usage | Business logic calls provider SDKs directly everywhere | | Deployment model | Build, config, and routing exist only in one platform | | Logs and metrics | Observability depends on provider-specific tools | | Secrets and bindings | Credentials are injected in a way that cannot move | | Local development | Function cannot run locally without emulating the provider | The risk is not that a team can never move. The risk is that moving becomes expensive at exactly the moment the workload is already important. A portable handler does not eliminate all platform work. It reduces the amount of business logic tied to one platform. ## The quick decision framework Use this table before writing a new serverless function. | Situation | Better pattern | Why | |---|---|---| | HTTP webhook endpoint | Standard HTTP handler | Easier to test, move, and run locally | | Small public API | Standard framework route | Keeps code close to normal app code | | Cron job | Normal function plus explicit input | Avoids platform-only event assumptions | | Object storage event | Thin adapter around standard logic | Keeps business logic portable | | Existing Lambda import | Convert to standard handler when possible | Reduces future migration work | | Language outside common runtimes | Dockerfile handler | Keeps runtime choice flexible | | Provider-specific feature is essential | Isolate provider code | Keep lock-in at the edge | | Business logic calls cloud APIs | Wrap those calls behind small modules | Avoids scattering platform dependency | | Function may move to VM later | Keep environment and config explicit | Makes server migration easier | | Prototype with no reuse expected | Provider-specific handler is acceptable | Speed may matter more than portability | A useful rule: > Put provider-specific code at the edge. Keep business logic in portable modules. That one rule prevents many future rewrites. ## Standard HTTP handlers are easier to move HTTP is the most portable shape for many serverless workloads. A webhook receiver, small API, callback endpoint, form handler, or internal tool can usually be expressed as normal HTTP code: ```text Request ↓ Validate input ↓ Call business logic ↓ Return response ``` That maps naturally to common application frameworks. Raff Functions supports standard handler formats such as Python FastAPI / ASGI, Node.js standard `http`, JavaScript Web Fetch, TypeScript, and Go `net/http`. That means the code can look like normal server code instead of a provider-specific event processor. For example, the portable shape is: ```text HTTP request in HTTP response out ``` The less portable shape is: ```text Provider event object in Provider response object out ``` The difference matters when the team wants to: - Run the same handler locally - Move the route to a VM - Put the route into a container - Test it with normal HTTP tooling - Share code with the main app - Avoid provider-specific mock events - Keep junior developers productive - Reduce migration complexity later A standard HTTP handler is not only cleaner. It is easier to reason about. :::cta Explore Raff Functions Use Raff Functions when you want standard HTTP handlers without learning a proprietary function format. ::: ## Adapters keep platform-specific code at the edge Sometimes a function must receive a provider-specific event. ![Architecture diagram showing a thin adapter converting provider events into portable serverless business logic](https://raff-images.s3.raffusercloud.com/serverless_thin_adapter_architecture_webp_556b20cdb1.png) That is common for: - Storage events - Queue events - Scheduled events - Legacy Lambda events - Provider-specific webhook formats - Internal platform triggers The key is to use a thin adapter. A thin adapter converts the platform event into a normal internal input. Then the business logic runs independently. Bad pattern: ```text Provider event ↓ Business logic mixed with provider event fields ↓ Provider response ``` Better pattern: ```text Provider event ↓ Adapter extracts normal input ↓ Portable business logic ↓ Adapter returns platform response ``` Example structure: ```text handler.py # provider/platform edge service.py # portable business logic repository.py # database access storage.py # object storage wrapper ``` This way, a migration only changes `handler.py` and maybe a small binding layer. The core logic remains the same. That matters for SaaS teams because many early functions become business-critical later. A billing webhook, export processor, file converter, or AI task should not be impossible to move because all logic is tangled with one event object. ## Portable functions need portable configuration Code is only one part of portability. A function also needs configuration: - Environment variables - Secrets - Memory - Timeout - Scaling limits - Trigger type - Database connection - Object storage bucket - API keys - Region - Log level - Feature flags If configuration exists only inside one provider dashboard, moving the function becomes harder. A portable approach: ```text Code reads named environment variables Secrets are documented Bindings are explicit Timeout and memory are recorded Trigger behavior is described Local development has an example .env ``` For example: ```text DATABASE_URL OBJECT_STORAGE_BUCKET WEBHOOK_SECRET LOG_LEVEL MAX_BATCH_SIZE ``` Those names can be reused across Raff Functions, local development, Docker containers, and VMs. Raff Functions supports environment variables, masked secrets, and bindings to Raff Managed Databases and Raff Object Storage with scoped credentials. Use those features, but still keep the function's required configuration clear in the repository. A function that cannot be configured outside the dashboard is not fully portable. ## Avoid spreading provider SDK calls through business logic Provider SDKs are sometimes necessary. A function may need to read object storage, call a queue, fetch secrets, publish events, or write logs. That is fine. The problem is scattering provider-specific SDK calls across the entire codebase. Better pattern: ```text business logic ↓ small interface/module ↓ provider-specific SDK ``` Example: ```text storage.save_report(file) database.update_job_status(job_id, status) notifications.send_email(user_id, template) ``` The business logic should not need to know which platform stores the file or how the credential is injected. This helps when moving between: - Raff Functions - Raff VM - Docker containers - Kubernetes jobs - local development - another function platform The internal wrapper can change. The business workflow stays readable. For a small team, this is not overengineering. It is a lightweight boundary that keeps migrations possible. ## Lock-in is not always bad, but it should be intentional Not every provider-specific feature is a mistake. Sometimes the best decision is to use the platform feature because it saves time, improves reliability, or gives a capability the team would not build itself. Provider-specific code may be acceptable when: - The function is small and temporary - The feature saves significant engineering time - The team has no realistic migration need - The workload is internal only - The provider feature is central to the product - The lock-in is documented and accepted - The code is isolated enough to replace later The problem is accidental lock-in. Accidental lock-in happens when a team writes code quickly without noticing that the function now depends on one provider's event structure, response shape, secret model, deployment workflow, and logs. A useful decision: ```text If lock-in saves time, document it. If lock-in touches business logic, isolate it. If lock-in is accidental, remove it early. ``` Portability is not an ideology. It is a risk control. ## Raff's portable-handler model Raff Functions is built around standard handlers rather than a Raff-specific function signature. ![Runtime map showing Raff Functions supporting standard handlers and portable deployment paths](https://raff-images.s3.raffusercloud.com/raff_functions_portable_runtime_map_webp_51749ac122.png) Supported patterns include: - Python FastAPI / ASGI - Node.js standard `http` - TypeScript - JavaScript Web Fetch - Go `net/http` - Dockerfile for other languages or custom runtimes That matters because the same application patterns are familiar outside the functions platform. A Python FastAPI handler can be easier to run locally. A Node `http` handler is a standard server shape. A Web Fetch handler follows a common request/response model. A Go `net/http` handler maps to normal Go server code. A Dockerfile escape hatch means the team is not blocked if the runtime needs something custom. Raff also supports importing AWS Lambda functions and converting them toward a cleaner, portable handler with a reviewable diff. That is useful when the team already has Lambda code but wants to reduce proprietary handler dependency over time. The goal is not to pretend all platforms are identical. The goal is to keep your function code close to standard application code. ## What a portable function structure looks like A portable function should separate four concerns: 1. Handler 2. Business logic 3. Data access 4. Platform bindings Example structure: ```text functions/ billing-webhook/ main.py service.py database.py storage.py README.md ``` The files have different jobs: | File | Responsibility | |---|---| | `main.py` | HTTP route or function entry | | `service.py` | Business logic | | `database.py` | Durable state access | | `storage.py` | File/artifact access | | `README.md` | Required env vars, triggers, timeout, owner | The handler should stay thin: ```text Receive request ↓ Validate input ↓ Call service function ↓ Return response ``` The service should not know whether it is running on Raff Functions, a VM, or a container. It should receive normal inputs and return normal outputs. That structure makes the function easier to test and easier to move. ## Portable handlers make local testing easier Local testing is one of the most practical benefits of portability. A function written as normal HTTP code can often be tested with: - curl - browser requests - Postman - normal unit tests - framework test clients - Docker - local environment variables A function tied to a proprietary event object often needs mock event JSON, context objects, and provider-specific local emulation. That extra complexity slows development. A portable test path looks like this: ```text Run handler locally ↓ Send normal HTTP request ↓ Assert response ↓ Test business logic separately ``` This is especially useful for: - Webhooks - API endpoints - form handlers - image processors - report generators - scheduled jobs with explicit inputs - file-processing functions A small team should not need a full cloud emulator to test simple business logic. ## Portability helps VM and Kubernetes migration later Some functions should stay functions. Others may move later. A webhook might start as a function, then become part of the main app. A batch function might grow into a worker VM. A file processor might later run as a Kubernetes job. A small API might become a full service. Portable handlers make those changes easier. A migration path might look like this: ```text Raff Function ↓ Docker container ↓ Raff VM ↓ Kubernetes workload ``` or: ```text Raff VM route ↓ Raff Function ↓ Worker VM ``` The direction can change. What matters is whether the code is trapped in one platform model. If the function's core logic is just a normal module, the team can move the runtime without rewriting the product behavior. For broader infrastructure decisions, read [Single VM vs Multi-VM Architecture for SaaS Apps](/learn/guides/single-vm-vs-multi-vm-saas-architecture) and [Kubernetes vs Docker Compose for Small Teams](/learn/guides/kubernetes-vs-docker-compose-small-teams). ## Trigger portability needs extra care HTTP handlers are the easiest to make portable. Non-HTTP triggers need more care. Common trigger types include: - Cron schedules - Object storage events - One-off future runs - Queue events - Webhooks - Database events - Internal events A portable trigger design should define a normal input shape for business logic. For example, an object storage event can be converted into: ```json { "bucket": "uploads", "key": "incoming/report.csv", "account_id": "acct_123" } ``` Then the service function can process that object without knowing the original provider event shape. A cron job can pass a simple input: ```json { "job_name": "daily-report", "run_date": "2026-07-20" } ``` A one-off job can pass: ```json { "job_id": "job_123", "input_uri": "s3://bucket/input.csv" } ``` The platform event can be different. The internal job input should be stable. This is the difference between portable business logic and provider-dependent glue. ## Database and storage bindings should stay narrow Functions often need access to databases and object storage. That access should be narrow and explicit. A portable function should not depend on one giant credential that gives broad access to everything. It should define exactly what it needs: - Which database - Which schema or table - Which object storage bucket - Which prefix - Which read/write permissions - Which API token - Which environment variables - Which tenant or account scope Raff Functions can bind to Raff Managed Databases with scoped per-function credentials and to Raff Object Storage with scoped S3 keys per bucket. That helps reduce the blast radius of each function. But portability still depends on how the application code uses those bindings. Good pattern: ```text Function reads DATABASE_URL and STORAGE_BUCKET Business logic calls database.py and storage.py Credentials stay outside code ``` Bad pattern: ```text Business logic depends on provider-specific binding object everywhere ``` Use the platform binding to inject access. Use your own small module to keep the code clean. ## Observability should be portable enough to understand Logs and metrics are part of the function's operating model. Raff Functions includes logs and metrics for every invocation, including live log tail, search and level filters, 14-day retention, count, p50, p95, and error rate per function. That is useful, but the log content should still be understandable outside one platform. Use structured, safe log messages: ```text webhook_received provider=stripe event_id=evt_123 job_started job_id=job_456 type=image_resize job_completed job_id=job_456 duration_ms=842 job_failed job_id=job_456 reason=object_not_found ``` Avoid logs that only make sense inside one provider's context object. Good logs should help the team debug the function whether it runs on Raff Functions, a VM, or another runtime. Log the business event, not only the platform event. ## A practical portability checklist Use this checklist before shipping a production serverless function. - [ ] The handler uses a standard framework or standard HTTP shape where possible. - [ ] Provider-specific event parsing is isolated in a thin adapter. - [ ] Business logic lives outside the handler file. - [ ] Database access is wrapped in a small module. - [ ] Object storage access is wrapped in a small module. - [ ] Environment variables are documented. - [ ] Secrets are not hardcoded. - [ ] The function can run locally with documented inputs. - [ ] Required memory and timeout are recorded. - [ ] Trigger type and schedule are documented. - [ ] Logs use safe business identifiers. - [ ] The function does not require a proprietary SDK in core logic. - [ ] Output files go to object storage. - [ ] Durable state goes to a database. - [ ] Provider-specific features are documented if used. - [ ] Migration assumptions are clear. - [ ] The team knows when to move the workload to a VM or Kubernetes. The checklist is not about making every function cloud-agnostic forever. It is about avoiding unnecessary rewrites. ## Common mistakes to avoid ### Putting business logic inside a proprietary handler A provider event object should not shape the whole codebase. Parse the event at the edge, then call portable business logic. ### Depending on a provider SDK everywhere SDKs are fine at the boundary. Do not scatter provider-specific calls across the entire workflow. ### Hiding configuration in the dashboard Environment variables, secrets, memory, timeout, and triggers should be documented in the repository. ### Making local testing too hard If a simple webhook or API handler requires a full cloud emulator to test, the function may be too tightly coupled. ### Assuming portability means no platform features Portability does not mean refusing useful features. Use platform features intentionally and isolate them when possible. ### Forgetting data portability Code is not the only lock-in. Data, files, logs, secrets, and deployment workflow also affect portability. ### Splitting too early Do not turn one simple function into too many abstraction layers. Use simple boundaries: handler, service, database, storage, configuration. ## Portable handlers keep future options open Serverless is most useful when it makes work easier to run, not when it traps the team inside one provider's event model. Use portable handlers for webhooks, small APIs, cron jobs, storage events, and batch tasks when the function may grow, move, or become business-critical. Keep provider-specific code at the edge. Keep business logic in normal modules. Store durable state in a database and files in object storage. Document configuration, triggers, timeouts, and secrets. For Raff teams, the natural pattern is to use [Raff Functions](/products/serverless-functions) for standard handlers, [Raff VM](/products/raff-vm) when the workload needs a full server, [Raff Managed Databases](/products/managed-databases) for durable records, and [Raff Object Storage](/products/object-storage) for files and artifacts. That gives the team flexibility without sacrificing a clean production operating model. :::cta Explore Raff Functions Deploy standard serverless handlers on Raff Functions without learning a proprietary function format. ::: --- ### Serverless Cost Controls: Spend Caps, Warm Instances & Usage Limits URL: https://rafftechnologies.com/learn/guides/serverless-cost-controls-spend-caps-warm-instances Description: Learn how serverless cost controls, spend caps, warm instances, usage limits, and anomaly reviews help small teams prevent unexpected function spend. Serverless cost control is the practice of limiting how much unexpected function activity can spend before it becomes an operational problem. That is different from serverless pricing. Pricing explains what a platform charges for memory, CPU, requests, egress, or other meters. Cost control decides what your team will allow, monitor, investigate, and stop when actual usage diverges from the plan. For small teams, this distinction matters because serverless scales easily. A webhook retry storm, overlapping cron job, recursive storage event, public endpoint spike, or overly aggressive scale setting can create more execution than anyone intended. The customer did not ask for that extra work, but the infrastructure can still run it. At Raff, we treat spend caps, warm capacity, and usage limits as production guardrails rather than billing settings. A spend cap is useful only if the team knows what should happen before and after it is reached. This guide focuses on that operating policy. For exact memory, active-CPU, free-tier, request, and egress pricing, use [Serverless Function Pricing](/learn/guides/serverless-function-pricing-cpu-memory-egress). ## Serverless cost controls limit financial blast radius A useful serverless budget has several layers. The monthly price model is only one of them. Teams should decide: - how much function spend is acceptable before review; - whether development and production share the same tolerance; - which functions may keep warm capacity; - how much concurrency or scale a dependency can safely absorb; - which usage changes count as an anomaly; - what happens when a cap pauses production work; - who is allowed to raise the cap; - when sustained usage should move to another compute model. The goal is not to prevent healthy growth. It is to contain unintended execution while the team still has time to understand it. A practical control stack looks like this: | Control | Main purpose | Failure it contains | |---|---|---| | Spend cap | Limits total account-level function spend | Runaway bill | | Warm-instance policy | Limits idle baseline capacity | Paying for readiness everywhere | | Concurrency/scale guardrail | Limits simultaneous execution | Cost burst and downstream overload | | Retry policy | Limits repeated failed work | Retry storms | | Trigger ownership | Prevents accidental loops | Recursive invocation | | Usage review | Detects changes quickly | Slow cost drift | | Compute-model review | Moves sustained work when needed | Using FaaS after the workload stops being bursty | **The safest serverless budget is not the highest cap you can tolerate; it is the lowest cap that still allows healthy production traffic plus known variance.** That gives the team a financial boundary without turning normal demand into an outage. ## Spend caps need an explicit production policy A spend cap should answer more than “What number did we type into the dashboard?” A production policy should define: 1. the owner of the cap; 2. the expected monthly usage range; 3. the amount of headroom above normal traffic; 4. what the team checks before increasing it; 5. what happens if the cap is reached; 6. whether a cap increase is temporary or permanent. Raff Functions currently has a **per-account spend cap on by default**. When the cap is reached, Functions pause rather than continuing to create an open-ended function bill. That is a useful safety property, but it can also interrupt production work if the cap is set too close to normal demand. The right posture is therefore neither “set it extremely low” nor “raise it until it can never be reached.” Set a guardrail that leaves realistic headroom, then review why usage is approaching it. A simple environment policy can look like this: | Environment | Default posture | Warm capacity | Cap behavior | |---|---|---|---| | Development | Low tolerance for accidental loops | Off | Keep conservative; raise only for a specific test | | Staging | Enough for production-like testing | Usually off | Review before load tests | | Production | Normal demand + planned headroom | Approved endpoints only | Investigate before permanent increases | Raff's current product interface shows a **$50/month example** when creating a function budget. Treat that as a UI example, not a universal recommendation for every production account. A team running occasional cron jobs and a team serving a public API need different headroom. A spend cap becomes operationally useful when someone can explain why it is set where it is. ## Retries and loops can multiply usage faster than traffic Unexpected serverless spend often comes from repeated work rather than genuine customer growth. Common examples include: - a webhook sender retries because acknowledgements are slow; - the function retries internally as well; - a cron job starts again before the previous run finishes; - a storage-event function writes output to a prefix that retriggers itself; - a client bug sends the same request repeatedly; - a failed batch is replayed from the beginning instead of resuming; - one event fans out into more work than expected; - a scaling change lets a bad trigger run many copies at once. These patterns are dangerous because they compound. ```text one bad event ↓ retry ↓ parallel scale-out ↓ more failed work ↓ more retries ``` **Retries, loops, and concurrency multiply usage faster than normal traffic growth because they repeat work the customer never intended to create.** That is why cost control starts with correctness. Use idempotency keys for external events. Separate input and output prefixes for storage workflows. Define overlap behavior for cron jobs. Put a ceiling on retry attempts. Record durable job state so long jobs can resume instead of restarting blindly. The existing [Webhooks on Serverless Functions](/learn/guides/serverless-functions-for-webhooks), [Cron Jobs on Serverless Functions vs Cron on a VM](/learn/guides/serverless-cron-jobs-vs-vm-cron), and [Object Storage Events on Serverless Functions](/learn/guides/object-storage-events-serverless-functions-file-processing) cover those workload-specific mechanics in more detail. From a cost-governance perspective, the rule is simple: **do not raise the budget to accommodate work that should not be happening.** ## Warm instances should be approved by latency need Scale-to-zero is one of the main reasons serverless can avoid idle capacity. Warm instances intentionally change that model by keeping capacity ready for latency-sensitive traffic. That can be the right decision, but it should be treated as an approved exception rather than a default toggle. Raff currently prices warm instances at **30% of the memory rate**. The detailed pricing mechanics belong in the [Serverless Function Pricing guide](/learn/guides/serverless-function-pricing-cpu-memory-egress). For cost control, the more important question is who is allowed to create that idle baseline and why. A practical approval test is: | Question | If “no” | If “yes” | |---|---|---| | Is the endpoint user-facing and latency-sensitive? | Keep scale-to-zero | Continue review | | Do measurements show startup latency materially affects the target? | Fix the actual bottleneck | Continue review | | Is the endpoint important enough to justify idle cost? | Keep scale-to-zero | Warm capacity may be justified | | Has the team reviewed the baseline after traffic changed? | Re-measure before expanding | Maintain intentionally | **Warm capacity should be treated as an approved exception for latency-sensitive paths, not a default setting for every function.** Cron jobs, file events, internal utilities, and many webhooks generally do not need always-ready capacity. A synchronous checkout or authentication-related endpoint may have a stronger case if measurements show startup latency matters. The dedicated [Cold Starts, Concurrency, and Scale-to-Zero guide](/learn/guides/serverless-cold-starts-concurrency-scale-to-zero) owns the latency mechanics. This guide owns the budget decision: warm capacity creates a baseline, so it needs a reason, an owner, and periodic review. ## Usage limits should protect downstream systems and budgets Concurrency and scale are not only performance settings. They also control how quickly a mistake can consume resources. Suppose one function calls a database. If a traffic spike creates 100 simultaneous executions, the function platform may be healthy while the database connection pool is not. The result can be a costly loop of timeouts and retries. A safer model is to size concurrency against the narrowest dependency: ```text incoming work ↓ function scale limit ↓ database / API / queue safe capacity ``` Use enough scale for legitimate demand, but do not let the function create more simultaneous pressure than downstream systems can handle. This also reduces financial blast radius. A broken trigger running at ten concurrent executions is easier to contain than the same trigger scaling without a deliberate ceiling. Raff's current Functions page shows **0→10** as a deployment example and allows scaling settings to be edited. That example is not a universal maximum. Raff also states that brand-new accounts start with lower concurrency and scale limits until **$10 lifetime paid**, after which those account-level restrictions lift automatically. The dedicated [Serverless Function Timeout, Memory & Concurrency Limits guide](/learn/guides/serverless-function-timeout-memory-concurrency-limits) owns hard runtime and capacity-limit mechanics. Here the ownership is cost governance: choose a safe operating ceiling instead of assuming maximum scale is always desirable. For production, document: - normal concurrency; - expected burst concurrency; - downstream connection/rate limits; - configured scaling ceiling; - retry behavior when downstream capacity is reached; - who approves scale increases. A scale increase should be a capacity decision, not a reflex after seeing throttling. ## Five-minute usage windows make anomaly reviews practical Cost governance is easier when teams can see changes before the end of the billing period. Raff currently reports Functions usage in **near-real-time 5-minute windows**. That gives a small team a practical way to compare a deployment, traffic event, or incident with the usage curve shortly after it happens. A useful anomaly review asks: | Signal | Question | |---|---| | Invocation count rises | Did customer traffic rise, or is something retrying? | | Duration rises | Is a dependency slow, causing more concurrent work? | | Error rate rises | Are failures generating retries or replays? | | p95 latency rises | Is the function waiting on a dependency or scaling poorly? | | Spend accelerates after deploy | Did memory, warm capacity, duration, or trigger behavior change? | | Spend rises with flat user traffic | Is background or duplicated work responsible? | Raff Functions also includes per-function logs and metrics such as invocation count, p50, p95, and error rate, with live log tail and 14-day retention. Those signals help classify the cause before the team raises a spend cap. A simple incident sequence is: ```text usage rises unexpectedly ↓ check invocation count + errors + latency ↓ identify function / trigger ↓ stop loop, reduce scale, or disable trigger if needed ↓ verify usage stabilizes ↓ then decide whether budget should change ``` This separates legitimate growth from waste. ## Raff cost controls support a simple operating model Raff's current Functions model gives small teams several controls that fit together: - a per-account spend cap is on by default; - Functions pause when the cap is reached; - usage is visible in 5-minute windows; - idle functions can scale to zero; - optional warm instances cost 30% of the memory rate; - scaling settings are configurable; - logs and metrics are included for each function; - new accounts begin with lower concurrency and scale limits until $10 lifetime paid. The pricing guide owns the exact memory, active-CPU, requests, egress, and free-tier numbers. The practical control model is more important here: ```text scale to zero by default + keep a spend cap + limit retries and unsafe scale + make warm capacity exceptional + review 5-minute usage after changes ``` At Raff, we would rather see a team deliberately raise a well-understood cap than start with an effectively unlimited budget because “serverless should scale.” Scaling safely means knowing both the technical and financial boundary. :::cta View Pricing Review the current Raff Functions pricing model before setting production spend caps, warm capacity, and usage guardrails. ::: ## Raise the cap only after classifying the cause Approaching a spend cap does not automatically mean the cap is too low. Use this decision framework first: | What changed? | Likely response | Raise cap now? | |---|---|---| | Legitimate customer traffic increased | Confirm demand and forecast next range | Possibly, with headroom | | Marketing launch created planned burst | Verify service health and duration | Temporary increase may fit | | Webhook retries spiked | Fix acknowledgement/idempotency | No | | Cron runs overlap | Add lock/skip/queue policy | No | | Storage event retriggers itself | Stop trigger and separate prefixes | No | | Warm baseline expanded | Review which endpoints need it | Usually not until justified | | Function duration increased | Find slow dependency or code path | Not before diagnosis | | Concurrency overwhelms database/API | Lower or shape scale; fix dependency path | No | | Workload became continuously busy | Compare always-on compute | Do not solve only with a larger cap | The last row matters. Serverless cost controls should not trap a workload in the wrong compute model. If a function is now continuously busy, needs warm capacity all day, or consumes predictable resources with little idle time, compare it with [Serverless Functions vs VMs](/learn/guides/serverless-functions-vs-vms-small-teams). The economic advantage of usage-based execution gets smaller as idle time disappears. Do not move solely because one month was busy. Look for a sustained workload-shape change. ## A launch checklist keeps cost governance concrete Before a production function goes live, record these decisions: - [ ] The function has one owner. - [ ] The trigger and expected invocation pattern are documented. - [ ] Expected normal usage is understood. - [ ] A spend cap is enabled and reviewed. - [ ] The team knows what happens when the cap is reached. - [ ] Retry limits are defined. - [ ] The function is idempotent where duplicate delivery is possible. - [ ] Cron overlap behavior is defined. - [ ] Storage event input and output paths cannot create an unintended loop. - [ ] Concurrency/scale fits downstream capacity. - [ ] Warm instances are off unless latency measurements justify them. - [ ] A responsible person approves warm-capacity changes. - [ ] Usage is reviewed after major deployments and traffic events. - [ ] Logs and metrics can identify the function causing an anomaly. - [ ] The team knows when to compare the workload with a VM or container. This checklist is deliberately operational. A pricing spreadsheet cannot prevent a retry storm or recursive trigger. The controls around the function can. ## Cost controls should make serverless safer to scale Serverless cost management works best when financial and technical guardrails are designed together. Use a spend cap to limit account-level exposure, but leave enough headroom for healthy traffic. Keep scale-to-zero as the default and approve warm instances only for latency-sensitive paths that have measured need. Limit retries, overlap, and concurrency so one mistake cannot multiply execution faster than the team can react. Raff's default spend cap, pause behavior, 5-minute usage visibility, scale controls, and optional warm capacity give teams the tools to build that policy. The important part is using them deliberately. When usage rises, classify the cause before raising the cap. If the growth is legitimate, expand the budget with evidence. If the work is duplicated, looping, retrying, or becoming continuously busy, fix the workload or reconsider the compute model instead. ### Sources - [Raff Functions](/products/serverless-functions) - [Raff Pricing](/pricing) --- ### Serverless APIs and Webhooks: HTTP Functions for Small Teams URL: https://rafftechnologies.com/learn/guides/serverless-apis-webhooks-http-functions Description: Learn when serverless APIs and HTTP Functions fit webhooks, callbacks, small APIs, and event-driven endpoints, and when a persistent app runtime fits better. A serverless API is an HTTP endpoint whose application logic runs as on-demand functions instead of a continuously managed application server. That model fits small teams when HTTP work is bounded, independently deployable, and able to keep durable state outside the function. The same HTTP function can serve a small API route, receive a webhook, handle a callback, or expose a lightweight internal endpoint without requiring the team to operate a full web server for that task. The important decision is not whether HTTP is "serverless." It is whether the request can be handled as a clear unit of work. A webhook that validates a signature, records an event, and returns is function-shaped. A large application with many routes, long-lived connections, shared in-process state, and constant traffic may fit a persistent app runtime better. At Raff, we use HTTP Functions as an event boundary: receive the request, authenticate or validate it, perform bounded work, write durable state, and return. This guide maps that operating model. The deeper implementation topics—webhook retries, API authentication, CORS, rate limiting, and choosing Function URLs versus an App Platform API—belong to their dedicated guides. ## Serverless APIs turn HTTP requests into function invocations A traditional application server stays running and listens for requests continuously. A serverless API maps incoming HTTP traffic to function execution. ```text Client / external service ↓ HTTPS URL ↓ HTTP Function ↓ Database / Object Storage / external API ↓ Response ``` The HTTP interface can still look like a normal API. Clients do not need to know whether the code behind the endpoint runs on a function, container, VM, or another compute model. The difference is operational: | Area | Serverless HTTP function | Persistent app runtime | |---|---|---| | Lifecycle | Runs from incoming demand | Process stays running | | Scaling | Function instances scale with load | App replicas or servers scale | | Idle capacity | Can scale down aggressively | Depends on app platform/runtime | | OS/process management | Mostly platform-owned | More runtime ownership | | State | Should be external/durable | Can reuse process state, but durable data still external | | Best fit | Bounded endpoints and event receivers | Larger persistent applications | A serverless API is therefore not a different HTTP protocol. It is a different execution model behind the HTTP boundary. The [Serverless vs Containers guide](/learn/guides/serverless-vs-containers) owns the broader lifecycle decision. This guide focuses specifically on HTTP APIs and webhooks built from functions. ## HTTP APIs fit when requests are bounded and independent A serverless HTTP endpoint is strongest when one request can be understood and completed independently. Good candidates include: - small REST-style endpoints; - form submissions; - API callbacks; - webhook receivers; - internal utility endpoints; - lightweight authorization callbacks; - metadata lookups; - short data transforms; - status-update endpoints; - endpoints that trigger asynchronous work; - low or irregular traffic APIs. The common shape is: ```text request arrives ↓ validate/authenticate ↓ perform bounded work ↓ write durable state if needed ↓ return response ``` This works especially well when endpoints have different traffic patterns. A billing webhook, image callback, and internal admin endpoint do not need to share the same scaling profile simply because they belong to one product. A function also creates a useful isolation boundary. External webhook retries or traffic spikes do not need to compete directly with the main application process. However, splitting every route into a separate function is not automatically better. Each deployment unit adds configuration, ownership, logs, secrets, and failure modes. Keep related routes together when that makes the application easier to operate. ## Webhooks are a specialized HTTP API workload A webhook is an HTTP request sent by another system to tell your application that an event occurred. Examples include: - payment succeeded; - subscription changed; - Git event occurred; - email bounced; - CRM record changed; - form was submitted; - monitoring alert fired; - document was signed. Because webhooks are event-driven, they are a natural serverless workload. But webhook correctness requires more than exposing a URL. A safe high-level flow is: ```text provider request ↓ validate sender/signature ↓ check duplicate event ↓ store durable event state ↓ acknowledge quickly ↓ process slow work separately ``` This connector guide deliberately does not own the detailed retry, signature, idempotency, replay, and durable-event design. Those belong to [Webhooks on Serverless Functions](/learn/guides/serverless-functions-for-webhooks). The ownership boundary matters for SEO and for readers: this page explains where HTTP Functions fit; the webhook guide explains how to operate a webhook endpoint safely. ## API state should live outside the function runtime Serverless HTTP code should not depend on one execution environment surviving for the next request. Durable state belongs in services designed to persist it: - user and application records → database; - sessions or durable tokens → appropriate persistent store; - uploaded files and generated artifacts → object storage; - job status → database; - secrets → environment or secret management; - long-running workflow state → database, queue, or workflow system. A safe pattern looks like this: ```text HTTP Function ↓ Managed Database = durable records Object Storage = files/artifacts External API = third-party action ``` Warm execution environments may let code reuse initialized clients or connection pools temporarily, but correctness should never depend on that reuse. This is one of the strongest architecture tests for serverless APIs: if the endpoint only works when local process state survives between requests, it is not cleanly function-shaped. ## Authentication, CORS, and rate limiting are separate API controls Putting an API behind a function does not remove normal HTTP security requirements. Production endpoints still need decisions around: - authentication and authorization; - CORS policy; - rate limiting or abuse controls; - request size and validation; - secret handling; - logging sensitivity; - tenant isolation; - replay protection where relevant; - API versioning; - error behavior. These controls should be designed per endpoint family. A public webhook receiver, browser-facing API, and internal service endpoint have different trust boundaries. The roadmap's dedicated **Serverless API Authentication, CORS, and Rate Limiting** guide owns those controls in depth. This connector keeps them visible as architectural requirements without duplicating that future article. A useful rule is: **serverless changes who operates the runtime; it does not remove the responsibilities of an Internet-facing API.** ## Function URLs work best when the HTTP surface stays simple A direct function URL can be a clean interface when a team needs one bounded HTTP service without a large routing layer. Good examples include: - one webhook receiver; - one callback endpoint; - a small internal API; - a narrow public endpoint; - a lightweight microservice with a few related routes. As the HTTP surface grows, the decision becomes broader. Teams may want a persistent application runtime when they need: - many tightly coupled routes; - long-lived connections; - extensive middleware; - shared in-process caches; - complex routing behavior; - a continuously busy API; - several coordinated background processes; - a full application framework running as one service. That next decision belongs to the planned **Function URLs vs App Platform APIs** guide. The point here is to avoid treating every HTTP endpoint as either "must be a function" or "must be a full app." The right boundary follows workload shape. ## Serverless APIs still need latency and concurrency planning HTTP functions can scale independently, but that scaling can move pressure downstream. A burst of API requests may create more simultaneous: - database connections; - external API calls; - object-storage operations; - authentication checks; - queue writes. The function platform being able to scale does not prove every dependency can absorb that scale. Use a capacity chain: ```text incoming HTTP traffic ↓ function scale/concurrency ↓ database / API / storage capacity ``` For latency-sensitive endpoints, cold-start behavior may also matter. Raff Functions supports scale-to-zero and optional warm capacity, so teams can choose between avoiding idle capacity and keeping latency-sensitive execution ready. The [Cold Starts, Concurrency, and Scale-to-Zero guide](/learn/guides/serverless-cold-starts-concurrency-scale-to-zero) owns startup behavior. The [Runtime Limits guide](/learn/guides/serverless-function-timeout-memory-concurrency-limits) owns hard timeout and capacity limits. This page only establishes that HTTP API design must account for both. ## Raff Functions provides a direct HTTP runtime Raff Functions currently supports HTTP live URLs with automatic TLS, alongside cron, one-off, and object-storage triggers. HTTP code can use standard handler patterns including Python FastAPI/ASGI, Node.js standard HTTP, JavaScript Web Fetch, TypeScript, and Go `net/http`, with a Dockerfile escape hatch for custom runtimes. That matters for API portability. The application can look like normal HTTP code rather than depending on a Raff-specific request/response signature. Current Raff Functions also provides: - scale-to-zero and load-based autoscaling; - editable runtime settings; - logs and metrics for invocations; - live log tail; - invocation count, p50, p95, and error-rate visibility; - timeouts up to **1 hour by default and up to 24 hours on request**; - bindings to managed databases and object storage; - a per-account spend cap that is on by default. Those characteristics make HTTP Functions useful for small APIs and event receivers that need to run independently without the team operating a full server just for the endpoint. They do not mean every API should become a function. A continuously busy application with a broad HTTP surface may be easier to operate as a persistent app or container runtime. :::cta View Pricing Compare Raff Functions with persistent compute after deciding whether your HTTP workload is bounded and event-driven. ::: ## Choose the HTTP runtime by request and application shape Use this framework before deployment: | HTTP workload | Better starting point | Why | |---|---|---| | Payment webhook | Function | Event-driven and isolated | | Git/CRM/email webhook | Function | Irregular external callbacks | | Small internal utility API | Function | Narrow bounded HTTP work | | Low-traffic public endpoint | Function | Can benefit from scale-to-zero | | Endpoint that starts background work | Function | Acknowledges and hands off bounded work | | Large application with many coupled routes | Persistent app runtime | Shared app lifecycle is clearer | | WebSocket/long-lived connection service | Persistent app runtime | Connection lifecycle matters | | Always-busy API | Compare both | Little idle time reduces scale-to-zero advantage | | API needing custom runtime but bounded requests | Function with Dockerfile may fit | Keeps event lifecycle with custom environment | | App plus several webhooks | Mixed | Persistent app + isolated webhook functions | Then ask: 1. Can one request complete as a bounded unit of work? 2. Can durable state live outside the execution environment? 3. Can the endpoint tolerate the function runtime limits and startup model? 4. Does independent scaling simplify operations? 5. Is the HTTP surface still small enough that function-level ownership remains clear? If the answers are mostly yes, a serverless API is a strong starting point. ## HTTP Functions should create a clean event boundary Serverless APIs work best when HTTP requests map cleanly to bounded application work. Use Functions for webhooks, callbacks, small APIs, and narrow endpoints that should scale independently and avoid idle server ownership. Keep durable records in a database and files in object storage. Treat authentication, CORS, rate limiting, retries, and downstream capacity as production concerns rather than features the serverless label solves automatically. For Raff teams, HTTP Functions provide standard handlers, TLS URLs, autoscaling, logs, metrics, and a path to custom Dockerfile runtimes. Keep the main application on a persistent runtime when its process needs to stay alive, and use Functions where an HTTP event should start and finish independently. ### Sources - [Raff Functions](/products/serverless-functions) - [Raff Pricing](/pricing) - [Postman — Serverless Architecture and Serverless APIs](https://blog.postman.com/serverless-architecture-and-the-feasibility-of-serverless-apis/) --- ### Serverless API Security: Authentication, CORS & Rate Limiting URL: https://rafftechnologies.com/learn/guides/serverless-api-security-authentication-cors-rate-limiting Description: Learn how to secure serverless APIs with authentication, authorization, CORS, rate limiting, validation, scoped secrets, and safe HTTP Function boundaries. Serverless API security is the set of controls that decides who may call an HTTP Function, what a browser may send, how much traffic a client may generate, and what the function is allowed to access after a request is accepted. Moving an API endpoint to serverless does not remove normal application-security responsibilities. The platform can manage the execution environment and scaling layer, but your application still needs authentication, authorization, request validation, CORS policy, abuse controls, scoped credentials, safe logs, and a clear trust boundary. For small teams, the main risk is treating these controls as one problem. They solve different problems. Authentication proves identity. Authorization decides what that identity may do. CORS controls which browser origins may read responses. Rate limiting controls request pressure. Input validation decides whether the request is acceptable at all. At Raff, we recommend separating those decisions before deploying an HTTP Function. A public webhook, a browser-facing API, and an internal service endpoint should not inherit the same security policy simply because they all use HTTPS. ## Serverless API security starts with the trust boundary Before choosing tokens, headers, or rate limits, define who is supposed to call the endpoint. A useful classification is: | Endpoint | Expected caller | Main controls | |---|---|---| | Public webhook | Known external provider | Signature/token validation, replay protection, idempotency | | Browser API | Authenticated user in approved frontend | Authentication, authorization, CORS, validation, rate limiting | | Public unauthenticated endpoint | Anyone | Strict validation, abuse controls, conservative rate limiting | | Internal service endpoint | Known service identity | Service authentication, scoped authorization, network/app controls | | Admin endpoint | Privileged staff/service | Strong authentication, authorization, narrow access, auditability | This prevents a common mistake: protecting every endpoint only with one shared API key or one broad IP rule. The trust boundary should answer: - Who can reach the URL? - Who should be accepted? - What identity is available after authentication? - What may that identity do? - Which browser origins are expected? - How much traffic should one identity generate? - What downstream systems can the function access? **A public URL is not the same as a public API. The URL may be Internet-reachable while the application still requires a verified identity before doing useful work.** ## Authentication and authorization solve different problems Authentication answers: **Who is calling?** Authorization answers: **What is that caller allowed to do?** A secure API normally needs both. Examples of authentication inputs include: - bearer tokens; - signed session tokens; - API keys; - service credentials; - webhook signatures or shared secrets; - application-specific session cookies. After the caller is authenticated, the handler should make an authorization decision using application context such as: - user ID; - tenant/account ID; - role; - API-key scope; - resource ownership; - action being requested. A simplified path is: ```text HTTP request ↓ authenticate caller ↓ resolve identity ↓ authorize requested action/resource ↓ validate input ↓ perform business logic ``` Do not confuse possession of a credential with permission to perform every action. One API key should not automatically grant access to every tenant, bucket, database operation, or administrative endpoint. For serverless functions, this separation is especially useful because functions are easy to expose independently. Each function or endpoint family can have a narrower security policy rather than inheriting one large application boundary. ## CORS is a browser policy, not authentication Cross-Origin Resource Sharing (CORS) controls whether browser JavaScript from one origin may read responses from another origin. CORS does **not** prove who the user is. It does not stop command-line clients, backend services, bots, or attackers from sending HTTP requests directly. That distinction is critical. If your frontend runs at: ```text https://app.example.com ``` and calls: ```text https://api.example.com ``` then the API may need to permit that origin through CORS. But the endpoint should still authenticate and authorize the user separately. A useful mental model is: | Control | Question answered | |---|---| | CORS | May browser code from this origin read the response? | | Authentication | Who is the caller? | | Authorization | May this identity perform this action? | | Rate limiting | How much traffic may this client/identity generate? | | Validation | Is this request structurally and semantically acceptable? | Do not use `Access-Control-Allow-Origin: *` as a shortcut on credentialed browser APIs unless the endpoint is intentionally public and the browser security model supports the intended flow. Use the narrowest origin policy that matches the application. Development, staging, and production frontends may need separate allowed origins rather than one broad wildcard. **CORS can reduce unwanted browser access, but it is never a replacement for server-side authorization.** ## Rate limiting protects the function and its dependencies Rate limiting controls how much request traffic a client, identity, tenant, token, or source may generate within a defined window. For serverless APIs, that matters for two reasons: 1. uncontrolled requests can increase function execution; 2. fast function scaling can transfer pressure to databases, APIs, queues, and other dependencies. The right enforcement key depends on the endpoint: - unauthenticated endpoint → IP/source plus route may help; - authenticated API → user, tenant, or API key is usually more meaningful; - internal service → service identity; - expensive operation → identity plus endpoint/action; - webhook receiver → provider/account/event behavior rather than browser identity. This guide does not own generic rate-limiter algorithms, quota headers, or detailed HTTP 429 design. Raff already has [API Rate Limiting Explained](/learn/guides/api-rate-limiting-protecting-apps-real-users), which covers fixed/sliding windows, token/leaky buckets, rate-limit keys, 429 responses, quotas, queueing, and user experience. The serverless-specific point is architectural: place a limit before one caller can turn automatic scale-out into uncontrolled compute or downstream pressure. A simple capacity chain is: ```text client traffic ↓ rate / abuse control ↓ function concurrency and scale ↓ database / API / storage capacity ``` Rate limiting and concurrency are related but different. Rate limiting controls incoming request behavior. Concurrency controls how much work executes at once. A production API may need both. ## Request validation should happen before expensive work Authentication does not make input safe. Once identity is established, validate the request before the handler performs expensive or irreversible operations. Validate dimensions such as: - required fields; - types and formats; - maximum body size; - allowed content types; - enum/value ranges; - resource identifiers; - tenant/resource ownership; - filenames and object keys; - URLs or callback destinations; - pagination and query bounds. Reject invalid requests early rather than letting them consume database queries, storage operations, external API calls, or long-running CPU work. This is both a security and cost-control measure. A malformed request that triggers expensive processing can be operationally harmful even when it is not a sophisticated attack. For endpoints that start asynchronous work, validate and authorize before creating the job. Do not queue unauthorized or structurally invalid work and hope a later worker rejects it. ## Webhook security needs signatures and replay awareness Webhooks are a special case because the caller is usually another service rather than a human user. A webhook should normally verify whatever sender-authentication mechanism the provider documents, such as: - HMAC signature; - signed timestamp; - shared secret/token; - provider-specific authorization header. Where the provider supplies an event ID or timestamp, use it to reduce duplicate or replay risk. The secure flow is: ```text receive raw request ↓ verify provider signature/token ↓ check timestamp/replay rule when available ↓ check duplicate event ID ↓ store durable event state ↓ acknowledge quickly ``` The existing [Webhooks on Serverless Functions guide](/learn/guides/serverless-functions-for-webhooks) owns the detailed signature, idempotency, retry, replay, and durable-event architecture. This guide keeps webhook authentication in scope only to distinguish it from browser/user authentication. Do not apply browser CORS thinking to webhook senders. Server-to-server webhook requests are not controlled by the browser's CORS policy. ## Secrets and downstream credentials should stay scoped An HTTP Function often needs access to more sensitive systems than the public caller should ever see directly. Examples include: - database credentials; - object-storage keys; - third-party API tokens; - webhook secrets; - encryption/signing keys; - internal service credentials. Keep those values out of source code and request-visible responses. Give each function only the access it actually needs. A useful scope model is: ```text Public request ↓ Function identity / environment secrets ↓ Only required database / bucket / external API permissions ``` Raff Functions currently supports environment variables and masked secrets, plus scoped bindings to Raff Managed Databases and Raff Object Storage. Use those features to avoid putting broad credentials into code or sharing one credential across unrelated functions. Scope also reduces incident impact. A file-processing function should not automatically have access to unrelated databases. A public webhook should not receive administrator-level infrastructure credentials just because another function needs them. ## Logs should help investigations without leaking credentials Security failures need enough context to investigate, but logs can create a second exposure path if they capture sensitive request data. Useful security log fields include: - request ID; - endpoint/function name; - authenticated user/service ID; - tenant/account ID where safe; - authorization result; - validation failure category; - HTTP status; - rate-limit result; - provider event ID for webhooks; - duration; - safe error code. Avoid logging: - passwords; - bearer tokens; - API keys; - session cookies; - full webhook secrets/signatures when unnecessary; - database credentials; - sensitive request bodies. Raff Functions currently includes invocation logs and metrics, live log tail, 14-day log retention, invocation count, p50, p95, and error rate. Those signals can help correlate authentication failures, validation errors, traffic spikes, and function behavior without embedding secrets in log messages. A good security log explains **what happened and to which identity/resource**, not the credential that proved it. ## Serverless security controls should fail in the right order The order of checks affects both security and cost. For a typical authenticated API, a sensible order is: ```text TLS request arrives ↓ coarse abuse/request-size checks ↓ authentication ↓ authorization ↓ input validation ↓ business logic ↓ downstream data/API access ``` The exact order can vary. For example, webhook signature verification may need access to the raw request body before parsing it. Browser CORS preflight requests need their own response path. Some rate-limit keys cannot be determined until authentication resolves the user or tenant. The principle is to reject cheap failures before expensive work when it is safe to do so. **A secure function should spend the least possible work on requests it will eventually reject.** This lowers the attack surface and reduces the financial impact of abusive or broken clients. ## Raff HTTP Functions provide the runtime, not an automatic API security policy Raff Functions currently provides HTTPS live URLs with automatic TLS, standard HTTP handlers, scale-to-zero, load-based autoscaling, editable runtime settings, logs and metrics, environment variables, masked secrets, and scoped database/object-storage bindings. These product capabilities support secure API design, but they should not be interpreted as a claim that every application-level control is automatically configured for your endpoint. Your application still needs to decide: - authentication mechanism; - authorization model; - CORS origins and methods; - validation rules; - rate-limit or abuse-control layer; - webhook verification behavior; - secret scope; - safe logging policy; - downstream capacity limits. Raff also has infrastructure-level security controls such as network isolation and platform security features, but those do not replace API-layer identity and authorization. For public HTTP Functions, keep the security boundary explicit in application code or the appropriate gateway/middleware layer. Do not assume that because the platform manages the runtime, it also understands your tenant model, roles, subscription plans, or endpoint business cost. :::cta View Pricing Review Raff Functions and persistent compute pricing after defining the security and traffic controls your HTTP workload needs. ::: ## Choose controls by endpoint type Use this production framework: | Endpoint type | Authentication | CORS | Rate/abuse control | Key extra control | |---|---|---|---|---| | Browser API | User/session/bearer identity | Explicit frontend origins | Per user/tenant + route | Authorization | | Public read-only endpoint | Maybe none | Only if browser use needs it | Per source/route | Validation/caching | | Webhook | Provider signature/token | Not relevant to server-to-server caller | Source/account/event-aware | Replay/idempotency | | Internal service API | Service identity | Usually irrelevant | Per service/action | Narrow authorization | | Admin API | Strong privileged identity | Explicit admin origin if browser-based | Conservative | Auditability | | Expensive compute endpoint | User/service identity | Depends on client | Lower route/concurrency limits | Cost/job controls | Before production, confirm: - [ ] Every endpoint has a defined expected caller. - [ ] Authentication and authorization are separate decisions. - [ ] Browser origins are explicit where CORS is required. - [ ] CORS is not being used as authorization. - [ ] Invalid input is rejected before expensive work. - [ ] Rate limits or abuse controls match the identity that owns the traffic. - [ ] Concurrency cannot overwhelm downstream dependencies. - [ ] Webhook signatures/tokens are verified where supported. - [ ] Secrets live outside source code. - [ ] Function credentials are scoped to required resources. - [ ] Logs exclude tokens, keys, and sensitive payloads. - [ ] Production errors do not expose stack traces or secrets. This is more useful than copying one generic “secure serverless” checklist because each endpoint has a different trust model. ## Serverless API security is layered, not one feature A secure HTTP Function needs several controls working together. Authenticate callers that require identity. Authorize them against the requested action and resource. Use CORS only for browser-origin policy, not as access control. Validate input before expensive work. Limit abusive or accidental request pressure before autoscaling can amplify it. Keep secrets and downstream credentials scoped. Log enough context to investigate failures without logging the credentials themselves. Raff Functions supplies the managed HTTP execution environment, TLS URL, scaling, observability, secret configuration, and service bindings. Your application supplies the business-specific trust rules. That division of responsibility keeps serverless APIs simple without pretending the platform can infer who your users are or what they should be allowed to do. ### Sources - [OWASP API Security Top 10](https://owasp.org/API-Security/) - [MDN — Cross-Origin Resource Sharing (CORS)](https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/CORS) - [Raff Functions](/products/serverless-functions) - [Raff Pricing](/pricing) --- ### Serverless API Endpoint vs App Platform: Which HTTP Runtime Fits? URL: https://rafftechnologies.com/learn/guides/serverless-api-endpoint-vs-app-platform Description: Learn when a serverless API endpoint or App Platform API fits better based on workload coupling, routing, process lifecycle, deployment workflow, scaling, and cost. A serverless API endpoint is best when one HTTP request maps to a bounded unit of work. An App Platform web service is better when the application itself needs to remain running as a persistent process with a broader routing, deployment, and service lifecycle. Both can expose HTTPS APIs. Both can scale. Both can run familiar frameworks. The real difference is what your team is deploying: **one independently triggered HTTP workload, or an application service that stays available as a running process.** For small teams, this distinction prevents two common mistakes. The first is turning an entire web application into many Functions even though its routes, middleware, background processes, and deployment lifecycle belong together. The second is keeping a full app service running only to serve one occasional webhook or callback endpoint. At Raff, we treat the decision as an HTTP runtime question. Use [Raff Functions](/products/serverless-functions) when the endpoint should start from demand and finish independently. Use [Raff Apps](/products/app-platform) when the HTTP surface belongs to a persistent application service with a managed build, deploy, revision, and service lifecycle. ## Function URLs and App Platform APIs expose HTTP differently A Function URL maps HTTP traffic directly to function execution. ```text Client ↓ HTTPS Function URL ↓ Function invocation ↓ Response ``` An App Platform API runs as part of a persistent web-service process: ```text Client ↓ HTTPS web service ↓ Running app process ↓ Router / middleware / application routes ↓ Response ``` The client can see a normal HTTPS API in both cases. The difference is the runtime lifecycle behind it. | Decision area | Function endpoint | App Platform web service | |---|---|---| | Deployment unit | Function or bounded handler | Application service | | Process lifecycle | Demand-triggered execution | Long-running service process | | Routing | Narrow function-owned HTTP surface | Broader application routing | | Idle behavior | Designed to scale to zero | Platform service may also scale to zero, depending on configuration | | Background processes | Separate functions/triggers | Workers, cron, and one-off services can live in same app project | | Deployment workflow | Function deployment | Git/Docker/buildpack application deployment | | Revisions/rollback | Function lifecycle | App-level immutable revisions and rollback | | Best fit | Webhooks, callbacks, narrow APIs | Full web apps, multi-route APIs, application services | A Function URL is not inherently simpler because it has fewer routes. An app service is not inherently heavier because it is persistent. The better model is the one whose lifecycle matches the application. ## Function endpoints fit narrow, independently scalable HTTP work Use a serverless API endpoint when one HTTP workload can stand on its own. Good candidates include: - payment or SaaS webhooks; - OAuth or provider callbacks; - low-traffic public endpoints; - lightweight internal APIs; - form handlers; - status-update endpoints; - endpoints that validate a request and create background work; - isolated API routes with very different traffic from the main application; - APIs that spend meaningful time idle. A good function-shaped endpoint usually has: 1. a clear request boundary; 2. bounded execution; 3. durable state outside the runtime; 4. no requirement for one process to stay alive between requests; 5. independent traffic or scaling characteristics. For example: ```text Billing provider ↓ Webhook Function ↓ verify + store event ↓ acknowledge ``` That endpoint does not need the entire customer-facing application process just to receive an event. Raff Functions currently gives each deployed HTTP Function a live HTTPS URL with automatic TLS. Standard handlers include Python FastAPI/ASGI, Node.js HTTP, JavaScript Web Fetch, TypeScript, and Go `net/http`, with a Dockerfile escape hatch for custom runtimes. Idle Functions can scale to zero and autoscale with load. The broader [Serverless APIs and Webhooks guide](/learn/guides/serverless-apis-webhooks-http-functions) owns the architecture of HTTP Functions. This guide owns the decision about when that direct endpoint should remain a Function versus become part of a full application service. ## App Platform APIs fit application-shaped HTTP surfaces An App Platform web service is stronger when the API belongs to a larger application lifecycle. Common signals include: - many related routes; - shared middleware across the API; - a full framework application such as Django, FastAPI, Express, Rails, Laravel, or another long-running web service; - shared in-process connection pools or caches; - multiple application processes that deploy together; - background workers tied to the same release; - cron jobs tied to the same codebase; - preview environments for pull requests; - coordinated application revisions and rollback; - persistent volumes or service bindings used by the application; - a team that wants Git-based push-to-deploy across the whole service. Raff Apps currently supports GitHub push-to-deploy, Dockerfiles, auto-buildpacks, full Docker Compose imports, immutable revisions, one-click rollback, preview environments, persistent volumes, and five service types: public web, private service, worker, cron, and one-off job. That changes the operating unit. Instead of managing each endpoint as an independent function, the team deploys an application service and its related processes as one project. **If routes, middleware, workers, and releases change together, keeping them in one app-service lifecycle can be simpler than splitting them into many independently deployed Functions.** The existing [Cloud VM vs App Platform guide](/learn/guides/cloud-vm-vs-app-platform-startups) owns the broader App Platform versus server-control decision. This page stays at the HTTP layer: direct Function endpoint versus managed application API. ## Route count is a signal, not a hard threshold Teams sometimes ask how many API routes justify moving from Functions to an App Platform. There is no universal number. Five completely independent webhook endpoints can remain clean as Functions. Three tightly coupled routes sharing complex middleware, sessions, common caches, and release behavior may already be easier as one application service. Use coupling rather than raw route count: | Question | Favors Function endpoints | Favors App Platform API | |---|---|---| | Do routes deploy independently? | Yes | No, they release together | | Do routes share heavy middleware? | Little | Extensive | | Do routes share one process-level runtime? | Not needed | Useful | | Does each route have different traffic? | Often | Mostly similar | | Are workers/cron part of same codebase? | Separate is fine | Same project helps | | Is previewing whole app important? | Less important | Important | | Is one rollback boundary useful? | No | Yes | | Is traffic mostly idle/event-driven? | Yes | Less important | A function architecture should not become a directory of tiny services only because the platform makes Functions easy to create. Likewise, a full app service should not become the default place for every callback just because the main application already exists. ## Long-lived connections and process behavior favor an app service Function endpoints are designed around bounded invocations. That can be a mismatch when the application depends on a persistent process lifecycle. App-service signals include: - long-lived connections; - background threads or continuously running consumers; - stable in-process caches that materially improve the application; - multiple routes sharing a persistent connection pool; - process-level schedulers; - framework plugins expecting a conventional server lifecycle; - several coordinated HTTP and worker processes. Raff Functions supports long execution windows—up to **1 hour by default and up to 24 hours on request**—so duration alone does not force an endpoint into an App Platform. The more important distinction is whether the workload is still a bounded invocation or whether the application process itself needs to stay alive. For example, a long report-generation request can still be poor HTTP architecture even if the Function can technically run for an hour. The better pattern may be to acknowledge the request, create asynchronous work, and let the client poll or receive a callback. Do not choose a persistent app service merely to escape a short Function timeout. Choose it because the application lifecycle requires a persistent service. ## Deployment workflow can decide the model before traffic does Runtime behavior is not the only concern. The team's release workflow also matters. A set of independent Functions can be attractive when each endpoint has a clear owner and release path. But a product team may prefer a full App Platform when the whole application should move through one Git-based deployment workflow. Raff Apps currently provides: - GitHub push-to-deploy; - CLI deployment; - buildpacks or Dockerfile builds; - full Docker Compose import; - immutable revisions; - one-click rollback; - pull-request preview environments; - shareable preview URLs; - web, private, worker, cron, and one-off service types. Those features matter when an API is part of a broader application rather than an isolated endpoint. A preview environment, for example, is much more valuable when reviewers need to test the frontend, API, database bindings, and related services together. If the workload is one webhook receiver, that whole application workflow may be unnecessary overhead. **Choose the deployment boundary that matches how the team changes the software, not only how the runtime executes it.** ## Cost should be compared at the service boundary Functions and App Platform services use different economic models, so comparing one request with one app instance is misleading. Raff Functions currently bills memory and active CPU, with requests and egress free and a monthly free tier after the required account activation. The product is designed for execution that follows demand. Raff Apps currently uses flat per-instance tiers billed per second. Public application egress is $0, seats are not billed, and a spend cap is on by default. Current published tiers start at **$3/month** for the Micro tier, with higher ceilings as CPU, memory, and disk increase. The useful cost question is: > Does this HTTP workload benefit more from usage that follows individual execution, or from an application service whose routes and processes share one runtime boundary? Function endpoints can be economically attractive for sporadic or independently scaling traffic. An App Platform can be attractive when many related routes and processes use the same service continuously or benefit from one release boundary. Do not use price alone to justify unnecessary fragmentation. Ten cheap Functions can still be harder to operate than one app service if they always change together. The [Serverless Function Pricing guide](/learn/guides/serverless-function-pricing-cpu-memory-egress) owns detailed Function metering. The [Cloud VM vs App Platform guide](/learn/guides/cloud-vm-vs-app-platform-startups) owns the broader app-platform cost model. ## Security controls exist in both models A direct Function endpoint and an App Platform API both need application-layer security. Both may need: - authentication; - authorization; - CORS policy for browser clients; - rate limiting or abuse controls; - input validation; - scoped secrets; - safe logs; - tenant isolation. The [Serverless API Security guide](/learn/guides/serverless-api-security-authentication-cors-rate-limiting) owns those controls for HTTP Functions. Moving an endpoint into a persistent app service does not eliminate them. It may centralize middleware and policy across many routes, which can be an operational reason to choose the App Platform model when the API surface becomes tightly coupled. Conversely, isolating a sensitive webhook or public callback in a separate Function can reduce its blast radius and keep third-party traffic away from the main application service. The security question is therefore also about boundaries: should this endpoint share the main application's security middleware and release lifecycle, or should it be isolated as its own HTTP Function? ## Raff makes a mixed HTTP architecture practical A production application does not need to choose one runtime for every HTTP endpoint. A practical Raff architecture can look like: ```text Frontend / clients ↓ Raff Apps web + API service ↓ Managed Database External providers ↓ Raff Functions webhooks/callbacks ↓ Managed Database / Object Storage ``` The main application receives customer traffic through an App Platform web service. External event receivers and occasional callbacks run as Functions. Both can connect to durable data services rather than forcing every workload into one process model. This mixed model is useful because it keeps each boundary understandable: - main application routes deploy together; - webhooks scale independently; - cron work can live in Functions or an Apps cron service depending on ownership; - workers can live with the App project when they share its release lifecycle; - isolated event processing can remain a Function. At Raff, we would not move a healthy Function endpoint into Apps only because traffic grew. We would move it when the endpoint becomes application-shaped: tightly coupled routes, shared middleware, coordinated releases, or persistent process behavior become more important than independent execution. :::cta View Pricing Compare Raff Functions and Raff Apps after deciding whether your HTTP workload is endpoint-shaped or application-shaped. ::: ## Use workload coupling as the final decision framework Start with these questions: | Question | Function endpoint | App Platform API | |---|---|---| | Is the HTTP work independently deployable? | Strong fit | Less important | | Is traffic sporadic or event-driven? | Strong fit | Can still fit | | Does the service need many related routes? | Possible, but review coupling | Strong fit | | Is shared middleware central to the app? | Can duplicate or package it | Strong fit | | Do workers/cron deploy with the same release? | Separate runtime may be fine | Strong fit | | Are preview environments important? | Endpoint-level testing | Whole-app previews fit better | | Does the process need to stay alive? | Weak fit | Strong fit | | Should one external endpoint be isolated? | Strong fit | Could unnecessarily share blast radius | | Does one app rollback need to revert all routes? | Weak fit | Strong fit | Then follow this sequence: 1. **Can the endpoint start and finish independently?** Start with a Function. 2. **Do routes, middleware, and releases belong together?** Start with an App Platform web service. 3. **Does the process itself need to stay alive?** Favor the App Platform. 4. **Is the endpoint third-party/event traffic that should be isolated?** Favor a Function. 5. **Do you need both?** Keep the main app on Apps and extract independently scaling endpoints into Functions. The strongest signal is coupling. If the endpoint is independent, Functions keep the runtime boundary small. If the HTTP surface is one application, Apps keeps the deployment boundary coherent. ## Choose the HTTP runtime that matches how the software behaves Function URLs and App Platform APIs can both expose production HTTPS endpoints. The useful distinction is not "serverless versus PaaS" as a technology contest. It is whether the software behaves like an independent invocation or a persistent application service. Use Raff Functions for webhooks, callbacks, narrow APIs, and independently scaling HTTP workloads. Use Raff Apps when routes, middleware, workers, previews, and releases belong to one managed application lifecycle. Mix them when the main app and event-driven endpoints have different operational needs. A clean runtime boundary should make deployment, scaling, security, and debugging easier for the team. If the boundary creates more coordination than it removes, choose the other model. ### Sources - [Raff Functions](/products/serverless-functions) - [Raff Apps](/products/app-platform) - [Raff Pricing](/pricing) --- ### Docker Resource Limits, Logging, and Disk Management URL: https://rafftechnologies.com/learn/guides/docker-resource-limits-logging-disk-management Description: Control Docker CPU, memory, logs, and disk growth on production VMs with clear limits, rotation, monitoring, and safe cleanup policies. Running Docker in production means more than keeping containers up. A single noisy process, an unbounded log file, or years of unused image layers can destabilize the whole VM even when every container is otherwise configured correctly. The practical goal is simple: **give important containers explicit resource boundaries, make log growth predictable, and treat Docker disk usage as an operating metric instead of an emergency.** This guide owns those production mechanics. It complements [Docker on a Cloud VM](/learn/guides/docker-on-a-cloud-vm-architecture-security-operations), which defines the overall host architecture, and [Docker Host Security Checklist for Production VMs](/learn/guides/docker-host-security-checklist-production-vms), which owns privilege and exposure controls. For persistent application data, use [Docker Volumes vs Bind Mounts](/learn/guides/docker-volumes-vs-bind-mounts-production). ## Docker resource limits are host stability controls Docker containers do not receive automatic CPU or memory ceilings just because they run in separate containers. By default, a container can use as much CPU or memory as the host kernel allows. That is convenient during development, but it can turn one runaway process into a host-wide incident in production. A useful production model separates three questions: | Question | Control | |---|---| | How much memory can this container consume? | Memory limit and optional reservation | | How much CPU can this container use? | CPU quota or CPU share policy | | How much spare capacity should remain for the host? | VM-level headroom | The host always needs capacity for more than the application containers. Docker Engine, the operating system, SSH, monitoring agents, filesystem cache, backup jobs, package updates, and short traffic bursts all compete for the same resources. A container limit is therefore not only about fairness between containers. It protects the host boundary itself. A production VM should avoid both extremes: - **No limits anywhere:** one service can consume the whole machine. - **Limits set exactly at idle usage:** ordinary traffic bursts cause throttling or OOM failures. The better model is measured limits plus host headroom. ## Memory limits should reflect failure tolerance, not guesses Memory pressure behaves differently from CPU pressure. CPU overuse normally causes throttling and slower work. Memory exhaustion can cause process termination. On Linux, if the host reaches severe memory pressure, the kernel's out-of-memory system may kill processes to recover capacity. Docker documents hard and soft memory controls: - `--memory` creates a hard ceiling; - `--memory-reservation` creates a softer target used during contention; - swap behavior can be controlled separately; - Docker recommends leaving the OOM protections in place rather than disabling them casually. A practical policy is: | Workload | Memory approach | |---|---| | Stateless API or worker | Use a measured hard limit with restart and monitoring | | Cache | Set an application-level cache limit and a container limit | | Build job | Allow burst capacity, but prevent it from consuming the host | | Database | Size deliberately and avoid tight limits that conflict with database memory behavior | | Reverse proxy | Usually small, but still monitor for unexpected growth | The most dangerous memory configuration is often not a limit that is too low. It is an important service with no known memory budget at all. ### OOM behavior should be observable If a container reaches its memory ceiling, the operator needs to know whether the failure came from: - a legitimate traffic spike; - a memory leak; - a bad deployment; - an undersized limit; - an undersized VM; - another container creating host-level pressure. Treat OOM events as capacity signals. Repeatedly raising limits without understanding the cause only moves the failure point. Avoid disabling the OOM killer as a general reliability tactic. Docker specifically warns that disabling OOM handling without a memory limit can allow a container to create host-wide memory exhaustion. ## Swap is a buffer, not a replacement for RAM Swap can prevent a short burst from immediately exhausting physical memory, but it changes performance characteristics. A container that repeatedly pushes active application memory into swap may remain alive while becoming dramatically slower. That can be worse than an explicit failure for latency-sensitive services. Docker's memory controls allow several models: - no explicit container memory limit; - memory limit with additional swap allowance; - memory limit with swap disabled for that container; - unlimited container swap up to host availability. There is no universal production value. The right choice depends on the workload. Use swap conservatively for: - short non-latency-sensitive bursts; - background jobs; - hosts where a small emergency buffer is preferable to immediate OOM. Be more cautious for: - databases; - low-latency APIs; - caches; - workloads where swap thrashing would create cascading timeouts. The main rule is to know whether swap is part of the operating design. Do not let it become an invisible performance fallback. ## CPU limits prevent noisy neighbors without creating false guarantees CPU is generally easier to constrain than memory because saturation usually slows work rather than killing it. Docker's `--cpus` option is the simplest hard ceiling for many workloads. A value of `0.5` allows up to half of one CPU, while `1.5` allows up to one and a half CPUs worth of scheduling time. CPU shares are different. They influence relative priority when CPU is contended, but they are not a strict reservation when the host is otherwise idle. That creates two useful patterns: | Goal | Better control | |---|---| | Prevent a background job from monopolizing the host | Hard CPU limit | | Let several services share spare CPU but prioritize one | CPU shares / relative weight | | Pin a specialized workload to specific cores | CPU set, only when needed | | Guarantee real-time behavior | Advanced kernel scheduling, not a normal Docker default | For most small teams, explicit `cpus` values are easier to reason about than low-level scheduler tuning. The key production mistake is confusing a CPU limit with capacity planning. A container limited to one CPU can still saturate that CPU continuously. The limit protects neighbors; it does not prove the service has enough compute. ## Compose should make resource policy visible For multi-service applications, resource policy belongs in the same versioned deployment model as the services themselves. Current Docker Compose supports service-level CPU and memory controls, including `cpus`, `mem_limit`, memory reservation, swap settings, PID limits, and deployment resource limits. A small production example might look like: ```yaml services: app: image: example/app:1.4.2 cpus: 1.5 mem_limit: 1g mem_reservation: 512m worker: image: example/app:1.4.2 command: worker cpus: 0.75 mem_limit: 768m ``` The exact values are workload-specific. The important part is that the limits are visible, reviewable, and changed intentionally alongside the application configuration. Do not copy resource values from another stack merely because the services use the same language or framework. Two Node.js, Python, or Java applications can have completely different memory and CPU profiles. Use observed production behavior to set limits, then leave enough room for bursts and host services. ## Logging is a disk-management decision Container logs are often the quietest path to a full filesystem. Docker's default logging driver is `json-file`. Current Docker documentation explicitly notes that it does not rotate logs by default, which means a chatty container can grow its log file until the host runs out of disk space. That makes logging policy part of capacity planning. A production logging decision should answer: - Which log driver is used? - How much local log history can each container retain? - Is rotation enabled? - Are logs compressed? - Are important logs also sent off-host? - How long must logs remain searchable? - Who alerts on abnormal log volume? A useful small-team default is to prefer Docker's `local` logging driver when local Docker logs are enough. Docker recommends `local` for ordinary Engine use because it rotates logs automatically and uses a more space-efficient format than unbounded `json-file` logging. By default, the `local` driver keeps up to five 20 MB files per container before compression, or roughly 100 MB of uncompressed log history per container. That is a bounded default, not a universal retention target. ## `json-file` can still be safe when rotation is explicit Some teams keep `json-file` because tooling already expects it. That is valid if rotation is configured. For example, Docker supports a daemon-level configuration such as: ```json { "log-driver": "json-file", "log-opts": { "max-size": "10m", "max-file": "3" } } ``` This caps the retained local log set instead of allowing a single file to grow without a ceiling. Two operational details matter: 1. Changing the Docker daemon's default logging configuration affects **newly created containers**, not existing containers automatically. 2. Logging options in `daemon.json` are expressed as strings. That means a logging-policy change is incomplete until the affected containers have been recreated with the intended configuration. Do not assume that restarting Docker alone retrofits existing containers. ## Remote logging changes retention, not host responsibility Sending logs to a remote system can reduce dependence on local disk and improve incident analysis, but the Docker host still needs a clear local policy. Remote logging can fail because of: - network outages; - authentication problems; - remote service limits; - configuration mistakes; - backpressure or rate spikes. If your remote logging driver uses Docker's local cache for `docker logs`, that cache also has its own disk behavior. The architecture decision is therefore: ```text Application stdout/stderr ↓ Docker logging driver ├── bounded local retention └── optional remote aggregation ``` Do not treat remote logging as permission to ignore disk alerts on the Docker host. ## Docker disk usage comes from several different stores When a Docker VM fills its disk, the cause is not always container logs. Common consumers include: - image layers; - stopped containers; - writable container layers; - named and anonymous volumes; - bind-mounted application data; - build cache; - local container logs; - database files; - application uploads; - backup archives stored on the same VM; - operating-system logs and package cache. Docker's `docker system df` command shows disk usage managed by the Docker daemon, including images, containers, local volumes, and build cache. A more detailed review uses: ```bash docker system df -v ``` This is a much better starting point than deleting files manually from Docker's data directory. For individual running-container writable layers, `docker ps -s` can help identify containers that are accumulating unexpected filesystem changes. Large writable layers often indicate an architectural problem, such as: - logs being written inside the container instead of through the logging driver; - uploads written to the container layer instead of persistent storage; - temporary files never being cleaned; - package or build artifacts created at runtime; - application data stored in the wrong path. Containers should remain reasonably replaceable. Persistent data belongs in a deliberate storage path. ## Images and build cache should be managed, not routinely wiped Docker does not aggressively remove unused objects automatically. That conservative behavior prevents accidental deletion but also means old objects can accumulate. Normal sources of growth include: - repeated application builds; - multiple retained image tags; - old stopped containers; - BuildKit cache; - temporary CI images; - one-off debugging containers. This is not automatically waste. Build cache can make deployments much faster, and retaining a previous image can make rollback easier. The goal is not to keep Docker at minimum disk usage. The goal is to know which disk usage is intentional. Use a simple classification: | Docker object | Keep when | Review when | |---|---|---| | Current image | Running or rollback target | Never remove blindly | | Previous release image | Needed for rollback window | Remove after policy expires | | Dangling image | Rarely needed | Safe candidate after review | | Build cache | Speeds active builds | Trim when excessive or stale | | Stopped container | Needed for debugging | Remove after investigation | | Named volume | Contains intentional state | Never prune without ownership check | | Anonymous volume | Temporary or accidental state | Review before cleanup | Disk cleanup should follow ownership, not age alone. ## `docker system prune` is useful but intentionally broad `docker system prune` removes unused Docker objects such as stopped containers, unused networks, dangling images, and unused build cache. That makes it useful during controlled cleanup, but it should not be treated as a cron job that blindly runs on every production host. Docker intentionally does **not** remove volumes by default with `docker system prune`, because unused volumes may contain important data. Adding broader flags increases the blast radius: - `-a` also removes unused tagged images, not only dangling ones; - `--volumes` can remove unused anonymous volumes; - separate volume-prune commands can remove named volumes when explicitly requested. Before pruning production systems, ask: 1. Which images are required for rollback? 2. Are stopped containers still needed for debugging? 3. Which volumes contain state? 4. Is build cache intentionally retained for deployment speed? 5. Can the deleted object be recreated safely? A safer production habit is inspect first, prune second. ## Volumes need a different cleanup policy from images Image cleanup and volume cleanup should not share the same automation policy. Images are generally reproducible artifacts. Volumes may contain primary data. That means this command category: ```text image prune container prune build cache prune ``` has a fundamentally different risk profile from: ```text volume prune ``` If a named volume exists without an attached running container, that does not mean it is disposable. It may belong to a stopped database, a migration, a rollback path, or a workload waiting to be recreated. Every production volume should have an owner and purpose. For the persistence decision, use [Docker Volumes vs Bind Mounts](/learn/guides/docker-volumes-vs-bind-mounts-production). This guide only owns operational disk pressure and cleanup policy. ## Disk alerts should trigger before Docker reaches emergency state A full filesystem can cause failures that look unrelated to storage: - databases stop accepting writes; - containers fail to start; - deployments fail while extracting images; - log writes fail; - package upgrades fail; - applications return unexpected errors; - monitoring agents stop recording data. The host should alert before it reaches that point. A useful monitoring set includes: - root filesystem utilization; - Docker data-root utilization if separate; - rate of disk growth; - inode usage; - Docker image and build-cache growth; - per-volume growth for important data; - application-specific data growth; - abnormal container log rates. Do not pick one percentage threshold and assume it fits every VM. A host with 20 GB free and a database growing 5 GB per hour is in more danger than a host with 10 GB free and stable usage. Monitor both remaining capacity and growth rate. ## Production headroom should be deliberate Resource limits are most effective when the VM itself has spare capacity. If the sum of all container hard limits equals the entire VM capacity, the host has no room for: - Docker Engine; - filesystem cache; - monitoring; - SSH sessions; - backup jobs; - deployments; - short application bursts; - kernel memory; - operating-system processes. Likewise, a disk that is intentionally filled to 95% in normal operation leaves little space for image pulls, database maintenance, temporary files, and log bursts. Think in terms of three layers: ```text VM capacity ├── operating-system + Docker reserve ├── normal container demand └── burst / maintenance headroom ``` The correct percentages depend on the workload. The principle does not. ## A practical production baseline Use this baseline before treating a Docker VM as production-ready: | Area | Production baseline | |---|---| | Memory | Important containers have measured limits or a documented reason not to | | CPU | Noisy background services cannot monopolize the host | | Swap | Behavior is intentional and monitored | | OOM | OOM events are visible and investigated | | Compose | Resource policy is versioned with the service definition | | Logging | Log growth is bounded locally | | Logging driver | `local`, rotated `json-file`, or deliberate remote driver | | Disk usage | `docker system df` is part of routine review | | Writable layers | Unexpected growth is investigated | | Images | Rollback images retained intentionally; stale artifacts reviewed | | Build cache | Retained for speed but bounded by policy | | Volumes | Never deleted only because Docker reports them unused | | Pruning | Manual or controlled automation with understood scope | | Alerts | Capacity and growth are monitored before emergency thresholds | | Host headroom | Capacity remains for OS, Docker, maintenance, and bursts | This is a stronger production model than simply scheduling a weekly `docker system prune`. ## Raff VM sizing should follow measured aggregate demand On a Raff VM, Docker containers share the CPU, memory, storage, and network resources available to the guest operating system. The best sizing workflow is therefore: 1. observe normal and peak container usage; 2. apply sensible service-level limits; 3. preserve headroom for the host and maintenance activity; 4. monitor growth over time; 5. resize the VM when the aggregate workload consistently approaches the intended operating range. Avoid sizing a VM from a fixed “containers per server” rule. A single database or build container can use more resources than dozens of lightweight web services. The same applies to disk. Image count alone does not tell you whether the host is safe. Logs, volumes, uploads, database growth, and build cache all matter. Use the live [Raff VM](/products/raff-vm) page when selecting current compute capacity. :::cta server Deploy a Raff VM with enough headroom to set explicit Docker resource, logging, and disk policies from the start. ::: ## Docker operations stay predictable when growth is bounded Docker resource limits, logging, and disk management solve one production problem: **prevent normal container behavior from turning into host-wide instability.** Set memory limits from measured demand and understand OOM behavior. Use CPU limits to prevent noisy neighbors without confusing throttling with capacity. Keep local logs bounded. Inspect Docker disk usage before cleanup. Treat images and build cache as reproducible artifacts, but treat volumes as potentially irreplaceable state. Most importantly, monitor capacity early enough that cleanup and resizing remain routine operations rather than incident response. Continue with [Docker on a Cloud VM](/learn/guides/docker-on-a-cloud-vm-architecture-security-operations) for the complete host model and [Docker Host Security Checklist](/learn/guides/docker-host-security-checklist-production-vms) for privilege, daemon, and network hardening. ### Sources - [Docker resource constraints](https://docs.docker.com/engine/containers/resource_constraints/) - [Configure Docker logging drivers](https://docs.docker.com/engine/logging/configure/) - [Local logging driver](https://docs.docker.com/engine/logging/drivers/local/) - [JSON file logging driver](https://docs.docker.com/engine/logging/drivers/json-file/) - [Docker system df](https://docs.docker.com/reference/cli/docker/system/df/) - [Prune unused Docker objects](https://docs.docker.com/engine/manage-resources/pruning/) - [Docker Compose service resource options](https://docs.docker.com/reference/compose-file/services/) --- ### Docker Host Security Checklist for Production VMs URL: https://rafftechnologies.com/learn/guides/docker-host-security-checklist-production-vms Description: Use this Docker host security checklist to harden production VMs across daemon access, privileges, networking, images, secrets, updates, and recovery. A secure Docker host is not just a VM with a firewall and updated containers. Production Docker security depends on protecting the host operating system, restricting access to the Docker daemon, reducing container privileges, limiting public network exposure, controlling images and secrets, and maintaining a recovery path if the host is compromised. The practical rule is simple: **secure the privileges and exposure that can lead to host-level control first, then add detection, scanning, and recovery controls around them.** Docker’s own security documentation treats the daemon attack surface, container configuration, kernel isolation, and hardening features as separate parts of the same security model. This checklist is for teams running Docker Engine on production cloud VMs. It does not replace the broader [VPS for Docker Containers](/learn/guides/vps-for-docker-containers), the runtime decision in [Podman vs Docker](/learn/guides/docker-vs-podman-small-teams), or the isolation comparison in [Docker vs Virtual Machines](/learn/guides/docker-vs-virtual-machines-when-to-use). Its job is narrower: define the minimum controls a Docker host should have before you treat it as production-ready. ## Docker host security starts with the VM and the daemon Docker containers share the host kernel, while the Docker daemon normally operates with powerful host privileges. That means host security and Docker security cannot be separated cleanly. Docker’s security guidance identifies the daemon attack surface as one of the major areas operators must protect. A user who can fully control a rootful Docker daemon can generally perform operations that affect the host, including mounting host paths or starting highly privileged containers. For that reason, Docker access should be treated as administrative access rather than ordinary application access. The first security boundary is therefore the set of people, services, and automation that can reach the host and the Docker API. A production host should have: - administrative SSH access limited to trusted operators; - individual accounts or controlled automation identities rather than broadly shared credentials; - Docker daemon access limited to identities that genuinely need host-level container control; - no casually exposed Docker API socket over the public network; - a defined method for rotating administrative credentials and removing access when responsibilities change; - host operating-system security updates included in the maintenance process, not only container-image updates. The Docker socket deserves special attention. Mounting `/var/run/docker.sock` into another container gives that container a control path to the Docker daemon. Management tools sometimes require it, but it should be treated as a privileged exception, not a harmless convenience. The same principle applies to CI/CD. A deployment runner that can control the production Docker daemon is part of the production trust boundary. Protect its credentials and scope just as carefully as direct administrator access. ## Container privileges should be reduced before adding more security tooling The fastest way to weaken Docker’s isolation is to grant a container more privilege than the application needs. Docker already uses Linux namespaces, cgroups, capabilities, and security profiles to create a restricted environment. Production configuration should preserve those defaults unless there is a documented reason to change them. The highest-impact controls are: - avoid `--privileged` containers unless the workload truly requires host-like access; - run application processes as a non-root user when the image and workload support it; - add Linux capabilities only when an application requires them instead of granting a broad capability set; - keep Docker’s default seccomp profile unless a specific, reviewed compatibility requirement justifies a custom profile; - keep AppArmor or SELinux protections enabled when supported by the host distribution; - avoid exposing host devices or sensitive host filesystems to containers without a clear operational requirement. Docker’s current seccomp documentation describes the default profile as a moderately protective allowlist designed to preserve broad compatibility and explicitly recommends against disabling it as a general workaround. This matters because disabling a security layer can turn a narrow application compatibility problem into a host-wide risk. Rootless Docker can reduce daemon and runtime privilege by running both as a non-root user inside a user namespace. It is useful when the workload is compatible with its networking, storage, and operational constraints. It should be evaluated as a privilege-reduction option, not treated as a requirement for every production host. A useful decision rule is: | Workload need | Better default | |---|---| | Ordinary web app, API, worker, or service | Keep default Docker isolation and run the process non-root where practical | | App needs one specific Linux capability | Add only that capability | | App requires host devices or kernel-level access | Isolate the workload carefully and document why | | Team can operate within rootless limitations | Evaluate Rootless Docker to reduce daemon privilege | | Compatibility issue appears under seccomp | Fix or narrowly profile the incompatibility; do not disable seccomp globally | Privilege reduction should come before adding more scanners or dashboards. A scanner can report risk; it cannot compensate for a container that already has unnecessary host-level power. ## Public network exposure should be intentionally small A Docker host can be securely patched and still be exposed through an unnecessary published port. Classify each service before publishing it: | Service type | Public exposure default | |---|---| | Reverse proxy or intended public web service | Public on required ports | | Application service behind a reverse proxy | Private unless direct access is required | | Database | Private | | Cache | Private | | Message broker | Private | | Internal worker | No public port | | Admin UI | Private, VPN-restricted, or tightly allowlisted | | Docker daemon/API | Never casually public | Docker networking deserves its own firewall review. On Linux, Docker creates firewall rules for bridge networks and published ports. Docker’s documentation warns that Docker and UFW interact in a way that can surprise operators: published container traffic can be diverted before it reaches the UFW chains normally used for host filtering. That means “UFW is enabled” is not enough evidence that a Docker-published port is protected the way you expect. For production hosts: - publish only the ports the application actually needs; - bind private services to loopback or private interfaces where appropriate; - verify externally which ports are reachable instead of relying only on firewall configuration output; - use a deliberate combination of infrastructure firewalling, host firewall policy, and Docker network design; - keep databases, caches, and administrative interfaces away from the public path unless there is a strong requirement. Do not disable Docker’s firewall integration casually. Docker warns that preventing it from creating required rules can break container networking and can produce less secure behavior if replacement rules are not designed correctly. ## Images, secrets, and mounts need separate trust boundaries A hardened host can still run an unsafe image or leak credentials through application configuration. Treat images, secrets, and mounts as three separate security decisions. ### Images need provenance and update ownership Production images should come from sources your team intentionally trusts. Prefer explicit versions or digests where reproducibility matters instead of allowing every deployment to resolve an uncontrolled moving target. Vulnerability scanning is useful because it identifies known issues in operating-system packages and application dependencies. It does not prove an image is safe, and it should not replace image ownership, patching, or review. The important operational questions are: - Who owns each production image? - Where is it built or obtained? - How is it updated when a base image or dependency receives a security fix? - Can the team identify which image version is currently running? - Can a compromised or unwanted image be replaced quickly? The broader image-versus-infrastructure-image distinction belongs in [Container Images vs VM Images](/learn/guides/container-images-vs-vm-images). ### Secrets should not be baked into images Passwords, API keys, certificates, and tokens should not be committed into a Dockerfile or application image. Docker Compose supports per-service secrets. Docker’s current Compose documentation notes that secrets are explicitly granted to services and mounted under `/run/secrets`, reducing the need to distribute the same sensitive value through broad environment-variable exposure. The implementation can vary, but the production requirement is consistent: secrets should have a defined owner, limited consumers, rotation path, and should not become part of the immutable image layer. ### Mounts can expand a container’s authority Every host bind mount should answer a question: why does this container need direct access to this host path? Read-only mounts are preferable when the application does not need to write. Sensitive paths such as Docker sockets, SSH material, system configuration, and broad host directories should be avoided unless the application is intentionally acting as privileged infrastructure. For the storage decision itself, use [Docker Volumes vs Bind Mounts](/learn/guides/docker-volumes-vs-bind-mounts-production). That guide owns persistence and host-file ownership; this security checklist only owns the privilege implications of exposing host paths to containers. ## Updates, logs, and resource controls limit the blast radius Security failures are not limited to remote compromise. A runaway process, unbounded logs, or a full filesystem can take a production host offline even when no attacker is involved. Docker uses cgroups for resource accounting and limits. Docker’s security guidance also notes that resource controls help prevent one container from exhausting shared host capacity. Production teams should therefore define resource and disk expectations for every important workload. At minimum, the operating model should answer: - Which containers need explicit CPU or memory limits? - What happens when a container exceeds its memory budget? - Where do container logs go? - How are logs rotated or retained? - Who receives an alert before the Docker data directory or root filesystem becomes full? - How are unused images, stopped containers, and build cache managed? - Who owns Docker Engine and host OS patching? Do not treat automatic restarts as a security or reliability strategy. A restart policy can recover a failed process; it cannot repair corrupted state, a compromised credential, a bad image, or a full disk. The deeper sizing, logging, and disk-management mechanics belong in the separate LC11 guide **Docker Resource Limits, Logging, and Disk Management**. The security requirement here is that uncontrolled resource consumption must not be allowed to become an easy denial-of-service path. ## Backups and host replacement are part of the security model A security plan that only tries to prevent compromise is incomplete. Production systems also need a recovery path for destructive events such as credential theft, malicious changes, ransomware, operator mistakes, corrupted application state, or an unrecoverable host. Separate replaceable infrastructure from durable state: ```text Replaceable - VM operating system - Docker Engine installation - application containers - reverse proxy containers - deployment configuration generated from source Durable or protected - databases - customer uploads - application-generated files - secrets and required configuration - backup archives ``` The host should be replaceable from known configuration rather than being a machine that can only be repaired in place. That creates an important distinction: - **container restart** is process recovery; - **container recreation** is application-runtime recovery; - **host replacement plus data restore** is infrastructure recovery. Backups should therefore be recoverable independently of the running host when the data warrants it. Database-aware backups may also be necessary even when the VM itself has an infrastructure-level backup. This is the same operating principle used in Raff’s [Docker Compose for Production](/learn/guides/docker-compose-for-production): production readiness depends on whether the workload can be rebuilt and its important state restored without reconstructing the system from memory. ## The production checklist prioritizes controls by failure impact Not every Docker security control has the same urgency. Use impact to prioritize the work. | Control | Priority | Main failure it reduces | Minimum production expectation | |---|---|---|---| | Docker daemon and admin access | Critical | Host takeover | Only trusted administrators and controlled automation can access it | | Privileged mode and capabilities | Critical | Container escape / excessive blast radius | No unnecessary privileged containers or capabilities | | Public port exposure | Critical | Direct attack on internal services | Only intentional ingress is publicly reachable | | Docker socket and sensitive mounts | Critical | Host control or host-data exposure | Mount only when operationally unavoidable and explicitly reviewed | | Host and Docker updates | High | Known vulnerability exploitation | Defined patch ownership and maintenance process | | Image provenance and scanning | High | Vulnerable or tampered workloads | Trusted, identifiable images with an update path | | Secrets handling | High | Credential leakage | Secrets are not baked into images and are scoped to required services | | Resource and disk controls | High | Denial of service | Resource expectations, log rotation, and disk monitoring are defined | | Backups and replacement | High | Destructive compromise or operator error | Important state can be restored on a replacement host | | Additional detection tooling | Medium | Slow incident detection | Add after privilege and exposure controls are in place | This order is intentional. If a container can control the Docker daemon or a private database is publicly reachable, fixing that risk usually matters more than adding another scanner. A practical production gate is to ask four questions: 1. **Who can become host administrator through Docker?** 2. **Which container can reach more of the host than it needs?** 3. **Which service is reachable from the internet but should not be?** 4. **Can we rebuild this host and restore the important state if we decide not to trust it anymore?** If any answer is unclear, the host still has a production-readiness gap. ## Raff VM security still follows a shared-responsibility boundary Running Docker on a cloud VM gives you a strong infrastructure boundary, but the container workload remains an operator responsibility. For a Raff VM, treat the responsibility split the same way you would for any production Linux Docker host: - Raff provides the VM infrastructure boundary; - your team controls the guest operating system, Docker Engine, users, application containers, published ports, secrets, mounts, and application data; - Docker and application updates remain part of your operating process; - recovery planning must include both infrastructure and application state. That is why the right starting point is not a vendor-specific hardening trick. It is a repeatable security baseline that still works if the host must be replaced. If your team is still deciding whether Docker belongs inside a VM, start with [Docker vs Virtual Machines](/learn/guides/docker-vs-virtual-machines-when-to-use). If Docker on a VM is already the chosen model, use this checklist as the security gate before production traffic reaches it. :::cta server Deploy a Raff VM when you need a controlled Linux host for Docker workloads and apply the same production security baseline from day one. ::: ## A Docker VM is production-ready when privilege, exposure, and recovery are controlled Docker security best practices are most useful when they are turned into a small set of enforceable production rules. Protect the Docker daemon like root access. Reduce container privilege instead of assuming container isolation is enough. Publish only intentional ports. Keep private infrastructure private. Separate image trust, secret handling, and host mounts. Patch the host and runtime. Control logs and resource consumption. Most importantly, maintain a replacement and restore path so a compromised host does not become an irreplaceable machine. That is the security threshold that matters: **the host is difficult to gain unnecessary control over, easy to observe, and replaceable when trust is lost.** ### Sources - [Docker Engine security](https://docs.docker.com/engine/security/) - [Rootless mode](https://docs.docker.com/engine/security/rootless/) - [Seccomp security profiles for Docker](https://docs.docker.com/engine/security/seccomp/) - [Packet filtering and firewalls](https://docs.docker.com/engine/network/packet-filtering-firewalls/) - [Manage secrets securely in Docker Compose](https://docs.docker.com/compose/how-tos/use-secrets/) --- ### Docker Compose Networking: Public Ports, Private Services, and DNS URL: https://rafftechnologies.com/learn/guides/docker-compose-networking-public-ports-private-services-dns Description: Design Docker Compose networking for production with deliberate port publishing, private services, service-name DNS, network segmentation, and safer host exposure. Docker Compose networking is simple until a production stack accidentally publishes a database, hard-codes container IPs, or assumes the host firewall will automatically protect every mapped port. The production goal is not to create the most complicated network layout. It is to make **traffic ownership obvious**: only services that need host-level access should publish ports, application services should communicate by service name, and sensitive dependencies should stay on networks that do not need public exposure. This guide owns that networking decision. For the broader single-host operating model, use [Docker Compose for Production](/learn/guides/docker-compose-for-production). For host hardening beyond Compose, use [Docker Host Security Checklist for Production VMs](/learn/guides/docker-host-security-checklist-production-vms). ## Docker Compose networking starts with one project network By default, Docker Compose creates a network for the application and connects the project's services to it. Services on that network can discover one another by **service name** through Docker's internal DNS. That means an application service should normally connect to PostgreSQL as something like: ```text postgres://db:5432 ``` —not by using the database container's current IP address. **Compose service names are stable discovery names; container IP addresses are not.** When a container is recreated, Docker can assign it a new IP address while keeping the service name available. Applications should reconnect by name rather than persisting container IPs in configuration. A simple topology looks like this: ```text Internet ↓ Host public interface ↓ published 80/443 Reverse proxy ↓ Compose network Web / API ├── db:5432 ├── redis:6379 └── worker service ``` The key distinction is that **service-to-service traffic uses the container port on the Compose network**. It does not need the host port used by external clients. If the database listens on `5432` inside its container, the application usually connects to `db:5432`. Publishing `5432` on the VM is unnecessary unless something outside the Compose network genuinely needs direct access. ## `ports` and internal service access solve different problems One of the most important Docker Compose networking decisions is whether a service needs a host port at all. Use this rule: | Requirement | Better default | |---|---| | Internet users need the service | Publish a deliberately chosen host port | | Reverse proxy on the same Compose network needs the app | Do not publish the app port | | App needs PostgreSQL or Redis | Connect by service name and container port | | Host-only administration needs access | Bind the published port to `127.0.0.1` when suitable | | Another VM needs access | Use an intentional private/public network path, not accidental `0.0.0.0` exposure | | Service should have no external connectivity | Consider an `internal: true` network | In Compose, `ports` creates a mapping between a port on the Docker host and a port in the container. For example: ```yaml services: proxy: image: nginx:alpine ports: - "80:80" - "443:443" ``` This makes the proxy reachable through host ports 80 and 443. A backend application on the same Compose network does not need that mapping merely so the proxy can reach it: ```yaml services: proxy: image: nginx:alpine ports: - "80:80" - "443:443" networks: - frontend app: image: example/app:1.0 networks: - frontend - backend ``` The proxy can address the application by its service name on the shared `frontend` network. This is the cleaner production pattern: **publish the edge, not every service behind the edge.** ## `expose` is not the same as publishing a port Compose also supports `expose`, but it is commonly misunderstood. `expose` declares container ports intended for service-to-service access. It does **not** publish those ports onto the Docker host. For example: ```yaml services: app: image: example/app:1.0 expose: - "3000" ``` Other services on an appropriate shared Docker network can use the application's container port without a host-level `ports` mapping. Also remember that an image may already declare exposed ports in its Dockerfile. The important security boundary is not whether `expose` appears in the Compose file; it is whether the service shares a network with another service and whether a port is published to the host. A useful mental model is: ```text Container port ├── reachable by permitted containers on shared Docker network └── reachable from host/outside only when intentionally published or otherwise routed ``` Do not add `ports` merely because you want one container to talk to another. ## Published ports need an explicit bind decision A Compose port mapping without a host IP normally binds on all host interfaces. For example: ```yaml ports: - "8080:8080" ``` can make port `8080` reachable through the VM's network interfaces, subject to the host's surrounding network controls. Docker's current documentation warns that publishing a port without a host IP binds to `0.0.0.0` by default. On a public VM, that can expose the service beyond what the operator intended. If a service only needs to be reached from the VM itself, bind it to loopback: ```yaml ports: - "127.0.0.1:8080:8080" ``` That pattern is useful when: - a host-level reverse proxy connects to a container; - an administrative interface should only be accessible through SSH tunneling; - a local monitoring agent needs the service; - a host process needs a container endpoint but external clients do not. The decision is not “published or unpublished” only. It is also **which host address owns the published port**. ## Docker port publishing and host firewalls must be designed together A common production mistake is assuming that a host firewall rule automatically behaves the same for normal host services and Docker-published ports. On Linux, Docker creates firewall rules for bridge networks, port publishing, NAT, and traffic isolation. Docker's documentation specifically warns that published container traffic can interact with host firewall tooling such as UFW in ways operators do not expect. **A Docker-published port should be treated as an explicit network exposure, not as a harmless Compose setting.** Before publishing a port on a production VM, verify all three layers: 1. **Compose:** which host IP and port are mapped? 2. **Docker:** which bridge/network and firewall rules implement the mapping? 3. **Infrastructure:** which public or private traffic can reach the VM interface? At Raff, we prefer a narrow exposure model for single-host Compose stacks: the reverse proxy owns public 80/443, while databases, caches, workers, and internal APIs stay private unless there is a specific operational reason to expose them. That separation keeps application architecture readable and reduces the number of host ports an operator must defend. For the host layer, continue with [Docker Host Security Checklist](/learn/guides/docker-host-security-checklist-production-vms). ## Separate frontend and backend networks when the trust boundary matters The default Compose network is often sufficient for small applications, but it allows every service attached to that network to reach the others at the network layer. When the stack has clearly different trust zones, define explicit networks. A common model is: ```text Internet ↓ proxy ↓ frontend network app ↓ backend network postgres / redis ``` In Compose: ```yaml services: proxy: image: nginx:alpine ports: - "80:80" - "443:443" networks: - frontend app: image: example/app:1.0 networks: - frontend - backend db: image: postgres:17 networks: - backend networks: frontend: {} backend: {} ``` Now the proxy and database do not share a Docker network. The application becomes the intended path between them. This is not a replacement for application authentication, database credentials, TLS where required, or host security. It is network-level reduction of unnecessary reachability. Use segmentation when it expresses a real boundary. Do not create six networks for six services merely to make the Compose file look sophisticated. ## `internal: true` creates a stronger isolated network boundary Compose networks support `internal: true` for networks that should be externally isolated. For example: ```yaml networks: backend: internal: true ``` This is useful for service groups that should communicate with one another but do not need ordinary external network access through that network. Typical candidates include: - database-only networks; - internal processing pipelines; - isolated test components; - services that should only receive traffic through another container. Use it carefully. An application that needs to call external APIs, download updates, reach managed databases, or contact SaaS services still needs an appropriate path for that traffic. Network isolation should reflect actual dependency needs, not a blanket assumption that every backend can be cut off from external destinations. ## Docker Compose DNS should use service names, not fixed IPs Within a Compose project, Docker's internal DNS lets services resolve one another by service name. That gives you a stable application contract: ```text app → db:5432 app → cache:6379 proxy → app:3000 ``` instead of: ```text app → 172.x.x.x ``` The second model is fragile because container addresses can change during recreation. This matters especially during deployments. A service replacement can join the network under a new IP address while keeping the same service name. Existing long-lived connections may break and need to reconnect, but new DNS lookups resolve the current endpoint. Applications should therefore: - use service names for Compose-local dependencies; - tolerate dropped connections during dependency recreation; - reconnect using DNS rather than cached container IP assumptions; - avoid embedding Docker subnet addresses in application configuration. This is one reason a production Compose stack should be designed around names and roles rather than container identities. ## Network aliases are useful, but ownership should stay clear Compose can assign additional aliases to services on a network. Aliases are useful when: - an application expects a legacy hostname; - a migration needs a temporary compatibility name; - multiple environments need a consistent dependency hostname; - an internal service needs a domain-like name separate from its Compose service key. But aliases can also make troubleshooting harder if several services claim ambiguous names. Prefer one obvious canonical service name and add aliases only for a defined compatibility or routing reason. The production question is: **if an operator sees this hostname in an application error, can they quickly identify which service owns it?** If not, the naming model is too clever. ## Custom DNS settings solve external resolution problems, not Compose discovery Compose supports service-level DNS settings such as `dns`, `dns_search`, and `dns_opt`. It also supports `extra_hosts` for adding hostname-to-address mappings inside the container. These controls are useful when a container must resolve infrastructure outside the normal Compose service-discovery model—for example: - a corporate DNS resolver; - a private internal domain; - a fixed legacy system; - an environment-specific host entry; - a host service addressed through a deliberate host gateway mapping. Do not replace normal Compose service discovery with manually maintained `extra_hosts` entries. If `app` needs to reach the Compose service `db`, use `db`. A hard-coded host mapping turns a dynamic container environment back into manual static networking. Use custom DNS controls for genuine external or infrastructure-specific resolution requirements. ## External networks can connect separate Compose projects Sometimes two Compose projects on the same Docker host need to communicate without being merged into one large Compose file. Compose can attach services to an existing external Docker network. This can be useful for: - one shared reverse proxy serving multiple stacks; - a shared observability agent; - controlled communication between separately deployed applications; - migration from one project layout to another. The trade-off is coupling. Once multiple projects share a network, changes to that network can affect multiple deployments. Naming collisions, unexpected reachability, and ownership questions become more important. Use an external network when there is a clear shared boundary, not as a shortcut to make every container on the host reachable from every other container. A practical rule is: | Scenario | Recommendation | |---|---| | One application, several services | Project-local network | | Proxy shared by multiple stacks | Dedicated external proxy network | | Database belongs to one app | Keep on app-specific backend network | | Monitoring needs access across stacks | Shared network only if required and controlled | | Unrelated applications | Keep networks separate | ## `network_mode: host` removes much of the normal Compose network boundary Compose supports host networking, where a container uses the host's network stack directly. That is a specialized option, not a faster default for production web applications. With host networking: - normal port mapping is not used; - the container shares the host network namespace; - Compose service-name DNS behavior changes; - the container has broader visibility into the host's networking environment. Use host networking only when the workload genuinely needs host-level network access—for example, certain monitoring, networking, or low-level system tools. For ordinary web applications, APIs, databases, workers, and reverse proxies, user-defined bridge networks provide a clearer security and operations model. ## Private services should remain private even when debugging is inconvenient Operators sometimes publish internal ports “temporarily” because it makes debugging easy. Those temporary mappings have a habit of becoming permanent infrastructure. Prefer controlled debugging paths: - `docker compose exec` into an appropriate service; - SSH access to the VM; - loopback-only published ports; - a temporary, reviewed mapping removed after the incident; - application-level admin endpoints behind authentication and deliberate routing. Do not leave PostgreSQL, Redis, internal dashboards, metrics endpoints, or management APIs listening publicly simply because an operator once needed remote access. The production network should describe the application's intended steady state, not its easiest debugging state. ## Networking failures should be debugged from the dependency path inward When two Compose services cannot communicate, debug the intended path rather than immediately adding `ports`. Check in this order: 1. Are both services running? 2. Do they share the intended Compose network? 3. Does the client use the service name rather than a stale IP? 4. Is the destination process listening on the expected container port? 5. Does the application bind to an address reachable inside the container rather than localhost only? 6. Are custom DNS settings or `extra_hosts` overriding expected resolution? 7. Is a network marked `internal` when external access is required? 8. For host/external traffic, is the host IP and port mapping intentional? `docker network inspect` and `docker compose port` are useful inspection tools, but the goal is to understand the model rather than memorize commands. A common diagnosis is simply this: **the services already share a Docker network, so publishing another host port does not solve the actual problem.** ## Production Compose networking baseline Use this table as the networking review for a single-host production stack: | Area | Production baseline | |---|---| | Public edge | Only the intended entry service publishes internet-facing ports | | Reverse proxy | Usually owns 80/443 | | App/API | Private behind proxy unless direct exposure is required | | Database | No public host port by default | | Cache/queue | No public host port by default | | Workers | No inbound host port unless explicitly required | | Service discovery | Use Compose service names | | Container IPs | Never treated as stable configuration | | Host-only access | Bind to `127.0.0.1` where appropriate | | Segmentation | Separate frontend/backend networks when it expresses a real trust boundary | | External networks | Shared only between projects that intentionally need communication | | DNS overrides | Used for external/infrastructure needs, not normal Compose discovery | | Host networking | Avoid unless the workload genuinely needs host network access | | Firewall review | Verify Docker port-publishing behavior together with host/infrastructure rules | This baseline is intentionally boring. Boring networks are easier to secure, explain, and recover. ## Raff VM networking should preserve a narrow public surface For a production Compose application on a Raff VM, start by defining what the internet actually needs to reach. For most web stacks, that is the reverse proxy or web entry point on ports 80 and 443. Internal services remain reachable through Docker networking, while broader VM-level access is controlled separately. At Raff, we treat the VM network boundary and the Compose network boundary as two different controls: - the **VM boundary** decides which traffic can reach the host; - the **Compose boundary** decides which containers can reach each other and which container ports are mapped onto that host. Keeping those layers separate makes changes easier to review. Adding a new internal service should not automatically create a new public host port. Use the live [Raff VM](/products/raff-vm) page when selecting the VM that will host the stack. :::cta server Deploy a Raff VM and keep your Docker Compose public surface limited to the services that actually need host-level access. ::: ## Docker Compose networking is safest when exposure is intentional Docker Compose networking does not require a complex topology to be production-ready. Use service names instead of container IPs. Let internal services communicate over shared Compose networks. Publish only the services that must cross the host boundary. Bind host-only endpoints to loopback. Segment frontend and backend networks when the trust boundary is meaningful. Treat host networking and external shared networks as deliberate exceptions rather than defaults. Most importantly, remember that `ports` is an exposure decision. A port mapping that looks like one line of YAML changes how traffic reaches the VM and should receive the same review as any other public network rule. Continue with [Docker Compose for Production](/learn/guides/docker-compose-for-production) for the complete operating model and [Docker Resource Limits, Logging, and Disk Management](/learn/guides/docker-resource-limits-logging-disk-management) for host stability controls. ### Sources - [Docker: Networking in Compose](https://docs.docker.com/compose/how-tos/networking/) - [Docker: Compose networks reference](https://docs.docker.com/reference/compose-file/networks/) - [Docker: Compose services reference](https://docs.docker.com/reference/compose-file/services/) - [Docker: Port publishing and mapping](https://docs.docker.com/engine/network/port-publishing/) - [Docker: Packet filtering and firewalls](https://docs.docker.com/engine/network/packet-filtering-firewalls/) --- ### Docker Compose Backup and Restore Strategy URL: https://rafftechnologies.com/learn/guides/docker-compose-backup-restore-strategy Description: Back up and restore a Docker Compose stack by protecting configuration, secrets, persistent data, databases, images, and a tested clean-host recovery path. A Docker Compose backup should protect **the application definition and the state the application cannot recreate**. That usually means more than copying `compose.yaml`, but less than trying to archive every container, image layer, and runtime file on the host. The production goal is to make a Compose stack **rebuildable on a clean VM**. If the original host disappears, the team should know which files define the stack, which data must be restored, which secrets and external dependencies are required, and in what order the services return. This guide owns that Compose-level recovery model. It does not replace the broader [Cloud Backup Strategy](/learn/guides/cloud-server-backup-strategies), database-native recovery in [Database Backup Strategy for SaaS Apps](/learn/guides/database-backup-strategy-saas-apps), or the storage choice in [Docker Volumes vs Bind Mounts](/learn/guides/docker-volumes-vs-bind-mounts-production). ## A Docker Compose backup has four separate parts A Compose application is easier to recover when its assets are divided by responsibility. | Layer | Examples | Recovery job | |---|---|---| | Application definition | `compose.yaml`, overrides, profiles, service settings | Recreate the service topology | | Runtime configuration | environment values, configs, secrets, certificates | Reconnect services safely | | Persistent state | named volumes, bind-mounted data, database backups | Restore data that containers cannot recreate | | External dependencies | object storage, managed databases, DNS, external APIs | Reconnect the rebuilt stack | **The Compose file recreates containers; it does not automatically recreate all application state.** A clean recovery design should therefore answer four questions: 1. Can we reconstruct the final Compose model? 2. Can we retrieve the required secrets and configuration? 3. Can we restore durable data to the expected paths or volumes? 4. Can the rebuilt stack reconnect to external systems safely? If one of those answers depends on remembering what was configured manually on the old VM, the stack is not fully recoverable yet. ## Back up the Compose source, not only the running containers Containers are deployment artifacts. The source of truth should be the files and image references that create them. Protect at least: - `compose.yaml` or `docker-compose.yaml`; - production override files; - `.env` templates or documented variable names; - reverse-proxy configuration; - application config files mounted into containers; - scripts used during deployment or migration; - image names and version tags or digests; - documented Compose project name where it matters; - any systemd or host wrapper used to start the stack. Keep these files in version control where possible. Version control is usually a better recovery source for Compose configuration than copying the running container filesystem. Docker's current `docker compose config` command is useful because it resolves multiple Compose files, variable interpolation, and shorthand into the actual model Docker will apply. Before a major change, rendering the resolved model gives the team a concrete record of what the production deployment currently means. For example: ```bash docker compose config > resolved-compose.yaml ``` The rendered file should be treated as recovery evidence, not necessarily as the primary source file. Secrets may be interpolated into resolved output depending on how configuration is defined, so store it only where access is appropriate. A safer long-term pattern is: ```text Git repository ├── compose.yaml ├── compose.production.yaml ├── proxy config └── deployment scripts Secret manager / protected file store └── production credentials Backup destination └── persistent application data ``` That separation is easier to audit than one large archive copied from `/var/lib/docker`. ## Do not treat Docker's internal data directory as the backup format Docker manages images, writable layers, metadata, networks, and volumes under its own data root. Copying that internal directory may look like a complete backup, but it tightly couples recovery to Docker's internal layout, storage driver, host state, and timing of the copy. For most Compose applications, recovery is cleaner when the team can: 1. provision a new VM; 2. install Docker; 3. retrieve the Compose definition; 4. pull or rebuild images; 5. recreate networks and volumes from Compose; 6. restore persistent data; 7. start services in a controlled order. This approach makes the backup portable across replacement hosts and avoids depending on undocumented assumptions about Docker's runtime metadata. **Back up the application's source of truth and durable state, not the Docker daemon's working directory as your only recovery method.** There are exceptions for specialized host-level imaging or forensic workflows, but they should be treated as infrastructure recovery, not the normal Compose backup design. ## Images should normally be reproducible or pullable Container images can consume significant backup space, but they are often rebuildable or available from a registry. A production recovery plan should record: - image registry; - repository name; - version tag; - image digest where deterministic rollback matters; - credentials required to pull the image; - source/build instructions if the registry is unavailable. If an image exists only on one production host and cannot be rebuilt, that image has become irreplaceable state and should be protected accordingly. That is a warning sign in the release process. A good default is: | Image situation | Recovery approach | |---|---| | Public upstream image | Pull again by trusted version | | Private application image | Pull from protected registry | | Internally built image | Registry + reproducible build source | | One-off local-only image | Export temporarily, then fix the release process | Do not turn every routine image layer into backup data just because it happens to exist on the VM. ## Named volumes need an explicit backup owner Docker volumes persist beyond the lifecycle of an individual container, but persistence is not historical recovery. Docker's current documentation includes a supported pattern for backing up and restoring a volume by mounting it into a temporary container and creating an archive. The exact command is less important than the operating rule: **the volume must be copied to a recovery destination outside the workload that uses it.** For a file-oriented volume, a simple model is: ```text Compose service ↓ Named volume ↓ controlled backup job Archive or backup repository ↓ Off-host recovery destination ``` Before backing up a volume, identify what owns consistency. | Volume contents | Better backup method | |---|---| | Static uploads or documents | File-level backup can fit | | Application-generated files | File-level backup plus app validation | | Database data directory | Database-native backup should lead | | Cache | Usually rebuild, not back up | | Queue state | Depends on durability/business requirement | | Search index | Often rebuild from primary data | For the detailed storage choice, use [Docker Volumes vs Bind Mounts](/learn/guides/docker-volumes-vs-bind-mounts-production). This guide only defines where volume recovery fits in the complete Compose stack. ## Database containers require database-aware backups A database running inside Docker Compose is still a database. The container boundary does not change its transaction or recovery semantics. Do not make a raw archive of a live PostgreSQL or MySQL data directory your only recovery method. Depending on the engine and required recovery target, use methods such as: - logical dumps; - physical/base backups; - write-ahead-log or binary-log retention; - point-in-time recovery; - application-coordinated maintenance or snapshot procedures. Then store the resulting backup artifacts outside the database container and preferably outside the VM. A clean architecture looks like: ```text Compose database container ↓ Database-aware backup ↓ Protected backup destination ↓ Restore into clean database container or managed database ``` The Compose backup should document **where the database backup comes from and how the application reconnects after restore**. It should not duplicate the database engine's own recovery documentation. For that layer, use [Database Backup Strategy for SaaS Apps](/learn/guides/database-backup-strategy-saas-apps). ## Bind mounts need path-level recovery documentation Bind mounts expose host filesystem paths directly into containers. Their recovery model therefore depends on the host path, not on Docker volume metadata. For every important bind mount, record: - host path; - container path; - ownership and permissions; - whether the directory is generated or durable; - backup destination; - restore order; - any dependency on host users or groups. For example: ```yaml services: app: volumes: - /srv/app/uploads:/app/uploads ``` A successful host replacement requires `/srv/app/uploads` to exist with the expected data and permissions before the application depends on it. This is one reason bind mounts can be operationally clear for teams that intentionally manage host paths, but fragile when important paths are created manually without documentation. ## Secrets should be recoverable without living in the backup archive A Compose stack often needs database passwords, API keys, TLS private keys, registry credentials, OAuth secrets, and other sensitive values. The recovery plan must prove those values are retrievable, but the general backup archive should not become an uncontrolled copy of every production secret. Use a separate protected recovery path for secrets: ```text Compose definition ↓ references Secret source ↓ Application containers ``` The secret source may be a protected secret manager, encrypted configuration repository, password vault, or tightly controlled backup file. Record: - which secrets are required; - where they are retrieved; - who can access them during recovery; - how access works if the normal identity path is unavailable; - which secrets should be rotated after a compromise. Do not put actual secret values into the recovery runbook. Docker Compose supports secrets and configs as explicit service resources. Whether the source is a file, environment value, external object, or another system, the recovery question stays the same: **can a replacement host obtain the required value without relying on the failed host?** ## Project names and volume names can affect restore behavior Compose normally scopes resource names by project. That can affect network names, container names, and named volumes. A volume defined as: ```yaml volumes: app_data: ``` may be created with a project-scoped name such as: ```text myproject_app_data ``` If a recovery process restores an archive into a differently named volume, the data can exist on disk while the Compose application still mounts an empty newly created volume. Therefore document either: - the expected Compose project name; or - explicit external/named resources where stable naming is required. Do not hard-code resource names unless there is a reason. The goal is not to defeat Compose's project isolation; it is to make sure the restore process knows which volume the rebuilt service will actually mount. A useful recovery check is: ```bash docker compose config --volumes ``` and then compare the intended volume names with the restored resources before starting stateful services. ## `docker compose down -v` is a data-destruction operation Named volumes normally persist when a Compose stack is brought down and recreated. Docker's current documentation shows that `docker compose down -v` removes named volumes associated with the project. **The `-v` flag can permanently delete stored application data.** Treat it like a destructive storage command, not a routine cleanup option. Before using it on a production stack, confirm: 1. which volumes will be removed; 2. whether each volume contains durable state; 3. whether a current backup exists; 4. whether the recovery procedure has been tested; 5. whether the removal is intentional rather than an attempt to fix an unrelated deployment issue. This risk is separate from general disk cleanup. For prune and disk-pressure policy, use [Docker Resource Limits, Logging, and Disk Management](/learn/guides/docker-resource-limits-logging-disk-management). ## The restore sequence should rebuild dependencies in order A Compose backup is only useful when there is a defined restore path. A practical fresh-host sequence is: ```text 1. Provision clean VM 2. Install supported Docker Engine + Compose plugin 3. Restore Compose files and deployment configuration 4. Retrieve secrets and registry credentials 5. Pull or rebuild required images 6. Recreate expected networks and empty volumes 7. Restore file/volume data 8. Restore database using database-native method 9. Start stateful dependencies 10. Start application services 11. Validate health and data 12. Re-enable public traffic ``` The exact order depends on the application. For example, a web container may be able to start before PostgreSQL is restored, but repeatedly crash while migrations or connection attempts run against an empty database. A worker may begin consuming jobs before the application is ready. A scheduler may send duplicate notifications in a recovery environment. Document which services should remain stopped until validation is complete. Compose startup dependencies can help with normal boot sequencing, but disaster recovery still needs a human-readable order that includes data restore and external systems. ## Restore into a clean host to prove portability The strongest Compose recovery test is not restarting the existing stack. It is rebuilding the application on a clean host using only approved recovery sources. That test proves whether the team has accidentally depended on: - an untracked host package; - a manually edited config file; - a local-only image; - a forgotten bind-mount path; - an undocumented firewall or reverse-proxy change; - credentials stored only on the failed VM; - a named volume whose real identity is unknown; - a database backup that cannot be restored; - an external dependency that no longer accepts the restored credentials. A clean-host test should end only after application-level validation. Check: - expected services are running; - application health endpoint responds; - database contains the expected recovery point; - uploads or durable files are present; - queues and workers behave correctly; - reverse proxy and TLS work; - external integrations are controlled; - logs and monitoring are visible; - no production side effects are triggered accidentally. For the broader evidence framework, use [Restore Testing Checklist for Production VMs](/learn/guides/restore-testing-checklist-production-vms). ## Keep backup destinations outside the Compose host A backup stored only on the same VM shares too much failure risk with production. If the disk, VM, account, or administrator action that damages production can also delete the only backup, the recovery boundary is weak. A Compose recovery design can use: - object storage; - a dedicated backup host; - a remote backup repository; - managed database recovery; - infrastructure-level VM backup as an additional layer. The correct choice depends on the data type and recovery requirements. On Raff, a practical model is: ```text Raff VM running Docker Compose ↓ Compose definition in version control ↓ Database-aware backups / file backups ↓ Off-host recovery destination ↓ Clean-host restore test ``` Use [Raff Object Storage](/products/object-storage) when the backup tool or application can write compatible artifacts to S3-compatible storage. Use [Raff Data Protection](/products/data-protection) for VM-level recovery when the workload also needs infrastructure recovery. At Raff, we treat Compose recovery and VM recovery as separate controls: VM recovery can bring back a server image, while Compose recovery proves the application can be rebuilt even when the original server is not trusted or available. ## A Docker Compose backup inventory prevents missing state Use this inventory before calling the stack recoverable: | Item | Back up? | Preferred source | |---|---|---| | Compose files | Yes | Version control | | Production overrides | Yes | Version control | | Resolved config snapshot | Useful before major changes | Protected recovery evidence | | Image source/build definition | Yes | Git + registry | | Private images | Yes, via registry or reproducible build | Container registry | | Secrets | Yes, separately | Secret manager / protected store | | Named-volume durable data | Yes | Workload-aware backup | | Bind-mounted durable data | Yes | File-level backup | | Database data | Yes | Database-native backup | | Cache | Usually no | Rebuild | | Container writable layer | Usually no | Recreate container | | Logs | Only when required for retention/audit | Logging system | | External object data | Separate policy | Object storage recovery plan | | DNS/TLS/network config | Document/source control | Infrastructure configuration | The purpose of the inventory is to distinguish **reproducible artifacts from irreplaceable state**. Backing up everything wastes storage and still may miss the one secret or external dependency required for recovery. Backing up only `compose.yaml` produces the opposite failure: perfect infrastructure definition with no business data. ## Production recovery baseline A Docker Compose stack is reasonably prepared for host loss when all of the following are true: - [ ] Compose files are versioned outside the VM. - [ ] Image tags or digests are known and pullable. - [ ] Required private registry access can be recovered. - [ ] Secrets are stored outside the failed host. - [ ] Every durable volume or bind mount has an owner. - [ ] Database containers have database-aware backups. - [ ] Backup copies exist outside the Compose VM. - [ ] Destructive `down -v` or prune operations require deliberate review. - [ ] Compose project/resource naming is understood. - [ ] The restore order is documented. - [ ] Stateful services can be restored before workers or schedulers create side effects. - [ ] A clean VM has been used to test the recovery path. - [ ] Application-level validation completes before traffic returns. This is the boundary of this guide: **reconstructing a Docker Compose application from clean infrastructure and protected state**. Generic retention schedules, RPO/RTO policy, provider-wide backup architecture, and detailed database recovery remain separate topics so the pages do not compete with one another. :::cta server Deploy a Raff VM as a clean Docker Compose recovery target and prove that your application can be rebuilt from versioned configuration and protected state. ::: ## Docker Compose backup is complete when the stack is rebuildable A Docker Compose backup strategy should not depend on copying the running containers themselves. Protect the Compose definition, image provenance, secrets, durable volumes or bind mounts, database-aware recovery artifacts, and the external dependencies required by the application. Keep recovery data outside the host, document resource naming and startup order, and test the process on a clean VM. The result should be simple to explain: **given a new server and the approved recovery sources, the team can rebuild the same application without relying on the old host.** Continue with [Docker Compose for Production](/learn/guides/docker-compose-for-production) for the overall operating model and [Docker Compose Networking](/learn/guides/docker-compose-networking-public-ports-private-services-dns) for the network boundary the restored stack must recreate. ### Sources - [Docker: Volumes — back up, restore, or migrate data volumes](https://docs.docker.com/engine/storage/volumes/) - [Docker: docker compose config](https://docs.docker.com/reference/cli/docker/compose/config/) - [Docker: Docker Compose CLI](https://docs.docker.com/reference/cli/docker/compose/) - [Docker: Compose configs](https://docs.docker.com/reference/compose-file/configs/) - [Docker: Compose quickstart — named volume persistence and `down -v`](https://docs.docker.com/compose/gettingstarted/) --- ### Scaling Beyond One Docker Compose Host URL: https://rafftechnologies.com/learn/guides/scaling-beyond-one-docker-compose-host Description: Learn how to scale beyond one Docker Compose host with role separation, multiple app VMs, load balancing, shared state, Swarm, and a clean path to orchestration. Docker Compose scales cleanly **inside one Docker Engine**. Once an application needs workloads placed across multiple hosts, the problem changes from container configuration to distributed scheduling, networking, state, and deployment coordination. That boundary matters because `docker compose up --scale web=3` can create several replicas, but those replicas still belong to the Docker Engine targeted by that Compose command. Docker's Swarm documentation explicitly notes that Compose itself does not use Swarm mode to schedule services across nodes; multi-node placement requires Swarm services or another orchestrator. This guide owns the **multi-host transition architecture**: how to scale a Compose-based application beyond one host without turning the page into another generic Docker-vs-Kubernetes comparison. For the one-host operating model, use [Docker Compose for Production](/learn/guides/docker-compose-for-production). For the explicit orchestration decision, use [Kubernetes vs Docker Compose for Small Teams](/learn/guides/kubernetes-vs-docker-compose-small-teams). ## One Compose project normally has one Engine boundary A normal production Compose deployment looks like this: ```text Users ↓ Single Docker host ↓ Compose project ├── web ├── worker ├── scheduler ├── cache └── supporting services ``` Compose can scale a service on that host: ```bash docker compose up -d --scale web=3 ``` That gives you more containers, not more failure domains. All three replicas still depend on the same host for: - CPU and memory capacity; - Docker Engine availability; - local storage; - host networking; - operating-system maintenance; - kernel failures; - host reboots; - disk exhaustion. This distinction is the starting point for every scaling decision. > More Compose replicas on one host increase process capacity. More hosts change the infrastructure architecture. If the problem is only CPU or memory pressure, a larger VM may be the simplest answer. If the problem is host failure, independent service scaling, deployment coordination, or workload placement, adding another host can be justified. ## Scale vertically before adding coordination you do not need The first scaling step should match the actual bottleneck. | Problem | First move to evaluate | Why | |---|---|---| | CPU saturation | Larger VM or more same-host replicas | Lowest operational change | | Memory pressure | Larger VM + explicit resource limits | Preserves one-host simplicity | | Disk growth | Separate durable data or expand storage | Compute may not be the bottleneck | | Database contention | Externalize or resize database | App-host scaling may not help | | Worker jobs affect web traffic | Split workers to another host | Separates competing workloads | | One host is a downtime risk | Add another app host | Creates another failure domain | | Deployments across hosts become manual | Introduce orchestration | Coordination is now the problem | A team should not add a second VM merely because the application has several containers. At Raff, we treat the transition as an operational-cost decision: **add another host when it removes a real resource or failure bottleneck, not when the architecture diagram looks too simple.** For CPU and memory policy on the existing host, use [Docker Resource Limits, Logging, and Disk Management](/learn/guides/docker-resource-limits-logging-disk-management). ## The simplest multi-host pattern is role separation The first useful move beyond one Compose host is often not two identical app hosts. It is separating a workload that has a different resource profile. A common example is web plus workers: ```text Users ↓ App VM └── Docker Compose: web + reverse proxy Worker VM └── Docker Compose: workers + schedulers Shared services ├── managed database └── object storage ``` This pattern works well when background jobs create CPU spikes, long-running tasks, or memory pressure that should not compete with user-facing traffic. The two hosts do not need to share one Compose project. In fact, it is usually clearer to give each host its own Compose definition or deployment profile with one explicit role. For example: ```text compose.web.yaml → app hosts compose.worker.yaml → worker hosts ``` or one base file with controlled production profiles. The architectural benefit is that each host becomes independently understandable and replaceable. Role separation is still **manual multi-host infrastructure**. Compose does not decide which host should run which workload. Your deployment pipeline, host inventory, and operating procedures do. ## Two identical app hosts require shared state Horizontal application scaling becomes useful only when two app instances can serve the same users safely. A common layout is: ```text Users ↓ Load balancer ├── App VM 1 → Docker Compose web replicas └── App VM 2 → Docker Compose web replicas ↓ Shared database ↓ Shared object storage / durable files ``` Before adding the second app host, remove assumptions that only work on one server. ### Sessions must not depend on one local process If a user session exists only in container memory or on one VM filesystem, requests routed to another host may lose authentication or application state. Use a shared session store, signed stateless session model, or another architecture that allows any healthy app instance to serve the request. ### Uploads must not live only on local disk If App VM 1 receives an uploaded file and stores it on its own filesystem, App VM 2 may not be able to serve that file. Durable user uploads usually need shared object storage or another storage model designed for multi-host access. ### Database state must be shared intentionally Two app hosts should normally connect to the same authoritative database service rather than each running an independent local database container. ### Scheduled jobs must avoid duplication If both app hosts start the same scheduler, a daily billing job may run twice. Assign one scheduler role, use distributed locking, or move scheduling into a system designed to coordinate it. ### Migrations need one owner A deployment that starts on two hosts at the same time should not accidentally run the same database migration concurrently unless the migration process is explicitly safe. These are application architecture requirements, not Docker syntax problems. ## A load balancer solves traffic distribution, not orchestration A load balancer can distribute traffic across two or more independent Compose hosts. That can provide meaningful availability without introducing Kubernetes. ```text Internet ↓ Load balancer ├── Host A │ └── Compose app └── Host B └── Compose app ``` For this model to work well, the load balancer needs reliable health information. A host should be removed from rotation when the application cannot serve real requests, not merely when the VM still responds to ping. Health checks should therefore reflect application readiness: - web process is listening; - required dependencies are reachable; - the instance has completed startup; - the deployment is not mid-migration; - the app can serve a lightweight request. This architecture improves host-level resilience, but your team still owns: - provisioning every host; - deploying the same image/configuration to every host; - keeping secrets consistent; - draining traffic before maintenance; - tracking which version is running where; - replacing failed hosts; - coordinating rollbacks. Once those tasks become the main operational burden, orchestration starts earning its complexity. ## Do not stretch one Compose network across hosts casually Compose networking is designed around the Docker Engine that creates the project network. Within one host, services can discover one another by Compose service name. Across independent Docker hosts, that automatic local service-discovery boundary no longer applies. You can connect hosts through normal private networking and address remote services through stable DNS names or private IPs. For example: ```text web host ↓ private DNS / IP worker host ↓ managed database ``` That is often simpler than attempting to make independent Compose projects behave like one distributed container network. Docker supports overlay networks for multi-host communication when Docker Engine is operating in Swarm mode. At that point, however, you are using a cluster feature with managers, workers, service scheduling, and Swarm networking rather than plain Compose-only operations. For single-host public/private exposure, use [Docker Compose Networking: Public Ports, Private Services, and DNS](/learn/guides/docker-compose-networking-public-ports-private-services-dns). ## Running the same Compose file on several hosts is not orchestration It is technically possible to run the same application definition against several Docker Engines. For example, CI/CD can SSH into two servers and run: ```text Host A → docker compose pull && docker compose up -d Host B → docker compose pull && docker compose up -d ``` That may be completely acceptable for a small team. But the deployment system must now answer questions Compose does not answer across those hosts: - What happens if Host A updates successfully and Host B fails? - Which host should receive traffic during deployment? - How is version drift detected? - How are secrets synchronized? - Which host runs one-off migrations? - Which host runs singleton scheduled jobs? - How is capacity rebalanced after a host failure? - Who replaces a failed VM? - How are logs and metrics aggregated? When these answers are simple, multiple Compose hosts can remain a valid operating model. When the answers require a growing collection of deployment scripts, host-specific exceptions, manual checks, and after-hours coordination, the team has effectively started building a scheduler around Compose. That is the point to compare an orchestrator instead of continuing to add scripts. ## Swarm is Docker's native multi-host path Docker's current production guidance states that Compose applications can be scaled on a Swarm cluster. Swarm adds the cluster primitives plain Compose lacks: managers, workers, services, scheduling, overlay networking, replica placement, rolling updates, and service discovery. A simplified model is: ```text Swarm manager ↓ schedules Worker 1 ─┐ Worker 2 ─┼─ overlay network + services Worker 3 ─┘ ``` There is an important compatibility nuance. Docker's current `docker stack deploy` documentation states that Swarm stack deployment uses the legacy Compose file version 3 model and is not fully compatible with the latest Compose Specification. That means teams should not assume that every modern Compose feature will transfer unchanged into `docker stack deploy`. Swarm can be a reasonable choice when: - Docker-native multi-node scheduling is desired; - the team already understands Docker Engine deeply; - the workload needs a smaller orchestration surface; - existing stack-file limitations are acceptable; - the team is willing to operate the Swarm managers and workers. This article does not treat Swarm as a mandatory intermediate step. It is one valid multi-host option. ## K3s or managed Kubernetes becomes stronger when coordination is the real problem Kubernetes-family orchestration becomes useful when the application needs a cluster operating model rather than a collection of individually managed servers. Typical triggers include: - replicas must survive node failure automatically; - workloads need automatic placement across nodes; - rolling deployments span several hosts; - services need stable cluster-level discovery; - configuration must be standardized across environments; - teams need scheduling constraints or workload affinity; - autoscaling becomes useful; - multiple application teams share the infrastructure; - manually tracking host capacity becomes error-prone. K3s can reduce some installation and control-plane overhead for teams that want a lighter Kubernetes distribution. Managed Kubernetes removes more control-plane operations when the business wants Kubernetes semantics without owning the complete cluster platform. The key is to move because orchestration solves measured coordination pain. Do not move because the application now has two servers. Two well-understood Compose hosts behind a load balancer can be easier to operate than a poorly understood cluster. For the full decision, continue with [Kubernetes vs Docker Compose for Small Teams](/learn/guides/kubernetes-vs-docker-compose-small-teams). For the broader container path, use [Container Infrastructure: Docker, K3s, and Kubernetes](/learn/guides/container-infrastructure-docker-k3s-kubernetes). ## The migration path should externalize state first The cleanest transition away from one Compose host usually begins before orchestration. A practical sequence is: ```text Stage 1 One Compose host Stage 2 External database + external durable files Stage 3 Separate worker or scheduler host Stage 4 Two app hosts behind a load balancer Stage 5 Standardized deployment and observability across hosts Stage 6 Orchestrator when host coordination becomes the bottleneck ``` This sequence reduces migration risk because the application becomes less dependent on local host state before workload placement changes. ### Externalize the database A managed database or dedicated database system keeps app hosts replaceable. ### Externalize durable uploads Move user files away from one app server's filesystem. ### Make images reproducible Every host should pull the same versioned image from a registry rather than build ad hoc production images independently. ### Centralize secrets Hosts should retrieve the same approved values from a controlled source. ### Centralize observability Metrics and logs should make host differences visible. ### Make deployment repeatable The same release should produce the same result on every host. These changes help whether the final destination is two Compose VMs, Swarm, K3s, or managed Kubernetes. ## State determines how easy horizontal scaling will be The easiest services to spread across hosts are stateless ones. | Component | Multi-host scaling difficulty | Preferred direction | |---|---:|---| | Stateless API/web | Low | Replicate behind load balancer | | Worker consuming shared queue | Low–medium | Replicate with queue semantics | | Scheduler/cron | Medium | Ensure singleton or locking behavior | | Cache | Medium | External shared cache or intentional partitioning | | Uploaded files | Medium | Shared object storage | | Database | High | Dedicated/managed database strategy | | Local filesystem application state | High | Externalize or design shared storage | A service that can be killed and recreated anywhere is naturally compatible with multi-host infrastructure. A service whose identity is tied to one local path, one IP, or one machine-specific configuration is harder to distribute. This is why application-state cleanup is often more important than the choice of orchestrator. ## Deployment consistency becomes the critical control With one Compose host, deployment drift is limited to one machine. With four hosts, one forgotten update can produce four different production states. A multi-host Compose operating model should therefore record at least: - expected image digest or immutable tag; - expected Compose revision; - expected environment/config version; - current release on each host; - health state; - deployment timestamp; - rollback version; - which hosts are currently in traffic rotation. A minimal deployment sequence can be: ```text 1. Remove Host A from traffic 2. Pull immutable release image 3. Apply Compose update 4. Wait for health 5. Return Host A to traffic 6. Repeat on Host B ``` This gives a simple rolling update without requiring a cluster scheduler. The limitation is ownership: your automation must implement the sequencing and failure handling. An orchestrator becomes valuable when you no longer want deployment scripts to be responsible for convergence. ## Backup and restore must work per role, not just per host Multi-host architecture changes recovery planning. If all important state has already been externalized, app and worker hosts can often be treated as replaceable compute. That is ideal: ```text Failed app host ↓ Provision replacement VM ↓ Install Docker ↓ Pull Compose config + images + secrets ↓ Join load balancer ``` Stateful services need their own recovery path. For a Compose-based application, use [Docker Compose Backup and Restore Strategy](/learn/guides/docker-compose-backup-restore-strategy) to define exactly what must survive host loss. Do not create identical full-host backups as a substitute for understanding which data is actually authoritative. ## Decision framework: stay on one host, add hosts, or orchestrate | Situation | Better next step | Why | |---|---|---| | One VM has spare headroom | Stay on one Compose host | Lowest complexity | | One service needs more CPU | Scale that service locally or resize VM | No new failure domain needed | | Workers hurt web latency | Separate worker host | Clear resource isolation | | Host failure is unacceptable | Two app hosts + load balancer | Adds host redundancy | | Two hosts are easy to deploy manually | Multi-host Compose can remain valid | Low coordination cost | | Host versions frequently drift | Improve deployment automation | Process problem first | | Placement across hosts matters | Introduce scheduler/orchestrator | Compose does not schedule across Engines | | Node failure should trigger automatic rescheduling | Orchestrator | Requires cluster reconciliation | | Several services need independent scaling and rolling updates | K3s/Kubernetes/other orchestrator | Cluster model is becoming useful | | Team wants Docker-native clustering and accepts stack constraints | Evaluate Swarm | Native multi-host Docker path | The correct transition point is not a fixed number of containers or VMs. **The transition point is when coordinating hosts costs more operational effort and risk than operating the orchestrator that would replace that coordination.** ## Raff path from Compose hosts to orchestration Raff VMs can support a staged multi-host design without forcing a cluster from day one. A small production path can look like: ```text Raff VM ↓ Docker Compose ↓ Separate database / durable storage ↓ Additional Raff VM for workers or app replicas ↓ Private service communication + load-balanced app hosts ↓ Raff Kubernetes when cluster scheduling becomes justified ``` This keeps each step tied to an actual requirement. Use [Raff VM](/products/raff-vm) while explicit host roles remain easy to understand and operate. Use [Raff Kubernetes](/products/kubernetes) when workload placement, multi-node availability, rollout coordination, and cluster-level service discovery become recurring needs. The architecture should remain portable either way: versioned images, externalized state, controlled configuration, tested backups, and observable health make both VM and cluster operations easier. :::cta server Add another Raff VM when a measured workload or failure boundary justifies a second Docker host; move to orchestration only when host coordination becomes the problem. ::: ## Scaling beyond one Compose host is a coordination decision Docker Compose can scale service replicas on the Docker Engine it targets, but plain Compose is not a multi-node scheduler. Once workloads must move or converge automatically across hosts, the architecture needs additional coordination. Do not jump directly from one VM to Kubernetes without checking simpler steps. Resize the host when the problem is capacity. Separate workers when workloads compete. Externalize databases and durable files before app replication. Add a second app host behind a load balancer when host availability matters. Then measure the new burden. If deployment sequencing, service discovery, placement, node recovery, and configuration drift are becoming harder than the cluster would be, orchestration has earned its place. Continue with [Kubernetes vs Docker Compose for Small Teams](/learn/guides/kubernetes-vs-docker-compose-small-teams) for the platform decision, or [Docker Compose Backup and Restore Strategy](/learn/guides/docker-compose-backup-restore-strategy) to make each host replaceable before scaling out. ### Sources - [Docker: Use Compose in production](https://docs.docker.com/compose/how-tos/production/) - [Docker: docker compose up](https://docs.docker.com/reference/cli/docker/compose/up/) - [Docker: Deploy a stack to a swarm](https://docs.docker.com/engine/swarm/stack-deploy/) - [Docker: Deploy services to a swarm](https://docs.docker.com/engine/swarm/services/) - [Docker: Overlay network driver](https://docs.docker.com/engine/network/drivers/overlay/) - [Docker: Compose Deploy Specification](https://docs.docker.com/reference/compose-file/deploy/) --- ### Restic vs Borg (2026): S3, SSH & Backup Comparison URL: https://rafftechnologies.com/learn/guides/restic-vs-borg-vs-rsync-backup-tools Description: Compare Restic vs Borg for Linux and cloud server backups: S3-compatible storage, SSH repositories, encryption, deduplication, restore workflows, and where Rsync fits. A cloud-server backup tool is software that preserves recoverable copies of files or system state outside the live workload so data can be restored after deletion, corruption, compromise, or infrastructure failure. For **Restic vs Borg**, the main difference is usually the repository model. Restic is a strong default when you want encrypted, deduplicated backups to S3-compatible object storage, SFTP, or another remote backend. Borg is strongest when you control a Linux backup host and want efficient deduplication, compression, authenticated encryption, and mountable archives over an SSH-based workflow. Rsync solves a different problem: it is excellent for fast file transfer, migration, mirrors, and readable destination copies, but it does not create a versioned backup repository by default. On Raff Technologies, these tools fit alongside platform-level recovery rather than replacing it. Start with [Cloud Server Backup Strategies: RPO, RTO, and Recovery Planning](/learn/guides/cloud-server-backup-rpo-rto-snapshots) to define what must be recoverable, then use this guide to choose the file-level tool that matches the failure you are designing for. ## Restic vs Borg is mainly a repository decision Restic and Borg overlap in important ways. Both are real backup programs built around deduplicated repositories, encryption, multiple restore points, pruning, and recovery from historical archives. The practical difference is where you want the repository to live and how much backup infrastructure you want to operate. Restic has a broad backend model. Its official documentation supports local storage, SFTP, REST servers, Amazon S3, S3-compatible object storage, Azure, Google Cloud Storage, Backblaze B2, Swift, and additional services through rclone. That makes Restic attractive when the backup should live outside the VM without requiring a second Linux server dedicated to receiving backups. Borg's mature stable workflow is more server-centric. A common design is a production Linux server writing deduplicated archives to a separate Linux repository host over SSH. Borg is especially appealing when the team controls both ends of that connection and values compression, mountable archives, and direct repository administration. Rsync sits beside these two rather than directly replacing them. It copies files efficiently between local or remote paths and can preserve permissions and other file metadata in archive mode. It can be part of a backup design, but history, retention, and protection from mirrored deletions must be designed separately. **A file copy is not a recovery policy; history, off-server separation, and restore testing determine whether it behaves like a backup.** ## The decision framework separates recovery history from file transfer Use the recovery requirement first, then choose the tool. | Decision factor | Restic | Borg | Rsync | |---|---|---|---| | Primary job | Versioned backup repository | Versioned backup repository | File copy and synchronization | | Deduplication | Yes | Yes | No repository-level deduplication by default | | Encryption in the backup tool | Yes | Yes, when configured | No backup-repository encryption | | Compression | Supported | Strong built-in options | Not a backup compression model | | S3-compatible storage | Native fit | Not the primary stable workflow | Requires another storage layer/tool | | Remote Linux backup host | Good | Excellent | Excellent for copies/mirrors | | Historical restore points | Built in through snapshots | Built in through archives | Must be designed separately | | Browse/mount historical backup | Repository restore/mount workflow | Strong mountable archive workflow | Destination is directly readable | | Best operational fit | Object storage or mixed backends | Controlled Linux repository server | Migration, mirror, readable copy | | Main operational risk | Repository credentials/password loss | Repository host/key management | Mirroring deletion or corruption | **Choose Restic if:** - the repository should live in S3-compatible object storage; - you want one backup model across several remote backend types; - encrypted off-server history matters more than directly readable destination files; - the team does not want to operate a dedicated Borg repository server. **Choose Borg if:** - you control a Linux backup host or storage server; - SSH is the natural transport between production and backup infrastructure; - compression and mountable archives matter; - the team is comfortable administering repository storage directly. **Choose Rsync if:** - the real job is migration or synchronization; - operators need files to remain directly readable at the destination; - a server-to-server copy is more useful than a repository format; - retention and historical recovery are handled by another layer. There is no useful universal winner. The correct choice depends on whether you need a backup repository, a controlled backup server, or simply a reliable file transfer. ## Restic fits object-storage and mixed-backend recovery Restic is a strong fit for cloud servers because the repository can be separated cleanly from the source VM. A practical architecture is: ```text Application VM ↓ Restic ↓ Encrypted repository ↓ S3-compatible object storage or remote backend ``` Each Restic backup creates a repository snapshot. Retention policies can preserve daily, weekly, monthly, or time-window-based history while pruning older data according to policy. Deduplication prevents unchanged data from being stored repeatedly as complete copies. Restic also encrypts repository data before it is stored. That makes the repository password part of the recovery architecture. If the only copy of the repository password is kept on the VM that is lost or compromised, the backup design still has a single point of failure. For Raff users, Restic can target [Raff Object Storage](/products/object-storage) through its S3-compatible interface. This is a useful off-server pattern because the repository is independent from the VM being protected. One limitation matters when designing retention: Raff Object Storage's current public feature set does not provide bucket versioning or Object Lock. Restic's own repository snapshots and retention policy therefore provide the backup history; do not assume the bucket itself gives you an additional historical or WORM layer. Restic is usually the better choice than Borg when object storage is the destination. It is also a cleaner choice than Rsync when you need encrypted historical restore points rather than a readable mirror. ## Borg fits controlled Linux backup repositories Borg is strongest when the team controls the repository host. A typical pattern is: ```text Production Linux VM ↓ SSH Dedicated backup host ↓ Borg repository ``` Borg deduplicates content, supports compression, offers authenticated encryption, and lets operators mount archives for inspection or selective restores. Those characteristics make it well suited to Linux administrators who want a backup system that behaves like infrastructure they fully control. This model has an operational advantage: the backup target can be isolated as its own server role. Access can be restricted, storage capacity can be monitored independently, and the team can decide exactly how repository retention and maintenance are handled. The trade-off is ownership. Someone must operate the backup host, secure SSH access, monitor capacity, update Borg, protect the repository keys, and verify recovery. Borg is a strong choice when: - the organization already has a backup server; - private Linux-to-Linux connectivity is available; - the repository should remain under direct administrative control; - mountable archives simplify file recovery; - object storage is not the primary target. For S3-compatible object storage, Restic has the simpler native model. Adding gateways or compatibility layers to make Borg behave like an object-storage client usually increases complexity without improving recovery for a small team. ## Rsync fits synchronization, migration, and readable copies Rsync remains one of the most useful Linux operations tools because it solves file movement directly. It can copy data locally or to a remote host, usually over SSH, and archive mode can preserve important filesystem metadata. That makes it valuable for: - server migrations; - copying upload directories; - maintaining a readable secondary copy; - seeding a new server; - synchronizing application files; - moving data before a cutover. The key limitation is historical recovery. A normal Rsync mirror represents the current copied state. If the source loses a file and the synchronization is configured to delete files that no longer exist at the source, the destination can faithfully reproduce the deletion. The official Rsync documentation explicitly treats `--delete` as an option that needs care. A dry run is a sensible control before destructive synchronization because synchronization correctness and backup recoverability are not the same thing. Rsync can be extended into a backup workflow with timestamped directories, `--backup-dir`, hard-link strategies, external snapshots, or retention scripts. That can work well, but operational complexity rises quickly. If the requirement is already “encrypted deduplicated history with pruning,” Restic or Borg usually expresses that requirement more directly. Use [Automate Server Backups with Cron and Rsync on Ubuntu 24.04](/learn/tutorials/automate-backups-cron-rsync-ubuntu-24-04) when Rsync really is the right operational building block. ## Platform backups, file backups, and database backups solve different failures One backup mechanism should not be expected to cover every failure mode. On Raff, platform-level Data Protection protects the VM at the infrastructure layer. Restic or Borg protects selected files through an independent repository model. Rsync transfers files between systems. Databases need their own consistency-aware recovery design. | Failure or task | Better recovery layer | Why | |---|---|---| | Whole VM must be restored | Raff scheduled VM backup | Infrastructure-level VM recovery | | Risky change needs a short-lived checkpoint | Raff snapshot, when backups are not enabled on that VM | Fast point-in-time VM rollback | | User deletes a file days ago | Restic or Borg | Historical file-level restore | | VM is compromised | Restic or Borg restored to a clean VM | Avoid trusting the compromised source | | Server migration | Rsync | Efficient readable server-to-server transfer | | Database logical corruption | Database-native backup/PITR | Transaction consistency matters | | Database dump needs off-server retention | Native dump + Restic/Borg/object storage | Separates database consistency from repository storage | Raff's current Data Protection model requires another important distinction: **a VM with scheduled backups enabled cannot also use snapshots at the same time.** Choose the platform protection mode that fits the workload instead of designing around an assumption that both mechanisms can always be stacked on one VM. File-level tools remain useful beside platform backups because they solve different restore questions. A VM backup may recover the server; a Restic or Borg repository may recover one file or a historical configuration independently. Database files need extra care. Copying a live PostgreSQL, MySQL, or MariaDB data directory with a generic file-copy command is not a substitute for a database-aware backup method. Use logical dumps, physical backup tooling, or point-in-time recovery appropriate to the engine, then store the resulting backup artifacts according to the retention design. For the broader recovery layers, read [Cloud Snapshots vs Backups](/learn/guides/snapshots-vs-backups-cloud-server) and [PostgreSQL Replication vs Backups vs Snapshots](/learn/guides/postgresql-replication-vs-backups-vs-snapshots). ## Backup integrity depends on credentials and restore tests A backup job that finishes successfully has not yet proven that the workload is recoverable. The recovery design should protect both the data and the credentials required to restore it. For Restic or Borg repositories: - keep repository passwords or keys outside the only VM being protected; - use separate credentials for backup access; - restrict repository permissions to the minimum required; - rotate credentials after a compromise; - monitor backup failures and repository capacity; - verify repository integrity on a defined schedule; - test restores from a clean environment. For object storage, use scoped credentials rather than broad account access where the product supports it. For a dedicated Borg host, restrict SSH access and treat the repository server as production recovery infrastructure rather than a disposable utility VM. Restore tests should match business recovery requirements. A file-level test can prove that selected files are readable. A service-level test should restore the application data onto a clean VM, start the service, validate logs and dependencies, and confirm that the restored data is usable. **A backup is not proven by job success; it is proven by restoring the data or service that matters.** For a structured recovery exercise, use the [Restore Testing Checklist for Production VMs](/learn/guides/restore-testing-checklist-production-vms). ## Raff supports layered recovery without forcing one backup tool Raff's role in this architecture is to provide the infrastructure layers while the team selects the file and application backup methods that match its workload. A practical small-team design can look like this: | Layer | Raff or application component | Recommended role | |---|---|---| | Compute | Raff VM | Runs the workload | | VM recovery | Raff Data Protection | Scheduled infrastructure-level recovery | | Short-lived checkpoint | Raff snapshot, when compatible with the VM's protection mode | Pre-change rollback | | File-level history | Restic or Borg | Independent historical repository | | Off-server repository | Raff Object Storage or separate backup host | Keeps recovery data away from source VM | | Database consistency | Database-native backup method | Produces recoverable database state | | Migration | Rsync | Moves files between systems | Raff Object Storage is S3-compatible, which makes it a natural Restic repository target when object storage is the chosen backend. A dedicated Linux backup VM is the more natural Borg pattern. Rsync remains useful when the real requirement is moving data rather than maintaining historical repository snapshots. This layered model also avoids overpromising. Platform backups do not replace database-native recovery. Restic does not replace VM recovery for every system failure. Borg does not remove the need to secure a backup host. Rsync does not create historical retention unless the team builds that retention explicitly. The strongest design is the smallest set of recovery layers that covers the failures the business actually needs to survive. ## Conclusion Restic vs Borg is primarily a repository and ownership decision. Choose **Restic** when encrypted, deduplicated backups need to go to S3-compatible object storage or another remote backend. Choose **Borg** when you control a Linux backup host and want efficient SSH-based repositories, compression, encryption, and mountable archives. Choose **Rsync** when synchronization, migration, or a directly readable secondary copy is the actual job. Do not make the tool carry responsibilities that belong to another recovery layer. Use platform-level VM protection for VM recovery, database-native methods for transaction-consistent database backups, and file-level repositories for historical data recovery. Start with [Cloud Server Backup Strategies: RPO, RTO, and Recovery Planning](/learn/guides/cloud-server-backup-rpo-rto-snapshots), then use [Restore Testing Checklist for Production VMs](/learn/guides/restore-testing-checklist-production-vms) to prove that the design works before an incident does it for you. :::cta Explore Object Storage Use S3-compatible off-server storage when Restic is the right fit for your backup repository. ::: ### Sources - [Restic Documentation](https://restic.readthedocs.io/en/stable/) - [BorgBackup Documentation](https://borgbackup.readthedocs.io/en/stable/) - [Rsync Manual](https://download.samba.org/pub/rsync/rsync.1) - [Raff Data Protection](/products/data-protection) - [Raff Object Storage](/products/object-storage) - Date verified: 2026-08-08 --- ### Cloud Firewall Best Practices: Inbound, Outbound, and Private Traffic URL: https://rafftechnologies.com/learn/guides/firewall-best-practices-cloud-servers Description: Cloud firewall best practices for inbound and outbound rules, SSH/RDP, private services, IPv4/IPv6, VM security, rule reviews, and Raff VPC architecture. A cloud firewall controls which network paths are allowed to reach or leave a cloud server. **The safest default is to expose only the public services the workload actually needs, restrict administrative access, keep databases and internal services on private paths, and review both inbound and outbound rules as the architecture changes.** Raff Technologies workloads can combine host-level firewall policy with [VPC](/products/vpc) private networking and the platform's current [Security](/products/security) capabilities. A firewall reduces reachability, but it does not replace secure authentication, patching, application security, encryption, monitoring, or backups. ## Cloud firewall best practices: quick answer For a typical cloud VM or small application stack: - deny unnecessary inbound traffic by default; - allow public HTTP/HTTPS only when the workload serves public users; - restrict SSH and RDP to approved administrative paths; - keep databases, caches, queues, metrics, and internal APIs off the public internet; - review outbound traffic for sensitive or predictable workloads; - apply equivalent policy to IPv4 and IPv6; - use separate rules for different server roles; - give temporary rules an owner and expiry; - test allowed and denied paths after every meaningful firewall change. | Traffic path | Safer default | |---|---| | Public web traffic | Allow TCP 80/443 only when required | | SSH or RDP | Restrict to trusted IPs, VPN, gateway, or private path | | Application runtime ports | Localhost or approved private sources | | Database, cache, queue | Private network and approved sources only | | Monitoring/admin dashboards | Private or strongly authenticated access | | Outbound package/API access | Allow required destinations where practical | | All other inbound traffic | Deny | A useful rule is: > **If a firewall rule has no clear service, source, owner, and reason to exist, it should not remain in production.** ## What is a cloud firewall? A **cloud firewall** is a network control that filters traffic to or from cloud workloads according to rules such as source, destination, protocol, port, and direction. A firewall can be enforced at more than one layer: - provider or platform network boundary; - virtual network or subnet boundary; - operating-system firewall inside the VM; - application gateway or reverse proxy; - application authentication and authorization. These layers solve related but different problems. A network firewall decides whether a connection can reach a service. The application still needs to decide whether the user or service is authorized to perform an action. ## Start with traffic flows, not a generic port list Before creating firewall rules, document the communication paths the application actually requires. For example: ```text Internet ↓ HTTPS 443 Public web / reverse-proxy VM ↓ private application port Application VM ↓ private database port Database service ``` Then add management and operational paths: ```text Approved administrator ↓ restricted SSH or RDP Application / database VM Monitoring service ↓ approved metrics path Application / database VM ``` For each flow, record: - source; - destination; - protocol; - port; - public or private path; - purpose; - owner; - expected lifetime. This is safer than copying a list of “common cloud ports” because every rule maps to a real dependency. ## Use deny by default for inbound traffic A deny-by-default inbound policy means connections are blocked unless a rule explicitly allows them. This reduces attack surface because installed or accidentally listening services do not automatically become reachable from the internet. A public Linux web VM might need: | Service | Port | Source | |---|---:|---| | HTTP | TCP 80 | Public internet, if used for redirect or certificate validation | | HTTPS | TCP 443 | Public internet | | SSH | TCP 22 | Approved admin source only | | Application runtime | TCP 3000, 8000, 8080, or app-specific | Localhost or approved private source | | Database | Engine-specific | No broad public access | The exact ports depend on the workload. Do not open ports simply because an application documentation page lists them; confirm whether the port must be reachable publicly, privately, or only from localhost. ## Inbound vs outbound firewall rules **Inbound firewall rules** control connections initiated toward the VM. **Outbound firewall rules** control connections initiated by the VM toward another destination. | Direction | Typical question | Example | |---|---|---| | Inbound | Who is allowed to reach this service? | Internet → HTTPS 443 | | Inbound | Who can administer this VM? | Office/VPN → SSH 22 | | Private inbound | Which application can reach the database? | App subnet → PostgreSQL 5432 | | Outbound | Which services may this VM call? | App VM → payment/API endpoint | | Outbound | Can this internal service reach the internet? | Worker → approved external dependencies | Inbound policy is usually the first priority because public exposure is easy to understand and exploit. Outbound filtering becomes more valuable when a workload handles sensitive data, has predictable dependencies, or would create meaningful risk if compromised. ## Restrict SSH and RDP separately from application traffic Administrative services can change the system, so they deserve stricter controls than user-facing web traffic. Prefer one or more of these patterns: - trusted source IPs; - VPN access; - controlled gateway or bastion access; - private-network administration; - temporary, time-bounded firewall access. Network restriction should be combined with identity controls such as: - individual administrator accounts; - SSH keys for Linux where appropriate; - strong Windows credentials; - least privilege; - rapid offboarding; - administrative logging. Avoid leaving SSH or RDP open to the entire internet simply because credentials are strong. Reachability and authentication are separate security layers. Read [Private vs Public Admin Access](/learn/guides/private-vs-public-admin-access) for the architecture decision. ## Keep databases and internal services private Database authentication is necessary, but it should not be the only boundary. Services that normally should not accept broad public traffic include: - PostgreSQL and MySQL; - Microsoft SQL Server; - Valkey and other caches; - message queues and brokers; - search services; - metrics endpoints; - internal APIs; - orchestration control planes; - internal dashboards. Allow the smallest approved source set, such as the application tier, a private subnet, or a controlled administrative path. Private networking does not mean “trusted by default.” A VPC can still become overly permissive if every private host can reach every service. Apply least privilege inside the private network as well. Use [Private Networking in Cloud](/learn/guides/private-networking-public-vs-private-traffic) for the broader public/private traffic design. ## Cloud firewall rules should follow server roles Different server roles should not inherit one universal rule set. | Role | Public ingress | Private ingress | Typical outbound | |---|---|---|---| | Public web/reverse proxy | HTTP/HTTPS | Admin, monitoring, backend | App dependencies, updates | | Application VM | Usually none | Web tier, admin, monitoring | Database, cache, APIs | | Database VM/service | None | Application tier, controlled admin | Backups, updates, monitoring as required | | Worker VM | None | Queue/admin/monitoring as needed | Queue, database, storage, APIs | | Bastion/gateway | Restricted admin protocol | Approved internal management | Limited management paths | | Monitoring system | Usually none | Metrics/log paths | Notification or storage destinations | Role-based rules are easier to review than one large collection of copied exceptions. ## Review outbound firewall rules where the risk justifies it Outbound restrictions can reduce the impact of: - compromised applications; - malicious dependencies; - unexpected data transfer; - lateral movement; - misconfigured scripts; - command-and-control traffic. Not every small VM needs a complex egress allowlist. Overly strict outbound rules can also break package repositories, certificate renewal, DNS, time synchronization, APIs, object storage, email delivery, or monitoring. Start with workloads that have narrow and predictable dependencies. Examples include: - a database host that should reach only updates, backups, DNS, and monitoring; - a worker that should call one approved API; - an internal service that should not initiate arbitrary internet connections; - a production application with a known set of external services. For external services whose IP addresses change frequently, do not build a brittle fixed-IP policy unless the service publishes stable ranges or another controlled egress mechanism is available. ## Apply equivalent policy to IPv4 and IPv6 A common dual-stack mistake is protecting IPv4 while IPv6 remains broadly reachable. Review both address families for: - HTTP/HTTPS; - SSH and RDP; - database/cache ports; - monitoring endpoints; - administrative dashboards; - outbound restrictions. Do not assume a platform or operating-system firewall automatically mirrors every IPv4 rule to IPv6. Read [IPv4, IPv6, and Dual-Stack Networking](/learn/guides/ipv4-ipv6-dual-stack-networking-cloud-servers) before enabling dual-stack access in production. ## Understand stateful firewall behavior Many cloud and operating-system firewalls are **stateful**, meaning return traffic for an allowed connection is tracked and permitted automatically. Others may evaluate directions or interfaces differently. Before designing complex rules, verify: - whether the firewall is stateful; - whether inbound and outbound policy are evaluated separately; - what happens to established connections after a rule changes; - whether NAT changes the apparent source or destination; - whether health checks or monitoring require separate rules; - whether IPv6 follows the same model. Do not add broad “return traffic” rules unless the firewall model actually requires them. ## Platform firewall vs OS firewall A provider-level or platform firewall can reduce traffic before it reaches the VM. An operating-system firewall such as nftables, UFW, firewalld, or Windows Defender Firewall enforces policy inside the guest. Using both can provide defense in depth, but duplicated rule sets can create operational confusion. A practical ownership model is: - platform/network policy for the broad exposure boundary; - operating-system firewall for host-specific services and interfaces; - application authentication for identity and authorization. Document which layer owns each rule. If traffic fails, operators should know whether to inspect the network boundary, host firewall, service binding, reverse proxy, or application permissions first. ## Managed firewall controls vs iptables or command-line rules Some teams prefer provider-level controls because they do not want every exposure change to depend on editing iptables, nftables, UFW, or Windows Firewall manually. That can reduce host-by-host drift, but it does not eliminate the need to understand the guest firewall. A service may still be reachable locally, bound to the wrong interface, or exposed through a different network path. For important workloads, treat provider-level filtering and host-level configuration as complementary controls with clear ownership rather than assuming one automatically replaces the other. ## Temporary firewall rules need an expiry Temporary access is one of the most common ways a narrow rule becomes permanent exposure. Every temporary rule should have: - reason; - requester; - owner; - creation time; - expiry or removal event; - affected workload. Typical temporary cases include: - migration access; - vendor support; - debugging; - one-time data transfer; - short-lived administrative work. Remove the rule when the work ends instead of waiting for a future audit. ## Test firewall changes from both allowed and denied paths A firewall change can either expose a service or lock out an administrator. Use a controlled change sequence: 1. Record the intended traffic flow. 2. Confirm an alternative access path or console exists before changing remote admin rules. 3. Add the narrowest required rule. 4. Test from an allowed source. 5. Test from a disallowed source. 6. Verify application health and monitoring. 7. Remove obsolete or temporary rules. 8. Record the result. For production database and administrative changes, avoid changing several firewall layers at once unless the rollback sequence is clear. ## Review firewall rules after architecture changes Firewall policy can become stale when infrastructure changes even if nobody edits the firewall directly. Review rules after: - adding or removing servers; - changing public IPs; - enabling IPv6; - moving a database to a separate service; - introducing a VPC; - replacing a reverse proxy; - changing monitoring tools; - retiring an administrator or vendor; - migrating an application; - exposing a new API or dashboard. Look for: - unused public ports; - source ranges that are broader than necessary; - old administrator IPs; - rules pointing to retired systems; - duplicate host and platform rules; - temporary exceptions without owners. Use [Stale Infrastructure Cleanup](/learn/guides/stale-infrastructure-risk-old-servers-forgotten-keys-abandoned-services) when security policy is tied to servers or services being retired. ## Firewall policy is only one part of cloud server security A firewall cannot protect an application from every threat on an allowed port. If HTTPS 443 is public, the application behind 443 still needs secure authentication, authorization, input handling, patching, secrets management, logging, and recovery controls. A production VM security baseline should also include: - supported OS and package updates; - secure SSH/RDP configuration; - least-privilege users; - protected secrets; - TLS for public services; - monitoring and alerting; - backups and tested restore procedures; - documented incident ownership. Use [Cloud Security Fundamentals](/learn/guides/cloud-security-fundamentals) for the broader security model and [Cloud Snapshots vs Backups](/learn/guides/snapshots-vs-backups-cloud-server) for recovery protection. ## How this applies on Raff For Raff workloads, the current architecture can use: - [Raff Cloud Servers](/products/raff-vm) for public or private application VMs; - [VPC](/products/vpc) for private service-to-service networking; - [Security](/products/security) for Raff's current platform security capabilities; - [Site-to-Site VPN](/products/site-to-site-vpn) when an approved private path between networks is required; - [Data Protection](/products/data-protection) for snapshot and backup workflows after security or configuration changes. A simple architecture can look like: ```text Internet ↓ only required public ports Public application / reverse-proxy VM ↓ private VPC path Application, database, and internal services ``` Do not depend on the public Load Balancer product page for this design while Raff's managed load-balancer availability is not currently confirmed as generally deployable. Traffic distribution can still be handled at the application architecture layer when required. Raff VM public traffic currently uses a **3 Gbps connection with unmetered VM traffic and no VM egress fee**. VPC traffic is private and unmetered. Network pricing does not change the security principle: private services should remain private even when traffic itself is inexpensive. :::cta Explore Raff Security Review Raff's current security and private-networking options before exposing a production VM to public traffic. ::: ## Cloud firewall checklist ### Public exposure - [ ] Only required public services are reachable. - [ ] SSH/RDP is restricted. - [ ] Database, cache, queue, and internal API ports are not broadly public. - [ ] IPv4 and IPv6 have equivalent intended policy. ### Private traffic - [ ] Internal services use private paths where appropriate. - [ ] Private-network access is still least privilege. - [ ] Application-to-database and worker-to-queue paths are documented. ### Rule quality - [ ] Each rule has a purpose and owner. - [ ] Temporary rules have an expiry. - [ ] Old server and administrator rules are removed. - [ ] Platform and OS firewall ownership is documented. ### Operations - [ ] Allowed paths were tested. - [ ] Denied paths were tested. - [ ] An alternate admin recovery path exists before remote-access changes. - [ ] Firewall reviews follow major architecture changes. :::cluster ## Conclusion Cloud firewall best practices are mostly about making network access intentional. Start with deny-by-default inbound policy, expose only required public services, restrict SSH and RDP, keep databases and internal services on private paths, review outbound access where it materially reduces risk, and apply the intended policy to both IPv4 and IPv6. The goal is not to create the largest firewall rule set. It is to maintain the **smallest understandable network policy that allows the application to work without exposing unnecessary paths**. ## Sources - [NIST SP 800-41 Rev. 1: Guidelines on Firewalls and Firewall Policy](https://csrc.nist.gov/pubs/sp/800/41/r1/final) - [Raff Security](/products/security) - [Raff VPC](/products/vpc) - [Raff Site-to-Site VPN](/products/site-to-site-vpn) --- ### MCP vs n8n vs API Integration: Choosing the Right Automation Layer URL: https://rafftechnologies.com/learn/guides/mcp-vs-n8n-vs-api-integration Description: Compare MCP vs n8n vs direct API integration, including MCP vs API, current n8n MCP support, security, orchestration, and hosting choices. MCP, n8n, and direct API integration solve different layers of an automation architecture. **MCP is a protocol for exposing tools and context to AI applications. n8n is a workflow automation platform that can orchestrate systems and now also includes MCP client/server capabilities. Direct API integration gives application code the most explicit control over requests, validation, retries, performance, and business rules.** They are not mutually exclusive. A production system can use all three: ```text Validated product API ↑ ↑ n8n workflows MCP-facing tools ``` The important decision is not “which technology wins?” It is **which layer should own the business rule, which layer should orchestrate the process, and which interface should an AI client receive**. For Raff Technologies workloads, the same separation helps infrastructure stay understandable: APIs and MCP services can run on application VMs or an app platform, n8n can run as a self-hosted workflow service, and private dependencies can remain behind controlled VPC paths. ## MCP vs n8n vs API: quick answer Choose **MCP** when an AI application needs a standardized way to discover and invoke approved tools or retrieve structured context. Choose **n8n** when a trigger should execute a visible, repeatable workflow across APIs, databases, SaaS tools, queues, and AI components. Choose **direct API integration** when the integration is part of the product itself and requires deterministic validation, transaction logic, low latency, high throughput, or tight test coverage. | Decision factor | MCP | n8n | Direct API integration | |---|---|---|---| | Primary role | AI-facing tool/context protocol | Workflow orchestration platform | Application-to-application interface in code | | Who controls execution? | AI host/client plus server policy | Workflow definition | Application code | | Best fit | AI assistants and tool-enabled applications | Business/ops automation | Core product features and backend systems | | Predictability | Depends on host, model, permissions, and tool policy | High when workflow paths are defined | Highest when behavior is explicitly coded | | Visual workflow | No | Yes | No | | Dynamic tool discovery | Core use case | Available through MCP features, but n8n itself is broader than MCP | Not normally | | Transaction/business logic | Better kept behind tools/APIs | Suitable for orchestration; use care with core invariants | Strong fit | | Typical owner | AI/platform team | Automation, ops, or engineering | Software engineering | A practical rule is: > **Use APIs for durable capabilities and business rules, n8n for repeatable orchestration, and MCP when AI clients need a standardized interface to selected capabilities.** ## What is MCP? MCP stands for **Model Context Protocol**. It is an open protocol that lets AI applications connect to external tools and contextual data through a defined interface. An MCP server can expose capabilities such as: - **tools** that perform actions or calculations; - **resources** that provide contextual data; - **prompts** that provide reusable interaction templates. A simplified architecture is: ```text User ↓ AI application / MCP client ↓ MCP server ↓ API, database, file, workflow, or internal service ``` The important architectural point is that the MCP server often sits **in front of an existing capability**. The underlying API, database, workflow, or application service still owns the actual data and business operation. MCP therefore does not replace good backend architecture. It standardizes how an AI-capable client sees and invokes selected capabilities. ## MCP changed materially in 2026 The MCP specification continues to evolve, so older architectural assumptions should not be treated as permanent protocol behavior. The **2026-07-28 MCP specification** moved the core HTTP model toward stateless operation. The previous initialization/session assumptions were removed from the new revision, and discovery became optional rather than a required handshake. This makes remote MCP services easier to place behind ordinary horizontally scaled HTTP infrastructure. The same release also continued authorization hardening and moved long-running tasks into an extension model. Roots, sampling, and protocol logging were marked deprecated for new implementations, while tools, resources, and prompts remain part of the server surface. For teams building a new MCP service, the implication is simple: **design against the current specification and SDK release rather than copying a 2025 example without checking its protocol version**. ## What is n8n? n8n is a workflow automation platform for connecting services, APIs, databases, triggers, transformations, conditions, and AI components into repeatable processes. A typical workflow might be: ```text Webhook received ↓ Validate payload ↓ Look up customer ↓ Call internal API ↓ Update CRM ↓ Send notification ``` The workflow path is defined in advance. Runtime data changes, but the process remains visible and inspectable. n8n is useful when: - a workflow crosses several services; - a webhook or schedule starts the process; - operators need visible execution history; - process logic changes more frequently than core product code; - several APIs need to be coordinated; - human approval or branching should be part of the flow. ## Is n8n an MCP server? **n8n is not the same thing as MCP, but current n8n releases can participate directly in MCP architectures.** n8n documentation now includes: - an **MCP Client** node; - an **MCP Client Tool** for AI workflows; - an **MCP Server Trigger**; - an **instance-level MCP server** for exposing selected n8n capabilities to MCP clients. That changes the practical comparison. A better model is: ```text MCP = protocol n8n = workflow platform that can also speak MCP API = underlying software interface ``` So the question “n8n vs MCP” is still useful for deciding architecture, but it is no longer accurate to describe them as completely separate technologies that cannot overlap. ## MCP vs n8n: what is the real difference? **MCP defines an interface. n8n defines and executes workflows.** MCP answers: > How can an AI client discover or invoke selected tools and context through a standard protocol? n8n answers: > How should a repeatable process move data and execute steps across connected systems? This means a workflow can be exposed through MCP without making MCP responsible for the workflow itself. For example: ```text AI client ↓ MCP start_customer_onboarding ↓ n8n workflow ↓ CRM → billing → email → internal notification ``` The AI client selects an approved high-level action. n8n owns the deterministic sequence. | Scenario | Better starting point | |---|---| | AI assistant needs approved tools | MCP | | Lead should be enriched and routed | n8n | | Product must provision an account reliably | Direct API | | AI assistant should start an approved workflow | MCP + n8n | | n8n needs access to an external MCP tool | n8n MCP client capability | | Existing workflow should be exposed to MCP clients | n8n MCP server capability | | Core capability should serve apps, workflows, and AI clients | API as source of truth + n8n/MCP adapters | ## MCP vs API: does MCP replace APIs? **No. MCP and APIs solve different interface problems.** An API exposes software capabilities to applications and services. MCP exposes selected capabilities in a way designed for MCP-compatible AI clients. A common architecture is: ```text Internal/product API ↓ MCP server exposes selected tools ↓ AI client ``` For example, a ticketing API may support dozens of endpoints, while the MCP layer exposes only: ```text search_tickets get_ticket create_ticket ``` The API should still enforce authentication, authorization, validation, tenant boundaries, business rules, rate limits, and data consistency. The MCP layer gives the AI client a controlled tool contract; it should not become a second copy of the business logic. ## API vs MCP: which should be the source of truth? For most production systems, **the API or underlying application service should remain the source of truth**. This matters because the same business rule may need to be used by: - the product UI; - mobile applications; - background jobs; - n8n workflows; - MCP clients; - internal automation. If validation is implemented separately in every n8n workflow and MCP tool, those implementations can drift. A stronger pattern is: ```text Product UI ↓ n8n workflow → Validated API ← MCP server ↑ Workers ``` The API owns the rule. n8n and MCP become controlled callers. ## When direct API integration is better Direct API integration is usually the better choice when: - the integration is a customer-facing product feature; - strict transaction or consistency rules apply; - latency matters; - high request volume is expected; - the engineering team needs extensive automated tests; - failures need domain-specific recovery behavior; - the integration must deploy with the application; - there should be no dependency on a separate workflow engine. Examples include account provisioning, payments, usage metering, authentication, infrastructure control planes, entitlement management, and customer-facing integrations. ## When n8n is better than direct API code n8n is strongest when the problem is **orchestration rather than a core product invariant**. Good candidates include CRM synchronization, sales or support routing, onboarding coordination, scheduled reports, content workflows, notifications, moderate-volume data movement, approval processes, and coordinating several vendor APIs. > **Keep core business invariants in tested application code. Use n8n to coordinate systems around those invariants.** ## When MCP is better for an AI client MCP is useful when the main consumer is an AI-capable host and you want a reusable, discoverable contract for tools or context. Use MCP when several AI clients may need the same capability, the client should discover approved tools, tool schemas need to be visible to AI hosts, resources or prompts should be exposed alongside actions, or the team wants a dedicated AI-facing permission boundary. Do not add MCP merely because an application contains an LLM. If the model only needs one tightly controlled backend action, a normal application API may remain simpler. ## Can MCP, n8n, and APIs work together? Yes. This is often the strongest architecture. ### Pattern 1 — MCP triggers a controlled n8n workflow ```text User ↓ AI host ↓ MCP approved_workflow_tool ↓ n8n ↓ CRM + email + internal API ``` ### Pattern 2 — n8n consumes MCP tools ```text Workflow trigger ↓ n8n ↓ MCP client External MCP server ↓ Approved tool ``` ### Pattern 3 — n8n exposes workflows through MCP ```text AI client ↓ MCP n8n MCP server / MCP Server Trigger ↓ Selected workflow ``` ### Pattern 4 — API stays authoritative ```text n8n ↓ AI → MCP → API ← Product ↑ Worker ``` This is the strongest long-term pattern when several automation surfaces share the same business operations. ## Security: the execution layer does not replace authorization Whether a request enters through MCP, n8n, or a direct API, the underlying system should still enforce authorization. Use least-privilege credentials, keep validation outside the model, separate read and write capabilities, treat retrieved content as untrusted, and protect n8n webhooks with the authentication or signature controls appropriate to the sender. ## Reliability: retries must not duplicate business actions Automation systems encounter transient failures, rate limits, network errors, and partial completion. Design important actions for **idempotency**. A repeated request should not accidentally create two invoices, two accounts, two VMs, two customer emails, or duplicate database records. | Failure | Typical handling | |---|---| | Temporary network failure | Bounded retry with backoff | | Rate limit | Retry according to provider guidance | | Invalid input | Fail and correct input | | Authentication failure | Stop and repair credentials | | Business-rule rejection | Do not blindly retry | | Partial multi-step workflow | Resume or compensate intentionally | ## Monitoring should follow the whole automation path A successful MCP tool call does not prove the downstream business process completed. A successful n8n node does not prove the final customer outcome was correct. Monitor MCP request/tool errors, n8n execution state, API latency and errors, queue depth, external provider failures, retries, and final business outcomes. ## Hosting MCP, n8n, and APIs on Raff ### Self-hosted n8n A self-hosted n8n deployment needs persistent configuration, secure credentials, a database strategy, backups, and enough memory for execution concurrency. It can run on a [Raff Cloud Server](/products/raff-vm). Use [What Is Self-Hosting?](/learn/guides/self-hosting-getting-started) for the broader operational trade-offs. ### MCP servers Remote MCP servers can run as application services on [Raff Cloud Servers](/products/raff-vm) or, where the workload fits, [Raff Apps](/products/app-platform). ### APIs Application APIs can run on Raff VMs or Raff Apps. Keep internal databases and services on controlled private paths through [VPC](/products/vpc) where public exposure is unnecessary. Use [Cloud Firewall Best Practices](/learn/guides/firewall-best-practices-cloud-servers) for network policy and [Stateful vs Stateless Applications](/learn/guides/stateful-vs-stateless-applications) for scaling decisions. ### Persistent state and recovery Workflow configuration, credentials, application databases, and business data may need independent recovery planning. Use [Data Protection](/products/data-protection) and [Cloud Snapshots vs Backups](/learn/guides/snapshots-vs-backups-cloud-server) for VM protection and recovery design. If an application needs PostgreSQL, MySQL, Valkey, ClickHouse, or Kafka without operating that service on the same VM, review [Managed Databases](/products/managed-databases). :::cta Explore Raff VM Deploy the API, automation service, or MCP endpoint on a cloud VM, then keep state, permissions, and private dependencies separated as the architecture grows. ::: ## Decision checklist Choose **MCP** if the main consumer is an AI client, tool discovery matters, and capabilities need a reusable AI-facing contract. Choose **n8n** if the process is workflow-oriented, several systems need coordination, and triggers, branches, approvals, or execution history matter. Choose **direct API integration** if the behavior is core product logic, strict validation or transactions matter, or high throughput and low latency are important. Combine them when an AI client should trigger a controlled workflow, n8n needs to consume MCP tools, or one validated API should serve product, workflow, and AI callers. :::cluster ## Frequently asked questions ### What is the difference between MCP and n8n? MCP is a protocol for exposing tools and context to AI applications. n8n is a workflow automation platform. Current n8n releases can also act as an MCP client or expose selected capabilities through MCP. ### Is n8n an MCP server? n8n itself is broader than an MCP server, but current n8n documentation includes MCP Server Trigger and instance-level MCP server functionality. ### Does n8n support MCP clients? Yes. Current n8n documentation includes MCP Client and MCP Client Tool functionality. ### Does MCP replace APIs? No. MCP servers often wrap APIs, SDKs, databases, workflows, or application functions. The underlying API should usually remain responsible for business validation, authorization, and state changes. ### What is the difference between MCP and an API? An API is a general software interface for applications and services. MCP is a protocol designed to make selected tools and context discoverable and usable by MCP-compatible AI clients. ### Should I use n8n or direct API code? Use n8n for visible orchestration across systems when the workflow is not a core product invariant. Use direct API code for strict transactions, high throughput, low latency, complex domain validation, and customer-facing product logic. ### Can n8n and MCP work together? Yes. An MCP client can invoke an n8n-exposed capability, and n8n can consume external MCP tools. ### Is MCP an AI agent framework? No. MCP defines how clients and servers exchange tool and context capabilities. It does not define the model's reasoning loop or business process. ### Which layer should own business rules? Core business validation should normally live in the authoritative API or service. n8n can orchestrate around it and MCP can expose a bounded AI-facing interface. ### Can Raff host n8n, MCP servers, and APIs? Yes. Self-hosted n8n, API services, and remote MCP services can run on Raff Cloud Servers. Application services may also fit Raff Apps, while VPC can keep supporting services on private network paths. ## Conclusion MCP, n8n, and direct APIs do not need to compete for the same responsibility. Use **direct APIs** to own durable application capabilities and business rules. Use **n8n** when a repeatable workflow must coordinate several systems. Use **MCP** when AI clients need a standardized, permission-limited way to discover and invoke selected capabilities. The current n8n platform can itself participate on both sides of MCP, which makes the distinction more architectural than product-versus-protocol. The cleanest production design still keeps authoritative validation and state changes in the appropriate backend service, then lets n8n and MCP connect to that boundary. ## Sources - [Model Context Protocol — 2026-07-28 Specification](https://blog.modelcontextprotocol.io/posts/2026-07-28/) - [n8n Documentation](https://docs.n8n.io/) - [Raff Cloud Servers](/products/raff-vm) - [Raff Apps](/products/app-platform) - [Raff VPC](/products/vpc) --- ### Secure Remote Access for MSPs: Bastion, VPN, or Zero Trust URL: https://rafftechnologies.com/learn/guides/secure-remote-access-for-msps-bastion-vpn-zero-trust Description: Secure remote access for MSPs using bastions, VPNs, zero-trust access, client isolation, RDP/SSH controls, technician offboarding, logging, and Raff VPC. Secure remote access for MSPs is the controlled way technicians reach client servers, private networks, databases, dashboards, and management systems without receiving permanent, unrestricted access across every customer environment. **Use a bastion when technicians mainly need controlled SSH or RDP access to private servers. Use a VPN or private-access gateway when they need several internal protocols or services. Use identity-aware zero-trust access when permissions must be tied more narrowly to a specific technician, device, resource, client, or time window.** For Raff Technologies customers and MSPs, the important design question is not simply which tunnel or gateway to deploy. It is whether the provider can explain **which technician can reach which client resource, through which path, for how long, and how that access is removed without affecting other customers**. This guide focuses on privileged infrastructure access rather than end-user remote-support software or RMM. For the simpler infrastructure comparison, see [Bastion Host vs VPN vs Public SSH](/learn/guides/bastion-host-vs-vpn-vs-public-ssh). ## Secure remote access for MSPs: quick decision | Access model | Best fit | Main advantage | Main risk | |---|---|---|---| | Restricted public SSH/RDP | Very small or temporary environments | Lowest setup burden | Management endpoints remain internet-routable | | Bastion host | Focused SSH/RDP access to private servers | Centralizes the admin entry path | Bastion becomes a privileged shared dependency | | VPN/private-access gateway | Several private protocols and resources | Practical network-level access | Reachability can become broader than the task | | Zero-trust / identity-aware access | Many technicians, contractors, or client-specific policies | Narrower resource- and identity-level policy | More identity and policy lifecycle work | | Dedicated client access plane | High-risk or contractually isolated customers | Strongest customer separation | Higher operational cost and duplication | A useful rule is: > **Give each technician the minimum client access required, for the minimum time required, through a path that can be attributed, reviewed, and revoked.** ## MSP remote access starts with the customer boundary An MSP crosses more trust boundaries than an internal infrastructure team. One technician may support several customers. A contractor may need one migration server for two days. Another customer may require a dedicated administrative path, separate credentials, or explicit approval before production access. The customer boundary therefore comes first: ```text Named MSP technician ↓ approved identity Controlled access path ↓ client-specific permission Client VPC / private network ↓ target-level authorization Approved server or service ``` Client environments should not become mutually reachable merely because the same MSP manages them. Avoid designs where: - one VPN profile reaches every customer; - one shared SSH key works across several tenants; - one Administrator password is reused across Windows servers; - one bastion has unrestricted routes into every client network; - one automation token can modify unrelated customer resources. For the network-separation side of the design, use [Private Cloud Networking for MSPs](/learn/guides/private-cloud-networking-for-msps). ## Bastion hosts fit focused server administration A bastion host is a controlled entry point used to reach private servers. ```text Technician ↓ restricted access Bastion ↓ private client network Approved Linux or Windows server ``` A bastion fits when: - technicians mainly need SSH or RDP; - target servers should not expose administration publicly; - the MSP wants a small number of controlled entry points; - broad network access is unnecessary; - technician activity needs to be easier to attribute and review. The benefit is reduced direct exposure. The trade-off is concentration of privilege. A shared bastion with routes to every customer can become a large cross-client failure domain. Reduce that risk with: - client-scoped routes; - named technician identities; - separate credentials per customer; - no universal private key stored on the bastion; - firewall rules that permit only required targets and ports; - separate bastions for customers that require stronger isolation. A bastion should also remain intentionally narrow. Do not turn the privileged entry host into a file server, CI runner, application host, or shared database server. ## VPN access fits mixed protocols and several private resources A VPN or private-access gateway is usually more practical when technicians need more than one management protocol. Typical MSP use cases include: - Windows RDP; - Linux SSH; - database administration; - private monitoring dashboards; - backup systems; - internal web applications; - several servers inside one customer network. ```text Technician device ↓ authenticated VPN/private access Client network ├─ RDP → Windows VM ├─ SSH → Linux VM ├─ DB client → database └─ HTTPS → internal dashboard ``` A VPN creates reachability. It does **not** automatically create least privilege. Control the scope with: - client-specific routes or gateways; - named users or peer identities; - MFA where supported by the selected access layer; - target-level firewall rules; - separate production and non-production routes; - explicit contractor expiry; - recurring access reviews. Avoid a flat MSP VPN where every authenticated technician can route to every customer environment. For some customers a VPN can replace the need for a bastion. For higher-control environments, the two can coexist: the VPN provides entry to the client network, while a bastion remains the narrower privileged path to production servers. ## Zero-trust remote access narrows authorization Zero trust does not mean “no VPN.” It means a user or device is not trusted merely because it joined a particular network. For MSP administration, a zero-trust or identity-aware access policy can express narrower decisions such as: ```text Technician A → Client A production bastion Technician B → Client B monitoring dashboard Contractor C → one migration VM until Friday ``` instead of: ```text Connected technician → entire MSP management network ``` **Zero-trust remote access** is useful when: - many technicians support different customer groups; - contractors receive short-lived access; - access should vary by client and resource; - device identity or posture matters; - approval or expiry is important; - audit evidence is a customer requirement. It does not make VPCs, VPNs, bastions, firewalls, or operating-system permissions obsolete. It adds a narrower authorization layer. The operational cost is policy ownership. Stale identity-aware policies can become just as permissive as a flat VPN if nobody removes old users, customer assignments, device records, or exceptions. ## Bastion vs VPN vs zero trust for MSPs The three models are often complementary rather than mutually exclusive. | Requirement | Bastion | VPN | Zero-trust / identity-aware layer | |---|---:|---:|---:| | Mainly SSH/RDP | Strong | Strong | Strong | | Several private protocols | Limited | Strong | Depends on implementation | | Keep target servers private | Yes | Yes | Yes | | Resource-specific authorization | Moderate | Needs target controls | Strong | | Contractor expiry | Manual or external identity | Manual or identity-backed | Strong fit | | Client-specific segmentation | Routes/firewall | Routes/firewall | Policy + network controls | | Simple small-team operation | Strong | Strong | More operational overhead | Do not select a technology based only on the security label. Select the smallest access architecture that supports the customer's risk, protocols, technician model, and evidence requirements. ## Windows and RDP deserve a stricter MSP model MSPs frequently manage Windows workloads where RDP is part of daily administration or where customers run business software, IIS, databases, or remote desktop workloads. For production Windows access, prefer: - private or tightly source-restricted RDP reachability; - named technician accounts; - strong credentials; - Network Level Authentication where supported; - limited local Administrators membership; - current Windows security updates; - MFA at the VPN, gateway, or identity layer where available; - removal of technician accounts when support responsibility ends. Do not use one shared Administrator credential across several customers simply because it simplifies support. Raff [Windows VM](/products/windows-vm) can host Windows Server workloads, while [VPC](/products/vpc) can keep supporting services and administrative traffic on private network paths where public exposure is unnecessary. For the broader public-versus-private decision, use [Private vs Public Admin Access](/learn/guides/private-vs-public-admin-access). ## SSH access should be attributable to a technician For Linux environments, every trusted SSH key should have a known owner and current purpose. Avoid: - one private key copied across the MSP team; - customer servers that still trust keys belonging to former staff; - direct root access that bypasses named users; - unrestricted SSH from the entire internet when a narrower path is practical. Prefer named users, individual keys, target-level privilege control, and clear removal when the technician no longer supports that client. Use [User Access Review for Cloud Servers](/learn/guides/cloud-access-reviews-small-teams-ssh-admin-permissions) to keep human and machine access current after deployment. ## Network reachability and authorization are separate controls A common MSP mistake is assuming that reaching the client network means the technician is authorized for every resource inside it. Use separate controls for: - entering the network; - reaching a target server; - authenticating to that server; - becoming root or Administrator; - accessing a database; - deleting backups or recovery points; - changing firewalls or routes. For example: ```text VPN membership ≠ access to every client subnet ≠ SSH/RDP authorization ≠ sudo/Administrator privilege ≠ backup deletion permission ``` This separation reduces the blast radius of one compromised technician identity. Use [Cloud Firewall Best Practices](/learn/guides/firewall-best-practices-cloud-servers) for inbound and outbound rule design. ## Joiners, movers, and leavers determine whether the model stays secure The connection technology matters less if identity lifecycle is weak. ### Joiners When a technician joins: - create an individual identity; - assign only approved customer groups; - separate human and machine credentials; - record an access owner; - require the approved authentication method. ### Movers When responsibilities change: - remove obsolete client assignments; - add new access through the normal approval path; - review stored credentials and devices; - confirm automation is not tied to the person's identity. ### Leavers When a technician or contractor leaves: - disable central identity access; - revoke VPN and bastion membership; - remove SSH keys and certificates; - remove Windows/RDP accounts; - rotate shared credentials they knew; - invalidate sessions where the tooling supports it; - verify access per client, not only at the central MSP layer. Temporary access should receive an expiry condition when it is granted. A migration permission without an end date is likely to become standing privilege. ## MSP remote-access logging should answer a client question A useful audit trail should help answer: > **Who reached which customer resource, when, through which access path, and what privileged action followed?** Depending on the architecture, evidence may come from: - VPN or gateway logs; - bastion authentication logs; - Linux SSH and sudo logs; - Windows security events; - firewall and route changes; - cloud API activity; - database audit logs; - backup restore or deletion records; - incident tickets. Logs should support a review process rather than becoming an archive that nobody can interpret. ## Break-glass access should survive gateway failure Private-access architectures introduce dependencies. A VPN, bastion, route, identity service, firewall rule, or DNS record can fail at exactly the time the MSP needs production access. Define a break-glass path before the incident. It should document: 1. who can authorize emergency access; 2. where the recovery credential or procedure is protected; 3. which customer resources can be reached; 4. which emergency actions are permitted; 5. how use is recorded; 6. how emergency credentials are rotated afterward; 7. how the normal access path is restored. If technicians routinely use break-glass access because it is easier than the primary path, redesign the primary path. ## Recovery access should not inherit everyday admin scope The ability to administer a server does not automatically require the ability to delete its recovery points. For important customers, review separately who can: - create snapshots; - restore backups; - change retention; - delete recovery points; - access application-level backup exports. This helps prevent one compromised technician identity from removing both production and recovery. Use [Cloud Snapshots vs Backups](/learn/guides/snapshots-vs-backups-cloud-server) for the recovery-model decision. ## How Raff maps to MSP remote-access architecture Raff provides infrastructure building blocks that can support client-separated administration: - [Raff Cloud Servers](/products/raff-vm) for Linux workloads, gateways, bastions, and supporting services; - [Windows VM](/products/windows-vm) for Windows Server and RDP-based workloads; - [VPC](/products/vpc) for private service-to-service and administrative traffic; - [IAM](/products/iam) for Raff's current identity and access product surface; - [Security](/products/security) for the current security product path; - [Site-to-Site VPN](/products/site-to-site-vpn) when an office or approved network needs a private tunnel into cloud resources; - [Data Protection](/products/data-protection) for snapshots and automated backup workflows. Current Raff VPC traffic is **private and unmetered**, and VPC itself does not carry a separate VPC charge. Raff VM public traffic currently uses a **3 Gbps connection with unmetered VM traffic and no VM egress fee**. Current network pricing also includes a **VPN gateway at $15/month for up to 10 peers** and **Site-to-Site VPN at $20/month per tunnel**. Check the live [pricing page](/pricing) before relying on a commercial value because product pricing can change. A practical client-specific design can look like: ```text Named MSP technician ↓ approved VPN / bastion / identity-aware access Client-specific Raff VPC ↓ explicit target rules Linux VM / Windows VM / private service ``` Raff provides the infrastructure boundary. The MSP still owns technician identity, customer-specific permission design, operating-system accounts, access reviews, logging, credential lifecycle, and offboarding. :::cta Explore Raff VPC Build private client network boundaries and keep administrative access scoped to the technicians and resources that actually need it. ::: ## MSP secure remote access checklist ### Customer separation - [ ] Each client has a defined administrative boundary. - [ ] One technician session does not automatically reach unrelated customers. - [ ] Shared credentials are not reused across clients. - [ ] Routes and firewall rules are customer-scoped. ### Technician access - [ ] Human access uses named identities. - [ ] SSH keys and Windows accounts have known owners. - [ ] Contractor access has an expiry condition. - [ ] MFA is used at the selected access layer where supported. ### Privilege - [ ] Network reachability is separate from server authorization. - [ ] RDP access does not automatically imply local Administrator rights. - [ ] Backup deletion and other high-impact permissions are reviewed separately. ### Operations - [ ] Access logs can be tied to a client and technician. - [ ] Offboarding removes access across all relevant clients. - [ ] Break-glass access is documented and tested. - [ ] The access model is reviewed when the customer or MSP team changes. :::cluster ## Frequently asked questions ### What is secure remote access for MSPs? Secure remote access for MSPs is the controlled way named technicians reach client servers and private services through client-specific, least-privilege, reviewable access paths. ### When should an MSP use a bastion host? Use a bastion when technicians mainly need SSH or RDP access to several private servers and broad network access is unnecessary. ### When should an MSP use a VPN? Use a VPN or private-access gateway when technicians need several internal protocols or resources such as SSH, RDP, databases, dashboards, and monitoring systems. ### What is zero-trust remote access? Zero-trust remote access evaluates access based on identity, resource, policy, and context instead of trusting a technician simply because they joined a private network. ### Does zero trust replace VPNs and bastion hosts? No. Identity-aware access can work alongside VPCs, VPNs, bastions, firewalls, and target-system permissions. It narrows authorization rather than replacing every network control. ### Should one MSP VPN connect every technician to every client? Usually no. A flat cross-client VPN creates unnecessary blast radius. Prefer client-specific routes, groups, gateways, or dedicated access planes according to customer risk. ### Should every MSP technician have permanent access to every customer? No. Access should be assigned according to customer, role, resource, and time. Temporary permissions should have an explicit expiry or review condition. ### How should MSPs secure RDP access? Prefer private or tightly restricted reachability, named accounts, Network Level Authentication where supported, current Windows updates, least privilege, and MFA at the access layer where available. ### What should MSP remote-access logs show? Where the tooling supports it, evidence should identify the technician, customer, target resource, connection time, authentication result, and significant privileged actions. ### How does Raff support MSP remote-access architecture? Raff Cloud Servers, Windows VM, VPC, IAM, Security, Site-to-Site VPN, and Data Protection provide compute, private networking, access, and recovery building blocks that an MSP can combine into customer-specific administrative boundaries. ## Conclusion Secure remote access for MSPs is less about choosing one universal technology and more about controlling customer boundaries, technician identity, reachability, privilege, and lifecycle together. Use a bastion for focused administration of private servers. Use a VPN when technicians need several internal protocols or services. Add identity-aware zero-trust controls when permissions must be more resource-specific or temporary. Use dedicated client access planes when risk or contractual requirements justify stronger isolation. Whatever model you choose, keep customer environments separated, use named identities, review access regularly, remove leavers immediately, and maintain a break-glass recovery path that does not become the normal way technicians work. ## Sources - [NIST SP 800-207: Zero Trust Architecture](https://csrc.nist.gov/pubs/sp/800/207/final) - [CISA: Require Multifactor Authentication](https://www.cisa.gov/audiences/small-and-medium-businesses/secure-your-business/require-multifactor-authentication) - [Raff VPC](/products/vpc) - [Raff IAM](/products/iam) - [Raff Security](/products/security) - [Raff Site-to-Site VPN](/products/site-to-site-vpn) - [Raff Windows VM](/products/windows-vm) - [Raff Pricing](/pricing) --- ### Cloud-Init vs Custom Images vs One-Click Apps URL: https://rafftechnologies.com/learn/guides/vm-provisioning-models-cloud-init-custom-images-one-click Description: Compare cloud-init, custom images, and one-click apps for VM and server provisioning, including first-boot automation, image lifecycle, security, replacement, and recovery. Cloud-init, custom images, and one-click apps are three ways to turn a new virtual machine into a usable server, but they move provisioning work to different stages of the VM lifecycle. **Use cloud-init when configuration must be decided at first boot. Use a custom image when many VMs should start from the same tested baseline. Use a one-click app when a prepared application template saves more time than controlling every installation decision. Production teams often combine these models instead of choosing only one.** For Raff Technologies workloads, the provisioning model affects replacement speed, configuration drift, patching, security, recovery, and how confidently a team can recreate a server after failure. A useful rule is: > **Put slow-changing common state in the image, instance-specific state in first-boot automation, ongoing host policy in configuration management, and application releases in CI/CD.** ## Cloud-init vs custom images vs one-click apps: quick comparison | Model | Best fit | Main strength | Main trade-off | |---|---|---|---| | Cloud-init | Instance-specific first-boot configuration | Flexible launch-time values | Boot-time dependencies and failure risk | | Custom image | Repeated stable VM baselines | Fast, consistent starting state | Rebuild, patching, and image hygiene | | One-click app | Common applications and stacks | Fastest path to a usable starting point | Opinionated defaults and less installation control | | Hybrid | Production fleets and repeatable environments | Separates stable and dynamic state | More than one lifecycle to maintain | Choose **cloud-init** when configuration differs by instance or environment. Choose a **custom image** when the same operating-system, runtime, security, or dependency baseline will be reused many times. Choose a **one-click app** when a maintained template closely matches the workload and the team accepts its defaults. Choose a **hybrid model** when the baseline, instance identity, host configuration, and application release change at different speeds. ## What is VM provisioning? **VM provisioning is the workflow that turns a newly created virtual machine into a server that is ready for its intended role.** Creating the VM is only the first step. A complete provisioning workflow may also establish: - operating-system image; - users and SSH access; - hostname and machine identity; - security updates; - packages and runtimes; - firewall rules; - network attachment; - application dependencies; - configuration files; - monitoring and logging; - application deployment; - readiness checks; - recovery configuration. A useful lifecycle is: ```text VM creation ↓ Base image ↓ First-boot bootstrap ↓ Host configuration ↓ Application deployment ↓ Readiness verification ↓ Production traffic ``` The strongest server-provisioning workflows make each stage observable. A VM being powered on should not automatically mean it is ready for users. ## A provisioning workflow should separate stable and changing state Different parts of a server change at different rates. | Layer | Typical responsibility | Change rate | |---|---|---| | Base image | OS, common packages, stable security baseline | Slow | | First boot | Hostname, SSH keys, registration, environment values | Per VM | | Host configuration | Ongoing packages, policy, agents | Periodic | | Application deployment | Application version | Frequent | | Persistent data | Database, uploads, business state | Continuous | Trying to put every responsibility into one layer creates coupling. For example, rebuilding an entire machine image for every application release may be unnecessary when the application changes daily and the operating-system baseline changes monthly. Conversely, installing a large runtime and dozens of packages on every first boot can make replacement slow and fragile when those components rarely change. The provisioning model should match the lifecycle of the state it owns. ## Cloud-init handles first-boot configuration Cloud-init is a Linux initialization system widely used by cloud images. It reads instance metadata and user data, then performs supported initialization tasks during boot. Typical cloud-init tasks include: - creating users; - adding SSH keys; - setting hostnames; - installing packages; - writing configuration files; - running bootstrap commands; - configuring supported storage or networking; - registering the VM with another system. A small example looks like this: ```yaml #cloud-config package_update: true packages: - nginx - git users: - name: deploy groups: sudo shell: /bin/bash sudo: ALL=(ALL) NOPASSWD:ALL ssh_authorized_keys: - ssh-ed25519 AAAA...example write_files: - path: /etc/nginx/conf.d/health.conf permissions: '0644' content: | server { listen 80; server_name _; location /health { return 200 'ok'; } } runcmd: - nginx -t - systemctl enable --now nginx ``` The exact modules and metadata sources available depend on the image and cloud platform. ## When cloud-init is the right choice Cloud-init works best when configuration becomes known at launch time. Examples include: - per-instance hostname; - deployment SSH key; - environment identifier; - monitoring registration; - a small package set; - bootstrap configuration; - a pointer to a versioned deployment artifact; - registration with a configuration-management system. Because cloud-init configuration is text, it can be versioned, reviewed, generated, and tested alongside infrastructure automation. It is especially useful when two VMs share the same base image but need different identities or environment-specific values. ## Cloud-init should not become the entire deployment platform Cloud-init is primarily a bootstrap layer, not a complete ongoing configuration-management system. A large first-boot script can depend on: - package mirrors; - DNS; - Git repositories; - external APIs; - secret stores; - license servers; - container registries. Every dependency creates another way for the server to become partially configured. Prefer a small bootstrap that establishes a known first state and then hands responsibility to the next layer. A practical sequence is: 1. establish identity and access; 2. install or enable the minimum bootstrap dependencies; 3. retrieve a versioned configuration or artifact; 4. register the machine with monitoring/configuration systems; 5. expose a readiness signal only after required services succeed. Use Ansible, another configuration-management system, a deployment pipeline, containers, or application-specific tooling for ongoing changes when those are better fits. ## Make first-boot automation idempotent and observable An idempotent task can be run again without creating duplicate or conflicting state. For example: - create a user only if it does not exist; - install a package only when required; - replace a configuration file deterministically; - enable a service rather than starting duplicate processes; - validate configuration before restart. Cloud-init failures should also be visible. Common Linux diagnostic files include: ```text /var/log/cloud-init.log /var/log/cloud-init-output.log ``` Exact locations can vary by distribution. Track provisioning completion separately from VM power state. A deployment gate or health check should confirm that the server is actually ready. ## Keep secrets out of reusable cloud-init data Do not treat user data as a permanent secret store. Depending on the platform and workflow, bootstrap data may appear in metadata, logs, automation history, support workflows, or copied configuration. Prefer: - short-lived credentials; - secret retrieval after identity is established; - scoped tokens; - deployment-time injection; - rotation after bootstrap when appropriate. Avoid placing reusable production passwords, private keys, or long-lived API credentials directly into templates that may be copied across servers. ## Custom images provide a reusable VM baseline A **custom image** is a prepared machine image that can be used as the starting point for new VMs. A custom image may contain: - operating-system updates; - approved packages; - language runtimes; - container runtime; - monitoring agents; - standard service definitions; - security configuration; - common application dependencies. Instead of downloading and configuring all of that during every boot, the VM starts from an artifact that has already been built and tested. This makes custom images useful for: - application fleets; - worker nodes; - CI/CD runners; - standardized developer environments; - replacement servers; - hardened baselines; - repeatable MSP/customer templates. ## Custom images trade boot work for image lifecycle work A custom image can make server provisioning faster and more consistent, but the work does not disappear. It moves into the image pipeline. An image needs: - a reproducible build definition; - patching policy; - version identifier; - automated or repeatable tests; - retirement policy; - rollback history where appropriate. Treat images as immutable artifacts. Build a new version instead of manually modifying an old image and continuing to use the same identity. For example: ```text web-base-2026-08-15 web-base-2026-09-01 web-base-2026-09-12 ``` A reproducible image pipeline can look like: ```text Current base OS ↓ Versioned build definition ↓ Packages + hardening ↓ Automated validation ↓ Reusable image ↓ Staging VM ↓ Approved production baseline ``` The tool can be Packer, scripts, API automation, or another build system. The important requirement is that the image can be recreated without undocumented manual changes. ## Custom-image hygiene prevents cloned identity and secrets Capturing a running server without preparation can clone state that should be unique. Before finalizing a reusable image, review: 1. **Secrets** — remove API keys, passwords, private certificates, tokens, and environment files that should not be cloned. 2. **SSH host keys** — regenerate per machine where the OS workflow requires it. 3. **Machine identity** — clear or regenerate machine-specific identifiers through the supported OS process. 4. **Cloud-init state** — clean prior instance state if cloud-init should run on the next VM. 5. **Logs and shell history** — remove operational or sensitive history that does not belong in the artifact. 6. **Network state** — remove static addresses, leases, or configuration that should not be duplicated. 7. **Monitoring identity** — make sure every new VM registers as a distinct node. 8. **Temporary build files** — remove caches and artifacts not needed at runtime. 9. **Patch state** — record and test the intended software baseline. 10. **Image metadata** — document version, build source, intended workload, and retirement criteria. Do not delete identity files blindly. Use the distribution's documented image-preparation process. ## Rebuild custom images instead of patching them forever An image captures the software state from the time it was built. If the image is never rebuilt, every new VM can recreate old vulnerabilities and obsolete packages very efficiently. A mature workflow therefore decides: - what event triggers a rebuild; - how security updates are incorporated; - how the image is tested; - how old versions are retired; - how quickly a new baseline can replace an affected image. Rebuild cadence should follow operational risk and the software lifecycle rather than an arbitrary calendar rule. ## One-click apps are prepared starting points A **one-click app** is a provider-maintained image or deployment template that starts with a common application or stack already prepared. Typical categories can include: - CMS platforms; - automation tools; - developer stacks; - container platforms; - control panels; - self-hosted applications. One-click apps reduce initial installation work, but **preinstalled does not mean fully managed**. The user may still own: - OS updates; - application updates; - credentials; - domain and TLS configuration; - firewall policy; - backups; - monitoring; - plugins/extensions; - migration; - application security. Use one-click apps when the template's architecture matches the workload well enough that maintaining a separate installation process does not create meaningful value. ## Review one-click templates before production use A template may make decisions about: - directory layout; - containers; - database placement; - exposed ports; - administrative access; - update behavior; - persistence; - TLS setup. Review those assumptions before placing customer data or production traffic on the instance. Also verify the application and operating-system version. A fast deployment is useful only if the resulting stack is current and maintainable. ## Cloud-init vs custom image: use lifecycle, not ideology The choice becomes clearer when you classify state by how often it changes. | Requirement | Cloud-init | Custom image | |---|---|---| | Per-instance hostname | Strong fit | Poor fit | | Per-instance SSH access | Strong fit | Avoid embedding personal keys | | Large stable runtime | Possible but slow | Strong fit | | Security baseline | Possible | Strong fit when rebuilt/tested | | Dynamic environment values | Strong fit | Poor fit | | Fast replacement | Depends on boot work | Strong fit | | Ongoing application release | Weak fit | Usually separate from both | The hybrid pattern is often strongest: ```text Reusable image ↓ stable OS/runtime/security baseline Cloud-init ↓ identity + environment-specific bootstrap Configuration management ↓ ongoing host policy CI/CD ↓ application version ``` This keeps each release cycle independent. ## Snapshot vs custom image: they solve different problems A snapshot is primarily a point-in-time recovery mechanism. A reusable custom image is prepared for clean repeated provisioning. A snapshot may contain: - current machine identity; - current application state; - logs; - temporary files; - credentials; - workload-specific data. Those qualities can be desirable for recovery and undesirable for a reusable baseline. Do not assume that a recovery snapshot should be promoted directly into a long-lived server template without image hygiene and validation. Use [Cloud Snapshots vs Backups](/learn/guides/snapshots-vs-backups-cloud-server) for the recovery distinction. ## Provisioning and infrastructure as code are separate layers Infrastructure as code may define: - VM size; - operating-system or image selection; - network attachment; - storage; - firewall policy; - API-driven resource creation. Cloud-init or the image then configures the operating system **inside** the resource. CI/CD may deploy the application after that. Keeping those layers separate makes failures easier to diagnose: ```text Infrastructure creation failed? → resource/IaC layer VM exists but host is incomplete? → image/bootstrap/configuration layer Host is healthy but app is broken? → deployment/application layer ``` Read [Infrastructure Automation on Raff](/learn/guides/automation-infrastructure-as-code-raff) for the broader automation model. ## Provisioning across development, staging, and production Development, staging, and production can share a controlled baseline without sharing every credential or capacity decision. A useful pattern is: - same approved image family; - separate environment-specific bootstrap values; - separate credentials; - separate databases; - separate network rules; - different VM sizes where justified; - separate deployment approvals. This reduces environment drift while preserving the boundaries production needs. Read [Staging vs Production vs Development Environments](/learn/guides/dev-staging-production-cloud-environments) for the environment model. ## Provisioning should support replacement, not only creation The real test of a provisioning workflow is whether the team can replace a server reliably. A replacement test should answer: 1. Can a new VM be created from the intended image? 2. Does bootstrap complete without manual intervention? 3. Are unique identity and credentials generated correctly? 4. Does the server join the expected private network? 5. Do monitoring and logging identify it as a new instance? 6. Can the application deploy successfully? 7. Does the readiness check pass? 8. Can traffic be moved to the replacement safely? 9. Can the old VM be removed without losing persistent data? If replacement requires remembering undocumented shell commands, provisioning is not yet reproducible. ## Scaling makes provisioning quality more important A single manually maintained VM can hide inconsistent setup for a long time. Multi-node or autoscaled architectures expose it quickly. When application nodes are expected to be interchangeable, every replacement should receive the same baseline and become ready through the same observable workflow. Do not scale a provisioning script that is already unreliable. First make server creation deterministic, move persistent state out of disposable nodes where appropriate, and define readiness. Use [Cloud Autoscaling for VMs](/learn/guides/auto-scaling-vm-planning) and [Stateful vs Stateless Applications](/learn/guides/stateful-vs-stateless-applications) when the provisioning model will support several replaceable backends. ## Security responsibilities differ by provisioning model | Responsibility | Cloud-init | Custom image | One-click app | |---|---|---|---| | Baseline patching | Base image + bootstrap | Image rebuild | Verify template, then maintain | | Secret handling | Avoid reusable plaintext | Remove before capture | Rotate/review initial credentials | | Consistency | Depends on execution | High when versioned | Depends on template maintenance | | Ongoing changes | Separate process | Rebuild or config management | User/service-owner responsibility | | Failure evidence | Bootstrap logs/status | Image/version inventory | Template + application health | No provisioning model removes security ownership. ## How VM provisioning fits Raff today [Raff VM](/products/raff-vm) and [Linux VM](/products/linux-vm) provide the compute layer for repeatable server workflows. Raff's automation surface includes API-driven provisioning and cloud-init-based bootstrap workflows, while the VM platform also supports current system images and custom-image workflows. A practical Raff provisioning design can look like: ```text Raff VM / Linux VM ↓ Current OS or custom image ↓ Cloud-init bootstrap ↓ Host configuration ↓ CI/CD application release ↓ Readiness check ``` For internal application traffic, attach the required resources to [Raff VPC](/products/vpc). VPC traffic is **private and unmetered**, and VPC itself has no separate VPC charge. Use [Data Protection](/products/data-protection) for snapshots and automated backup recovery. Recovery copies are separate from a clean reusable image: their job is to protect recoverable state, not to define the server-provisioning baseline. For prebuilt application starting points, review the current [Raff Marketplace](/marketplace) and [App Platform](/products/app-platform) options. Treat a prepared application as managed only when the product explicitly includes that operational responsibility. Raff's current image catalog includes supported Linux distributions such as Ubuntu 24.04, Debian 13, Rocky Linux 9, AlmaLinux 9, CentOS Stream 9, Alpine 3.21, Fedora 42, and openSUSE 15, alongside FreeBSD 14 and custom-image options. Use the current dashboard when the exact available image version matters to automation. :::cta Deploy Your Server Start with a Raff VM and build a provisioning workflow that separates the image, first boot, application deployment, and recovery layers. ::: ## VM provisioning checklist ### Baseline - [ ] The operating-system/image source is documented. - [ ] Stable packages belong in a reproducible baseline. - [ ] Image versions have rebuild and retirement rules. ### First boot - [ ] Bootstrap logic is small enough to diagnose. - [ ] Tasks are idempotent where practical. - [ ] Long-lived secrets are not embedded in reusable user data. - [ ] Bootstrap completion is observable. ### Identity and security - [ ] SSH host identity and machine identity are unique. - [ ] Personal credentials are not baked into reusable images. - [ ] Monitoring agents register each VM separately. ### Application - [ ] Application releases are separated from slow-changing host state where practical. - [ ] Persistent business data survives server replacement. - [ ] Readiness is checked before production traffic arrives. ### Recovery - [ ] Snapshots/backups are treated separately from reusable images. - [ ] A replacement VM has been tested from a clean start. - [ ] Restore procedures cover persistent data, not only server configuration. :::cluster ## Frequently asked questions ### What is VM provisioning? VM provisioning is the workflow that turns a newly created virtual machine into a server ready for its role by applying the image, access, configuration, application setup, and readiness checks it needs. ### What is cloud-init used for? Cloud-init is primarily a first-boot initialization layer for tasks such as users, SSH access, hostnames, configuration files, small package sets, and bootstrap commands. ### Should I use cloud-init or a custom image? Use cloud-init for values that change per instance or environment. Use a custom image for a stable baseline reused across many VMs. Combine them when both needs exist. ### When should a team use custom VM images? Use custom images when many servers need the same tested OS, runtime, security, or dependency baseline and fast, consistent replacement matters. ### Is a snapshot the same as a custom image? No. A snapshot is primarily a recovery point and may contain machine-specific state. A reusable custom image should be prepared and sanitized for clean repeated provisioning. ### Are one-click apps fully managed? Not necessarily. A one-click app can provide a prepared starting point while application updates, backups, credentials, monitoring, networking, and security remain the user's responsibility. ### What is a server provisioning workflow? A server provisioning workflow usually creates the VM, selects a base image, applies first-boot configuration, establishes ongoing host state, deploys the application, and verifies readiness before production use. ### How do cloud-init and infrastructure as code work together? Infrastructure as code creates resources such as VMs, networks, and storage. Cloud-init configures supported operating-system state during first boot. Configuration management and CI/CD can then own ongoing host state and application releases. ### Does provisioning replace backups? No. Provisioning recreates infrastructure and configuration. Backups protect changing persistent data and historical recovery points. Production recovery usually requires both reproducible servers and protected data. ### How does Raff support VM provisioning? Raff VM and Linux VM provide current system and custom-image workflows, API-driven provisioning and cloud-init-based bootstrap options, while VPC, Data Protection, Marketplace, and App Platform cover related private networking, recovery, and application-starting-point needs. ## Conclusion Cloud-init, custom images, and one-click apps are not competing versions of the same feature. They place configuration work at different points in the VM lifecycle. Use cloud-init for instance-specific first-boot values. Use custom images for stable, repeatedly reused baselines. Use one-click apps when a prepared application template is a better starting point than maintaining the entire installation process yourself. For production systems, the strongest pattern is often hybrid: build a tested baseline, keep first-boot logic small, manage ongoing state separately, deploy applications through a repeatable release process, verify readiness before traffic arrives, and protect persistent data with a real recovery plan. ## Sources - [Cloud-init documentation](https://docs.cloud-init.io/) - [Raff VM](/products/raff-vm) - [Raff Linux VM](/products/linux-vm) - [Raff VPC](/products/vpc) - [Raff Data Protection](/products/data-protection) - [Raff Marketplace](/marketplace) --- ### VPS Setup Checklist: What to Configure After Deployment URL: https://rafftechnologies.com/learn/guides/first-cloud-server-after-provisioning Description: Use this VPS setup checklist after deployment to configure updates, SSH access, firewall rules, monitoring, backups, DNS, and recovery in the right order. A newly deployed VPS is not production-ready just because it is running. **Before you install an application, verify the server, apply updates, create a safer administrator account, configure SSH access and firewall rules, enable monitoring, and define a backup path.** This checklist explains the correct order and the decision behind each step without replacing the detailed setup tutorials. This guide focuses on the post-deployment checklist. Command-by-command Linux hardening remains in the linked tutorials. ## VPS setup checklist at a glance | Priority | Configuration area | Why it comes now | | --- | --- | --- | | 1 | Verify the deployed server | Confirms the image, resources, networking, and access path are correct | | 2 | Apply operating-system updates | Reduces exposure to already-patched vulnerabilities | | 3 | Create an administrative user | Limits routine use of the root account | | 4 | Configure SSH keys | Replaces password-only remote access with stronger authentication | | 5 | Review root and password login | Reduces unnecessary SSH attack paths after key access is proven | | 6 | Configure the firewall | Exposes only the services the workload needs | | 7 | Set automatic security updates | Keeps critical patches moving between maintenance windows | | 8 | Configure hostname, DNS, and time | Prevents service, certificate, logging, and monitoring confusion | | 9 | Enable monitoring and alerts | Detects resource pressure and service failure before users report it | | 10 | Configure backups and restore ownership | Creates a recovery path before production data appears | | 11 | Deploy the workload | Application installation begins only after the server baseline is ready | The exact implementation differs between Linux distributions and Windows Server. The operating principle is the same: verify first, reduce exposure, create visibility, and only then deploy the application. ## Verify the server before changing it Confirm that the VM matches the intended deployment before installing packages or copying data. Review: - operating system and version - kernel and architecture - assigned vCPU and memory - disk capacity and mounted filesystems - public and private IP addresses - DNS resolution - current time and time synchronization - console or recovery access A mismatch is easiest to correct while the server is empty. Also record how emergency access works before changing SSH or firewall settings. A browser-based console or recovery workflow is valuable when a remote-access rule is misconfigured. ## Apply operating-system and package updates Cloud images are maintained baselines, but packages can change between image creation and deployment. Apply available updates before building the application stack. On Ubuntu, package updates, security maintenance, and reboot requirements should follow the current Ubuntu Server documentation. A kernel or core library update may require a reboot before the running system uses the new version. Do not combine the first patch cycle with an application migration or major architecture change. Establish a clean server baseline first. For the exact Ubuntu commands, use [Secure an Ubuntu 24.04 Server](/learn/tutorials/secure-ubuntu-24-04-server). ## Create a non-root administrative account Use a named administrative account for normal operations and grant only the privileges required for the role. Direct root access may be available during provisioning, but it should not become the default operating habit. A named account improves accountability and reduces the chance that every command runs with unrestricted privileges. It does not eliminate risk: an account with unrestricted `sudo` can still gain full control. The value comes from clearer identity, controlled privilege escalation, and the ability to remove one person’s access without rotating a shared root workflow. For a team, avoid shared SSH credentials. Each administrator should use an individual key and an access-removal process. ## Configure SSH key authentication SSH keys are the preferred access method for Linux administration because they avoid password-only remote login and can be issued per person or automation workflow. The private key should remain on the administrator’s trusted device or approved credential system. Only the public key belongs on the server. Protect private keys with appropriate file permissions and, where practical, a passphrase or hardware-backed key. Test key-based access from a second terminal before changing password or root-login settings. Keep the current session open until the new path has been verified. Use [Set Up SSH Keys on Ubuntu 24.04](/learn/tutorials/set-up-ssh-keys-ubuntu-24-04) for the implementation steps. ## Decide how root and password login should work After key access for a named administrator has been tested, review whether direct root login and SSH password authentication are still required. A common production baseline is: - named user access - SSH keys for remote authentication - privilege escalation through `sudo` - direct root login restricted or disabled - password authentication restricted or disabled after testing This is not a universal rule. Break-glass access, configuration-management systems, compliance controls, and team maturity can change the design. The important point is to make the decision explicitly and preserve a tested recovery path. Never close the original session until the new SSH configuration has been tested. Remote-access mistakes are operational incidents, not only security issues. ## Configure a default-deny firewall policy A firewall should allow the minimum inbound access required by the workload. For a public web server, the initial inbound set may include: - the administrative SSH path - HTTP on port 80 - HTTPS on port 443 That does not mean every server should open all three ports. A database-only VM, internal worker, VPN endpoint, or private service needs a different policy. Databases, caches, queues, and administrative dashboards should normally use localhost, a private network, a VPN, a bastion path, or a restricted source range instead of broad public exposure. Allow the administrative path before enabling the firewall. Use [Set Up UFW on Ubuntu 24.04](/learn/tutorials/set-up-ufw-firewall-ubuntu-24-04) for Linux-specific commands and [Firewall Best Practices for Cloud Servers](/learn/guides/firewall-best-practices-cloud-servers) for the policy decision. ## Enable automatic security maintenance deliberately Automatic security updates reduce the time between a security fix becoming available and being installed. They should be configured with an explicit reboot and maintenance policy rather than enabled without operational planning. Decide: - which repositories and update classes are allowed automatically - whether automatic reboots are permitted - when reboots can occur - how failed updates are reported - which updates require staging validation Automatic security maintenance does not replace planned upgrades. Application dependencies, database changes, major distribution upgrades, and configuration changes still need testing and change control. ## Configure hostname, DNS, and time synchronization Server identity and time configuration affect more systems than expected. Set and verify: - a meaningful hostname - forward and reverse DNS where required - the correct time zone for operations - NTP or system time synchronization - DNS records used by the application Incorrect time can break certificate validation, authentication, distributed logs, scheduled tasks, database replication, and incident analysis. Incorrect hostname and DNS configuration can also create confusion in monitoring and automation. Do not point production DNS to the server before the application, TLS, firewall, and health checks are ready. ## Enable monitoring before production traffic A VPS needs both infrastructure visibility and service-level checks. Monitor at least: - CPU use and load - memory and swap - disk space and inode use - disk I/O pressure - network traffic and errors - service status - external application availability - certificate expiry - backup age and failure Resource graphs explain what the VM is doing. External health checks show whether users can reach the service. Application logs and error monitoring explain why the workload is failing. Set alerts with enough context to act. A dashboard that nobody reviews is not an operational control. Use [Cloud Server Monitoring Basics](/learn/guides/cloud-server-monitoring-basics) for the broader monitoring model. ## Define backups before data arrives Backup design should be in place before the server stores production data. Separate the layers: - **Infrastructure snapshot:** fast rollback before risky server changes - **Scheduled VM backup:** broader server recovery according to the selected retention - **Application or database backup:** recovery that understands the workload’s data format - **Off-server copy:** protection from server loss and some account or platform failures A snapshot is not automatically a complete database backup. A database dump is not automatically a complete server recovery plan. Use the mechanism that matches the failure mode. Document: - what is backed up - how often it runs - where copies are stored - who can delete them - how long they are retained - who owns restoration - when the last restore test succeeded Read [Snapshots vs Backups](/learn/guides/snapshots-vs-backups-cloud-server) for the infrastructure distinction. ## Review application and network exposure before deployment Before installing the workload, decide which services belong on the public internet and which should remain internal. A common small application may include: - public reverse proxy or load balancer - application process bound to localhost or a private interface - database reachable only through a private path - administrative access limited by key, source range, VPN, or bastion - backup destination outside the VM One-server deployments can still use clear boundaries. Do not expose a database publicly merely because the application and database share one VM. ## Linux and Windows setup paths are different This guide owns the decision sequence, not one operating system’s commands. For Linux, the work commonly includes SSH, `sudo`, package updates, UFW or another firewall, system services, logs, and unattended security updates. For Windows Server, the equivalent baseline includes administrator access, Windows Update, Remote Desktop policy, Windows Defender Firewall, account controls, monitoring, backup, and application-specific roles. Do not copy Linux controls into Windows terminology or assume a Windows VPS should expose RDP broadly without additional access controls. ## Decision framework: when is the VPS ready? A new VPS is ready for its first workload when the team can answer yes to the following: 1. Does the server match the intended image, region, and resource plan? 2. Are current security updates installed? 3. Is administrative access named, tested, and recoverable? 4. Are unnecessary password and root access paths restricted? 5. Does the firewall expose only required services? 6. Are time, hostname, and DNS correct? 7. Will the team be alerted about service failure, disk exhaustion, and backup failure? 8. Is there a documented backup and restore owner? 9. Are internal services kept off the public interface where practical? 10. Can the workload be rolled back or restored after a failed deployment? A server that is merely reachable is provisioned. A server that passes this checklist is ready to host a workload. :::cluster ## How this applies on Raff A [Raff Linux VM](/products/linux-vm) provides the server environment, operating-system choice, network access, and infrastructure controls needed to build this baseline. The customer still owns operating-system configuration, application security, patch policy, monitoring, and workload recovery unless a managed product explicitly transfers that responsibility. Use [Raff VPC](/products/vpc) when application, database, worker, and internal services should communicate without unnecessary public exposure. Use [Data Protection](/products/data-protection) for infrastructure backups and snapshots, then add application-aware backups where the workload requires them. The live [Raff pricing page](/pricing) should be used for current plan selection. This guide intentionally avoids historical plan prices and universal utilization thresholds because the correct VM size depends on the workload, software stack, traffic, and required headroom. ## Conclusion The correct VPS setup order is simple: verify the server, patch it, establish controlled administrative access, reduce network exposure, create monitoring and recovery, and then deploy the application. This page remains a checklist and decision guide. Use the linked tutorials for exact commands, and use [Choosing the Right VM Size](/learn/guides/choosing-right-vm-size) when capacity—not initial configuration—is the main question. :::cta Deploy Your Server Create a Raff VM, apply a secure baseline, and deploy only after access, monitoring, and recovery are ready. ::: ## Sources - [Ubuntu Server documentation: Security](https://documentation.ubuntu.com/server/explanation/security/) - [Ubuntu Server documentation: OpenSSH](https://documentation.ubuntu.com/server/how-to/security/openssh-server/) - [Ubuntu Server documentation: Automatic updates](https://documentation.ubuntu.com/server/how-to/software/automatic-updates/) - Date verified: 2026-07-29 --- ### Single VM vs Multi-VM Architecture for SaaS Apps URL: https://rafftechnologies.com/learn/guides/single-vm-vs-multi-vm-saas-architecture Description: Decide when a SaaS app should stay on one VM or separate its application, database, workers, files, cache, and traffic routing across multiple systems. A single-VM architecture runs the application and most supporting roles on one server. A multi-VM architecture separates roles such as the app, database, background workers, cache, storage, and traffic routing across independent systems. **Start with one VM when simplicity is the main requirement. Split roles when measurement shows that one shared failure domain, resource pool, deployment process, or recovery path has become unacceptable.** Multi-VM does not mean microservices or Kubernetes. A monolithic SaaS application can remain one codebase while its infrastructure is separated gradually. ## Single VM vs multi-VM architecture at a glance | Decision factor | Single VM | Multi-VM | |---|---|---| | Initial setup | Simpler | More components and networking | | Cost structure | One shared resource pool | Capacity purchased by role | | Deployment | One server may affect every role | Roles can be deployed independently | | Failure boundary | One host can affect the whole system | Failures can be isolated by role | | Scaling | Increase the whole VM | Scale selected roles independently | | Data recovery | App and data recovery may be coupled | Each stateful role can have its own recovery plan | | Observability | Fewer systems, but shared signals | Clearer role-level metrics with more tooling | | Best fit | Prototypes, internal tools, early production | Growing production workloads with measured separation needs | A useful rule is: > Keep one VM while its shared boundaries remain acceptable. Add another role only when you can name the risk, bottleneck, or operating constraint that the split removes. ## Use a six-part topology decision Before moving from one VM to several, review six questions: 1. **Capacity:** Which role is exhausting CPU, memory, storage, connections, or throughput? 2. **Failure isolation:** Which services should continue if one role fails or is restarted? 3. **Recovery:** Which data needs its own backup, restore, and recovery objective? 4. **Deployment:** Which roles need separate release or maintenance windows? 5. **State:** Which sessions, files, jobs, and records prevent an app node from being replaced? 6. **Operations:** Can the team monitor, secure, deploy, and recover the additional system? A split is justified when the operational benefit exceeds the additional network, monitoring, security, and recovery work. ## A single VM is a valid production starting point One VM can run a reverse proxy, web application, API, database, worker, cache, scheduled jobs, and monitoring for an early product. This topology is often appropriate when: - traffic and job volume are modest - brief maintenance downtime is acceptable - one team owns the complete workload - the database and files are still small enough to recover predictably - deployments are infrequent - app, worker, and database resource usage do not interfere materially - the product is still validating demand The value is operational clarity. There is one host to deploy, inspect, secure, back up, and pay for. The architecture should still be production-aware. Use separate processes, explicit service ownership, resource monitoring, restrictive firewall rules, documented backups, and a tested restore path. “Single VM” should not mean “undocumented server.” Use [Production VPS Checklist for SaaS Apps](/learn/guides/production-vps-checklist-saas-app) to review the production baseline before deciding whether more servers are needed. ## One VM becomes risky when unrelated roles share every boundary A single host couples several concerns: - CPU and memory - storage capacity and latency - operating-system maintenance - application deployment - network exposure - monitoring and logs - backup and restore - incident blast radius The architecture may still work under normal traffic while becoming hard to operate during failure or maintenance. Common warning signs include: - background jobs delay user requests - database activity competes with the application for memory or disk I/O - uploads or logs threaten database free space - one deployment restarts the app, workers, and scheduler together - a backup job causes noticeable production latency - every capacity increase requires resizing unrelated roles - an app-server rebuild also requires moving customer data or files - a restore would recover several unrelated services together - incidents are difficult to isolate because every signal comes from one host One warning does not require a complete redesign. It identifies the role that should be measured first. ## Diagnose the constraint before adding servers Multi-VM architecture does not automatically solve performance. If the database query plan is the bottleneck, adding app servers can increase pressure. If an external API controls request latency, separating workers will not remove that dependency. If the application leaks memory, a new topology may only spread the problem. Correlate user impact with: - request and job latency - error rate - CPU and memory pressure - disk latency and capacity - database query, lock, and connection behavior - queue age and depth - upload and processing volume - backup duration - deployment and restart impact Use [Cloud Server Performance Bottlenecks](/learn/guides/cloud-server-performance-bottlenecks-cpu-ram-disk-network) to find where work is waiting before changing the topology. ## Multi-VM architecture separates infrastructure roles Multi-VM means that roles run on separate VMs or suitable managed services. It does not require splitting the application code into microservices. ![Diagram comparing single VM SaaS architecture with multi-VM SaaS architecture](https://raff-images.s3.raffusercloud.com/single_vm_vs_multi_vm_comparison_diagram_webp_979f6a655a.png) A monolithic application might use: ```text Users ↓ Application VM ↓ private network Database ↓ Object storage and background workers ``` The app and workers may still run the same codebase with different commands. Infrastructure separation allows each role to have its own capacity, access, deployment, and recovery boundaries. ## Choose the first split from the evidence The database is a common first split because it owns durable business data, but it is not automatically first for every application. | Observed constraint | Likely first split | |---|---| | Database memory, storage, backup, or maintenance risk | Database | | CPU-heavy jobs delay web requests | Background workers | | Durable uploads block VM replacement or horizontal scaling | Object storage | | Cache or queue is critical and competes with the app | Cache or queue | | One app node cannot meet traffic or availability needs | Additional app nodes and load balancing | | Security policy requires separate access boundaries | Sensitive backend role | | App deployment must not affect scheduled jobs | Worker or scheduler | Select one change, migrate it safely, and confirm that the user-facing or operational result improves before continuing. ## Split the database when data needs an independent boundary Separate the database when its lifecycle no longer matches the application server. Useful triggers include: - database storage grows independently of application compute - backups or maintenance affect the application - the database needs stricter network and administrator access - the app VM should be replaceable without moving customer records - database memory and disk behavior require independent tuning - database recovery objectives differ from app-server recovery ```text Users ↓ Application VM ↓ private network Database VM or managed database ``` The split creates a clearer data boundary, but it also introduces network latency, credentials, connection management, and a second failure domain. Measure connection usage and query behavior after migration. Use [Separate App and Database Server](/learn/guides/separate-app-database-server) for the detailed decision. ## Move durable files away from replaceable compute Local application storage is simple on one VM, but it can block later scaling. When user uploads exist only on one app server: - another app node may not see the file - replacing the VM requires copying durable data - app-server backups grow with file volume - storage and compute cannot scale independently - failed uploads and partial processing are harder to reconcile A cleaner model is: ```text Application VM ↓ Database stores file metadata ↓ Object storage stores durable objects ``` Keep disposable temporary files local when bounded and safe to recreate. Move customer uploads, exports, media, and other durable objects to shared storage when they must survive app-node replacement. ## Separate workers when background work affects users Background jobs often have a different resource and failure profile from web traffic. Workers may process: - emails and notifications - reports and exports - imports - image or document processing - billing tasks - integration synchronization - scheduled cleanup A separate worker VM is justified when job execution consumes enough CPU, memory, database capacity, or deployment attention to affect the user-facing app. ```text Web or API VM ↓ Queue or job store ↓ Worker VM ``` The worker design must handle retries, duplicate execution, job ownership, and graceful shutdown. Adding workers without database and dependency headroom can create a new bottleneck. ## Separate cache or queue when it becomes critical state A small local cache may remain on one VM. A cache or queue deserves an independent boundary when its failure, memory usage, or restart behavior has meaningful product impact. Review: - whether the data is disposable or authoritative - whether several app and worker nodes need shared access - memory growth and eviction behavior - queue persistence and retry semantics - connection limits - recovery after restart Do not move a cache merely because a multi-server diagram includes one. Split it when the application needs independent scaling, shared access, or failure control. ## Add multiple app VMs only after externalizing state Horizontal app scaling requires requests to move safely between nodes. Before adding app servers, externalize or deliberately manage: - user sessions - uploaded files - background jobs - scheduled tasks - required cache state - configuration and secrets - application logs and metrics Microsoft’s scale-out guidance recommends avoiding instance stickiness and resolving backend bottlenecks before adding instances. AWS similarly recommends offloading state so servers can be replaced without availability impact. Use [Stateful vs Stateless Applications](/learn/guides/stateful-vs-stateless-applications) before adding a load balancer. ## Load balancing adds routing, not complete availability A load balancer can distribute new traffic and remove unhealthy app nodes from rotation. It does not automatically make the database, storage, DNS, application deployment, or load-balancer layer resilient. A multi-node app tier needs: - meaningful readiness checks - externalized state - connection draining - compatible deployments - enough remaining capacity after one node fails - shared observability - database connection planning ```text Users ↓ Load balancer ↓ App VM 1 App VM 2 ↓ private network Database, cache, queue, and storage ``` Use [Load Balancing Explained](/learn/guides/load-balancing-explained) for L4, L7, health-check, timeout, and failover decisions. ## More VMs do not automatically create high availability Role separation and redundancy are different architectural choices. A separate database VM isolates resources but remains one database node. Two app VMs improve the app tier only if traffic routing, state, and remaining capacity are designed correctly. Several roles may still depend on one network, credential, deployment pipeline, or storage system. Review each failure domain: - app node - worker - database - queue or cache - object storage - load balancer - DNS - external dependencies - shared configuration and secrets Multi-VM architecture improves isolation when boundaries are intentional. It can also create more failure modes when ownership and recovery are unclear. ## Compare cost by role and risk A multi-VM design has a higher visible infrastructure cost, but it may avoid scaling every role together. On one VM, a worker CPU spike can force a larger plan for the app, database, and cache at the same time. After separation, worker capacity can change without resizing the database. The reverse can also be true: several lightly used VMs may cost more and create unnecessary operations. Evaluate: - infrastructure spend by role - expected downtime cost - recovery time - engineering and on-call time - deployment risk - unused capacity - monitoring and tooling overhead Use current product and pricing pages during implementation rather than embedding temporary plan prices in an evergreen architecture decision. ## A staged SaaS topology path The architecture should evolve one justified boundary at a time. ![Raff SaaS architecture path from one VM to managed database, object storage, workers, and load balancing](https://raff-images.s3.raffusercloud.com/raff_saas_architecture_scaling_path_webp_b9ede7d183.png) ### Stage 1: One VM ```text Application + database + worker + cache ``` Priorities: - production baseline - monitoring - backup and restore - clear service ownership - documented separation triggers ### Stage 2: Separate the most valuable boundary This may be the database, worker, files, or another role according to measured risk. ```text Application VM ↓ Separated role ``` ### Stage 3: Externalize durable and shared state Move sessions, files, jobs, and other state that would prevent application-node replacement. ### Stage 4: Add independent capacity Scale the database, workers, or other role according to its own workload. ### Stage 5: Add multiple app nodes Introduce load balancing when traffic, deployment safety, maintenance, or app-tier availability requires more than one node. The next stage should solve a current constraint. It should not exist only because the diagram looks more mature. ## Private networking becomes important after separation Once services are separated, internal traffic should use controlled private paths where available. Raff VPC can connect VMs and supported managed services through private networking. A common topology is: ```text Public internet ↓ Load balancer or application entry point ↓ private network Application, database, workers, cache, and internal services ``` Private networking reduces unnecessary public exposure, but it does not replace firewall rules, authentication, encryption, database permissions, or application security. ## Use a migration plan for every split A role split should have a defined sequence: 1. Measure the existing workload and define success. 2. Create the new role and restrict access. 3. Configure monitoring, backups, and ownership. 4. Synchronize or migrate state where required. 5. Test with production-like behavior. 6. Cut traffic or processing over deliberately. 7. Observe latency, errors, resource use, and recovery signals. 8. Keep a rollback path until the result is stable. 9. Remove obsolete data, credentials, rules, and services. Do not split several stateful roles in one change unless the migration requires it. Smaller changes make cause and rollback clearer. ## Single VM vs multi-VM decision matrix | Evidence | Better next move | |---|---| | No measured contention or recovery problem | Keep one VM | | One resource is constrained but roles remain compatible | Resize vertically | | Database needs independent recovery or tuning | Separate database | | Workers affect user-facing latency | Separate workers | | Durable files block replacement | Move files to object storage | | App node must be replaceable | Externalize state | | One app node is the capacity boundary | Add app nodes and load balancing | | One app node is the availability boundary | Add redundancy and failure capacity | | Team cannot operate several roles safely | Improve automation and observability first | Use [Horizontal vs Vertical Scaling](/learn/guides/horizontal-vs-vertical-scaling-cloud) when the main decision is resize versus add instances. ## How this applies on Raff A Raff topology can combine: - [Raff Cloud Servers](/products/raff-vm) for application and worker roles - [Managed Databases](/products/managed-databases) when the database should have a separate managed boundary - [Object Storage](/products/object-storage) for durable shared files - a suitable traffic-distribution layer when several replaceable application nodes need to serve traffic; confirm current managed service availability before making it a dependency - [Raff VPC](/products/vpc) for controlled private communication - [Data Protection](/products/data-protection) according to recovery needs Choose only the components the workload currently needs. Verify current capabilities and pricing on the live product pages before implementation. ## Pre-split checklist ### Evidence - The current bottleneck or risk is measured. - The role being separated has a clear owner and purpose. - Success criteria are defined. ### State and data - Durable data has an authoritative location. - Sessions, uploads, and jobs are mapped. - Backup and restore behavior is documented. ### Operations - Monitoring exists for the new role. - Access and private-network rules are defined. - Deployment and maintenance ownership are clear. - The team can diagnose cross-service failures. ### Migration - Data synchronization and cutover are planned. - Rollback is possible. - Obsolete services and credentials will be removed. - The architecture diagram and runbooks will be updated. :::cluster ## Conclusion Single-VM architecture is often the correct starting point for a SaaS application. Multi-VM architecture becomes valuable when one shared server creates unacceptable contention, failure exposure, deployment coupling, or recovery risk. Do not split every role at once. Identify the constraint, separate the role that removes it, validate the result, and keep the application model as simple as the product allows. A monolith can remain a monolith while its database, workers, files, and app tier gain clearer operational boundaries. The best topology is the smallest one that meets the workload’s current performance, reliability, security, and recovery requirements. :::cta Explore Raff VM Start with a clear cloud foundation, then separate roles as measured production needs emerge. ::: ## Sources - [Microsoft Azure Architecture Center: Design to Scale Out](https://learn.microsoft.com/en-us/azure/architecture/guide/design-principles/scale-out) - [Microsoft Azure Well-Architected Framework: Scaling and Partitioning](https://learn.microsoft.com/en-us/azure/well-architected/performance-efficiency/scale-partition) - [AWS Well-Architected: Make Systems Stateless Where Possible](https://docs.aws.amazon.com/wellarchitected/latest/framework/rel_mitigate_interaction_failure_stateless.html) - [Raff Cloud Servers](/products/raff-vm) - [Raff VPC](/products/vpc) --- ### IPv4, IPv6, and Dual-Stack Networking for Cloud Servers URL: https://rafftechnologies.com/learn/guides/ipv4-ipv6-dual-stack-networking-cloud-servers Description: Compare IPv4, IPv6, and dual-stack networking for cloud servers, including DNS, firewalls, application binding, monitoring, and migration planning. IPv4, IPv6, and dual-stack describe how a cloud server is addressed and reached across modern networks. **IPv4 remains the broadest compatibility baseline. IPv6 provides a much larger address space and cleaner long-term network planning. Dual-stack lets a service use both, but only works well when DNS, firewall rules, application listeners, and monitoring are configured for both address families.** For most public applications, the safest path is not an immediate IPv6-only cutover. It is a staged rollout: keep IPv4 available, add IPv6 where the platform and application path support it, test both independently, and publish both DNS records only after the complete route works. ## IPv4 vs IPv6 vs dual-stack: quick answer Choose **IPv4-only** when broad compatibility and operational simplicity matter more than immediate IPv6 adoption. Choose **dual-stack** when you want to support both IPv4 and IPv6 clients without forcing a hard migration. Choose **IPv6-only** only when every client, dependency, monitoring service, and administrative path is known to support IPv6 or when translation is deliberately part of the design. | Decision factor | IPv4-only | IPv6-only | Dual-stack | |---|---|---|---| | Public compatibility | Highest | Depends on client and dependency support | High | | Operational complexity | Lowest | Medium | Highest | | Address-space flexibility | Limited | Very high | Very high | | DNS records | `A` | `AAAA` | `A` and `AAAA` | | Firewall review | IPv4 rules | IPv6 rules | Both rule sets | | Best fit | Fast launches and legacy dependencies | Controlled modern environments | Gradual public adoption | A useful rule is: > Do not publish an `AAAA` record until the IPv6 path works end to end. DNS should advertise a working route, not an intended future state. ## What IPv4 means for a cloud server IPv4 uses 32-bit addresses such as: ```text 203.0.113.20 ``` It remains widely supported by browsers, enterprise networks, monitoring providers, partner systems, allowlists, and operational tooling. IPv4 is often the simplest starting point for: - public websites - APIs with third-party consumers - services used by older corporate networks - workloads that depend on IPv4 allowlists - teams that have not yet tested IPv6 operations Its limitation is address scarcity. Public IPv4 addresses are finite, and private IPv4 ranges can also become difficult to manage when environments, customers, VPNs, and internal networks begin to overlap. NAT can extend IPv4 designs, but it also adds translation, state, and troubleshooting complexity. ## What IPv6 changes IPv6 uses 128-bit addresses such as: ```text 2001:db8:1234:1::20 ``` The larger address space is the obvious difference, but it is not the only operational change. IPv6 affects: - address planning - DNS - firewall policies - service binding - log formats - monitoring - access-control lists - application libraries - third-party allowlists IPv6 does not remove the need for firewalls or least-privilege access. A globally routable address should not be treated as permission for the internet to reach the service. The security model remains: 1. expose only required services 2. restrict source and destination traffic 3. authenticate users and services 4. monitor both expected and unexpected access ## What dual-stack actually means Dual-stack means the relevant server, network, or application path can use both IPv4 and IPv6. For a public website, a simplified path looks like this: ```text Client ├─ IPv4 route → A record → IPv4 listener └─ IPv6 route → AAAA record → IPv6 listener ``` A complete dual-stack deployment may require support at every layer: - the cloud platform assigns or routes IPv6 - the VM operating system configures the address - the firewall allows the intended IPv6 traffic - the reverse proxy or application listens on IPv6 - DNS publishes the correct `AAAA` record - monitoring tests the IPv6 endpoint separately A service is not operationally dual-stack merely because the operating system displays an IPv6 address. ## Why broken IPv6 can affect users Modern clients may receive both `A` and `AAAA` records and choose between multiple addresses. Algorithms such as Happy Eyeballs reduce delays by attempting suitable routes without waiting too long for a broken path. That does not make bad IPv6 configuration harmless. A partially working route can still create: - slow connection attempts - failures from specific ISPs or office networks - monitoring disagreements - TLS or proxy issues visible only over one address family - support cases that appear intermittent Test from real external IPv4 and IPv6 networks rather than relying only on local server checks. ## DNS design for IPv4 and IPv6 ### `A` records An `A` record maps a hostname to an IPv4 address. ```text app.example.com → 203.0.113.20 ``` ### `AAAA` records An `AAAA` record maps a hostname to an IPv6 address. ```text app.example.com → 2001:db8:1234:1::20 ``` ### Dual-stack DNS A dual-stack hostname usually publishes both: ```text app.example.com → A → 203.0.113.20 app.example.com → AAAA → 2001:db8:1234:1::20 ``` Before publishing the `AAAA` record, verify: - the address is assigned and routed correctly - the service listens on the intended IPv6 socket - TLS certificates and SNI behavior work - firewall rules allow only the intended ports - health checks pass over IPv6 - logs record the client address correctly - upstream dependencies do not assume IPv4-only source addresses DNS should be the final publication step after the network path is validated. ## Firewall rules must cover both families A common migration error is protecting IPv4 carefully while leaving IPv6 broader than intended. Review IPv4 and IPv6 exposure separately. For a web VM, the intended policy may be: | Service | IPv4 | IPv6 | Source | |---|---|---|---| | HTTP 80 | Allow | Allow | Public internet | | HTTPS 443 | Allow | Allow | Public internet | | SSH 22 | Restricted | Restricted | Approved admin source or private path | | Database port | Deny publicly | Deny publicly | Application network only | Do not assume a firewall tool automatically mirrors IPv4 rules to IPv6. Confirm the actual behavior of the operating system and platform firewall. Private addresses also do not replace firewall policy. A private network limits reachability, while firewall rules define which reachable systems may communicate. ## Application and reverse-proxy binding Even when networking is configured correctly, the application may listen only on IPv4. Common listener examples include: ```text 0.0.0.0:443 IPv4 on all interfaces [::]:443 IPv6 on all interfaces 127.0.0.1:3000 IPv4 loopback only [::1]:3000 IPv6 loopback only ``` The exact behavior depends on the operating system and application runtime. On some systems, an IPv6 wildcard listener may also accept IPv4-mapped connections; on others, separate listeners are needed. Verify the behavior rather than assuming it. For reverse proxies such as Nginx, HAProxy, or Caddy, test: - frontend IPv4 reachability - frontend IPv6 reachability - backend connection family - original client-IP forwarding - TLS termination - health-check behavior Read [Reverse Proxy vs Load Balancer](/learn/guides/reverse-proxy-vs-load-balancer) when deciding where the public listener should sit. ## Public and private traffic are separate decisions Public IPv6 adoption does not require every internal service to become publicly reachable. A practical architecture may use: ```text Internet clients ↓ IPv4 or IPv6 Public load balancer or reverse proxy ↓ private network Application servers ↓ private network Database and internal services ``` The public edge may support both address families while backend communication stays on the private addressing model supported by the environment. Use [Private Networking in Cloud: Public vs Private Traffic](/learn/guides/private-networking-public-vs-private-traffic) to decide which components should be internet-accessible. ## IPv4-only: when it remains reasonable IPv4-only is still a valid choice when: - your service must support the widest possible range of networks - third-party allowlists accept only IPv4 - operational tooling has not been tested with IPv6 - your team needs the simplest initial deployment - IPv6 does not yet solve a current constraint The important point is to avoid creating unnecessary future barriers. Keep configuration and application code flexible by: - storing hostnames instead of hardcoded IP addresses - supporting IPv6-safe log and database fields - avoiding parsing logic that assumes dotted-decimal addresses - reviewing libraries and access-control systems for IPv6 support ## Dual-stack: when it is the better migration path Dual-stack is a good fit when: - the workload is public-facing - both legacy and modern networks must connect - the team wants gradual IPv6 adoption - IPv6 routing is supported across the required platform path - monitoring can validate each family independently Dual-stack adds operational work because every exposed service has two potential paths. That added work is justified when compatibility and gradual adoption both matter. ## IPv6-only: when to use it carefully IPv6-only may work well for: - controlled internal networks - greenfield environments with known dependencies - specialized services where clients are IPv6-capable - architectures with a tested IPv4 translation layer Before choosing IPv6-only, verify: - package repositories and update systems - identity providers - external APIs - monitoring and alerting services - CI/CD runners - DNS resolvers - support access - backup destinations A single critical IPv4-only dependency can make an otherwise clean IPv6-only design unreliable. ## Monitoring and observability Monitor IPv4 and IPv6 as distinct service paths. At minimum, test: - DNS `A` response - DNS `AAAA` response - TCP connection over IPv4 - TCP connection over IPv6 - TLS handshake over both families - application health response - latency and error rate by address family Logs and analytics should preserve valid IPv6 addresses. Database columns sized only for short IPv4 strings can truncate or reject IPv6 values. For textual storage, allow enough space for normalized and non-normalized address representations or use a database-native IP address type where available. ## A practical rollout plan ### Stage 1: audit the path Confirm platform support, VM configuration, firewall behavior, proxy listeners, DNS management, and monitoring capability. ### Stage 2: test without public DNS Reach the service directly over the assigned IPv6 address or use a temporary test hostname. ### Stage 3: validate the application Check authentication, redirects, callbacks, WebSockets, API clients, logs, and rate limiting. ### Stage 4: publish the `AAAA` record Add the IPv6 DNS record only after the path is stable. ### Stage 5: monitor both families Track failures separately and keep rollback simple: removing the `AAAA` record should be an available response to an IPv6-specific incident. ### Stage 6: expand gradually Move additional services only after the first deployment behaves predictably. ## How this applies on Raff [Raff VPC](/products/vpc) provides controlled private connectivity between supported resources. Confirm the current addressing options for the exact VPC and resource type you are deploying before treating IPv6 support as an architectural dependency. Public IPv6 assignment and end-to-end dual-stack behavior should also be verified for the exact resource you are deploying. Before adding a public `AAAA` record, check the current Raff dashboard or documentation for: - whether the VM or selected traffic-distribution endpoint has a public IPv6 address - how that address is routed - whether platform firewall rules cover IPv6 - whether the selected private network uses IPv4, IPv6, or both Use [Linux VMs](/products/linux-vm) for the application layer and [Raff VPC](/products/vpc) to keep internal service traffic away from unnecessary public exposure. The live [pricing page](/pricing) should be used for current infrastructure costs rather than embedding plan prices in a networking guide. ## Common mistakes ### Publishing `AAAA` before testing the route A DNS record can send real users to an incomplete path. ### Protecting only IPv4 IPv6 exposure requires its own firewall review. ### Assuming the application listens on both families Confirm the actual socket configuration. ### Hardcoding IPv4 addresses Use DNS names when possible and make storage formats IPv6-safe. ### Treating private addressing as full isolation Private networks and firewall policy solve different parts of the security model. ### Monitoring only one path A service can be healthy over IPv4 and unavailable over IPv6, or the reverse. ## Conclusion IPv4, IPv6, and dual-stack are operational choices that affect much more than address format. IPv4 remains the simplest compatibility baseline. IPv6 provides long-term address flexibility. Dual-stack is often the safest public migration model because it preserves IPv4 while introducing IPv6 gradually. The success of dual-stack depends on the complete path: address assignment, routing, DNS, firewall rules, application binding, TLS, and monitoring. Test each family separately and publish only routes that are ready to serve users. :::cta Explore VPC Keep application, database, and internal service traffic on controlled private network paths. ::: ## Sources - [Cloud-init documentation](https://docs.cloud-init.io/) - [RFC 8305: Happy Eyeballs Version 2](https://www.rfc-editor.org/rfc/rfc8305.html) - [Raff VPC](/products/vpc) --- ### Kubernetes Cost Optimization: Reduce Cluster Spend URL: https://rafftechnologies.com/learn/guides/kubernetes-cost-optimization-startups Description: Reduce Kubernetes costs by measuring allocation, rightsizing requests, tuning autoscaling, removing idle capacity, and controlling storage and observability. Kubernetes cost optimization means reducing unnecessary cluster spend while preserving the performance, reliability, and delivery speed the workload actually needs. For most teams, the best sequence is straightforward: **measure where the cluster cost goes, separate workload cost from idle capacity, right-size CPU and memory requests, tune autoscaling, remove unused environments, simplify node pools, and control storage and observability growth.** Tooling helps, but optimization starts with accurate workload signals and clear ownership. At Raff Technologies, we treat Kubernetes cost as an infrastructure design problem rather than a hunt for one cheap setting. A cluster can be well utilized and still be expensive because of storage, duplicated environments, unnecessary replicas, or operational overhead. It can also look underutilized for a valid reason when the spare capacity protects an important availability or scaling requirement. This guide focuses on a practical Kubernetes cost optimization workflow for startups and small platform teams. For the architecture decision that comes before optimization, see [Kubernetes vs Docker Compose for Small Teams](/learn/guides/kubernetes-vs-docker-compose-small-teams). ## Kubernetes cost optimization at a glance A useful optimization loop has seven steps. | Step | Question | Typical action | |---|---|---| | 1. Measure | Where does cluster cost actually go? | Break cost down by cluster, namespace, workload, storage, and idle capacity | | 2. Allocate | Which team, product, or environment owns the spend? | Use labels, namespaces, and cost-allocation tooling | | 3. Right-size | Are requests materially above normal usage? | Adjust CPU and memory requests from observed workload behavior | | 4. Autoscale | Does capacity follow real demand? | Tune HPA, VPA, and node scaling for the workload | | 5. Remove idle | Which resources stay allocated without useful work? | Delete, scale down, consolidate, or schedule non-production resources | | 6. Optimize infrastructure | Are nodes, storage, and supporting services matched to the workload? | Simplify node pools, improve placement, review persistent storage and external services | | 7. Govern | Will the waste return next month? | Add quotas, ownership, budgets, retention policies, and recurring reviews | Do not start with the most advanced autoscaler or a list of optimization tools. Start by making the cost visible enough that the team can explain it. ![Diagram showing Kubernetes cost factors including nodes, storage, environments, monitoring, and operations](https://raff-images.s3.raffusercloud.com/kubernetes_cost_breakdown_small_teams_webp_736101d03c.png) ## Measure total cluster cost before trying to reduce it Kubernetes makes resource consumption dynamic. Pods appear and disappear, workloads share nodes, PersistentVolumes have separate lifecycles, and application teams often share the same cluster. The cloud invoice therefore tells you what the infrastructure cost, but not always which workload caused that cost. A practical cost model separates three categories: ```text Total cluster cost = workload-attributed cost + idle or unallocated capacity + shared cluster overhead ``` This distinction matters. **Workload-attributed cost** is the portion associated with application workloads: CPU, memory, persistent storage, load balancers, and other resources that can be tied to a namespace, deployment, job, or team. **Idle cost** is provisioned capacity that is not currently allocated to useful workload demand. Some idle capacity is waste. Some is intentional headroom. **Shared overhead** includes resources that support the cluster as a whole, such as system workloads and platform-level components. OpenCost formalizes this type of allocation model and can break Kubernetes cost down by concepts including containers, Pods, deployments, labels, namespaces, and clusters. That makes it useful when the question changes from “Why is the cluster expensive?” to “Which workload, environment, or team is responsible for the increase?” For a small team, begin with a weekly or monthly view showing: - total cluster cost; - cost by production and non-production; - cost by namespace or application; - CPU and memory requested versus used; - idle node capacity; - persistent storage cost; - load-balancer and networking cost where applicable; - observability and backup cost outside the node bill. If the team cannot explain the largest cost categories, optimization is still a measurement problem. ## Cost allocation needs a stable ownership model Cost data becomes more useful when infrastructure has consistent ownership metadata. A cluster can be technically healthy while still being financially opaque because workloads are named inconsistently and nobody can tell which product or environment owns them. Use labels and namespaces that make these dimensions visible: ```text environment = production | staging | preview team = platform | api | data service = web | worker | reporting owner = team-name cost-center = product-or-business-unit ``` You do not need an enterprise chargeback program to benefit from allocation. Even a five-person engineering team gains value from being able to answer: - How much does production cost compared with staging? - Which service is driving the latest increase? - Which preview environments still exist? - How much node capacity is currently idle? - Which workload is reserving the most memory? This is the foundation for **showback**—making cost visible to the team that creates it. Formal chargeback can come later if the organization actually needs it. ## Right-size CPU and memory requests from observed behavior Resource requests are one of the most important Kubernetes cost signals because the scheduler uses them when deciding where Pods can run. If requests are much higher than the workload normally needs, the scheduler sees less free capacity than the physical nodes may actually have. That can lead to poor bin packing and additional nodes. If requests are too low, the workload may compete aggressively for resources or become difficult to schedule safely during real demand. The goal is not to make every request as small as possible. The goal is to make requests reflect the workload’s operating envelope. A practical rightsizing process is: 1. Collect historical CPU and memory usage across representative traffic periods. 2. Separate normal operation, predictable peaks, deployments, and batch windows. 3. Compare requests with actual use for each important container. 4. Identify consistently over-requested and under-requested workloads. 5. Adjust one workload class at a time. 6. Re-measure latency, errors, throttling, OOM events, queue time, and scheduling behavior. 7. Keep enough headroom for the workload’s real failure and traffic model. Avoid sizing from one quiet hour or one unusual peak. Use enough history to understand the workload pattern. ### CPU and memory should not be tuned identically CPU and memory fail differently. CPU can be throttled when a configured CPU limit is reached. Memory pressure is less forgiving: containers that exceed available or enforced memory can be terminated by the kernel. That means “reduce every request and limit by 30%” is not a safe optimization strategy. Review CPU and memory separately, and connect the change to application behavior. A web API, JVM service, queue worker, and in-memory cache can require very different safety margins even when their average utilization looks similar. For the official mechanics, see [Kubernetes resource management for Pods and containers](https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/). ## VPA is a rightsizing tool, not a replacement for measurement The Vertical Pod Autoscaler adjusts or recommends CPU and memory resources for workloads according to observed demand. That makes VPA useful when requests drift away from actual use, but the team still needs to understand what the recommendation means for the application. VPA is most useful when: - workload resource needs change over time; - many deployments have stale requests; - manual rightsizing does not happen consistently; - the team wants recommendations before automating changes. Use recommendation-only or controlled rollout modes first when automatic resource changes could affect a sensitive production workload. The important point is that rightsizing and horizontal scaling solve different problems. VPA changes resources per Pod; HPA changes the number of Pods. ## Tune HPA only after requests and metrics are trustworthy The Horizontal Pod Autoscaler changes replica count based on observed metrics such as CPU, memory, or custom metrics. That can improve both performance and cost when capacity tracks actual demand. It can also scale waste when the underlying signals are wrong. Common HPA cost problems include: - minimum replica counts that are higher than the availability requirement; - CPU targets based on inflated requests; - scaling on a metric that does not represent user demand; - background jobs increasing a metric intended for web traffic; - slow scale-down behavior leaving excess capacity for long periods; - production autoscaling settings copied into staging and previews. Kubernetes calculates CPU utilization for HPA relative to resource requests, which is another reason accurate requests matter. A better workflow is: ```text measure workload → right-size requests → choose the correct scaling metric → tune HPA behavior → observe replica and node response → validate cost and user impact ``` For request-driven services, traffic or queue metrics can sometimes represent demand better than raw CPU. The right metric depends on the application. See [Kubernetes Horizontal Pod Autoscaling](https://kubernetes.io/docs/concepts/workloads/autoscaling/horizontal-pod-autoscale/) for current HPA behavior. ## Node autoscaling solves a different layer of the problem Pod autoscaling and node autoscaling are related but not interchangeable. HPA changes the number of Pods. Node autoscaling changes cluster capacity so those Pods have somewhere to run. A simple sequence looks like this: ```text Demand rises → HPA creates more Pods → Pods need additional schedulable capacity → node autoscaler adds nodes ``` The reverse should also work. When demand falls, workloads scale down and unused node capacity should eventually be removable when the cluster’s availability and disruption rules permit it. Node autoscaling is less effective when: - Pod requests are inflated; - PodDisruptionBudgets prevent consolidation unexpectedly; - workloads use restrictive affinity or anti-affinity rules; - many specialized node pools leave fragmented capacity; - local storage or topology constraints make workloads difficult to move; - minimum node counts are higher than the actual resilience requirement. Autoscaling does not fix poor scheduling economics. It automates whatever constraints you have already designed. ## Simplify node pools before adding more of them Node pools are useful when workloads have materially different resource or scheduling requirements. Too many pools can create fragmentation. For a small team, every new node class should answer a real requirement such as: - a memory-heavy workload; - compute-intensive processing; - a workload that needs different isolation; - a different availability or scheduling policy; - specialized hardware. Avoid creating separate pools simply because every service feels unique. A cost-aware cluster often has fewer workload classes than application services. | Workload group | Possible treatment | |---|---| | General web/API workloads | Shared general node pool | | Background workers | Shared worker pool only if their resource pattern materially differs | | Memory-heavy workloads | Separate memory-oriented capacity when measurement justifies it | | Non-production | Smaller or schedulable capacity with stricter cleanup | | Specialized hardware | Dedicated pool only for workloads that need it | The goal is enough separation to schedule efficiently without turning the cluster into many small islands of stranded capacity. For a deeper node-level decision, continue with [Kubernetes Node Pools: Design, Sizing, and Workload Placement](/learn/guides/kubernetes-node-pools). ## Idle capacity is not automatically waste A low utilization percentage does not prove the cluster is poorly optimized. Production systems may need spare capacity for: - traffic bursts; - a node failure; - rolling updates; - rescheduling after maintenance; - short-lived batch workloads; - latency objectives that would be missed at high saturation. The useful question is whether the idle capacity has a reason. Classify idle capacity into three groups: 1. **Required headroom** — justified by availability, scaling, or recovery needs. 2. **Temporary headroom** — needed for a known migration, launch, or maintenance window. 3. **Unowned waste** — capacity that remains because nobody has reviewed or removed it. Optimization should target the third category first. If removing one node would make a production service unable to survive the failure scenario it was designed for, that node is not necessarily waste. Cost decisions must preserve the reliability model. ## Non-production environments are often the easiest savings Production usually receives the most attention, but staging, QA, previews, demos, and migration environments can create a large fixed baseline. Audit every non-production environment against five questions: - Does it need to run 24/7? - Does it need production-sized replicas? - Does it need production-sized persistent storage? - Does it need production log retention? - Who owns deletion or scale-down? Preview environments should normally have an automatic end condition. A pull request that was merged weeks ago should not still own compute, storage, and a load balancer. Staging should match production where parity is necessary for release confidence, not necessarily in full capacity. Useful controls include: - TTL or automated cleanup for previews; - scheduled scale-down for environments unused outside working hours where operationally safe; - stricter ResourceQuotas for non-production namespaces; - smaller log-retention windows; - smaller datasets where full production data volume is unnecessary. For the environment design decision, use [Development, Staging, and Production Cloud Environments](/learn/guides/dev-staging-production-cloud-environments). ## ResourceQuota and LimitRange create financial guardrails Kubernetes ResourceQuota can cap aggregate resource requests and limits inside a namespace. LimitRange can define default, minimum, and maximum resource behavior for resources in that namespace. These controls are useful when several teams or environment types share a cluster. For example: ```text production → capacity driven by service objectives staging → smaller namespace quota preview → strict quota + automatic deletion batch → bounded concurrency and resource budget ``` Quotas do not optimize an application by themselves. They prevent one namespace or workflow from consuming an unlimited share of cluster capacity without an explicit decision. See [Kubernetes Resource Quotas](https://kubernetes.io/docs/concepts/policy/resource-quotas/) for the current behavior. ## Persistent storage can outgrow compute savings A team can right-size every Pod and still have a rising Kubernetes bill because storage keeps growing. Review: - PersistentVolume capacity; - unattached or abandoned volumes; - snapshots and backup retention; - database data growth; - log volumes written to persistent disks; - storage classes that provide more performance than the workload uses; - development PVCs that survive after their workloads are deleted. Persistent storage deserves a lifecycle owner just like compute. For application uploads, media, exports, and backup archives, object storage may be a better architecture than keeping growing file collections on cluster volumes. The right choice depends on whether the application needs block/filesystem semantics or API-based object access. Use [App Uploads: VM Disk vs Object Storage](/learn/guides/app-uploads-vm-disk-vs-object-storage) for that decision. ## Network and load-balancer cost should be visible separately Node utilization is not the complete Kubernetes bill. Depending on the provider and architecture, cost can also come from: - public load balancers; - cross-zone or cross-region traffic; - NAT or gateway services; - public egress; - service-to-service traffic patterns; - external managed services reached from the cluster. A service that looks inexpensive in CPU may still have a high delivery cost if it moves large amounts of data. Track network-heavy workloads separately and avoid assuming that reducing Pod CPU automatically reduces total platform cost. ## Observability needs retention and sampling policies Kubernetes produces a large amount of operational data: container logs, node metrics, events, traces, application metrics, ingress logs, and audit data. Visibility is necessary. Unlimited retention is not. Define observability policy by environment and diagnostic value. | Environment | Practical policy | |---|---| | Production | Keep the data required for operations, incident analysis, security, and business requirements | | Staging | Shorter retention unless a release process requires more | | Preview | Minimal retention with environment cleanup | | Temporary test | Retain only what the test needs | Review high-cardinality metrics, duplicated log streams, verbose debug logging, and traces that are collected but never used. The goal is not to reduce observability until incidents become harder to diagnose. It is to stop paying indefinitely for telemetry that has no operational purpose. ## OpenCost and Kubecost solve the visibility layer Cost tooling is valuable once the team knows what decisions it wants to make. **OpenCost** is a vendor-neutral open-source project for measuring and allocating Kubernetes and cloud infrastructure costs. Its model can attribute costs to Kubernetes objects and expose workload, idle, and shared costs. **Kubecost** builds on the OpenCost cost-allocation engine and adds a broader product experience around Kubernetes cost management. A small team can use tooling like this to answer questions such as: - cost by namespace; - cost by deployment or service; - idle cost; - request efficiency; - cost trends by environment; - shared infrastructure allocation; - showback to teams or products. Do not select a tool only because its dashboard looks comprehensive. Decide first which cost decisions you need the tool to support. For a single cluster, the first useful outcome may simply be a weekly report that identifies the biggest workload, idle, storage, and non-production cost changes. ## Use a recurring Kubernetes cost review Optimization fails when it happens only after the invoice surprises someone. A short monthly review is enough for many small teams. ### Cost movement - What changed since the previous review? - Which workloads created the increase? - Did cost rise because of users, reliability, data, or waste? ### Resource efficiency - Which workloads are materially over-requested? - Which workloads regularly hit CPU, memory, or latency limits? - Is node capacity fragmented? ### Autoscaling - Are minimum replicas still justified? - Does HPA scale on the right signal? - Can nodes scale down after demand falls? ### Environments - Which preview, QA, migration, and demo workloads still exist? - Do they need to run continuously? ### Storage and observability - Which volumes and snapshots are growing? - Are retention policies still appropriate? - Is telemetry volume growing faster than application traffic? ### Ownership - Does every large resource have a team or service owner? - Does every temporary resource have an end condition? The output should be a small action list with owners, not only a cost dashboard screenshot. ## When optimization should become architecture simplification Sometimes the cluster is expensive because the cluster solves a problem the product no longer has—or never had. ![Decision diagram comparing Kubernetes optimization with simplifying architecture on Raff](https://raff-images.s3.raffusercloud.com/optimize_kubernetes_vs_simplify_architecture_webp_1568daa4ce.png) Consider a simpler deployment model when: - one or two application services dominate the cluster; - the team does not benefit from Kubernetes scheduling or service orchestration; - most environments are small and static; - cluster operations consume more engineering time than the workload justifies; - a VM or Docker Compose deployment can meet the same reliability and deployment requirements more simply. Do not migrate away from Kubernetes only because average utilization is low. Compare the complete operating model: deployment, scaling, failure recovery, observability, security, and engineering time. Likewise, do not keep Kubernetes only because the migration already happened. Architecture is a current business decision, not a sunk-cost obligation. ## How this applies on Raff Raff supports both a managed Kubernetes path and simpler VM-based architectures. ![Raff cost-aware path from VM to Managed Database, Object Storage, worker VMs, and Kubernetes](https://raff-images.s3.raffusercloud.com/raff_cost_aware_kubernetes_path_webp_ef62522faf.png) For a Kubernetes workload, use the live [Raff Kubernetes](/products/kubernetes) and [Raff pricing](/pricing) pages for current node options, product availability, and pricing instead of relying on plan numbers embedded in an evergreen guide. A cost-aware Raff architecture can combine: - [Raff Kubernetes](/products/kubernetes) for workloads that benefit from Kubernetes orchestration; - [Raff VM](/products/raff-vm) when a workload is simpler to operate directly on a VM; - [Managed Databases](/products/managed-databases) when database operations should have a separate managed boundary; - [Object Storage](/products/object-storage) for durable uploads, media, exports, and archives that do not need a mounted filesystem. The optimization principle remains the same: keep each workload on the infrastructure layer that matches its operational requirements. Raff Technologies should not be used as a reason to move every application into Kubernetes. The stronger decision is to use Kubernetes where scheduling, multi-node operations, rollout control, and service coordination create measurable value, then optimize that cluster from actual usage data. :::cta Explore Raff Kubernetes Review Raff Kubernetes for workloads that need managed cluster orchestration, then size the deployment from measured CPU, memory, storage, and availability requirements. ::: ## Kubernetes cost optimization checklist Use this checklist during a cost review: - [ ] Cluster spend can be separated into workload, idle, storage, and shared costs. - [ ] Production and non-production spend are visible separately. - [ ] Important workloads have an owner. - [ ] CPU requests are compared with historical usage. - [ ] Memory requests are compared with historical usage and OOM behavior. - [ ] Limits are intentional rather than copied from templates. - [ ] VPA recommendations are reviewed where useful. - [ ] HPA metrics match real workload demand. - [ ] Minimum replica counts are justified by availability needs. - [ ] Node pools represent real workload classes rather than every application. - [ ] Idle node capacity has a documented reason. - [ ] Preview environments have automatic cleanup. - [ ] Non-production namespaces have appropriate quotas. - [ ] Persistent volumes, snapshots, and backups have lifecycle owners. - [ ] Observability retention differs by environment where appropriate. - [ ] Network and load-balancer costs are included in the review. - [ ] Cost is reviewed on a recurring schedule. - [ ] Architecture simplification remains an option when Kubernetes no longer creates enough value. ## Reduce Kubernetes cost by improving the operating model Kubernetes cost optimization is not a single autoscaler setting or a one-time rightsizing project. The strongest process makes cost explainable. Measure cluster spend by workload and environment. Separate useful headroom from unowned idle capacity. Right-size requests from observed behavior. Use VPA for resource recommendations where it helps, HPA for replica scaling, and node autoscaling for cluster capacity. Keep node pools simple, remove expired non-production resources, and apply lifecycle policies to storage and observability. Then repeat the review as the product changes. A well-optimized Kubernetes platform is not necessarily the cluster with the highest utilization or the lowest possible bill. It is the cluster where capacity, reliability, and spend can each be traced to a real workload requirement. ### Sources - [Kubernetes: Resource Management for Pods and Containers](https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/) - [Kubernetes: Horizontal Pod Autoscaling](https://kubernetes.io/docs/concepts/workloads/autoscaling/horizontal-pod-autoscale/) - [Kubernetes: Vertical Pod Autoscaling](https://kubernetes.io/docs/concepts/workloads/autoscaling/vertical-pod-autoscale/) - [Kubernetes: Resource Quotas](https://kubernetes.io/docs/concepts/policy/resource-quotas/) - [OpenCost Specification](https://opencost.io/docs/specification/) - [OpenCost Documentation](https://opencost.io/docs/) --- ### Managed Kafka vs Self-Hosted Kafka: Cost, Scaling & Ownership URL: https://rafftechnologies.com/learn/guides/managed-kafka-vs-self-hosted-kafka Description: Compare managed Kafka vs self-hosted Kafka across total cost of ownership, cloud hosting, scaling, broker operations, control, and on-call responsibility. Managed Kafka vs self-hosted Kafka is mainly a decision about **who operates the Kafka platform and what that responsibility costs over time**. Managed Kafka transfers more broker lifecycle, infrastructure, patching, monitoring, and recovery work to a provider. Self-hosted Kafka keeps that control—and the operational burden—with your team. For a small SaaS or platform team, the decision should not start with “a few VMs are cheaper than a managed service.” It should start with the required availability, broker-level control, growth pattern, on-call ownership, and the total engineering work needed to keep Kafka healthy. Raff Technologies offers both paths: teams can run Kafka themselves on Raff VMs or use the managed Kafka product path. The right model depends on whether direct broker ownership is a real requirement or simply an infrastructure task the product team would prefer not to carry. ## Managed Kafka vs self-hosted: quick decision | Question | Managed Kafka usually fits | Self-hosted Kafka usually fits | |---|---|---| | Who should own broker failures? | Provider/platform service | Your platform team | | Who should patch and maintain brokers? | Provider | Your team | | Do you need host-level control? | No | Yes | | Do you already operate Kafka reliably? | Not required | Usually yes | | Is engineering time scarce? | Strong fit | Higher operational cost | | Do you need exact broker configuration? | Only within service limits | Full control | | How should cost be compared? | Managed plan + retained app work | Infrastructure + operations + engineering | | Who still owns topics and consumers? | Your application team | Your application team | A useful default is: > **Choose managed Kafka when Kafka is infrastructure for your product. Choose self-hosted Kafka when operating Kafka itself is a documented technical requirement and your team can sustain that responsibility.** ## Managed Kafka and self-hosted Kafka move different responsibilities The biggest difference is not the Kafka API. It is the responsibility boundary around the cluster. | Responsibility | Managed Kafka | Self-hosted Kafka | |---|---|---| | Infrastructure provisioning | Provider/service scope | Team-owned | | Broker installation and lifecycle | Provider/service scope | Team-owned | | Host and broker patching | Provider/service scope | Team-owned | | Failed broker replacement | Provider/service scope | Team-owned | | Monitoring platform | Provider-defined baseline | Team designs and operates | | Capacity changes | Supported service workflow + customer decision | Team designs and executes | | Partition reassignment / broker balancing | Service-dependent | Team-owned | | Broker security baseline | Shared/provider-heavy | Team-owned | | Topic design | Team-owned | Team-owned | | Partition keys and ordering | Team-owned | Team-owned | | Producers and consumers | Team-owned | Team-owned | | Consumer groups and offsets | Team-owned | Team-owned | | Schema compatibility | Team-owned | Team-owned | | Retry and idempotency behavior | Team-owned | Team-owned | | Business validation after replay | Team-owned | Team-owned | Managed Kafka therefore reduces **broker operations**, not Kafka application design. A provider cannot decide whether an order stream needs per-customer ordering, whether a consumer can safely replay millions of events, or whether duplicate delivery creates an invalid business action. Those remain application decisions in either model. ## Kafka total cost of ownership is more than the VM bill GSC data for this guide shows users are explicitly asking whether self-managed Kafka is really cheaper and what the total cost of ownership difference is. That is the right question. A self-hosted Kafka cost model can include: ```text Compute + storage + network transfer where applicable + replication overhead + monitoring and alerting + spare/recovery capacity + engineering time + on-call coverage + patching and upgrades + capacity planning + incident response + backup/recovery work + migration and decommissioning work ``` A managed Kafka cost model can include: ```text Managed service plan + storage/capacity growth + optional availability features + network transfer where applicable + engineering time for Kafka application design + migration effort + service constraints that require workarounds ``` The comparison becomes useful only when both sides assume a similar service level. Comparing one managed production cluster with one inexpensive VM ignores replication, maintenance, monitoring, recovery, and operator time. ### A simple Kafka TCO worksheet Before deciding, estimate the monthly operating load in four buckets: | Cost bucket | Managed Kafka | Self-hosted Kafka | |---|---|---| | Infrastructure | Included or bundled in service plan | Brokers, storage, network, spare capacity | | Platform operations | Mostly transferred to provider | Monitoring, patching, upgrades, balancing, incidents | | Application operations | Producers, consumers, topics, schemas, lag | Same | | Change risk | Service constraints and migration | Upgrade, rebalancing, broker/storage/network changes | Then ask one practical question: > If a Kafka incident happens at 03:00, who is expected to diagnose the broker layer and restore it? If the answer is an application engineer who does not routinely operate Kafka, the apparent self-hosting savings may be misleading. The reverse can also be true. A team with an existing Kafka platform, automation, mature monitoring, documented upgrades, and staffed on-call may have a lower incremental cost from self-hosting than from a managed service premium. For a wider infrastructure-cost framework, see [Managed vs Self-Hosted Databases](/learn/guides/managed-vs-self-hosted-databases). ## Self-hosted Kafka vs cloud-managed Kafka “Self-hosted Kafka vs cloud” is not really cloud versus non-cloud. Self-hosted Kafka can run on cloud VMs. The actual distinction is **self-managed infrastructure versus a managed Kafka service**. A self-hosted cloud deployment can look like: ```text Kafka clients ↓ Private network ↓ Kafka broker VMs ↓ Attached storage + monitoring + backups ↓ Your team owns the operating lifecycle ``` A managed deployment can look like: ```text Kafka clients ↓ Private / supported service connection ↓ Managed Kafka cluster ↓ Provider operates broker infrastructure ``` Both are cloud architectures. What changes is the operational boundary. Choose self-hosted cloud Kafka when direct VM, storage, networking, broker configuration, or upgrade control is required. Choose managed Kafka when the workload fits the service boundary and the team would rather spend engineering capacity on producers, consumers, event design, and product behavior. ## Scaling Kafka means scaling more than brokers Kafka scaling is not one knob. Traffic growth can increase pressure on: - producer throughput; - consumer throughput; - partition count; - broker CPU and memory; - disk capacity and throughput; - replication traffic; - consumer lag; - retention storage; - network throughput; - recovery time after a broker failure. In a managed model, the provider normally owns more of the broker lifecycle and exposes a supported capacity or HA workflow. The application team still owns partition design, consumer concurrency, retention requirements, and the workload signals that indicate more capacity is needed. In a self-hosted model, your team must convert those signals into infrastructure work. That can include adding brokers, expanding storage, verifying replica health, reassigning partitions, checking client behavior, and validating the cluster afterward. The useful question is not only “Can we add a broker?” It is **who owns the safe capacity change and what happens if it goes wrong during peak traffic?** ## Self-hosting is justified when broker-level control is a hard requirement Strong self-hosting signals include: - exact broker settings that a managed service restricts; - custom networking or security architecture outside the service boundary; - exact patch or upgrade timing; - host-level observability or debugging requirements; - specialized storage layout; - unsupported plugins, extensions, or surrounding services; - custom multi-cluster topology; - regulatory or contractual requirements for direct operational ownership; - an existing Kafka platform team with mature automation and on-call coverage. The key is that the requirement should be documented before the team accepts the operations burden. “Kafka is open source” is not enough. “A VM is cheaper” is also not enough. Those statements describe licensing and infrastructure price, not production Kafka ownership. If self-hosting is the right answer, a [Raff VM](/products/raff-vm) provides the infrastructure control needed to run the broker stack, while your team remains responsible for Kafka installation, security, storage, monitoring, upgrades, scaling, and recovery. ## Managed Kafka fits when broker operations are not product differentiation Managed Kafka is usually a stronger fit when: - the engineering team is small; - there is no dedicated Kafka platform owner; - broker upgrades would compete with product work; - standard service networking and security controls are sufficient; - the supported scaling model covers expected growth; - the team wants a clear support and maintenance boundary; - Kafka is infrastructure for the product rather than the product itself. Managed still requires operational discipline from the application team. You still need owners for topic creation, partition growth, schemas, consumer lag, producer failures, replay procedures, retention, and capacity thresholds. A managed broker can be healthy while the application is behind because consumers are lagging. Moving broker infrastructure to a provider does not move business-level stream correctness to the provider. Raff's current managed Kafka product uses **Apache Kafka in KRaft mode**, avoiding ZooKeeper in the service architecture. The current product path also exposes a private-only connection model with TLS/SCRAM and an optional multi-broker HA model. Verify the live [Managed Kafka product page](/products/managed-databases/kafka) for current versions, availability, plan sizes, and pricing before making a production decision. ## Managed Kafka does not remove application-level failure modes Both managed and self-hosted Kafka still need a plan for: - bad producer payloads; - incompatible schema changes; - consumer crashes; - consumer lag; - poison events; - retry storms; - duplicate side effects; - incorrect partition keys; - retention that is too short for replay; - replay after downstream failure; - application behavior during leadership or broker changes. These are workload problems, not just infrastructure problems. Use [Kafka Architecture for Small Teams](/learn/guides/kafka-architecture-small-teams) for the core topic, partition, replication, and retention model. Use [Kafka Consumer Groups, Lag, and Rebalances](/learn/guides/kafka-consumer-groups-lag-rebalances) when the bottleneck is consumer-side operations. ## The decision framework makes the operating model explicit | Decision question | Managed Kafka usually fits when... | Self-hosted Kafka usually fits when... | |---|---|---| | Who owns broker incidents? | Product team should not own the broker host pager | Named platform team already owns Kafka incidents | | Is broker-level control required? | Supported service controls are enough | Hard requirement needs deeper broker/host control | | Who owns upgrades? | Service maintenance model is acceptable | Exact timing/procedure must be team-controlled | | How variable is growth? | Supported resize/HA workflow is valuable | Team has automation for capacity and rebalancing | | What is scarce? | Engineering/operator time | Managed-service budget or service flexibility | | Are service limits acceptable? | Versions, networking, quotas, and controls fit | A hard service limit blocks the architecture | | How mature is on-call? | Kafka infrastructure should not add a pager domain | Kafka runbooks and incident ownership already exist | | Is migration portability important? | Standard Kafka clients/protocol are enough | Infrastructure-level portability is a requirement | A practical decision order is: ```text workload requirement → hard control requirements → availability and recovery expectations → growth pattern → operations maturity → equivalent total cost → managed or self-hosted ``` Do not put price first when the two options transfer very different responsibilities. ## A sustainable choice remains correct during an incident Before choosing self-hosted Kafka, identify who will: - distinguish broker, storage, network, producer, and consumer failures; - replace failed broker infrastructure; - validate replica and partition health; - preserve capacity during recovery; - coordinate consumer catch-up; - execute upgrades or rollback; - restore monitoring and alerting; - validate the business stream after infrastructure recovers. If those responsibilities have no named owner, self-hosting creates an operational dependency without an operating model. Before choosing managed Kafka, ask the opposite questions: does the service expose the controls you need, is the connection model compatible, can you observe the workload signals you still own, and are the scaling and maintenance boundaries acceptable? The best model is not maximum control or minimum operations. It is **enough control for the workload with responsibilities the team can sustain.** :::cluster ## Conclusion Managed Kafka vs self-hosted Kafka is primarily an ownership and total-cost decision. Choose managed Kafka when the service fits the workload and broker operations would otherwise compete with product engineering. Choose self-hosted Kafka when a documented requirement needs deeper control and the team already has the automation, monitoring, upgrades, capacity planning, and incident-response capability to run Kafka reliably. Compare equivalent production assumptions—not a managed cluster against one inexpensive VM. Then use [Kafka Architecture for Small Teams](/learn/guides/kafka-architecture-small-teams) for the topic, partition, consumer, replication, and retention decisions that remain your responsibility in either model. :::cta Explore Managed Databases Compare Raff Managed Kafka with the operational responsibilities your team would keep when self-hosting Kafka. ::: ## Sources - [Apache Kafka Documentation](https://kafka.apache.org/documentation/) - [Apache Kafka Operations](https://kafka.apache.org/documentation/#operations) - [Raff Managed Kafka](/products/managed-databases/kafka) - [Raff Managed Databases](/products/managed-databases) - Product details reviewed: 2026-09-14; use the live product page for current versions, availability, plan sizes, and pricing. --- ### PostgreSQL High Availability: Architecture, Failover & Replication URL: https://rafftechnologies.com/learn/guides/postgresql-high-availability Description: PostgreSQL high availability explained: architecture, synchronous vs asynchronous replication, failover, fencing, read replicas, application reconnects, and managed vs self-hosted HA. PostgreSQL high availability (HA) is an architecture for keeping database service available when the current primary fails. A reliable design needs more than replication: it needs a promotion-ready standby, failure detection, safe failover, protection against split brain, a stable writer endpoint, application reconnect behavior, and a process for restoring redundancy after the incident. For most small teams, the practical question is not simply “do we have a replica?” It is **whether the database can establish one safe writable primary and resume application traffic within the required recovery window**. Raff Technologies supports both operating models: teams can build PostgreSQL HA themselves on cloud VMs or use Managed PostgreSQL when they want the platform to own more of the standby, failover, monitoring, and recovery path. ## PostgreSQL high availability: quick answer A basic PostgreSQL HA architecture normally includes these components: | Component | Purpose | |---|---| | Primary PostgreSQL server | Accepts application writes | | Standby server | Replays WAL and remains ready for promotion | | Replication mode | Defines durability and latency trade-offs | | Failure detector / orchestrator | Determines when the primary is no longer safe to use | | Fencing mechanism | Prevents the old primary from continuing to accept writes | | Writer endpoint | Routes applications to the active primary | | Connection retry logic | Allows clients to recover after the writer changes | | Monitoring | Tracks health, lag, replication, failover, and degraded redundancy | | Backups / PITR | Provides historical recovery outside the HA path | The most important distinction is this: > **Replication copies database state. High availability turns that replica into a safe, tested service-continuity system.** A read replica may be useful without being a valid HA target. A standby becomes part of HA only when promotion, fencing, routing, reconnects, and recovery are deliberately designed and tested. ## PostgreSQL HA architecture starts with the failure boundary High availability should begin with the failure you are trying to survive. Common targets include: - PostgreSQL process failure; - primary VM or host failure; - storage failure affecting the primary; - planned maintenance that requires replacing the writer; - loss of connectivity to one database node; - a zone-level failure when nodes are placed in separate failure domains. Different failures require different architecture. A standby on the same host protects against a PostgreSQL process problem but not host loss. A standby on another VM improves host resilience. A standby in another failure domain can protect against a wider infrastructure failure, but replication latency and network behavior become more important. Before choosing topology, define two targets: - **How long can writes be unavailable?** This shapes the failover and reconnect path. - **How much recent committed data can be lost?** This shapes synchronous versus asynchronous replication and recovery decisions. Those targets are related to RTO and RPO, but HA does not replace backup and disaster-recovery planning. Use [PostgreSQL Replication vs Backups vs Snapshots](/learn/guides/postgresql-replication-vs-backups-vs-snapshots) for the historical recovery layer. ## A common PostgreSQL high-availability architecture A production HA topology can be represented as: ```text Application | | writer endpoint / service discovery v +-------------------+ | Current primary | | PostgreSQL writer | +-------------------+ | | WAL streaming v +-------------------+ | HA standby | | promotion-ready | +-------------------+ Monitoring / orchestrator | detects failure | fences old primary | promotes standby | updates writer route v Application reconnects to new primary ``` The exact implementation may use a managed database service or a self-hosted orchestration layer, but the responsibilities are similar. The architecture is incomplete if it answers only “where is the replica?” It must also answer: 1. Who decides the primary is actually unavailable? 2. Which standby is eligible for promotion? 3. How is the old primary prevented from returning as a writer? 4. How does the writer endpoint move? 5. How do application connections recover? 6. How is a new standby created after failover? If any of those answers depends on manual improvisation during an outage, the system is not yet fully operationalized as HA. ## Synchronous vs asynchronous replication changes the HA trade-off PostgreSQL can use synchronous or asynchronous replication, and the choice affects durability, latency, and availability behavior. ### Asynchronous replication With asynchronous replication, the primary can acknowledge a commit before a standby has confirmed that change. Advantages: - lower write latency; - less dependency on standby/network responsiveness; - simpler performance characteristics across slower links. Trade-off: - if the primary fails before recent WAL reaches the standby, promotion may lose some recently acknowledged transactions. This can be acceptable when a small amount of recent data loss is within the business recovery target. ### Synchronous replication With synchronous replication, commit acknowledgement can wait for the configured synchronous standby condition. Advantages: - reduces the risk that a successfully acknowledged transaction is missing after failover; - makes the standby a stronger candidate for low-data-loss HA. Trade-offs: - write latency includes the synchronous replication path; - a slow or unreachable synchronous standby can affect write availability depending on configuration; - topology and network quality matter more. PostgreSQL's documentation explicitly describes the functional-versus-performance trade-off: synchronous designs improve failover consistency but can impose meaningful latency when the replication path is slow. The correct question is not “is synchronous better?” It is: > **Does the workload need the additional durability enough to accept the latency and availability dependency it creates?** ## HA standby and read replica are different roles A hot standby can serve read-only queries while replaying WAL, which makes it possible to use replicas for both availability and read scaling. But the two roles optimize for different things. | Replica role | Primary objective | Main operating priority | |---|---|---| | HA standby | Become the next writer safely | Promotion readiness, low lag, predictable recovery | | Read replica | Offload application reads | Read capacity and query usefulness | | Reporting replica | Run analytical or long queries | Query availability, sometimes more tolerated lag | | DR replica | Survive a wider failure boundary | Geographic/failure-domain separation and recoverability | A reporting replica may intentionally tolerate more lag or run queries that interfere with replay. That makes it useful for analytics but potentially poor as an immediate failover target. A useful operating rule is: > **Use read replicas to scale reads. Use an HA standby to protect writer continuity. Combine the roles only when lag, query workload, promotion behavior, and recovery are designed for both.** ## PostgreSQL failover is more than promotion Promotion is only one stage in a complete failover. A safe failover path normally includes: ### 1. Detect the primary failure Monitoring or orchestration must determine whether the primary is actually unusable. A short packet-loss event, overloaded host, failed health check, or monitoring outage should not automatically create a second writer. ### 2. Confirm an eligible standby The candidate should be healthy, replaying WAL, and inside the accepted lag or durability threshold. ### 3. Fence the old primary Fencing means preventing the old writer from continuing to accept writes. This may involve powering down the old node, revoking its network path, removing it from routing, or another mechanism appropriate to the platform. ### 4. Promote the standby The selected standby becomes writable. ### 5. Move the writer endpoint Applications need a stable way to find the new writer. Depending on the architecture this may be handled by a managed service endpoint, proxy, virtual IP, load-balancing layer, DNS, or service discovery. ### 6. Reconnect applications Existing PostgreSQL connections do not magically become connections to the new primary. Pools, workers, APIs, and scheduled jobs must reconnect. ### 7. Validate writes The failover is not complete until the application can successfully perform critical database operations against the new writer. ### 8. Restore redundancy After promotion, the system may temporarily have only one healthy database node. A replacement standby needs to be created and replication health restored. A high-availability design therefore needs both a **failover procedure** and a **post-failover recovery procedure**. ## Fencing prevents split brain One of the most important HA concepts is preventing two PostgreSQL primaries from accepting writes independently. Consider this failure: ```text Primary A loses network connectivity ↓ Standby B is promoted ↓ Applications begin writing to B ↓ Primary A reconnects and still believes it is primary ``` If A can accept new writes after B is promoted, the database can develop two independent histories. PostgreSQL streaming replication does not by itself solve this external coordination problem. A complete HA system therefore needs a method to ensure that the previous writer cannot return to service until it has been safely rejoined, rebuilt, or otherwise reconciled. For self-hosted HA, this is one reason teams commonly use an orchestration layer rather than treating `pg_ctl promote` as the entire failover design. ## Self-hosted PostgreSQL HA needs an orchestration layer PostgreSQL provides replication, standby, promotion, and recovery primitives, but a self-hosted deployment still needs a system around them for automatic HA. Common responsibilities include: - health checking; - leader/primary election or authority; - promotion decisions; - fencing or node isolation; - writer endpoint updates; - standby reconfiguration; - topology state; - alerting; - operator workflows after failover. Self-hosted ecosystems often use tools such as Patroni, repmgr, Pgpool-II, HAProxy, Keepalived, or cloud-native service-discovery components in different combinations. These tools do not all solve the same problem, so architecture should be based on the exact responsibilities required rather than selecting one product name and assuming HA is complete. For a small team, the operational question is important: **who maintains the HA control plane itself?** If the team cannot confidently test and repair the orchestration layer during an outage, a managed HA service may be the lower-risk operating model. ## Replication lag is a failover-readiness signal Replication lag is the distance between the primary's current state and what the standby has received or replayed. For HA, lag is important because promotion turns the standby's current state into the authoritative writable state. Useful questions include: - Is WAL still reaching the standby? - Is replay keeping up under normal write traffic? - Is lag increasing steadily? - Are standby queries delaying WAL replay? - Is the candidate still within the acceptable failover threshold? - Would the system allow promotion at the current replication state? Lag should be interpreted with the replication mode. With asynchronous replication, increasing lag can directly increase the amount of recent data at risk during primary failure. With synchronous replication, lag and standby health can instead affect write performance or availability depending on configuration. Do not treat lag as a single dashboard number. The underlying cause may be disk throughput, network latency, CPU pressure, long-running standby queries, checkpoint behavior, or primary workload growth. ## Application reconnect behavior determines whether HA works for users A database can complete failover correctly while the application still appears down. When the writer changes, applications may experience: - broken database connections; - interrupted transactions; - connection-pool errors; - workers retrying simultaneously; - uncertain transaction outcome near commit time; - caches or services still pointing at old state. A production HA plan should define: - **writer discovery:** how clients locate the current primary; - **retry policy:** which failures should trigger reconnects; - **backoff:** how clients avoid a reconnect storm; - **transaction handling:** what happens when the connection disappears during commit; - **idempotency:** whether retrying an operation can create duplicate side effects; - **pool recovery:** how dead connections are discarded; - **health checks:** whether application health tests include database writes where appropriate. Connection-pool tuning itself belongs in [PostgreSQL Connection Pooling: PgBouncer, Limits & SaaS Workloads](/learn/guides/postgresql-connection-pooling-pgbouncer). The HA requirement is that the pool can recover cleanly when the writer endpoint changes. **Database HA is complete only when application writes resume safely against the new primary.** ## PostgreSQL HA does not replace backups or PITR A standby follows the primary's current state. That is useful for availability, but it also means valid-looking destructive changes can propagate. Examples include: - accidental `DELETE` or `DROP` operations; - incorrect migrations; - application bugs that corrupt data; - compromised credentials performing destructive writes. HA may keep the database online through those events while preserving the wrong state perfectly. That is why production PostgreSQL should treat these as separate controls: | Control | Main purpose | |---|---| | HA standby | Fast continuity after primary failure | | Read replica | Read scaling | | Backup | Independent recovery copy | | PITR | Restore to a point before an unwanted change | | DR architecture | Recover from a wider service or location failure | Use [PostgreSQL Replication vs Backups vs Snapshots](/learn/guides/postgresql-replication-vs-backups-vs-snapshots) for the full recovery model. ## When PostgreSQL high availability is worth the complexity Not every production database needs automatic HA. | Requirement | Recommended posture | |---|---| | Several hours of database downtime are acceptable | Prioritize tested backup/recovery first | | Primary failure must recover quickly | Use a promotion-ready standby and tested failover path | | Read traffic is the main constraint | Add read replicas; do not assume they are HA targets | | Continuity and read scaling both matter | Separate HA and read-scaling roles unless intentionally combined | | Application cannot reconnect safely | Fix reconnect/retry behavior before relying on automatic failover | | Team cannot operate fencing/routing/orchestration | Prefer managed HA when the service fits | | Custom topology or host-level control is mandatory | Self-host with an explicit orchestration and testing model | Small teams should usually sequence reliability work in this order: 1. establish reliable backups and PITR; 2. prove restore procedures; 3. make connection recovery and retries safe; 4. define availability and data-loss targets; 5. add HA when the continuity requirement justifies the extra moving parts. Adding a standby before proving recovery can create the appearance of reliability without covering destructive-data failures. ## Managed vs self-hosted PostgreSQL HA The PostgreSQL concepts stay the same, but the ownership boundary changes significantly. | HA responsibility | Managed PostgreSQL | Self-hosted PostgreSQL | |---|---|---| | Standby provisioning | Platform-managed within service scope | Team-owned | | Replication configuration | Platform-managed | Team-owned | | Failure detection | Platform-managed when HA is enabled | Team/orchestrator-owned | | Promotion | Platform-managed | Team/orchestrator-owned | | Old-primary fencing | Platform HA layer | Team-owned | | Writer routing | Managed endpoint behavior | Team-designed | | Application reconnects | Application team | Application team | | Query/schema correctness | Application team | Application team | | Backup/PITR | Separate recovery layer | Team-designed unless provided separately | | Failover validation | Shared operating responsibility | Team-owned | Raff's live Managed PostgreSQL product currently describes HA as a **primary plus synchronous standby in separate zones with automatic failover**. The product page also lists PostgreSQL 14–16, PITR, read replicas, connection pooling, monitoring, and private networking as current service capabilities. Because product versions, pricing, and service limits change faster than editorial guidance, verify the live [Raff Managed PostgreSQL page](/products/managed-databases/postgresql) before making a production decision. For self-hosted PostgreSQL on a [Raff VM](/products/raff-vm), the team gets deeper control over software, topology, storage, and orchestration choices, but also owns patching, monitoring, failover automation, fencing, routing, standby rebuilds, backups, and incident response. ## PostgreSQL HA testing checklist An HA diagram is not evidence that failover works. A useful failover exercise should prove the full service path: - [ ] Primary failure is detected inside the expected window. - [ ] The intended standby is healthy and eligible for promotion. - [ ] Replication state is inside the accepted threshold. - [ ] The old primary cannot continue accepting writes. - [ ] The standby is promoted successfully. - [ ] The writer endpoint moves to the new primary. - [ ] Applications establish new connections. - [ ] Connection pools discard stale sessions. - [ ] In-flight transactions follow the expected retry behavior. - [ ] Background jobs and workers recover safely. - [ ] Critical application writes succeed after failover. - [ ] Monitoring identifies the new primary correctly. - [ ] A replacement standby is created. - [ ] Redundancy is restored. - [ ] The measured interruption matches the availability target. Planned failover exercises are valuable because they test assumptions before a real infrastructure failure makes the test mandatory. The strongest evidence of PostgreSQL HA is not “we have a replica.” It is **a recently validated transition from one writable primary to another with correct application behavior afterward.** :::cluster ## Conclusion PostgreSQL high availability is an architecture for safe writer continuity, not simply a replication checkbox. A production HA design needs a clear failure boundary, an appropriate synchronous or asynchronous replication model, a promotion-ready standby, reliable failure detection, fencing, writer routing, application reconnect logic, lag monitoring, and a process for rebuilding redundancy after failover. Use read replicas for read scaling unless they are deliberately qualified as failover targets. Keep backups and PITR as a separate historical recovery layer. For small teams, choose managed HA when operating the failover control plane would consume engineering capacity without creating product value; self-host when deeper control is a real requirement and the team can own the entire operating model. :::cta Explore Managed Databases Compare Raff Managed PostgreSQL with self-hosted PostgreSQL when deciding who should own standby operations, failover, backups, and monitoring. ::: ## Sources - [PostgreSQL: High Availability, Load Balancing, and Replication](https://www.postgresql.org/docs/current/high-availability.html) - [PostgreSQL: Failover](https://www.postgresql.org/docs/current/warm-standby-failover.html) - [PostgreSQL: Hot Standby](https://www.postgresql.org/docs/current/hot-standby.html) - [PostgreSQL: Synchronous Replication](https://www.postgresql.org/docs/current/warm-standby.html#SYNCHRONOUS-REPLICATION) - [Raff Managed PostgreSQL](/products/managed-databases/postgresql) - Product details reviewed: 2026-09-14; verify the live product page for current versions, pricing, availability, and service limits. --- ### MongoDB vs MySQL: Differences, Performance & Use Cases URL: https://rafftechnologies.com/learn/guides/mongodb-vs-mysql Description: Compare MongoDB vs MySQL across data model, performance, transactions, JSON, scaling, use cases, migration, and operations to choose the right database. MongoDB vs MySQL is primarily a **data-model decision**: MongoDB is document-oriented, while MySQL is relational. MongoDB fits applications where one bounded document is the natural unit of data. MySQL fits applications where relationships, constraints, joins, SQL reporting, and established MySQL ecosystems are central. Both databases can run serious production workloads. Both support indexes, transactions, replication, JSON-style data, backups, and large datasets. The useful question is not which one is universally faster or newer. It is **which model matches the application's real read, write, relationship, consistency, and operating requirements with less long-term friction**. Raff Technologies supports MySQL through its managed database platform and supports self-hosted database workloads on Raff VMs. This guide focuses on the database decision first; hosting should follow the data model rather than drive it. ## MongoDB vs MySQL: quick answer | Decision area | MongoDB | MySQL | |---|---|---| | Primary model | Documents and collections | Relational tables and rows | | Best fit | Document-first applications | Relationship-heavy applications | | Relationships | Embedding or references | Foreign keys and joins | | Transactions | Single-document atomicity + multi-document transactions | InnoDB transactions across related rows/tables | | Flexible fields | Native document structure | JSON type inside a relational schema | | Query language | MongoDB Query Language + aggregation | SQL | | Reporting | Possible, but model-dependent | Strong fit for relational SQL reporting | | Horizontal distribution | Native sharding model | Usually requires a more specialized architecture | | Common ecosystem fit | MongoDB-native stacks, catalogs, content, flexible aggregates | WordPress, WooCommerce, Laravel/PHP, business apps, relational SaaS | **Choose MongoDB** when the application naturally stores and retrieves self-contained documents with nested data and relatively limited cross-record relationships. **Choose MySQL** when the application depends on related entities, foreign keys, joins, SQL reporting, vendor compatibility, or a mature MySQL ecosystem. ## The main difference is document vs relational modeling MongoDB stores BSON documents inside collections. A document can contain nested objects and arrays, so related data that belongs to one aggregate can live together. MySQL stores data in relational tables. Relationships between entities are represented explicitly through keys, constraints, and joins. InnoDB, the default storage engine in modern MySQL deployments, provides transactional behavior, row-level locking, crash recovery, and foreign-key support. Consider an ecommerce order. A document-first design might store the order, shipping address, and line items together: ```text order customer_id status shipping_address line_items[] ``` A relational design might separate those entities: ```text orders order_items customers addresses products payments ``` Neither model is automatically better. The right model depends on whether those pieces behave as one bounded aggregate or whether they need to be independently related, constrained, queried, and updated across the system. ## MongoDB is stronger when one document is the natural business unit MongoDB is a good fit when most product behavior happens inside a bounded document. Common examples include: - content blocks with type-specific fields; - product catalogs with highly variable attributes; - configuration documents; - workflow definitions; - event payloads; - imported third-party records that preserve their original structure; - profiles with optional nested sections; - applications already designed around MongoDB-style document access. Embedding related data can reduce extra reads because the application can retrieve one document instead of reconstructing an aggregate from several tables or references. MongoDB also supports multi-document transactions, but that should not be treated as a reason to ignore document design. If ordinary application behavior repeatedly needs many cross-document transactions, many-to-many references, and relationship-heavy reporting, the workload may be fighting the document model. A production MongoDB schema still needs discipline: - document validation; - embedding vs reference rules; - index ownership; - limits on document growth; - duplicated-field update rules; - retention and deletion behavior; - backup and recovery procedures. Flexible schema does not mean uncontrolled schema. ## MySQL is stronger when relationships are part of the product model MySQL is a strong fit when the application is naturally relational or when its ecosystem already expects MySQL. Typical examples include: - WordPress and WooCommerce; - Laravel and PHP applications; - ecommerce systems; - users, teams, permissions, and roles; - orders, invoices, payments, and inventory; - subscriptions and billing records; - business software with relational reporting; - vendor applications certified for MySQL. Foreign keys and joins let the database represent and enforce relationships explicitly. A payment can reference an invoice. An order can reference a customer. A permission can reference a role and user without duplicating the full related record in every location. This matters when data integrity across entities is part of the business rule rather than merely an application convenience. ## MongoDB vs MySQL performance: neither is universally faster The query `MongoDB vs MySQL performance` is common, but there is no useful universal benchmark winner. Performance depends on: - schema or document design; - indexes; - query shape; - joins or aggregation pipelines; - transaction scope; - working-set size; - concurrency; - storage latency; - memory; - network path; - connection behavior; - replication configuration; - the exact versions and settings being tested. | Workload pattern | MongoDB may have an advantage when... | MySQL may have an advantage when... | |---|---|---| | Read one complete object | Data is already embedded in one indexed document | Data is already in one table or simple indexed joins | | Relationship-heavy query | Usually requires references/aggregation | Joins and relational indexes match the model | | Variable attributes | Fields genuinely vary by document | Variation is limited to bounded metadata in JSON | | Multi-record consistency | Possible with multi-document transactions | Relational transaction is the natural model | | SQL analytics/reporting | Requires compatible tooling/modeling | Native SQL ecosystem fits naturally | | Native document sharding | Strong fit when shard key is well designed | Different distributed architecture required | A model mismatch usually matters more than the database brand. MongoDB becomes awkward when most requests reconstruct relationships across collections. MySQL becomes awkward when a team stores the whole domain in uncontrolled JSON blobs and then expects relational constraints to protect it. If performance is the reason for considering a migration, test representative production-like data and queries before changing engines. ## Transactions differ more in modeling than in simple feature checklists Both MongoDB and MySQL support transactions, so “MongoDB has no transactions” is outdated. MongoDB provides atomic operations within a single document and supports transactions across multiple documents, collections, databases, and sharded environments where supported. MySQL InnoDB provides ACID transactions across related rows and tables, with relational constraints and locking behavior built around that model. The practical difference is how often the application needs a transaction boundary wider than one natural record. If most business operations affect one aggregate, MongoDB's document model can make the common case simple. If ordinary operations routinely coordinate users, accounts, invoices, payments, inventory, permissions, and other independent entities, MySQL's relational model is often easier to reason about. ## MySQL JSON can cover flexible metadata without replacing the relational model MySQL supports a native JSON type and JSON functions. That means variable fields alone are not a reason to move an application to MongoDB. A common hybrid pattern is: ```text id account_id status created_at metadata_json ``` Core fields remain normal relational columns while optional metadata lives in JSON. This pattern works well when: - most of the application is relational; - only selected fields vary; - SQL reporting still matters; - ownership and relationships should remain explicit; - one backup and operating model is preferable. Do not hide critical billing, authorization, relationship, uniqueness, or frequently filtered fields inside JSON merely to avoid schema design. MongoDB becomes more compelling when document structure is not a small metadata exception but the dominant data model of the application. ## Scaling differs because the engines expect different architectures MongoDB includes a native sharding architecture for horizontally distributing documents across shards. This can be useful when a workload genuinely requires horizontal distribution and has a shard key that spreads traffic and data well. MySQL applications typically scale first through: - query and index optimization; - more memory or compute; - stronger storage; - caching; - connection tuning; - read replicas; - workload separation. More distributed MySQL architectures exist, but they change the operating model and should not be treated as the default path for a normal InnoDB application. Before choosing a database for future scale, identify the current or expected bottleneck. “We may need to scale later” is too vague to justify a data-model choice. ## MongoDB vs MySQL for common application types | Application type | Usually stronger starting point | Why | |---|---|---| | WordPress / WooCommerce | MySQL | Ecosystem and software compatibility | | Laravel/PHP business app | MySQL | Relational model and ecosystem fit | | Billing/subscription system | MySQL | Strong relationships and consistency rules | | Inventory/order system | MySQL | Joins, constraints, transaction-heavy relationships | | Flexible product catalog | MongoDB can fit well | Variable document attributes and bounded aggregates | | CMS/content blocks | MongoDB can fit well | Nested, variable content structures | | Workflow/configuration records | MongoDB can fit well | Document-shaped data | | Relational SaaS with teams/roles/payments | MySQL | Relationship-heavy domain | | Event payload archive | MongoDB can fit | Naturally document-shaped events | These are starting points, not absolute rules. Existing architecture, team expertise, integrations, reporting, and operating maturity can change the decision. ## Migration between MongoDB and MySQL is a data-model migration Changing MongoDB to MySQL—or MySQL to MongoDB—is rarely a simple database-engine swap. A MongoDB-to-MySQL migration may require: - breaking documents into normalized tables; - defining primary and foreign keys; - resolving duplicated fields; - redesigning indexes; - rewriting queries and aggregation logic; - translating transaction boundaries; - validating referential integrity. A MySQL-to-MongoDB migration may require: - deciding what to embed; - deciding what remains referenced; - handling duplicated fields; - converting joins into application or aggregation logic; - redefining uniqueness and consistency rules; - redesigning reporting workflows. Because the data model changes, migrate only when a documented product, scale, compatibility, or operational requirement justifies the engineering and recovery risk. ## Managed vs self-hosted changes operations, not the database model After choosing the engine, decide who should operate it. A managed database can transfer more responsibility for provisioning, patching, backups, monitoring, maintenance, and availability to the platform. The application team still owns schema design, queries, indexes, credentials, migrations, capacity decisions, and validation during recovery. A self-hosted database gives deeper operating-system and database control but leaves the full operating model with the team. Raff provides a live [Managed MySQL](/products/managed-databases/mysql) path. For MongoDB, verify current managed availability on the live [Managed Databases](/products/managed-databases) page before depending on a managed service; MongoDB can also be operated as a self-hosted workload on a [Raff VM](/products/raff-vm). For the hosting decision itself, use [Managed vs Self-Hosted Databases](/learn/guides/managed-vs-self-hosted-databases). ## Decision checklist Choose MongoDB when most of these statements are true: - [ ] One document is the natural business aggregate. - [ ] Nested data is usually read and written together. - [ ] Fields vary significantly across records. - [ ] Cross-record relationships are limited or manageable. - [ ] Document-oriented access is already part of the application design. - [ ] Native document sharding is a concrete requirement. Choose MySQL when most of these statements are true: - [ ] The domain contains many related entities. - [ ] Foreign keys and joins are useful business safeguards. - [ ] SQL reporting matters. - [ ] WordPress, WooCommerce, Laravel, PHP, or vendor software expects MySQL. - [ ] Multi-row transactional consistency is common. - [ ] The team already operates MySQL reliably. If neither side is obvious, model one or two representative product workflows in both styles before choosing. :::cluster ## Conclusion MongoDB vs MySQL is not a contest between a modern database and an old database. It is a choice between two different modeling and operating approaches. Choose MongoDB when documents are the natural unit of product data and most behavior stays inside those bounded aggregates. Choose MySQL when relationships, foreign keys, joins, SQL, vendor compatibility, and relational reporting are central. Do not select or migrate an engine because of generic performance claims. Model representative data, test representative queries, define recovery requirements, and choose the database whose normal operating model matches the application. If PostgreSQL is also still under consideration, use [MySQL vs PostgreSQL vs MongoDB](/learn/guides/mysql-vs-postgresql-vs-mongodb) for the broader three-engine decision. :::cta Explore Managed Databases Choose the database model first, then compare the managed and self-hosted operating paths available for your workload. ::: ## Sources - [MongoDB: Data Modeling](https://www.mongodb.com/docs/manual/data-modeling/) - [MongoDB: Document Relationships](https://www.mongodb.com/docs/manual/applications/data-models-relationships/) - [MongoDB: Transactions](https://www.mongodb.com/docs/manual/core/transactions/) - [MySQL 8.4: InnoDB Transaction Model](https://dev.mysql.com/doc/refman/8.4/en/innodb-transaction-model.html) - [MySQL 8.4: Foreign Key Constraints](https://dev.mysql.com/doc/refman/8.4/en/create-table-foreign-keys.html) - [MySQL 8.4: JSON Data Type](https://dev.mysql.com/doc/refman/8.4/en/json.html) - [Raff Managed MySQL](/products/managed-databases/mysql) - [Raff Managed Databases](/products/managed-databases) - Product details reviewed: 2026-09-14; verify the live product pages for current availability, versions, limits, and pricing. --- ### Kubernetes Load Balancer vs Ingress Controller: Differences & When to Use Each URL: https://rafftechnologies.com/learn/guides/kubernetes-load-balancer-vs-ingress-controller Description: Compare Kubernetes LoadBalancer Services vs Ingress controllers, including routing, TLS, TCP/UDP, public endpoints, Gateway API, and when to use each. Kubernetes load balancer vs ingress is not a simple either/or choice. A `LoadBalancer` Service gives one Kubernetes Service an external traffic path, while an Ingress controller routes HTTP/HTTPS traffic across one or more Services using hostnames, URL paths, and TLS rules. The two often work **together**. An Ingress controller itself commonly needs a public entry path, which may be provided by a load balancer. Raff Technologies recommends starting with the traffic requirement first: protocol, routing rules, public endpoint count, TLS ownership, and failure boundary. ## Kubernetes Load Balancer vs Ingress: quick answer | Question | LoadBalancer Service | Ingress controller | |---|---|---| | Exposes one Service directly | Yes | Indirectly through routes | | Best fit for HTTP/HTTPS routing | Limited | Yes | | Hostname routing | No | Yes | | Path routing | No | Yes | | Shared entry for multiple web Services | No | Yes | | Generic TCP/UDP exposure | Often a strong fit | Not part of standard Ingress API | | Centralized TLS for several web apps | Provider/workload dependent | Common use case | | Requires an Ingress controller | No | Yes | | Can coexist with a load balancer | Yes | Yes — commonly does | **Use a `LoadBalancer` Service** when one workload needs its own external endpoint, especially for TCP, UDP, or a service that does not benefit from shared HTTP routing. **Use an Ingress controller** when multiple HTTP/HTTPS Services can share one public entry and need hostname, path, or centralized TLS routing. **Do you need a load balancer with Kubernetes Ingress?** Often, yes. The Ingress controller must still be reachable from outside the cluster, so many environments place a load balancer or another edge path in front of it. For the broader Service model, see [Kubernetes Services Explained: Ingress and Load Balancers](/learn/guides/kubernetes-services-ingress-load-balancers). ## Kubernetes LoadBalancer Services provide direct external Service exposure A Kubernetes Service with `type: LoadBalancer` requests an external load-balancing implementation from the environment when one is available. The traffic model is conceptually direct: ```text Client ↓ External load-balancing path ↓ LoadBalancer Service ↓ Eligible Pods ``` The Service still represents a changing set of backend Pods. The difference is that the environment can attach an externally reachable address or load-balancing resource to that Service. This model is useful when one workload genuinely needs its own external endpoint. Common examples include: - TCP services that are not HTTP-based; - UDP services where the implementation supports the required protocol; - one public application that does not need host- or path-based multiplexing; - a service that benefits from a dedicated traffic boundary; - workloads whose client protocol does not fit the Ingress API. A `LoadBalancer` Service does **not** provide application-layer routing by hostname or URL path. It exposes Service ports and relies on the load-balancing implementation to deliver traffic to the Service backends. Kubernetes documents that the exact external load-balancer behavior is implementation-specific. Depending on the environment, the path may involve NodePorts or direct routing. ## Ingress controllers consolidate HTTP and HTTPS routing Ingress solves a different problem. It defines HTTP and HTTPS routing rules to Kubernetes Services. A typical architecture looks like this: ```text Internet ↓ Public entry ↓ Ingress controller ↓ Host/path rules ├── app.example.com → web Service ├── api.example.com → api Service └── /admin → admin Service ``` The backend Services can remain `ClusterIP`, so they do not each need a public endpoint. Ingress can provide or coordinate capabilities such as: - hostname routing; - path routing; - TLS termination; - name-based virtual hosting; - shared HTTP/HTTPS entry for multiple Services; - controller-specific traffic features. An Ingress resource alone does nothing. An Ingress controller must watch those resources and implement the routing behavior. This is why “load balancer vs ingress controller” can be misleading. In many production clusters, the actual path is: ```text External load-balancing path ↓ Ingress controller ↓ ClusterIP Services ↓ Pods ``` The better question is not which component wins. It is **which layer should own external exposure and which layer should own HTTP routing**. ## Is Kubernetes Ingress a load balancer? Not exactly. A Kubernetes Ingress resource is a set of HTTP/HTTPS routing rules. The Ingress controller is the software that implements those rules. That controller may itself perform reverse-proxy and load-balancing behavior across backend Pods, but it still needs a way to receive traffic from outside the cluster. So the layers are different: ```text External reachability -> load balancer / public edge HTTP routing -> Ingress controller Backend discovery -> Kubernetes Service Workload -> Pods ``` Treating these layers separately makes troubleshooting and architecture reviews much clearer. ## Load balancers and Ingress controllers solve different traffic problems | Requirement | LoadBalancer Service | Ingress controller | |---|---|---| | Give one Service an external endpoint | Strong fit | Possible through controller routing, but indirect | | HTTP hostname routing | No native Service feature | Yes | | HTTP path routing | No native Service feature | Yes | | Centralized TLS for several web apps | Not by Service routing alone | Common use case | | Generic TCP exposure | Strong fit where supported | Not part of standard Ingress API | | Generic UDP exposure | Strong fit where supported | Not part of standard Ingress API | | Share one web entry across many Services | Poor fit if each Service gets its own endpoint | Strong fit | | Separate traffic boundary per workload | Strong fit | Requires separate controller/listener design if desired | | Controller-specific web routing features | No | Yes | | Works without an Ingress controller | Yes, if LoadBalancer integration exists | No | Ingress is specifically designed around HTTP and HTTPS. Standard Ingress does not model arbitrary TCP or UDP exposure. That makes **protocol** the first architecture decision. If the client speaks HTTP or HTTPS, shared application-aware routing may be valuable. If the client uses another protocol, a dedicated Service exposure path is often easier to reason about. ## Shared Ingress routing reduces public endpoint sprawl Consider a small SaaS cluster with three web-facing components: ```text frontend api auth ``` A dedicated exposure model can look like: ```text frontend → external endpoint A api → external endpoint B auth → external endpoint C ``` An Ingress model can instead use: ```text one public web entry ↓ Ingress controller ├── app.example.com → frontend ├── api.example.com → api └── auth.example.com → auth ``` This can simplify DNS, TLS, firewall policy, and the list of internet-facing resources. The trade-off is concentration. The Ingress controller becomes part of the request path for every application routed through it. It must therefore be monitored, sized, replicated when required, and upgraded deliberately. Consolidation is useful when it removes unnecessary public interfaces. It is harmful when one shared controller becomes an operational dependency that the team does not understand. ## Dedicated LoadBalancer Services keep some traffic paths simpler Ingress is not automatically the simpler option. A dedicated `LoadBalancer` Service can be cleaner when one workload needs one external protocol endpoint and there is no benefit from shared HTTP routing. Examples include: - a TCP service with its own port; - a UDP workload where supported; - a public service that should have an independent lifecycle from the web ingress layer; - one external application with no hostname/path routing requirement; - infrastructure where the load-balancing implementation provides a workload-specific capability. The path is shorter: ```text Client ↓ LoadBalancer Service ↓ Pods ``` The cost trade-off is provider-specific. Some environments create a separately billed load balancer for every `LoadBalancer` Service; others price or implement public entry differently. Do not assume hyperscaler pricing or topology applies everywhere. Count the actual external resources your cluster creates and verify current platform pricing before using cost as the deciding factor. ## TLS ownership changes the design With Ingress, multiple HTTP/HTTPS applications can commonly terminate TLS at the shared ingress layer: ```text HTTPS client ↓ Ingress TLS termination ↓ Host/path routing ↓ ClusterIP Service ``` This can centralize certificate handling and web traffic policy. A dedicated `LoadBalancer` Service does not automatically define where TLS terminates. TLS might terminate: - inside the application Pod; - at the external load-balancing implementation; - at another proxy in front of the Service; - through protocol passthrough to the backend. The correct choice depends on end-to-end encryption requirements, client certificates, protocol passthrough, and how the team wants to manage certificates. Ingress controller implementations differ, so review the selected controller's own documentation instead of assuming identical TLS behavior across controllers. ## Kubernetes LoadBalancer vs Ingress decision framework Use these five questions: | Decision question | Choose a LoadBalancer Service when | Choose an Ingress controller when | |---|---|---| | What protocol is exposed? | TCP/UDP or another non-HTTP path | HTTP/HTTPS | | How many web Services need public access? | One Service with no routing benefit | Several Services can share an entry | | Is host/path routing required? | No | Yes | | Should the workload have its own public boundary? | Yes | Not necessarily | | Where should TLS and web routing policy live? | Workload/provider-specific path | Shared controller layer | Use this sequence: 1. **Keep the Service private unless external clients need it.** Start with `ClusterIP` for internal workloads. 2. **Identify the protocol.** HTTP/HTTPS can use Ingress or Gateway-style routing; non-HTTP protocols may need another exposure model. 3. **Count the required public entry points.** Do not create one per internal Service by habit. 4. **Choose the routing owner.** Decide whether TLS, hostname, and path policy belong in a shared controller or a workload-specific path. 5. **Define the failure boundary.** A shared ingress layer affects several applications; a dedicated endpoint isolates that concern but increases infrastructure count. The decision is not “which Kubernetes object is better?” It is “which traffic boundary matches the workload?” ## Ingress remains supported while Gateway API is the newer direction The Kubernetes Ingress API is stable but frozen: it is not being expanded with new features. Gateway API is the newer Kubernetes networking model for more expressive and role-oriented routing. It introduces resources such as `GatewayClass`, `Gateway`, and `HTTPRoute` and can separate infrastructure ownership from application-route ownership more clearly. That does **not** mean existing Ingress deployments need to be replaced automatically. For an existing cluster with a stable, supported Ingress controller, there may be no business reason to migrate only because the API is frozen. For new architectures that need advanced routing, multiple protocol types, clearer ownership boundaries, or less dependence on controller-specific annotations, Gateway API deserves evaluation before standardizing on new Ingress configuration. ## How this maps to Raff Kubernetes The Kubernetes traffic model does not change just because the cluster runs on Raff. The same design questions still apply: which Services should stay private, which workloads need direct external exposure, and which HTTP/HTTPS applications can share a routing layer. For current Raff Kubernetes networking, public-entry options, supported integrations, and pricing, use the live [Raff Kubernetes](/products/kubernetes) and [VPC](/products/vpc) pages as the source of truth rather than hardcoding product assumptions into application architecture. A typical pattern is still: ```text Internet ↓ public entry / Ingress layer ↓ private Kubernetes Services ↓ Pods ``` or, when one workload needs a dedicated external path: ```text Internet ↓ dedicated LoadBalancer Service ↓ Pods ``` The Raff-specific rule is the same as the general Kubernetes rule: expose only the traffic path the workload actually needs. ## Production reviews should trace the complete request path Before approving either design, write down the complete client-to-Pod path. For a LoadBalancer Service: ```text Client ↓ External address ↓ LoadBalancer Service ↓ EndpointSlices ↓ Ready Pods ``` For Ingress: ```text Client ↓ Public entry ↓ Ingress controller ↓ Ingress host/path rule ↓ ClusterIP Service ↓ EndpointSlices ↓ Ready Pods ``` Then verify ownership at every hop: - Which component owns the public address? - Where does TLS terminate? - Which resource defines routing? - Which Service receives traffic? - Which Pods are ready endpoints? - Which NetworkPolicies permit the path? - What happens when the ingress controller loses a replica? - What happens when the backend loses a replica? - Which metrics and logs identify the failed layer? A diagram with more boxes is not automatically more resilient. Reliability improves when each box has a defined responsibility and failure behavior. For related diagnosis, use [Kubernetes DNS and Service Discovery Troubleshooting](/learn/guides/kubernetes-dns-service-discovery-troubleshooting) and [Kubernetes Network Policies for Small Teams](/learn/guides/kubernetes-network-policies-small-teams). ## Conclusion Use a Kubernetes `LoadBalancer` Service when one Service needs its own external endpoint, especially for non-HTTP protocols or an intentionally isolated traffic boundary. Use an Ingress controller when multiple HTTP/HTTPS Services benefit from shared hostname, path, and TLS routing behind one public entry. In many production clusters, the correct architecture uses **both**: a load-balancing or edge layer exposes the Ingress controller, and the controller routes traffic to private `ClusterIP` Services. Choose based on protocol, routing requirements, endpoint count, TLS ownership, and failure isolation—not on which Kubernetes object is more popular. :::cta cluster Deploy Raff Kubernetes, then choose dedicated or shared public routing based on the protocol and workload boundary. ::: ## Sources - [Kubernetes Service](https://kubernetes.io/docs/concepts/services-networking/service/) - [Kubernetes Ingress](https://kubernetes.io/docs/concepts/services-networking/ingress/) - [Kubernetes Gateway API](https://kubernetes.io/docs/concepts/services-networking/gateway/) - Product details reviewed: 2026-09-14; verify Raff networking and pricing on the live product pages. --- ### PostgreSQL vs MySQL: Differences, Performance & Use Cases URL: https://rafftechnologies.com/learn/guides/postgresql-vs-mysql Description: Compare PostgreSQL vs MySQL across performance, JSON, transactions, extensions, replication, use cases, migration, and managed hosting to choose the right database. PostgreSQL vs MySQL is a choice between two mature relational databases that overlap heavily but differ in extensibility, data types, SQL behavior, ecosystem fit, and some operational patterns. For a new application, **choose PostgreSQL when you expect complex relational queries, PostgreSQL-specific extensions, advanced data types, JSONB-heavy workloads, geospatial features, or a PostgreSQL-centered application stack. Choose MySQL when the application ecosystem already expects MySQL, especially WordPress, WooCommerce, many PHP applications, or vendor software certified for MySQL.** Neither database is universally faster, simpler, or more scalable. Schema design, indexes, query shape, concurrency, storage, connection behavior, replication, and operator experience usually matter more than the database name alone. Raff Technologies provides managed PostgreSQL and managed MySQL alongside self-hosted database options on cloud VMs. This guide focuses on choosing the engine first, then deciding whether managed or self-hosted operation fits the team. ## PostgreSQL vs MySQL: quick comparison | Decision area | PostgreSQL | MySQL | |---|---|---| | Core model | Relational with strong extensibility and additional data types | Relational, commonly using InnoDB | | SQL and relational features | Strong fit for complex relational workloads | Strong fit for mainstream transactional web workloads | | JSON | `json` and `jsonb`; JSONB supports indexing and operators | Native JSON type and JSON functions | | Extensions | Broad extension model | Plugin/component ecosystem with a different scope | | Geospatial | PostGIS ecosystem when available | Spatial data types and functions available | | Transactions | ACID transactions with multiple isolation levels | InnoDB ACID transactions with multiple isolation levels | | Concurrency model | MVCC-based | InnoDB MVCC plus locking | | Replication | Physical and logical replication options | Binary-log-based replication and related topologies | | Common ecosystem fit | SaaS, data-rich apps, extension-driven workloads | WordPress, WooCommerce, PHP, established MySQL software | | Managed hosting | Widely available | Widely available | | Best reason to choose | PostgreSQL-specific capabilities or existing standard | Ecosystem compatibility or existing MySQL standard | The first question should be **“what does the application need that would be expensive to change later?”** not “which database wins a benchmark?” ## PostgreSQL and MySQL are more alike than many comparisons suggest Both databases support the fundamentals expected from a production relational database: - tables and relational schemas; - SQL queries; - primary and foreign keys; - indexes; - joins; - transactions; - constraints; - JSON data; - replication; - backups and recovery workflows; - managed and self-hosted deployment models. That means a normal CRUD application can often run well on either engine. The differences matter most when the product relies on a capability that is deeply tied to one database, such as a PostgreSQL extension, a vendor-certified MySQL dependency, a particular JSON/query pattern, or an existing operational standard. For a broader three-engine comparison that also includes document databases, use [MySQL vs PostgreSQL vs MongoDB](/learn/guides/mysql-vs-postgresql-vs-mongodb). ## Choose PostgreSQL when database capabilities are part of the product design PostgreSQL is often a natural fit when the application uses the database as more than a simple persistence layer. Common signals include: - complex relational models; - advanced joins and reporting queries; - JSONB fields that need meaningful indexing and querying; - geospatial workloads through PostGIS where supported; - vector search through an approved extension such as pgvector where supported; - custom types or extension-driven capabilities; - logical replication requirements; - an existing PostgreSQL-centered development stack; - a team already experienced with PostgreSQL operations. The extension model is one of PostgreSQL's clearest differentiators. Extensions can add database objects and capabilities without treating every additional feature as application-side logic. That flexibility is useful only when the application needs it. It is not a reason to migrate a stable MySQL application by itself. ### PostgreSQL is a good default for many new SaaS applications—but not automatically A new SaaS product often contains users, teams, permissions, subscriptions, invoices, application data, audit records, and reporting requirements. PostgreSQL can fit these workloads well because of its relational capabilities and extension ecosystem. But “new SaaS” is not sufficient justification on its own. A SaaS product built around software that requires MySQL should use MySQL unless there is a documented reason not to. Database choice should follow application requirements rather than architecture fashion. ## Choose MySQL when compatibility and ecosystem fit reduce risk MySQL remains a practical choice when the surrounding application already expects it. Common examples include: - WordPress; - WooCommerce; - PHP applications built and tested around MySQL; - vendor software certified for MySQL; - existing production systems with mature MySQL schemas; - teams with established MySQL monitoring, backup, and recovery procedures; - applications whose libraries and operational tooling already assume MySQL behavior. MySQL's ecosystem value is easy to underestimate. Compatibility can remove migration work, reduce surprises during upgrades, and keep vendor support intact. A stable MySQL application should not be migrated to PostgreSQL just because PostgreSQL exposes features the application does not need. For teams comparing MySQL-compatible engines specifically, see [MySQL vs MariaDB for Production Apps](/learn/guides/mysql-vs-mariadb-production-apps). ## PostgreSQL vs MySQL performance: neither is universally faster “PostgreSQL vs MySQL performance” is one of the most common comparison questions, but a universal winner would be misleading. Performance depends on: - schema design; - indexes; - query shape; - join complexity; - read/write ratio; - transaction size; - concurrency; - connection pooling; - memory; - storage latency and throughput; - maintenance settings; - replication configuration; - database version; - application driver behavior. A useful performance comparison tests the **same product workload** on both engines with representative data. | Workload question | What to measure | |---|---| | API latency | p50, p95 and p99 query/application latency | | Query efficiency | actual query plans, rows scanned, index usage | | Write-heavy workload | transaction latency, lock waits, WAL/binlog volume | | High concurrency | active connections, waits, deadlocks, pool saturation | | Reporting | join/aggregation latency on production-like datasets | | JSON queries | index usage and query plan for real JSON predicates | | Recovery | backup duration and measured restore time | | Replication | replica lag under production write load | Do not migrate because a third-party benchmark shows one database winning an unrelated test. If performance is the reason for considering a change, reproduce the slow queries and concurrency patterns first. A missing index or poor schema can remain slow after an engine migration. ## Transaction and concurrency behavior should be tested, not assumed equivalent Both PostgreSQL and MySQL support ACID transactions, but their concurrency behavior and defaults are not identical. PostgreSQL uses MVCC to allow transactions to work with different row versions while reducing unnecessary read/write blocking. MySQL InnoDB also uses MVCC together with locking mechanisms. The practical migration concern is that the same application transaction can behave differently around: - isolation levels; - row and range locking; - deadlocks; - long-running transactions; - concurrent updates; - retry behavior; - serialization conflicts; - connection-pool pressure. For normal application development, the important question is not which concurrency system looks better in a feature matrix. It is whether the application behaves correctly under the concurrency it will actually receive. Before migrating an existing database, run representative concurrent transactions and verify application retry/error handling. ## PostgreSQL JSONB vs MySQL JSON Both PostgreSQL and MySQL support JSON. A comparison that says “PostgreSQL supports JSON and MySQL does not” is outdated. PostgreSQL provides both `json` and `jsonb`. JSONB stores a decomposed representation designed for processing and supports indexing strategies and operators useful for querying document-like fields. MySQL provides a native JSON type and JSON functions, allowing JSON data to live inside a relational schema. The decision depends on how much of the application is actually document-shaped. ### PostgreSQL JSONB is useful when flexible data still belongs inside a relational system A common PostgreSQL pattern is: ```text accounts orders payments products metadata JSONB ``` Core business relationships remain relational while selected attributes stay flexible. ### MySQL JSON works well when flexibility is a bounded exception MySQL can use a similar hybrid model when most application data is relational and a limited set of attributes varies. Do not put important authorization, billing, relationship, uniqueness, or frequently filtered fields into JSON merely to avoid schema design. If document-oriented storage is the dominant application model, compare a document database as well rather than forcing either relational engine to behave like one. See [MongoDB vs MySQL](/learn/guides/mongodb-vs-mysql). ## PostgreSQL extensions are a real differentiator—but verify managed-service support PostgreSQL's extension ecosystem is one of the strongest reasons to select it when the product genuinely depends on that capability. Examples can include: - geospatial functionality; - vector workloads; - cryptographic helpers; - additional indexing or data types; - monitoring or utility extensions. However, managed PostgreSQL providers usually expose an approved extension catalog rather than unrestricted host access. So the correct sequence is: 1. identify the exact extension the product needs; 2. verify that the target PostgreSQL version supports it; 3. verify that the managed provider exposes it; 4. test upgrades and restore behavior with that extension enabled. Do not choose a managed PostgreSQL service because “PostgreSQL has extensions” if the extension you need is not available on that service. ## Indexing and query design matter more than generic engine labels Both engines provide multiple index types and query-planning capabilities, but index design must follow the workload. For either database, production review should include: - which queries drive the most application latency; - whether filtering columns are indexed appropriately; - whether composite index order matches real predicates; - whether indexes are duplicated or unused; - how write-heavy tables are affected by index count; - whether JSON queries can use appropriate indexes; - whether large scans are intentional; - how query plans change as the dataset grows. The presence of a sophisticated database feature does not compensate for a poor query model. ## Replication and high availability are separate from backups PostgreSQL and MySQL both support replication patterns, but replication is primarily an availability and scaling mechanism—not a substitute for recoverable backups. A replica can reproduce unwanted changes such as: - accidental deletes; - destructive updates; - bad migrations; - application bugs. Production architecture should define separately: - availability target; - replica topology; - failover process; - replication-lag monitoring; - backup frequency; - retention; - point-in-time recovery requirements; - restore testing; - RPO and RTO. For PostgreSQL-specific availability design, see [PostgreSQL High Availability: Architecture, Failover & Replication](/learn/guides/postgresql-high-availability). ## PostgreSQL vs MySQL for common workloads | Workload | Usually start with | Why | |---|---|---| | New relational SaaS | PostgreSQL often fits well | Rich relational model and extension options | | WordPress / WooCommerce | MySQL | Ecosystem compatibility | | PHP app already built for MySQL | MySQL | Lower compatibility risk | | GIS-heavy application | PostgreSQL | PostGIS ecosystem when available | | Vector workloads using pgvector | PostgreSQL | Extension ecosystem when supported | | Vendor business software requiring MySQL | MySQL | Vendor compatibility | | Existing healthy PostgreSQL app | PostgreSQL | Avoid unnecessary migration | | Existing healthy MySQL app | MySQL | Avoid unnecessary migration | | Relational app with flexible metadata | Either | Test the exact JSON and indexing requirements | | Team with strong experience in one engine | Usually keep that engine | Operational knowledge reduces risk | These are starting points, not universal rules. The application framework, vendor support, data model, query patterns, migration cost, and operator knowledge can outweigh a generic recommendation. ## PostgreSQL vs MySQL for managed databases The GSC queries reaching this page include users asking how to choose between a PostgreSQL-compatible and MySQL-compatible **managed relational database**. For that decision, separate the engine choice from the operations choice. First choose the engine: ```text Need PostgreSQL-specific capability or existing PostgreSQL standard -> PostgreSQL Application/vendor ecosystem expects MySQL -> MySQL ``` Then choose the operating model: ```text Want provider-managed patching, backups, monitoring and database lifecycle -> Managed database Need root access, custom host packages or unsupported database configuration -> Self-hosted database on a VM ``` Managed PostgreSQL and managed MySQL still leave important responsibilities with the application team: - schema design; - SQL queries; - indexes; - credentials and application access; - migrations; - connection behavior; - capacity decisions; - recovery validation; - application behavior during failover. For the operating-model decision, see [Managed vs Self-Hosted Databases](/learn/guides/managed-vs-self-hosted-databases). ## Migrating between PostgreSQL and MySQL is an application migration PostgreSQL and MySQL both use SQL, but that does not make migration trivial. A migration can affect: - SQL syntax; - data types; - identity/auto-increment behavior; - functions and stored logic; - JSON expressions; - indexes; - constraints; - transaction behavior; - drivers and ORMs; - migrations; - backup tooling; - replication design; - observability; - operational runbooks. An ORM can reduce some application differences, but it does not make database engines interchangeable. Before migrating: 1. inventory engine-specific schema and SQL; 2. test data conversion; 3. run application tests against the target engine; 4. benchmark representative production queries; 5. define cutover and rollback; 6. validate backups and restore on the target engine; 7. verify reporting, background jobs, and integrations. If the current database is healthy, the migration needs a documented benefit large enough to justify that work. ## How Raff supports PostgreSQL and MySQL Raff provides [Managed PostgreSQL](/products/managed-databases/postgresql) and [Managed MySQL](/products/managed-databases/mysql) as part of its [Managed Databases](/products/managed-databases) platform. For current database versions, plan sizes, backup scope, high-availability options, extension availability, free-tier eligibility, and pricing, use the live product pages and console as the source of truth rather than relying on static article numbers. Teams that need deeper host-level control can also run PostgreSQL or MySQL on a [Raff VM](/products/raff-vm), with the database lifecycle then owned by the team. A practical Raff decision is: ```text PostgreSQL fits the application -> Managed PostgreSQL when you want less platform operations -> Raff VM when you need full host/database control MySQL fits the application -> Managed MySQL when you want less platform operations -> Raff VM when you need full host/database control ``` For the engine-specific hosting decision, continue with [Postgres Hosting: Managed vs Self-Hosted for SaaS](/learn/guides/postgresql-hosting-for-saas) or [MySQL Hosting: Managed vs Self-Hosted for Production Apps](/learn/guides/mysql-hosting-managed-vs-self-hosted). ## PostgreSQL vs MySQL decision checklist Choose PostgreSQL when most of these are true: - [ ] The application needs PostgreSQL-specific extensions or data types. - [ ] JSONB querying/indexing is an important part of the product. - [ ] Geospatial or vector extensions are a concrete requirement. - [ ] The team already operates PostgreSQL reliably. - [ ] The application is new and its ecosystem does not require MySQL. - [ ] Complex relational querying is central to the workload. Choose MySQL when most of these are true: - [ ] WordPress, WooCommerce, PHP software, or a vendor requires MySQL compatibility. - [ ] The existing production application already runs reliably on MySQL. - [ ] The team has mature MySQL operations and no PostgreSQL-specific requirement. - [ ] Third-party tooling or support contracts assume MySQL. - [ ] Migration away from MySQL would create risk without a clear product benefit. If both fit, choose the one your team can operate and recover confidently, then validate the decision with representative schema, queries, and concurrency. ## Conclusion PostgreSQL vs MySQL does not have a universal winner. Choose PostgreSQL when its extensibility, JSONB, data types, geospatial/vector ecosystem, or existing PostgreSQL standard directly benefits the application. Choose MySQL when compatibility with WordPress, WooCommerce, PHP software, vendor applications, or an established MySQL operating model reduces risk. For performance, test the actual workload rather than relying on generic database benchmarks. For production operations, define backups, restore testing, replication, RPO/RTO, monitoring, and failover separately from the engine decision. Once the engine is clear, choose managed hosting if the team wants to transfer more database-platform work to the provider, or self-host when host-level control is a real requirement. :::cta Explore Managed Databases Compare Raff Managed PostgreSQL and MySQL, then verify current versions, availability, features, and pricing on the live product pages. ::: ## Sources - [PostgreSQL: Data Types](https://www.postgresql.org/docs/current/datatype.html) - [PostgreSQL: JSON Types](https://www.postgresql.org/docs/current/datatype-json.html) - [PostgreSQL: Extending SQL](https://www.postgresql.org/docs/current/extend.html) - [PostgreSQL: Transaction Isolation](https://www.postgresql.org/docs/current/transaction-iso.html) - [MySQL: InnoDB Storage Engine](https://dev.mysql.com/doc/refman/8.4/en/innodb-storage-engine.html) - [MySQL: InnoDB Transaction Model](https://dev.mysql.com/doc/refman/8.4/en/innodb-transaction-model.html) - [MySQL: JSON Data Type](https://dev.mysql.com/doc/refman/8.4/en/json.html) - [Raff Managed PostgreSQL](/products/managed-databases/postgresql) - [Raff Managed MySQL](/products/managed-databases/mysql) - Product details reviewed: 2026-09-14; verify current versions, plan limits, availability, and pricing on the live Raff product pages and console. --- ### Serverless vs Containers: Differences, Cost & When to Use Each URL: https://rafftechnologies.com/learn/guides/serverless-vs-containers Description: Compare serverless vs containers across architecture, scaling, cost, portability, runtime control, serverless containers, Kubernetes, and common use cases. Serverless vs containers is not a comparison between two mutually exclusive technologies. **Serverless is an execution and operations model; a container is a packaging and runtime unit.** A serverless platform can run functions, containers, or both. For most teams, the practical decision is this: **use serverless when you want the platform to own more scaling and runtime lifecycle around demand; use containers when you need a portable application runtime with more control over processes, dependencies, networking, or deployment behavior.** Raff Technologies supports both approaches through Functions, Raff Apps, cloud VMs, and Kubernetes. The right choice starts with workload lifecycle, not with which product name sounds more modern. ## Serverless vs containers: quick comparison | Decision area | Serverless | Containers | |---|---|---| | What it describes | Execution/operations model | Application packaging/runtime unit | | Typical scaling | Platform-managed, often including scale-to-zero | Depends on where the container runs | | Infrastructure ownership | Provider owns more of the runtime lifecycle | Team controls more of runtime and deployment | | Runtime control | Platform-defined boundaries | Broad control inside the image | | Startup model | On demand or automatically scaled | Process starts from an image and stays running until replaced/stopped | | Best fit | Bursty APIs, events, cron, webhooks, on-demand jobs | Web apps, APIs, workers, daemons, custom runtimes | | Persistent local process | Usually not the primary model | Natural fit | | Portability | Depends on handler/runtime model | Strong when using OCI/Docker images | | Can use containers underneath | Yes | Not necessarily serverless | | Can scale to zero | Often | Yes, on some container platforms | **Choose serverless first** when demand is intermittent, scaling should be platform-managed, and the workload can tolerate the platform's runtime boundaries. **Choose containers first** when the process itself matters: long-lived services, custom packages, persistent connections, multi-process workloads, or a runtime that should behave the same across environments. The important nuance is that a containerized workload can also be serverless when a platform runs the container, autos-scales it, and removes server management from the team. ## Serverless computing is an operating model, not a packaging format Serverless usually means the application team does not provision or manage the underlying servers directly. The platform decides where workloads run, starts capacity when needed, and manages more of the scaling lifecycle. That model can appear as: - Functions-as-a-Service (FaaS); - serverless container platforms; - event-driven jobs; - scale-to-zero application platforms; - managed runtimes that hide the server layer. A serverless function is therefore one implementation of serverless computing, not the definition of serverless itself. This matters because many comparisons incorrectly frame the choice as: ```text serverless = function containers = server ``` A more accurate model is: ```text Packaging/runtime choice -> function handler or container image Operating model -> serverless platform, app platform, VM, or Kubernetes ``` That separation makes architecture decisions much clearer. ## Containers package the runtime; they do not decide who operates it A container image packages an application with its runtime dependencies, libraries, binaries, filesystem layout, and startup command. The same image can run on: - a developer laptop; - Docker on a VM; - a developer app platform; - a serverless container platform; - Kubernetes. So “container” does not automatically mean “self-managed infrastructure.” A team can package an application as a container while delegating scaling, routing, deployment, and infrastructure management to a platform. This is one reason the serverless-vs-containers question is better treated as **operations model vs runtime control**, not as two incompatible technologies. ## Functions are the clearest serverless fit for bounded event-driven work Functions work well when the workload has a clear trigger and completion point. Typical examples include: - webhook receivers; - scheduled jobs; - object-storage events; - image or document transforms; - API callbacks; - notification fan-out; - one-off processing; - lightweight HTTP endpoints; - periodic synchronization; - bounded ETL steps. A function-shaped workload looks like: ```text Event arrives ↓ Start execution ↓ Perform bounded work ↓ Write durable output/state ↓ Finish ``` The platform can then scale execution independently from the rest of the application. Functions become a poor fit when the application depends on a continuously running local process, long-lived local state, unusual networking requirements, permanent filesystem assumptions, or host-level customization outside the platform boundary. For exact runtime constraints, see [Serverless Function Timeout, Memory & Concurrency Limits](/learn/guides/serverless-function-timeout-memory-concurrency-limits). For startup behavior, see [Serverless Cold Starts, Concurrency & Scale-to-Zero](/learn/guides/serverless-cold-starts-concurrency-scale-to-zero). ## Containers fit persistent services and custom runtime environments Containers are a strong fit when the application should remain available as a process or needs more control over the runtime environment. Common examples include: - long-running web applications; - APIs with steady traffic; - queue workers that stay connected; - reverse proxies; - applications with long-lived TCP connections; - multi-process services; - software requiring custom operating-system packages; - self-hosted applications distributed as Docker images; - workloads with custom networking or filesystem behavior. A containerized service normally follows this lifecycle: ```text Build image ↓ Start process ↓ Become ready ↓ Serve requests/jobs repeatedly ↓ Replace or stop later ``` This persistent process model makes containers a natural fit when connection pools, in-process caches, background loops, or application daemons are intentionally kept alive. Important business state should still live in durable storage rather than relying on one container replica's local lifecycle. ## Serverless containers sit between functions and self-managed containers “Serverless container” is not a contradiction. A serverless container platform can let the team deploy a container image while the platform handles much of the surrounding infrastructure, routing, autoscaling, and idle-capacity lifecycle. That model is useful when the team wants: - a Dockerfile or OCI image; - custom dependencies; - a conventional web process; - more runtime control than a function handler; - less infrastructure ownership than a VM or Kubernetes cluster. This creates three useful operating levels: | Model | Application unit | Who owns more of the infrastructure lifecycle? | |---|---|---| | Function | Handler / bounded task | Platform | | App or serverless container platform | Service / container image | Platform | | VM or Kubernetes | Container/process on infrastructure you control more directly | Team + platform, depending on service | Raff Apps fits the middle category: applications can deploy from GitHub, buildpacks, Dockerfiles, or docker-compose while the platform handles deployment and scaling around the service. Current Raff Apps product details should be checked on the live product page because runtime, plan, and scaling options can change independently from this guide. ## Serverless vs containers for scaling Both serverless and containerized workloads can scale horizontally. The difference is **what gets scaled and who owns the mechanism**. A function platform may scale execution instances from incoming demand: ```text request/event ↓ execution instance(s) ↓ finish ↓ capacity may disappear ``` A container platform may scale long-lived service replicas: ```text traffic ↓ container replica(s) ↓ readiness / connection pools / application process ↓ replicas remain until scaled down or replaced ``` The trade-offs include: - cold-start latency; - process startup time; - readiness probes; - connection-pool behavior; - cache warm-up; - downstream database capacity; - maximum concurrency; - scale-down behavior. Autoscaling does not remove capacity planning. A platform that can create 100 function executions or container replicas quickly can still overwhelm a database that safely handles only 50 concurrent application connections. Scale limits should therefore follow downstream capacity, not just compute elasticity. ## Serverless vs containers cost depends on utilization There is no universal rule that serverless is cheaper than containers. Serverless often fits economically when the workload is: - intermittent; - bursty; - idle for meaningful periods; - independently scalable; - easy to bound per execution. Reserved or continuously running container capacity can fit better when the workload is: - continuously busy; - predictable; - long-lived; - able to keep allocated CPU and memory productive; - easier to operate as one persistent service or worker pool. A useful cost comparison includes the whole system: ```text Serverless cost = execution + memory/CPU meters + warm capacity + retries + platform-specific fees Container cost = service/VM/node capacity + load balancing + storage + orchestration + operator time ``` Do not compare one function invocation with one container and call that a total-cost analysis. Also avoid assuming every container platform reserves capacity continuously. Some application platforms can scale services to zero, which changes the economics substantially. For current Raff Functions meters, use [Serverless Function Pricing](/learn/guides/serverless-function-pricing-cpu-memory-egress) and the live product page rather than hardcoding prices here. ## Runtime control usually favors containers Containers expose a broader application environment because the team defines the image. That can include: - language runtime; - system libraries; - binaries; - startup process; - filesystem layout; - package versions; - runtime environment variables; - network-listening behavior. Functions usually impose a more opinionated execution contract. The platform may define supported handlers, request models, timeouts, memory ranges, filesystem behavior, or trigger formats. Raff Functions reduces some portability friction by supporting standard handler styles and a Dockerfile path for custom runtimes. Current live product information lists Python, Node.js, TypeScript/JavaScript, Go, standard handlers, and a Dockerfile escape hatch. That means a custom dependency does not automatically require moving to a persistent container service. The workload's lifecycle still matters. ## Portability usually favors container images—but not automatically OCI/Docker images provide a portable packaging format, but portability depends on more than the image. A containerized application can still depend heavily on: - proprietary managed databases; - provider-specific networking; - identity APIs; - event systems; - storage semantics; - ingress configuration; - orchestration annotations. Likewise, a serverless function can be portable when its handler uses standard frameworks and provider-specific adapters are kept outside business logic. A useful portability review asks: 1. Can the application run locally without the production platform? 2. Are provider-specific SDK calls isolated? 3. Can data be exported and restored elsewhere? 4. Is the runtime contract documented? 5. Are deployment settings portable, or tied to one proprietary configuration format? For serverless-specific design, see [Portable Serverless Handlers: Avoid Lock-In](/learn/guides/portable-serverless-handlers-avoid-lock-in). ## Serverless vs containers vs Kubernetes Kubernetes is not the opposite of serverless. It is an orchestration platform for containerized workloads. The relationship is better represented as: ```text Serverless Functions -> platform-managed execution Raff Apps / serverless-style app platform -> platform-managed application services or containers Containers on a VM -> team manages the host and container runtime Kubernetes -> cluster orchestrates containerized workloads across nodes ``` Use Kubernetes when the container environment genuinely needs capabilities such as: - multi-node scheduling; - workload placement; - service discovery; - rolling deployments; - cluster-level networking; - autoscaling across a fleet; - node pools; - standardized orchestration across many services. Do not adopt Kubernetes merely because an application uses containers. One or several containers can run effectively on an application platform or VM. For the next decision, see [Kubernetes vs Docker Compose for Small Teams](/learn/guides/kubernetes-vs-docker-compose-small-teams). ## Serverless vs containers for common workloads | Workload | Better starting point | Why | |---|---|---| | Webhook receiver | Serverless function | Triggered and bounded | | Scheduled cleanup | Serverless function | Runs only on schedule | | File-processing event | Serverless function | Clear event and completion point | | Bursty small API | Function or serverless app service | Can benefit from scale-to-zero | | Constant web application | Containerized service | Persistent process and steady traffic | | Long-running API | Containerized service | Stable runtime and process lifecycle | | Always-on queue worker | Container | Continuous consumer process | | Custom Dockerfile web app | App platform or container host | Image defines runtime requirements | | Long-lived TCP service | Container | Persistent connections matter | | One Docker Compose stack | App platform or VM | Full cluster may be unnecessary | | Many services across nodes | Kubernetes | Orchestration becomes a cluster problem | | Mixed SaaS architecture | Both | Persistent app plus event-driven functions | This is a starting framework, not a universal rule. Traffic pattern, state, recovery requirements, networking, team skills, and existing platform dependencies can change the choice. ## A practical decision framework Ask these questions in order: ### 1. Does the workload have a clear trigger and completion point? If yes, evaluate a serverless function first. ### 2. Does the application need a persistent process? If yes, evaluate a containerized service. ### 3. Does the team want a container but not server operations? Evaluate an application or serverless-container platform before jumping to a VM or Kubernetes. ### 4. Does the container need full host control? Use a VM when root access, host packages, custom networking, or direct operating-system control is a real requirement. ### 5. Does the workload need cluster-level orchestration? Use Kubernetes when multi-node scheduling and orchestration solve an actual operational problem. ### 6. What state survives a restart? Keep business state in durable services such as managed databases, object storage, or persistent volumes according to the workload's consistency and recovery requirements. This sequence avoids solving an application-lifecycle problem with unnecessary infrastructure. ## How this maps to Raff Raff currently provides several deployment paths for these workload shapes. Use [Raff Functions](/products/serverless-functions) for on-demand and event-driven execution. The live product page currently lists scale-to-zero, standard handlers, Dockerfile runtimes, HTTP/cron/storage triggers, and long-running execution options. Verify current runtime limits and pricing on the live page because those values can change. Use [Raff Apps](/products/app-platform) when the application should deploy as a web service, private service, worker, cron job, one-off job, Dockerfile, buildpack project, or docker-compose stack without managing the underlying servers directly. Use [Raff VM](/products/raff-vm) when the team wants full server control for Docker, Docker Compose, custom networking, or other host-level requirements. Use [Raff Kubernetes](/products/kubernetes) when a container workload genuinely needs cluster scheduling, orchestration, service discovery, node pools, and Kubernetes APIs. A mixed architecture can be completely reasonable: ```text Customer-facing application -> Raff Apps / VM / Kubernetes Webhook + scheduled + burst jobs -> Raff Functions Durable relational state -> Managed Database Files / objects -> Object Storage ``` The goal is not to standardize every workload on one compute model. It is to give each workload the simplest lifecycle the team can operate reliably. ## Conclusion Serverless vs containers is not a strict technology choice because the concepts describe different layers. **Serverless describes how much infrastructure and scaling lifecycle the platform owns. Containers describe how the application runtime is packaged.** A container can run on a serverless platform, an app platform, a VM, or Kubernetes. Choose functions for bounded, triggered work. Choose containerized services for persistent processes and greater runtime control. Choose a serverless or application platform when you want container portability without server management. Move to VMs or Kubernetes only when the workload actually needs that additional control or orchestration. :::cta Compare Raff Compute Options Compare Functions, Raff Apps, VMs, and Kubernetes after deciding which workloads should be event-driven and which should run as persistent application services. ::: ## Sources - [Cloudflare: Serverless Computing vs Containers](https://www.cloudflare.com/learning/serverless/serverless-vs-containers/) - [Docker Documentation](https://docs.docker.com/) - [Kubernetes Documentation](https://kubernetes.io/docs/concepts/) - [Raff Functions](/products/serverless-functions) - [Raff Apps](/products/app-platform) - [Raff VM](/products/raff-vm) - [Raff Kubernetes](/products/kubernetes) - Product details reviewed: 2026-09-14; verify current runtime limits, scaling behavior, availability, and pricing on the live Raff product pages. --- ### Docker Compose in Production: Best Practices, Deployment & Limits URL: https://rafftechnologies.com/learn/guides/docker-compose-for-production Description: Use Docker Compose in production with practical best practices for configuration, security, health checks, releases, storage, backups, monitoring, recovery, and single-host limits. Docker Compose can be used in production when a **single host is an acceptable compute, scaling, and failure boundary** and the team treats the Compose stack as production infrastructure rather than a development shortcut. The production work is not just `docker compose up -d`. A reliable deployment needs versioned configuration, controlled secrets, health checks, explicit networking, durable state, off-host recovery, monitoring, release discipline, and a tested way to rebuild the application on a replacement host. Raff Technologies supports this operating model through cloud VMs for teams that want full control of Docker and the host. If the application eventually needs multi-node scheduling or less host-level operations, the next step may be an app platform or Kubernetes rather than a larger Compose file. Docker's current documentation explicitly supports Compose for production use on a single server and recommends production-specific configuration such as different ports, environment values, restart policies, and removing development-only bind mounts. ## Docker Compose in production: quick answer | Question | Production guidance | |---|---| | Can Docker Compose run production workloads? | Yes, especially when one host is an acceptable boundary | | Should production reuse the development file unchanged? | Usually no; keep a base model and production-specific differences | | Should source code be bind-mounted from the host? | Usually avoid development-style code bind mounts in production | | Are restart policies enough for reliability? | No; they help process recovery, not host or data recovery | | Do named volumes replace backups? | No; a volume on one host shares that host's failure domain | | Should every service expose a host port? | No; expose only what must receive traffic from outside the Compose network | | Does `depends_on` mean a dependency is ready? | Not by itself; use a health check and `condition: service_healthy` where readiness matters | | When should you move beyond Compose? | When one host is no longer an acceptable availability or scheduling boundary | **A good production Compose deployment is reproducible and recoverable.** If a replacement VM cannot be brought up from known configuration and restored data, the stack is still dependent on the original host. ## Docker Compose is a valid single-host production model Docker Compose defines the application's services, networks, volumes, configuration, and dependencies in a machine-readable model. Docker's current documentation lists single-host production deployments as a supported Compose use case. For a small application, a production architecture may look like this: ```text Internet ↓ Reverse proxy / TLS endpoint ↓ Private Compose network ├── web / API ├── worker ├── scheduler └── cache Durable services ├── managed database or protected database storage ├── object storage for durable uploads └── recovery copies outside the application host ``` The model works well when: - the application fits comfortably on one VM; - vertical scaling is still practical; - short host maintenance or recovery windows are acceptable; - services do not need automatic placement across several nodes; - the team can monitor and recover the host; - the operational simplicity of one machine is more valuable than cluster-level automation. The container count is not the deciding factor. Ten modest containers on one reliable host can be simpler than three services that each require independent replicas, placement, and failover. ## Keep a base Compose model and a small production delta Development and production usually need different behavior without needing two unrelated application definitions. A useful structure is: ```text compose.yaml + compose.production.yaml + production environment / secrets = resolved production model ``` Docker documents using multiple Compose files so later files override or extend the base definition. Production differences commonly include: - removing development bind mounts; - binding different host ports; - changing environment values; - setting restart behavior; - selecting production images; - changing logging options; - enabling or removing supporting services; - attaching production storage and networks. Keep the production override as small as practical. Before deployment, inspect the fully resolved model instead of assuming file merging produced what you intended: ```bash docker compose -f compose.yaml -f compose.production.yaml config ``` This is especially useful when environment interpolation, multiple files, or shared fragments affect the final configuration. ## Production images should be reproducible A production host should not become the place where application source code is edited or where undocumented build state accumulates. Prefer an image lifecycle such as: ```text source commit ↓ CI/build process ↓ versioned container image ↓ registry ↓ production host pulls known version ``` Useful production rules include: - use explicit image versions rather than depending only on a moving `latest` tag; - keep the Dockerfile in version control; - make the build repeatable from a known source revision; - know which image version is running before and after a release; - retain a rollback image while it remains compatible with the database and configuration. An immutable image does not make the whole deployment immutable. Compose configuration, secrets, volumes, database migrations, and host-level settings also affect reproducibility. ## Expose only the services that need public traffic Compose networking and the host firewall solve different problems. A production stack commonly exposes only the entry service: | Service | Typical exposure | |---|---| | Reverse proxy / gateway | Public 80/443 | | Application service | Internal Compose network | | Worker | Internal only | | Database | Private | | Cache | Private | | Metrics or admin service | Private or tightly restricted | Containers on the same Compose network can communicate using service names without every service publishing a host port. Publishing database or cache ports to the public interface when no external client needs them increases attack surface without adding application value. For wider host controls, see [Cloud Security Fundamentals](/learn/guides/cloud-security-fundamentals). ## Secrets should not become ordinary application configuration Production credentials need a deliberate ownership and distribution model. Docker Compose supports secrets that can be explicitly granted to services and mounted into containers as files. Typical secrets include database passwords, API credentials, private keys, webhook signing secrets, third-party tokens, and TLS private material. Whatever secret mechanism you use, define: 1. where the source secret is stored; 2. which service receives it; 3. how it is rotated; 4. how a replacement host receives it; 5. how old credentials are revoked. A backup of the application is incomplete if the team cannot securely restore the credentials required to start it. ## Health checks should represent readiness, not just a running process A container can be running while the application inside it is still unable to serve useful work. Docker Compose supports `healthcheck` and dependency conditions. Normal dependency ordering does **not** mean Compose waits until a service is ready. When readiness matters, Docker documents using `condition: service_healthy` with a meaningful health check. ```yaml services: app: image: example/app:1.8.2 depends_on: db: condition: service_healthy db: image: postgres:18 healthcheck: test: ["CMD-SHELL", "pg_isready -U $${POSTGRES_USER} -d $${POSTGRES_DB}"] interval: 10s timeout: 5s retries: 5 start_period: 30s ``` Treat this as a pattern, not a copy-paste production database design. The exact health check should match the service and should be lightweight enough to run repeatedly. ## Restart policies help process recovery, not infrastructure recovery A restart policy can bring a crashed container process back. It does not solve: - a failed VM; - corrupted persistent data; - a full filesystem; - deleted volumes; - a bad database migration; - an invalid secret; - a broken release; - unavailable external dependencies. Production planning therefore needs separate recovery layers: ```text Process failure -> restart policy / health monitoring Application release failure -> rollback procedure Host failure -> rebuild host + redeploy Compose stack Data loss or corruption -> backup / PITR / application-aware restore ``` A stack is much easier to recover when the host itself is treated as replaceable. ## Persistent storage and backups are different controls A named Docker volume can preserve data when a container is recreated. It does **not** make that data independent of the host. Think in two categories: ```text Replaceable - container image - application container - proxy container - worker container Durable - database data - customer uploads - application-generated files - secrets / configuration sources - backup archives ``` If durable data exists only on one VM, the host remains part of the data failure domain. One way to reduce that risk is to keep less business state on the Compose host: ```text Compose VM ├── web/API ├── worker └── reverse proxy ↓ Managed database ↓ Object storage ``` A self-hosted database inside Compose can still be valid, but then the team must own database-aware backups, restore testing, storage growth, upgrades, and corruption recovery. For file storage decisions, see [App Uploads: VM Disk vs Object Storage](/learn/guides/app-uploads-vm-disk-vs-object-storage). For recovery planning, see [RPO vs RTO for Cloud Backups](/learn/guides/cloud-server-backup-rpo-rto-snapshots). ## Production releases should change the smallest necessary surface A simple Compose release flow may be: ```text build/test image ↓ push versioned image ↓ pull on production host ↓ run required migration ↓ recreate changed service ↓ verify health + logs + key request path ``` A production release plan should define: - the image/version being deployed; - how the production Compose model is rendered; - whether a data backup is required before a migration; - how database migrations are run; - which service or services are recreated; - what post-deploy verification is required; - what condition triggers rollback; - whether the previous application version remains compatible with the current database schema. Rollback is not simply “start the old image.” A destructive or incompatible database migration can make the old application version unusable. For deployment-strategy trade-offs, see [Blue-Green vs Rolling Deployments](/learn/guides/blue-green-vs-rolling-deployments). ## Logging and monitoring must survive `docker compose logs` `docker compose logs` is useful for immediate troubleshooting, but production observability should also cover: - host CPU and memory; - disk usage and inode pressure; - container restarts; - application error rate; - request latency where applicable; - database availability and saturation; - backup success/failure; - certificate expiry if TLS is managed locally; - external dependency failures; - storage growth. Also define log retention. Unlimited local logs can become a disk-capacity incident on the same host that runs the application. ## A production Compose host should be replaceable A useful recovery test is simple: > If this VM disappeared, what exact inputs would we need to recreate the application elsewhere? The answer should be a known set of artifacts: - host provisioning settings; - Docker installation/configuration; - Compose files; - image registry access; - environment-specific configuration; - secrets; - DNS/TLS procedure; - database recovery procedure; - persistent-file recovery procedure; - deployment verification steps. A replacement-host exercise is more valuable than assuming snapshots or backups will work during the first real outage. ## Docker Compose production best-practices checklist Before relying on Compose for production, verify: - [ ] Compose files are version controlled. - [ ] Production differences are explicit and reviewed. - [ ] Development-only bind mounts are removed where appropriate. - [ ] Images use known versions. - [ ] Only required services publish host ports. - [ ] Secrets have defined ownership and rotation. - [ ] Important dependencies have meaningful health checks. - [ ] Restart behavior is defined where appropriate. - [ ] Durable data is identified separately from replaceable containers. - [ ] Backups exist outside the container lifecycle. - [ ] Database restores have been tested. - [ ] Host disk growth is monitored. - [ ] Application and host metrics are observable. - [ ] Releases include verification and rollback criteria. - [ ] The full stack can be recreated on a replacement host. - [ ] The team knows which requirement would justify moving beyond one host. ## When Docker Compose stops being the right production model | Requirement | Single-host Compose | Likely next step | |---|---|---| | Several related services on one machine | Strong fit | Stay with Compose | | Predictable traffic | Strong fit | Resize/optimize based on measurements | | One-host maintenance window is acceptable | Strong fit | Keep recovery simple | | Occasional worker separation | Possible | Separate workload onto another host if needed | | Application must survive one host failing | Weak fit | Multi-host architecture / orchestration | | Automatic workload placement across nodes | Not its main model | Kubernetes or another scheduler | | Independent replicas across nodes | Weak fit | Cluster-level orchestration | | Many services need cluster discovery/policy | Weak fit | Kubernetes | | Team wants container deployment without managing a VM | Extra host operations | Consider an app platform | Do not migrate to Kubernetes simply because the stack reached an arbitrary number of services. Move because a measured operational requirement—high availability, multi-node scheduling, independent scaling, placement, policy, or fleet management—has made the single-host boundary the problem. For that decision, see [Kubernetes vs Docker Compose for Small Teams](/learn/guides/kubernetes-vs-docker-compose-small-teams) and [Container Infrastructure: Docker, K3s, and Kubernetes](/learn/guides/container-infrastructure-docker-k3s-kubernetes). ## How this maps to Raff A [Raff VM](/products/raff-vm) is the full-control path when a team wants to operate Docker Compose directly on its own Linux host. For current VM sizes, storage, networking, backup options, and pricing, use the live [Raff pricing page](/pricing) rather than static numbers in this guide. If the goal is to deploy application services without owning as much host-level operation, compare [Raff Apps](/products/app-platform). If the application has genuinely moved into multi-node orchestration requirements, compare [Raff Kubernetes](/products/kubernetes). The progression does not have to be `Compose -> Kubernetes`. It can be `Compose on VM -> larger or better-operated VM -> split selected state/services -> app platform or Kubernetes only when requirements justify it`. ## Conclusion Docker Compose in production is a valid choice when one host remains an acceptable deployment and failure boundary. Production readiness comes from the operating model around Compose: reproducible configuration, known image versions, restricted exposure, secret handling, health checks, monitoring, durable-state planning, off-host recovery, controlled releases, and replacement-host procedures. When multi-node scheduling or node-failure tolerance becomes a real requirement, move beyond the single-host model because the requirement changed—not because Compose is inherently “development only.” Docker's own documentation supports Compose as a production deployment model on a single server. :::cta Deploy a Raff VM Run Docker Compose on a full-control cloud VM, and use the live pricing page to choose capacity for your workload. ::: ## Sources - [Docker: Use Compose in production](https://docs.docker.com/compose/how-tos/production/) - [Docker: Merge Compose files](https://docs.docker.com/compose/how-tos/multiple-compose-files/merge/) - [Docker: Control startup and shutdown order](https://docs.docker.com/compose/how-tos/startup-order/) - [Docker Compose documentation](https://docs.docker.com/compose/) - Product details reviewed: 2026-09-14; verify current Raff VM, Apps, Kubernetes, backup, and pricing details on the live product pages. --- ### Kubernetes Requests vs Limits: CPU, Memory, and Scheduling URL: https://rafftechnologies.com/learn/guides/kubernetes-requests-vs-limits Description: Understand Kubernetes requests vs limits for CPU and memory, including scheduling, throttling, OOM behavior, HPA, QoS, LimitRange, best practices, and worker capacity. Kubernetes requests and limits control **compute resources for Pods and containers**. A request tells the scheduler how much CPU or memory to plan for; a limit sets a runtime boundary on how much of that resource a container may consume. **These settings are not API rate limits, ingress rate limits, or request-per-second throttles.** In Kubernetes resource management, “requests vs limits” means CPU, memory, and related compute-resource policy. Raff Technologies supports managed Kubernetes for teams that want to run containerized workloads without operating the control plane themselves. Accurate requests and sensible limits matter because they affect scheduling, node capacity, autoscaling signals, performance, and failure behavior. ## Kubernetes requests vs limits: quick answer | Setting | Scheduler uses it? | Runtime effect | Common failure when wrong | |---|---:|---|---| | CPU request | Yes | Influences CPU weighting under contention | Over-requesting wastes schedulable capacity; under-requesting packs workloads too tightly | | Memory request | Yes | Helps represent expected working-set needs | Under-requesting can increase node memory pressure | | CPU limit | No for placement | CPU usage above the ceiling is throttled | Latency and throughput can degrade during legitimate bursts | | Memory limit | No for placement | Memory use is constrained; exceeding the boundary can result in OOM termination | Restarts or instability when the limit is below real peak memory | The simplest rule is: ```text Requests = scheduling baseline Limits = runtime boundary ``` Requests answer **“what capacity should Kubernetes plan for?”** Limits answer **“how far may this container consume after it is running?”** ## Kubernetes resource requests are scheduling inputs The Kubernetes scheduler places Pods using resource requests rather than waiting to observe their future CPU or memory usage. For example: ```yaml resources: requests: cpu: "250m" memory: "256Mi" limits: cpu: "500m" memory: "512Mi" ``` This container requests: - `250m` CPU, or 0.25 CPU; - `256Mi` memory. It is limited to: - `500m` CPU; - `512Mi` memory. If four Pods each request `500m` CPU, their combined CPU request is: ```text 4 × 500m = 2000m = 2 CPU ``` That requested capacity matters before actual runtime usage is known. ### Requests that are too high Inflated requests can: - make Pods unschedulable earlier; - leave node capacity unused; - cause a cluster to appear full even when observed usage is low; - contribute to unnecessary node scale-out when cluster autoscaling is used. ### Requests that are too low Understated requests can: - pack too many active workloads onto one node; - increase CPU or memory contention; - make capacity planning misleading; - distort resource-utilization autoscaling signals. A request should therefore represent a **defensible operating baseline**, not an arbitrary “safe” number. For broader worker sizing, see [Kubernetes Cluster Sizing](/learn/guides/kubernetes-cluster-sizing). ## CPU requests and CPU limits solve different problems CPU resources are compressible: when a workload cannot get as much CPU as it wants, it can usually continue running more slowly. A CPU request influences scheduling and relative CPU allocation under contention. A CPU limit defines a ceiling on CPU time the container may consume. If a container tries to use CPU beyond its configured limit, Kubernetes relies on the container runtime and kernel mechanisms to throttle that workload. That creates an important production trade-off: ```text Low CPU limit -> stronger containment -> greater risk of throttling legitimate bursts Higher/no CPU limit -> more burst freedom -> less strict noisy-neighbor containment ``` For latency-sensitive web applications, a CPU limit that looks generous during average load can still cause problems during short bursts, garbage collection, startup, or traffic spikes. Do not assume that every CPU limit should equal the request or that every limit should be exactly 2× the request. Measure burst behavior first. ## Memory requests and memory limits have different failure behavior Memory is not handled like CPU. A memory request influences scheduling. A memory limit constrains how much memory a container is allowed to use. Memory-limit enforcement is reactive rather than gradual CPU-style throttling. When a process attempts to use memory beyond its allowed boundary, the kernel can terminate a process in the container, producing an out-of-memory failure such as `OOMKilled`. Operationally: ```text CPU exceeds limit -> throttling / slower execution Memory exceeds usable boundary -> process may be terminated ``` That makes memory sizing especially important for applications with: - garbage-collected runtimes; - large startup peaks; - caches; - image/video processing; - batch jobs; - unpredictable query buffers; - memory leaks. A memory request should reflect the workload's normal working set closely enough for responsible placement. A memory limit should reflect how much growth is acceptable before termination is preferable to further node pressure. ## Kubernetes CPU and memory units are easy to misread CPU is measured in CPU units. ```text 1 CPU = 1 CPU core or 1 virtual core 500m = 0.5 CPU 250m = 0.25 CPU 100m = 0.1 CPU ``` `100m` means one hundred millicpu, not 100 CPUs. Memory is expressed as a quantity such as: ```text 256Mi 512Mi 1Gi ``` Do not reuse CPU-style intuition for memory units. A value such as `400m` in a memory field is not 400 MiB. A small unit typo can turn a reasonable manifest into a workload that fails immediately or is scheduled very differently from what the author intended. ## What happens if you set a limit but no request? This is a common source of confusion. When a container has a limit but no explicit request for that resource, Kubernetes may use the limit value as the request unless another admission-time defaulting mechanism supplies a value. For example: ```yaml resources: limits: cpu: "1" ``` can result in an effective CPU request of `1` as well. That means a team intending only to cap CPU usage can accidentally create a much larger scheduling request than expected. Namespace policy can also inject values through a `LimitRange`, so always inspect the **effective manifest and runtime configuration**, not only the source YAML you remember writing. ## Requests influence Horizontal Pod Autoscaler utilization Requests are also important when Horizontal Pod Autoscaler uses resource utilization targets. For CPU utilization, a simplified model is: ```text CPU utilization = current CPU usage / CPU request ``` Suppose a Pod is using `200m` CPU. With a `100m` request: ```text 200m / 100m = 200% utilization ``` With a `500m` request: ```text 200m / 500m = 40% utilization ``` The workload is doing the same amount of CPU work, but the autoscaling signal is completely different. Kubernetes also documents that if the relevant resource request is missing for containers in a targeted Pod, resource-utilization calculation can be undefined and the autoscaler may not act on that metric as expected. This is why HPA tuning should not begin with the HPA target alone. First make resource requests credible. ## Requests and limits affect Pod Quality of Service Kubernetes classifies Pods into QoS classes including: - `Guaranteed`; - `Burstable`; - `BestEffort`. At a high level: - a Pod with no CPU or memory requests/limits can fall into `BestEffort`; - a Pod with some resource configuration commonly falls into `Burstable`; - `Guaranteed` requires strict CPU and memory request/limit relationships for the applicable resources and containers. QoS matters during node resource pressure because eviction behavior differs between classes. Do not optimize resource settings purely to obtain a QoS label. Start with the workload's real operating requirements, then understand the QoS class that results. ## LimitRange and ResourceQuota are not the same thing These two Kubernetes policies solve different problems. ### LimitRange A `LimitRange` can apply namespace-level constraints and defaults for individual objects, including: - default requests; - default limits; - minimum values; - maximum values; - maximum limit-to-request ratios. It is useful as a guardrail when workload manifests may omit resource configuration. ### ResourceQuota `ResourceQuota` governs aggregate namespace consumption and object counts. The distinction is: ```text LimitRange -> defaults and boundaries for individual workloads/objects ResourceQuota -> aggregate namespace consumption ``` Shared clusters may use both. Neither replaces proper workload sizing. Defaults should catch omissions, not force every service into the same resource shape. ## Requests vs limits best practices for production There is no universal request-to-limit ratio that works for every application. Start from observed behavior. | Workload behavior | Request approach | Limit approach | |---|---|---| | Steady CPU with short bursts | Request near sustained demand | Leave measured burst headroom if policy allows | | Bursty latency-sensitive API | Avoid requesting every peak | Test whether CPU limit causes throttling during valid bursts | | Stable memory working set | Request near normal working set with justified headroom | Set a tested boundary above normal/expected peaks | | Startup memory spike | Include startup behavior in measurements | Ensure limit survives legitimate startup peak | | Batch job | Request realistic baseline | CPU limit can protect neighbors if slower completion is acceptable | | Memory leak | Fix the application rather than masking it with a large request | Limit can provide containment while the root cause is fixed | | Critical service | Request enough capacity to reflect importance | Choose boundaries from failure policy, not a generic ratio | Review several operating windows: 1. normal traffic; 2. peak traffic; 3. application startup; 4. rolling deployment overlap; 5. scheduled jobs; 6. failure recovery; 7. unusual but legitimate bursts. For each workload, record: - typical CPU usage; - peak CPU and burst duration; - normal memory working set; - peak memory; - startup memory; - replica count; - CPU-throttling impact; - OOM/restart impact. ## Common Kubernetes requests and limits mistakes ### Mistake 1: copying values from another application Two services with the same language and framework can have completely different resource behavior. ### Mistake 2: assuming request equals average usage A request is a scheduling commitment. Average usage can be useful evidence, but startup peaks, sustained load, contention, and failure policy also matter. ### Mistake 3: setting every CPU limit very close to the request This can remove useful burst capacity and create unnecessary throttling. ### Mistake 4: treating memory limits like CPU limits Memory cannot simply be slowed down when the boundary is exceeded. OOM failure behavior must be tested. ### Mistake 5: using limits but forgetting requests This can create unexpected effective requests and misleading scheduling behavior. ### Mistake 6: confusing resource limits with traffic rate limiting Kubernetes CPU/memory requests and limits do not control HTTP requests per second, API quotas, or ingress traffic rates. Those are separate networking/application concerns. ### Mistake 7: tuning HPA before tuning requests Utilization-based HPA depends on requests. Bad requests produce bad percentages. ## How requests affect worker capacity and cost Resource requests directly influence whether new Pods fit on existing workers. The chain is straightforward: ```text Pod requests ↓ Scheduler evaluates node allocatable resources ↓ Pod fits or remains pending ↓ Cluster capacity may need to change ``` Inflated requests can make a cluster appear capacity-constrained earlier than necessary. Requests that are too low can produce tighter packing and contention after scheduling. This is why requests are also a cost-management input, not just a manifest detail. For Raff Kubernetes, use the live [Kubernetes product page](/products/kubernetes) and [pricing page](/pricing) for current worker sizes, autoscaling capabilities, control-plane availability, and pricing rather than relying on static article numbers. For the broader cost model, continue with [Kubernetes Cost Optimization](/learn/guides/kubernetes-cost-optimization-startups). ## How to review requests and limits over time Resource policy should change when the workload changes. Revisit settings after: - major releases; - traffic changes; - runtime upgrades; - new background jobs; - database-client changes; - replica-strategy changes; - repeated CPU throttling; - repeated OOM kills; - node-pressure incidents; - HPA behavior that does not match expectations. A recurring review should ask: - Are requests close to sustained useful demand? - Are Pods pending because capacity is truly insufficient or because requests are inflated? - Is CPU throttling correlated with latency or job duration? - Are memory limits causing legitimate workloads to restart? - Are memory requests representative of the normal working set? - Are HPA targets calculated against credible requests? - Are namespace defaults still appropriate? - Does this workload need a different node pool or isolation boundary? ## Conclusion Kubernetes requests vs limits is fundamentally a scheduling-versus-runtime decision. **Requests tell Kubernetes how much resource capacity to plan for when placing workloads. Limits define how much resource consumption is allowed after those workloads are running.** CPU and memory behave differently: CPU can be throttled, while memory pressure can result in process termination. Start with measurements, keep resource policy separate from traffic rate limiting, and review the values as applications evolve. Accurate requests improve scheduling and autoscaling signals; sensible limits help contain runtime behavior without turning normal bursts into avoidable incidents. :::cta Explore Raff Kubernetes Run Kubernetes workloads with managed control-plane operations, then size worker capacity from measured resource requests and production behavior. ::: ## Sources - [Kubernetes: Resource Management for Pods and Containers](https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/) - [Kubernetes: Horizontal Pod Autoscaling](https://kubernetes.io/docs/concepts/workloads/autoscaling/horizontal-pod-autoscale/) - [Kubernetes: Pod Quality of Service Classes](https://kubernetes.io/docs/concepts/workloads/pods/pod-qos/) - [Kubernetes: Limit Ranges](https://kubernetes.io/docs/concepts/policy/limit-range/) - Product details reviewed: 2026-09-14; verify current Raff Kubernetes worker sizes, autoscaling behavior, availability, and pricing on live product pages. --- ### Managed ClickHouse vs Self-Hosted ClickHouse: Cost, Scaling & Ownership URL: https://rafftechnologies.com/learn/guides/managed-clickhouse-vs-self-hosted-clickhouse Description: Compare managed and self-hosted ClickHouse across pricing models, scaling, backups, HA, operational ownership, and total cost for production analytics. ClickHouse can be run as a managed service or operated directly on your own infrastructure. The database engine may be the same family of technology, but the production responsibility model is not. For a business choosing between managed ClickHouse and self-hosted ClickHouse, the useful comparison is **total operating cost, scaling responsibility, recovery ownership, and how much cluster engineering the team wants to own**. A self-hosted node can look inexpensive on day one. The comparison changes when production needs backups, monitoring, upgrades, replicas, coordination, capacity planning, and someone who can recover the system under pressure. This guide owns that deployment and total-cost-of-ownership decision. For schema, ordering keys, partitions, ingestion, and analytical design, use [ClickHouse Architecture for Production Analytics](/learn/guides/clickhouse-architecture-production-analytics). ## Managed vs self-hosted ClickHouse at a glance | Decision area | Managed ClickHouse | Self-hosted ClickHouse | |---|---|---| | Provisioning | Provider workflow | Your team | | OS and host maintenance | Provider | Your team | | ClickHouse upgrades | Provider within service policy | Your team plans and executes | | Monitoring platform | Usually included to a defined scope | Your team builds or integrates | | Backups | Service-defined and operated | Your team designs, stores, tests, and restores | | Scaling | Service workflow or automation | Resize nodes, add replicas/shards, rebalance and validate | | Replication / HA | Service feature | Your team designs and operates replicas and coordination | | Root access | Usually no | Yes | | Exact version/configuration control | Service limits apply | Full control | | Billing model | Provider-specific | Compute + storage + networking + operations | | Schema and query design | Your team | Your team | | Ingestion correctness | Your team | Your team | | Retention and TTL decisions | Your team | Your team | The important point is that **managed ClickHouse transfers platform operations, not analytical ownership**. Your team still owns the data model, ingestion logic, ordering keys, materialized views, retention rules, and query behavior. Self-hosting keeps those responsibilities and adds the database platform itself. ## “Managed ClickHouse” is a category, not one architecture Teams often use “ClickHouse Cloud” and “managed ClickHouse” interchangeably, but that can hide important differences. ClickHouse Cloud is the official managed service from ClickHouse. Its current cloud architecture separates compute from shared object storage and uses SharedMergeTree for cloud services. Self-managed ClickHouse commonly uses local storage with MergeTree-family engines, and replicated deployments use ReplicatedMergeTree plus coordination through ClickHouse Keeper. Other managed providers can use different infrastructure and billing models while still operating ClickHouse for the customer. Raff Managed ClickHouse, for example, currently runs ClickHouse 25.8 LTS on plan-based resources with NVMe storage, optional two-replica high availability with Keeper, managed backups, TLS, allowlists, private networking, monitoring, and plan-based scaling. Do not assume that a feature or architecture described for ClickHouse Cloud automatically describes every managed ClickHouse service. Compare the **service contract you will actually buy**. ## The self-hosted cost is larger than the VM line item The easiest cost mistake is comparing one self-hosted VM with one managed database invoice. A production self-hosted ClickHouse budget can include: ```text compute + local or attached storage + backup storage + backup transfer + monitoring and logs + additional replica capacity + Keeper coordination capacity + network transfer + spare capacity for maintenance and failure + engineering time + upgrade work + restore testing + incident response ``` A single-node analytical database may not need every line immediately. But once the workload becomes business-critical, availability and recovery requirements usually add infrastructure and operating work. ClickHouse’s own documentation describes replication as a self-managed cluster responsibility, with ClickHouse Keeper coordinating replicated tables. Its current guidance also warns that self-managed replicated tables can become read-only when coordination is unavailable or under-resourced. That is not an argument against self-hosting; it is a reminder to price the **whole production topology**, not just the primary database server. **The cheapest server is not necessarily the cheapest ClickHouse operating model.** ## Managed ClickHouse also has more than one billing model Managed does not automatically mean predictable or unpredictable pricing. The provider’s billing dimensions matter. As of August 24, 2026, ClickHouse Cloud’s billing documentation says Cloud charges for compute, compressed storage, data transfer, and ClickPipes where applicable. Compute is metered per minute and storage is metered separately. Backups also count toward storage billing. Its AWS `us-east-1` documentation gives a Basic example with one 8 GiB RAM / 2 vCPU replica, 500 GB compressed data, 500 GB backup, and modest transfer. The documented total is **$66.52/month when active about six hours per day** and **$186.27/month when active 24 hours per day**. The same documentation gives a Scale example starting at **$499.38/month** for two 8 GiB replicas with 1 TB of data plus one backup and the stated transfer assumptions. Those figures are examples, not universal ClickHouse Cloud quotes. Region, tier, compute time, storage, transfer, replicas, and workload behavior change the bill. Re-check the live ClickHouse pricing page before making a purchasing decision. Raff uses a different managed pricing model. The current Raff Managed ClickHouse page lists flat monthly plan prices with backups, networking, traffic, and monitoring included in the plan price. Current examples are: | Raff ClickHouse plan | Included compute / storage | Current base price | |---|---|---:| | Entry | 2 vCPU, 4 GB RAM, 80 GB NVMe | $59.99/mo | | Mid | 4 vCPU, 8 GB RAM, 120 GB NVMe | $107.99/mo | | Scale | 8 vCPU, 16 GB RAM, 180 GB NVMe | $191.99/mo | Raff currently prices high availability at **+70%** of the plan and additional storage at **$0.15/GB**. These are current public figures, not permanent constants; verify the live product page before procurement. The models are not directly comparable from the table alone. ClickHouse Cloud separates compute and storage and can scale compute down for idle workloads. Raff uses fixed plan shapes and flat monthly billing. The right model depends on workload duty cycle, stored data, query peaks, availability needs, and how much billing variability the business accepts. ## Compare total cost with the same workload and reliability target A meaningful ClickHouse cost comparison needs one workload definition. Record at least: - compressed dataset size; - monthly data growth; - ingestion rate and peak bursts; - important query concurrency; - CPU and memory required during normal and peak windows; - whether the workload is continuous or idle for long periods; - number of replicas required; - acceptable downtime; - backup retention; - expected restore time; - public and cross-region data transfer; - engineering hours needed to operate the platform. Then compare both models against the same requirement. A self-hosted single node should not be compared with a managed HA service if the business actually requires node-failure tolerance. Likewise, an always-on fixed managed plan should not be compared with an autoscaling cloud example without accounting for the real duty cycle. A useful TCO model is: ```text monthly infrastructure + backup / recovery infrastructure + monitoring + availability overhead + network charges + expected database-operations engineering time = operating-model cost ``` Engineering time should not be invented as an arbitrary dollar multiplier. Use your own loaded engineering cost and measured monthly hours. ## Self-hosted ClickHouse is strongest when control is a requirement Self-hosting can be the right decision when the additional control has clear value. Typical reasons include: - root or operating-system access is required; - exact ClickHouse versions and upgrade timing must be controlled; - custom filesystem or storage topology is needed; - unusual server settings or host-level integrations are required; - the team already operates ClickHouse clusters confidently; - hardware utilization can be optimized around a stable, predictable workload; - data-location or platform constraints require customer-controlled infrastructure; - a custom sharding or replication design is part of the platform architecture. In this model, the team needs ownership beyond `clickhouse-server` installation. For a replicated deployment, the operating surface can include: ```text ClickHouse replicas + ClickHouse Keeper quorum + storage + backups + monitoring + upgrades + networking + capacity planning + failure testing ``` ClickHouse’s current Kubernetes Operator can automate parts of cluster provisioning, Keeper, scaling, configuration, and rolling upgrades. Automation reduces manual work, but it does not remove ownership of the operator, Kubernetes platform, storage, backups, monitoring, or recovery. Self-hosting makes the most sense when your team wants those controls **and has the operational capability to use them safely**. ## Managed ClickHouse is strongest when database operations are not the product Managed ClickHouse is usually attractive when the business needs analytical performance but does not want to build a ClickHouse platform team. It fits especially well when: - the database supports customer-facing analytics or dashboards; - developers need a production cluster without owning host patching; - backups and restore workflows should be service-operated; - scaling should happen through a provider workflow rather than cluster redesign; - monitoring should arrive with the service; - a small team cannot justify dedicated ClickHouse operations expertise; - predictable responsibility boundaries are more valuable than root access. The provider still cannot fix a poor ordering key, an uncontrolled ingestion pattern, a bad TTL policy, or an expensive query design. Those remain application and data-engineering responsibilities. At Raff, the recurring operating-model rule is: **if the team’s competitive advantage is the analytics product rather than operating ClickHouse itself, managed infrastructure should be the default candidate until a specific control requirement proves otherwise.** ## Scaling changes the ownership gap Single-node ClickHouse is operationally much simpler than a distributed production cluster. A self-hosted team can first scale vertically by adding CPU, memory, and faster storage. When one node is no longer enough, horizontal growth can introduce replicas for availability/read capacity and shards for data or compute distribution. ClickHouse Keeper coordinates replicated state in self-managed clusters. Every new layer adds decisions: - How many replicas? - How many shards? - Where does Keeper run? - How are cluster configuration changes rolled out? - How are distributed DDL operations handled? - How is data rebalanced? - How are upgrades sequenced? - What happens when a node or coordination service is unavailable? Managed platforms move part or all of those infrastructure decisions behind the service boundary. That is why the managed-vs-self-hosted decision can change over time. A team may reasonably self-host one analytical node, then move to managed infrastructure when HA, sharding, backups, and upgrades make ClickHouse operations a separate platform responsibility. ## Backups and replicas must remain separate decisions Replication and backups solve different failure classes. | Failure | Replica / HA helps? | Backup helps? | |---|---:|---:| | One database node fails | Yes | Usually not the fastest path | | A destructive mutation replicates | No | Yes, if recovery point predates it | | Data is deleted intentionally by mistake | Usually no | Yes | | Storage becomes unavailable on one node | Yes, with correct topology | Yes for recovery | | Entire cluster configuration is lost | Partly | Backup + documented rebuild path | | Bad schema or ingestion change corrupts logical results | Often reproduces problem | Historical recovery may help | Self-hosted teams must choose backup destinations, schedules, retention, credentials, restore procedures, and verification. Managed services reduce that platform work, but customers still need to understand the provider’s retention and recovery contract and validate application correctness after recovery. Raff Managed ClickHouse currently documents daily full backups plus six-hour incremental chains and on-demand backups. ClickHouse Cloud has its own backup model and current billing documentation says backup storage is billed as storage. Do not transfer one provider’s recovery assumptions to another. For a broader recovery framework, read [Database Restore Testing: RPO, RTO, and Recovery Validation](/learn/guides/database-restore-testing-rpo-rto-recovery-validation). ## A practical decision framework | Situation | Better starting point | |---|---| | Small team, production analytics, no ClickHouse operator | Managed ClickHouse | | Need exact host/version/storage control | Self-hosted ClickHouse | | One low-risk internal analytics node | Self-hosting can be reasonable | | Customer-facing analytics with recovery requirements | Managed is usually easier to own | | Existing ClickHouse platform team and stable workload | Self-hosting deserves TCO evaluation | | Workload is highly intermittent | Compare autoscaling managed economics carefully | | Business needs predictable monthly infrastructure lines | Compare flat-plan managed models | | Custom multi-shard topology is strategic | Self-hosting may justify its operational cost | | Team wants to move off a self-hosted cluster | Managed migration path | The decision should be revisited when workload or team structure changes. “We already run it ourselves” is not a permanent architecture requirement. ## Where Raff fits [Raff Managed ClickHouse](/products/managed-databases/clickhouse) is aimed at teams that want ClickHouse without operating the host, backup platform, routine upgrades, monitoring layer, and HA plumbing themselves. The current service provides ClickHouse 25.8 LTS, plan-based NVMe resources, daily plus incremental backups, TLS and IP allowlists, private connectivity, query insights, storage expansion, and optional HA using two replicas with Keeper. Raff also currently offers migration assistance for teams moving from ClickHouse Cloud or self-hosted ClickHouse. Teams that need full host control can instead run ClickHouse on [Raff VMs](/products/raff-vm) and own the database lifecycle themselves. That gives two distinct Raff paths: ```text Want ClickHouse, not ClickHouse operations → Raff Managed ClickHouse Need root access and exact cluster control → self-host ClickHouse on Raff VMs ``` The product choice should follow the responsibility requirement, not the other way around. ## Production checklist before choosing Before signing off on either model, document: - [ ] dataset size after ClickHouse compression; - [ ] monthly growth and retention period; - [ ] ingestion rate and peak bursts; - [ ] important query latency and concurrency; - [ ] required uptime and node-failure behavior; - [ ] replica/shard requirements; - [ ] backup retention and restore target; - [ ] monthly public/cross-region transfer; - [ ] upgrade ownership; - [ ] monitoring and alert ownership; - [ ] on-call ownership; - [ ] exact host-level controls the application genuinely needs; - [ ] billing dimensions and spend guardrails; - [ ] migration and rollback plan. If the self-hosted case cannot name who owns upgrades, Keeper, backups, restore testing, and incidents, the apparent infrastructure savings are incomplete. If the managed case cannot explain service limits, billing dimensions, recovery behavior, and the remaining customer responsibilities, the convenience case is also incomplete. ## Conclusion Managed ClickHouse vs self-hosted ClickHouse is ultimately a choice about **which operational responsibilities are worth owning**. Self-hosting gives maximum control and can be efficient for teams with mature ClickHouse operations and predictable workloads. Managed ClickHouse reduces platform work and can be the better business decision when the team wants to spend engineering time on analytics, ingestion, and product behavior instead of cluster maintenance. For cost, compare the same dataset, duty cycle, reliability target, backup policy, and engineering ownership. For scaling, price the architecture you will need after one node—not only the machine that gets you started. Continue with [ClickHouse Architecture for Production Analytics](/learn/guides/clickhouse-architecture-production-analytics) for schema and ingestion design, or review [Database Reliability Operations for Small Teams](/learn/guides/database-reliability-operations-small-teams) for monitoring and recovery ownership. :::cta Explore Managed ClickHouse Compare Raff’s current ClickHouse plans and migration path with the operating cost of running the cluster yourself. ::: ## Sources - [ClickHouse Cloud Pricing](https://clickhouse.com/pricing) - [ClickHouse Cloud Billing Overview](https://clickhouse.com/docs/products/cloud/reference/billing/billing-overview) - [ClickHouse Cloud Architecture](https://clickhouse.com/cloud) - [ClickHouse Keeper](https://clickhouse.com/clickhouse/keeper) - [ClickHouse Kubernetes Operator](https://clickhouse.com/blog/clickhouse-kubernetes-operator) - [Raff Managed ClickHouse](/products/managed-databases/clickhouse) - [Raff Managed Databases](/products/managed-databases) - Product and pricing details reviewed: 2026-08-24 --- ### Redis RDB vs AOF: Persistence & Data Loss Trade-Offs URL: https://rafftechnologies.com/learn/guides/redis-persistence-rdb-aof-data-loss-trade-offs Description: Compare Redis RDB vs AOF across durability, fsync behavior, restart speed, write overhead, backup use, data-loss windows, and when to use both. **RDB and AOF solve different Redis persistence goals.** RDB creates periodic point-in-time snapshots; AOF records write operations so Redis can replay them after restart. RDB is compact and usually faster to restore, but it can lose changes made after the last snapshot. AOF can reduce the data-loss window substantially—Redis documents `appendfsync everysec` as the suggested/default compromise, with roughly one second of potential data loss in a severe failure—but it adds write I/O and larger persistence files. For higher-value state, Redis can use **RDB and AOF together**. Since Redis 7, AOF uses a multi-part format with a base file plus incremental AOF files. When both RDB and AOF are enabled, Redis uses the AOF dataset during restart because it is considered the more complete copy. Raff Technologies offers a managed Redis-compatible path through [Managed Valkey](/products/managed-databases/valkey), while teams that need exact Redis persistence controls can self-host Redis on a [Raff VM](/products/raff-vm). In either model, persistence should follow the workload's recovery requirements rather than being enabled by habit. ## Redis RDB vs AOF: quick comparison | Factor | RDB | AOF | |---|---|---| | Persistence method | Periodic point-in-time snapshot | Logs write operations for replay | | Typical data-loss window | Changes since last successful snapshot | Depends on fsync policy; `everysec` is designed for about a one-second window in a severe failure | | Write-path overhead | Lower between snapshot events | Continuous append + fsync overhead | | File characteristics | Compact snapshot artifact | Larger write history; rewritten/compacted over time | | Restart behavior | Load snapshot | Replay AOF dataset | | Backup friendliness | Strong: compact point-in-time files | Useful, but operationally larger and more complex | | Best fit | Rebuildable state, wider RPO, backup snapshots | State needing a smaller recovery gap | | Can use both? | Yes | Yes | The practical choice is not “which is faster?” but **how much acknowledged data can the application lose, how quickly must it recover, and can the state be rebuilt from another durable source?** ## What is Redis RDB persistence? RDB persistence creates a snapshot of the in-memory dataset at a point in time. Redis writes the dataset to an RDB file according to configured save rules or explicit snapshot commands. A simple timeline looks like this: ```text 12:00 RDB snapshot completes 12:01 writes 12:02 writes 12:03 host/process failure ``` If the 12:00 snapshot is the latest valid RDB file, changes made after it may not be present after recovery. That makes RDB a good fit when: - the application can tolerate a recovery gap; - the dataset is mostly rebuildable cache or derived state; - compact backup artifacts are useful; - lower continuous write overhead matters; - fast loading from a snapshot is valuable; - the business recovery point objective can be met by the snapshot schedule. RDB is less suitable when losing the most recent minutes of queue, session, or coordination state would create unacceptable customer impact. ### RDB schedule effectively sets the recovery point An RDB configuration is also an RPO decision. If snapshots are created every five minutes, a catastrophic failure immediately before the next snapshot can expose close to five minutes of unpersisted changes. The exact risk depends on the save rules and whether the latest snapshot completed successfully. Do not choose an RDB schedule only from CPU or disk convenience. Match it to the application's acceptable data-loss window. ## What is Redis AOF persistence? AOF—Append Only File—records write operations so Redis can reconstruct the dataset by replaying them after restart. This can provide a smaller recovery gap than periodic RDB snapshots, but the durability depends heavily on the `appendfsync` policy. Redis currently documents three main policies: | `appendfsync` policy | Behavior | Trade-off | |---|---|---| | `always` | Sync each append to durable storage | Strongest durability, highest write overhead | | `everysec` | Sync approximately once per second | Suggested/default compromise; roughly one second of potential loss in a severe failure | | `no` | Let the operating system decide when to flush | Lowest application-side fsync overhead, larger/less predictable loss window | For most production applications considering AOF, `everysec` is the useful starting point because it balances durability and performance better than syncing every write. AOF is attractive when: - recent write loss must be minimized; - queue or session state has a tighter recovery target; - the storage layer can handle continuous persistence I/O; - the team can monitor AOF size and rewrite activity; - a one-snapshot-per-several-minutes RPO is not acceptable. AOF still does not turn Redis into the ideal source of truth for invoices, orders, subscriptions, audit history, or other durable business records. Those usually belong in a database designed as the authoritative system of record. ## Redis 7+ uses multi-part AOF Modern Redis AOF is not simply one ever-growing log file. Since Redis 7, AOF uses a **multi-part format**. Redis can maintain: - a base AOF file representing the dataset at rewrite time; - one or more incremental AOF files containing later changes; - a manifest that tracks the active AOF parts. This improves AOF rewrite management and changes what operators should expect to see on disk. For self-hosted Redis, backup, restore, file-copy, and monitoring procedures should therefore be based on the current AOF layout rather than assuming a single legacy `appendonly.aof` file is the complete persistence state. ## RDB vs AOF: which should you use? Use **RDB** when the workload can tolerate the snapshot recovery gap and values compact backups, lower continuous write overhead, and straightforward point-in-time recovery. Use **AOF** when the workload requires a smaller data-loss window and the added write I/O and file-management overhead are acceptable. Use **RDB + AOF** when the state is important enough that both a compact snapshot path and a more granular write log are valuable. Use **no persistence** when the dataset is truly disposable and safely rebuildable from another source. A useful starting table is: | Workload | Starting persistence model | |---|---| | Rebuildable read cache | None or periodic RDB | | Session store | RDB or AOF based on acceptable logout/state-loss window | | Rate-limit counters | Depends on whether resets are acceptable | | Locks | Persistence is usually not the main correctness mechanism | | Queue / pending jobs | AOF or another stronger recovery design, plus application-level idempotency | | Streams with important pending state | Tighter persistence and tested recovery | | Durable customer/business records | Keep authoritative state in a primary durable database | Temporary data can still be production-critical. A session store is not the system of record, but losing every active session may still be a serious incident. ## What happens when RDB and AOF are both enabled? Redis supports running RDB and AOF together. When both are enabled, Redis uses **AOF to reconstruct the dataset during restart** because the AOF is expected to contain the more complete version of the data. RDB still provides value in this configuration: - compact periodic recovery artifacts; - convenient off-host backups; - faster disaster-recovery options in some workflows; - an additional recovery path if an AOF-related problem occurs; - easier point-in-time archival. Using both is not automatically better for every workload. It increases disk activity, storage use, monitoring, and recovery complexity. A disposable cache may not need either mechanism; a production queue may justify both plus independent backups. ## RDB and AOF have different performance costs Persistence affects more than disk space. ### RDB resource impact RDB snapshots can create temporary pressure from: - process forking; - copy-on-write memory; - snapshot I/O; - temporary disk-space requirements; - snapshot duration on large datasets. A server that is comfortably sized for steady-state memory can still experience pressure during snapshot work. ### AOF resource impact AOF adds: - continuous append I/O; - fsync activity according to policy; - growing persistence files between rewrites; - AOF rewrite work; - additional disk-space needs during rewrite/compaction; - longer recovery replay for larger write histories. Capacity planning should leave headroom for persistence operations, not only for the in-memory dataset itself. Monitor at least: - used memory and RSS; - disk free space; - persistence file size; - last successful RDB save; - RDB save duration; - AOF rewrite status and duration; - persistence errors; - write latency during persistence operations; - restart/restore time. ## Persistence does not replace backups RDB and AOF answer: > What can Redis reconstruct after a process or host restart when the persistence files are still available? A backup strategy answers: > What can we recover after the host, disk, account, or persistence files themselves are lost or corrupted? Keeping RDB or AOF only on the same host is therefore not sufficient for important state. If the data matters, define: - an off-host or independent copy; - backup frequency; - retention; - encryption/access controls; - restore ownership; - restore validation; - maximum acceptable data loss (RPO); - maximum acceptable recovery time (RTO). A persistence file that has never been restored successfully is only an untested recovery assumption. For the wider recovery model, see [RPO vs RTO for Cloud Backups](/learn/guides/cloud-server-backup-rpo-rto-snapshots) and [Database Restore Testing](/learn/guides/database-restore-testing-rpo-rto-recovery-validation). ## No persistence can be correct for a pure cache If every key is safely rebuildable, running Redis without persistence can be a valid production design. Recovery becomes: ```text Redis restarts empty → application misses cache → durable source serves requests → cache warms again ``` The operational risk is then **cold-cache pressure**, not loss of authoritative data. Before using no persistence, verify: - the primary database can survive the temporary miss rate; - expensive keys can be rebuilt safely; - cache warming will not create a thundering-herd problem; - request latency during warm-up is acceptable; - the application behaves correctly when the cache is unavailable. Do not enable AOF merely because “production Redis should be persistent” if the workload is designed to be disposable. ## Valkey uses the same RDB and AOF concepts Valkey supports RDB and AOF persistence concepts, including using them together. This makes the same recovery questions relevant to teams moving between Redis and Valkey. Migration still needs version awareness. Valkey documents compatibility with Redis OSS 2.x through 7.2.x RDB/AOF files for Valkey 7.2+ migration paths, while later Redis Community Edition persistence files should not be assumed compatible automatically. If persistence files will be copied during migration, record: ```text source Redis version → source persistence mode → target Valkey version → supported file-compatibility path → restore validation ``` For the broader compatibility decision, see [Redis vs Valkey: Compatibility, Operations, and Migration](/learn/guides/redis-vs-valkey-compatibility-migration). ## How this maps to Raff Raff's managed Redis-compatible service is [Managed Valkey](/products/managed-databases/valkey). A managed service reduces host-level persistence, patching, and service-lifecycle work, while the application team still owns the business meaning of cache, sessions, queues, TTLs, and acceptable data loss. Teams that need exact Redis configuration, direct persistence-file access, custom modules, or host-level control can self-host Redis on a [Raff VM](/products/raff-vm). Do not choose managed or self-hosted Redis-compatible infrastructure only from persistence features. Choose from the responsibility boundary: ```text Want less platform operations → evaluate Managed Valkey Need exact Redis persistence/host controls → self-host Redis on a VM ``` Use the live [Managed Databases](/products/managed-databases) and [Raff VM](/products/raff-vm) pages for current service scope rather than static plan details in this guide. ## Redis persistence production checklist - [ ] Workload role is documented: cache, sessions, queue, stream, lock, or other state. - [ ] Acceptable data-loss window is defined. - [ ] RDB snapshot schedule matches the intended RPO if RDB is used. - [ ] `appendfsync` policy is explicitly chosen if AOF is used. - [ ] AOF multi-part files are included in self-hosted backup/recovery procedures. - [ ] Disk has headroom for snapshots and AOF rewrites. - [ ] Memory has headroom for fork/copy-on-write behavior. - [ ] Persistence failures are monitored. - [ ] Off-host backups exist if the state matters. - [ ] Restore time has been measured. - [ ] Cache warm-up behavior is understood if persistence is disabled. - [ ] Durable business records remain in the appropriate primary database. ## Conclusion For **Redis RDB vs AOF**, RDB is the simpler point-in-time snapshot model and AOF is the finer-grained write-log model. Choose RDB when a snapshot-defined recovery gap is acceptable. Choose AOF when the workload needs a smaller data-loss window and can absorb the extra I/O and file-management work. Use both when the workload justifies multiple recovery paths, and keep independent backups whenever the persisted state actually matters. The persistence mode should follow RPO, RTO, workload role, and recovery testing—not a generic rule that every production Redis instance needs the same configuration. :::cta Explore Managed Valkey Reduce Redis-compatible host operations while keeping application-level durability and recovery requirements explicit. ::: ## Sources - [Redis Persistence](https://redis.io/docs/latest/operate/oss_and_stack/management/persistence/) - [Valkey Migration from Redis](https://valkey.io/topics/migration/) - [Raff Managed Valkey](/products/managed-databases/valkey) - [Raff Managed Databases](/products/managed-databases) - Product and technical details reviewed: 2026-09-14 --- ### Redis Eviction Policies: Choosing the Right Memory Strategy URL: https://rafftechnologies.com/learn/guides/redis-eviction-policies-memory-strategy Description: Choose a Redis eviction policy across LRU, LFU, LRM, noeviction, volatile policies, maxmemory, TTLs, monitoring, and Valkey compatibility. Redis eviction policies determine what Redis does when the dataset reaches the configured `maxmemory` threshold. Depending on `maxmemory-policy`, Redis can reject memory-growing writes or evict keys using LRU, LFU, LRM, TTL, or random-selection rules. For most dedicated caches, **`allkeys-lru` or `allkeys-lfu` are practical starting points**. Use `noeviction` when silently deleting keys is less acceptable than returning write errors. Use `volatile-*` policies only when TTLs deliberately identify which keys are safe to evict. Raff Technologies supports Redis-compatible workloads through [Managed Valkey](/products/managed-databases/valkey), while teams that need exact Redis configuration can self-host Redis on a [Raff VM](/products/raff-vm). In either model, the eviction policy is an application reliability decision: the infrastructure cannot decide which of your keys are safe to lose. For persistence behavior, see [Redis RDB vs AOF](/learn/guides/redis-persistence-rdb-aof-data-loss-trade-offs). For cache, queue, and session role design, use [Redis Cache Strategy for SaaS Apps](/learn/guides/redis-cache-queue-strategy-saas-apps). ## Redis eviction policies: quick decision table | Policy | Keys eligible for eviction | Selection rule | Typical fit | |---|---|---|---| | `noeviction` | None | Reject memory-growing writes | State that must not disappear silently | | `allkeys-lru` | Any key | Least recently used | General-purpose dedicated cache | | `allkeys-lfu` | Any key | Least frequently used | Stable hot-set cache | | `allkeys-lrm`* | Any key | Least recently modified | Read-heavy Redis workloads where stale writes matter more than reads | | `allkeys-random` | Any key | Random | Uniform/cyclic access patterns | | `volatile-lru` | TTL keys only | Least recently used | Mixed dataset with deliberate TTL boundary | | `volatile-lfu` | TTL keys only | Least frequently used | TTL-scoped cache with stable hot set | | `volatile-lrm`* | TTL keys only | Least recently modified | Redis workloads with TTL-scoped write recency | | `volatile-random` | TTL keys only | Random | TTL-scoped uniform data | | `volatile-ttl` | TTL keys only | Shortest remaining TTL | TTL intentionally signals eviction priority | \* Current Redis documentation lists LRM policies starting with Redis 8.6. Valkey's current eviction documentation lists LRU, LFU, random, TTL, and `noeviction` policies but not LRM. Verify the exact engine and version before depending on LRM behavior. The most important question is not LRU versus LFU. It is **which keys are allowed to disappear when memory pressure arrives**. ## How `maxmemory` and eviction work Redis uses `maxmemory` to define the dataset memory threshold at which the configured eviction behavior is enforced. A self-hosted configuration can be set in `redis.conf`: ```text maxmemory 4gb maxmemory-policy allkeys-lru ``` or changed at runtime with `CONFIG SET`. The simplified flow is: ```text Client command adds data → Redis checks memory → memory exceeds maxmemory → eviction policy selects keys, or write is rejected → Redis returns below the dataset limit ``` A single large command can temporarily push memory noticeably above `maxmemory` before Redis brings the dataset back under the configured threshold. Treat `maxmemory` as an eviction threshold, not an exact ceiling for total process RSS. ## `maxmemory` is not the same as total Redis process memory A common production mistake is setting `maxmemory` equal to all RAM available to the process or VM. Redis may need additional memory for: - replication buffers; - AOF buffers; - client buffers; - allocator overhead and fragmentation; - persistence operations; - fork/copy-on-write behavior; - operating-system processes. Redis specifically excludes some replication and AOF buffer memory from the value compared against `maxmemory`. The `INFO memory` field `mem_not_counted_for_evict` exposes memory used by those buffers. For a replicated or persisted deployment, leave headroom instead of treating `maxmemory` as the machine's physical RAM size. Useful checks include: ```text INFO memory INFO stats ``` Review at least: - `used_memory`; - `used_memory_dataset`; - `mem_not_counted_for_evict`; - RSS/resident memory; - fragmentation; - `evicted_keys`; - `expired_keys`; - keyspace hits and misses; - rejected commands; - time spent above the eviction threshold. ## `allkeys-lru` is a strong default for many dedicated caches LRU means **Least Recently Used**. `allkeys-lru` makes every key eligible for eviction and favors retaining keys accessed recently. It fits applications where recent access is a useful predictor of future demand. Typical examples include: - application response caches; - profile or permission lookup caches; - dashboard fragments; - API response caches; - recently viewed catalog data. Example: ```text hot profile → accessed repeatedly → likely retained old dashboard result → not accessed recently → more likely evicted ``` Redis does not implement mathematically exact LRU. It samples candidate keys and chooses among them, which avoids the memory overhead of maintaining a perfect global ordering. Redis exposes `maxmemory-samples` for self-hosted deployments that need to tune the approximation. Increasing the sample count can make eviction closer to exact LRU at the cost of additional CPU work. Do not tune this before measuring whether cache misses are actually a problem. ## `allkeys-lfu` favors a stable hot set LFU means **Least Frequently Used**. Instead of primarily asking which key was accessed recently, LFU tries to preserve keys that are repeatedly useful over time. That can fit workloads where a relatively small group of keys stays popular while one-off scans or bursts should not displace them. Typical examples include: - popular product metadata; - frequently reused configuration; - common authorization data; - API responses with a stable popularity distribution; - catalog data with a persistent hot set. The useful distinction is: ```text LRU → what was used recently? LFU → what is used frequently? ``` Redis and Valkey both implement LFU approximately rather than maintaining exact access counters for every request. Frequency counters also decay so historically popular keys do not remain permanently protected after traffic patterns change. Use cache hit rate, eviction rate, origin-database load, and latency to decide whether LFU actually performs better for your workload. ## LRU vs LFU vs LRM The three policies optimize for different signals: | Policy | Tracks | Better fit when... | |---|---|---| | LRU | Recent access | Recent use predicts near-future reuse | | LFU | Access frequency | A persistent hot set should survive one-off scans | | LRM | Recent modification | Frequently read but stale/unmodified data should be evicted before actively updated data | LRM means **Least Recently Modified**. Current Redis documentation states that LRM is available starting with Redis 8.6 and updates its recency signal on writes rather than reads. This makes LRM relevant to a read-heavy workload where a key can be read frequently but has not been updated for a long time. In that situation, LRU may keep the key because reads continually refresh its recency, while LRM can still treat it as an old modification candidate. Do not assume LRM is available across every Redis-compatible engine. Valkey's current documentation does not list LRM among its eviction policies, so check the exact engine/version before putting LRM into configuration or migration runbooks. ## `volatile-*` policies make TTL part of the eviction boundary Volatile policies only consider keys that have an expiration. That creates a potential boundary such as: ```text cache keys → TTL set → eligible for eviction persistent keys → no TTL → not eligible under volatile policy ``` This can work, but only when TTL ownership is disciplined. Two failure modes matter: 1. A cache key accidentally has no TTL, so it becomes protected from volatile eviction and keeps consuming memory. 2. An important key accidentally gets a TTL, so it becomes eligible for eviction. There is another important behavior: **if no keys satisfy the volatile policy's TTL requirement, Redis/Valkey behaves like `noeviction` and memory-growing writes can fail.** That means a volatile policy is not a guarantee that Redis will always be able to free memory. Use volatile policies when TTLs are part of the application's explicit data contract, not as a workaround for mixed responsibilities that would be safer on separate instances. ## `volatile-ttl` uses expiry time as an eviction hint `volatile-ttl` selects among expiring keys and favors those with the shortest remaining time-to-live. Example: ```text key A → expires in 20 seconds key B → expires in 30 minutes key C → expires in 4 hours ``` Under memory pressure, key A is the strongest eviction candidate because it is already close to natural expiration. This is useful when the application sets meaningful TTLs that reflect business value or recomputation cost. It is less useful when TTLs are arbitrary. If expiration times do not represent how disposable a key is, `volatile-ttl` is using a poor signal. ## `allkeys-random` can fit uniform access patterns Random eviction is less sophisticated but can be reasonable when all keys have roughly equal reuse probability. For example, an application that continuously scans or cycles through the entire dataset may not gain much from trying to preserve a recency-based hot set. Random policies are also simple to reason about operationally: - `allkeys-random` can remove any key; - `volatile-random` only removes keys with TTLs. Do not choose random eviction simply because it is simpler to configure. Use it when the application's access distribution actually makes LRU/LFU signals weak. ## `noeviction` protects existing keys but makes writes fail With `noeviction`, Redis does not delete keys to make room. When the memory threshold is reached, commands that need to add more data can return errors. Read-only operations against existing data can continue. This may be safer for: - coordination state; - important sessions; - queue metadata; - locks; - state where silent deletion is worse than an explicit application error. But `noeviction` is not a durability feature. It simply changes the failure mode from hidden key loss to visible write rejection. Production use therefore needs: - memory alerts; - application handling for rejected writes; - capacity headroom; - retention or cleanup rules; - a scale-up or scale-out procedure; - incident ownership. A write error is safer than silent state loss only when the application is designed to handle the error. ## Cache, sessions, queues, and locks should not share one eviction assumption The biggest architecture risk is combining workloads that have different loss tolerance. | Workload | Eviction tolerance | Safer starting approach | |---|---|---| | Rebuildable read cache | High | `allkeys-lru` or `allkeys-lfu` | | Short-lived API cache | High | allkeys or carefully designed volatile policy | | Sessions | Medium to low | Separate instance or explicit failure contract | | Rate limits | Depends on security/product behavior | Avoid accidental eviction; define fail-open/fail-closed behavior | | Distributed locks | Low | Do not let eviction define correctness | | Queue state | Low | Separate role with persistence/recovery plan | One Redis-compatible endpoint can technically support several of these roles. That does not mean one `maxmemory-policy` makes sense for all of them. A practical Raff rule is: **if deleting one class of keys is normal but deleting another causes a customer incident, separate those roles before tuning the eviction algorithm.** For workload boundaries, see [Redis Cache Strategy for SaaS Apps](/learn/guides/redis-cache-queue-strategy-saas-apps). ## TTL and eviction solve different problems TTL defines how long a key should exist under normal application behavior. Eviction defines what happens when memory runs short before that normal lifecycle completes. ```text TTL = normal key lifetime maxmemory-policy = memory-pressure behavior ``` A cache key should still have a deliberate lifecycle even when the server is allowed to evict it earlier. For important cache namespaces, document: - source of truth; - expected lifetime; - invalidation event; - stale-data tolerance; - rebuild cost; - behavior on cache miss; - effect of mass eviction or cold restart. Do not use aggressive eviction to compensate for keys that should have expired naturally but never received a TTL. ## Monitor eviction with cache outcomes, not one counter Some eviction is normal for a bounded cache. `evicted_keys` increasing does not automatically indicate an incident. Correlate it with: - `keyspace_hits`; - `keyspace_misses`; - cache hit ratio; - `evicted_keys`; - `expired_keys`; - origin-database load; - request latency; - write rejections; - memory usage and fragmentation; - traffic/deployment changes. A healthy pattern might be: ```text Evictions rise moderately + hit rate remains high + origin database remains stable + user latency remains stable = normal bounded-cache churn may be acceptable ``` A problem pattern looks more like: ```text Evictions spike + hit rate falls + origin database load rises + latency rises = capacity, key lifecycle, or policy mismatch ``` For `noeviction` and volatile policies, also monitor rejected commands. Redis exposes command statistics that can show which commands are being stopped after the memory threshold is reached. ## Redis and Valkey policy compatibility is similar but not identical Redis and Valkey share the core eviction model: - `maxmemory`; - `noeviction`; - LRU; - LFU; - random eviction; - volatile TTL-scoped variants; - `volatile-ttl`; - approximate sampling algorithms. But exact policy availability can diverge as the projects evolve. Redis currently documents LRM policies starting with Redis 8.6, while Valkey's current key-eviction documentation does not list LRM. If you are moving a workload between Redis and Valkey, include the eviction configuration in the compatibility checklist rather than assuming that every `maxmemory-policy` string is portable. For the larger migration decision, see [Redis vs Valkey: Compatibility, Operations, and Migration](/learn/guides/redis-vs-valkey-compatibility-migration). ## How this maps to Raff Raff's managed Redis-compatible path is [Managed Valkey](/products/managed-databases/valkey). Managed infrastructure reduces host-level operational work, while the application team still owns the meaning of cache keys, TTLs, sessions, queues, and acceptable eviction. Teams that need direct Redis configuration, exact engine/version control, or host-level access can self-host Redis on a [Raff VM](/products/raff-vm). The decision path is: ```text Want less host/database operations → evaluate Managed Valkey Need exact Redis maxmemory-policy or host controls → self-host Redis on a VM ``` Use current live product pages for service scope rather than treating static article copy as the source of truth for plan limits or managed-database capabilities. ## Redis eviction production checklist - [ ] Every key role is classified as disposable or non-disposable. - [ ] `maxmemory` leaves runtime and operating-system headroom. - [ ] Replication/AOF buffer memory is considered where applicable. - [ ] The selected policy matches the workload's allowed data loss. - [ ] TTL keys are deliberate if a `volatile-*` policy is used. - [ ] The team knows volatile policies can fall back to write rejection when no eligible TTL keys exist. - [ ] LRU, LFU, or LRM is chosen from an actual access/update pattern. - [ ] Exact Redis/Valkey policy support is verified for the deployed version. - [ ] Cache hit/miss and eviction metrics are monitored together. - [ ] Rejected writes are monitored for `noeviction` or volatile-policy exhaustion. - [ ] Queue/session/lock state is separated when loss tolerance differs. - [ ] Cache warm-up and mass-eviction behavior are understood. ## Conclusion Redis eviction policy determines **which failure mode appears when the dataset reaches its memory boundary**. Use `allkeys-lru` when recent use is the best signal for future reuse, `allkeys-lfu` when a stable hot set matters, and Redis 8.6+ LRM when recent modification—not recent reading—is the useful signal and your exact engine supports it. Use volatile policies only when TTLs deliberately define the evictable set, and use `noeviction` when rejecting writes is safer than silently deleting existing state. The best policy is the one that preserves the right data and produces a failure mode your application is prepared to handle. :::cta Explore Managed Valkey Run Redis-compatible workloads with managed infrastructure while keeping memory and eviction policy aligned to application behavior. ::: ## Sources - [Redis Key Eviction](https://redis.io/docs/latest/develop/reference/eviction/) - [Valkey Key Eviction](https://valkey.io/topics/lru-cache/) - [Raff Managed Valkey](/products/managed-databases/valkey) - [Raff Managed Databases](/products/managed-databases) - Technical details reviewed: 2026-09-14 --- ### Redis Hosting: Managed Valkey vs Self-Hosted Redis URL: https://rafftechnologies.com/learn/guides/redis-hosting Description: Compare Redis hosting options: managed Valkey vs self-hosted Redis across cost, control, persistence, security, backups, monitoring, compatibility, and operations. **Redis hosting** usually means choosing between a managed Redis-compatible service and running Redis yourself on a VM or server. Managed hosting removes much of the host, patching, monitoring, backup, and failover work. Self-hosted Redis gives you direct control over the operating system, Redis version, configuration, persistence files, modules, and topology. For most small teams, **managed Redis-compatible hosting is the safer default when Redis supports production sessions, queues, rate limits, or customer-facing cache performance.** Self-host Redis when you have a documented reason to need root access, exact Redis behavior, custom modules, direct persistence-file access, or infrastructure controls the managed service does not expose. Raff Technologies offers a managed Redis-compatible path through [Managed Valkey](/products/managed-databases/valkey), while exact Redis can be self-hosted on a [Raff VM](/products/raff-vm). This guide compares those two operating models without treating Valkey and Redis as identical products. ## Redis hosting: managed vs self-hosted quick comparison | Decision factor | Managed Redis-compatible hosting | Self-hosted Redis | |---|---|---| | Host provisioning | Provider | Your team | | OS patching | Provider | Your team | | Redis/Valkey service lifecycle | Provider-defined | Your team | | Root / OS access | Usually no | Yes | | Exact Redis version | Service-defined | Your choice | | Custom `redis.conf` | Limited to exposed controls | Full control | | Modules | Service support varies | Your choice | | Persistence files | Managed through service workflow | Direct access | | Monitoring | Usually included to a defined scope | You build/integrate it | | Backups / snapshots | Provider workflow | You design and operate it | | HA / failover | Provider option where supported | You design and operate it | | Security boundary | Provider + application team | Infrastructure + application team | | Best fit | Teams reducing database operations | Teams needing exact Redis/host control | The important distinction is **operational ownership**, not whether both options can answer Redis-compatible commands. ## What does “Redis hosting” actually include? A production Redis deployment is more than a process listening on port `6379`. A complete hosting model includes: - compute and memory sizing; - operating-system maintenance; - network access; - authentication and credentials; - TLS where required; - `maxmemory` and eviction policy; - persistence strategy; - backups and retention; - restore procedures; - monitoring and alerting; - upgrades; - replicas or failover when required; - incident response. A managed service owns some of these responsibilities for you. A self-hosted deployment moves them back to your team. That is why comparing only the managed monthly plan against the price of one VM is incomplete. ## Managed Redis hosting vs Managed Valkey “Managed Redis hosting” is often used as a generic search term for a hosted Redis-compatible cache, session store, or queue layer. Raff's managed engine is **Valkey**, not Redis Community Edition. Valkey is a Linux Foundation project that forked from Redis OSS 7.2 and preserves compatibility with Redis OSS 7.2 and earlier open-source releases. Newer Redis and Valkey releases can evolve independently, so compatibility should be validated against the exact commands, clients, modules, persistence files, and server behavior your application uses. Current Raff Managed Valkey capabilities are documented on the live product page. At the time of this review, the service includes managed networking and observability, TLS/IP access controls, snapshots, configurable eviction behavior, and an optional high-availability path. These capabilities can change, so use the [Managed Valkey product page](/products/managed-databases/valkey) as the source of truth rather than static limits in this guide. Managed Valkey is a stronger fit when: - the application already uses Redis-compatible clients; - the team wants less host maintenance; - cache or session availability affects customers; - queues or rate limits have become production dependencies; - backups and failover should use a provider workflow; - private/restricted connectivity matters; - no requirement depends on root access or an unsupported module. A managed service does **not** decide which keys are safe to evict, how long sessions should live, whether queue jobs are idempotent, or whether Redis-compatible state can be reconstructed. Those remain application decisions. ## Self-hosted Redis: when direct control is worth the work Self-hosting Redis means your team owns the server and Redis lifecycle. It becomes reasonable when a requirement explicitly needs: - an exact Redis release; - root access; - custom Redis configuration; - direct RDB/AOF file access; - custom modules; - host-level monitoring or security agents; - OS/kernel tuning; - a custom replication or failover topology; - infrastructure placement your managed provider does not support. A real production checklist looks more like this: ```text Provision host → harden OS → install Redis → restrict network access → configure authentication / ACLs → set maxmemory + eviction → choose RDB / AOF / both / none → configure monitoring → configure backup → test restore → plan upgrades → plan failure recovery ``` If nobody owns those steps after launch, self-hosting is not actually cheaper—it is simply leaving operational work unpriced. For implementation, use [How to Install Redis on Ubuntu 24.04](/learn/tutorials/install-redis-ubuntu-24-04). For memory behavior, see [Redis Eviction Policies](/learn/guides/redis-eviction-policies-memory-strategy). For recovery, see [Redis RDB vs AOF](/learn/guides/redis-persistence-rdb-aof-data-loss-trade-offs). ## Hosted Redis for cache, sessions, queues, and rate limits The right hosting model depends heavily on what Redis is doing. | Workload | Operational sensitivity | Hosting implication | |---|---|---| | Rebuildable read cache | Lower | Managed or self-hosted can both fit | | Session store | Medium/high | Recovery, TTLs, availability, and security matter | | Rate limiting | Medium/high | Eviction/failure can change enforcement behavior | | Job queue | High | Persistence, retries, idempotency, and recovery matter | | Pub/sub | Depends | Reconnection and message-loss behavior matter | | Distributed locks | High | Do not let hosting/eviction assumptions define correctness | | Durable business records | Very high | Usually belongs in a durable primary database instead | Redis often begins as “just a cache” and later becomes login state, background job coordination, rate limiting, or real-time application infrastructure. Re-evaluate the hosting model when the consequences of losing or delaying Redis state become customer-visible. ## Managed vs self-hosted Redis cost Compare **total operating cost**, not one monthly number. A self-hosted Redis cost model can include: ```text VM / server + backup storage + monitoring + replica capacity + engineering time + security maintenance + upgrades + restore testing + incidents ``` A managed hosting cost model can include: ```text managed service plan + HA / extra capacity where required + application engineering + provider constraints ``` For a small development cache, one self-hosted VM may be perfectly reasonable. For a production session or queue layer, the difference in infrastructure price may be less important than the cost of an engineer owning patching, failover, backups, and recovery. Use the exact same workload when comparing options: - same memory target; - same availability requirement; - same recovery requirement; - same backup retention; - same network/security requirement; - same expected operator time. Do not compare a single Redis VM with a managed HA service and conclude that one is “more expensive” without normalizing the architecture. ## Redis hosting security Redis-compatible services should not be treated like public web applications. For managed hosting, review: - TLS support; - credential scope; - IP allowlists or network policy; - private connectivity; - account-level MFA/access control; - provider backup access; - auditability where required. For self-hosted Redis, also own: - OS patching; - firewall rules; - Redis bind/listen configuration; - authentication/ACL configuration; - SSH administration; - private-network design; - host monitoring; - secret rotation. The common unsafe pattern is exposing Redis directly to the public internet because it was quick during development. Production Redis should be reachable only from approved applications and administrators through a deliberately restricted network path. ## Persistence is separate from hosting Managed hosting does not automatically make Redis data durable, and self-hosting does not automatically mean persistence is configured correctly. Redis-compatible workloads usually choose among: - no persistence; - RDB snapshots; - AOF-style persistence where supported; - a combination of persistence mechanisms; - provider-managed snapshots/backups. The correct choice depends on what the data means. A rebuildable cache may intentionally run without durable persistence. A queue or session layer may need a much smaller data-loss window. Durable business records usually belong in a primary database designed to be the system of record. Define: - **RPO:** how much Redis-compatible state can be lost? - **RTO:** how long can recovery take? - who owns restoration; - where independent backups live; - how restore success is verified. For the detailed persistence decision, see [Redis RDB vs AOF](/learn/guides/redis-persistence-rdb-aof-data-loss-trade-offs). ## Eviction policy can matter more than hosting model A well-managed service with the wrong eviction policy can still cause application incidents. When `maxmemory` is reached, the engine may evict keys or reject writes depending on policy. That behavior can be harmless for rebuildable cache and dangerous for sessions, queues, locks, or rate-limit state. Before choosing a provider, answer: 1. Which keys are disposable? 2. Which keys must never disappear silently? 3. Are TTLs consistently set? 4. What happens when the cache is cold? 5. What happens when writes are rejected? 6. Can the database of record absorb a cache-miss spike? If cache keys can be dropped normally but queue/session keys cannot, separating those workloads is usually safer than looking for one perfect `maxmemory-policy`. ## Managed hosting does not remove application-level monitoring A provider can monitor hosts and database processes. Your team still needs to monitor whether Redis-compatible infrastructure is helping or hurting the application. Track metrics such as: - memory utilization; - latency; - connections; - cache hit/miss ratio; - evictions; - expired keys; - rejected writes; - queue depth where applicable; - replica/failover state where applicable; - persistence or backup failures; - origin-database load when cache misses increase. A green database status is not enough if cache hit rate collapses and the primary database becomes overloaded. ## Redis hosting migration checklist When moving from self-hosted Redis to managed Valkey—or between providers—treat compatibility and recovery as separate checks. Document: ```text source engine + version → clients / drivers → commands used → modules used → persistence format → key count + memory → TTL behavior → eviction policy → network dependencies → cutover plan → rollback plan ``` Valkey's official migration documentation describes compatibility with Redis OSS 7.2 and earlier open-source versions. Do not generalize that statement to every later Redis release or proprietary module without testing. Validate at least: - application connects successfully; - authentication works; - critical commands behave as expected; - Lua/scripts work if used; - modules have an equivalent path; - TTLs survive correctly; - queue/session behavior remains correct; - persistence/import path is supported; - rollback remains possible. For a broader engine comparison, see [Redis vs Valkey: Compatibility, Operations, and Migration](/learn/guides/redis-vs-valkey-compatibility-migration). ## How Raff fits Redis hosting Raff supports two distinct paths. ### Managed Redis-compatible hosting Use [Managed Valkey](/products/managed-databases/valkey) when you want Raff to own more of the database infrastructure lifecycle. Current capabilities, available sizes, HA options, backups, networking, and pricing should be verified on the live product page because managed-service features can evolve. ### Self-hosted Redis Use a [Raff VM](/products/raff-vm) when you need exact Redis and direct server control. The VM path gives your team control of the guest operating system, Redis release, configuration, modules, persistence, firewall rules, and backup tooling. Your team remains responsible for operating Redis inside the guest. A practical decision looks like this: ```text Need less database/platform operations → Managed Valkey → validate Redis compatibility Need exact Redis or host-level control → Self-host Redis on a VM → own the full Redis lifecycle ``` Neither is universally better. The correct option is the one that matches the workload's compatibility requirements and the operations your team is prepared to own. ## Redis hosting decision checklist Choose **managed Redis-compatible hosting** when most of these are true: - [ ] Redis-compatible clients are sufficient. - [ ] No unsupported Redis-specific module is mandatory. - [ ] The team wants less host/service maintenance. - [ ] Provider-managed backups or HA reduce operational risk. - [ ] Root access is unnecessary. - [ ] Service-defined networking and security controls fit the application. Choose **self-hosted Redis** when several of these are true: - [ ] Exact Redis version matters. - [ ] Root access is required. - [ ] Custom modules are required. - [ ] Direct RDB/AOF access is required. - [ ] Custom OS/network tuning is required. - [ ] The team already operates monitoring, backups, upgrades, and recovery confidently. ## Conclusion For most small teams evaluating **Redis hosting**, the best default is the option that minimizes operational risk without blocking a real technical requirement. Use managed Redis-compatible hosting when the application can run on Valkey-compatible behavior and your team benefits from provider-owned host operations, backups, monitoring, and availability tooling. Self-host Redis when exact Redis behavior or server-level control is genuinely required and your team can own the complete lifecycle. Do not choose from deployment speed alone. Choose the model you can secure, monitor, recover, upgrade, and operate after Redis becomes production-critical. :::cta Explore Managed Valkey Compare Raff's current managed Valkey capabilities with the operational work required to self-host Redis. ::: ## Sources - [Valkey Migration from Redis](https://valkey.io/topics/migration/) - [Redis Key Eviction](https://redis.io/docs/latest/develop/reference/eviction/) - [Redis Persistence](https://redis.io/docs/latest/operate/oss_and_stack/management/persistence/) - [Raff Managed Valkey](/products/managed-databases/valkey) - [Raff Managed Databases](/products/managed-databases) - Product and technical details reviewed: 2026-09-14 --- ### Microsoft SPLA Licensing Explained: Hosted Windows Server Guide URL: https://rafftechnologies.com/learn/guides/microsoft-spla-hosted-windows-vms Description: Understand Microsoft SPLA licensing for hosted Windows Server, including provider licensing, BYOL, RDS, SQL Server, pricing, and how to evaluate an SPLA host. Microsoft SPLA is the **Services Provider License Agreement**, Microsoft’s licensing program for service providers and ISVs that deliver eligible Microsoft software as hosted services to end customers. For a Windows Server buyer, the practical value is simple: **the hosting provider can supply the Microsoft licensing path for the hosted workload instead of requiring you to buy a standalone Windows Server license for that provider’s infrastructure.** That does not mean every Microsoft product is automatically included, and it does not make activation the same thing as licensing compliance. Raff Technologies provides Windows Server licensing through its Microsoft SPLA program. For the common hosted Windows Server Standard path, Raff currently lists the Windows license as **$15/month per VM**, separate from compute. Multi-user Remote Desktop Services, SQL Server, Microsoft 365 Apps, and other Microsoft products can require separate licensing. This guide focuses on **Microsoft SPLA licensing for hosted Windows Server** and how to evaluate an SPLA hosting provider before buying. For the broader Raff-specific decision between SPLA, evaluation, and customer-owned licensing, see [Windows Server Licensing on Raff](/windows-server/windows-licensing). > Microsoft licensing rules can change and depend on the exact product, agreement, deployment model, and user access. Microsoft Product Terms, the current Services Provider Use Rights (SPUR), and the applicable customer/provider agreements control the final licensing position. This guide is practical infrastructure guidance, not legal advice. ## What is Microsoft SPLA? Microsoft describes SPLA as a licensing program for service providers and ISVs that want to license eligible Microsoft software to provide hosted software services and applications to end customers. Current Microsoft licensing guidance confirms several important characteristics: - SPLA agreements have a **three-year term**; - eligible products are licensed for hosted service-provider use; - product use is governed by the **Services Provider Use Rights (SPUR)**; - SPLA uses different licensing models depending on the product, including per-core and Subscriber Access License models; - providers report applicable license usage on a monthly basis; - Windows Server Standard and Datacenter remain available through the SPLA channel. In practice, SPLA is relevant to cloud providers, MSPs, SaaS vendors, application hosts, accounting/ERP providers, and other businesses that deliver Microsoft-based software as a hosted service. ## Why SPLA matters when buying a hosted Windows Server VM A Windows VM quote has at least two separate layers: 1. **Infrastructure** — vCPU, RAM, NVMe/SSD storage, networking, backups, support, and the VM itself. 2. **Microsoft licensing** — Windows Server plus any additional Microsoft access rights or products required by the workload. That separation matters because a low advertised VM price is not necessarily the total price of a licensed production Windows environment. On Raff, the current Windows VM product page lists compute from **$13.99/month** and Windows Server Standard licensing through SPLA at **$15/month per VM**, for a current starting total of **$28.99/month** before optional items such as RDS access, additional storage, backups, or application-specific licensing. The commercial value of SPLA is not that licensing disappears. It is that the provider can make the licensing path explicit and bill it as a monthly service component. ## SPLA is provider-led licensing The easiest way to understand SPLA is to ask one question: **Who supplies the Microsoft licensing rights for this hosted deployment?** With SPLA, the service provider supplies eligible Microsoft software as part of its hosted service under the provider’s Microsoft agreement and the applicable SPUR terms. For the customer, that generally means: - no upfront purchase of a perpetual Windows Server license just for the hosted VM; - the Windows license can be billed with the hosting service; - the provider handles its SPLA reporting obligations; - the customer still needs to identify the actual products and access model used by the workload. SPLA does **not** mean one Windows Server license automatically covers RDS, SQL Server, Office, Microsoft 365 Apps, or every Microsoft workload installed on the VM. ## What an SPLA hosting provider should make clear before you buy A trustworthy SPLA hosting offer should make the licensing boundary understandable before checkout, not after an audit or migration. Ask the provider to clarify: - whether the Windows Server license is included or a separate line item; - which Windows Server edition/version is being supplied; - whether the price changes with VM size; - whether Remote Desktop Services requires separate SALs; - how SQL Server is licensed if installed; - whether Microsoft 365 Apps/Office are supported and under which customer rights; - whether BYOL is available for eligible customer licenses; - what information the customer must provide about users, products, and workload design; - whether provider-supplied licenses remain with the provider if you migrate away. Be cautious when a host treats **activation** as proof of licensing. A server can be technically activated without proving that the deployment has the correct Microsoft licensing rights. ## How to verify an SPLA hosting offer commercially For a buyer, you usually do not need to become a Microsoft licensing specialist. You do need enough clarity to avoid hidden costs and unsupported claims. A good provider should be able to answer these questions in writing: | Question | Why it matters | |---|---| | Is Windows Server licensing itemized? | Prevents a cheap compute price from hiding the license cost | | Is the license provider-supplied or BYOL? | Determines who supplies the rights | | Are RDS users licensed separately? | Multi-user RDS can materially change monthly cost | | Is SQL Server included? | Usually no; SQL licensing is a separate decision | | Does the provider distinguish test/evaluation from production? | Evaluation should not silently become the production licensing model | | Can I bring eligible customer licenses? | Important for organizations with subscription/Software Assurance rights | | What happens when I leave the provider? | Provider-supplied SPLA rights generally do not become your portable license | A provider that can clearly explain these boundaries is usually easier to work with than one that simply says “Windows included.” ## SPLA vs evaluation vs customer-owned licensing Most hosted Windows buyers encounter three practical paths. | Licensing path | Best fit | Production use | Who supplies the licensing path? | |---|---|---|---| | Windows Server evaluation | Lab, migration test, proof of concept | Not as the permanent production basis | Microsoft evaluation terms | | SPLA through the provider | Hosted production workload | Yes, where eligible and correctly licensed | Hosting provider | | Customer-owned licensing / BYOL | Organization already owns qualifying rights | Yes, when Microsoft terms permit the deployment | Customer | ### Evaluation Evaluation is useful for a short migration test, proof of concept, or application validation. It should not become the permanent licensing basis of a business-critical production workload simply because the VM continues to run. ### SPLA SPLA is often the simpler path when: - the workload is moving into production; - you want the hosting provider to supply Windows Server licensing; - your organization does not maintain its own Microsoft licensing estate; - you do not have a clearly documented BYOL right for the hosted scenario; - monthly provider billing is easier operationally. ### Customer-owned licensing / BYOL BYOL is not the same as “we already have a product key.” Microsoft’s current guidance provides the **Flexible Virtualization Benefit** for eligible subscription licenses or licenses with active Software Assurance. That benefit can allow customers to deploy eligible software, including Windows Server, on an Authorized Outsourcer’s shared or dedicated infrastructure, subject to Microsoft Product Terms and the specific licensing requirements. Microsoft also explicitly distinguishes Windows Server from traditional License Mobility through Software Assurance. Before using BYOL, verify: - the exact Microsoft licensing program; - whether the licenses are subscription licenses or have active Software Assurance where required; - whether the provider qualifies for the intended outsourcing scenario; - core minimums and VM licensing requirements; - user/device access requirements; - whether the rights apply to the exact software deployed. ## What does SPLA cover for Windows Server? SPLA is a framework, not a single all-inclusive Windows bundle. Microsoft’s current SPLA guidance includes a **Per Core (OS)** model for Windows Server. Microsoft also notes that certain Windows Server roles or functionality can require Subscriber Access Licenses. That becomes important when a server moves from ordinary administration to a service used interactively by multiple employees or customers. A normal Windows Server VM can support administrator access for server management. A real multi-user Remote Desktop Session Host deployment requires a separate RDS licensing decision. ## RDS licensing is separate from the Windows Server license A Windows Server license does not grant unlimited users the right to use the server as a shared remote desktop environment. If the workload uses **Remote Desktop Session Host** for regular multi-user access, RDS licensing must be evaluated separately. For Raff-hosted SPLA deployments, Raff currently lists **RDS User SALs at $8/month per user** for applicable multi-user deployments. Customer-owned environments can use a different Microsoft access model where their agreement permits it. See [RDS CAL Licensing on Windows Server](/windows-server/rds-cal-licensing-guide) before quoting a multi-user RDP environment. ## SQL Server is a separate licensing decision Windows Server licensing covers the operating system. It does not automatically license SQL Server Standard or Enterprise. If the application uses SQL Server, confirm the edition and production licensing model separately. For example: - SQL Server Express has free-use limits; - SQL Server Developer is for development/testing rather than production; - SQL Server Standard and Enterprise require appropriate production licensing; - customer-owned SQL Server rights differ from Windows Server rights and may involve License Mobility or Flexible Virtualization depending on the scenario. This is why a Windows VM quote and a complete Microsoft workload quote are not always the same number. ## Microsoft 365 Apps and Office require separate review Do not assume a Windows Server SPLA license gives users the right to run Microsoft 365 Apps or Office in a hosted session environment. Desktop productivity software has separate licensing and activation requirements. Shared Computer Activation and user subscription requirements can apply independently of Windows Server and RDS. Before migrating a business desktop workload, inventory **every Microsoft product** installed or accessed by users. ## What Raff handles under its hosted Windows licensing path For a standard Raff Windows Server deployment using Raff-supplied SPLA licensing, Raff handles the provider-side licensing path for the Windows Server product and the related provider reporting obligations. The customer still controls and is responsible for the guest environment, including: - which applications are installed; - which users access the workload; - whether RDS is used for multi-user access; - whether SQL Server or additional Microsoft products are installed; - guest OS configuration and patching; - application security, credentials, and data; - providing accurate workload/user information where additional licensing is needed. That boundary matters commercially. Raff provides the cloud infrastructure and applicable provider-supplied licensing path; it does not turn a self-managed Windows VM into a fully managed application environment. ## Current Raff Windows SPLA pricing Raff currently publishes the following common licensing components: | Component | Current published price | Notes | |---|---:|---| | Windows VM compute | From $13.99/month | Infrastructure component; plan-dependent | | Windows Server Standard via SPLA | $15/month per VM | Provider-supplied Windows Server licensing | | RDS User SAL | $8/month per user | For applicable multi-user RDS deployments | | SQL Server / other Microsoft products | Workload-dependent | Requires separate review | These figures were checked against Raff’s live Windows VM pages on **September 14, 2026**. Because product pricing can change, use [Windows VM](/products/windows-vm) and [Raff pricing](/pricing) for the current checkout-level numbers. ## A practical SPLA buying decision Before deploying a production Windows workload, answer these questions. ### 1. Is this test or production? Use evaluation licensing only when it genuinely fits a test/evaluation scenario. Establish the permanent production licensing path before employees or customers depend on the service. ### 2. Who supplies the Windows Server rights? If Raff supplies them, SPLA is the provider-led path. If the customer supplies them, validate the customer’s Microsoft rights for the hosted deployment. ### 3. Will regular users connect through Remote Desktop Services? If yes, quote and validate RDS licensing separately. ### 4. Is SQL Server installed? If yes, identify the exact edition and production licensing model before migration. ### 5. Are Microsoft 365 Apps or Office installed? If yes, validate the user subscriptions and shared-computer rights separately. ### 6. Are you moving from another hosting provider? Do not assume the old provider’s SPLA licensing transfers with the VM image. Re-establish the licensing path at the destination. ### 7. Do you already own qualifying Microsoft licenses? If yes, compare SPLA with BYOL under the current Flexible Virtualization Benefit and Microsoft Product Terms before paying twice for rights you may already have. ## Common SPLA misunderstandings ### “The VM is activated, so licensing is solved.” Activation and licensing rights are different. Activation only proves the software accepted an activation mechanism; it does not establish that the deployment model has the correct legal rights. ### “SPLA includes every Microsoft product on the server.” It does not. Windows Server, RDS, SQL Server, Office, and Microsoft 365 Apps can each require separate licensing analysis. ### “BYOL is always cheaper.” Not necessarily. Existing licenses can reduce cost only when the customer has the correct rights and can document them. SPLA can be operationally simpler for small teams that do not manage Microsoft volume licensing. ### “Windows Server uses ordinary License Mobility.” Microsoft distinguishes Windows Server from traditional License Mobility. Eligible subscription licenses or licenses with active Software Assurance may instead use the Flexible Virtualization Benefit on qualifying Authorized Outsourcers, subject to Microsoft terms. ### “A hosting provider saying ‘Microsoft licensed’ is enough.” Ask what product is licensed, under which provider/customer model, whether RDS/SQL are separate, and how the cost appears on the invoice. Precise answers are more useful than a generic badge. ### “Evaluation is fine as long as the server keeps running.” Evaluation is a testing path, not a permanent production licensing strategy. ## Why SPLA matters for MSPs and hosted application providers SPLA is particularly useful when an MSP, SaaS vendor, ERP/accounting provider, or software host needs to deliver a Microsoft-based environment without asking every customer to solve the hosting license model independently. Common examples include: - hosted Windows business applications; - RDS-based accounting or ERP environments; - IIS and .NET application hosting; - Windows-based SaaS infrastructure; - SQL Server-backed applications; - customer Windows environments operated by an MSP. For these workloads, licensing clarity is a commercial trust issue. The buyer should understand the VM cost, the Microsoft licensing cost, which access licenses are additional, and what happens if the workload changes. ## Should you use Raff SPLA or BYOL? Choose **Raff-supplied SPLA** when you want a straightforward hosted production license, do not have qualifying customer-owned rights, or prefer the provider to supply and report the Windows Server licensing component. Evaluate **BYOL** when your organization already has eligible Microsoft subscription licenses or licenses with active Software Assurance and the Flexible Virtualization Benefit applies to the intended deployment. Use **evaluation licensing** only for genuine test, proof-of-concept, or migration-validation scenarios. If you are unsure, list the Windows Server version, user count, RDS requirement, SQL Server edition, Microsoft 365/Office requirement, and any customer-owned licenses before requesting a quote. That information is enough to avoid most obvious licensing mismatches before migration. :::cta Deploy Windows Now Deploy a Raff Windows VM and choose the production licensing path that fits your workload. ::: ## Sources - [Microsoft — SPLA Licensing Guidance](https://www.microsoft.com/licensing/guidance/SPLA) - [Microsoft — SPLA Licensing Documents](https://www.microsoft.com/licensing/docs/view/Services-Provider-License-Agreement-SPLA) - [Microsoft — Services Provider Use Rights](https://www.microsoft.com/licensing/spur) - [Microsoft — Windows Server 2025 Licensing Guidance](https://www.microsoft.com/licensing/guidance/Windows-Server-2025) - [Microsoft — Flexible Virtualization Benefit](https://www.microsoft.com/licensing/guidance/Flexible-Virtualization-Benefit) - [Microsoft — Windows Server Virtualization Licensing Guidance](https://www.microsoft.com/licensing/guidance/Windows-Server-Virtualization-Technologies) - [Raff — Windows Server Licensing](/windows-server/windows-licensing) - [Raff — Windows VM](/products/windows-vm) - [Raff — Pricing](/pricing) - Microsoft and Raff product/licensing details reviewed: 2026-09-14 --- ### Nginx vs Apache: Which Web Server to Choose in 2026 URL: https://rafftechnologies.com/learn/guides/nginx-vs-apache-which-web-server-2026 Description: Nginx vs Apache: compare architecture, performance, .htaccess, reverse proxying, WordPress, PHP-FPM, migration risk, and which web server fits a VPS. **Nginx vs Apache is not a universal speed contest.** Choose **Nginx** when you want a centrally managed, reverse-proxy-first web server for a new API, application runtime, static site, or container workload. Choose **Apache HTTP Server** when the application depends on `.htaccess`, Apache modules, delegated per-directory configuration, or an existing Apache operating model that already works. For WordPress, PHP-FPM, and many ordinary websites, **either can be the right choice**. Application code, database latency, caching, TLS, storage, PHP workers, and configuration can affect user experience more than the web-server brand. Raff Technologies supports both approaches on self-managed Linux VMs. The practical goal is to choose the server your team can configure, patch, observe, test, and recover consistently. ![Nginx vs Apache comparison chart showing Nginx as a strong default for modern VPS apps, reverse proxying, APIs, and static sites, while Apache fits WordPress, PHP, .htaccess, and legacy hosting workflows.](https://raff-images.s3.raffusercloud.com/Nginx_vs_Apache_comparison_chart_e443a92222.png) ## Nginx vs Apache: the short answer | Decision area | Nginx | Apache HTTP Server | |---|---|---| | Strong default for | New reverse-proxy-first applications | Compatibility-driven or delegated-configuration workloads | | Architecture | Master process with event-driven workers | Modular server using one selected Multi-Processing Module | | `.htaccess` | No | Yes, when enabled | | Reverse proxy | Native, common deployment role | Supported through `mod_proxy` and related modules | | PHP | Commonly proxies to PHP-FPM | Can use PHP-FPM through `mod_proxy_fcgi` | | Node.js / Python / Go / Java | Strong fit as public reverse proxy | Also capable as reverse proxy | | Static files | Strong fit | Fully capable | | Shared-hosting style delegation | Less natural | Strong fit | | Existing Apache estate | Usually migration required | Lowest compatibility risk | | New centrally managed VPS | Often simpler starting point | Also valid if team standardizes on Apache | A useful rule is: > **Choose Nginx for a new centrally managed proxy-first stack unless you have a reason to need Apache. Choose Apache when `.htaccess`, modules, or existing compatibility are themselves requirements.** ## What is the difference between Nginx and Apache? The biggest differences are not simply “fast vs slow.” They are **request-processing architecture, configuration ownership, and compatibility model**. Nginx uses a master process with event-driven worker processes. A worker can manage many active connections without assigning one dedicated thread or process to every idle connection. Apache uses one Multi-Processing Module (MPM) at a time. On modern threaded Unix-like systems, Apache can use the `event` MPM, which handles keep-alive and some connection work asynchronously instead of tying a request worker to every idle connection. That means old comparisons that describe all Apache deployments as one-process-per-connection are outdated. The other major difference is configuration. Apache can permit `.htaccess` files inside directory trees. Nginx does not have a direct `.htaccess` equivalent; routing, access, caching, and rewrite behavior is normally controlled through central configuration. ## Use six questions to choose between Nginx and Apache ### 1. Does the application require `.htaccess`? If the application, plugin, control panel, or customer workflow writes `.htaccess` rules, Apache is normally the lower-risk choice. Nginx does not process `.htaccess`. Existing rewrite, access, header, and caching rules must be translated into Nginx configuration. Apache's own documentation recommends using the main server configuration instead of `.htaccess` when administrators control the full server, because distributed configuration adds per-directory lookup and another place where behavior can change. ### 2. Is the server primarily a reverse proxy? Nginx is a natural default when the public server mainly forwards requests to an application on localhost, a private IP, or a container. A common architecture is: ```text Internet ↓ HTTPS Nginx ↓ localhost or private network Node.js / Python / Go / Java / PHP-FPM / container ``` Apache can perform the same role through `mod_proxy`, `mod_proxy_http`, `mod_proxy_fcgi`, WebSocket support, and load-balancing modules. Existing Apache expertise can therefore outweigh the value of changing products. ### 3. Who owns configuration? Nginx fits a model where administrators or automation own the complete configuration centrally. Apache can also be centrally managed, but it additionally supports delegated directory-level behavior through `.htaccess` when that is genuinely required. For a small team that controls the full VPS, one centrally reviewed configuration model is usually easier to audit and reproduce. ### 4. What application model already exists? A new Node.js, Python, Go, Java, or container application usually already expects a separate application process behind a reverse proxy. Nginx fits that model cleanly. A migrated WordPress, Drupal, or traditional PHP estate may already depend on Apache rewrite rules, modules, control-panel conventions, and support procedures. Preserving a working model can be safer than translating it during migration. ### 5. Is the web server actually the bottleneck? Do not switch because of a generic “Nginx is faster” article. Measure: - time to first byte; - application and database latency; - static-file throughput; - concurrent connections; - CPU and memory under representative traffic; - PHP-FPM or application worker saturation; - TLS overhead; - upstream queueing and timeouts; - error rate; - deployment and recovery time. A slow database query remains slow behind either server. ### 6. Can the team operate the migration safely? Switching web servers can affect: - redirects and rewrites; - headers; - real-client IP handling; - TLS; - compression; - cache rules; - body and upload limits; - proxy timeouts; - WebSockets and streaming; - file ownership; - logging; - application routing. Stay with the current server when the expected benefit is smaller than the migration risk. ## Nginx uses an event-driven worker model Nginx normally runs one master process and several worker processes. Its workers use event-based, non-blocking request handling so one worker can manage many connections. This design is especially natural for: - reverse proxying; - static assets; - APIs with many concurrent connections; - centralized routing to several application services; - long-lived connections when configured correctly; - a public edge in front of private runtimes. The architecture does not make every Nginx deployment fast automatically. Worker limits, upstream behavior, TLS, logging, buffering, operating-system limits, and application latency still matter. Nginx also supports configuration testing with: ```bash nginx -t ``` A validate-before-reload workflow is useful for production changes. ## Modern Apache is not just prefork Apache HTTP Server uses one Multi-Processing Module to control how it accepts and processes connections. Common Unix-like MPMs include: - `event`; - `worker`; - `prefork`. On supported threaded Unix-like platforms, Apache's current documentation identifies `event` as the default MPM. The `event` MPM is designed so request workers are used for active processing rather than being held by every keep-alive connection. This matters because many old Nginx-vs-Apache comparisons benchmark Nginx against an outdated prefork-style Apache configuration and then generalize the result. Apache's modular architecture remains a strength when the workload depends on authentication, authorization, rewrite, proxy, hosting, or application-specific modules. ## Nginx vs Apache performance: benchmark the real workload There is no responsible evergreen statement such as “Nginx is twice as fast” or “Apache uses X% more memory.” Results depend on: - server hardware; - web-server version; - Apache MPM and loaded modules; - TLS settings; - caching; - file sizes; - request concurrency; - logging; - keep-alive behavior; - application runtime; - database latency. ### Static benchmarks answer only a static question A test that serves one cached file repeatedly may be relevant for a static asset workload. It does not predict the performance of: - WordPress; - a Node.js API; - authenticated application traffic; - database-heavy PHP; - uploads; - long-running requests; - cache misses. ### Dynamic applications are often limited behind the web server ```text Client ↓ Nginx or Apache ↓ Application runtime ↓ Database / cache / external API ``` If application processing takes hundreds of milliseconds, replacing the web server may have little effect on total latency. ### A useful benchmark controls the variables Use the same: - VM profile; - application and dataset; - TLS configuration; - compression policy; - logging level; - cache state; - request mix; - concurrency profile. Measure latency percentiles, throughput, CPU, memory, errors, and saturation rather than only requests per second. ## Nginx is a strong default for new reverse-proxy-first applications Nginx's proxy module can forward requests to HTTP or HTTPS upstreams and control headers, buffering, timeouts, caching, connection behavior, and upstream groups. Nginx is a good starting point when: - the application already listens on an internal port; - configuration is centrally managed; - the public edge serves static assets and proxies dynamic traffic; - multiple internal applications need hostname or path routing; - the team wants one consistent server-block model. Keep the application runtime private when it does not need direct public exposure. For example: ```text Internet ↓ HTTPS Nginx on Raff VM ↓ localhost Application runtime ↓ private network Database / cache / queue ``` ## Apache is also a capable reverse proxy Apache's `mod_proxy` family supports reverse proxying, FastCGI, WebSocket upgrades, load balancing, and multiple upstream protocols through related modules. Apache is a reasonable proxy choice when: - the team already operates Apache safely; - authentication or authorization modules are integrated at the edge; - the same server hosts Apache-dependent applications; - existing virtual-host and logging standards are mature; - replacing Apache has no measured benefit. The comparison is not “Nginx proxies and Apache does not.” Both can act as reverse proxies; they differ in architecture and operating model. ## `.htaccess` is Apache's clearest compatibility advantage Apache `.htaccess` files let directory owners apply permitted configuration without editing the main server configuration. That can be useful for: - shared hosting; - migrated CMS installations; - plugins that distribute rewrite rules; - environments where users lack root access; - compatibility with existing control-panel workflows. It is less attractive on a centrally managed VPS where one team controls all server configuration. If overrides are required, allow only the directive categories the application needs rather than broadly enabling every override. ## Nginx vs Apache for WordPress WordPress currently recommends **either Apache or Nginx** as robust web-server choices. Choose Apache for WordPress when: - the site or plugins depend on `.htaccess`; - the migration comes from shared hosting; - existing support procedures assume Apache; - preserving current rewrite behavior reduces risk. Choose Nginx for WordPress when: - the team controls the full server configuration; - PHP runs through PHP-FPM; - rewrite and cache rules can be centrally managed; - the team already operates Nginx; - WordPress is part of a broader reverse-proxy-first stack. Neither choice fixes: - slow plugins; - inefficient SQL queries; - too few PHP workers; - poor page/object caching; - an undersized VM. For WordPress, the lower-risk choice is often more important than the theoretical architecture advantage. ## Both can use PHP-FPM Nginx commonly forwards PHP requests to PHP-FPM using FastCGI. Apache can use PHP-FPM through `mod_proxy_fcgi` together with `mod_proxy`. Once both use PHP-FPM, total performance can depend more on: - PHP worker count; - opcode caching; - application code; - database performance; - filesystem latency; - page/object caching; - memory limits; - request timeouts. Choose the web server from compatibility and operations, then tune PHP from measurements. ## Security depends more on configuration than brand Both Nginx and Apache can be operated securely, and both can be exposed through unsafe configuration. A production baseline includes: - supported packages and security updates; - TLS and certificate-renewal monitoring; - only required public ports; - restricted SSH access; - private database/cache/application ports where practical; - least-privilege service accounts; - controlled file permissions; - access and error logging; - configuration backups and rollback; - tested recovery. For reverse proxies, also validate: - trusted proxy and real-client IP handling; - forwarded host/protocol headers; - request-body limits; - upload limits; - upstream TLS verification where used; - WebSockets and streaming; - timeout and retry policy. Apache's official proxy documentation explicitly warns against exposing an unsecured forward proxy. Reverse proxying should expose only intended backends. ## HTTP/2 and other protocol checkboxes should not decide the server alone Both servers support modern TLS and HTTP/2 configurations when the relevant modules and packages are available. The useful questions are: - Is the required feature enabled in the package you actually deploy? - Does TLS negotiation work correctly? - Are certificates renewed and monitored? - Do proxy headers preserve the correct host and scheme? - Do WebSockets or streaming work end to end? - Can the team debug the path when it fails? Do not choose a web server from a protocol feature checklist without checking the deployed build and operating-system package. ## Using Nginx and Apache together is a compatibility pattern, not a default Nginx can sit in front of Apache: ```text Internet ↓ Nginx public edge ↓ Apache application server ``` This can preserve Apache-specific behavior while centralizing TLS, static assets, or proxying in Nginx. Use the pattern only when it solves a real compatibility problem. It adds: - two configuration layers; - two sets of logs and timeouts; - additional header/client-IP handling; - more services to patch and monitor; - more debugging points. One well-operated web server is usually better than two layers with unclear ownership. ## Which should you choose by workload? | Workload | Better starting point | Why | |---|---|---| | New Node.js, Python, Go, or Java app | Nginx | Clean proxy-first model | | Static site/front-end assets | Nginx | Straightforward central configuration | | Existing WordPress with `.htaccess` | Apache | Lowest compatibility risk | | WordPress with centrally managed PHP-FPM | Either | Operations and caching matter more | | Shared hosting | Apache | `.htaccess` supports delegated control | | Existing Apache estate with mature automation | Apache | Avoid unnecessary migration | | Container app behind a VM edge | Nginx | Common proxy-first pattern | | Workload requiring Apache modules | Apache | Module dependency decides the choice | | Multi-node app | Either | High availability is a separate architecture decision | ## Should you switch from Apache to Nginx? Switch when there is a defined operational or capacity benefit, for example: - `.htaccess` delegation is no longer needed; - the team is standardizing on centralized proxy configuration; - application runtimes are being separated from the web server; - representative testing shows a useful capacity or operating benefit; - the team has a tested migration and rollback plan. Do **not** switch because an unrelated benchmark says Nginx is faster. Likewise, moving from Nginx to Apache can make sense if Apache-specific modules, `.htaccess`, control-panel workflows, or established automation reduce operational risk. ## Migration requires behavioral equivalence Before switching, inventory: - virtual hosts/domains; - redirects and rewrites; - document roots; - MIME types; - compression; - security headers; - access restrictions; - client IP forwarding; - TLS certificates and protocols; - upload/body-size limits; - proxy timeouts; - WebSockets; - log formats; - PHP-FPM/application sockets; - health checks; - startup/reload behavior. Validate the replacement in parallel where possible and preserve a rollback path during cutover. A working homepage does not prove that logins, uploads, admin routes, redirects, webhooks, APIs, and large requests are equivalent. ## How Nginx and Apache fit on Raff Both Nginx and Apache can run on a [Raff VM](/products/raff-vm). The VM is self-managed at the guest OS and application level, so your team remains responsible for web-server installation, configuration, patching, monitoring, application security, and recovery. A simple architecture is: ```text DNS ↓ Raff VM public IP ↓ Nginx or Apache on 80/443 ↓ localhost Application runtime ``` For multi-server applications: ```text Internet ↓ Traffic-distribution layer ↓ Application VMs ↓ Raff VPC Database / cache / queue ``` Use [Raff VPC](/products/vpc) when backend communication should stay private, and [Data Protection](/products/data-protection) as part of the recovery design. Do not assume a managed Raff load balancer is available until the live product page confirms it; choose the traffic-distribution layer that is actually available for the deployment. Use the live [pricing](/pricing) and product pages for current VM resources and commercial terms. :::cta Explore Raff VM Deploy the Linux VM for the web-server architecture your team can operate and recover confidently. ::: ## Nginx vs Apache decision checklist ### Choose Nginx when - [ ] The application uses a separate runtime or container. - [ ] The server is primarily a reverse proxy or static edge. - [ ] Configuration is centrally owned. - [ ] `.htaccess` compatibility is not required. - [ ] The team already knows how to validate and reload Nginx safely. ### Choose Apache when - [ ] The application depends on `.htaccess` or Apache modules. - [ ] Per-directory delegation is a real requirement. - [ ] Existing Apache automation and support are mature. - [ ] Migration would add risk without a measured benefit. - [ ] The selected MPM and modules are understood. ### Validate either option - [ ] Measure the application and database separately from the web server. - [ ] Test TLS, redirects, uploads, headers, and WebSockets. - [ ] Keep internal application/database services off the public network where practical. - [ ] Validate configuration before reload. - [ ] Monitor upstream errors and timeouts. - [ ] Back up configuration and application data. - [ ] Test recovery. :::cluster ## Frequently asked questions ### Is Nginx better than Apache? Not universally. Nginx is a strong default for new centrally managed, reverse-proxy-first applications. Apache is often better when `.htaccess`, Apache modules, shared-hosting style delegation, or existing compatibility are requirements. ### What is the main difference between Nginx and Apache? Nginx uses an event-driven worker architecture with centrally managed configuration. Apache uses a selectable Multi-Processing Module and can additionally support distributed `.htaccess` configuration. ### Which is faster, Nginx or Apache? It depends on hardware, Apache MPM, modules, TLS, caching, concurrency, logging, application runtime, and database behavior. Benchmark the configuration and workload you would actually operate rather than relying on a generic speed multiplier. ### Should I use Nginx or Apache for WordPress? Use Apache when the site depends on `.htaccess` or inherited Apache behavior. Use Nginx when configuration is centrally managed and the team is comfortable operating WordPress with PHP-FPM and centrally managed rewrite/cache rules. WordPress officially supports both. ### Does Nginx support `.htaccess`? No. Nginx uses central configuration. Existing `.htaccess` rewrite, access, caching, and header rules must be translated when migrating from Apache. ### Can Apache work as a reverse proxy? Yes. Apache supports reverse proxying, FastCGI, WebSocket upgrades, load balancing, and multiple upstream protocols through `mod_proxy` and related modules. ### Can both Nginx and Apache use PHP-FPM? Yes. Nginx commonly uses FastCGI to PHP-FPM, while Apache can use PHP-FPM through `mod_proxy_fcgi`. PHP and database tuning may matter more than the web-server choice. ### Should I switch from Apache to Nginx? Switch only when centralized configuration, a proxy-first architecture, capacity, or operations provide a measured benefit. Keep Apache when compatibility and mature automation outweigh the expected gain. ### Which web server should I use on a VPS? For a new centrally managed VPS application, Nginx is often the simpler starting point. Choose Apache when the application requires `.htaccess`, Apache modules, or inherited Apache behavior. ### Which web server should I use on Raff? Both work on Raff Linux VMs. Choose Nginx for new reverse-proxy-first stacks and Apache for compatibility-driven workloads, then keep backend runtimes and databases private where practical. ## Conclusion For most new VPS applications, **Nginx is a strong default when the architecture is reverse-proxy-first and centrally managed**. Apache remains the better choice when `.htaccess`, modules, delegated configuration, or existing compatibility materially reduce operational risk. Neither server is universally faster. Measure the complete request path, preserve required behavior, and choose the platform your team can configure, patch, observe, and recover consistently. ## Sources - [NGINX Beginner's Guide](https://nginx.org/en/docs/beginners_guide.html) - [NGINX Architecture](https://blog.nginx.org/nginx-architecture) - [NGINX HTTP Proxy Module](https://nginx.org/en/docs/http/ngx_http_proxy_module.html) - [Apache HTTP Server Multi-Processing Modules](https://httpd.apache.org/docs/2.4/mpm.html) - [Apache event MPM](https://httpd.apache.org/docs/2.4/mod/event.html) - [Apache HTTP Server .htaccess Tutorial](https://httpd.apache.org/docs/2.4/howto/htaccess.html) - [Apache Reverse Proxy Guide](https://httpd.apache.org/docs/2.4/howto/reverse_proxy.html) - [Apache mod_proxy](https://httpd.apache.org/docs/2.4/mod/mod_proxy.html) - [WordPress Requirements](https://wordpress.org/about/requirements/) - [Raff Cloud Servers](/products/raff-vm) - Technical sources reviewed: 2026-09-15 --- ### Docker Volumes vs Bind Mounts: What Matters in Production URL: https://rafftechnologies.com/learn/guides/docker-volumes-vs-bind-mounts-production Description: Compare Docker volume vs bind mount for production: persistence, host paths, Compose behavior, permissions, down -v, backups, and when to use each. **Docker volume vs bind mount** comes down to ownership. Use a **named Docker volume** when the persistent data belongs to the containerized application and Docker should manage the storage object. Use a **bind mount** when the container intentionally needs a specific file or directory owned by the host. For most production application state on a single Docker host, a named volume is the cleaner default. Docker's current documentation calls volumes the preferred mechanism for persistent data generated by and used by containers. Bind mounts remain the right tool for host-managed configuration, certificates, source trees, export directories, and other workflows where the host path itself matters. Raff Technologies hosts the Docker VM layer; Docker storage choices still remain part of the guest-OS and application design. A Docker named volume is not the same thing as a Raff block [Volume](/products/volumes), and neither a named volume nor a bind mount is automatically a backup. > **Application-owned persistent state → named volume. Host-owned path → bind mount. Temporary in-memory state → tmpfs. Critical data → add a separate backup and restore plan.** ## Docker volume vs bind mount: quick answer | If you need... | Better default | |---|---| | Application/database state managed through Docker | Named volume | | A specific host file or directory inside the container | Bind mount | | Direct host editing or inspection | Bind mount | | Less dependence on hard-coded host paths | Named volume | | Host-managed config that the container should not change | Read-only bind mount | | Temporary data that should not persist to disk | `tmpfs` | | Data shared across multiple containers on one host | Usually named volume | | Data shared across multiple Docker hosts | Requires a deliberate shared-storage architecture | | Protection from deletion, corruption, or host loss | Separate backup/recovery system | The comparison is not “which mount type is more professional?” A production Compose stack can correctly use both. ![Docker volumes vs bind mounts comparison showing Docker-managed persistent storage versus host path-mounted files.](https://raff-images.s3.raffusercloud.com/docker_volumes_vs_bind_mounts_comparison_png_9a50059abe.png) ## What is a Docker volume? A Docker volume is a persistent storage object created and managed by the Docker daemon. Its lifecycle is independent from the lifecycle of one container: ```text Container A ↓ Named volume: app_data ↑ Container A recreated ``` Removing the container does not automatically remove the named volume. Docker can create, list, inspect, and remove volume objects independently. Typical commands are: ```bash docker volume create app_data docker volume ls docker volume inspect app_data ``` Docker's current documentation recommends volumes when the container generates persistent data, especially when the data should survive container replacement or should not depend on a specific host directory structure. A useful production rule is: > If an operator should think of the data as **application state**, start with a named volume unless another storage requirement says otherwise. ## What is a Docker bind mount? A **Docker bind mount** maps an existing path from the Docker daemon host directly into the container. For example: ```text Host /srv/my-app/config.yml ↓ Container /app/config.yml ``` The host path is part of the deployment contract. That makes bind mounts useful when: - a host-side process manages the file; - operators need direct host access; - configuration should come from a known host path; - certificates are maintained outside the container; - development source code should appear immediately inside a container; - another host process collects or writes files in the same directory. Docker bind mounts are **read-write by default**. A container with a writable bind mount can create, modify, or delete files on the host path, so production bind mounts should be narrow and read-only whenever write access is unnecessary. Example: ```yaml services: app: image: my-app volumes: - /srv/my-app/config.yml:/app/config.yml:ro ``` Bind mounts also make a workload more host-specific. The same path, file, ownership, permissions, and expected directory structure must exist when the workload moves to another Docker host. ## Docker mount types are broader than just volumes and bind mounts For Linux application storage, the main decision is usually among: - **volume mounts** for Docker-managed persistent data; - **bind mounts** for host-path-backed data; - **tmpfs mounts** for temporary in-memory data. Docker's current storage documentation also lists additional mount types such as **image mounts** and **named pipes**, and Compose supports platform-specific mount forms. For ordinary persistent application state, however, the practical production comparison remains **Docker volumes vs bind mounts**. ## Docker volumes vs bind mounts: ownership is the real difference | Decision area | Named Docker volume | Bind mount | |---|---|---| | Storage object managed by | Docker | Host/operator | | Source path | Docker-managed | Explicit host path | | Host-path coupling | Lower | High | | Direct host access | Not the intended workflow | Core feature | | Survives container recreation | Yes unless explicitly removed | Yes while host path remains | | Read/write default | Read/write | Read/write | | Good default for app-owned state | Yes | Only when host ownership is intentional | | Good for host-managed config | Less direct | Yes, often `ro` | | Cross-host move | Requires migration/restore | Requires migration/restore of host path | | Backup included | No | No | One subtle but important point: Docker's documentation says directly manipulating the underlying files of Docker-managed volume storage from the host is not the supported interaction model. If direct host-side file access is a requirement, that is a strong signal for a bind mount instead. A named volume reduces **path coupling**. It does not make live data magically portable between servers. ## Named volumes are usually the safer default for application-owned state Typical volume workloads include: - PostgreSQL or MySQL data directories; - Redis persistence; - self-hosted application state; - generated service data; - data shared by several containers on the same Docker host. Example: ```yaml services: db: image: postgres:16 restart: unless-stopped volumes: - db_data:/var/lib/postgresql/data volumes: db_data: ``` The Compose definition describes a storage object called `db_data` rather than hard-coding `/srv/postgres-data` into the service. That improves deployment clarity, but production ownership still includes: - capacity monitoring; - Linux ownership and permissions; - application consistency; - backup frequency; - restore procedure; - migration to a replacement host; - recovery after accidental deletion or corruption. **Docker-managed does not mean provider-managed, replicated, backed up, or highly available.** With the default local volume model on a single Docker host, losing the host can still mean losing the live volume unless the data exists elsewhere in a recoverable form. ## Bind mounts are right when the host must own the files Bind mounts are not merely a development shortcut. They are a valid production pattern when host ownership is intentional. Examples include: - a host-managed reverse-proxy configuration; - TLS certificates maintained by a host-side agent; - an export directory consumed by another host service; - a directory collected by an existing host backup workflow; - carefully scoped socket or device integration; - files generated outside Docker that a container must read. A good production bind mount answers three questions: 1. Why does this file belong to the host instead of the containerized application? 2. Does the container really need write access? 3. What creates the path, owns it, and restores it on a replacement server? Avoid broad mounts such as entire home directories or system directories unless the workload has a documented reason. Mounting `/var/run/docker.sock` deserves special treatment: access to the Docker daemon socket gives a container a high-trust control path to the Docker host. It should not be treated like an ordinary config-file mount. ## `--mount` vs `-v`: production behavior differs when paths are missing Docker supports both `--mount` and `-v` / `--volume` syntax. For Docker Engine commands, Docker currently recommends the more explicit `--mount` syntax. A key safety difference for bind mounts is the source path: ```bash docker run \ --mount type=bind,source=/srv/my-app/config,target=/app/config \ my-app ``` With `--mount`, a missing bind source path returns an error by default. That is often useful in production because a missing required path fails loudly rather than silently changing the deployment. Docker Compose has a related nuance: **short bind-mount syntax can create a missing host source directory for backward compatibility**. Compose long syntax lets you disable that behavior with `create_host_path: false`. Example: ```yaml services: app: image: my-app volumes: - type: bind source: /srv/my-app/config target: /app/config read_only: true bind: create_host_path: false ``` This can prevent a typo or missing deployment step from turning into an empty directory mounted over a required application path. ## Mounting over existing container files can hide them This is one of the easiest Docker storage mistakes to make. If a bind mount is placed over a container directory that already contains files, the files from the image are **obscured while the mount is active**. Example: ```text Image contains: /app/config/default.yml Bind mount: /srv/config → /app/config Result: The image's /app/config contents are hidden by the host mount. ``` A non-empty Docker volume mounted over an existing container path also obscures the underlying image files. An **empty** volume behaves differently: Docker copies the existing container-directory contents into the empty volume by default. The `volume-nocopy` / Compose `nocopy` option disables that initialization behavior. Before mounting over a populated image path, ask: - Does the image ship required defaults there? - Should the external storage replace those files? - Should an empty volume be pre-populated? - Is a first-run initialization workflow expecting those files? ## Permissions still matter with both mount types Volumes do not bypass Linux permissions. If the container runs as UID `1001`, the files in the mounted storage still need ownership or permissions that allow UID `1001` to use them. Bind mounts make this especially visible because host UID/GID values meet container UID/GID expectations directly. Production tests should use the same user model as production. A deployment that only works because the container runs as root can fail after security hardening—or may already have more privileges than the application needs. Also account for: - SELinux labeling on applicable hosts; - read-only mounts; - umask and created-file ownership; - application-specific permission requirements. ## Docker Compose volume vs bind mount: use both when ownership differs A production Compose stack can mix mount types intentionally: ```yaml services: app: image: my-app restart: unless-stopped volumes: - app_data:/app/data - /srv/my-app/config.yml:/app/config.yml:ro db: image: postgres:16 restart: unless-stopped volumes: - db_data:/var/lib/postgresql/data volumes: app_data: db_data: ``` This communicates three separate ownership decisions: 1. `app_data` is application-owned persistent state. 2. `db_data` is database-owned persistent state. 3. `/srv/my-app/config.yml` is host-owned configuration exposed read-only. The point is not to standardize every mount on one type. The point is to make each mount explainable. ## What does `docker compose down -v` delete? This is operationally important because the `-v` flag can remove real application data. By default: ```bash docker compose down ``` removes the Compose containers and networks, but named volumes normally remain. When you run: ```bash docker compose down -v ``` Docker Compose removes: - named volumes declared in the Compose `volumes` section; and - anonymous volumes attached to the removed containers. External volumes are not removed by `docker compose down`. A bind mount is different: its data is a normal host path, not a Docker named-volume object, so `docker compose down -v` does not mean “delete the host directory.” The bind mount disappears with the container, but the underlying host files remain unless something else deletes them. For production data, treat `docker compose down -v` as a destructive command and verify backups before using it on a stateful stack. ## Volumes and bind mounts do not solve multi-host storage A named volume with Docker's default local storage model belongs to a Docker host. If you move the workload to another host, the new host does not automatically receive the old volume contents. Likewise, a bind mount depends on the host path existing on the new server. For multi-host persistence, you need an explicit architecture such as: - backup + restore during host migration; - attached block storage moved or reconstructed according to provider capabilities; - a supported shared-storage system; - a volume driver backed by external storage; - application-native replication; - managed database/storage services. Do not infer multi-host availability from the fact that Docker calls something a “volume.” ## Docker volume vs bind mount performance Do not choose purely from generic benchmark claims. Docker's documentation recommends volumes for high-performance persistent I/O and notes that volumes avoid the container writable-layer storage-driver overhead. That comparison is mainly **volume vs container writable layer**, not a universal guarantee that a volume will beat every bind mount on every host. Actual performance depends on: - host filesystem; - storage device; - Docker Desktop vs native Linux; - virtualization/file-sharing layer; - workload I/O pattern; - sync/fsync behavior; - database configuration. For a production database, measure the real deployment rather than assuming the mount label determines performance. ## Backup strategy matters more than mount type A Docker volume is not a backup. A bind mount is not a backup. Both can preserve corrupted or deleted data just as persistently as healthy data. Recovery planning should answer: - What state is business-critical? - Is filesystem-level backup safe for this application? - Does the database require dump, physical backup, or point-in-time recovery? - Is there a recovery copy outside the affected VM? - What are the RPO and RTO? - Has restore been tested on a clean host? For live databases, casually copying the data directory while writes continue can be unsafe unless the database and backup method explicitly support that workflow. A stronger model is: ```text Container image = replaceable application package Live volume/bind path = current persistent state Database-aware backup = consistent recovery copy VM backup/snapshot = infrastructure recovery point Off-VM copy = protection from host loss ``` For a complete Compose workflow, see [Docker Compose Backup and Restore Strategy](/learn/guides/docker-compose-backup-restore-strategy). ## Production decision framework | Question | Better default | |---|---| | Database or long-lived app state? | Named volume | | Host process must edit/collect files? | Bind mount | | Host-managed config? | Read-only bind mount | | Development source code? | Bind mount | | Temporary in-memory state? | `tmpfs` | | Avoid hard-coded host path? | Named volume | | Need direct host file access? | Bind mount | | Need state on another Docker host? | Explicit migration/shared-storage plan | | Loss would hurt production? | Separate backups + tested restore | Production checklist: - [ ] Name important volumes clearly. - [ ] Document why every bind mount exists. - [ ] Use `ro` when the container does not need writes. - [ ] Prefer explicit mount syntax for critical paths. - [ ] Prevent silent creation of required Compose bind paths where appropriate. - [ ] Confirm UID/GID ownership and permissions. - [ ] Monitor disk growth. - [ ] Inventory which mounts contain business-critical state. - [ ] Use application-aware database backups where required. - [ ] Keep recovery copies outside the affected VM when host loss matters. - [ ] Test restoration. - [ ] Treat `docker compose down -v` as destructive for named-volume data. ## How this applies on Raff [Raff VM](/products/raff-vm) provides the Linux compute boundary on which Docker Engine and Docker Compose can run. Keep these layers separate: ```text Raff VM ↓ Linux filesystem / attached storage ↓ Docker volume or bind-mount design ↓ Container application ``` A Docker named volume using the default local driver is **not the same product** as Raff [Volumes](/products/volumes). Raff Volumes are infrastructure block storage attached to the VM; Docker then needs an intentional guest-filesystem and mount design on top of that storage. Similarly, Raff [Data Protection](/products/data-protection) can support infrastructure-level recovery, but it does not remove the need for application-aware backup procedures for consistency-sensitive databases. For a small production Docker stack, a clean model is: ```text Raff VM | +-- named Docker volumes for app-owned state | +-- narrow read-only bind mounts for host-owned config | +-- application-aware database backup | +-- infrastructure recovery plan ``` Raff VMs remain self-managed at the guest OS and application level. Your team owns Docker upgrades, Compose configuration, mount permissions, application consistency, storage growth, and workload-level restore testing. When a single-host Compose environment starts requiring multi-node scheduling, service placement, or cluster-level orchestration, compare it with [Kubernetes vs Docker Compose for Small Teams](/learn/guides/kubernetes-vs-docker-compose-small-teams). :::cta Explore Raff VM Run Docker on a Raff VM, then keep application-owned state, host-owned files, and recovery responsibilities clearly separated. ::: :::cluster ## Frequently asked questions ### What is the difference between a Docker volume and a bind mount? A Docker volume is a persistent storage object managed by Docker. A bind mount maps a specific path from the Docker host directly into the container. Volumes reduce host-path coupling; bind mounts are appropriate when direct host access is part of the design. ### When should I use a Docker volume instead of a bind mount? Use a named volume for persistent application-owned data when the host does not need to manage the files directly. Use a bind mount when a specific host file or directory must be visible inside the container. ### What is a Docker bind mount? A bind mount maps an existing file or directory from the Docker daemon host into a container path. It is read-write by default unless configured read-only. ### Are Docker volumes better for production? For application-generated persistent data, Docker officially recommends volumes as the preferred persistence mechanism. Bind mounts are still correct in production when the host intentionally owns or manages the mounted files. ### Should a production database use a Docker volume? A named volume is usually a clean Docker-native storage default for a database on one host. It does not replace database-aware backups, capacity monitoring, or restore testing. ### What happens when I run `docker compose down -v`? Compose removes named volumes declared by the project and anonymous volumes attached to its containers. This can permanently delete state. External volumes are not removed, and bind-mounted host files are not Docker volume objects deleted by this flag. ### Do Docker volumes move automatically to another server? No. A local Docker volume remains tied to its Docker host unless you deliberately migrate/restore the data or use an external/shared volume architecture. ### Why did a bind mount hide files that were in my image? Mounting a bind path over a populated container directory obscures the existing image files at that path while the mount is active. Recreate the container without the mount to expose the original files again. ### Should I use `--mount` or `-v`? Docker currently recommends `--mount` because it is more explicit and supports the full mount option set. For bind mounts, a missing source path normally causes `--mount` to fail instead of silently creating a directory. ### Do Docker volumes replace backups? No. Volumes provide persistence, not historical recovery. Critical state still needs a backup method appropriate to the application plus tested restoration. ## Conclusion Docker volumes vs bind mounts is fundamentally an ownership decision. Use a **named volume** when persistent data belongs to the application and Docker should manage the storage object. Use a **bind mount** when the host must intentionally own, provide, inspect, or manage the files. Use `tmpfs` when data should remain temporary and in memory. For production, the mount type is only one layer. Permissions, host coupling, Compose teardown behavior, storage capacity, backup consistency, off-host recovery, and restore testing matter just as much. ## Sources - [Docker Docs - Storage](https://docs.docker.com/engine/storage/) - [Docker Docs - Volumes](https://docs.docker.com/engine/storage/volumes/) - [Docker Docs - Bind mounts](https://docs.docker.com/engine/storage/bind-mounts/) - [Docker Docs - Compose services and mount syntax](https://docs.docker.com/reference/compose-file/services/) - [Docker Docs - docker compose down](https://docs.docker.com/reference/cli/docker/compose/down/) - [Docker Docs - Compose in production](https://docs.docker.com/compose/how-tos/production/) - [Raff VM](/products/raff-vm) - [Raff Volumes](/products/volumes) - [Raff Data Protection](/products/data-protection) - Technical documentation reviewed: 2026-09-15 --- ### Application Observability for Small Teams: Metrics, Logs, and Traces URL: https://rafftechnologies.com/learn/guides/observability-small-teams-metrics-logs-traces Description: Learn application observability for small teams: monitoring vs observability, metrics, logs, traces, OpenTelemetry, alerting, cost control, and production architecture. Application observability helps a small team answer four production questions: **Is the service working for users, what changed, where is the failure, and what should we do next?** The practical starting point is not a large monitoring platform. Start with user-facing latency, traffic, errors, and saturation; add structured logs and reliable request IDs; then introduce distributed tracing when requests cross enough services that logs no longer explain the path. For teams running workloads on **Raff Technologies**, the same rule applies: keep the first observability layer small enough to operate, and separate telemetry components only when production risk, data volume, or resource contention justifies another VM or service. Observability should shorten detection and recovery time—not become another platform the team struggles to maintain. > **Small-team default:** external availability checks + application metrics + infrastructure metrics + structured logs. Add tracing after architecture complexity creates a real debugging problem. ## Application observability vs monitoring: the quick answer Monitoring and observability overlap, but they are not identical. **Monitoring** checks conditions you already know to watch: availability, error rate, disk space, queue depth, certificate expiry, backup failure, or CPU pressure. **Observability** gives you enough telemetry and context to investigate why the system is behaving the way it is, including failures you did not predict in advance. | Question | Monitoring | Observability | |---|---|---| | Is the service available? | Strong | Strong | | Is latency above a threshold? | Strong | Strong | | Which deployment changed behavior? | Limited without context | Strong | | Which dependency caused one slow request? | Limited | Strong with traces/context | | Why did only one workflow fail? | Often incomplete | Stronger with correlated signals | | Who should act now? | Alert/runbook concern | Alert + diagnostic context | The best small-team system uses both: monitoring should tell you **what matters now**, and observability should help explain **why**. ## Metrics, logs, and traces answer different questions OpenTelemetry treats metrics, logs, and traces as separate telemetry signals. They are most useful when they share consistent service, environment, deployment, request, and trace context. | Signal | Best question | Practical use | |---|---|---| | Metrics | Is behavior changing? | Detection, trends, capacity, SLIs | | Logs | What happened inside this component? | Errors, events, jobs, deployment context | | Traces | Where did this request spend time or fail? | Cross-service latency and dependency diagnosis | A latency metric can show that checkout became slower. Logs may reveal database timeouts. A trace can show that most of the request duration came from one external API. Do not collect all three signals at maximum detail by default. Collect the minimum detail that supports detection, diagnosis, and recovery. ## Start with the four user-facing service signals Google SRE's four golden signals remain a useful baseline for user-facing systems: - **Latency:** how long successful and failed requests or jobs take. - **Traffic:** how much demand the system is serving. - **Errors:** how often users receive incorrect or failed outcomes. - **Saturation:** how close a constrained resource is to its practical limit. A small web application might begin with: | Signal | Example | |---|---| | Latency | p50, p95, p99 HTTP response time | | Traffic | requests/second or completed jobs/minute | | Errors | 5xx rate, failed jobs, rejected transactions | | Saturation | CPU, memory pressure, DB connections, queue depth | Do not use averages alone. A healthy average can hide tail latency, short saturation periods, or failures isolated to one endpoint. The useful sequence is: ```text User symptom ↓ Service metric ↓ Application / dependency evidence ↓ Infrastructure evidence ↓ Action ``` That ordering prevents teams from treating every CPU spike as a customer incident. ## Infrastructure metrics explain capacity, not user experience by themselves For each production VM, database, cache, queue, and worker, collect the signals that reveal resource pressure and waiting. A practical baseline includes: - CPU utilization and load; - memory use and swap activity; - free disk space and growth rate; - disk latency and I/O wait; - network throughput and errors; - process health and restart count; - database connections and query latency; - queue depth, retries, and oldest-job age; - backup age and failure where recovery depends on it. Interpret these beside application behavior. High CPU is not automatically an incident if latency and errors remain healthy. Low CPU does not prove health if the workload is waiting on storage, locks, or an external dependency. For capacity diagnosis, use [Cloud Server Performance Bottlenecks](/learn/guides/cloud-server-performance-bottlenecks-cpu-ram-disk-network) and [Choosing the Right VM Size](/learn/guides/choosing-right-vm-size). ## Structured logs should preserve searchable context Logs become operationally valuable when the team can filter and correlate them during an incident. Prefer structured records with consistent fields such as: - timestamp; - severity; - service and component; - environment; - deployment/version; - request ID or job ID; - trace ID when tracing is enabled; - route or workflow name; - result/status code; - duration; - dependency name; - retry count. Standardize field names across services. If one service calls the field `service`, another calls it `app_name`, and a third calls it `component`, incident searches become slower and dashboards become harder to reuse. Do not log passwords, private keys, access tokens, session cookies, payment data, or unnecessary personal data. Logs are copied, indexed, retained, and accessed by more systems than application developers often expect. Application logs and audit logs also serve different purposes. Application logs explain software behavior; audit logs preserve accountable actions. See [Application Logs vs Audit Logs](/learn/guides/application-logs-vs-audit-logs-developers). ## Correlation IDs are a high-return improvement Before a small team invests heavily in distributed tracing, consistent request and job IDs can provide much of the investigative value. A practical flow is: ```text Incoming request ↓ request_id API / web application ↓ same request_id Worker / queue / downstream call ↓ same request_id Searchable logs ``` When an alert reports elevated errors, an operator can move from the metric to one failed request and then search every relevant component using the same ID. Generate or accept an identifier at the edge, propagate it across important internal boundaries, and include it in logs. When OpenTelemetry tracing is later introduced, preserve trace and span context as well. ## Add distributed tracing when request paths become hard to explain Distributed tracing becomes valuable when a user action crosses several services, queues, workers, databases, or external APIs. Add tracing when: - metrics prove there is a latency problem but not where it occurs; - one workflow crosses multiple services or VMs; - asynchronous work hides the original failure; - retries and fallbacks obscure the first error; - different teams own different parts of one request; - p95 or p99 latency is difficult to attribute. A monolith on one VM may not need full distributed tracing. A multi-service application may need it early. Architecture complexity—not fashion—should determine the timing. Trace volume can grow quickly, so sampling should be deliberate. Preserve enough healthy traffic to understand normal behavior while prioritizing errors, slow requests, low-volume critical workflows, and newly changed services when the backend supports those policies. ## OpenTelemetry gives small teams a portable collection layer OpenTelemetry is a vendor-neutral framework for generating, collecting, and exporting telemetry. The OpenTelemetry Collector can receive traces, metrics, and logs, process them, and forward them to one or more observability backends. That separation can be useful because instrumentation does not have to be tightly coupled to one backend. A simple architecture is: ```text Application / VM telemetry ↓ OpenTelemetry Collector ↓ Metrics / logs / traces backend ``` The Collector does not remove the need to choose a backend, retention policy, alerting model, or capacity plan. It provides a consistent collection and processing layer. For a very small application, adding a Collector before it solves a real problem may still be unnecessary. Use it when standardizing telemetry across services or keeping backend options flexible creates operational value. ## Three observability stages for small teams ### Stage 1 — One production VM Use the smallest reliable set: - external uptime/black-box check; - application error reporting; - latency, traffic, and error metrics; - VM CPU, memory, disk, and network metrics; - structured application logs; - deployment markers; - backup-failure alerts. At this stage, correlation IDs often provide more value than full tracing. ### Stage 2 — Application and data services are separated Once the app, worker, database, cache, or queue live on separate resources, add: - dependency latency/error metrics; - central log collection; - consistent service/environment labels; - request and job context across components; - database and queue saturation indicators; - an OpenTelemetry Collector if it reduces agent/instrumentation fragmentation. ### Stage 3 — Multi-service or distributed application When cross-service diagnosis becomes expensive, add: - distributed tracing for important workflows; - trace-to-log correlation; - sampling and retention policies; - service-level indicators and objectives; - deployment-aware dashboards; - stronger alert routing and runbooks. The maturity target is not “collect everything.” It is “make the next incident faster to understand.” ## Define SLIs before creating more alerts A service level indicator (SLI) measures behavior users care about. A service level objective (SLO) sets a target for that indicator over a period. Small teams can start with one or two critical workflows: | Workflow | Possible SLI | |---|---| | Public API | successful valid requests under a latency threshold | | Checkout | completed transactions / valid attempts | | Authentication | successful valid logins | | Background export | jobs completed within the expected window | This prevents alerting from becoming a list of infrastructure thresholds with no connection to user impact. An SLO does not mean every miss should page someone. It gives the team a shared definition of reliability and a stronger basis for deciding which symptoms require urgent action. ## Alerts should be urgent, important, actionable, and owned Prometheus guidance recommends keeping alerting simple and paging on symptoms associated with user pain rather than every possible cause. For every urgent alert, define: - the user-facing condition that is failing; - the affected service/workflow; - severity; - an owner or rotation; - the first diagnostic link or query; - the first response step; - how recovery is confirmed. Use different destinations for different urgency levels: | Signal | Better destination | |---|---| | Immediate user impact requiring action | Page / urgent incident channel | | Capacity risk requiring planned work | Ticket / operations queue | | Diagnostic cause without current impact | Dashboard / non-urgent notification | | Deployment/configuration event | Timeline / searchable logs | Avoid duplicate paging at every layer. If an application latency alert already captures user impact, separate urgent pages for every downstream CPU, disk, and database symptom may create noise instead of clarity. ## Deployment markers reduce diagnosis time Many incidents follow a change. Record deployment, configuration, migration, and infrastructure events on the same timeline as service metrics. Preserve at least: - deployment version; - start and completion time; - environment; - actor or automation identity; - result; - rollback event when used. During an incident, “what changed before the graph moved?” should not require reconstructing a timeline from CI logs, chat messages, and shell history. ## Control observability cost before volume becomes a problem Observability cost grows through several independent dimensions: - log bytes ingested; - trace/span volume; - metric cardinality; - retention duration; - indexing and query cost; - network transfer to an external backend; - compute and storage for a self-hosted stack. The first controls should be simple: 1. Remove debug logs that are never used. 2. Keep metric labels bounded; avoid raw user IDs, request IDs, or unbounded URL values as metric labels. 3. Use route templates such as `/users/:id` rather than unique paths. 4. Retain high-resolution data only as long as it is operationally useful. 5. Sample traces deliberately. 6. Keep request-specific detail in logs/traces rather than exploding metric cardinality. Do not optimize away evidence that your incident process actually needs. Cost control should remove low-value telemetry, not the signals that prove user impact. ## Do not put every monitoring component on the same failure boundary If the application, metrics backend, logs, dashboards, and alerting all depend on one VM, that VM can fail and remove the evidence needed to diagnose itself. For a small workload, co-locating components may still be a reasonable cost decision. Understand the trade-off and keep at least one external signal such as uptime/black-box monitoring outside the primary failure boundary. As the service becomes more important, separate the monitoring backend when: - telemetry competes with the application for CPU, memory, or disk; - losing one VM would remove both the service and its evidence; - log/metric retention requires materially more storage; - several VMs need one shared observability system; - incident diagnosis depends on telemetry surviving application-host failure. This is also a reason to monitor the monitoring system itself. ## Self-hosted vs managed observability is an ownership decision A self-hosted stack can offer control over software, retention, and deployment. A managed observability service can reduce the work required to operate storage, upgrades, alerting components, and backend availability. Choose based on operational ownership rather than ideology. Self-hosting is a stronger fit when: - the team is comfortable operating the stack; - data volume is predictable; - storage and retention are understood; - control over deployment and data location matters; - the team can recover the observability backend after failure. A managed backend is often a stronger fit when: - the team wants to spend less engineering time maintaining telemetry infrastructure; - retention or ingestion scales unpredictably; - backend availability matters more than infrastructure control; - the organization needs capabilities the team does not want to operate itself. The collection layer and backend decision can also be separated. OpenTelemetry can provide portable instrumentation while the backend remains managed or self-hosted. ## How this applies on Raff A [Raff VM](/products/raff-vm) can host an application, a collector, or a small self-hosted observability stack. As telemetry volume or architecture complexity grows, move the observability backend to a separate VM instead of allowing monitoring workloads to compete with the application they are supposed to diagnose. A practical Raff path is: ```text Stage 1 Raff VM: application + lightweight telemetry agents External uptime check Stage 2 Raff VM(s): application / workers ↓ private traffic Raff VPC ↓ Dedicated telemetry VM or external backend Stage 3 Application VMs + database + workers ↓ Collector / observability backend ↓ Separate retention and recovery policy ``` Use [Raff VPC](/products/vpc) for private service-to-service communication where supported. If a self-hosted telemetry backend needs storage growth independent from the application VM, evaluate [Raff Volumes](/products/volumes) as an infrastructure storage layer and design the guest filesystem and application retention policy explicitly. [Raff Data Protection](/products/data-protection) can support infrastructure-level recovery for eligible resources, but backups do not replace application-aware export, retention, or restore procedures for the observability software itself. Raff provides the infrastructure boundary. Your team still owns instrumentation, alert rules, telemetry retention, access control, dashboards, incident workflows, and restore testing unless a managed service explicitly transfers that responsibility. :::cta Explore Raff VM Start with a simple application VM, then separate telemetry components when measured resource use or reliability requirements justify it. ::: ## Application observability checklist Before calling the system production-observable, confirm: - [ ] Critical user workflows have latency and error signals. - [ ] Traffic and saturation are visible. - [ ] VM and database capacity signals are monitored. - [ ] External monitoring can detect failure of the primary environment. - [ ] Logs are structured and searchable. - [ ] Request/job IDs propagate across important workflows. - [ ] Sensitive values are excluded or redacted from telemetry. - [ ] Deployments appear on the operational timeline. - [ ] Urgent alerts have owners and documented first actions. - [ ] Metric labels have controlled cardinality. - [ ] Log retention and trace sampling are intentional. - [ ] The observability backend itself is monitored. - [ ] Incident reviews lead to instrumentation or runbook improvements. :::cluster ## Conclusion Application observability for a small team should begin with user impact, not a tool catalog. Start with latency, traffic, errors, and saturation. Add structured logs with consistent request context. Use correlation IDs before adding complexity that does not yet solve a real problem. Introduce distributed tracing when important requests cross enough boundaries that metrics and logs no longer explain the path. Then make the system operational: define meaningful SLIs, page only on actionable symptoms, mark deployments, control telemetry cost, and keep enough monitoring outside the main failure boundary to diagnose an outage. For Raff workloads, begin on the smallest infrastructure that can be operated reliably and separate the telemetry stack only when resource contention, retention, or reliability requirements make that separation valuable. ## Sources - [OpenTelemetry Documentation](https://opentelemetry.io/docs/) - [OpenTelemetry Collector](https://opentelemetry.io/docs/collector/) - [Google SRE: Monitoring Distributed Systems](https://sre.google/sre-book/monitoring-distributed-systems/) - [Prometheus: Alerting Practices](https://prometheus.io/docs/practices/alerting/) - [Raff VM](/products/raff-vm) - [Raff VPC](/products/vpc) - [Raff Volumes](/products/volumes) - [Raff Data Protection](/products/data-protection) - Technical references verified: 2026-09-15 --- ### Podman vs Docker: Security, Compatibility, and When to Switch URL: https://rafftechnologies.com/learn/guides/docker-vs-podman-small-teams Description: Compare Podman vs Docker for small teams: rootless security, Docker compatibility, Compose vs Quadlet, migration risks, and when to switch runtimes. **For most small teams, Docker is still the lower-risk default because Docker Compose, vendor documentation, CI/CD tooling, and third-party integrations are more broadly supported. Podman becomes the stronger choice when rootless operation, a daemonless Linux-first workflow, and systemd-native service management through Quadlet are explicit requirements.** For teams running container workloads on **Raff Technologies**, the runtime decision should come after the workload decision. Docker or Podman can both run well on a Linux VM. If the real problem is multi-node scheduling, replicas, service discovery, or coordinated rollouts across servers, changing container engines will not solve it; that is where Kubernetes becomes the more relevant next step. The important security nuance is also simple: **Podman is not automatically secure and Docker is not automatically insecure.** Docker supports rootless mode, while Podman makes rootless operation a central part of its design. The safer choice is the runtime your team can configure, patch, monitor, and operate consistently. ## Podman vs Docker: quick verdict | Situation | Better default | Why | |---|---|---| | Existing Docker Compose estate | Docker | Lowest migration and compatibility risk | | Vendor docs assume Docker | Docker | Fewer unsupported edge cases | | CI or tooling depends on Docker API/socket | Docker | Native compatibility | | Linux server with rootless-first requirement | Podman | Rootless is a core operating model | | Team manages services through systemd | Podman | Quadlet integrates container lifecycle with systemd | | Need pods on one Linux host | Podman | Pods are a native abstraction | | Need cluster scheduling across multiple servers | Kubernetes, not either runtime alone | Runtime choice does not provide multi-node orchestration | | No clear reason to migrate | Stay on the current runtime | Avoid change without operational benefit | Both Docker and Podman can run OCI-compatible container images. The difference that matters most is not image format. It is **how the runtime fits your surrounding deployment, security, networking, storage, and operations workflow**. ## Docker and Podman use different operating models Docker Engine uses a client-server architecture. The Docker CLI communicates with the long-running `dockerd` daemon through the Docker API. The daemon manages containers, images, networks, and volumes. Podman is designed so ordinary local container operations do not require one always-running central daemon. The `podman` CLI manages containers directly, while an API service can still be exposed when remote or compatibility workflows need one. That distinction affects operations: | Area | Docker | Podman | |---|---|---| | Core architecture | Client + API + long-running daemon | Daemonless local engine for normal operation | | Rootless mode | Supported | Core/common operating model | | Compose | Native Docker Compose workflow | Runs Compose workloads through an external compose provider | | systemd | Docker service + container restart policies; systemd can wrap lifecycle | Quadlet generates systemd-managed container services | | Pods | Not a primary Docker abstraction | Native pod support | | API ecosystem | Very broad Docker API/socket ecosystem | Compatibility API available, but not universal behavioral parity | | Typical strength | Compatibility and ecosystem | Linux-native rootless/systemd workflow | “Daemonless” should not be interpreted as “no background processes.” Containers still run as processes, and systemd or other services may manage their lifecycle. The distinction is that normal Podman operation does not depend on one central daemon in the same way Docker Engine does. ## Is Podman more secure than Docker? **Not automatically.** Podman has an attractive security model because rootless operation is deeply integrated into its normal Linux workflow, but Docker also supports a true rootless mode in which both the Docker daemon and containers run without root privileges inside a user namespace. Rootless operation can reduce the impact of some runtime or container compromises because the processes do not start with host root privileges. It is one security layer, not a complete container security strategy. Security still depends on: - where images come from and how quickly they are patched; - whether unnecessary Linux capabilities are removed; - seccomp, AppArmor, or SELinux policy where applicable; - whether containers run privileged; - secret handling; - filesystem permissions; - read-only filesystem use where practical; - exposed ports and firewall policy; - runtime socket access; - host patching; - backup and recovery controls. A container with excessive privileges, exposed secrets, or unsafe mounts can remain dangerous under either runtime. ### Rootless Docker vs Podman The practical comparison is not “Podman has rootless; Docker does not.” Both support it. Podman commonly starts from a rootless-first Linux workflow. Docker's standard deployment model still commonly uses the system Docker daemon, with rootless mode available as a deliberate configuration choice. Rootless deployments can affect: - low-numbered/privileged ports; - user and group mappings; - bind-mount ownership; - cgroups behavior; - device access; - networking implementation and performance; - storage drivers; - integration with other host services. Test the actual production workload. A security architecture that breaks backup jobs, networking, or file permissions is not a finished security architecture. ## Docker socket access is a major trust boundary Many container-management tools, CI runners, dashboards, and automation systems mount or access a runtime socket. With Docker, software that can control the Docker API may effectively gain powerful control over the host through container creation, mounts, networking, and privileged execution. Podman compatibility sockets can create a similarly high-trust control path when exposed to software. Treat runtime API/socket access as administrative access: - do not expose it publicly; - restrict filesystem permissions; - avoid mounting it into arbitrary containers; - document which applications require it; - remove unused integrations; - prefer narrowly scoped automation where possible. This matters more than the runtime brand name when evaluating real-world container security. ## Podman Docker compatibility: images are the easy part Podman and Docker can both work with OCI-compatible images and registries, so many Docker-built images can run under Podman without modification. But **image compatibility is not the same as operational compatibility**. A migration can still reveal differences in: - container networking; - bind mounts and UID/GID ownership; - rootless filesystem permissions; - host access from containers; - Docker API/socket dependencies; - Compose behavior; - build features; - health-check assumptions; - service naming; - restart lifecycle; - SELinux labeling; - privileged or device-dependent workloads. If the image starts successfully but the application cannot write to its data directory, discover another service, reach a host dependency, or satisfy its health check, the migration is not compatible yet. ## Docker Compose vs Podman Compose This is one of the highest-risk areas for an existing small-team deployment. Docker Compose is part of the standard Docker workflow and is assumed by a large amount of application documentation. Podman supports Compose workloads through an **external compose provider** rather than reproducing every Docker Compose behavior inside the Podman engine itself. That means a simple Compose stack may work with very little change, but teams should test rather than assume perfect equivalence. Pay special attention to: - custom networks and DNS expectations; - health checks and dependency order; - bind-mount ownership under rootless execution; - container naming assumptions; - applications that mount `/var/run/docker.sock`; - build extensions or Docker-specific options; - host networking; - privileged containers and devices; - third-party deployment tools expecting Docker events or APIs. For a production Compose estate with no Podman-specific requirement, Docker remains the lower-risk default. ## Podman Quadlet vs Docker Compose **Docker Compose and Podman Quadlet overlap, but they are not direct equivalents.** Docker Compose is primarily an application-oriented way to define and run a multi-container stack. Quadlet is a systemd-oriented deployment model: declarative Podman files are translated into systemd services, so the host's normal service manager controls startup, dependencies, logging, restart behavior, and lifecycle. Quadlet supports unit types for containers, pods, networks, volumes, images, builds, and Kubernetes-style YAML workloads. Use Docker Compose when: - developers already think in Compose projects; - the same application definition is used locally and on servers; - vendor deployment instructions ship as Compose; - portability across Docker environments matters more than systemd integration. Use Quadlet when: - containers are long-running Linux server services; - the team already operates systemd confidently; - host boot ordering matters; - rootless per-user services are useful; - you want container services managed through `systemctl` and `journalctl`; - Kubernetes would add unnecessary cluster complexity. A small Linux operations team may find Quadlet cleaner than maintaining shell wrappers around containers. A product team using Compose across laptops, CI, staging, and production may prefer to keep one familiar deployment model. ## Podman pods do not replace Kubernetes Podman includes pods as a native concept. Containers in a pod can share selected namespaces and be managed together on one host. That is useful for tightly coupled containers and some Kubernetes-like workload patterns, but it does **not** turn one Podman server into a Kubernetes cluster. Podman alone does not provide the same multi-node operating model for: - scheduling replicas across nodes; - cluster-wide reconciliation; - cross-node service discovery; - node failure rescheduling; - cluster ingress and service primitives; - coordinated multi-node rollout behavior. If your pain is becoming “we have too many containers across too many servers to coordinate manually,” compare [Kubernetes vs Docker Compose for Small Teams](/learn/guides/kubernetes-vs-docker-compose-small-teams) rather than expecting a runtime switch to solve orchestration. ## Networking differences can break an otherwise clean migration Basic port publishing and container networking exist in both runtimes, but rootless networking and host integration can behave differently enough to matter. Before switching production workloads, test: - service-to-service DNS resolution; - published ports; - reverse proxy discovery; - access from containers to host services; - IPv4/IPv6 behavior where used; - firewall interaction; - database connectivity; - rootless networking throughput and latency for relevant workloads. Do not work around networking issues by exposing databases, caches, or internal APIs directly to the public internet. When a containerized workload is split across multiple Raff VMs, use private infrastructure paths where appropriate rather than treating public IPs as the default internal network. ## Persistent storage needs a migration plan Switching runtimes is easy when containers are stateless. Persistent data is where migrations become dangerous. Before changing Docker to Podman or moving from rootful to rootless execution: 1. Inventory every named volume and bind mount. 2. Record UID/GID ownership and permissions. 3. Identify which process is the authoritative writer. 4. Take an application-aware backup. 5. Stop or quiesce writes before copying state. 6. Test ownership under the destination runtime. 7. Start the workload in non-production or a maintenance window. 8. Verify application-level reads and writes. 9. Test restore before deleting the old environment. Rootless Podman may surface ownership problems that did not appear in a rootful Docker deployment because host IDs are mapped differently. For the storage trade-off itself, see [Docker Volumes vs Bind Mounts](/learn/guides/docker-volumes-vs-bind-mounts-production). ## Performance usually should not decide Docker vs Podman For normal web applications, the runtime is rarely the dominant performance factor. Application code, CPU sizing, memory pressure, storage latency, database design, network paths, image startup behavior, and concurrency limits usually matter more. Avoid universal claims that Docker or Podman is “faster.” Benchmark the operation that matters to your workload: - build time; - cold startup; - HTTP latency/throughput; - storage I/O; - rootless networking; - memory overhead; - reboot recovery; - deployment and rollback duration. Test on the same operating system, VM size, storage layer, and workload. Cross-provider benchmark numbers can hide more than they reveal. ## When Docker is the better choice Choose or keep Docker when most of these are true: - your team already deploys with Docker Compose; - application vendors document Docker as the supported path; - CI/CD or management software uses Docker APIs; - developer onboarding benefits from common Docker workflows; - production is already stable on Docker; - developers need similar tooling across laptops and servers; - Podman does not solve a specific current problem. For most small teams, this remains the pragmatic default. ## When Podman is the better choice Choose Podman when most of these are true: - rootless operation is an explicit production requirement; - Linux servers—not desktop tooling—are the center of the workflow; - the team is comfortable with systemd; - Quadlet fits the desired deployment model; - Docker-specific API/socket integrations are limited; - native pods on one host are useful; - the team can test Compose, networking, and volume behavior before migration. Podman is especially compelling when the desired outcome is “manage containerized Linux services like other systemd services” rather than “keep every Docker workflow unchanged.” ## Should you switch from Docker to Podman? Use this sequence before deciding: 1. **Name the problem.** Is it root privileges, systemd integration, daemon policy, or something else? 2. **Check compatibility.** Which applications depend on Docker Compose, APIs, sockets, or specific networking behavior? 3. **Validate rootless constraints.** Test storage, ports, cgroups, devices, and network paths. 4. **Choose the lifecycle model.** Compose, Quadlet, or another deployment workflow? 5. **Protect persistent data.** Back up and test restore first. 6. **Test incident operations.** Reboot, restart, log inspection, rollback, and recovery must work. 7. **Keep a rollback path.** Do not remove the known-good Docker environment before acceptance checks pass. If you cannot identify a concrete benefit that survives those tests, staying on Docker is usually the better engineering decision. ## Migration checklist: Docker to Podman Before production cutover, confirm: - [ ] All containers, networks, ports, volumes, and secrets are inventoried. - [ ] Docker socket/API dependencies are identified. - [ ] Compose features have been tested with the chosen Podman workflow. - [ ] Bind-mount ownership works in the intended rootless/rootful mode. - [ ] Network and reverse-proxy behavior is verified. - [ ] Database and persistent data backups are current. - [ ] Restore has been tested. - [ ] Logging and monitoring still collect the required signals. - [ ] The service starts correctly after a host reboot. - [ ] Deployment and rollback are documented. - [ ] Operators know whether Compose or Quadlet owns lifecycle. - [ ] The old environment remains recoverable until acceptance is complete. ## How this applies on Raff A Linux-based [Raff VM](/products/raff-vm) can run either Docker or Podman. Choose the VM size from the actual application, build, database, storage, and concurrency requirements rather than from the container engine alone. For a simple production app, one VM with Docker Compose or Podman/Quadlet may be the right operating boundary. As the application grows, separate infrastructure roles when there is a measurable reason to do so. A practical path can look like: ```text Raff VM ↓ Docker Compose or Podman/Quadlet ↓ Raff VPC for private cross-VM traffic when roles split ↓ Raff Data Protection for infrastructure recovery where applicable ↓ Raff Kubernetes when multi-node orchestration becomes the actual problem ``` Use [Raff VPC](/products/vpc) when application, database, worker, or internal-service traffic spans multiple supported resources. Review [Raff Data Protection](/products/data-protection) for infrastructure-level recovery, while keeping application-aware backup and restore procedures for stateful workloads. If containers start spreading across several VMs and deployment coordination becomes the bottleneck, evaluate [Raff Kubernetes](/products/kubernetes) instead of trying to solve a cluster problem by changing only the local container runtime. :::cta Explore Raff VM Run Docker or Podman on a Linux VM, then add infrastructure complexity only when the workload requires it. ::: ## Conclusion For most small teams comparing **Podman vs Docker**, Docker is still the safer default because it minimizes compatibility and workflow changes. Podman is the stronger alternative when rootless-first Linux operations, daemonless runtime behavior, and systemd-native management through Quadlet solve real requirements. Do not switch only because Podman commands resemble Docker commands. OCI image compatibility is useful, but production compatibility also includes Compose behavior, APIs, sockets, networking, persistent storage, permissions, monitoring, and recovery. And if the underlying problem is multi-node coordination rather than the local container engine, move the decision up one layer: compare VM-based deployment with Kubernetes orchestration instead. ## Sources - [Docker Engine documentation](https://docs.docker.com/engine/) - [Docker rootless mode](https://docs.docker.com/engine/security/rootless/) - [Podman documentation](https://docs.podman.io/en/latest/markdown/podman.1.html) - [Podman systemd and Quadlet documentation](https://docs.podman.io/en/latest/markdown/podman-systemd.unit.5.html) - [Podman Quadlet basic usage](https://docs.podman.io/en/latest/markdown/podman-quadlet-basic-usage.7.html) - Technical references verified: 2026-09-15 --- ### Preview Environments vs Staging: What Startups Actually Need URL: https://rafftechnologies.com/learn/guides/preview-environments-vs-staging Description: Compare preview environments vs staging: when startups need ephemeral previews, persistent staging, or both, with lifecycle, secrets, data, cost, and Raff architecture guidance. **Preview environments and staging solve different release problems. A preview environment is usually an ephemeral deployment created for one branch, pull request, or change. A staging environment is a stable pre-production environment used to validate the combined release before production.** For most startups, use **preview environments when parallel change review is the bottleneck**, use **staging when release confidence is the bottleneck**, and use **both when those are separate decisions**. For teams building on **Raff Technologies**, this does not require an elaborate platform from day one. A small team can begin with one persistent staging VM, add ephemeral preview environments when shared staging becomes contested, and automate cleanup only when the workflow earns that complexity. > **Quick rule:** preview answers “Is this change ready to merge?” Staging answers “Is this release ready to ship?” ## Preview environments vs staging at a glance | Decision factor | Preview / ephemeral environment | Staging environment | |---|---|---| | Main purpose | Validate one change | Validate one combined release | | Typical trigger | Branch, commit, or pull request | Release candidate or promotion step | | Lifetime | Short-lived | Persistent or regularly recreated | | Users | Developers, QA, design, product reviewers | Engineering, QA, operations, release owners | | Data | Synthetic or isolated test data | Production-like but protected data | | Configuration | Change-specific and restricted | Production-compatible configuration structure | | Main risk reduced | Review and merge risk | Release and integration risk | | Cleanup | Automatic expiry/deletion | Managed as a long-lived environment | The mistake is treating one environment as a universal pre-production layer. Preview and staging are most useful when each owns a clear decision. ## What is an ephemeral environment? An **ephemeral environment** is a temporary environment created for a specific task and destroyed when that task is complete. Preview environments are one common type. A typical flow is: ```text Pull request opened ↓ Ephemeral preview environment created ↓ Review / automated tests / stakeholder approval ↓ Pull request merged or closed ↓ Environment and related resources deleted ``` The defining characteristic is not the technology used to create it. It is the lifecycle: the environment has an explicit trigger, owner, and end condition. Ephemeral environments are useful because they reduce contention. Instead of five developers repeatedly replacing one shared staging environment, each change can have an isolated place to be reviewed. They also create new operational requirements: cleanup, secret isolation, test data, DNS or URLs, cost controls, and protection against untrusted code. A temporary environment that is never deleted is simply forgotten infrastructure. ## Start with the confidence your team is missing Do not begin by asking which environment is more modern. Ask which decision currently lacks evidence. Use a preview environment when: - several changes need review in parallel; - product, design, or QA needs a shareable version of one branch; - shared staging is constantly overwritten; - pull-request feedback is slow because reviewers cannot run the change; - change-specific automated tests benefit from isolation. Use staging when: - a release combines several merged changes; - database migrations, workers, queues, and integrations must be tested together; - deployment and rollback procedures need validation; - a stable pre-production endpoint is required; - the team needs one shared release-approval environment. Use both when change-level review and release-level validation are separate gates. ## Preview environments are change-level deployments A preview environment is commonly created from a branch, pull request, or commit and given its own URL. Heroku Review Apps and Vercel Preview Deployments are familiar examples of this operating model: each change can receive an isolated deployable surface for review rather than competing for one shared pre-production environment. ```text Pull request A → Preview A Pull request B → Preview B Pull request C → Preview C ``` Preview environments are strongest for: - visual and product review; - feature acceptance; - branch-specific API testing; - integration tests against isolated test services; - reproducing a bug on a known commit; - validating configuration before merge; - sharing a change with internal stakeholders. They are weaker when the question depends on the complete release, long-running behavior, production-scale data, or the final production deployment path. ## Staging is a release-level environment A staging environment is a stable pre-production system used to validate the release expected to reach production. ```text Merged release candidate ↓ Staging deployment ↓ Migration + integration + smoke + operational checks ↓ Approval ↓ Production ``` A useful staging environment should validate more than whether the home page loads. Depending on the application, it may test: - the production deployment mechanism; - database migrations; - background workers and scheduled jobs; - HTTPS, DNS, proxy, and firewall behavior; - environment-specific configuration; - external services in approved test modes; - logs, metrics, alerts, and health checks; - rollback or recovery steps. Staging provides value only when teams trust it. A long-lived environment that has drifted away from production can create false confidence. ## Preview does not automatically replace staging A preview may prove that one branch works while missing: - interactions with other merged changes; - final release configuration; - production deployment permissions; - shared database migration behavior; - long-running jobs; - release ordering; - production-like network paths; - operational monitoring. Conversely, staging is often inefficient for branch review. One shared environment becomes unstable when several developers deploy unrelated changes to it throughout the day. The choice is therefore not preview **or** staging by default. Give each environment one job. ## Choose preview only, staging only, or both | Team situation | Better model | Why | |---|---|---| | One or two developers, infrequent releases | Staging only | One stable checkpoint may be enough | | Many pull requests and frequent visual review | Preview first | Parallel feedback is the main constraint | | Fast development plus meaningful production risk | Preview + staging | Separate merge confidence from release confidence | | Complex integrations or migrations | Staging required | Combined-system validation matters | | Disposable prototype | Local/development only | Extra infrastructure may not yet earn its cost | | Shared staging constantly overwritten | Add previews | Remove branch-level work from staging | | Preview deploys exist but releases still surprise production | Add/improve staging | Change-level checks are not proving the release | Environment architecture should evolve when workflow risk changes—not merely when the team reaches a particular size. ## Environment parity should match the decision The Twelve-Factor App recommends keeping development, staging, and production as similar as practical. The same principle applies to previews, but identical capacity is rarely necessary. Keep these compatible when they affect correctness: - runtime and dependency versions; - database engine and major version; - build artifact; - environment-variable names; - queue and worker behavior; - storage APIs; - reverse proxy and TLS behavior; - schema migration process; - health checks. These may differ intentionally: - VM size; - traffic volume; - retention period; - redundancy; - test dataset size; - number of application nodes. Document material differences. An environment cannot prove behavior it does not reproduce. ## Promote a known artifact through staging Final release control should identify exactly what is expected to reach production. A safer release path is: ```text Commit / merge ↓ Versioned build artifact ↓ Staging validation ↓ Production promotion or deployment ``` Record the commit, artifact version, migrations, validation result, and production deployment. Some platforms promote an existing preview artifact. Others rebuild for production using production configuration. Verify which model your deployment system uses; “promote” does not always mean the identical bytes and settings move unchanged. ## Secrets must be isolated by environment Preview environments are frequently created automatically, making secret scope especially important. Use separate credentials for: - preview; - staging; - production. A preview environment should not inherit broad production access merely because it was created from the same repository. Apply these controls: - scope credentials to one environment and service; - keep preview credentials low privilege; - restrict who can trigger production deployment; - do not expose production secrets to untrusted pull requests; - rotate credentials when environments or integrations are retired. Production secrets should never be copied into temporary environments for convenience. ## Data must be separated from production A preview or staging application should not write to the production database. Use: - synthetic data; - seeded fixtures; - isolated test databases; - masked or anonymized copies; - service sandbox modes. Preview environments usually need small, disposable datasets. Staging may need more representative schemas and edge cases, but that does not justify copying raw customer data without an approved transformation and access process. Each preview should also avoid interfering with other previews. Shared test databases can create conflicting migrations, duplicate webhook events, reused accounts, and nondeterministic tests. ## External integrations need environment-specific behavior Preview and staging deployments may interact with email, payments, OAuth, webhooks, object storage, queues, analytics, and external APIs. Define whether each integration is: - mocked; - disabled; - connected to a sandbox; - connected to an isolated test account; - allowed with strict limits. A preview should not send real customer email or trigger live payments. Staging should validate integrations through approved non-production endpoints where available. ## Ephemeral environments need a complete lifecycle Creating a preview is only half the system. Every temporary environment needs a reliable deletion path. Track: - owner; - repository and pull request; - commit or branch; - creation time; - expiration condition; - URL and DNS records; - credentials; - database or dataset; - storage objects; - firewall rules; - destruction result. Deleting only the compute instance is not enough. Remove related databases, storage, credentials, DNS, queues, and network rules. Use [Stale Infrastructure Cleanup](/learn/guides/stale-infrastructure-risk-old-servers-forgotten-keys-abandoned-services) for the wider cleanup process. ## Staging also needs ownership and reset rules A persistent staging environment can accumulate its own drift and test debris. Define: - who owns availability and configuration; - how data is reset; - when migrations are applied; - who may deploy; - how release candidates are identified; - whether staging may be used for demos; - how drift is detected; - when the environment is rebuilt. Do not allow staging to become an unofficial production service. If customers or permanent business workflows depend on it, its role has changed. ## Measure whether each environment earns its cost The full cost includes more than compute: - build minutes; - databases and storage; - test integrations; - CI/CD maintenance; - environment-specific failures; - orphaned resources; - security review; - developer waiting time. Useful indicators include: - pull-request-to-review time; - staging conflicts; - abandoned previews; - release defects staging should have caught; - environment drift incidents; - monthly non-production infrastructure cost. A preview system is justified when faster parallel review outweighs automation and cleanup cost. Staging is justified when it catches release-level failures or provides a trusted operational checkpoint. ## VM-based preview environments can be the simplest useful model Preview environments do not require Kubernetes or a custom internal platform. For a small team, an ephemeral VM can be enough when the application needs host-level isolation, Docker Compose, system packages, custom ports, or a production-like Linux environment. ```text Pull request ↓ automation Temporary Raff VM ↓ App + test configuration ↓ Review / validation ↓ Destroy VM + associated resources ``` A VM-based preview has a higher provisioning cost than a lightweight serverless preview, but it can provide more realistic infrastructure behavior for applications that will actually run on VMs in production. Use it when that fidelity is valuable. Do not provision a full VM per pull request simply because the automation is possible. ## When containers or Kubernetes make more sense As preview volume grows, teams may want denser or more automated environments. Containers can reduce setup overhead when many previews share common infrastructure. Kubernetes namespaces or isolated workloads can support larger-scale ephemeral-environment systems, but they also introduce cluster policy, quotas, cleanup, ingress, secrets, and observability concerns. Do not move to Kubernetes just to create previews if the team does not otherwise need a cluster operating model. Review [Kubernetes vs Docker Compose for Small Teams](/learn/guides/kubernetes-vs-docker-compose-small-teams) first. ## A practical environment progression ### Stage 1 — Local development plus production Appropriate only for a low-impact prototype. Keep production deployment and recovery documented. ### Stage 2 — Add staging Use one stable environment to validate complete releases before production. ### Stage 3 — Add previews Create short-lived branch environments when shared staging begins blocking parallel work. ### Stage 4 — Automate lifecycle and promotion Standardize provisioning, secrets, datasets, tests, approval, expiry, and deletion. ### Stage 5 — Add specialist environments only when justified Performance, security, demo, migration, or load-testing environments should have a defined purpose and retirement rule. This progression is not mandatory. A frontend-heavy team may adopt previews before staging; a migration-heavy backend may need staging first. ## How this applies on Raff A VM-based Raff setup can use separate [Raff VM](/products/raff-vm) instances for persistent staging or temporary preview workloads, with [Raff VPC](/products/vpc) for private backend communication where supported. A practical model is: ```text Pull request ↓ automation Temporary preview VM ↓ merge Shared staging Raff VM ↓ release approval Production environment ``` Use separate credentials, databases, storage paths, and network rules for each environment. If previews need durable artifacts or test files that should survive independently of the VM lifecycle, evaluate [Raff Object Storage](/products/object-storage) rather than coupling temporary compute and long-lived data. If environment creation grows into a genuine multi-node orchestration problem, [Raff Kubernetes](/products/kubernetes) may become relevant. Do not adopt it solely because ephemeral environments sound more sophisticated on a cluster. :::cta Explore Raff VM Build a persistent staging environment first, then add isolated preview environments when parallel review justifies them. ::: ## Preview and staging decision checklist ### Choose preview environments when - branch-level review is slow; - several changes need parallel validation; - reviewers need shareable change-specific URLs; - environments can be provisioned and deleted reliably; - test data and credentials can be isolated. ### Choose staging when - complete releases need validation; - migrations and integrations must be tested together; - deployment and rollback need a stable checkpoint; - the environment can remain production-compatible; - access and data boundaries are controlled. ### Use both when - previews validate changes before merge; - staging validates the combined release; - each environment has a distinct owner and purpose; - artifacts, configuration, and promotion are traceable; - cleanup and drift are measured. :::cluster ## Conclusion Preview environments and staging are complementary controls. Use **ephemeral preview environments** to isolate and accelerate change-level review. Use **staging** to validate the combined release, deployment path, migrations, integrations, and operational behavior before production. For a small team, start with the simplest environment model that fixes the current release bottleneck. One persistent staging VM may be enough. Add previews when parallel review creates measurable friction, and automate their lifecycle before temporary infrastructure starts becoming permanent infrastructure by accident. ## Sources - [The Twelve-Factor App: Dev/Prod Parity](https://12factor.net/dev-prod-parity) - [GitHub Docs: Deployments and Environments](https://docs.github.com/en/actions/reference/workflows-and-actions/deployments-and-environments) - [Heroku Dev Center: Review Apps](https://devcenter.heroku.com/articles/github-integration-review-apps) - [Vercel Docs: Environments](https://vercel.com/docs/deployments/environments) - Technical references verified: 2026-09-15 --- ### Cloud Firewall Rules Explained: Inbound, Outbound, and Least Privilege URL: https://rafftechnologies.com/learn/guides/cloud-firewall-rules-explained Description: Learn inbound vs outbound cloud firewall rules, least-privilege policy, firewall rule best practices, verification, private networking, and rule lifecycle management. **Inbound firewall rules control connections trying to reach a cloud server. Outbound rules control connections leaving it. A strong cloud firewall policy starts with the smallest required exposure, scopes administrative and internal services to trusted sources, documents why every rule exists, and verifies the effective policy from outside the server.** For workloads on **Raff Technologies**, treat firewall policy as one layer of the security model—not as a substitute for SSH/RDP hardening, application authentication, patching, private networking, or monitoring. This guide explains the architecture and review process without assuming that every firewall product evaluates rules in exactly the same way. > **Practical rule:** public web traffic may need broad access to 80/443. Administrative ports, databases, caches, queues, dashboards, and internal APIs usually should not. ## Cloud firewall rules at a glance | Question | Safer default | |---|---| | What should be publicly reachable? | Only services intended for public users | | SSH/RDP source | Trusted IP range, VPN/private path, or another controlled admin path | | Database/cache source | Application/private network only | | Inbound policy | Explicitly allow required traffic; deny unnecessary exposure | | Outbound policy | Start from workload needs; restrict sensitive roles where the benefit justifies operational complexity | | Rule ownership | Named service/owner and reason | | Rule lifetime | Review and remove when the dependency disappears | | Verification | Test from the network path users or administrators actually use | The goal is not the largest ruleset. It is a policy your team can explain. ## What is a cloud firewall rule? A firewall rule describes network traffic that should be allowed or denied according to properties such as: - direction; - source and destination; - protocol; - port or port range; - network/interface context; - connection state, depending on implementation. A typical inbound requirement might be expressed as: ```text Allow TCP 443 Source: public internet Reason: customer HTTPS traffic ``` An administrative rule should be narrower: ```text Allow TCP 22 Source: approved admin network Reason: Linux administration ``` Do not copy syntax or rule-order assumptions from one firewall product into another. Cloud firewalls, Linux nftables/iptables, UFW, Windows Defender Firewall, security groups, and network ACLs can have different evaluation and state models. Verify the implementation you actually use. ## Inbound vs outbound firewall rules **Inbound rules** control traffic attempting to enter a server or protected network boundary. Examples: - browser → HTTPS service; - administrator → SSH/RDP; - application server → database; - monitoring system → metrics endpoint. **Outbound rules** control traffic initiated toward another destination. Examples: - application → external API; - server → package repository; - database → backup destination; - CI runner → source/package registry. Return traffic for an established connection may be handled automatically by a **stateful** firewall. Stateless systems require a different rule design. Do not assume statefulness from the word “cloud firewall”; confirm the product behavior. ## Stateful vs stateless firewalls A stateful firewall tracks connection state. When an allowed connection is established, related return traffic can be recognized as part of that connection. A stateless firewall evaluates packets without relying on the same connection-tracking model. This matters because a rule such as “allow outbound HTTPS” can behave differently depending on the firewall architecture and where the rule is enforced. The important operational lesson is: > **Design from the documented behavior of the firewall you use, not from a generic diagram.** The same applies to rule ordering. Some systems use ordered rules, some use priorities, some combine allow/deny semantics differently, and some security-group-style models are not “first match wins.” ## Least privilege for firewall rules Least privilege means granting only the network reachability required for a workload to function. For firewall policy, apply four constraints: 1. **Service:** Which process needs to be reachable? 2. **Port/protocol:** What exact network path does it use? 3. **Source:** Which users, servers, networks, or services need access? 4. **Lifetime:** How long should the rule exist? For example, this is broad: ```text TCP 5432 from 0.0.0.0/0 ``` This is narrower: ```text TCP 5432 from application private subnet ``` The second rule does not make PostgreSQL secure by itself. Database authentication, TLS where required, patching, roles, and application security still matter. It simply removes unnecessary network reachability. ## Firewall rule best practices ### Keep public exposure intentional Public web servers commonly need HTTP/HTTPS. That does not mean their database, cache, application debug port, monitoring endpoint, or admin dashboard should also be public. Before opening a port, record: - service name; - owner; - source that needs access; - business/technical reason; - whether a private path can be used instead; - review or expiry condition. ### Restrict administrative access SSH and RDP are management surfaces. Prefer a trusted source range, VPN/private-access model, bastion, or another controlled administrative path when the environment justifies it. Changing SSH from port 22 to another port may reduce background scanning noise, but it is not a substitute for strong authentication and source restriction. Use [Bastion Host vs VPN vs Public SSH](/learn/guides/bastion-host-vs-vpn-vs-public-ssh) when choosing the administration model. ### Keep databases and caches private where practical Typical internal services include: | Service | Common port | Preferred exposure | |---|---:|---| | PostgreSQL | 5432 | Application/private sources only | | MySQL | 3306 | Application/private sources only | | Redis/Valkey | 6379 | Application/private sources only | | Internal API | App-specific | Approved service/private sources | | Metrics endpoint | App-specific | Monitoring sources only | | SSH | 22 | Controlled admin sources | | RDP | 3389 | Controlled admin sources | | HTTP/HTTPS | 80/443 | Public only when the service is intentionally public | These are common ports, not a universal template. Verify the actual service configuration. ### Avoid oversized trusted CIDRs A broad CIDR can accidentally grant access to far more systems than intended. If one subnet needs access, scope to that subnet rather than a much larger private range merely because it is convenient. Document why the range exists so future operators can safely narrow or remove it. ### Remove temporary rules Temporary migrations, debugging sessions, vendor access, tests, and incident-response work often create temporary network exceptions. Every temporary rule should have: - an owner; - a reason; - an expiry or review point; - a cleanup step. Without lifecycle ownership, temporary access becomes permanent exposure. ## A practical inbound policy by server role | Server role | Public inbound | Restricted inbound | |---|---|---| | Public web/app | 80/443 as required | SSH/RDP from admin path | | Database | Usually none | DB port from application/private path; admin from controlled path | | Worker | Usually none | Admin/monitoring paths only | | Monitoring server | Only if product requires it | Admin and monitored-source paths | | Bastion | Admin entry port from trusted sources | Private access to approved targets | | CI runner | Usually none | Admin access only when required | A role-based policy is easier to review than a long list of ports with no architecture behind it. ## Outbound firewall rules: when are they useful? Outbound restrictions can reduce the destinations a compromised or misconfigured workload can reach, but they also add maintenance cost. They are most useful when: - a sensitive workload has a small, predictable set of dependencies; - compliance or customer requirements demand egress controls; - a database or internal service has little reason to reach the public internet; - a deployment environment needs a deliberately constrained network path; - exfiltration and command-and-control risk justify tighter egress policy. They can be harder to operate when applications depend on large or frequently changing SaaS endpoints, CDNs, package repositories, or third-party APIs. Do not build an outbound allowlist you cannot maintain. A stale security rule that repeatedly gets bypassed during incidents is not a strong control. ## Do not use domain names as if they were static IP policy A rule such as “allow only npm, Docker Hub, and GitHub” sounds simple but can be difficult at the network firewall layer because services may use changing IP ranges, CDNs, redirects, mirrors, and multiple domains. Before enforcing destination allowlists, understand whether the firewall supports: - IP/CIDR destinations; - service tags or provider-managed lists; - FQDN/domain-aware policy; - dynamic updates; - logging for denied egress. Otherwise, maintenance can become fragile. ## Private networking and firewall rules solve different problems A private network reduces unnecessary internet exposure. A firewall decides which reachable systems may communicate. A common multi-VM design is: ```text Internet ↓ Public application endpoint ↓ private network Application VM ↓ private network Database / cache / worker ``` The database can remain off the public internet while still accepting traffic from the application tier. Use [Raff VPC](/products/vpc) for supported private connectivity between Raff resources. Private networking should still be paired with appropriate authentication, host/service configuration, and network policy. ## Cloud firewall vs host firewall A network-level firewall and a host firewall can provide complementary boundaries. ### Network or cloud firewall Useful for: - controlling traffic before it reaches the guest OS; - reducing public exposure; - applying infrastructure-level source/port policy; - creating a policy boundary separate from the application. ### Host firewall Linux UFW/nftables/iptables or Windows Defender Firewall can provide guest-level controls such as: - interface-specific policy; - local service exposure; - OS-managed rule automation; - application or host-specific restrictions supported by that firewall. Do not assume the two layers must contain identical rule syntax or features. Define the intended effective policy, then verify the combined result. ## Avoid firewall lockouts Firewall changes can remove your own administrative path. Before changing production access: 1. Confirm console or recovery access. 2. Identify the current admin source IP/network. 3. Add and verify the new allow path before removing the old one. 4. Keep an existing administrative session open during the change where appropriate. 5. Test from a second session. 6. Roll back immediately if the expected path fails. Do **not** disable the host firewall on a production system simply to test another layer unless you have an approved maintenance procedure and understand the exposure created by doing so. ## Verify the effective firewall policy Configuration is not evidence until the intended network path has been tested. Useful checks include: ```bash # Test a specific TCP port from an authorized client nc -zv server.example.com 443 # Scan selected expected ports from an external test system nmap -sV -p 22,80,443 server.example.com ``` A full port scan can also be useful when authorized and appropriate, but avoid scanning systems you do not own or have permission to test. Verify both positive and negative cases: - public HTTPS is reachable; - SSH works from the approved admin path; - SSH is not reachable from an unapproved source where restriction is intended; - database ports are not publicly reachable; - private application-to-database traffic works; - monitoring reaches only the intended endpoint. Test from the actual source networks. A localhost check does not prove public or private firewall behavior. ## Logging and monitoring make firewall policy operable Where supported, firewall logs can help answer: - Which rules are being hit? - What traffic is being denied? - Is a temporary rule still used? - Are repeated scans targeting an exposed service? - Did a deployment introduce a new outbound dependency? Do not enable unlimited verbose logging without a retention plan. High-volume deny logs can become expensive and noisy. Connect firewall review to your broader [Application Observability for Small Teams](/learn/guides/observability-small-teams-metrics-logs-traces) and monitoring process. ## Build a firewall rule lifecycle Treat network rules as maintained infrastructure: ```text REQUEST ↓ Identify service, source, port, owner ↓ REVIEW ↓ Confirm private/restricted path and least privilege ↓ APPLY ↓ VERIFY positive + negative cases ↓ MONITOR ↓ REVIEW / EXPIRE ↓ REMOVE when no longer required ``` A useful rule record contains: | Field | Example | |---|---| | Service | Production web | | Direction | Inbound | | Protocol/port | TCP 443 | | Source | Public | | Owner | Web platform | | Reason | Customer HTTPS | | Added | Change/ticket reference | | Review | Recurring or service retirement | The record can live in infrastructure-as-code, a change system, or another controlled source. The important part is that another engineer can understand the rule later. ## Firewall review checklist Review production policies regularly and after architecture changes. - [ ] Every public port maps to an active service. - [ ] SSH/RDP is restricted where practical. - [ ] Databases and caches are not unnecessarily public. - [ ] CIDR ranges are no broader than required. - [ ] Temporary/vendor rules have owners and expiry conditions. - [ ] Old environments and services no longer have rules. - [ ] IPv4 and IPv6 exposure are both reviewed where applicable. - [ ] Private-network rules still follow least privilege. - [ ] Outbound restrictions match current dependencies. - [ ] Positive and negative connectivity tests pass. - [ ] Recovery access is known before high-risk changes. ## How this applies on Raff For a Raff deployment, start with the architecture rather than assuming a particular firewall behavior. Use [Raff VM](/products/raff-vm) or [Windows VM](/products/windows-vm) for the workload, [Raff VPC](/products/vpc) for supported private resource-to-resource connectivity, and review the current [Raff Security](/products/security) surface for infrastructure security capabilities available to the resource you are deploying. A practical pattern is: ```text Internet ↓ only required public services Raff VM / Windows VM ↓ Raff VPC where applicable Private application, database, worker, or internal service ``` Inside the guest OS, keep the host firewall and service listeners aligned with the intended architecture. A service bound to every interface can still be a configuration risk even when another network layer currently blocks it. Use the live product pages for current firewall/security capabilities instead of relying on old assumptions about default open ports, rule statefulness, security-group features, or enforcement location. :::cta Explore Raff VPC Keep internal application and database traffic on controlled private paths, then expose only the services that genuinely need public reachability. ::: ## Conclusion Good cloud firewall policy is simple to describe: **allow the traffic the workload needs, restrict who can reach sensitive services, remove rules that no longer have an owner, and verify the effective policy from the real network path.** Inbound and outbound rules are only one layer. Combine them with private networking, strong administrative access, service authentication, patching, monitoring, and recovery. Most importantly, avoid universal assumptions about rule ordering, statefulness, default policies, or provider features. The safest firewall rule is one whose purpose, scope, implementation, and test result your team can explain. ## Sources - [Ubuntu Server documentation — Firewalls](https://documentation.ubuntu.com/server/how-to/security/firewalls/) - [NIST SP 800-41 Rev. 1 — Guidelines on Firewalls and Firewall Policy](https://csrc.nist.gov/pubs/sp/800/41/r1/final) - [Raff VPC](/products/vpc) - [Raff Security](/products/security) - Technical references reviewed: 2026-09-15 --- ### Windows VPS Hosting for Small Teams: Costs, Sizing, and RDP URL: https://rafftechnologies.com/learn/guides/windows-vps-hosting-small-teams Description: Compare Windows VPS hosting for RDP, Windows business software, IIS and SQL Server. Learn provider criteria, sizing, licensing, security, backups, and total cost. **Windows VPS hosting is a virtual server running Windows Server for workloads that need Remote Desktop, IIS, .NET, SQL Server, Windows-only business software, or Windows administration. For a small team, the right Windows VPS is not simply the cheapest server: it is one with enough resources for the real workload, a clear Microsoft licensing model, controlled RDP access, backups, and an operator who owns updates and recovery.** **Raff Technologies** provides Windows cloud VMs for teams that need a Windows Server environment without maintaining physical hardware. This guide explains when a Windows VPS makes sense, what to compare before buying, how to plan RDP and multi-user access, and how to size the server without relying on misleading one-size-fits-all specifications. If you are already ready to deploy rather than research the architecture, compare the current [Raff Windows VM](/products/windows-vm) options and [pricing](/pricing). ## Windows VPS hosting at a glance | Question | Practical answer | |---|---| | What is a Windows VPS? | A virtual server running Windows Server with allocated compute, storage, and networking | | Best fit | RDP, Windows business software, IIS/.NET, SQL Server, PowerShell, Windows services | | Main alternative | Linux VPS when the workload has no Windows dependency | | Most important sizing input | Actual application load and concurrent interactive users | | Biggest RDP mistake | Treating administrative RDP as an unlimited multi-user desktop service | | Biggest security mistake | Exposing RDP broadly without strong access controls | | Hidden cost to check | Windows/RDS licensing, backup storage, additional storage, and operator time | | Raff destination | [Windows VM](/products/windows-vm) | The buying decision should start with the workload. If your application runs cleanly on Linux, Windows can add unnecessary licensing and operational overhead. If the workload genuinely depends on Windows, using the correct operating environment is usually simpler than forcing a migration for infrastructure reasons alone. ## What is Windows VPS hosting? A **Windows VPS** or **Windows Server VPS** is a virtual machine that runs Microsoft Windows Server. The provider operates the underlying physical infrastructure while the customer administers the guest operating system and the software installed on it. Depending on the provider and plan, the VM has an allocation of CPU, RAM, storage, networking, and an IP address. The customer then configures Windows roles, applications, accounts, firewall policy, backups, and access. Common Windows VPS workloads include: - Remote Desktop administration; - Windows-only line-of-business software; - IIS and ASP.NET applications; - .NET Framework applications; - SQL Server workloads; - PowerShell automation; - Windows services and scheduled tasks; - development and testing environments; - internal tools that require a Windows desktop or API. The term **Windows cloud server** is often used for the same buying problem. The important distinction is not the marketing label; it is what level of virtualization, resource allocation, support, licensing, storage, and network control the service actually provides. ## Windows VPS vs Linux VPS Choose the operating system from application requirements, not familiarity. | Decision factor | Windows VPS | Linux VPS | |---|---|---| | Strong fit | Windows software, RDP, IIS, .NET Framework, SQL Server | Linux-native web stacks, containers, open-source services | | Common admin access | RDP, PowerShell, Windows admin tools | SSH and Linux administration tools | | OS licensing | Microsoft licensing must be accounted for | Many distributions have no OS license charge | | GUI | Native Windows desktop/admin experience | Usually command-line/server-first | | Resource overhead | Often needs more memory for GUI/interactive workloads | Often efficient for headless services | | Best decision rule | Workload requires Windows | Workload does not require Windows | If the application is a Node.js service, containerized API, Nginx workload, or other Linux-native stack, a [Linux VM](/products/linux-vm) may be the cleaner choice. If the application expects Windows Server, Windows APIs, IIS, a Windows desktop session, or vendor support tied to Windows, a Windows VPS is the appropriate starting point. ## Windows VPS vs Remote Desktop VPS **RDP VPS** and **Remote Desktop VPS** are common commercial search terms, but RDP is an access protocol—not a different type of server. A Windows VPS can provide Remote Desktop access. The important question is **what the RDP sessions are for**. ### Administrative RDP An administrator connects to configure the server, install software, troubleshoot, or perform maintenance. This is server administration. ### Multi-user Remote Desktop Services Employees use Windows sessions as their everyday workspace or to operate shared applications. This is a different deployment model and may require Remote Desktop Services roles and the appropriate licensing. Do not buy a server based only on the phrase “RDP VPS” and assume that any number of employees can use it simultaneously. Define the access model and licensing requirement first. ## Windows VPS vs a managed cloud desktop A managed cloud desktop and a Windows VPS can both present a Windows interface remotely, but the operating responsibility is different. | Option | Best fit | Responsibility | |---|---|---| | Windows VPS | Teams needing server-level control | Customer manages OS/application configuration | | Managed cloud desktop | Teams primarily buying user desktops | Provider abstracts more of the desktop platform | | Office PC | One local user/simple workload | Business owns device availability and remote access | | Local server | On-premises Windows workloads | Business owns hardware and operating environment | A Windows VPS is attractive when you need administrator control over installed software, server roles, networking, storage, and application configuration. If you only need managed desktops for employees, a purpose-built desktop service may remove work you do not want to own. ## When a small business should use a Windows VPS A Windows VPS for business is easiest to justify when four things are true: 1. The workload has a real Windows dependency. 2. It matters to daily operations or production. 3. Remote or centralized access creates business value. 4. Someone is responsible for updates, access, backups, and recovery. ### Windows business software Some accounting, ERP, CRM, tax, legal, manufacturing, trading, and other industry applications still depend on Windows desktop or server components. Moving the workload to a hosted Windows server can centralize the software and data instead of depending on one office computer. Before migrating, verify the software vendor's supported server versions, multi-user model, database requirements, and licensing terms. Do not assume that software running on a Windows laptop is automatically supported on Windows Server or in a multi-user RDS environment. ### IIS and .NET applications Windows Server remains a natural environment for IIS, ASP.NET, .NET Framework applications, Windows authentication, and other Microsoft-stack dependencies. For an IIS application, size for the application process, expected traffic, background work, and database behavior—not merely the operating system minimum. ### SQL Server workloads SQL Server can be far more sensitive to memory and storage behavior than a lightweight application server. Plan database memory, database size, log growth, backup windows, recovery requirements, and storage performance separately from Windows itself. For important production databases, the question may become whether to operate SQL Server yourself or use a managed database architecture where the application permits it. ### Windows automation and scheduled workloads PowerShell jobs, Windows services, automation tools, testing agents, and other background tasks can be good VPS workloads because they may need Windows compatibility without needing a physical desktop. The resource profile can be very different from an interactive RDP server. Measure the actual job rather than buying a large desktop-oriented configuration by default. ## How to choose a Windows VPS provider Commercial searches for **Windows VPS provider**, **Windows VPS hosting**, and **Windows server hosting** often lead to price tables. Price matters, but a useful comparison should answer more than “how much RAM do I get?” Evaluate: | Buying factor | What to verify | |---|---| | Windows versions | Which currently supported Windows Server versions are available? | | Licensing | Is the Windows license included, separate, or customer-supplied? | | RDS | How is multi-user Remote Desktop licensing handled? | | CPU/RAM | What resource model does the selected plan provide? | | Storage | Capacity, expansion options, and the storage model | | Backups | What is protected, retention options, and how restore works | | Networking | Public connectivity and supported private networking | | Access | Administrator access and recovery/console options | | Security | Network controls and the customer's security responsibilities | | Resizing | How can compute/storage be changed as usage grows? | | Support | What the provider will and will not troubleshoot | | Migration | Whether migration assistance is available and what it covers | A provider comparison is more useful when you calculate the **working system**, not only the advertised VM. Windows licensing, RDS, backups, storage growth, migration, and operator time can materially affect total cost. ## Windows VPS sizing: start with workload, not a generic chart There is no universal “5 users = X GB RAM” rule. Concurrent users can have radically different workloads. A person running one accounting application is not equivalent to a user running browsers, Office applications, reporting tools, and multiple line-of-business programs in the same RDP session. Use these inputs: - baseline Windows memory consumption; - application memory at normal and peak usage; - number of concurrent interactive users; - CPU-intensive application tasks; - database memory and I/O requirements; - system disk and data growth; - backup/import/export workloads; - antivirus/security tooling; - expected traffic for IIS applications; - operational headroom for updates and maintenance. ### Practical sizing method **Step 1: Measure or document the application.** If you are migrating, observe the current system. If it is new, use the software vendor's current requirements as the baseline. **Step 2: Separate interactive and background load.** RDP users, databases, web applications, and scheduled jobs consume resources differently. **Step 3: Add operational headroom.** A server should survive normal patching, backup, application update, and traffic periods without running at its limit. **Step 4: Monitor after deployment.** Watch sustained CPU, available memory, paging, disk latency/queue behavior, disk free space, and application-specific metrics. **Step 5: Resize from evidence.** Increase resources because measurements show pressure—not because an evergreen article claims every workload needs the same plan. This is more reliable than fixed app-name sizing tables that become stale as software versions and usage patterns change. ## Sizing an RDP VPS for multiple users For interactive Remote Desktop workloads, concurrent sessions are only the first input. Estimate: ```text Windows + security baseline + application/server services + concurrent user working sets + operational headroom = memory planning baseline ``` Then test representative sessions. Browsers can materially increase per-user memory use. Large spreadsheets, accounting reports, IDEs, design software, or several applications open at once can also change the profile. For CPU, look for simultaneous peak activity. Ten mostly idle sessions may require less CPU than three users simultaneously running heavy reports. For storage, separate capacity from performance. A server can have plenty of free disk space and still feel slow if the workload is storage-latency sensitive. ## Windows VPS cost: what should be included? A Windows VPS cost comparison should include the complete environment. | Cost component | Why it matters | |---|---| | VM plan | CPU, RAM, and included system storage | | Windows licensing | Required for the Windows Server environment according to the licensing model | | RDS licensing | Relevant to qualifying multi-user Remote Desktop deployments | | Additional storage | Databases, files, logs, and growth | | Backup/recovery | Retention and recovery requirements | | Migration | Data/application transfer and validation | | Operations | Patching, monitoring, access reviews, troubleshooting | Raff's current package and licensing prices can change independently of this evergreen guide, so use the live [pricing page](/pricing) rather than an embedded historical price. This also prevents a common SEO problem: optimizing for “cheap Windows VPS” by presenting a low headline number that does not represent the customer's actual Windows environment. ## Should you buy the cheapest Windows VPS? “Cheap Windows VPS” has strong commercial search demand, but **lowest advertised price is not the same as lowest working cost**. A low-cost plan can be rational for a small test server, automation task, or lightweight Windows workload. It becomes a poor value if the team loses hours to memory pressure, storage constraints, unclear licensing, weak recovery, or migration problems. Compare providers on: - the resource level your workload actually needs; - Windows and RDS licensing requirements; - storage expansion; - backup/recovery options; - support scope; - migration effort; - network/security capabilities. If two providers have different inclusions, comparing only the base VM price is not an apples-to-apples comparison. ## Windows Server licensing and RDP licensing are different decisions Windows Server licensing and Remote Desktop Services licensing should not be treated as the same thing. A server can be properly licensed for Windows Server while a multi-user Remote Desktop deployment has additional licensing requirements. For a small team, define: - which Windows Server edition/version the workload needs; - who provides the Windows Server license under the hosting arrangement; - whether RDP is only for server administration; - whether users will consume Remote Desktop Services sessions; - whether RDS licensing is per user or per device for the intended scenario; - whether other Microsoft server products introduce additional licensing requirements. **Raff is a Microsoft SPLA partner**, which provides a licensing route for eligible hosted Microsoft workloads on Raff infrastructure. The exact licensing configuration should still be confirmed for the customer's intended use before deployment. For current Microsoft product licensing questions, treat Microsoft documentation and the applicable service-provider licensing terms as the authority rather than relying on an old blog post. ## RDP security: do not make port 3389 your entire access strategy Internet-exposed RDP is a high-value target. A Windows VPS should not rely on “strong password + public RDP” as its complete security architecture. A practical baseline includes: - use Network Level Authentication where applicable; - keep Windows and exposed services patched; - use unique administrative accounts and least privilege; - avoid shared administrator credentials; - restrict inbound RDP reachability where practical; - use firewall/network controls intentionally; - consider VPN or other controlled administrative access patterns; - protect identity with MFA where the chosen access architecture supports it; - monitor failed logons and unusual access; - remove access promptly when users leave; - keep backups separate from the active server's normal failure domain. Use [Cloud Firewall Rules Explained](/learn/guides/cloud-firewall-rules-explained) for network-policy principles and [Cloud Security Fundamentals](/learn/guides/cloud-security-fundamentals) for the broader baseline. ## Public RDP, VPN, or private access? The right access model depends on who needs to connect and from where. | Model | Useful when | Trade-off | |---|---|---| | Restricted public RDP | Small admin group with stable trusted source networks | Simple, but still internet-facing | | VPN-controlled access | Users/admins can enter through a controlled network path | Additional access layer to operate | | Private service communication | App/database/internal services communicate without public exposure | Does not by itself solve remote-user identity/access | [Raff VPC](/products/vpc) can provide supported private connectivity between Raff resources. Private networking complements—not replaces—Windows firewall rules, authentication, and application permissions. ## Backups and recovery for Windows VPS hosting A Windows VPS becomes a business system when people depend on its files, applications, or database. At that point, backup design should be part of the purchase decision. Document: 1. What data must survive VM loss? 2. What is the recovery point objective? 3. How quickly must the service return? 4. Where are recoverable copies stored? 5. How are database/application-consistent backups handled? 6. Who receives backup failure alerts? 7. When was the last restore test? Snapshots can be useful around infrastructure changes, but they should not be confused with a complete application/data recovery strategy. Evaluate [Raff Data Protection](/products/data-protection) and [Volumes](/products/volumes) according to the workload's storage and recovery requirements. ## Migrating an office Windows workload to a VPS Most small-business Windows VPS projects begin with an existing machine. Before migration, inventory: - Windows/application versions; - application installers and license requirements; - databases and data directories; - users and permissions; - scheduled tasks and Windows services; - mapped drives and file shares; - firewall rules and listening ports; - integrations and external IP allowlists; - printers/peripherals that may depend on local access; - backup and rollback procedures. A safer migration sequence is: ```text Build target Windows VPS → install and patch prerequisites → install application → copy/test data → validate representative users/workflows → plan final sync/cutover → monitor → retire old environment only after validation ``` Do not make the first production login the first full test. For a broader migration framework, see [Cloud Migration Checklist for Small Teams](/learn/guides/cloud-migration-checklist-small-teams). ## Windows VPS for IIS and web applications For IIS hosting, the Windows VPS should be evaluated as an application server rather than a remote desktop. Focus on: - application pool memory and CPU behavior; - .NET/runtime requirements; - TLS and certificate management; - deployment and rollback; - application logs; - database connectivity; - backup of configuration and state; - monitoring response time and errors; - restricting administrative access separately from public web traffic. If the application is public, only the required web ports should need public reachability. SQL Server and administration interfaces should not be made public merely because the web application is public. ## Windows VPS for SQL Server For SQL Server, VM sizing must consider both Windows and the database engine. Key questions include: - database size and growth rate; - working-set memory; - peak query concurrency; - transaction log behavior; - backup frequency and duration; - restore-time requirements; - storage latency; - maintenance tasks; - SQL Server edition/licensing. Do not use an RDP-user sizing rule for a database server. The workload is different. ## What Raff offers for Windows VPS workloads Raff's commercial destination for this guide is the [Windows VM product page](/products/windows-vm). Use that page as the source for current available Windows versions, plan specifications, and pricing rather than copying volatile plan details into this guide. For a growing Windows environment, relevant Raff building blocks include: - [Windows VM](/products/windows-vm) for Windows compute; - [VPC](/products/vpc) for supported private connectivity; - [Volumes](/products/volumes) where attached block storage fits the workload; - [Data Protection](/products/data-protection) for supported recovery options; - [Pricing](/pricing) for current commercial details. This is deliberately a small set. A Windows VPS buyer should have a clear route from research to the product that solves the immediate problem rather than being sent through unrelated cloud services. :::cta Deploy a Windows VM Compare current Raff Windows VM options for RDP, IIS, Windows applications, and other supported Windows Server workloads. ::: ## Windows VPS buying checklist Before purchasing a Windows VPS, confirm: ### Workload - [ ] The software genuinely requires or benefits from Windows Server. - [ ] The application's supported Windows Server versions are known. - [ ] Concurrent users and peak workload are estimated. - [ ] Database/storage growth is understood. ### Licensing - [ ] Windows Server licensing model is confirmed. - [ ] RDP administration vs RDS user access is clearly separated. - [ ] RDS licensing is confirmed if required. - [ ] Application/SQL Server licensing has been checked separately. ### Security - [ ] Administrative access is restricted appropriately. - [ ] Shared administrator accounts are avoided. - [ ] Patch ownership is assigned. - [ ] Publicly exposed ports are intentional. ### Recovery - [ ] Important data is backed up. - [ ] Backup retention is defined. - [ ] Restore procedure is documented. - [ ] Recovery has been tested for important workloads. ### Provider - [ ] Current plan and licensing price are confirmed. - [ ] Storage growth path is understood. - [ ] Support scope is understood. - [ ] Migration responsibilities are clear. ## Conclusion A Windows VPS is the right infrastructure when the workload needs Windows—not merely because the buyer is familiar with a Windows desktop. Small businesses commonly use Windows VPS hosting for Remote Desktop, Windows business software, IIS/.NET, SQL Server, and automation, but each workload has a different sizing and licensing profile. For buyers comparing **Windows VPS hosting**, **Windows Server VPS**, **RDP VPS**, or **Windows server hosting**, prioritize the complete operating environment: workload fit, resources, licensing, access security, storage, backups, and support. That is a better decision than optimizing for the cheapest headline VM. Raff Technologies provides Windows cloud VMs for these workloads. If the requirements are clear, the next step is to compare the current [Windows VM](/products/windows-vm) configurations and [pricing](/pricing), then size from the application and real concurrent usage. ## Sources - [Microsoft Remote Desktop Services documentation](https://learn.microsoft.com/windows-server/remote/remote-desktop-services/) - [Microsoft Windows Server documentation](https://learn.microsoft.com/windows-server/) - [Microsoft SQL Server documentation](https://learn.microsoft.com/sql/sql-server/) - [Raff Windows VM](/products/windows-vm) - [Raff Pricing](/pricing) - Technical and product references reviewed: 2026-09-15 --- ### Windows Server Licensing for Hosted VMs: SPLA, BYOL & RDS URL: https://rafftechnologies.com/learn/guides/why-microsoft-licensing-matters-windows-vm-provide Description: Learn how Windows Server licensing affects hosted VMs, including SPLA, BYOL, RDS CALs, SQL Server, Standard vs Datacenter, and provider selection. **Microsoft licensing matters when choosing a Windows VM provider because a production Windows server is not only compute, RAM, storage, and RDP access. The buyer also needs a valid licensing path for Windows Server and, depending on the workload, may need separate rights for Remote Desktop Services, SQL Server, or other Microsoft software.** **Raff Technologies** provides Windows cloud VMs and is a Microsoft SPLA partner. For a small business or MSP, that makes licensing clarity part of the infrastructure decision: before production, you should know what the provider supplies, what is separate, who will access the server, and whether additional Microsoft products are involved. If you are evaluating a hosted Windows workload now, start with [Raff Windows VMs](/products/windows-vm) and use the live [pricing page](/pricing) for current commercial details. ## Windows Server licensing at a glance | Question | Practical answer | |---|---| | Is a Windows VM only a compute purchase? | No. Windows Server is licensed software. | | Does Windows Server licensing cover every Microsoft product? | No. RDS, SQL Server, Office/Microsoft 365 Apps, and other products can introduce separate requirements. | | Is RDP itself a separate server product? | No. But multi-user Remote Desktop Services is different from administrative RDP access. | | Can a hosting provider license Microsoft software? | Eligible service providers can use Microsoft's SPLA framework for eligible hosted software/services. | | Can a customer always bring an existing Windows license? | No. BYOL depends on the customer's license rights and deployment model. Verify eligibility rather than assuming portability. | | What should a buyer ask first? | What software is running, who uses it, how it is licensed, and who is responsible for each license. | This guide is a buyer-oriented explanation, not a substitute for Microsoft Product Terms or licensing advice for a specific contract. Microsoft licensing changes over time, so final entitlement questions should be checked against current Microsoft terms and the customer's agreements. ## Why Windows Server licensing belongs in the provider decision Two providers can advertise similar vCPU, RAM, storage, and monthly pricing while offering very different levels of licensing clarity. A useful Windows VM provider comparison therefore includes both infrastructure and software rights: - which Windows Server versions and editions are available; - how the hosted Windows Server license is supplied; - whether the quoted price includes the required Windows licensing for the offered service; - how multi-user Remote Desktop workloads are handled; - whether SQL Server or other Microsoft software is separate; - whether customer-owned licenses can be used in the intended environment; - who is responsible for confirming eligibility; - what happens when a test workload becomes a production business system. The important commercial question is not simply **“Does this provider offer Windows?”** It is **“Can this provider explain the licensing path for my actual workload?”** ## Windows Server 2025 licensing: what buyers should understand Microsoft's current Windows Server 2025 licensing guidance distinguishes Standard, Datacenter, and Essentials editions. Standard and Datacenter use a core-based licensing model. Microsoft also documents both physical-core licensing and, for eligible subscription licenses or licenses with active Software Assurance, licensing by virtual machine. For a customer buying a hosted Windows VM, you normally do not need to reproduce the provider's infrastructure-level licensing calculation yourself. But you should understand that Windows Server licensing is a real component of the service and should not be hidden behind vague language such as “Windows included.” Microsoft's current guidance also lists SPLA as an available channel for Windows Server 2025 Standard and Datacenter. That matters for hosted infrastructure because provider-supplied licensing and customer-owned licensing are different paths. ## What Microsoft SPLA means for hosted Windows workloads **SPLA** stands for **Services Provider License Agreement**. Microsoft describes it as a program for service providers and ISVs that license eligible Microsoft software to provide software services and hosted applications to end customers. For a customer, the practical value is that an eligible hosting provider can have a structured provider licensing path for applicable Microsoft workloads instead of asking every customer to solve hosted licensing independently. Raff is a Microsoft SPLA partner. That does **not** mean every Microsoft product or every customer scenario is automatically included with every Raff Windows VM. It means Raff has a provider licensing framework that can be used where applicable. The workload still matters. A Windows Server VM, an RDS environment, and a SQL Server deployment are not the same licensing decision. For a deeper SPLA-specific explanation, see [Microsoft SPLA Explained: Hosted Windows VMs](/learn/guides/microsoft-spla-hosted-windows-vms). ## Provider licensing vs BYOL There are two concepts buyers frequently encounter when moving Windows workloads into hosted infrastructure. ### Provider-supplied licensing The hosting provider supplies the applicable Microsoft licensing as part of, or alongside, the hosted service under its permitted licensing model. This can simplify procurement because the customer buys the hosted environment without independently transferring an existing license into it. ### Bring Your Own License (BYOL) The customer relies on rights attached to licenses it already owns or subscribes to. BYOL should never be interpreted as **“I own a Microsoft license, therefore I can use it on any cloud VM.”** Eligibility can depend on the product, agreement, subscription or Software Assurance status, outsourcing terms, and the hosting environment. Microsoft's current Windows Server guidance, for example, says the option to license Windows Server by virtual machine is available to customers with subscription licenses or licenses with active Software Assurance, subject to the applicable rules and minimums. For a buyer, the safe rule is simple: **verify BYOL eligibility before deployment rather than after the workload is in production.** ## Administrative RDP vs Remote Desktop Services One of the most important Windows VM licensing distinctions is the difference between administering a server remotely and using it as a multi-user desktop/application environment. | Scenario | Licensing question | |---|---| | Administrator connects to manage the server | Windows Server administrative access scenario | | Staff use hosted applications in remote sessions | Evaluate Remote Desktop Services requirements | | Multiple employees use the VM as their daily desktop | Treat as an RDS/user-access design, not merely “an RDP VPS” | | Contractors and employees connect from multiple devices | Decide whether the applicable RDS model should be user- or device-oriented | Microsoft supports **Per User** and **Per Device** RDS CAL models. RDS CAL version compatibility also matters: an older RDS CAL cannot be used to access a newer Windows Server session host. This is why “RDP included” is not enough information for a business planning a shared Windows environment. If RDP is central to your buying decision, read [Windows VPS Hosting for Small Teams](/learn/guides/windows-vps-hosting-small-teams). ## Windows Server CALs and RDS CALs are not the same thing A frequent source of confusion is treating all Client Access Licenses as interchangeable. Windows Server access rights and Remote Desktop Services access rights are separate concepts. An environment that requires RDS licensing does not become correctly licensed simply because the underlying Windows Server is licensed. The buyer should identify: 1. the Windows Server environment; 2. the users/devices accessing Windows Server services; 3. whether users are consuming Remote Desktop Services functionality; 4. any additional Microsoft server applications; 5. which party supplies each required license. For hosted environments, ask the provider how these layers apply to the service being offered rather than importing an on-premises assumption into the cloud. ## SQL Server is a separate licensing decision Installing SQL Server on a licensed Windows Server VM does not automatically license SQL Server. Before using SQL Server in production, clarify: - which SQL Server edition is required; - whether the application vendor bundles or requires a particular SQL license; - whether licensing is provider-supplied or customer-supplied; - whether the deployment model changes the licensing calculation; - whether the database should instead use a managed database architecture where the application supports it. This matters commercially because a Windows VM quote and a complete Microsoft application stack can have very different total costs. Do not compare Windows providers using only the VM's headline price if the actual workload also needs SQL Server licensing. ## Office and Microsoft 365 Apps require separate review A Windows Server VM is also not a blanket license for Office or Microsoft 365 Apps. If employees will run Office applications inside a hosted desktop or RDS environment, confirm the current Microsoft licensing and activation requirements for that scenario before deployment. This is especially important for small businesses migrating a familiar office PC workflow into the cloud. Software that was licensed appropriately on an employee laptop does not automatically carry identical rights into a shared hosted Windows Server environment. ## Windows Server Standard vs Datacenter: what matters for a hosted-VM buyer Microsoft positions Windows Server Standard for low-density or non-virtualized environments and Datacenter for highly virtualized/software-defined datacenter environments. When licensed by physical cores, current Microsoft guidance gives Standard rights for two OSEs under the documented conditions, while Datacenter provides unlimited virtualization rights on the fully licensed server. For an individual hosted-VM buyer, however, **do not choose a provider merely because its infrastructure licensing uses a particular edition**. Your buying questions are more practical: - Is the Windows Server edition/version offered suitable for my application? - Is the hosted licensing path valid for the service? - Are features my application depends on available? - Are RDS, SQL Server, or other licenses separate? - What does the complete environment cost? The provider is responsible for its provider-side licensing model. The customer is still responsible for understanding the applications, users, and customer-supplied licenses it introduces. ## Windows Server license cost: compare the complete workload Searches for **Windows Server license cost** often lead to retail or reference pricing. That is not always the right number for a hosted Windows VM decision. A hosted workload can include several cost layers: | Cost layer | Example | |---|---| | Compute | vCPU and RAM | | Windows Server | Hosted Windows licensing path | | Remote access | RDS licensing where required | | Database | SQL Server licensing where required | | Storage | System/data volumes and growth | | Recovery | Backup and retention requirements | | Operations | Patching, monitoring, migration, support | For Raff, use the current [pricing page](/pricing) rather than a hardcoded number in this evergreen licensing guide. That keeps the content useful even when plans or licensing prices change and prevents a buyer from mistaking an old article price for a current quote. ## Licensing questions to ask a Windows VM provider Before putting a Windows workload into production, ask: ### Windows Server - Which Windows Server version and edition will I run? - How is Windows Server licensed in this hosted service? - Is the applicable Windows licensing included in the quoted service or separate? ### Users and RDP - Is RDP only for administration or will employees use remote sessions daily? - If Remote Desktop Services is required, how are RDS licenses supplied? - Should the deployment use a Per User or Per Device model? ### Applications - Will the workload use SQL Server? - Will users run Office or Microsoft 365 Apps? - Does the third-party business application have its own hosted/RDS licensing rules? ### BYOL - Are we planning to use existing Microsoft licenses? - What exact license/subscription rights do we have? - Have we verified that those rights apply to this provider and deployment model? ### Responsibility - Which licenses does the provider supply? - Which licenses remain the customer's responsibility? - Who will confirm the final production configuration before cutover? A provider that can answer these questions clearly reduces procurement and migration uncertainty. ## Red flags when comparing Windows VM providers Treat these claims cautiously: - **“Windows is free.”** Windows Server is licensed software. - **“All Microsoft licenses are included.”** Different products and access models can require separate licensing. - **“Just bring any license key.”** A key is not the same thing as valid use rights. - **“Unlimited RDP users.”** Multi-user RDS requires more than simply enabling RDP. - **“SQL Server is covered because Windows is licensed.”** SQL Server is a separate product/licensing decision. - **A provider that cannot explain who owns licensing responsibility.** Ambiguity becomes the customer's operational risk later. Licensing clarity is therefore a useful commercial trust signal when comparing Windows infrastructure providers. ## How Raff approaches hosted Microsoft licensing Raff's goal is to make the Windows infrastructure decision clear before the workload becomes business-critical. For an eligible hosted workload, Raff's Microsoft SPLA relationship provides a provider licensing route where applicable. Customers should still tell us what they plan to run and how users will access it, because Windows Server, RDS, SQL Server, and customer-supplied Microsoft software can require different answers. The practical path is: ```text Define workload → choose Windows VM resources → identify Microsoft products → define users/access model → confirm licensing path → confirm current price → deploy and validate ``` For infrastructure, start with [Raff Windows VM](/products/windows-vm). For current commercial details, use [Raff Pricing](/pricing). For RDP-heavy workloads, use [Windows VPS Hosting for Small Teams](/learn/guides/windows-vps-hosting-small-teams). For the SPLA model itself, use [Microsoft SPLA Explained](/learn/guides/microsoft-spla-hosted-windows-vms). :::cta Explore Raff Windows VMs Compare Raff Windows VM options, then confirm the licensing and access model required for your production workload. ::: ## Windows VM licensing checklist Before production, confirm all of the following: - [ ] Windows Server version and edition are known. - [ ] Provider-supplied vs customer-supplied licensing is documented. - [ ] Administrative RDP and multi-user RDS are not being confused. - [ ] RDS licensing is confirmed where applicable. - [ ] SQL Server licensing is reviewed separately if installed. - [ ] Office/Microsoft 365 Apps licensing is reviewed separately if used. - [ ] BYOL eligibility is verified rather than assumed. - [ ] Third-party application licensing supports the hosted environment. - [ ] Current provider pricing has been checked. - [ ] Someone owns licensing validation before production cutover. ## Conclusion Microsoft licensing should be part of the Windows VM buying decision, not an afterthought. The infrastructure can be technically ready while the licensing model is still unclear. For small businesses and MSPs, the most important distinction is responsibility: know what the provider licenses, what the customer supplies, whether users need RDS, and whether SQL Server or other Microsoft software adds another licensing layer. Raff Technologies is a Microsoft SPLA partner and provides Windows cloud VMs for supported Windows Server workloads. If you are evaluating a production deployment, compare [Raff Windows VMs](/products/windows-vm), review [current pricing](/pricing), and confirm the licensing model for the actual software and users before cutover. ## Sources - [Microsoft Windows Server 2025 Licensing Guidance](https://www.microsoft.com/licensing/guidance/Windows-Server-2025) - [Microsoft Windows Server Licensing Resources](https://www.microsoft.com/en-us/licensing/product-licensing/windows-server) - [Microsoft Windows Server Virtualization Licensing Guidance](https://www.microsoft.com/licensing/guidance/Windows-Server-Virtualization-Technologies) - [Microsoft Services Provider License Agreement (SPLA)](https://www.microsoft.com/licensing/docs/view/Services-Provider-License-Agreement-SPLA) - [Microsoft Remote Desktop Services CAL guidance](https://learn.microsoft.com/en-us/windows-server/remote/remote-desktop-services/rds-client-access-license) - Technical/licensing references reviewed: 2026-09-15 --- ### Incident Response Plan for Small Teams: Triage, Containment, and Recovery URL: https://rafftechnologies.com/learn/guides/server-incident-response-small-teams-triage-containment-recovery Description: Build a practical incident response plan for a small team, with triage, evidence preservation, containment, recovery, communication, and a ready-to-use checklist. An **incident response plan** gives a small team a repeatable way to detect, declare, contain, recover from, and learn from security and reliability incidents. For a small team, the most useful plan is not the longest one: it makes the first decisions obvious—who owns the incident, what is affected, whether customer data or privileged access is at risk, what evidence must be preserved, and which recovery path is safe. For teams running production workloads on **Raff Technologies**, the same principle applies: prepare containment, clean replacement infrastructure, private connectivity, and recoverable data before an incident happens. The goal is to reduce decision time without turning every alert into an emergency. ## Incident response plan at a glance A practical incident response process can be organized into seven decisions: 1. **Detect and validate** — confirm that the signal represents a real operational or security problem. 2. **Declare and assign ownership** — name the incident owner and set an initial severity. 3. **Assess impact and scope** — identify affected users, systems, data, credentials, and dependencies. 4. **Preserve evidence** — retain the logs and state needed to understand what happened. 5. **Contain** — stop ongoing harm or spread without creating unnecessary damage. 6. **Recover and validate** — roll back, restore, rebuild, fail over, or otherwise return the service to a trusted state. 7. **Learn and improve** — document causes and assign concrete follow-up work. This structure aligns with current incident-response guidance that treats response as part of broader cybersecurity risk management, not as an isolated emergency document. ## What should an incident response plan include? Before an incident, your plan should answer these questions: - What conditions require an incident to be declared? - Who becomes the incident owner? - How do we classify severity? - Who can isolate a VM, revoke credentials, stop writes, or approve a restore? - Where are the logs and recovery points? - Which recovery path applies to each critical workload? - Who communicates with customers and partners? - Who evaluates contractual, privacy, insurance, or legal notification requirements? - Where can the plan be accessed if the normal production or collaboration systems are unavailable? For a small team, clarity matters more than a complex organizational chart. ## Define what counts as an incident Not every alert is an incident, and not every incident is a security breach. | Event | Typical handling | |---|---| | Brief CPU spike with no user impact | Operational investigation | | Failed deployment with visible errors | Reliability incident | | Customer-facing outage | Availability incident | | Suspected stolen SSH key or admin token | Security incident | | Unexpected database deletion or corruption | Data-integrity incident | | Malware, unauthorized process, or unexplained persistence | Security incident | | Backup job failure with no immediate outage | Recovery-readiness incident | | One noisy alert with no supporting evidence | Validate before escalation | Declare an incident when coordination, containment, recovery, customer communication, or evidence preservation is needed beyond routine troubleshooting. A useful conservative rule is to treat suspected compromise of privileged access, sensitive data, or an internet-facing production system as high priority until evidence narrows the risk. ## Triage by impact, scope, and confidence Severity should reflect business and technical risk rather than how alarming the first alert looks. ### Impact Ask: - Are customers unable to use a critical function? - Is sensitive or regulated data involved? - Are transactions, writes, or files being lost or corrupted? - Is revenue or business continuity affected? ### Scope Determine whether the incident affects: - one process or one VM - one service or several dependencies - one user or many customers - one credential or a shared identity path - a single network segment or multiple systems ### Confidence Separate what is confirmed from what is suspected: - Is the incident confirmed or still an unverified signal? - Is the cause known? - Are the timestamps and logs reliable? - Is there evidence that the problem is spreading? A simple severity model can work well: | Severity | Example | Response posture | |---|---|---| | Critical | Confirmed privileged compromise, active data destruction, major multi-service outage | Immediate ownership, containment, and business decision path | | High | Customer-facing outage, suspected compromise, serious corruption | Rapid coordination and frequent updates | | Medium | Degraded service, failed deployment, contained access issue | Assigned owner and structured remediation | | Low | No user impact, isolated warning, weak signal | Validate and handle during normal operations | Severity can change as evidence improves. Record why it changed. ## Assign incident-response roles before you need them Small teams may not have separate security, operations, support, and communications departments. The responsibilities still need owners. | Role | Responsibility | |---|---| | Incident owner | Sets priority, approves major actions, and keeps the next decision clear | | Technical lead | Investigates scope and proposes containment and recovery | | Communications owner | Manages internal, customer, partner, or leadership updates | | Scribe | Records timestamps, evidence, hypotheses, actions, and outcomes | | Business owner | Confirms customer impact and recovery priorities | One person can hold several roles. What matters is knowing who has authority to isolate a server, rotate credentials, stop writes, restore data, or communicate externally. ## First 15 minutes: an incident response checklist The first minutes should create control, not force a premature root-cause diagnosis. ### 1. Confirm the signal Use more than one useful source when possible: - monitoring and health checks - application and infrastructure logs - customer reports - deployment history - authentication events - database or storage behavior - network or access-control changes ### 2. Assign an owner and initial severity Record: - earliest known signal - affected workload - current customer impact - suspected security or data risk - incident owner - next update time ### 3. Pause unrelated changes Stop deployments, migrations, cleanup jobs, and configuration changes that could destroy evidence or add new variables. ### 4. Choose the immediate objective Usually this is one of the following: - stop ongoing harm - restore critical availability - preserve data integrity - protect credentials - prevent spread - verify whether the signal is real ### 5. Start one incident timeline Record decisions as they happen rather than reconstructing them later. ## Preserve evidence before destructive actions Evidence helps determine scope, root cause, customer impact, and whether a recovered environment can be trusted. Useful evidence may include: - application, system, authentication, and network logs - process lists and listening ports - active network connections - deployment and configuration history - cloud activity records - affected files and timestamps - database logs and transaction history - suspicious accounts, SSH keys, tokens, or scheduled tasks - monitoring graphs - snapshots or disk copies when appropriate Do not assume a snapshot is clean. A snapshot can preserve compromised or corrupted state; its purpose may be evidence or later analysis rather than direct production restoration. Avoid rebooting, deleting processes, wiping a server, or rotating every credential before considering what evidence will disappear. If continued operation creates greater harm, containment takes priority—document what could not be preserved. ## Containment: stop harm without confusing it with recovery Containment reduces ongoing damage or spread while the team prepares a trusted recovery path. | Containment action | Appropriate when | Main risk | |---|---|---| | Restrict exposed network paths | Public exposure is unnecessary or suspicious | May block users or integrations | | Isolate a VM | Compromise or lateral movement is possible | Immediate service interruption | | Disable an account or key | One identity is suspected | Hidden dependencies may fail | | Rotate credentials | A secret may be exposed | Automation and services may break | | Stop application writes | Corruption or destructive changes continue | Availability becomes limited | | Remove an unhealthy backend | One instance is failing | Remaining capacity may be insufficient | | Roll back a deployment | A recent release is likely responsible | Database or schema changes may be incompatible | | Shut down a service | Continued operation creates greater harm | Full outage | Containment and recovery are different decisions. Restricting a route may stop harm but not restore a trusted service. Restarting a process may restore availability without removing the cause. For administrative exposure decisions, see [Private vs Public Admin Access](/learn/guides/private-vs-public-admin-access). For network-rule design, see [Cloud Firewall Best Practices](/learn/guides/firewall-best-practices-cloud-servers). ## Choose the right recovery path Recovery depends on what failed and whether the existing environment can still be trusted. | Incident | Likely recovery choice | |---|---| | Bad application release | Roll back or fix forward | | Failed OS or package update | Roll back or rebuild from a known baseline | | Resource exhaustion | Reduce load, resize, scale, or optimize | | Database corruption | Stop harmful writes and restore to an approved recovery point | | Deleted files | Restore selected files or data | | Compromised credential | Revoke, rotate, review scope, and validate affected systems | | Suspected VM compromise | Rebuild from a trusted baseline and restore verified data | | Infrastructure loss | Recreate infrastructure and restore retained data | | Network misconfiguration | Restore known-good rules and validate allowed and denied paths | ### Roll back Use rollback when a recent controlled change is the likely cause and the previous version remains compatible with current data and configuration. ### Restore Use restore when data or system state must return to a known recovery point. Confirm the recovery point, expected data-loss window, and restoration time before proceeding. ### Rebuild Prefer rebuild when the server cannot be trusted, its state is poorly understood, or repair would leave uncertainty about persistence, credentials, or hidden changes. ### Fail over Use failover only when the secondary path has been tested and data consistency is understood. An untested standby is not a reliable incident-response strategy. For preparation, read [Cloud Server Backup Strategy](/learn/guides/cloud-server-backup-strategies) and [High Availability vs Disaster Recovery](/learn/guides/high-availability-vs-disaster-recovery-small-teams). ## Validate recovery before declaring the incident resolved A VM responding to ping does not mean the service is recovered. Validate the functions that customers and operators actually depend on: - authentication and authorization - critical application workflows - database reads and writes - queues and background jobs - integrations and webhooks - file and object access - DNS, TLS, and routing - monitoring and alerting - backup jobs - administrator access - security indicators related to the incident After recovery, use a defined observation or warranty period. Continue watching the original failure signal, customer impact, resource behavior, and suspicious activity before closing the incident. ## Communication: facts, impact, action, next update Internal updates should answer: - What is affected? - What is the current impact? - What is confirmed? - What remains a hypothesis? - What action is happening now? - Who owns the next decision? - When is the next update? Customer communication should avoid unsupported root-cause claims. State observed impact, current mitigation, available workarounds, and when the next update is expected. Do not wait for perfect certainty before acknowledging a customer-visible outage. At the same time, do not declare a security breach, data loss, or root cause without evidence and the appropriate business or legal review. Notification obligations vary by jurisdiction, contract, data type, and customer relationship. Your plan should identify who evaluates those obligations rather than expecting engineers to improvise legal decisions during an incident. ## Keep one reliable incident timeline The timeline should record: - timestamp - observation or evidence - action taken - person responsible - reason for the decision - result - next step Separate facts from hypotheses. | Time | Example record | |---|---| | 14:05 | Monitoring detects elevated API errors | | 14:08 | Incident declared; customer login affected | | 14:11 | Recent deployment identified as leading hypothesis | | 14:16 | New deployments paused; rollback approved | | 14:24 | Error rate returns to baseline | | 14:31 | Login and billing workflows validated | A clear timeline supports handoffs, customer updates, post-incident review, and evidence preservation. ## Build an incident response playbook before the outage An incident response plan defines the decision framework. A playbook makes common scenarios executable. Prepare: - workload inventory and business owners - severity definitions - incident roles and contact methods - an out-of-band communication path - administrator and emergency access - log locations and retention expectations - known containment actions - rollback, restore, and rebuild procedures - backup ownership and restore tests - customer communication templates - vendor and support contacts - decision path for privacy, legal, insurance, or contractual review Store the plan somewhere accessible if the production environment, identity provider, documentation system, or primary chat platform is unavailable. Exercise scenarios such as: - compromised SSH or administrator credentials - failed database migration - destructive file encryption - expired TLS certificate - accidental network lockout - deleted production data - failed deployment outside normal hours The exercise should test access, decisions, contacts, and recovery—not merely confirm that a document exists. ## Post-incident review: turn lessons into owned work A useful review answers: 1. What happened? 2. When did impact begin and end? 3. How was it detected? 4. What increased or reduced the impact? 5. Which containment and recovery actions worked? 6. Which assumptions were wrong? 7. What should change? Follow-up work should have owners and due dates. Examples include: - restrict unnecessary public administration - improve alert quality - increase useful log retention - add deployment rollback checks - test database restoration - remove stale credentials - separate application and database recovery - add a customer communication template - document emergency access A post-incident review that ends with “be more careful” has not improved the system. ## Incident response examples by scenario | Scenario | First priority | Recovery bias | |---|---|---| | Failed deployment | Stop further changes and validate rollback | Roll back or fix forward | | Availability outage | Restore critical service safely | Restart, reroute, resize, or restore | | Credential compromise | Revoke access and determine scope | Rotate, validate, and rebuild where trust is lost | | Suspected malware | Isolate and preserve evidence | Clean rebuild and verified data restore | | Database corruption | Stop harmful writes | Approved backup or point-in-time recovery where available | | Data deletion | Prevent further deletion | Granular or full restore | | Traffic flood or DDoS | Protect availability and origin systems | Filter, rate-limit, reroute, or scale according to available controls | | Configuration error | Restore known-good state | Revert and validate dependencies | ## How Raff can support incident-response readiness Raff is infrastructure, not a substitute for your incident-response process. But designing the workload around recoverability can make response easier. Depending on the architecture, teams can use: - [Cloud VMs](/products/raff-vm) for production workloads or clean replacement instances - [VPC](/products/vpc) to keep service-to-service traffic on private network paths where appropriate - [Data Protection](/products/data-protection) for supported backup and recovery workflows - [Volumes](/products/volumes) for persistent block storage - [Object Storage](/products/object-storage) for S3-compatible object storage and suitable retained data A practical cloud incident workflow may isolate an affected workload, preserve the evidence that matters, deploy a clean replacement VM, restore verified data, validate the application, and retire the affected environment deliberately. Before an incident, verify the exact recovery behavior, network design, access controls, backup coverage, and operational steps your workload depends on. Do not discover your recovery assumptions during the outage. :::cta Deploy a Raff VM Build a recoverable cloud workload with clear compute, private networking, storage, and data-protection options. ::: ## Incident response checklist ### Declare and coordinate - Incident owner assigned - Severity and affected workload recorded - Customer, data, and privileged-access risk assessed - Next update time set - Unrelated changes paused ### Investigate and preserve - Signal confirmed with available evidence - Timeline started - Relevant logs and state preserved - Facts separated from hypotheses - Scope and spread assessed ### Contain - Immediate objective selected - Access, traffic, writes, or affected systems restricted as needed - Credential actions coordinated with dependencies - Evidence impact documented ### Recover - Rollback, restore, rebuild, failover, or scaling path selected - Recovery point and expected data loss confirmed - Critical workflows validated - Monitoring and backups verified - Observation period started ### Close and improve - Customer and internal updates completed - Timeline finalized - Root and contributing causes documented - Improvement actions assigned - Temporary rules, accounts, and resources removed :::cluster ## Conclusion A small-team **incident response plan** should shorten the time between a signal and a controlled decision. Define declaration criteria and ownership before an incident, triage by impact and scope, preserve useful evidence, contain the specific risk, and choose a recovery path that returns the workload to a trusted state. The strongest plans are operational: the team knows where the logs are, who can make emergency changes, how recovery is performed, and how customer communication works. Test those assumptions before production depends on them. ## Sources - [NIST SP 800-61 Rev. 3: Incident Response Recommendations](https://csrc.nist.gov/pubs/sp/800/61/r3/final) - [NIST Cybersecurity Framework 2.0](https://www.nist.gov/cyberframework) - [CISA Incident and Vulnerability Response Playbooks](https://www.cisa.gov/news-events/news/incident-and-vulnerability-response-playbooks) - [Raff VPC](/products/vpc) - [Raff Data Protection](/products/data-protection) --- ### Container Images vs VM Images: What Developers Should Know URL: https://rafftechnologies.com/learn/guides/container-images-vs-vm-images-deployment Description: Compare container images vs VM images for deployment, security, updates, rollback, portability, and small-team infrastructure decisions. **Container images package an application and its user-space dependencies; VM images package an operating-system-level machine baseline.** Use a container image when you want to version and move the application independently. Use a VM image when the server itself—OS, packages, agents, configuration, and machine-level controls—needs to be recreated consistently. Many production systems use both. For developers deploying on **Raff Technologies**, this distinction is useful before choosing a Linux VM, Windows VM, Docker-based deployment, or a more automated provisioning model. The artifact you standardize determines what you can rebuild quickly, what you must patch, and what a rollback actually restores. ## Container image vs VM image at a glance | Question | Container image | VM image | |---|---|---| | What does it standardize? | Application and user-space dependencies | Machine/OS baseline | | Typical unit of deployment | Service or process | Virtual machine | | Best when | App releases change frequently | OS/server configuration must stay consistent | | Usually smaller/faster to replace | Yes | No, relative to a container image | | Includes a guest OS kernel | No; containers share the host kernel | The VM boots its own guest OS/kernel | | Good for app portability | Strong | More environment/provider dependent | | Good for server baselines | Limited | Strong | | Replaces backups? | No | No | The key idea is **application artifact versus machine artifact**. That is different from the broader “containers vs virtual machines” runtime question. ## Container images are application artifacts The Open Container Initiative (OCI) Image Specification defines a container image around a manifest, configuration, and filesystem layers. An image is used to create a container runtime filesystem and configuration; it is not a complete virtual machine. A typical container image can capture: - application code; - language/runtime dependencies; - libraries and user-space packages; - filesystem layers; - startup command and metadata. It normally does **not** package the host kernel, physical/virtual networking design, external database, persistent volumes, host firewall, or your complete backup strategy. This makes container images a strong fit when the application changes more frequently than the infrastructure beneath it. ## VM images are machine artifacts A VM image is used to create or recreate a virtual machine from a known machine or disk baseline. Depending on the platform and image format, that baseline can include the operating system, installed packages, system configuration, agents, runtimes, and other disk state. A VM image is useful when the machine is the thing you need to standardize: - a hardened Linux baseline; - a Windows Server environment; - a server with required system packages or agents; - a legacy workload with machine-level dependencies; - a repeatable base for a fleet of similar VMs. Do not confuse a VM image with a backup. A reusable image is primarily a provisioning artifact. Recovery of production data needs its own snapshot/backup design. ## Container images vs virtual machines: avoid the common comparison mistake A **container** and a **virtual machine** are runtime environments. A **container image** and a **VM image** are artifacts used to create those environments. | Comparison | What is being compared? | |---|---| | Container vs virtual machine | Runtime/isolation model | | Container image vs VM image | Deployment/provisioning artifact | | Docker image vs VM image | Application artifact vs machine artifact | If your decision is about runtime isolation, density, kernel boundaries, or whether to run containers at all, see [Docker vs Virtual Machines](/learn/guides/docker-vs-virtual-machines-when-to-use). If you already know the runtime and are deciding what to build, store, version, and deploy, continue here. ## When to use a container image Choose container images when the application should have its own release lifecycle. They are especially useful when: - application releases are frequent; - services use different language/runtime dependencies; - CI/CD should produce a versioned deployable artifact; - the same application should move between development, staging, and production; - you want to run several services with Docker Compose; - Kubernetes may become useful later; - application rollback should not require replacing the whole server. For example, a small SaaS team can keep a relatively stable Linux VM while shipping a new application image several times per week. The application release and host maintenance schedules remain separate. ### What container images do not solve Containerization does not remove infrastructure responsibility. You still need to plan: - host patching; - firewall and network exposure; - secrets; - persistent storage; - database durability; - monitoring; - backups; - image provenance and vulnerability management. A repeatable application image is valuable precisely because these other responsibilities can be treated as separate layers. ## When to use a VM image Choose a VM image when repeatable machine state matters more than independent application packaging. Common cases include: - standardized server baselines; - Windows workloads where the OS environment is central to the application; - legacy software with machine-level dependencies; - preconfigured infrastructure agents; - fleets that need the same operating-system starting point; - environments where booting from a known baseline is preferable to repeating a long manual setup. A VM image becomes less attractive as the application release cadence accelerates. Rebuilding a complete machine artifact for every small application change couples two lifecycles that often should remain separate. ## Container image, VM image, or both? For many small teams, the hybrid model is the cleanest answer. | Layer | Practical artifact/control | |---|---| | VM/OS baseline | VM image or provisioning automation | | Application | Container image | | Service coordination | Docker Compose, systemd, Kubernetes, or deployment tooling | | Runtime configuration | Environment/configuration and secrets management | | Persistent data | Volumes/database/storage | | Recovery | Snapshots and backups | The VM gives the team a known infrastructure boundary. Container images give individual applications a versioned release artifact. A typical small-team pattern is: 1. provision a Linux VM; 2. harden and configure the host reproducibly; 3. deploy one or more versioned container images; 4. keep application data outside ephemeral container filesystems; 5. back up the persistent data independently; 6. rebuild rather than manually mutate containers when the application changes. This avoids forcing every infrastructure concern into Docker while also avoiding full-server rebuilds for every code release. ## Docker image vs VM image A Docker image is a container image used by Docker’s container workflow. The important architectural difference remains the same: the Docker image describes application/user-space filesystem and configuration, while a VM image describes a machine-level environment. Use a Docker image when you want a deployable application artifact that can run on a suitable Docker host. Use a VM image when you want a repeatable virtual-machine baseline. A Docker image is therefore **not a lightweight VM image**. Containers and VMs use different isolation models, and container images should not be treated as compressed virtual machines. ## How updates differ The fastest-changing layer should usually have the smaller, independently versioned artifact. | Change | Usually better handled with | |---|---| | Application code release | Container image | | One service's runtime dependency | Container image | | Container base-image security update | Rebuilt container image | | Host OS baseline | VM image/provisioning automation | | Machine-wide agent/configuration | VM baseline/configuration management | | Windows Server baseline | VM image/provisioning workflow | | Persistent database contents | Backup/data recovery process | This separation improves operational clarity. A bad application release should not require you to reason about an unrelated OS image change, and an OS security refresh should not depend on a new application version. ## Rollback and recovery are not the same thing Images can help you return software to a known version, but they do not automatically recover production state. A container rollback can redeploy a previous application image. That does not undo an incompatible database migration or restore deleted customer data. A VM image can recreate a known server baseline. That does not necessarily restore the latest application data. Use different mechanisms for different recovery jobs: | Need | Appropriate mechanism | |---|---| | Roll back app binary/dependencies | Previous container image | | Recreate trusted server baseline | VM image/provisioning | | Quickly revert machine disk state | Snapshot, where appropriate | | Recover important persistent data | Tested backup/restore process | On Raff, [Data Protection](/products/data-protection) should be evaluated separately from the image strategy. If persistent application data is stored on [Volumes](/products/volumes), include those volumes in the recovery design rather than assuming the application image protects them. ## Security: what belongs in each image Both image types can reproduce vulnerabilities as efficiently as they reproduce good configuration. The goal is not merely to create an image—it is to create a rebuildable, reviewable artifact. ### Container image security Focus on: - trusted/minimal base images where practical; - dependency and image vulnerability scanning; - rebuilding when the base or dependencies change; - avoiding secrets in image layers; - immutable/versioned references for production releases; - registry access control and image provenance; - running with the least runtime privilege the application needs. Docker recommends rebuilding images regularly to pick up updated dependencies and using small, trusted base images where appropriate. ### VM image security Focus on: - OS patch level; - user/admin accounts; - SSH/RDP configuration; - machine-level agents; - default network exposure; - secrets or credentials accidentally captured on disk; - stale packages; - a documented process to refresh and retire old images. A “golden image” is useful only while it remains a trusted baseline. An old golden image can become a repeatable way to deploy old vulnerabilities. ## Portability vs reproducibility Container images can improve application portability, but an image alone does not reproduce an entire production system. A containerized service can still depend on: - environment variables and secrets; - DNS; - external databases; - queues; - mounted storage; - network policy; - cloud services; - CPU architecture and host/runtime compatibility. A VM image captures more of the machine environment, but it may be less portable across platforms and image formats. Ask a more precise question than “is this portable?” Ask: **which layer can I recreate from this artifact, and which dependencies remain external?** ## Image size, build speed, and deployment speed Container images are generally designed around layered application filesystems and can often be distributed and replaced more efficiently than full machine images. But image size alone is not the business objective. A small image that takes 20 minutes to become healthy because it depends on slow migrations is not a fast deployment. A larger VM image that boots into a fully prepared machine can be appropriate when the server baseline is the product of the deployment. Measure the workflow that matters: - build time; - transfer/pull time; - boot/start time; - health-check time; - rollback time; - time to rebuild after a security update. Optimize the end-to-end recovery and release process rather than chasing the smallest artifact. ## Image sprawl is an operational cost Both container and VM images become liabilities when nobody knows which versions are safe to use. Set basic ownership rules: - production images have an owner; - versions are identifiable and immutable where practical; - build source is known; - stale images are retired; - supported base versions are documented; - security refreshes trigger rebuilds; - teams can reproduce an image instead of manually editing it after creation. Avoid relying on ambiguous tags such as `latest` as the only production identifier. A rollback is much easier when the exact artifact is known. ## Which image strategy fits a small team? | Team/workload | Practical default | |---|---| | One simple app on one VM | Standard VM deployment or container image on a VM | | Several services on one VM | Container images + Docker Compose | | Frequent application releases | Container images | | Several machines needing same baseline | VM image or provisioning automation | | Windows business/legacy software | Windows VM baseline; containerize only where the app supports it | | Kubernetes workload | Container images | | Legacy machine with difficult dependencies | VM image can simplify initial reproduction; modernize deliberately | | Persistent database | Treat data protection separately from both image types | Small teams should optimize for **maintainable repeatability**, not maximum tooling. A complex image factory that nobody owns is worse than a simple documented deployment that the team can reliably rebuild. ## Choosing infrastructure for container-based deployment Once you decide to use container images, the next purchase decision is the host environment. For a small deployment, evaluate a cloud VM on: - CPU and memory fit for the application; - persistent storage requirements; - private networking for internal services; - backup/recovery options; - bandwidth model; - administrative access; - ability to scale to multiple VMs or Kubernetes if the workload grows; - support when infrastructure issues block deployment. Raff [Linux VMs](/products/linux-vm) can host Docker and Docker Compose workloads with root-level server control. Teams that outgrow single-host coordination can evaluate [Managed Kubernetes](/products/kubernetes) rather than treating Kubernetes as the default starting point. :::cta Deploy a Linux VM Run containerized applications on a Raff Linux VM and keep the application artifact separate from the server and data layers. ::: ## Choosing infrastructure for VM-image-driven workloads VM-image-driven workloads often care more about operating-system control and machine consistency. Evaluate: - supported operating systems; - administrative/root access; - provisioning and image/template workflow; - storage and snapshot options; - private networking; - recovery process; - licensing requirements for commercial operating systems/software; - how machine baselines will be patched and refreshed. For Windows workloads, review [Raff Windows VMs](/products/windows-vm) and plan application licensing separately from the VM artifact. For Linux workloads, compare the live [Linux VM](/products/linux-vm) options and current [pricing](/pricing) rather than relying on hard-coded plan values in an architecture guide. ## Container image vs VM image decision checklist Choose **container images** if most of these are true: - the application changes more frequently than the host; - CI/CD should produce a deployable artifact; - services need independent dependencies; - Docker Compose or Kubernetes is part of the deployment model; - application rollback should be independent of host replacement. Choose **VM images** if most of these are true: - OS configuration is a major part of the workload; - you need repeatable machine baselines; - server-level agents/packages must be preconfigured; - the workload is legacy or tightly coupled to machine state; - recreating a complete server is more important than moving one app independently. Choose **both** if you want a controlled VM baseline with independently released containerized applications on top. ## Conclusion Container images and VM images solve different deployment problems. A container image is primarily an application artifact. A VM image is primarily a machine artifact. Neither replaces backups, networking, secrets management, monitoring, or a tested recovery plan. For many small teams, the clean architecture is a stable VM layer, versioned container images for frequently changing services, and persistent data protected independently. That model keeps application releases, machine maintenance, and recovery from becoming one coupled process. ## Sources - [Open Container Initiative — Image Specification](https://specs.opencontainers.org/image-spec/) - [Docker — Building best practices](https://docs.docker.com/build/building/best-practices/) - [Docker — What is an image?](https://docs.docker.com/get-started/docker-concepts/the-basics/what-is-an-image/) - [Google Cloud — Create custom images](https://cloud.google.com/compute/docs/images/create-custom) - [Raff Linux VMs](/products/linux-vm) - [Raff Windows VMs](/products/windows-vm) --- ### WebSocket Hosting Explained: Persistent Connections, Scaling, and Cost URL: https://rafftechnologies.com/learn/guides/websocket-hosting-persistent-connections-scaling-cost Description: Plan WebSocket hosting for real-time apps. Compare one-VM and multi-node designs, size persistent connections, handle load balancing, reliability, security, and cost. WebSocket hosting means running a server that can keep long-lived, two-way connections open with browsers, mobile clients, or other applications. For an early real-time product, **one well-sized cloud VM is often the simplest place to start**. The infrastructure becomes more complex when concurrent connections, message fan-out, availability requirements, or deployment risk force the application across multiple nodes. For teams evaluating **WebSocket hosting** rather than only learning the protocol, the important questions are practical: how many connections must stay open, how much data moves through them, what happens when a server restarts, and how will the architecture scale without making the product unnecessarily expensive? Raff Technologies provides cloud VMs and supporting infrastructure that let teams run and control this stack directly, from a single WebSocket server to a multi-node deployment. This guide explains those decisions without assuming that every real-time application needs Kubernetes, a managed real-time service, or a distributed architecture on day one. ## What Is WebSocket Hosting? A WebSocket server maintains persistent communication sessions instead of treating every interaction as a separate request-response cycle. The protocol begins with an HTTP handshake and then upgrades the connection so client and server can exchange messages in both directions over the same connection. That makes WebSockets useful for workloads such as chat, collaborative applications, multiplayer features, live dashboards, notifications, and streaming application state. The protocol itself is standardized in [RFC 6455](https://www.rfc-editor.org/rfc/rfc6455.html), while the browser-facing API is documented by [MDN](https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API). The hosting difference is operational. A conventional web server may handle a large number of short requests. A WebSocket server can have thousands of clients connected while relatively few messages are moving. Capacity therefore depends on more than requests per second. | Metric | Why it matters | |---|---| | Concurrent connections | Each live connection consumes some memory, socket/file-descriptor capacity, and network state | | Messages per second | Drives application CPU and serialization work | | Payload size | Affects bandwidth, memory, and serialization cost | | Fan-out | One event sent to many clients can multiply work quickly | | Connection duration | Long sessions change deployment and failure behavior | | Reconnect rate | A restart or network problem can create a sudden connection spike | | Message latency | Real-time products become visibly degraded when delivery slows | A useful capacity model is therefore **connections × activity per connection**, not simply monthly visitors. ## WebSockets vs SSE vs Polling Do not choose WebSockets merely because the product is described as “real time.” Choose the simplest communication model that satisfies the interaction. | Model | Good fit | Main trade-off | |---|---|---| | HTTP polling | Infrequent status checks and simple clients | Repeated requests add overhead when updates are frequent | | Long polling | Compatibility-oriented applications with occasional updates | More request churn than a persistent connection | | Server-Sent Events (SSE) | Primarily server-to-browser streams | Browser communication is one-way from server to client | | WebSockets | Frequent bidirectional communication | Persistent connections require more operational planning | If a dashboard only receives server updates, SSE may be sufficient. If a browser and server need to exchange frequent messages in both directions, WebSockets are usually the more natural model. If updates occur every few minutes, ordinary polling may be easier to operate. This decision matters commercially too: unnecessary infrastructure is still infrastructure your team has to monitor, secure, deploy, and pay for. ## When Should You Host a WebSocket Server on a Cloud VM? A cloud VM is a strong fit when you want control over the WebSocket process, reverse proxy, runtime, network configuration, and scaling path without building around the restrictions of a platform that may impose connection-duration or protocol limitations. Common fits include: - SaaS applications adding chat, presence, live status, or collaboration. - Internal dashboards with continuously changing data. - Node.js, Go, Python, Java, Elixir, or other persistent application servers. - Docker-based real-time services. - Teams that want to start with one server and add infrastructure only when measured load requires it. A VM is less attractive when the team explicitly wants a fully managed real-time messaging product and does not want to operate the connection layer. That can reduce operational work, although the application then needs to fit the provider's pricing, limits, APIs, and architecture. The hosting decision is therefore not “VMs are always better.” It is **control and predictable infrastructure ownership versus outsourcing more of the real-time layer**. ## How to Size a WebSocket Server There is no reliable universal formula such as “1 GB RAM supports X WebSocket users.” Framework, runtime, TLS, authentication state, message buffers, application code, operating system limits, and traffic patterns all affect the result. Start with four workload measurements: 1. **Peak concurrent connections.** Measure simultaneous connected clients, not registered users. 2. **Average and peak message rate.** Include inbound and outbound messages. 3. **Typical and maximum payload size.** Small JSON events and large streamed payloads create very different network profiles. 4. **Fan-out ratio.** A message delivered to one client is different from one broadcast to 10,000 clients. Then load-test the actual application and observe CPU, memory, connection count, network throughput, event-loop or worker latency, and error rates. Keep headroom for traffic spikes and reconnect storms rather than planning to run permanently at the observed failure boundary. For a first deployment, [Raff Linux VMs](https://rafftechnologies.com/products/linux-vm) provide a straightforward environment for running the application and measuring the real workload before introducing additional nodes. ## Why Persistent Connections Change Memory and Network Planning An idle WebSocket can consume little CPU, but it is not free. The operating system and application maintain socket state, and the application may retain authentication, subscription, room, or session information for each client. Memory pressure often grows with connection count. CPU pressure often grows with message processing. Network pressure grows with message volume and fan-out. These limits can arrive at different times. For example, two applications can both have 5,000 active connections: - App A sends a small state update to each client once per minute. - App B sends multiple updates per second and broadcasts many events to large groups. The second workload can require substantially more CPU and network capacity even though the connection count is identical. This is why buying a WebSocket server based only on vCPU count or a generic “number of users” estimate is risky. Benchmark the application pattern you actually expect. ## Reverse Proxy Requirements for WebSocket Hosting Production WebSocket servers commonly sit behind Nginx, Caddy, Traefik, or another proxy. The proxy can terminate TLS, route domains and paths, and separate public traffic handling from the application process. The WebSocket handshake uses HTTP upgrade semantics. With Nginx, the `Upgrade` and `Connection` headers need explicit proxy handling because they are hop-by-hop headers; Nginx documents the current behavior in its [WebSocket proxying documentation](https://nginx.org/en/docs/http/websocket.html). Check these settings when deploying: | Proxy concern | What to verify | |---|---| | Protocol upgrade | WebSocket upgrade reaches the upstream correctly | | TLS | Production connections use `wss://` where appropriate | | Idle timeout | Valid quiet connections are not terminated unexpectedly | | Maximum connections | Proxy limits do not become the first bottleneck | | Health checks | Unhealthy backends stop receiving new connections | | Graceful shutdown | Existing connections can drain during maintenance when possible | For the broader distinction between the two edge roles, see [Reverse Proxy vs Load Balancer](https://rafftechnologies.com/learn/guides/reverse-proxy-vs-load-balancer). ## WebSocket Load Balancing: What Changes at Multiple Nodes? **WebSocket load balancing** becomes relevant when one server is no longer enough for capacity or availability. The important difference from ordinary stateless HTTP is that a connected client remains attached to a backend for the lifetime of that connection. A typical scaling path is: | Stage | Architecture | Good fit | |---|---|---| | 1 | One VM running the WebSocket application | Prototype and early production | | 2 | Reverse proxy + application on one VM | TLS, routing, cleaner process separation | | 3 | Separate application/worker services | Background work begins affecting connection handling | | 4 | Load balancer + multiple WebSocket nodes | Capacity or availability exceeds one node | | 5 | Shared pub/sub or messaging layer | Events must reach clients connected to different nodes | Adding a second WebSocket server does not automatically make the application distributed correctly. If user A is connected to node 1 and user B to node 2, an event created on node 1 may need a shared mechanism to reach node 2. Depending on the application, that mechanism might be a pub/sub system, message broker, database-backed event flow, or another coordination layer. The correct choice depends on delivery requirements and workload; do not add one merely because a diagram of a WebSocket architecture contains it. ## Do WebSockets Need Sticky Sessions? Sticky sessions can keep a reconnecting or session-bound client associated with a particular backend, but they are not a substitute for distributed application design. | Problem | Sticky sessions solve it? | |---|---:| | Keep a connection on its established backend | The live connection already does this | | Preserve backend-local state across new connections | Sometimes | | Deliver an event to users on other nodes | No | | Recover when a backend fails | No | | Prevent uneven long-lived connection distribution | Not necessarily | | Share presence or room membership globally | No | Prefer to understand which state truly must be shared. A stateless reconnect path plus shared application state can be easier to recover than relying heavily on backend affinity. ## Reliability: Design for Disconnects and Reconnect Storms A production WebSocket application should assume that connections will disappear. Mobile network changes, browser suspension, proxy timeouts, deploys, VM restarts, backend failures, and ordinary internet instability can all disconnect clients. Define the recovery behavior before traffic grows: - Use reconnect backoff rather than allowing every client to retry continuously. - Add jitter so thousands of clients do not reconnect at exactly the same interval. - Decide whether a reconnect needs a full state refresh or event replay. - Make duplicate event handling safe where delivery can be retried. - Drain connections during planned deployments where the stack supports it. - Test a server restart under realistic connection load. A reconnect storm is an important capacity case. A server that comfortably maintains 20,000 established connections may behave very differently when thousands of clients perform authentication and connection setup simultaneously. ## WebSocket Security Checklist Persistent connections do not bypass normal application-security requirements. They create a long-lived public application surface. Use a baseline that includes: - TLS (`wss://`) for production traffic where data crosses untrusted networks. - Authentication during or immediately after connection establishment. - Authorization for channels, rooms, topics, and actions—not just authentication. - Origin validation for browser clients where appropriate. - Strict message validation and size limits. - Rate limits for connection attempts and messages. - Secret management outside application source code. - OS and runtime patching. - Logging for failed authentication, abnormal disconnects, and abuse patterns. If internal services such as databases or message systems do not need public exposure, place them on private networking. Raff's [VPC](https://rafftechnologies.com/products/vpc) can be part of that design when separating public application nodes from private service traffic. ## Observability for Real-Time Applications CPU and RAM alone do not tell you whether a WebSocket product is healthy. Add connection-level signals. Track at least: | Signal | What it can reveal | |---|---| | Active connections | Capacity trend and abnormal drops | | Connection attempts | Traffic spikes and abuse | | Connection establishment failures | Proxy, TLS, auth, or capacity problems | | Reconnect rate | Network, timeout, deployment, or backend instability | | Messages per second | Application workload | | Message processing latency | Event-loop or worker pressure | | Outbound queue/buffer growth | Slow consumers or overloaded fan-out | | Unexpected disconnects | Reliability regression | | Network throughput | Transfer pressure | | Pub/sub or broker lag | Cross-node delivery bottlenecks | The browser `WebSocket` interface itself does not provide backpressure; MDN notes that applications can experience buffering problems when messages arrive faster than they can be processed. This is another reason to measure queue or buffer growth rather than watching CPU alone. [MDN WebSocket API](https://developer.mozilla.org/en-US/docs/Web/API/WebSockets_API) For a broader monitoring model, see [Application Observability for Small Teams](https://rafftechnologies.com/learn/guides/observability-small-teams-metrics-logs-traces). ## How Much Does WebSocket Hosting Cost? The advertised VM price is only one part of **WebSocket hosting cost**. A useful estimate includes the infrastructure needed to meet the application's actual reliability and scale target. Model these components: | Cost driver | When it grows | |---|---| | Compute and memory | More connections, heavier message processing, larger per-client state | | Network transfer | Higher message frequency, payload size, and fan-out | | Storage | Durable application state, logs, databases, and retained events | | Load balancing | Multi-node traffic distribution becomes necessary | | Shared messaging/state | Nodes must coordinate events or presence | | Backup/recovery | Persistent application data needs recovery protection | | Operations | Monitoring, incident response, deploys, and capacity testing require team time | Raff uses monthly VM plans rather than hourly billing. Check the current [Raff pricing page](https://rafftechnologies.com/pricing) for current plan prices instead of relying on a hard-coded number in an architecture guide. This distinction matters when comparing providers. A low entry price can be irrelevant if the workload later requires paid transfer, additional managed components, or a larger architecture than expected. Compare the **total design you need**, not only the smallest advertised server. ## Single VM vs Multi-Node WebSocket Hosting Start with one VM when it meets the requirement. Distributed systems create real operational cost. ### One VM is usually enough when - Peak connection count is comfortably within tested capacity. - Message rate and fan-out leave CPU and network headroom. - Short maintenance interruptions are acceptable. - The team is still validating the product or traffic model. - Cross-node state coordination would add complexity without solving a current problem. ### Move toward multiple nodes when - Load testing shows a real single-node capacity ceiling. - One node is an unacceptable availability risk for the business. - Deployments disconnect too many important sessions. - A single process or VM cannot meet latency objectives at peak traffic. - Traffic requires geographic or architectural separation. When moving to multiple nodes, plan load balancing, health checks, connection draining, reconnect behavior, and shared state together. See [Single Server vs Multi-Server Architecture](https://rafftechnologies.com/learn/guides/single-server-vs-multi-server-architecture) before adding nodes only for appearance of scale. ## A Practical WebSocket Hosting Architecture on Raff A small team can use a staged architecture rather than buying the final architecture on day one. **Stage 1 — One cloud VM.** Run the WebSocket application, reverse proxy, and monitoring on a [Raff Cloud VM](https://rafftechnologies.com/products/raff-vm) or Linux VM. Load-test the application and establish baseline connection, message, memory, CPU, and network metrics. **Stage 2 — Separate persistent data.** As the application matures, move durable state to the appropriate database/storage layer and make sure application data has a recovery plan. Use [Volumes](https://rafftechnologies.com/products/volumes) where block storage fits the workload and [Data Protection](https://rafftechnologies.com/products/data-protection) for supported backup/recovery needs. **Stage 3 — Isolate private services.** Keep services that do not need public ingress on a [VPC](https://rafftechnologies.com/products/vpc) where the architecture benefits from private service communication. **Stage 4 — Add nodes for a measured reason.** Introduce load balancing and a shared message/state mechanism only after capacity or availability requirements justify them. This path keeps the initial hosting model understandable while leaving room to scale. It also makes provider evaluation easier: the team can see which infrastructure component solves which measured constraint. :::cta Deploy a Cloud VM Start your WebSocket server on a Raff VM, measure real connection load, and scale the architecture when the workload requires it. ::: ## WebSocket Hosting Buyer Checklist Before choosing infrastructure for a real-time application, ask the provider and your own team: | Question | Why it matters | |---|---| | Can I run a persistent server process without platform request-duration limits? | WebSockets require long-lived connections | | Do I control the reverse proxy and runtime configuration? | Timeouts and upgrade behavior may need tuning | | What network-transfer model applies? | Fan-out can make transfer a major cost driver | | Can I scale CPU/RAM when measured load grows? | Early sizing estimates will change | | Is private networking available? | Databases and internal services may not need public exposure | | Can I add load balancing later? | Multi-node growth should not require a complete migration | | What backup/recovery options exist for persistent data? | WebSocket transport does not protect application state | | Is pricing understandable at my expected architecture? | The smallest plan is not the total workload cost | | Can I reach a real support path when infrastructure is failing? | Real-time failures are immediately visible to users | The best WebSocket hosting provider is not necessarily the one claiming the largest connection number. Your application code determines much of that capacity. Prefer infrastructure that gives you enough control to test, observe, secure, and grow the actual workload. ## Common WebSocket Hosting Mistakes **Sizing from monthly users.** Concurrent sessions and message behavior are the useful capacity inputs. **Assuming idle connections are free.** They may be light, but connection state still consumes resources. **Scaling to multiple servers before measuring one.** This adds load balancing and distributed-state problems before they are necessary. **Adding a load balancer but ignoring shared state.** Users connected to different nodes may still need the same events. **Ignoring reconnect storms.** Connection establishment and authentication can be more expensive than maintaining an established socket. **Using WebSockets for one-way, infrequent updates.** SSE or polling may be simpler. **Treating the VM price as the whole cost.** Network, redundancy, shared services, storage, backups, and operations also matter. **Skipping failure tests.** Restart a backend, break a dependency, and observe what clients actually do. ## Final Decision Choose WebSocket hosting when persistent bidirectional communication is important to the product. For a small team, the default architecture should usually be simple: one well-sized VM, a WebSocket-aware reverse proxy, secure client handling, and connection-level monitoring. Scale when measurements or business requirements justify it. Multi-node WebSocket hosting is not merely “more servers”; it introduces load balancing, failure recovery, reconnect behavior, and shared event/state coordination. Planning those pieces together is what turns a working WebSocket server into reliable real-time infrastructure. Raff Technologies can support that staged path with cloud VMs and supporting networking, storage, and recovery products. Start with the architecture you can operate today, measure the workload, and add complexity only when it solves a demonstrated constraint. --- ### Server Health Checks Explained: Liveness, Readiness, and Synthetic Monitoring URL: https://rafftechnologies.com/learn/guides/server-health-checks-explained-liveness-readiness-and-synthetic-monitoring Description: Design server health checks that trigger the right action. Learn liveness vs readiness, startup probes, health endpoints, synthetic monitoring, alerts, and failure handling. **Server health checks should answer one operational question and trigger one appropriate action.** A liveness check asks whether the process should be restarted. A readiness check asks whether the instance should receive traffic. A startup check protects slow initialization. Synthetic monitoring asks whether users can actually reach and use the service. That distinction matters because a bad health check can make an outage worse. Restarting every application instance during a database problem, routing users to an app that is still warming up, or declaring a service healthy because `/health` returns `200` while login is broken are all common failure modes. For teams running applications on **Raff Technologies**, health checks are part of the production design, not a monitoring afterthought. Whether the workload runs on a single cloud VM, several VMs, Docker, or Kubernetes, the goal is the same: detect the right failure, take the least destructive recovery action, and give the team enough context to understand what happened. ## Server health checks at a glance | Check | Question | Typical action | |---|---|---| | Liveness | Is the process healthy enough to keep running? | Restart only when restart is likely to help | | Readiness | Can this instance safely receive production traffic? | Remove from traffic until ready | | Startup | Has initialization completed? | Delay liveness/readiness enforcement | | Dependency check | Is a required downstream dependency usable? | Degrade, stop traffic, or alert depending on impact | | Synthetic check | Can a user-facing workflow succeed from outside? | Alert/investigate customer impact | | Worker/job health | Is background work actually progressing? | Alert or restart the affected worker if appropriate | The key rule is simple: **do not use one endpoint to control restarts, routing, uptime alerts, and business health at the same time**. ## Liveness vs readiness: the most important distinction A service can be alive but not ready. For example, a web process can still respond to a local health endpoint while its database pool is exhausted. Restarting the process may not fix the dependency problem, but continuing to send production traffic to it may still be harmful. That leads to two different decisions: - **Liveness:** should this process continue running? - **Readiness:** should this instance receive new traffic right now? Kubernetes documents the same separation: liveness probes determine when a container should be restarted, while readiness probes determine whether it should receive traffic. Incorrect liveness design can create cascading failures by restarting containers that are otherwise recoverable. [Kubernetes probes](https://kubernetes.io/docs/concepts/workloads/pods/probes/) A practical rule is: > **Liveness should fail only when restarting this process is likely to improve the situation. Readiness should fail when the instance should stop receiving new traffic.** ## What should a liveness probe check? A good **liveness probe** is narrow, fast, and local to the process. Useful liveness signals can include: - the process can respond; - the event loop or worker is not deadlocked; - the runtime can make basic progress; - critical internal state is not irrecoverably corrupted. Avoid putting every dependency into liveness. | Liveness check | Good idea? | Why | |---|---:|---| | Process/event-loop can respond | Yes | Restart may recover a stuck process | | Internal deadlock detector | Yes | Restart may restore progress | | Full database query | Usually no | Restarting the app does not fix a DB outage | | Payment provider call | No | External provider failure should not restart your app fleet | | Object storage check | Usually no | Feature impact may be partial rather than process failure | | Expensive business workflow | No | Too deep and fragile for restart control | If a database outage makes every liveness probe fail, an orchestrator can restart the whole application fleet at once. That adds connection churn and startup load to an existing outage. ## What should a readiness probe check? A **readiness probe** should represent whether the instance can serve useful production traffic now. That may include: - application initialization completed; - configuration loaded; - required local components are ready; - essential database connectivity is available; - the instance is not draining during deployment; - a critical dependency required by nearly every request is usable. Readiness can be deeper than liveness because the action is less destructive: stop routing new traffic to the instance while it recovers. ### Readiness should follow the traffic model Do not automatically mark the entire service unready because one optional feature is degraded. For example: - If email delivery fails but checkout still works, the web app may remain ready while the email subsystem alerts separately. - If the primary database is unavailable and almost every request requires it, readiness may reasonably fail. - If image processing workers are down but the main API can still serve reads, the API may remain ready while the worker health signal fails. The right boundary depends on what the instance is responsible for serving. ## Health check endpoint design A **health check endpoint** should be easy for humans and automation to interpret. Keep response behavior deterministic and inexpensive. A basic split might look like: ```text /health/live -> process survival /health/ready -> traffic readiness /health/start -> startup completion, if your platform uses a separate check ``` The endpoint response should not expose secrets, credentials, detailed stack traces, or internal topology to public callers. Good properties include: - small response body; - fast timeout; - predictable status codes; - no expensive queries; - no unnecessary dependency chain; - clear ownership of what failure means. If an endpoint checks five external services and takes several seconds, it is no longer a simple routing signal. It is closer to a deep diagnostic or synthetic test. ## Startup probes prevent restart loops Some applications need meaningful startup time. JVM or .NET services may warm up; applications may load models or indexes; caches may initialize; a service may need to establish network connections before it can serve traffic. A **startup probe** gives the application a realistic initialization window before normal liveness/readiness rules take effect. Kubernetes specifically uses startup probes to delay liveness and readiness until startup succeeds. [Kubernetes startup probes](https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/) Use a startup check when: - boot time is consistently longer than normal liveness thresholds; - cold start behavior varies significantly; - initialization includes large data or model loading; - startup frequently triggers false liveness failures. Do not use a huge startup window to hide an unknown boot problem. Measure normal startup duration and choose thresholds deliberately. ## Dependency health checks: which dependencies belong where? Dependencies should be checked according to the action you want to take when they fail. | Dependency | Better use | |---|---| | Primary database | Often readiness if most traffic requires it | | Cache | Readiness only if service cannot degrade without it | | Queue/broker | Worker health or feature-specific alert | | Payment provider | Synthetic or transaction-specific monitoring | | Email provider | Feature-specific alert, rarely liveness | | Object storage | Readiness only for services that cannot serve without it | | Auth provider | Readiness or synthetic login check depending on architecture | A dependency failure is not automatically a process failure. The useful question is: **what should the platform do if this dependency is unavailable?** If the answer is “restart the app,” it may belong in liveness. If the answer is “stop sending this instance new traffic,” it may belong in readiness. If the answer is “alert the team but keep serving other features,” it belongs elsewhere. ## Synthetic monitoring: the outside-in health check Internal health endpoints cannot prove the whole customer path works. **Synthetic monitoring** tests the service from outside, closer to the way a user experiences it. It can verify: - DNS resolution; - TLS and certificate validity; - public HTTP availability; - login; - API responses; - checkout or another critical transaction; - file upload/download; - WebSocket connection and basic message flow. Google SRE distinguishes **white-box monitoring**, which uses internal system knowledge, from **black-box monitoring**, which evaluates externally visible behavior. Black-box monitoring is especially useful for active user-facing symptoms. [Google SRE — Monitoring Distributed Systems](https://sre.google/sre-book/monitoring-distributed-systems/) ### Uptime monitoring vs synthetic monitoring Simple **uptime monitoring** asks whether an endpoint responds. Synthetic monitoring can go further by testing a meaningful path. | Test | What it proves | |---|---| | Ping/TCP check | Network endpoint is reachable | | HTTP `200` check | A page/endpoint responds | | API synthetic | Authenticated request returns expected result | | Browser synthetic | User-facing flow can complete | | Transaction synthetic | Critical business workflow still works | A homepage returning `200` does not prove login works. A load balancer with healthy targets does not prove customers can complete checkout. Use synthetic tests for the small number of journeys that represent real service usability. ## False positives and false negatives A health-check system can fail in two directions. **False positive:** the system is treated as unhealthy when it is actually usable. **False negative:** the system is treated as healthy while customers are affected. Examples: | Failure | Type | Result | |---|---|---| | Liveness depends on a third-party API | False positive | Healthy app processes restart during provider outage | | Readiness fails on optional cache | False positive | Capacity is removed unnecessarily | | `/health` always returns 200 | False negative | Broken business path stays “healthy” | | Web worker responds but queue is stuck | False negative | Background work silently stops | | Server is healthy but DNS fails | False negative | Users cannot reach it | The solution is not “deeper checks everywhere.” It is to give each check a narrow job and combine internal health with black-box validation. ## Health checks for load balancers and reverse proxies Traffic-distribution systems should use **readiness**, not simple process existence, to decide whether a backend receives new requests. A useful lifecycle is: ```text Starting -> not ready Initialized -> ready Draining -> not ready, still alive Broken process -> liveness failure Recovered -> ready again ``` This supports safer deployments because a server can stop receiving new traffic before the process is terminated. See [Reverse Proxy vs Load Balancer](/learn/guides/reverse-proxy-vs-load-balancer) and [Load Balancing Explained](/learn/guides/load-balancing-explained) for the surrounding traffic architecture. ## Health checks during deployment Deployments are where badly designed probes often become visible. A safer deployment sequence is: 1. Start the new instance/process. 2. Let startup complete. 3. Wait for readiness. 4. Add it to traffic. 5. Mark the old instance unready/draining. 6. Let active requests finish where practical. 7. Stop the old process. This prevents traffic from reaching a server simply because the process exists. For multi-node applications, readiness should be part of the release strategy rather than a separate monitoring feature. ## Background workers need different health checks A background worker can be “alive” while doing no useful work. For workers, add progress-oriented signals such as: - last successful job time; - queue depth; - age of the oldest job; - processing latency; - failure/retry rate; - heartbeat from the worker process. A worker health endpoint that only returns `200` can miss the most important failure: jobs are not moving. The same principle applies to cron jobs and scheduled tasks. Their health signal is often “did this job finish when expected?” rather than “does a process respond on a port?” ## Database health is more than connection success For databases, a single successful connection is only one signal. Depending on the workload, important health signals can include: - connection success; - query latency; - replication lag; - disk capacity; - lock/contention pressure; - backup success; - restore readiness. Do not put all of those into your web application's liveness endpoint. Monitor the database as its own production component and let application readiness reflect only the dependency behavior needed for serving requests. ## Alerting: do not page on every failed probe A failed health check is a signal, not automatically a page-worthy incident. Google SRE recommends separating signals that require urgent human action from lower-priority information. Monitoring should help answer both **what is broken** and **why**, while customer-facing symptoms should strongly influence paging decisions. [Google SRE — Monitoring Distributed Systems](https://sre.google/sre-book/monitoring-distributed-systems/) A practical model: | Event | Typical urgency | |---|---| | One readiness failure during deploy | Usually no page | | One redundant instance restarts once | Watch/ticket depending on context | | Many instances fail readiness | High urgency | | Synthetic login fails from several locations | High urgency | | Startup never completes after realistic window | Deployment investigation | | Optional dependency degraded | Warning/ticket | | Public endpoint unavailable | Page when customer-impacting | Alert on sustained, actionable symptoms rather than every transient probe result. ## Health checks and observability are different A health check answers a small operational question. Observability explains behavior. If readiness fails, you still need metrics, logs, and traces to understand why. Health checks should therefore work alongside: - CPU and memory metrics; - latency and error rates; - logs; - traces; - database metrics; - queue metrics; - dependency telemetry. Google's SRE framework highlights latency, traffic, errors, and saturation as core monitoring signals for user-facing systems. Health checks complement these signals; they do not replace them. See [Application Observability for Small Teams](/learn/guides/observability-small-teams-metrics-logs-traces) for the broader monitoring model. ## Health checks on Raff infrastructure Raff gives teams control over the application and VM layers needed to implement custom health logic. A practical small-team path is: | Stage | Health design | |---|---| | One application VM | `/live` + `/ready` + external synthetic check | | Reverse proxy in front | Route only to ready app processes | | Multiple VMs | Per-node readiness + external synthetic + shared observability | | Worker tier | Worker heartbeat + queue progress | | Private dependencies | Keep database/internal-service traffic on [VPC](/products/vpc) where appropriate | | Business-critical workload | Add tested backup/recovery through [Data Protection](/products/data-protection) and an incident runbook | For a simple web application, start on a [Raff Cloud VM](/products/raff-vm) or [Linux VM](/products/linux-vm) with clear application-level health endpoints. If the architecture later moves to [Managed Kubernetes](/products/kubernetes), keep the same semantic distinction between startup, liveness, and readiness instead of inventing new meanings for each environment. :::cta Deploy a Cloud VM Run your application on a Raff VM and build health checks around the real recovery and traffic decisions your workload needs. ::: ## Server health check buyer checklist Infrastructure choice affects how easily health checks can drive recovery. Before choosing or expanding a hosting platform, confirm: - Can you run persistent monitoring agents and custom health endpoints? - Can the application control startup and shutdown behavior? - Can unready instances be removed from traffic in a multi-node design? - Is private networking available for dependencies that should not be public? - Can you observe CPU, memory, disk, network, and application metrics? - Can you back up and recover persistent data independently of process health? - Can your team reach useful support when infrastructure behavior is unclear? A provider cannot design the application health model for you, but it should not make that model unnecessarily difficult to operate. ## Practical server health check policy For a small team, the following baseline is enough to avoid many reliability mistakes: - **Liveness:** local and shallow; fail only when restart is likely to help. - **Readiness:** represents whether production traffic should reach the instance. - **Startup:** protect realistic initialization time. - **Dependencies:** check them according to the action their failure should trigger. - **Synthetic:** validate at least one critical user-facing path externally. - **Workers/jobs:** monitor progress, not just process existence. - **Alerts:** page on sustained, actionable customer impact. - **Observability:** keep metrics/logs/traces available for root-cause analysis. - **Incident review:** update checks after incidents when they were too shallow, too deep, or missing. ## Final decision Server health checks are reliability controls, not status decorations. Use liveness to decide whether restarting a process is sensible. Use readiness to control traffic. Use startup checks to protect slow initialization. Use synthetic monitoring to confirm customer-visible behavior. Keep those decisions separate so a dependency problem does not turn into a restart storm and a green internal endpoint does not hide a broken user journey. For small teams, simple checks with clear consequences are usually safer than a large collection of ambiguous health endpoints. Build the minimum useful health model, test what happens when each check fails, and expand it when real incidents reveal a missing signal. ## Sources - [Kubernetes — Liveness, Readiness, and Startup Probes](https://kubernetes.io/docs/concepts/workloads/pods/probes/) - [Kubernetes — Configure Liveness, Readiness and Startup Probes](https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/) - [Google SRE — Monitoring Distributed Systems](https://sre.google/sre-book/monitoring-distributed-systems/) - [Raff Cloud VMs](/products/raff-vm) - [Raff VPC](/products/vpc) --- ### Cloud Runbooks for Small Teams: Incidents, Deployments, Access, and Recovery URL: https://rafftechnologies.com/learn/guides/cloud-runbooks-small-teams-incidents-deployments-access-recovery Description: Build a practical cloud operations runbook for incidents, deployments, access, recovery, and server operations. Includes a reusable template and automation guidance. A **runbook** is a repeatable operating guide for a known production event: an incident, failed deployment, access change, patch window, restore, rebuild, or another task where the wrong action can create downtime or data loss. For a small team, a good runbook should answer seven things quickly: **what triggered it, who owns the response, what to check first, which actions are safe, which actions need approval, how to recover or roll back, and what proves the system is healthy again**. Raff Technologies workloads can run across Linux VMs, Windows VMs, private networks, and protected storage. That flexibility is useful only when the team knows how to operate the environment repeatedly. A runbook turns infrastructure knowledge into a process another engineer can execute under pressure. ## Runbook quick answer Use a runbook when an operational event is **repeatable, time-sensitive, and risky enough that improvisation is dangerous**. | Event | Recommended runbook | |---|---| | Production outage | Incident response runbook | | Failed release | Deployment rollback runbook | | Leaked credential or admin change | Access and credential-rotation runbook | | OS/package maintenance | Patch and rollback runbook | | Data loss or corruption | Restore/recovery runbook | | VM becomes untrusted or unrecoverable | Rebuild runbook | | RDP/IIS/Windows service issue | Windows operations runbook | | SSH/systemd/Linux service issue | Linux operations runbook | The purpose is not to document every command. It is to make the **decision path** clear before the team is under pressure. ## What is a runbook? A runbook is an operational document that describes how to handle a known event safely and consistently. It differs from general documentation: | Document | Main purpose | |---|---| | Architecture documentation | Explains how the system is designed | | Setup guide | Explains how to install or provision something | | Runbook | Explains what to do when a specific operational event occurs | | Playbook | Coordinates a broader scenario across people, systems, or teams | | Checklist | Confirms required steps or conditions | | Post-incident review | Explains what happened and what should change | A runbook is most useful when it contains **decision gates**, not only steps. “Restart the server” is a weak instruction. “Restart only if liveness has failed, no data operation is in progress, and restart is expected to improve the failure mode” is a real operational decision. ## Runbook template for small teams Use this template as the default structure for a cloud operations runbook. | Section | What to document | |---|---| | Runbook name | Clear event or task | | Applies to | Service, VM, environment, or workload | | Owner | Person or role responsible for accuracy | | Trigger | Conditions that make the runbook relevant | | Impact/severity | Expected customer or business impact | | First checks | Evidence needed before taking action | | Safe actions | Low-risk steps allowed immediately | | Approval gates | Destructive or high-risk steps requiring explicit approval | | Rollback/recovery | How to reverse or recover from the action | | Verification | Evidence that the system is healthy again | | Escalation | Who to involve when the runbook no longer fits | | Communication | Who needs updates and when | | Post-action notes | What to record after execution | | Last reviewed | Date and owner of the last review | A useful runbook is often short. The responder should be able to find the trigger, first action, and stop condition without reading an essay. ## The most important field is the trigger A runbook should begin with a specific condition that tells the team when to use it. Weak triggers create ambiguity: | Weak trigger | Better trigger | |---|---| | “Server is broken” | “Production API returns sustained 5xx errors and customer requests are failing” | | “Database issue” | “Connection acquisition or query latency is blocking production requests” | | “Deployment failed” | “New release causes elevated errors, failed readiness checks, or a rollback decision” | | “Access problem” | “Admin credential, SSH key, API token, or account must be granted, removed, or rotated” | | “Backup issue” | “Restore is required or a recovery point cannot be validated” | A metric alone is not always a trigger. High CPU can be normal if the workload is productive. The runbook should be tied to an operational decision or customer impact. ## Incident response runbook An **incident response runbook** gives the team a predictable first response when production is degraded or unavailable. NIST SP 800-61 Rev. 3 treats incident response as part of a broader risk-management lifecycle that includes preparation, detection, response, recovery, and improvement. Google SRE guidance similarly emphasizes clear ownership, communication, and coordination during incidents. A small-team incident runbook should include: | Section | Decision | |---|---| | Declare | Does this meet the team's incident threshold? | | Severity | What is the customer/business impact? | | Owner | Who coordinates the response? | | Triage | What is affected, how broadly, and since when? | | Evidence | Which logs, metrics, timestamps, and changes must be preserved? | | Containment | What can reduce impact without destroying useful evidence? | | Recovery | Restart, rollback, restore, rebuild, or fail over? | | Communication | Who needs an update and when? | | Exit criteria | What proves the incident is resolved? | | Review | What should change afterward? | One person may hold multiple roles in a small team. The important part is that **ownership is explicit**. See [Incident Response Plan for Small Teams](/learn/guides/server-incident-response-small-teams-triage-containment-recovery) for the broader response framework. ## Deployment runbook A **deployment runbook** defines how a release moves from “ready to deploy” to “verified in production,” including when to stop or roll back. Minimum sections: - deployment owner; - change summary; - risk level; - active incidents or maintenance conflicts; - database/schema migration risk; - backup or restore prerequisite where appropriate; - rollout sequence; - health/readiness checks; - rollback or fix-forward path; - stop condition; - post-deployment validation. A practical release decision should look like this: ```text Prechecks pass -> deploy to limited scope -> readiness succeeds -> critical user path succeeds -> error/latency signals remain acceptable -> continue rollout ``` If those checks fail, the runbook should already define whether the team rolls back, pauses, or fixes forward. If rollback is impossible—such as after an irreversible data migration—the runbook must state the alternative recovery path before the change begins. ## Access and credential runbook Access changes deserve a runbook because they combine security risk with the possibility of locking the team out of production. Common triggers include: - new engineer onboarding; - employee or contractor offboarding; - compromised SSH key; - leaked API key; - Windows administrator change; - emergency production access; - secret or password rotation. A safe access runbook should document: 1. Who approves the change. 2. Which systems are affected. 3. Whether access is temporary or permanent. 4. Which dependent services use the credential. 5. How the old credential is revoked. 6. How new access is tested before the old path disappears. 7. What audit evidence is retained. For emergency access, define an expiration or review step. Temporary incident access should not silently become permanent production access. ## Recovery and disaster recovery runbooks A backup is not a runbook. The **restore process** is the runbook. A recovery runbook should answer: - What event requires restore or rebuild? - What is the acceptable Recovery Point Objective (RPO)? - What is the Recovery Time Objective (RTO)? - Which recovery point is trusted? - Who approves the restore? - In what order do dependencies recover? - What proves the recovered data is correct? - When can customer traffic return? A basic dependency-aware sequence can be: ```text Administrative access -> private/network path -> database and persistent data -> application service -> internal dependencies -> workers and scheduled jobs -> public traffic ``` Do not bring background jobs back before their data dependencies are ready. Retry storms and duplicate side effects can turn recovery into another incident. See [Disaster Recovery Plan for Small Teams](/learn/guides/disaster-recovery-plan-small-teams) and [Cloud Server Backup Strategy](/learn/guides/cloud-server-backup-rpo-rto-snapshots) for deeper recovery planning. ## Patch and maintenance runbook Routine patching can still create downtime. A patch runbook should define: | Decision | What to record | |---|---| | Urgency | Routine, urgent, emergency | | Scope | Which systems are affected | | Window | When maintenance occurs | | Owner | Who applies and verifies the change | | Prechecks | Current health, access, recovery path | | Expected impact | Reboot, service restart, downtime, none | | Validation | Service status, application health, logs | | Rollback | Restore, rebuild, package rollback, app rollback | | Deferral | What compensating control applies if patching waits | Use [Cloud VM Patch Management](/learn/guides/cloud-vm-patch-management-maintenance-windows-rollback) for the maintenance-window and rollback decision model. ## Rebuild runbook: when repair is the wrong choice Sometimes repairing a server is slower or less trustworthy than rebuilding it. A rebuild runbook is useful when: - the operating system is badly damaged; - a security incident makes host trust uncertain; - configuration drift is severe; - storage or filesystem damage makes recovery unreliable; - replacement from known-good configuration is faster than diagnosis. The runbook should define: 1. What data must be preserved before replacement. 2. Which configuration is authoritative. 3. How a replacement VM is provisioned. 4. How private networking and firewall paths are restored. 5. How persistent data is reattached or restored. 6. How the application is deployed. 7. How customer traffic moves to the replacement. 8. When the old server can be destroyed. The last step matters. Do not delete the original system until required evidence, data, and rollback options have been preserved. ## Windows and Linux runbooks need different operational details The decision structure can be shared, but Windows and Linux operating steps often differ. | Linux examples | Windows examples | |---|---| | SSH access | RDP access | | systemd services | Windows Services | | journald/syslog | Event Viewer | | apt/dnf package changes | Windows Update / role-specific maintenance | | Nginx/Apache | IIS | | shell scripts | PowerShell | For Windows workloads, document how the team validates RDP, IIS/application services, Event Viewer findings, patching, administrator access, and any workload-specific licensing requirements. For Linux workloads, document service names, log locations, firewall assumptions, deployment paths, and which directories or files must never be removed casually. The goal is not two separate operations cultures. It is to remove OS-specific tribal knowledge from the incident path. ## Runbook automation: when should you automate? **Runbook automation** is useful after the team understands the procedure well enough to define safe inputs, failure conditions, approvals, and rollback behavior. Automate when: - the task repeats frequently; - the decision rules are measurable; - the inputs are predictable; - the action is idempotent or safely repeatable; - rollback is understood; - human approval can be placed before destructive steps. Keep a human decision when: - data loss is possible; - the failure mode is ambiguous; - the action is difficult to reverse; - business context determines the correct choice; - the system changes faster than the automation. A useful progression is: ```text Document -> execute manually -> test repeatedly -> add checks and guardrails -> automate low-risk steps -> preserve approval for destructive actions ``` Do not automate a vague runbook. Automation only makes a bad procedure execute faster. See [Automation & Infrastructure-as-Code on Raff](/learn/guides/automation-infrastructure-as-code-raff) for infrastructure repeatability beyond incident operations. ## Verification and exit criteria make a runbook trustworthy A runbook should never end with “command completed.” It should end with evidence. Useful verification signals include: - health/readiness endpoints; - critical user journeys; - application error rate; - latency; - queue depth or oldest-job age; - database connectivity and query success; - logs showing expected state; - CPU, memory, disk, and network saturation; - backup/replication status where relevant. Define the **exit criteria** before the incident if possible. For example: > “Recovery is complete when login succeeds, critical writes complete, error rate is back within normal range, background jobs are moving, and no critical alerts remain.” That is stronger than “the VM is online.” ## Review runbooks after real use A stale runbook can be dangerous because responders assume it is correct. Review a runbook when: - it was used during an incident; - a deployment failed; - a restore test exposed missing steps; - access or secret management changed; - the architecture changed; - a service moved to another host or dependency; - the team discovered an unclear instruction. Instead of changing a date simply to look fresh, record a review when someone has actually verified the procedure. Useful ownership fields are: - owner; - last reviewed date; - systems covered; - known limitations; - change history. ## Minimum runbook set for a small team A small team does not need dozens of runbooks immediately. Start with the operational failures most likely to create serious business impact: 1. **Production incident response** — who owns the outage and how triage begins. 2. **Deployment rollback** — how to stop a bad release from spreading. 3. **Access onboarding/offboarding** — how privileged access is granted and removed. 4. **Backup restore** — how a recovery point becomes a working service. 5. **Patch maintenance** — how updates are applied and reversed. 6. **Server rebuild** — how an untrusted or damaged VM is replaced. 7. **OS-specific operations** — the Windows or Linux actions your workload actually uses. Add more only when repeated incidents or operational risk justify them. ## Applying runbooks on Raff Raff can provide the infrastructure building blocks; the team still owns the operating decisions in its runbooks. A practical model is: | Operational need | Raff building block | |---|---| | Application or service host | [Raff Cloud VM](/products/raff-vm) | | Linux workload | [Linux VM](/products/linux-vm) | | Windows workload | [Windows VM](/products/windows-vm) | | Private service communication | [VPC](/products/vpc) | | VM backup and recovery planning | [Data Protection](/products/data-protection) | For a production application, document the exact access path, service names, deployment process, health checks, backup/recovery path, and escalation contact before the system becomes business-critical. :::cta Deploy a Cloud VM Build your workload on Raff, then document the operational decisions your team will need during incidents, deployments, and recovery. ::: ## Runbook quality checklist Before calling a runbook production-ready, check that: - [ ] The trigger is specific. - [ ] The owner is named by role or person. - [ ] The first checks preserve useful evidence. - [ ] Safe actions are separated from destructive actions. - [ ] High-risk steps require an approval gate. - [ ] Rollback or recovery is documented. - [ ] Verification uses observable evidence. - [ ] Exit criteria are explicit. - [ ] Escalation is defined when the procedure stops fitting. - [ ] Access secrets are not stored directly in the runbook. - [ ] Links point to current systems and documentation. - [ ] The runbook has been reviewed after the last major change or real use. ## Common runbook mistakes **Writing only commands.** Commands are not enough when the real risk is deciding whether to run them. **No trigger.** Responders do not know when the runbook applies. **No stop condition.** The procedure continues even after the situation changes. **No approval gate.** Destructive actions can be executed casually. **No verification.** The team assumes success because a command returned zero. **Putting credentials in the runbook.** The document should link to the approved secret-management path instead. **Automating before understanding.** Automation can amplify a bad recovery decision. **Treating every metric spike as an incident.** Runbooks should be tied to impact or an operational decision, not noise. **Mixing stale Windows/Linux assumptions.** OS-specific steps should match the systems actually in production. ## Final decision A cloud runbook is useful when it removes ambiguity from a risky, repeatable operational event. For small teams, the best runbooks are not the longest. They make the trigger, owner, first checks, approval gates, rollback path, verification, and exit criteria obvious. Build those first for incidents, deployments, access, patching, restore, and rebuild workflows. Then improve them from real incidents and tests. When a procedure becomes stable and measurable, automate the low-risk steps—but keep destructive actions behind clear guardrails. ## Sources - [NIST SP 800-61 Rev. 3 — Incident Response Recommendations](https://csrc.nist.gov/pubs/sp/800/61/r3/final) - [Google SRE Workbook — Incident Response](https://sre.google/workbook/incident-response/) - [Raff Cloud VMs](/products/raff-vm) - [Raff VPC](/products/vpc) - [Raff Data Protection](/products/data-protection) --- ### Software Supply Chain Security for Developers: Protecting Cloud Servers URL: https://rafftechnologies.com/learn/guides/developer-supply-chain-security-cloud-servers Description: Learn how to secure the software supply chain from dependencies and CI/CD to SBOMs, build provenance, secrets, container images, and cloud deployment access. **Software supply chain security protects the path from source code to the software running in production.** For a small team, that path includes source control, third-party dependencies, CI/CD workflows, build systems, container images, secrets, deployment credentials, and the cloud servers that finally run the application. The practical goal is not to eliminate every third-party dependency or add enterprise process to every commit. It is to know **what can change production, what evidence proves an artifact came from the expected source, which credentials can reach the environment, and how quickly the team can contain a compromised component or deployment path**. Raff Technologies can provide Linux or Windows cloud VMs, private networking, and recovery building blocks. Those infrastructure boundaries help separate development, staging, and production, but software supply chain security remains a shared engineering responsibility: your team still controls source, dependencies, pipelines, secrets, images, and release policy. ## Software supply chain security: quick framework Use this sequence for a small production team: 1. **Map the path to production.** Identify repositories, dependencies, CI/CD, registries, credentials, and deployment targets. 2. **Reduce who and what can change releases.** Protect branches, review workflows, use least privilege, and separate test from production credentials. 3. **Control dependencies and build inputs.** Use lockfiles, trusted registries, review significant updates, and track what is shipped. 4. **Create evidence.** Generate an SBOM where useful and preserve build provenance or attestations for important artifacts. 5. **Verify before deployment.** Confirm the artifact, image, or package is the expected version from the expected build path. 6. **Isolate environments.** Development and staging should not automatically inherit production secrets or administrator access. 7. **Prepare containment.** Know how to revoke credentials, block a bad artifact, restore a known-good release, and rebuild affected servers. A useful test is simple: > If one dependency, CI workflow, maintainer account, build runner, or deployment credential were compromised today, how far could the attacker move before another control stopped them? ## What is the software supply chain? The **software supply chain** is every system and dependency involved in creating, building, distributing, and deploying software. A typical small-team path looks like this: ```text Developer workstation → source repository → pull request and review → dependency/package sources → CI workflow → build runner → artifact or container registry → deployment credential → staging → production cloud server ``` Each arrow is a trust boundary. A vulnerability in application code is one risk. A compromised package maintainer, malicious build step, leaked registry credential, mutable CI action, or stolen deployment token can bypass otherwise good server hardening. That is why **cloud server security starts before code reaches the server**. ## Where software supply chain attacks happen A software supply chain attack targets a trusted path instead of attacking the final server directly. | Attack surface | Example failure | Production impact | |---|---|---| | Source control | Stolen developer or maintainer account | Unauthorized code or workflow change | | Dependencies | Malicious or compromised package | Attacker code enters the build | | Build process | Tampered runner or build step | Artifact differs from reviewed source | | CI/CD workflow | Over-permissioned or modified pipeline | Secrets stolen or malicious release deployed | | Artifact registry | Image/tag replaced or overwritten | Wrong artifact reaches production | | Secrets | Long-lived token exposed | Direct access to repository, registry, or server | | Deployment path | Shared SSH key or broad API credential | Production can be changed outside review | | Developer tooling | Compromised extension or workstation | Source, tokens, or credentials stolen | The important question is not only “is the server patched?” It is **which trusted systems can produce or deploy what the server executes?** ## Start with a production-path inventory Before buying tools, document the actual path to production. For each production workload, record: | Area | Questions to answer | |---|---| | Repository | Which repo and branches can produce production code? | | Review | Who can approve and merge? | | Dependencies | Which package ecosystems and registries are trusted? | | CI/CD | Which workflows can access production secrets or deploy? | | Runner | Hosted, self-hosted, ephemeral, or long-lived? | | Artifact | Package, binary, VM image, or container image? | | Registry | Where is the artifact stored and who can push? | | Credentials | Which secrets or identity tokens can deploy? | | Target | Which Linux/Windows VMs, cluster, or service receives the release? | | Recovery | How do you return to a known-good release? | This inventory often reveals risks faster than another generic security scanner. ## Dependency security: control what enters the build Modern applications depend on open-source and third-party packages. The goal is not to remove dependencies; it is to reduce **uncontrolled change and unknown provenance**. Common dependency risks include: - typosquatting and dependency confusion; - compromised maintainer accounts; - malicious package releases; - vulnerable versions; - abandoned components; - install scripts that execute code; - transitive dependencies the team never selected directly. A practical small-team baseline: ### Use lockfiles Commit the appropriate lockfile for the ecosystem so installs resolve to known versions instead of silently changing between builds. ### Review high-impact dependency changes Treat a new authentication library, build plugin, database driver, package-manager script, or production-critical framework differently from a small development-only utility. ### Remove unused packages Every dependency increases maintenance and review surface. If the application no longer uses it, remove it. ### Prefer trusted package sources Use the official ecosystem registry or an intentionally controlled internal proxy/mirror. Avoid adding random package sources to solve one build problem. ### Separate development and production dependencies Test tooling should not automatically become part of the production artifact. Dependency scanning can help identify known vulnerabilities, but it does not prove a package is trustworthy. Vulnerability data and supply chain trust answer different questions. ## Software Bill of Materials (SBOM): what it solves A **Software Bill of Materials (SBOM)** is an inventory of software components associated with a software product or artifact. CISA's current SBOM guidance emphasizes structured component data that can support automation and software transparency at scale. An SBOM can help a team answer: - Which component versions are inside this release? - Are we affected by a newly disclosed vulnerability? - Which products or environments include the affected component? - Did this release contain the dependency we expected? An SBOM is most useful when it corresponds to the artifact that actually shipped. For a small team, start where the operational value is clear: - customer-facing releases; - security-sensitive products; - enterprise customer requirements; - container images distributed across environments; - applications with large dependency trees. Do not treat “we generated an SBOM” as proof that the software is safe. An SBOM improves **visibility**; it does not automatically validate source integrity, build integrity, or vulnerability remediation. ## Build provenance and SLSA A secure build should answer more than “the pipeline passed.” It should provide evidence about **where the artifact came from and how it was built**. SLSA (Supply-chain Levels for Software Artifacts) is an industry specification for incrementally improving software supply chain security. The current SLSA v1.2 specification includes Build and Source tracks. Its build model uses **provenance**—verifiable information describing how an artifact was produced and which source/input material was involved. A useful small-team progression is: | Maturity | Practical goal | |---|---| | Basic | Builds are repeatable and tied to reviewed source | | Better | The build emits provenance/attestation for the artifact | | Stronger | Provenance is signed or otherwise protected from tampering | | Advanced | Build infrastructure itself is hardened and verification policy is enforced | You do not need to chase a framework level simply for the label. Use the SLSA model to improve traceability and make artifact verification possible. ## CI/CD security: treat the pipeline as production infrastructure A workflow that can deploy to production is privileged infrastructure. It may be able to: - read secrets; - create releases; - push container images; - connect to production servers; - modify cloud resources; - run database migrations; - change DNS or configuration. That means CI/CD security should focus on **permissions, trust boundaries, and untrusted input**. ### Give each workflow minimum permissions A test workflow does not need production deploy rights. A documentation build does not need write access to infrastructure. A dependency update job should not automatically receive every environment secret. For GitHub Actions, GitHub's current security guidance recommends explicitly limiting `GITHUB_TOKEN` permissions rather than assuming broad defaults are appropriate. ### Pin third-party actions when possible GitHub's secure-use guidance states that pinning an action to a full-length commit SHA is the way to use that action as an immutable release. Tags are convenient, but tags can move. For security-sensitive workflows, review third-party action code and pin the exact version you intend to trust. ### Restrict who can change workflow files A pull request that changes application code and a pull request that changes the deployment pipeline do not carry the same risk. Use branch protection, required review, and CODEOWNERS or equivalent ownership rules where appropriate so pipeline changes receive deliberate review. ### Be careful with untrusted pull requests Do not let untrusted contributions execute with production secrets or highly privileged workflow tokens. The CI event model matters as much as the code being tested. ## Prefer short-lived deployment identity over long-lived secrets Long-lived cloud or deployment credentials are valuable to attackers because they can continue working after the CI job ends. Where supported, use **federated or short-lived identity** instead of storing a permanent cloud access key in CI. For example, GitHub Actions supports OpenID Connect (OIDC) so workflows can request short-lived identity tokens and exchange them with supported cloud providers. GitHub recommends configuring trust conditions so only intended repositories, branches, tags, or environments receive cloud access. Even when OIDC is not available, reduce secret risk by: - scoping credentials to one environment; - using separate deploy credentials per production system; - rotating credentials after exposure or staff changes; - removing old keys and tokens; - keeping secrets out of source, images, screenshots, and logs. A production deploy credential should not also be the team's universal administrator credential. ## Container image security Containers add another software supply chain boundary: the image. A secure container workflow should answer: - Which base image did we use? - Who produced the final image? - Which dependency versions are inside it? - Where is the image stored? - Can the tag be changed after review? - Do we verify the digest or attestation before deployment? - Are registry credentials scoped appropriately? Prefer images from sources you intentionally trust, use specific versions or immutable digests where the workflow supports them, and rebuild regularly enough to incorporate security fixes. Do not expose production credentials during image build. Secrets copied into an image layer can remain recoverable even after the Dockerfile line that created them is changed. For persistent workloads, remember that image security and data recovery are separate concerns. A known-good image does not replace backups of databases, uploads, or other state. ## Artifact verification: deploy what you reviewed The release process should establish a chain of confidence: ```text Reviewed source → controlled build → identifiable artifact → protected registry → verified deployment ``` A useful artifact policy may include: - immutable version or digest; - build identifier; - source commit reference; - SBOM; - provenance/attestation; - signature or verification metadata where the toolchain supports it; - controlled registry permissions. The exact tool is less important than the outcome: **production should not run an artifact simply because a mutable tag happens to have the expected name.** ## Secrets are the bridge between the supply chain and the server Secrets are often the shortest path from development systems to infrastructure. High-risk examples include: - SSH private keys; - Windows administrator credentials; - cloud API tokens; - registry credentials; - database passwords; - Git provider tokens; - deployment webhook secrets. Good secret boundaries are environment-specific. Development should not automatically unlock production. Staging should not use the production database password. A CI deploy identity should be able to perform the deployment—not every administrative action available in the account. If the same secret is embedded in laptops, CI, cron jobs, and manual deployment scripts, rotation becomes difficult exactly when you need it most. ## SSH and direct server access Direct server access remains part of the supply chain when developers or automation can bypass normal release controls. A safer model uses: - individual SSH keys instead of one shared private key; - named Windows administrator accounts where practical; - offboarding when a person leaves or changes role; - separate credentials for humans and automation; - restricted administrative network paths; - logs that show who performed important actions; - an emergency-access path separate from everyday deployment. ![Terminal window showing separate SSH key files for development, staging, and production server access.](https://raff-images.s3.raffusercloud.com/Screenshot_2026_06_01_at_11_10_54_6bc25a4f50.png) The strongest deployment workflow loses value if anyone can quietly SSH to production and replace the artifact by hand without review. That does not mean manual access must disappear. It means direct access should be **intentional, attributable, and exceptional enough that the team notices when it is used**. ## Separate development, staging, and production Environment separation limits blast radius. | Environment | What it should contain | What it should not inherit automatically | |---|---|---| | Development | Test data, developer tooling, experimental builds | Production credentials and production database access | | Staging | Production-like configuration and release candidate | Broad production administration rights | | Production | Approved artifact, restricted secrets, monitored workload | Experimental tools and unreviewed changes | ![Raff dashboard showing separate cloud VMs for development, staging, and production environments.](https://raff-images.s3.raffusercloud.com/Screenshot_2026_06_01_at_11_03_26_1592238e5d.png) For small teams, separate VMs can be an understandable boundary: one compromised development environment does not have to imply immediate production access. Private networking can also reduce unnecessary public exposure when services communicate internally. Use [Raff VPC](/products/vpc) for current private-networking capabilities. ## AI coding agents need the same boundaries AI-assisted coding changes development speed, not the security model. An agent that can edit files, run commands, install dependencies, or modify workflow configuration should be treated like any other powerful development tool. Safer patterns include: - work in development or ephemeral environments; - keep production secrets out of the workspace; - require review for CI/CD and infrastructure changes; - review dependency additions; - restrict direct production administration; - validate generated commands before destructive execution; - keep production deployment as a controlled release step. ![Terminal window showing a clean cloud development workspace prepared for AI-assisted coding.](https://raff-images.s3.raffusercloud.com/A_clean_cloud_development_workspace_gives_AI_assisted_coding_tools_a_safe_place_to_prepare_changes_before_they_reach_production_2f8eaf77ea.png) See [AI Coding Agents and Cloud Dev Environments](/learn/guides/ai-coding-agents-cloud-dev-environments) for the environment-design side of that workflow. ## What NIST SSDF adds to the model NIST's Secure Software Development Framework (SSDF) provides a high-level set of practices that organizations can integrate into their existing software development lifecycle. For a small team, the useful idea is not adopting another heavyweight process. It is making secure development activities repeatable across four broad concerns: - prepare the organization; - protect software from tampering; - produce well-secured software; - respond to vulnerabilities. NIST published SSDF v1.1 as the current final version and released SSDF v1.2 as a draft revision in December 2025. Use the final framework for stable requirements and track the draft when planning future process changes. ## Supply chain incident response A compromised dependency or build credential requires a different response from a normal application bug. Your response runbook should be able to answer: 1. **What artifact is affected?** 2. **Which source commit and build produced it?** 3. **Where was it deployed?** 4. **Which credentials might have been exposed?** 5. **Can the compromised component still publish or deploy?** 6. **Which known-good version can replace it?** 7. **Do we need to rebuild servers, rotate secrets, or restore data?** 8. **What customer or regulatory communication is required?** Immediate containment may include: - disable or rotate compromised credentials; - block the affected package/image/artifact; - suspend the unsafe workflow; - restrict registry push access; - redeploy a known-good artifact; - rebuild hosts if their integrity is uncertain; - increase monitoring for abuse of exposed credentials. Use [Incident Response Plan for Small Teams](/learn/guides/server-incident-response-small-teams-triage-containment-recovery) and [Cloud Runbooks for Small Teams](/learn/guides/cloud-runbooks-small-teams-incidents-deployments-access-recovery) to define ownership and recovery before an incident. ## Small-team software supply chain checklist ### Source control - [ ] Production branches have controlled merge rights. - [ ] Important repository and workflow changes require review. - [ ] Former team members and contractors are removed promptly. - [ ] MFA/strong account security is enabled where supported. ### Dependencies - [ ] Lockfiles are committed where the ecosystem supports them. - [ ] New production dependencies receive review. - [ ] Unused dependencies are removed. - [ ] Vulnerability/dependency alerts have an owner. ### CI/CD - [ ] Workflow permissions use least privilege. - [ ] Test workflows do not receive production secrets unnecessarily. - [ ] Third-party actions/workflows are reviewed and pinned appropriately. - [ ] Self-hosted runners do not become permanent unreviewed production backdoors. ### Artifacts - [ ] Production deploys a specific artifact version/digest. - [ ] Registry push permissions are limited. - [ ] SBOM or component inventory exists where operationally useful. - [ ] Build provenance/attestation is preserved for important releases. ### Secrets and access - [ ] Development credentials cannot administer production. - [ ] Human and machine identities are separate where practical. - [ ] Long-lived deployment secrets are minimized. - [ ] Rotation/revocation steps are documented. - [ ] Shared SSH keys or administrator credentials are avoided. ### Production and recovery - [ ] Staging and production are separated appropriately. - [ ] Public exposure is limited to required services. - [ ] A known-good artifact can be redeployed quickly. - [ ] Backups/recovery protect persistent data separately from application artifacts. - [ ] Supply chain incidents have an owner and containment path. ## How Raff fits this security model Raff's role is the **runtime and infrastructure boundary**, not the software supply chain itself. Teams can use Raff cloud infrastructure to separate environments and design recovery paths: | Need | Raff building block | |---|---| | Linux application or build/test environment | [Linux VM](/products/linux-vm) | | General cloud compute | [Raff VM](/products/raff-vm) | | Private service communication | [VPC](/products/vpc) | | VM-level recovery planning | [Data Protection](/products/data-protection) | A practical pattern is to keep development and staging separate from production, deploy only approved artifacts to production, keep internal service paths private where appropriate, and maintain an independent recovery path for data and servers. Raff does not automatically secure your packages, Git repositories, CI workflow, application secrets, or container registry. Those remain part of the engineering controls described in this guide. :::cta Deploy a Cloud VM Create separate Linux environments for development, staging, and production, then apply least-privilege deployment and recovery controls around the software that reaches them. ::: ## Buyer checklist: infrastructure for a secure delivery workflow When choosing infrastructure for an application delivery pipeline, verify more than CPU and RAM. Ask: - Can development, staging, and production be separated clearly? - Is private networking available for internal services? - Can production administration be limited to specific access paths? - Are backup and recovery controls available for the VM and persistent data? - Can servers be recreated without relying on undocumented manual changes? - Is there an API or automation path if repeatable provisioning becomes important? - Can the team get useful infrastructure support when a failure may be below the application layer? - Is the pricing model understandable enough that security boundaries such as separate staging or recovery environments are practical to maintain? The cheapest single server is not always the lowest-risk production design if every environment, credential, and workload must share it. ## Common software supply chain mistakes **Treating vulnerability scanning as the whole program.** A clean scanner result does not prove the build or deployment path is trustworthy. **Allowing CI to become a universal administrator.** Pipelines should have only the permissions needed for their job. **Using mutable artifact references.** A tag or label that can move after review weakens release traceability. **Generating an SBOM and never using it.** Component inventory has value when it supports vulnerability response, customer requirements, or release verification. **Keeping permanent cloud keys in CI.** Prefer short-lived identity where the platform supports it; otherwise scope and rotate credentials deliberately. **Sharing one SSH key.** Shared access makes offboarding, attribution, and rotation harder. **Letting development inherit production secrets.** Environment separation should include identity and credentials, not only separate VMs. **No recovery path for a compromised artifact.** The team should know how to block, replace, and verify the affected release. ## Final decision Software supply chain security is the practice of controlling the trusted path from source code to the software running in production. For a small team, the highest-value controls are usually straightforward: know the production path, reduce who can change it, control dependency and workflow permissions, minimize long-lived secrets, identify the artifact that was actually built, preserve useful SBOM/provenance evidence, separate environments, and rehearse containment and recovery. You do not need every enterprise security product to improve supply chain security. You do need to make the release path **visible, attributable, least-privileged, and recoverable**. ## Sources - [NIST SP 800-218 — Secure Software Development Framework (SSDF) v1.1](https://csrc.nist.gov/pubs/sp/800/218/final) - [NIST SSDF publications and current revision status](https://csrc.nist.gov/projects/ssdf/publications) - [CISA SBOM Resources Library](https://www.cisa.gov/topics/cyber-threats-and-advisories/sbom/sbomresourceslibrary) - [CISA — Securing the Software Supply Chain: Recommended Practices for Developers](https://www.cisa.gov/sites/default/files/2023-12/ESF_SECURING_THE_SOFTWARE_SUPPLY_CHAIN_DEVELOPERS.pdf) - [SLSA v1.2 Specification](https://slsa.dev/spec/v1.2/) - [GitHub Actions — Secure use reference](https://docs.github.com/en/actions/reference/security/secure-use) - [GitHub Actions — OpenID Connect in cloud providers](https://docs.github.com/en/actions/how-tos/secure-your-work/security-harden-deployments/oidc-in-cloud-providers) - [Raff VM](/products/raff-vm) - [Raff VPC](/products/vpc) - [Raff Data Protection](/products/data-protection) --- ### Office Server Replacement Guide: What SMBs Should Move First URL: https://rafftechnologies.com/learn/guides/office-server-replacement-small-business Description: Plan a small business server migration to cloud infrastructure. Learn what to move first, what to keep local, how to size the target, and how to reduce cutover risk. **Office server replacement should start with workload discovery, not with buying a new server.** For most small businesses, the safest path is to inventory what the current machine actually does, separate cloud-ready workloads from hardware-dependent ones, and migrate one low-risk, high-value workload first. Raff Technologies provides Linux and Windows cloud VMs for teams moving selected workloads away from aging office hardware. The goal is not to move everything to the cloud. It is to decide which business applications belong on a cloud server, which should move to SaaS or a managed service, which should stay local, and which can be retired. For small businesses planning a **server migration to cloud infrastructure**, the best first candidates are usually workloads with clear users, clear data, predictable resource needs, and a simple rollback path. Shared file systems, device-linked software, and poorly documented legacy applications usually need more discovery before cutover. ## When an office server becomes a business risk An office server can run reliably for years. The risk appears when the business becomes more dependent on it than the recovery plan can support. Common warning signs include: - hardware is old but still business-critical; - backups exist but nobody has tested a restore; - one person knows the administrator credentials; - remote access depends on the office internet connection; - users cannot work if the office loses power or connectivity; - storage is close to full; - operating-system or application updates are delayed because nobody wants to break the server; - nobody has documented scheduled jobs, services, databases, or integrations; - replacement parts or vendor support are becoming difficult to obtain; - the company has no clear answer to “how long would recovery take if this server failed today?” Replacing the server is not automatically the answer. The first step is understanding the workload and its dependencies. ## Inventory before you migrate anything A small business server migration often fails because the team inventories the machine but not the services running on it. Create a workload inventory that includes: | Area | What to record | |---|---| | Applications | Installed business software, web apps, services, agents | | Data | Databases, shared folders, application data, uploads, archives | | Users | Who logs in, from where, and how often | | Authentication | Local accounts, Active Directory, app accounts, service accounts | | Network | Open ports, inbound/outbound connections, IP allowlists, DNS | | Dependencies | Other servers, APIs, databases, file shares, printers, scanners | | Scheduled work | Cron jobs, Windows Task Scheduler jobs, exports, syncs, scripts | | Licensing | Windows Server, RDS, SQL Server, and application licensing requirements | | Backups | What is protected, retention, restore process, last successful restore test | | Recovery target | Acceptable downtime and acceptable data loss | Microsoft's current migration guidance emphasizes discovering servers, assessing readiness, and identifying dependencies before migration. That principle is provider-independent: if two systems depend on each other, moving one without understanding the other can create an outage. A useful rule is simple: **do not migrate a workload you cannot describe.** ## What small businesses should move first The first migration should reduce risk without creating a large operational project. Good first candidates usually have four characteristics: 1. a named owner; 2. a known user group; 3. a clear data set; 4. a clear way to test success and roll back. ### Public websites and customer portals A website or customer portal is often a good early candidate because it is already intended to be available outside the office. A custom website, API, portal, booking system, or small web application can often move to a [Linux cloud VM](/products/linux-vm) without requiring the rest of the office infrastructure to change at the same time. A simple marketing site may not need a VM at all; managed website hosting can be easier. The cloud VM case becomes stronger when the workload needs custom application logic, a database, background jobs, Docker, private services, or direct server control. ### Internal dashboards and lightweight business apps Internal dashboards often have predictable users and limited dependencies. Examples include: - operations dashboards; - inventory views; - reporting portals; - internal admin panels; - lightweight CRM-style tools; - document-processing apps; - approval workflows. These can be good first workloads because the business can test access, permissions, performance, and recovery with a smaller group before migrating something more critical. ### Automation and scheduled jobs Office servers frequently run hidden jobs that nobody notices until they stop. Examples include: - scheduled exports; - database syncs; - file processing; - invoice or report generation; - API polling; - notification jobs; - backup scripts; - data cleanup. These jobs can move well to cloud infrastructure when they do not depend on local devices or local-only network paths. Before moving them, document every job, its schedule, credentials, inputs, outputs, dependencies, and what happens after failure. ### Windows business software that needs remote access Windows applications can be a strong cloud candidate when users need centralized remote access or when the current office server is primarily kept alive for one Windows-only workload. Examples include: - Windows business applications; - IIS and ASP.NET workloads; - Microsoft SQL Server-backed software; - accounting or ERP software supported in hosted environments; - industry-specific Windows applications; - internal administrative systems. A [Raff Windows VM](/products/windows-vm) can provide a hosted Windows Server environment when the application is suitable for a cloud VM. Multi-user remote desktop needs licensing planning. Microsoft documents that users or devices connecting to a Windows Server Remote Desktop Services Session Host require appropriate RDS CALs, and CAL version compatibility must match the server environment. Do not assume ordinary administrator access is a substitute for a properly licensed multi-user RDS deployment. For the Windows-specific buying decision, see [Windows VPS Hosting for Small Teams](/learn/guides/windows-vps-hosting-small-teams) and [Windows Server Licensing for Hosted VMs](/learn/guides/why-microsoft-licensing-matters-windows-vm-provide). ## What should usually move later Some workloads are poor first migrations even when the long-term goal is cloud adoption. ### Shared file servers File servers often contain more operational complexity than their folder structure suggests. Before moving a shared drive, identify: - active vs archived data; - permissions and access groups; - large or frequently changing files; - applications that use mapped paths; - sync requirements; - retention requirements; - sensitive folders; - restore expectations; - how users will access files after migration. A SaaS file platform may be better for user collaboration. A cloud VM plus storage may fit application-driven file access. Large business archives may require a different storage design entirely. Do not choose a VM simply because the old system was also “a server.” Choose the destination from the workload. ### Printer, scanner, label, and device workflows Local devices are a common reason to keep part of the environment on-premises. Printers, scanners, label systems, cameras, POS devices, USB keys, and industrial devices may depend on: - local network discovery; - vendor drivers; - fixed IP addresses; - mapped paths; - USB or serial connectivity; - low-latency access to nearby hardware. These are often better handled with a hybrid architecture until the workflow can be redesigned or the vendor confirms cloud compatibility. ### Poorly documented legacy applications An old application may look simple but depend on: - an old database version; - local file paths; - hard-coded IP addresses; - a license server; - a USB dongle; - unsupported Windows components; - other services running on the same machine. Vendor validation and dependency discovery should happen before migration. ## Cloud server, SaaS, local, or hybrid? A small business server replacement does not need one destination for every workload. | Workload | Typical destination to evaluate first | |---|---| | Email and calendar | SaaS | | Simple website | Managed website platform | | Custom website/API | Cloud VM | | Windows business application | Windows cloud VM if vendor and licensing permit | | Internal Linux app | Linux cloud VM | | Database | Managed database or VM, depending on operational requirements | | Shared files | SaaS file platform, cloud storage, VM, or hybrid | | Printer/scanner workflow | Local or hybrid | | Hardware-linked software | Local until compatibility is verified | | Backup/archive | Dedicated backup or storage design | The right target is often mixed. A business might keep Microsoft 365 for email and documents, run a Windows application on a cloud VM, host an internal web app on Linux, keep device-dependent services locally, and separate the production database from the application server. ## How to plan a server migration to cloud infrastructure A safe migration sequence reduces both technical and business risk. ### 1. Discover Inventory workloads, data, users, network paths, scheduled jobs, and dependencies. ### 2. Classify Put each workload into one of four groups: | Group | Meaning | |---|---| | Move first | Cloud-friendly and easy to validate | | Move later | Valuable to move but needs more discovery | | Keep local | Hardware-linked or office-dependent | | Retire | No longer needed or replaced by another system | ### 3. Measure actual resource use Do not size the target server only from the old server's CPU and RAM labels. Record, where possible: - peak and typical CPU use; - memory use; - disk capacity and growth; - IOPS or storage activity for database-heavy systems; - network traffic; - concurrent users; - application response time; - backup size and duration. Performance data helps avoid paying to reproduce years of oversized local hardware in the cloud. ### 4. Design the target environment Decide whether the workload needs: - Linux or Windows; - one VM or multiple components; - a managed database; - [private networking](/products/vpc); - additional [block storage](/products/volumes); - [data protection](/products/data-protection); - a public IP; - VPN/private access; - RDS licensing; - application-specific licensing. Keep the design as simple as the workload allows. ### 5. Build before cutover Create the target environment, apply updates, configure access, migrate representative data, and validate the application before production users depend on it. ### 6. Test recovery Backups matter only if the business can restore from them. Before cutover, verify: - what is backed up; - where backup data lives; - how often it runs; - who can restore it; - how long restore takes; - what data can be lost between backups. ### 7. Test with real users A successful login is not enough. Ask representative users to perform their normal tasks and validate: - application behavior; - printing or exports where relevant; - permissions; - remote access; - performance; - integrations; - reports; - data updates. ### 8. Cut over with rollback Define the cutover window and the conditions that would trigger rollback. Keep the previous environment available until the new workload has survived normal business use and the required data has been validated. For a broader process, use the [Cloud Migration Checklist for Small Teams](/learn/guides/cloud-migration-checklist-small-teams). ## How to choose a cloud server for a small business The commercial decision should follow the workload assessment. When comparing a **cloud server for small business**, evaluate more than the advertised monthly VM price. ### Operating system support Choose a provider that supports the OS and workload model you actually need. Linux is usually the natural choice for web applications, APIs, Docker workloads, automation, open-source applications, and many databases. Windows is appropriate when the application depends on Windows Server, IIS, RDP, or Windows-specific business software. ### Storage and recovery Ask whether application data should live on the boot disk or separate storage, whether storage can be expanded, which backup options exist, and how the workload would be rebuilt if the VM were unavailable. ### Private networking If the application and database run separately, private networking can reduce unnecessary public exposure between components. ### Licensing Windows Server, RDS, SQL Server, and third-party business software can all have separate licensing requirements. Provider access to Windows infrastructure does not automatically solve every application licensing requirement. ### Support and migration risk Ask how support works when the VM is unreachable, storage must be recovered, networking behaves unexpectedly, the workload must be resized, or migration timing is critical. ### Total cost Compare the target environment over a realistic period. Include: ```text VM + storage + backups + licensing + migration work + support/administration + monitoring + recovery planning ``` The cheapest VM can be the expensive choice if the surrounding operating model is weak. ## How Raff fits office server replacement Raff Technologies can support the infrastructure part of a small business server migration when the target workload fits a cloud VM model. | Requirement | Raff path | |---|---| | Linux web app, API, automation, or self-hosted software | [Linux VM](/products/linux-vm) | | Windows business software, IIS, RDP, or Windows Server workload | [Windows VM](/products/windows-vm) | | General cloud VM requirement | [Raff Cloud VM](/products/raff-vm) | | Private service-to-service communication | [VPC](/products/vpc) | | Additional persistent block storage | [Volumes](/products/volumes) | | VM backup and recovery planning | [Data Protection](/products/data-protection) | | Database without operating it on the application VM | [Managed Databases](/products/managed-databases) | Use the live [Raff pricing page](/pricing) for current plan sizes and prices rather than relying on a hard-coded figure in an evergreen migration guide. The important design principle is to migrate the workload, not blindly recreate the old server. A small Windows application may need one Windows VM. A Linux application may fit one VM plus managed database. A device-heavy office workflow may stay hybrid. :::cta Compare Raff Cloud VMs Review Linux and Windows VM options after you have documented the workload, resource requirements, licensing, and recovery plan. ::: ## Office server replacement checklist Before approving a migration, confirm: - What does the current server actually run? - Which services are still actively used? - Who owns each workload? - Which users and devices depend on it? - Which applications require Windows? - Which systems depend on Active Directory or local authentication? - Which ports and network paths are required? - Which jobs run automatically? - Which data is business-critical? - Where is the database? - How quickly is storage growing? - Which workloads depend on printers, scanners, USB, or other local hardware? - Does the software vendor support hosted/cloud operation? - What licenses are required after migration? - What is the expected CPU, RAM, storage, and user demand? - What is the acceptable downtime? - What is the acceptable data-loss window? - Has a backup restore been tested? - Who owns the new server after migration? - What would trigger rollback? - When can the old server be safely decommissioned? If the business cannot answer these questions, it is not ready for cutover. It is ready for discovery. ## Final decision For most SMBs, office server replacement should be a **workload-by-workload migration**, not a one-day move from one machine to another. Move cloud-friendly workloads first: custom web applications, internal dashboards, automation, and selected Windows business applications with clear licensing and access requirements. Delay shared file systems, hardware-linked software, and undocumented legacy workloads until their dependencies are understood. A cloud server can remove dependence on office power and aging hardware, but it also creates a new operating model. The successful migration is the one where the application, data, licensing, backup, network access, and owner are all clear before users are switched over. Continue with [Cloud Servers for Small Business](/learn/guides/cloud-servers-for-small-business), [Local Server vs Cloud Server](/learn/guides/local-server-vs-cloud-server-small-business), or the [Cloud Migration Checklist](/learn/guides/cloud-migration-checklist-small-teams). ## Sources - [Microsoft Learn — Assess physical servers for migration](https://learn.microsoft.com/en-us/azure/migrate/tutorial-assess-physical) - [Microsoft Learn — Dependency analysis in Azure Migrate](https://learn.microsoft.com/en-us/azure/migrate/concepts-dependency-visualization) - [Microsoft Learn — License Remote Desktop Services with CALs](https://learn.microsoft.com/en-us/windows-server/remote/remote-desktop-services/rds-client-access-license) - [Raff Linux VM](/products/linux-vm) - [Raff Windows VM](/products/windows-vm) - [Raff VPC](/products/vpc) - [Raff Data Protection](/products/data-protection) --- ### Cheap VPS vs Reliable VPS: What Small Teams Should Know URL: https://rafftechnologies.com/learn/guides/cheap-vps-vs-reliable-vps Description: Compare cheap VPS hosting by CPU, RAM, storage, bandwidth, backups, support, and recovery. Learn when an affordable VPS is safe for production and when to spend more. **Cheap VPS hosting can be a good production choice when the server is correctly sized, the data is recoverable, and the provider's bandwidth, storage, support, and upgrade model fit the workload.** Low price is not the reliability problem; buying a server without understanding what is included is. For small teams, the better question is not “What is the cheapest VPS?” It is **“What is the lowest-cost VPS that can run this workload safely?”** Raff Technologies offers Linux and Windows cloud VMs, but this guide does not assume Raff—or any provider—is automatically the cheapest or best choice. The goal is to help you compare an **affordable VPS** by the costs and risks that appear after deployment. If the workload is disposable, price can dominate the decision. If customers, revenue, business software, or important data depend on it, recovery time and operational effort become part of the real VPS cost. ## Cheap VPS vs reliable VPS: quick decision A cheap VPS and a reliable VPS are not opposites. | Workload | Main buying priority | What to verify before choosing the cheapest option | |---|---|---| | Learning / sandbox | Price | Root access and rebuild speed | | Temporary test VM | Price | Easy deletion/recreation | | Small personal site | Price + basic uptime | Enough RAM, backups if content matters | | Staging environment | Cost + production similarity | Runtime, storage, deployment parity | | Small API or SaaS MVP | Reliability + growth path | RAM, CPU, monitoring, backup, resize path | | Production database | Recovery + storage behavior | Memory, disk performance, backups, restore test | | Client/MSP workload | Support + predictability | Recovery, support boundary, billing, ownership | | Windows business workload | RAM + licensing + recovery | Windows fit, RDP/RDS requirements, backup | | Business-critical internal app | Downtime + recovery | Monitoring, backup, owner, recovery procedure | A practical rule: > **Disposable workload: optimize aggressively for price. Important workload: optimize for total operating risk.** ## What “cheap VPS hosting” actually means A cheap VPS is simply a virtual server sold at a low price relative to other options. The price does not tell you whether the server is suitable for your application. Two VPS plans with similar headline prices can differ in: - CPU allocation and contention; - RAM; - local vs network-backed storage; - SSD/NVMe performance; - included transfer or egress charges; - public IP pricing; - snapshot and backup options; - private networking; - operating-system licensing; - resize rules; - support scope; - region; - billing model. That is why `cheap VPS`, `affordable VPS`, and `low cost VPS` should be treated as **budget filters**, not as technical product categories. ## The cheapest VPS is safe only when the workload is cheap to fail Before comparing providers, ask what happens if the VM disappears or becomes unavailable. ### Low-consequence workloads Price can be the primary criterion when: - the server is for learning; - the environment can be rebuilt from code; - no unique production data lives on the VM; - downtime does not affect customers; - the project is temporary; - the team is comfortable self-managing the server. A small Linux development VM is a good example. If it can be recreated in an hour from Git and configuration, paying a premium for a complex recovery architecture may not create much value. ### High-consequence workloads The buying decision changes when the VM runs: - a customer-facing SaaS application; - an ecommerce or booking system; - a production database; - a client's workload; - a Windows business application; - an internal system employees depend on; - automation that affects billing, support, or operations. For these workloads, the cheapest plan is only attractive if it still has a credible monitoring, backup, restore, support, and growth path. ## 1. Compare RAM before chasing the lowest price Memory is one of the easiest ways to turn a low-cost VPS into an unstable one. The operating system, application runtime, database, reverse proxy, containers, monitoring agents, package updates, and background jobs all compete for RAM. Watch for: - sustained swap use; - out-of-memory kills; - containers restarting; - database cache pressure; - slow Windows sessions; - failed package or application updates; - memory spikes during deployments or backups. A server does not need large unused memory, but it should have enough headroom for normal peak behavior. For a more complete sizing process, use [Choosing the Right VM Size](/learn/guides/choosing-right-vm-size). ## 2. Compare CPU behavior, not just vCPU count Two plans can both advertise “2 vCPU” while behaving differently under sustained load. Ask: - Is the CPU shared or dedicated/optimized? - Does the workload use short bursts or sustained compute? - Can the VM be resized without a full migration? - Does the application become CPU-bound during builds, compression, analytics, or traffic peaks? A small website can often tolerate shared CPU. CI runners, busy APIs, data processing, game servers, or CPU-heavy databases may need more predictable compute. Do not pay for CPU you will not use, but do not assume every vCPU label represents identical performance. ## 3. Storage performance can matter more than disk capacity Cheap VPS comparisons frequently emphasize how many gigabytes are included. For active workloads, **how the storage behaves** can matter more than unused capacity. Storage pressure affects: - databases; - WordPress/CMS admin activity; - Docker layers; - application logs; - package installs; - uploads; - queues; - build caches; - backup creation. Before buying, verify: - storage type; - whether the root disk is persistent across rebuild workflows; - whether additional block storage is available; - how storage expansion works; - whether snapshots/backups include attached volumes; - what happens when disk space is exhausted. Raff offers [Volumes](/products/volumes) for workloads that need persistent block storage separate from the VM's base disk. The right storage layout depends on the application. ## 4. Bandwidth can turn an affordable VPS into an expensive one A low server price is less useful if the workload later accumulates transfer charges or hits a traffic allowance. This matters for: - public APIs; - file downloads; - websites with large media; - backups; - software distribution; - CI artifacts; - proxies and VPN workloads; - applications that transfer large amounts of data between users and the VM. When comparing VPS hosting, separate these concepts: | Network term | What it tells you | |---|---| | Port speed | Maximum interface/link capacity under provider conditions | | Included transfer | Amount of traffic included in the plan | | Egress pricing | Cost of outbound traffic beyond or outside included policy | | Private-network traffic | Cost/policy for internal traffic between resources | | Unmetered bandwidth | Transfer is not billed per GB under the provider's stated policy | Raff VM plans use a monthly billing model and include unmetered bandwidth. Check the live [Raff pricing page](/pricing) for current plan details rather than relying on an old hard-coded configuration in an evergreen guide. ## 5. Backups determine whether “cheap” survives the first incident A low-cost production VM without a recovery plan can be an expensive failure. Separate four concepts: - **application backup** — database dumps, file backups, application data; - **VM snapshot** — point-in-time infrastructure/disk state where supported; - **server image/template** — repeatable provisioning artifact; - **restore procedure** — the actual steps that return the workload to service. They are not interchangeable. Before choosing a VPS for important data, answer: 1. What data cannot be recreated? 2. How frequently does it change? 3. How much data loss is acceptable? 4. How long can the application stay offline? 5. Where are backups stored? 6. Has the team tested a restore? Raff [Data Protection](/products/data-protection) can be part of a VM recovery design, but application-level data protection still needs to match the workload. ## 6. Uptime claims are not the same as reliable architecture Provider uptime matters, but a single VPS is still a single application failure domain. A VM can be available while the application is broken because of: - a failed deployment; - full disk; - database corruption; - expired credentials or certificates; - application deadlock; - bad firewall rules; - memory exhaustion. Likewise, a provider SLA does not replace backups or redundancy. For important workloads, reliability includes: ```text provider infrastructure + correct sizing + monitoring + secure access + application health + backups + restore testing + a recovery owner ``` If the business cannot tolerate one VM being unavailable, the answer may be a multi-node architecture rather than a more expensive single VPS. ## 7. Support has an economic value Unmanaged VPS hosting assumes your team can operate the guest environment. That usually includes: - OS updates; - SSH/RDP security; - web server configuration; - application deployment; - database administration if self-hosted; - monitoring; - backups; - incident diagnosis. Provider support typically has a boundary: infrastructure issues are different from debugging your application or administering your guest OS. Before buying, verify what happens when: - the VM is unreachable; - networking appears broken; - a storage operation fails; - the server needs resizing; - the control plane behaves unexpectedly; - billing or account access blocks production work. For an MSP or small development team, reducing hours spent diagnosing provider-level problems can be worth more than a small monthly price difference. ## 8. A cheap VPS needs a practical upgrade path Starting small is good infrastructure discipline when you can observe the workload and resize deliberately. The danger is starting on a plan or platform that becomes a dead end. Check: - available larger VM sizes; - whether CPU and RAM can be resized; - whether disk expansion is supported; - whether downgrades require migration/rebuild; - whether additional VMs can communicate privately; - whether load balancing is available if the app later needs multiple nodes; - whether data can be exported cleanly if you leave the provider. The lowest-cost first month matters less if month six requires an emergency migration. ## Cheap Linux VPS: when it makes sense Linux is usually the simplest low-cost server path for: - websites; - APIs; - Node.js, Python, PHP, Go, Java, and similar runtimes; - Docker Compose; - automation; - VPNs; - self-hosted tools; - CI runners; - small databases. A [Raff Linux VM](/products/linux-vm) is relevant when the workload needs full Linux server control. Compare it against other providers on the actual resources, bandwidth policy, region, recovery model, and support boundary—not on the word “cheap.” If a managed platform can run the workload with less operational work, that may still be the better total-cost choice. ## Cheap Windows VPS requires a different calculation Windows VPS pricing and sizing cannot be evaluated exactly like a lightweight Linux VM. Consider: - Windows Server licensing; - application licensing; - RDP usage; - RDS licensing for multi-user Session Host scenarios; - higher memory needs for some Windows workloads; - SQL Server licensing where applicable; - backup and recovery for business applications. A low advertised Windows VM price can be misleading if the real workload needs additional licensing or significantly more RAM. Raff [Windows VM](/products/windows-vm) is one option for hosted Windows Server workloads, but licensing and application compatibility should be checked for the intended use before purchase. ## Can a cheap VPS be used for production? Yes—if production requirements are modest and the operating model is complete. A low-cost production VPS is reasonable when: - the measured workload fits comfortably; - the server has resource headroom; - important data is backed up; - restore steps are known; - monitoring is configured; - access is hardened; - the bandwidth policy fits expected traffic; - the application can be resized or migrated when demand grows. A small production application does not become safer because the server costs more. It becomes safer when the infrastructure and recovery plan match its business impact. ## When you should spend more Pay more when the additional cost buys something the workload actually needs. Examples: ### More RAM Useful when memory pressure is already visible or several services share the VM. ### More predictable CPU Useful for sustained compute, CI, high-traffic APIs, or CPU-sensitive applications. ### Better storage architecture Useful for databases, write-heavy services, and growing persistent data. ### Better recovery Useful when the cost of losing data or rebuilding manually is significant. ### Separate services Sometimes the right upgrade is not a larger VM. Moving the database to a separate or managed service can reduce contention and operational risk. ### Multiple application nodes If downtime tolerance is low, redundancy may be more valuable than making one server bigger. The buying principle is **pay for the risk you need to remove**, not for a larger plan because it appears more “production grade.” ## The real cost of a cheap VPS Use total cost instead of headline price. A practical model is: ```text VM + storage + backups + bandwidth/egress + public IP charges where applicable + OS/application licenses + monitoring + operator time + expected recovery/migration effort ``` That model explains why two providers with different entry prices can reverse order once the production architecture is included. For current Raff costs, use [Pricing](/pricing). For a broader cost framework, see [Cloud Server Cost in 2026](/learn/guides/cloud-server-cost-2026). ## How Raff fits the affordable VPS decision Raff Technologies is a cloud VM provider rather than a claim to be the lowest-price VPS on the market. For a buyer comparing affordable VPS options, Raff is most relevant when these characteristics match the workload: - Linux or Windows virtual machines; - monthly VM billing rather than hourly VM billing; - unmetered bandwidth; - NVMe-based VM storage; - private networking through [VPC](/products/vpc); - additional [Volumes](/products/volumes) where separate block storage is useful; - [Data Protection](/products/data-protection) for supported recovery workflows; - a VM-centered platform rather than a hyperscaler-sized service catalog. Use [Raff VM](/products/raff-vm) and [Pricing](/pricing) for the current configurations and terms. This article intentionally avoids hard-coded plan prices and temporary promotional details so the buying framework stays useful as plans change. :::cta Compare Raff VM Plans Compare current Linux and Windows VM configurations against the CPU, RAM, storage, bandwidth, recovery, and support requirements of your workload. ::: ## Cheap VPS buyer checklist Before paying for an affordable VPS, verify: - [ ] Does the VM have enough RAM for normal peak use? - [ ] Is the CPU model/allocation appropriate for sustained load? - [ ] What type of storage backs the VM? - [ ] Can storage grow independently if needed? - [ ] What traffic is included and what is billed separately? - [ ] Is public IPv4 included or separately charged? - [ ] Which region will actually host the VM? - [ ] Are snapshots/backups available? - [ ] What exactly is included in backup scope? - [ ] Has the team defined an application-level backup where needed? - [ ] Can the VM be resized without an emergency migration? - [ ] Is private networking available if the architecture grows? - [ ] What does provider support cover? - [ ] Who manages OS updates and application security? - [ ] Which Windows/application licenses are required? - [ ] How will you export data if you leave? - [ ] What is the full monthly cost after required add-ons? If a provider cannot answer the items that matter to your workload, the low entry price is not enough information to make the purchase. ## Common mistakes when shopping for cheap VPS hosting **Sorting only by monthly price.** It ignores storage, bandwidth, backup, IP, and licensing differences. **Buying the smallest RAM plan automatically.** The result can be swap pressure and instability rather than savings. **Assuming “NVMe” alone guarantees database performance.** Storage architecture and workload behavior still matter. **Treating backups as a checkbox.** A backup that has never been restored is an unproven recovery path. **Assuming an uptime SLA makes one VM highly available.** Redundancy is an architecture decision. **Ignoring support boundaries.** Know what the provider handles and what remains your responsibility. **Choosing Windows from price alone.** Licensing and memory requirements can materially change total cost. **Waiting until the VM is overloaded before planning growth.** Resize or redesign from measured trends, not after users report failure. ## Final decision: choose the lowest-cost safe VPS A cheap VPS can be exactly the right infrastructure for a small team. The goal is not to avoid inexpensive hosting; it is to avoid **false economy**. For learning, temporary testing, and easy-to-rebuild systems, optimize aggressively for price. For production, client, database, or business workloads, compare RAM, CPU behavior, storage, bandwidth, backups, support, licensing, and the growth path before deciding what “affordable” actually means. The strongest purchase is usually the **lowest-cost server whose failure and recovery model you understand**. If you still need to choose a provider, continue with [Virtual Private Server Hosting Guide](/learn/guides/virtual-private-server-hosting). If the next question is capacity, use [Choosing the Right VM Size](/learn/guides/choosing-right-vm-size). ## Sources - [Raff VM](/products/raff-vm) - [Raff Linux VM](/products/linux-vm) - [Raff Windows VM](/products/windows-vm) - [Raff Pricing](/pricing) - [Raff Data Protection](/products/data-protection) --- ### Docker VPS Hosting: What Developers Should Know URL: https://rafftechnologies.com/learn/guides/vps-for-docker-containers Description: Learn when Docker VPS hosting fits production apps, how to size a Docker host, manage Compose, volumes, networking, backups, security, and when to move to Kubernetes. **Docker VPS hosting is a strong fit when your containerized application can run safely on one virtual server and your team wants more control than a managed app platform without operating Kubernetes.** A Linux VPS can host Docker Engine, Docker Compose, a reverse proxy, application containers, workers, caches, and even a small database—provided CPU, RAM, storage, networking, backups, and recovery are designed for the whole stack. Raff Technologies provides Linux cloud VMs that can be used as self-managed Docker hosts. The important boundary is ownership: the VM provider operates the infrastructure layer, while your team remains responsible for Docker, container images, the guest OS, application configuration, persistent data, security, monitoring, and restore procedures. For many small teams, Docker Compose on one VPS is a practical production architecture. It stops being the right model when the workload needs host-level redundancy, automatic multi-node scheduling, independent scaling across many services, or a platform team that can operate an orchestrator. ## Docker VPS hosting: quick decision | Situation | Docker on one VPS | Consider another model | |---|---:|---| | Small SaaS/API | Strong fit | When one-host downtime becomes unacceptable | | Docker Compose stack | Strong fit | When services need independent node placement | | Self-hosted internal tool | Strong fit | When managed hosting removes meaningful operational work | | Staging / preview environment | Strong fit | Rarely needs Kubernetes by itself | | App + Redis + workers | Strong fit | When resource contention becomes hard to control | | Production database in a container | Possible | Separate or managed DB when recovery/scaling needs differ | | Multi-node HA application | Limited | Kubernetes or another orchestration model | | Frequent horizontal autoscaling | Limited | Managed Kubernetes / orchestration | | Many teams sharing a platform | Usually weak fit | Platform-level isolation and governance | A useful rule is: > **Use Docker on a VPS while one server remains an acceptable failure and operating boundary. Move beyond it when the architecture—not fashion—requires multiple nodes or stronger automation.** ![Decision matrix showing when Docker on a VPS fits small teams and when Kubernetes or managed container platforms may be better.](https://raff-images.s3.raffusercloud.com/docker_on_vps_decision_matrix_webp_65a79a7509.png) ## What is Docker VPS hosting? Docker VPS hosting means installing Docker Engine on a virtual private server or cloud VM and running applications as containers on that host. A small production stack might look like: ```text Internet ↓ Firewall ↓ Reverse proxy :80/:443 ↓ Docker network ├─ web ├─ api ├─ worker ├─ cache └─ database ↓ Persistent volumes + backups ``` The VPS supplies compute, memory, disk, and networking. Docker supplies application packaging and container lifecycle. Docker Compose lets a team describe several related services in one configuration. Docker's own production guidance explicitly supports running Compose applications on a single server and recommends production-specific configuration such as appropriate port bindings, environment settings, restart policies, and logging. [Docker — Use Compose in production](https://docs.docker.com/compose/how-tos/production/) Docker does **not** remove the need to operate the server. You still need to patch the host, monitor resource pressure, protect Docker access, manage backups, and know how to rebuild the environment. ## Docker Compose is often enough before Kubernetes For a small application, Compose can describe the complete service topology without adding a cluster control plane. ![Diagram showing a Docker Compose stack running on a VPS with public traffic, reverse proxy, internal Docker network, app container, database container, Redis cache, worker container, volumes, logs, and back](https://raff-images.s3.raffusercloud.com/docker_compose_on_vps_architecture_webp_c09d4d4eb8.png) A typical `compose.yaml` might include: | Service | Role | Persistent? | |---|---|---:| | reverse-proxy | TLS and public routing | Configuration/cert state may matter | | app | User-facing application | Usually replaceable | | worker | Background processing | Usually replaceable | | Redis/Valkey | Cache, queue, sessions | Depends on use | | PostgreSQL/MySQL | Database | Yes | | monitoring | Metrics/log collection | Depends on retention model | Docker Compose is usually sufficient when: - one host can meet availability requirements; - the application has a manageable number of services; - vertical scaling is acceptable; - deployments can be coordinated on one machine; - persistent data has a clear recovery strategy; - the team prefers a smaller operational surface. Kubernetes becomes more useful when scheduling and coordination across multiple nodes become real requirements. If you are evaluating that transition, read [Kubernetes vs Docker Compose for Small Teams](/learn/guides/kubernetes-vs-docker-compose-small-teams). ## Size the VPS for the whole container stack Containers share the host's finite resources. Docker does not create additional CPU, RAM, storage, or network capacity. ![Visual map showing how different Docker workloads use VPS resources including CPU, RAM, NVMe storage, bandwidth, disk I/O, logs, and volumes](https://raff-images.s3.raffusercloud.com/docker_vps_resource_pressure_map_webp_66c2638493.png) Before choosing a VPS, list every service that will normally run together: ```text host OS + Docker daemon + reverse proxy + app replicas + workers + database + cache + monitoring + backups + build or deployment activity ``` ### CPU CPU pressure can come from application requests, image builds, compression, database queries, background workers, and scheduled jobs. Watch sustained CPU saturation and queue/latency growth rather than one short spike. ### RAM Memory is often the first constraint on compact Compose stacks. Databases, caches, Node.js/JVM processes, multiple workers, and monitoring agents can make a server that looked large enough during deployment fail under normal concurrency. Watch for: - host swapping; - OOM kills; - container restart loops; - database cache pressure; - workers dying during peak load; - deployments failing because temporary memory demand is higher. ### Storage Docker uses disk for images, writable layers, named volumes, build cache, container logs, uploads, and databases. Capacity and I/O behavior both matter. ### Network Network planning includes public traffic, image pulls, backups, external APIs, database connections, and traffic between services. If the stack later spans multiple VMs, private networking becomes part of the architecture. For the broader sizing process, use [Choosing the Right VM Size](/learn/guides/choosing-right-vm-size). ## Persistent data: containers are replaceable, data is not A production Docker design should make the difference between **replaceable containers** and **persistent state** obvious. Docker documents volumes as its preferred mechanism for persisting data generated and used by containers. Volumes survive container replacement and can be backed up, restored, and migrated independently. [Docker — Volumes](https://docs.docker.com/engine/storage/volumes/) Persistent state may include: - database files; - customer uploads; - CMS media; - workflow data; - application-generated documents; - queue state where durability is required; - configuration that is not recreated from code; - retained logs where required. ![Diagram showing replaceable Docker containers and protected persistent volumes with backup storage, restore testing, and recreated VPS recovery path.](https://raff-images.s3.raffusercloud.com/docker_volumes_backup_model_webp_050df13d3f.png) A useful design rule: ```text Image + Compose definition + config → recreate the service Persistent data + backup → recover the business state ``` Do not assume a VM snapshot alone is a database backup. Database workloads may need database-aware dumps, physical backups, WAL/binlog retention, or another recovery method appropriate to the database. ## Named volumes vs bind mounts Both can be valid, but they solve different operational needs. | Storage method | Useful when | Operational concern | |---|---|---| | Named Docker volume | Docker should manage container data storage | Know where data is and how it is backed up | | Bind mount | Host path must be explicit or shared with host tooling | Host directory layout becomes part of deployment | | External/block storage | Persistent data needs a separate storage boundary | Mount/recovery behavior must be documented | | Object storage | App stores uploads, media, exports, archives | Application must support object storage semantics | | Managed database | DB operations should be separated from app VM | Network, credentials, migration, service cost | For databases, uploads, or rapidly growing state, separating persistent data from the application VM can make recovery and scaling easier. Raff [Volumes](/products/volumes) can provide additional block storage where that model fits. ## Docker networking: publish only what must be public One of the most important Docker security decisions is which ports become reachable outside the host. Docker's documentation warns that published ports are exposed outside the host by default when they are bound to all host addresses. [Docker — Port publishing and mapping](https://docs.docker.com/engine/network/port-publishing/) A common public/private pattern is: ```text Internet ↓ 80 / 443 ↓ reverse proxy ↓ internal Docker network ├─ app:3000 ├─ database:5432 ├─ cache:6379 └─ worker: no public port ``` In most web stacks: - reverse proxy: public 80/443; - app container: internal unless direct public access is intentional; - database: internal; - Redis/Valkey: internal; - worker: no public listener required; - monitoring/admin interfaces: restricted; - Docker daemon socket/API: never casually exposed. If containers on separate VMs need to communicate, use an intentional private network architecture rather than exposing backend ports publicly. Raff [VPC](/products/vpc) can be used for private communication between supported VM resources. ## A reverse proxy simplifies the public edge A reverse proxy gives multiple containers one controlled public entry point. Common options include Nginx, Caddy, Traefik, and Apache. The proxy can handle: - HTTPS termination; - domain/subdomain routing; - redirects; - headers; - compression; - WebSockets; - access controls; - routing several applications from one host. The proxy should be treated as production infrastructure. Its configuration, certificates, and deployment method should be recoverable along with the rest of the stack. ## Protect the Docker daemon Access to the Docker daemon is highly privileged. Docker's security documentation notes that users who can control the daemon can perform actions with major impact on the host. Only trusted users should have that access. [Docker — Engine security](https://docs.docker.com/engine/security/) Production controls should include: - do not publish the Docker socket/API to the internet; - limit membership in groups that can control Docker; - use SSH or properly protected TLS when remote daemon access is required; - keep Docker Engine and the host OS patched; - avoid unnecessary privileged containers; - mount the Docker socket into application containers only when there is a well-understood need; - avoid storing secrets inside images; - restrict container capabilities and filesystem access where practical. Docker also supports **rootless mode**, which runs the daemon and containers without root privileges under supported conditions. It can reduce some daemon/runtime risk, though its requirements and operational trade-offs should be tested for your workload. [Docker — Rootless mode](https://docs.docker.com/engine/security/rootless/) ## Container images are part of the security boundary A Docker VPS is only as trustworthy as the software you deploy to it. Before production: - build from known base images; - pin versions where reproducibility matters; - rebuild when base images receive security updates; - remove unused packages from images; - keep secrets out of Dockerfiles and image layers; - scan images as part of CI/CD where practical; - control who can push production images; - define how the team rolls back to a known-good image. A container image gives repeatability, not automatic trust. For the difference between container images and infrastructure images, read [Container Images vs VM Images](/learn/guides/container-images-vs-vm-images). ## Logs and Docker artifacts can fill the disk Disk exhaustion is a common single-host failure mode because several sources grow at once: - container stdout/stderr logs; - database files; - uploads; - unused images; - build cache; - stopped containers; - named volumes; - local backup files. Useful operational checks include: ```bash docker system df docker ps --all docker image ls docker volume ls ``` Do not schedule aggressive cleanup commands blindly. A volume or image that looks unused to an operator may still be part of a rollback or recovery workflow. For production, set log retention/rotation and alert before disk usage becomes an emergency. ## Back up the business state, not only the VPS A Docker backup plan should answer two separate questions: 1. Can we recreate the host and container definitions? 2. Can we restore the persistent business data? Protect what is difficult or impossible to recreate: - database state; - uploads; - Compose/config files if not in version control; - secrets through an approved secure backup path; - reverse-proxy configuration; - certificates where appropriate; - application-specific persistent volumes. Store recovery data separately from the VM when losing the VM would otherwise also lose its backup. Then test the recovery path: ```text new VM → install/configure Docker → restore Compose/config → restore persistent data → start services → validate app health → test a critical user workflow ``` Raff [Data Protection](/products/data-protection) can be one layer of infrastructure recovery. It does not remove the need for workload-aware database and application backups. ## Health checks and restart policies are not the same thing A restart policy can bring a process back after it exits. It does not prove the application is usable. For a production Compose stack, separate: - **process restart behavior**; - **container health checks**; - **external synthetic monitoring**; - **dependency monitoring**. For example, a container can be running while its database connection is broken or its user-facing endpoint returns errors. Use [Server Health Checks Explained](/learn/guides/server-health-checks-explained-liveness-readiness-and-synthetic-monitoring) for the broader health model. ## Should the database run in Docker on the same VPS? It can, especially for an early application, but the decision should be explicit. A same-host database keeps architecture simple. It also means application compute, workers, Docker activity, logs, and database I/O share one failure and resource boundary. Keep the database on the same VPS when: - the workload is small and understood; - one-host availability is acceptable; - backup and restore are tested; - resource contention is low; - the team values simplicity. Separate or use a managed database when: - database recovery has a different RPO/RTO; - memory or storage pressure dominates the host; - independent resizing is useful; - app deployments should not affect database resources; - availability requirements exceed one server. For the decision framework, see [VPS for Databases](/learn/guides/vps-for-databases) or [Raff Managed Databases](/products/managed-databases). ## When Docker on one VPS stops being enough A Docker VPS becomes the wrong operating boundary when the application needs capabilities that depend on several hosts. Signals include: - one-host failure is no longer acceptable; - several app replicas must survive host failure; - services need independent autoscaling; - deployments need automated scheduling across nodes; - the platform has many teams or workloads; - service discovery and network policy are becoming operational problems; - the team needs cluster-level rollout and placement controls; - managing several independent Docker hosts has become fragile. At that stage, [Managed Kubernetes](/products/kubernetes) may be a better architecture. Kubernetes adds operational concepts and should solve a real scaling or reliability problem—not simply replace a Compose file because the application uses containers. ## Docker VPS cost: compare the whole stack The cost of Docker hosting includes more than the base VM: ```text VM + persistent storage + backups + network policy / transfer where applicable + monitoring + database layer + image registry if used + operator time + expected recovery effort ``` Docker can lower deployment friction while increasing service density. That makes it easy to keep adding containers until the host is difficult to size or recover. The right question is not “what is the cheapest VPS that runs Docker?” It is: > **What is the lowest-cost host that gives this container stack enough headroom and a credible recovery path?** ## How Raff fits Docker VPS hosting Raff Technologies fits the self-managed Docker-on-VM model for teams that want a Linux server rather than a fully managed container runtime. A practical path can use: | Need | Raff path | |---|---| | Docker host | [Linux VM](/products/linux-vm) or [Raff VM](/products/raff-vm) | | Additional block storage | [Volumes](/products/volumes) | | Private traffic between VMs | [VPC](/products/vpc) | | Infrastructure recovery | [Data Protection](/products/data-protection) | | Multi-node orchestration later | [Managed Kubernetes](/products/kubernetes) | Raff VM billing is monthly rather than hourly. Current configurations and prices should be checked on [Pricing](/pricing) instead of relying on static plan figures inside this guide. Raff provides the VM and surrounding infrastructure controls. Your team remains responsible for Docker Engine, Compose, images, container configuration, application security, data protection at the workload layer, and day-to-day container operations. :::cta Deploy a Linux VM Run a Docker or Docker Compose stack on a Raff Linux VM when one server is still the right operational boundary for your application. ::: ## Docker VPS production checklist Before treating a Docker VPS as production infrastructure, confirm: - [ ] Every running service is documented. - [ ] CPU and RAM are sized for the full stack, not one container. - [ ] Persistent volumes are identified. - [ ] Database and upload recovery are tested. - [ ] Only required ports are published. - [ ] Backend services are not unnecessarily public. - [ ] Docker daemon access is restricted. - [ ] Images come from controlled sources. - [ ] Secrets are not baked into images or committed to source control. - [ ] Container and host logs have retention limits. - [ ] Disk usage is monitored. - [ ] Host OS and Docker updates have an owner. - [ ] Health monitoring tests user-facing behavior. - [ ] A failed deployment has a rollback path. - [ ] The team knows when one VPS will no longer meet availability requirements. ## Final decision Docker VPS hosting is a strong production model for small and moderate container stacks when **one VM is still an acceptable compute, failure, and recovery boundary**. Use Docker Compose to keep the deployment repeatable, keep only the public edge exposed, treat volumes and databases as protected state, secure Docker daemon access, monitor host pressure, and rehearse recovery onto a replacement VM. Do not add Kubernetes merely because the application uses containers. Add orchestration when multiple nodes, independent scaling, placement, or availability requirements make the extra platform layer useful. For small teams, a well-operated Docker VPS can remain simpler than a cluster while still providing a clear path toward [Raff Managed Kubernetes](/products/kubernetes) when the workload eventually needs it. ## Sources - [Docker — Use Compose in production](https://docs.docker.com/compose/how-tos/production/) - [Docker — Volumes](https://docs.docker.com/engine/storage/volumes/) - [Docker — Port publishing and mapping](https://docs.docker.com/engine/network/port-publishing/) - [Docker — Engine security](https://docs.docker.com/engine/security/) - [Docker — Rootless mode](https://docs.docker.com/engine/security/rootless/) - [Raff Linux VM](/products/linux-vm) - [Raff Managed Kubernetes](/products/kubernetes) --- ### RDP VPS Pricing: What Actually Affects Cost? URL: https://rafftechnologies.com/learn/guides/rdp-vps-pricing-cost-factors Description: Understand RDP VPS pricing by Windows VM size, concurrent users, storage, backups, Windows licensing, RDS CALs or SALs, support, and recovery requirements. **RDP VPS pricing should be calculated from the Windows workload, not from the cheapest server plan.** The real monthly cost can include the Windows VM, CPU and RAM, storage, backups, Windows Server licensing, Remote Desktop Services licensing for multi-user Session Host deployments, application licenses, support, and the operational cost of keeping business users productive. Raff Technologies provides Windows cloud VMs for hosted Windows workloads. A lightweight server used occasionally by an administrator has a very different cost profile from a Remote Desktop Session Host used every day by several employees running accounting software, browsers, SQL tools, or line-of-business applications. The fastest way to compare plans is to start with **concurrent activity, application requirements, data/recovery needs, and licensing model**. Only then compare the VM price. ## RDP VPS pricing: quick cost model A practical budget looks like: ```text Windows VM + additional storage + backup / recovery + RDS licensing if required + application licensing + monitoring / security tooling + support / administration ``` | Workload | Main cost drivers | |---|---| | Occasional server administration | Windows VM size, security, backup | | One user running a business app | RAM, application requirements, storage, backup | | Several daily remote users | CPU, RAM, RDS licensing, profiles, support | | Accounting / ERP workload | RAM, storage, application licensing, backup, support | | SQL-backed Windows app | RAM, storage I/O, SQL licensing/operations, recovery | | IIS / ASP.NET workload | CPU/RAM, traffic, app/database architecture | | MSP-managed customer server | Predictability, support, backup, licensing, operational ownership | The lowest advertised Windows VPS price can be a useful starting point, but it is not the total cost of a production Remote Desktop environment. ## RDP VPS vs Windows VPS: what are you paying for? **RDP is an access protocol; the VPS is the server.** Buying an “RDP VPS” normally means buying a Windows virtual server and connecting to it with Remote Desktop. The infrastructure cost is driven by the Windows VM underneath that session: - vCPU; - RAM; - storage; - network; - Windows Server licensing model; - backup and recovery; - support; - application requirements. For multi-user desktop or RemoteApp scenarios, Remote Desktop Services becomes a separate licensing and architecture decision. This distinction prevents a common buying mistake: assuming that because one administrator can connect through RDP, the server is automatically licensed and sized as a shared desktop for several employees. ## CPU cost: size for what users actually do Remote Desktop responsiveness depends on the applications running inside the session. CPU pressure can come from: - multiple browser sessions; - accounting or ERP applications; - PowerShell automation; - IIS / .NET applications; - report generation; - antivirus/security scans; - scheduled tasks; - SQL tools or local database work; - compression and file processing. An admin-only server may spend most of its time idle. A server used as an everyday workspace can create sustained CPU demand during business hours. Do not size from the number of named users alone. Size from **concurrent users and concurrent work**. ## RAM is often the first Remote Desktop bottleneck Windows Server, applications, user sessions, browsers, security software, monitoring agents, and database services all consume memory. This makes RAM one of the most important Windows VPS cost factors. Watch for: - growing pagefile use; - slow session logins; - applications closing unexpectedly; - browser tabs becoming unresponsive; - database memory pressure; - poor performance during updates or backup operations. A useful planning formula is: ```text OS baseline + application/service memory + active-session memory + security/monitoring + peak headroom ``` There is no reliable “X GB per RDP user” rule that fits every workload. One user running a heavy browser, Excel workbook, ERP client, or SQL tool may consume more memory than several lightweight administrative sessions. ## Storage affects both price and user experience Windows VPS storage is used by more than the operating system. Plan for: - Windows updates; - installed applications; - user profiles; - documents and exports; - application data; - IIS logs; - temporary files; - database files; - backup staging; - profile caches. For business software, storage growth should be measured rather than guessed. Before choosing a plan, ask: 1. How large is the current application and data set? 2. Do users save files on the server? 3. Is a database running locally? 4. How quickly is data growing? 5. Can storage expand separately from compute? 6. What happens to the workload if the system disk becomes full? 7. Is important data backed up independently? Raff [Volumes](/products/volumes) can provide additional block storage for workloads that benefit from separating persistent storage from the base VM design. ## Windows Server licensing belongs in the comparison Windows VPS pricing should make the Windows licensing model clear. A buyer should confirm: - which Windows Server versions are available; - how the provider licenses hosted Windows Server; - whether Windows licensing is included in the quoted VM price or represented separately; - whether the planned application has its own Windows/version requirements; - whether additional Microsoft or third-party licenses are needed. Do not assume that the cheapest Linux VPS price on a provider's site also represents the cost of a Windows workload. For Raff-specific licensing context, see [Windows Server Licensing for Hosted VMs](/learn/guides/why-microsoft-licensing-matters-windows-vm-provide). ## RDS licensing changes multi-user Remote Desktop cost A Windows Server VM used as a multi-user Remote Desktop Services environment needs licensing planning beyond the base Windows Server workload. Microsoft documents RDS CALs in **Per User** and **Per Device** models for standard RDS deployments. Microsoft also notes that the RDS CAL version must be compatible with the Windows Server Session Host version; for example, an older RDS CAL cannot license access to a newer Session Host version. [Microsoft — RDS CAL licensing](https://learn.microsoft.com/en-us/windows-server/remote/remote-desktop-services/rds-client-access-license) For service-provider hosted scenarios, Microsoft documents service-provider licensing options such as per-user SALs through the applicable provider licensing channel. [Microsoft — RDS payment/licensing options](https://learn.microsoft.com/en-us/windows-server/remote/remote-desktop-services/rds-plan-choose-how-you-pay) The commercial implication is important: | Access model | What to plan | |---|---| | Server administration | Windows Server administrative access model | | Dedicated business app for one user | VM + application/license requirements | | Multiple employees using RD Session Host | RDS licensing + concurrency + profiles + support | | Hosted desktop offered by an MSP/provider | Provider licensing model + authorized users + operations | Do not buy a VM first and investigate RDS licensing after users are already working on it. ## Per-user vs per-device RDS licensing Microsoft's standard RDS licensing model supports Per User and Per Device CALs. The suitable model depends on how people access the Session Host. **Per User** can fit when one employee connects from several devices. **Per Device** can fit when several employees share a smaller set of devices. The server also needs an appropriately configured RD Licensing service and compatible licenses for the Session Host deployment. [Microsoft — License Remote Desktop Session Hosts](https://learn.microsoft.com/en-us/windows-server/remote/remote-desktop-services/rds-license-session-hosts) For hosted/provider scenarios, licensing terms can differ from a customer's own RDS CAL deployment. That distinction should be confirmed before production. ## Concurrent users matter more than company headcount Suppose two companies each have ten employees. Company A has one accountant who connects to the Windows VM for an hour per day. Company B has eight staff members working in Remote Desktop throughout the day with browsers and business software open. They do not need the same server. When estimating cost, record: - authorized users; - expected concurrent users; - typical session duration; - application mix; - peak CPU/RAM periods; - user-profile size; - file-transfer behavior; - printing or redirection requirements; - database usage. This gives you a much better starting point for VM sizing and licensing than total employee count. ## Application licensing can outweigh the VM price The Windows VPS is only the infrastructure layer. Applications may have separate terms for hosted, server, concurrent-user, subscription, or remote-access use. Common examples include: - SQL Server; - Microsoft applications; - accounting software; - ERP systems; - QuickBooks or Sage-type workloads; - industry-specific software; - security products. Do not assume that installing software on a licensed Windows Server automatically licenses the application itself. For buyer planning, separate the budget into: ```text Windows infrastructure RDS access where required application licenses support/management backup/recovery ``` ## Backups and recovery are part of RDP VPS cost A business Remote Desktop server can quietly become the place where users store company files, reports, exports, profiles, or application data. That makes recovery a financial requirement, not an optional feature. Define: - what data must be protected; - how often it changes; - acceptable data loss (RPO); - acceptable downtime (RTO); - whether the application needs database-aware backup; - who can perform a restore; - how the restored environment is validated. A VM snapshot and an application/database backup solve different problems. Raff [Data Protection](/products/data-protection) can be part of the infrastructure recovery design. Workload-specific application or database backups may still be required. ## Support changes the real business cost For a development VM, waiting for an infrastructure problem may be inconvenient. For a Windows server that employees use to perform daily work, the same outage can stop billing, accounting, customer support, or operations. When comparing providers, ask what support can help with and where the boundary sits. Typical provider-level questions include: - Is the VM reachable at the infrastructure layer? - Is networking functioning? - Is storage attached correctly? - Can the VM be resized? - Is the platform experiencing an incident? Application-level Windows administration, RDS configuration, SQL tuning, and third-party software support may remain your responsibility or require an MSP. The cheaper VM is not automatically cheaper if your team spends more time diagnosing infrastructure ambiguity. ## Network and bandwidth: usually not the first bottleneck, but still relevant Interactive RDP traffic is often modest compared with video delivery, but a Remote Desktop server may also handle: - file uploads/downloads; - Windows updates; - browser traffic generated inside sessions; - cloud sync; - database/API traffic; - backups; - software installers; - report exports. Compare the provider's current network and transfer policy instead of assuming every Windows VPS includes the same traffic model. Raff currently uses monthly VM billing and unmetered bandwidth for its VM plans. Use [Pricing](/pricing) for current plan details rather than a static price or port-speed claim in this evergreen guide. ## Cheap RDP VPS vs production Windows VPS Low-cost RDP VPS hosting can be sensible for low-risk workloads. ### Price-first workloads - testing; - learning; - temporary Windows administration; - one lightweight app; - disposable environments. ### Reliability-first workloads - daily employee access; - accounting or ERP; - client workloads; - business files; - hosted line-of-business software; - SQL-backed applications; - workloads where downtime stops work. The distinction is **cost of failure**. If the VM can be recreated without business impact, optimize harder for price. If employees and customer operations depend on it, include recovery, licensing, support, and headroom in the purchase decision. ## A practical Windows VPS sizing workflow Do not choose a Windows VM only from a provider's plan names. Use this process: ### 1. Inventory the workload List applications, services, databases, scheduled tasks, security tools, users, and stored data. ### 2. Separate users from concurrent users Record how many people are authorized and how many are active at the same time. ### 3. Measure current resource use when migrating If you are moving an existing server, capture normal and peak CPU, memory, disk, and storage growth. ### 4. Add headroom Size for real peaks, updates, backups, scans, and user concurrency—not the quietest five minutes of the day. ### 5. Validate licensing Confirm Windows, RDS, SQL Server, Microsoft applications, and third-party software before production. ### 6. Test the real workflow Run the business application with representative users. Do not approve the VM because the desktop itself feels responsive. ### 7. Monitor and resize from evidence After launch, monitor memory pressure, CPU saturation, storage growth, login experience, application response time, and backup success. ## How Raff fits the RDP VPS pricing decision Raff Technologies provides [Windows VMs](/products/windows-vm) for hosted Windows Server workloads. A buyer evaluating Raff for RDP should map the workload to the infrastructure it actually needs: | Need | Raff path | |---|---| | Windows Server VM | [Windows VM](/products/windows-vm) | | General VM comparison | [Raff VM](/products/raff-vm) | | Additional block storage | [Volumes](/products/volumes) | | VM recovery planning | [Data Protection](/products/data-protection) | | Private connectivity to other VMs/services | [VPC](/products/vpc) | | Current monthly VM pricing | [Pricing](/pricing) | Raff VM billing is monthly rather than hourly. Do not use old hard-coded plan prices when estimating a deployment; the live pricing page is the source for current configurations. For multi-user Windows workloads, plan licensing separately from VM sizing. Raff infrastructure can host the Windows workload, while the exact RDS and application licensing path must match the deployment model. :::cta Compare Windows VM Plans Review current Raff Windows VM options after you know the concurrent users, application requirements, storage, backup, and licensing model for the workload. ::: ## RDP VPS buyer checklist Before purchasing a Windows VPS for Remote Desktop, confirm: - [ ] Which applications will run on the server? - [ ] How many users are authorized? - [ ] How many users are concurrent at peak? - [ ] Is this administration or an RD Session Host workload? - [ ] What Windows Server version does the application support? - [ ] Which RDS licensing model applies? - [ ] Are RDS CAL/SAL versions compatible with the Session Host? - [ ] Does SQL Server or another application require separate licensing? - [ ] How much RAM does the complete workload need? - [ ] How quickly will user/application data grow? - [ ] Where will backups be stored? - [ ] Has restore been tested? - [ ] What provider support is included? - [ ] Who owns Windows/RDS/application administration? - [ ] Can the VM and storage grow without an emergency migration? - [ ] What is the complete monthly cost after licensing and recovery requirements? ## Common RDP VPS pricing mistakes **Comparing Linux entry pricing to a Windows workload.** The OS, resource profile, and licensing are different. **Treating RDP as a multi-user license.** Remote connectivity and RDS licensing are separate concepts. **Sizing from employee count.** Concurrent activity and application behavior matter more. **Buying too little RAM.** Windows workloads often become memory-constrained before buyers expect it. **Ignoring application licenses.** VM pricing does not license SQL Server, accounting software, or other commercial applications automatically. **Adding backups later.** Production data may become business-critical before anyone notices the recovery gap. **Using stale price/spec claims from an old guide.** Compare current provider pricing and product terms at purchase time. ## Final decision RDP VPS pricing is best understood as the total cost of a **Windows workload delivered through Remote Desktop**, not as a single server-plan number. Start with the applications and concurrent users. Then calculate Windows VM resources, storage, recovery, RDS licensing where required, application licensing, and the operational support model. For low-risk admin or test workloads, a small Windows VM may be enough. For daily multi-user business software, the correct purchase is the configuration that gives users adequate performance and gives the business a credible licensing, backup, support, and recovery path. Use [Raff Windows VM](/products/windows-vm) and [Pricing](/pricing) for current infrastructure options, and validate the Microsoft/application licensing model before production. ## Sources - [Microsoft — License Remote Desktop Services with CALs](https://learn.microsoft.com/en-us/windows-server/remote/remote-desktop-services/rds-client-access-license) - [Microsoft — License Remote Desktop Session Hosts](https://learn.microsoft.com/en-us/windows-server/remote/remote-desktop-services/rds-license-session-hosts) - [Microsoft — Remote Desktop Services licensing options](https://learn.microsoft.com/en-us/windows-server/remote/remote-desktop-services/rds-plan-choose-how-you-pay) - [Raff Windows VM](/products/windows-vm) - [Raff Pricing](/pricing) --- ### K3s vs K8s: Differences, Trade-Offs, and When to Use Each URL: https://rafftechnologies.com/learn/guides/k3s-vs-full-kubernetes-cluster-model Description: K3s is Kubernetes, not a separate orchestrator. Compare K3s vs K8s on resource footprint, HA, customization, production use, and self-managed vs managed ownership. **K3s vs K8s is mainly a packaging and operational-ownership decision, not a compatibility decision.** K3s is a fully compliant Kubernetes distribution, while K8s is simply shorthand for Kubernetes. For a small team that wants Kubernetes APIs and scheduling without assembling every cluster component separately, K3s can reduce the amount of platform integration work. A more explicit self-managed Kubernetes setup, commonly bootstrapped with tools such as kubeadm, gives a platform team more control over networking, storage, ingress, policy, and lifecycle choices. Managed Kubernetes is a third option when the workload model matters but control-plane ownership does not. At **Raff Technologies**, we frame this choice around the work your team wants to own after deployment. This guide owns the **K3s vs K8s decision**: differences, resource footprint, HA, customization, production use, and when managed Kubernetes changes the answer. For implementation details, use the dedicated K3s architecture, HA, networking, storage, and upgrade guides linked throughout this page. ## K3s vs K8s at a glance K3s is not a smaller alternative to Kubernetes in the sense of a different orchestrator. It is Kubernetes packaged with a narrower operating surface and more defaults included. | Decision area | K3s | Self-managed kubeadm-style K8s | Managed Kubernetes | |---|---|---|---| | Kubernetes API | Kubernetes-conformant | Kubernetes-conformant | Kubernetes-conformant service model | | Initial setup | More components packaged together | More components selected and integrated by the operator | Provider operates the control plane | | Default components | Includes common networking, DNS, ingress, service LB, storage helper, runtime, and utilities | Operator chooses more of the surrounding stack | Depends on provider | | Single-node path | Straightforward | Possible, but more assembly is usually required | Usually not the target operating model | | Default simple datastore | SQLite on a normal single-server K3s install | etcd is the normal upstream control-plane datastore | Provider-owned control-plane datastore | | HA ownership | Team-owned | Team-owned | Provider-owned control-plane HA boundary | | Customization | High, but starts opinionated | Highest control from the start | More service boundaries and provider conventions | | Upgrade responsibility | Team-owned | Team-owned | Control plane is provider-operated; workloads still belong to the customer | | Best fit | Small teams, edge, labs, focused production platforms | Teams with explicit platform standards | Teams that want Kubernetes without operating the control plane | The practical shortcut is: ```text Choose K3s when you want Kubernetes but fewer integration decisions. Choose kubeadm-style K8s when cluster composition itself needs to follow your platform standards. Choose managed Kubernetes when you want the Kubernetes workload model without owning the control plane. ``` ## What is the actual difference between K3s and K8s? **K8s means Kubernetes. K3s is a Kubernetes distribution.** That makes the common search “K3s vs K8s” slightly misleading. The useful comparison is not whether one can run Kubernetes workloads and the other cannot. The useful comparison is how Kubernetes is packaged, which components arrive by default, and how much cluster composition your team must own. K3s packages the Kubernetes control plane and common supporting components into a compact distribution. Current K3s documentation includes components and integrations such as containerd, Flannel, CoreDNS, Traefik, ServiceLB, network policy, local-path storage provisioning, and supporting utilities. Many of those defaults can be disabled or replaced. A kubeadm-style installation takes a more explicit approach. Kubeadm bootstraps a conformant Kubernetes cluster, but the operator is expected to make more surrounding infrastructure choices, including the container runtime, CNI, ingress, storage, load balancing, observability, and lifecycle model. So the difference is better described as: ```text K3s = Kubernetes + packaged defaults + smaller integration surface Kubeadm-style K8s = Kubernetes + more explicit platform assembly ``` Neither model is “more real” Kubernetes. The difference is how much surrounding platform work is pre-packaged versus deliberately assembled by your team. ## K3s has a smaller resource and operating footprint, but workloads still dominate sizing K3s is designed for a lighter operating footprint, but it is important not to turn that into an unrealistic performance claim. Current K3s requirements list these baseline minimums before application workload capacity is added: - **K3s server:** 2 CPU cores and 2 GB RAM - **K3s agent:** 1 CPU core and 512 MB RAM K3s also recommends SSD-backed storage because datastore performance affects cluster behavior, particularly when etcd is involved. Its current resource-profile testing shows roughly 1.6 GB of RAM for a tested K3s server running a simple workload under the documented Intel test environment. Treat that as a K3s engineering reference, not as a universal production sizing promise. Kubeadm documentation currently calls for at least **2 GiB RAM per machine** and **2 CPUs on the control-plane machine** when creating a cluster. That is also a bootstrap requirement, not a production capacity target. The important point is that these numbers are not a clean benchmark proving one distribution makes your application faster. Production capacity still depends on: - application CPU and memory demand; - number and size of Pods; - ingress traffic; - database and storage I/O; - observability agents; - control-plane topology; - rescheduling headroom; - upgrade and failure capacity. If you need the actual self-managed topology rather than this distribution comparison, continue with [K3s on Cloud VMs: Architecture, HA, Storage, and Operations](/learn/guides/k3s-on-cloud-vms-architecture-ha-storage-operations). ## K3s is easier to start because more decisions have defaults A normal K3s installation can give a small team a working Kubernetes cluster without first selecting every cluster subsystem. A single K3s server can run the datastore, control-plane components, kubelet, container runtime, and application workloads required for a functional single-node cluster. That makes K3s attractive for: - development and CI clusters; - edge deployments; - internal platforms operated by a small team; - small production systems with an explicit recovery plan; - teams learning Kubernetes on real infrastructure; - teams that need multi-node scheduling but do not need a custom platform stack from day one. The benefit is not that K3s removes Kubernetes concepts. Your team still needs to understand Pods, Services, storage, networking, security, resources, upgrades, and recovery. The benefit is that the distribution reduces how many integration decisions must be solved before the cluster becomes usable. For a small engineering team, that can be a meaningful operational advantage. Fewer independently selected platform components means fewer integration boundaries to document, upgrade, and troubleshoot. ## Standard self-managed K8s fits teams that need explicit platform control A kubeadm-style Kubernetes model becomes more useful when the platform itself needs to follow organization-specific standards. That can include requirements around: - a specific CNI and network-policy model; - ingress or Gateway implementation; - storage classes and CSI platform; - control-plane topology; - cluster add-ons and observability; - admission and policy controls; - identity and administrative access; - upgrade automation; - multi-cluster conventions; - security baselines shared across several teams. The benefit is control and standardization. The cost is ownership. Every platform choice becomes something the team must be able to install, validate, upgrade, monitor, back up where relevant, and recover during an incident. This is why the more configurable option is not automatically the more mature option. A custom stack is valuable when it implements real requirements. If the reason for customization is only “we may need it later,” the team can create platform work before it has a platform problem. ## High availability does not disappear because K3s is lightweight K3s reduces packaging complexity, not distributed-systems requirements. A normal single-server K3s installation uses embedded SQLite by default. That is simple, but it is not a highly available control plane. For **HA with embedded etcd**, current K3s documentation requires **three or more server nodes** and an odd number of servers so etcd can maintain quorum correctly. K3s also supports an HA model with an external datastore. That separates datastore ownership from the K3s server set, but the external database must then have its own availability, backup, monitoring, and recovery design. The decision therefore changes from: ```text Can K3s run on one small server? ``` to: ```text What failure must this production cluster survive, and who owns recovery when that failure occurs? ``` That question matters more than the “lightweight” label. For the detailed datastore decision, use [K3s High Availability: Embedded etcd vs External Database](/learn/guides/k3s-high-availability-embedded-etcd-vs-external-database). That page owns SQLite, embedded-etcd quorum, external PostgreSQL/MySQL/etcd, and backup architecture so this comparison does not duplicate it. ## Is K3s production-ready? Yes, K3s can be used for production workloads, but **production readiness comes from the architecture and operating process, not from the distribution name**. Before using either K3s or another self-managed Kubernetes distribution for an important workload, document at least: | Production question | Decision your team needs | |---|---| | Control-plane failure | Single-server recovery or HA topology | | Datastore | Backend, performance, backup, and restore process | | Networking | Private cluster paths, public exposure, firewall rules | | Ingress | Traffic entry, TLS, and failure behavior | | Persistent data | Storage failure model and backup boundary | | Administrative access | Who can reach and administer the cluster | | Secrets | Storage, access, rotation, and recovery | | Upgrades | Supported version path and maintenance process | | Observability | Cluster, node, workload, and datastore signals | | Recovery | Tested control-plane and application recovery procedure | K3s gives you a smaller starting surface. It does not replace these decisions. The detailed member guides cover the areas that should not be expanded inside a K3s-vs-K8s comparison: - [K3s Networking, Ingress, and Load Balancing](/learn/guides/k3s-networking-ingress-load-balancing) - [K3s Persistent Storage and Backup Strategy](/learn/guides/k3s-persistent-storage-backup-strategy) - [K3s Upgrade and Rollback Strategy](/learn/guides/k3s-upgrade-rollback-strategy) ## When should a small team choose K3s? K3s is a strong option when your team has already justified Kubernetes but wants to keep cluster composition relatively simple. Choose K3s when most of these are true: - you need Kubernetes scheduling or APIs; - a small infrastructure team owns the environment; - packaged defaults cover most requirements; - you do not need a deeply customized platform stack on day one; - self-managing the control plane is an intentional responsibility; - the team is prepared to own backups, upgrades, security, networking, and recovery; - edge, lab, CI, or resource-conscious deployment is part of the use case. A useful warning is that **K3s should not be the answer to “we want Kubernetes because Kubernetes is standard.”** If Docker or Docker Compose still solves the deployment problem cleanly, adding any Kubernetes distribution creates a new control plane and operating model. Use [Kubernetes vs Docker Compose for Small Teams](/learn/guides/kubernetes-vs-docker-compose-small-teams) if you have not yet proven that orchestration is necessary. ## When should a platform team choose kubeadm-style K8s? A more explicit self-managed Kubernetes stack is stronger when platform composition itself is part of the requirement. Choose that direction when most of these are true: - several teams depend on shared cluster standards; - networking, storage, identity, policy, or observability must follow organization-wide architecture; - the team operates multiple clusters with repeatable automation; - Kubernetes is a first-class internal platform rather than only an application scheduler; - custom add-ons and lifecycle controls solve named requirements; - platform engineers already own cluster upgrades, security, incident response, and recovery. In that environment, the extra integration surface can be justified because the organization is intentionally building and operating a platform. ## When should you use managed Kubernetes instead of K3s or kubeadm? Managed Kubernetes changes the most important variable: **who owns the control plane**. If your product needs Kubernetes scheduling, Services, Deployments, autoscaling, and ecosystem compatibility, but your team does not gain meaningful product value from operating API servers, control-plane availability, datastore lifecycle, and control-plane upgrades, a managed service can be a cleaner boundary. You still own important application responsibilities such as: - workload manifests and releases; - resource requests and limits; - application security and secrets; - worker capacity decisions; - persistent application data; - application monitoring; - application backup and recovery. Managed Kubernetes does not make platform operations disappear. It moves a defined part of them to the provider. This is why the K3s vs K8s decision should include managed Kubernetes before the team commits to months of self-managed cluster lifecycle work. :::cta Explore Raff Kubernetes Compare Raff Managed Kubernetes with self-managed K3s before deciding how much control-plane ownership your team should carry. ::: ## K3s vs K8s on Raff: compare ownership before price Raff supports both self-managed and managed Kubernetes paths. For **self-managed K3s or kubeadm-style Kubernetes**, a team can use [Raff VMs](/products/raff-vm). Current General Purpose pricing lists a **2 vCPU / 4 GB / 80 GB NVMe VM at $17.99/month**. For K3s, that is above the current documented 2-core/2-GB server minimum, but application capacity must still be sized separately. For teams that want Kubernetes without owning the control plane, [Raff Kubernetes](/products/kubernetes) currently lists: - **standard control plane: $0/month**; - **2 vCPU / 4 GB worker: $17.99/month**; - **optional three-master HA control plane: $30/month**. That makes an equal-size VM and worker-node price comparison useful, but incomplete. The real comparison is: ```text Self-managed K3s on Raff VMs = VM cost + your team's control-plane operations Self-managed kubeadm-style K8s on Raff VMs = VM cost + broader platform assembly + your team's control-plane operations Raff Managed Kubernetes = worker-node cost + Raff-operated control-plane boundary ``` For a small team, engineering time, incident ownership, upgrades, and recovery can matter more than a small difference in infrastructure price. Product and pricing details verified: **2026-09-16**. Check the live [Raff Pricing](/pricing) and [Raff Kubernetes](/products/kubernetes) pages before purchase because plans can change. ## K3s vs K8s decision checklist Choose **K3s** if: - Kubernetes is justified; - you want a smaller self-managed operating surface; - packaged defaults fit most requirements; - your team accepts control-plane ownership; - you can document HA, backup, upgrade, and recovery procedures. Choose **kubeadm-style self-managed Kubernetes** if: - platform customization is a requirement rather than a future possibility; - your team already operates Kubernetes as a platform; - networking, storage, security, and add-ons need explicit standards; - you have repeatable lifecycle automation and clear cluster ownership. Choose **managed Kubernetes** if: - Kubernetes workloads matter more than control-plane customization; - control-plane operations are not product differentiation; - your team would rather spend its infrastructure time on workloads, capacity, reliability, and application delivery. ## Conclusion The useful answer to **K3s vs K8s** is not “lightweight Kubernetes versus full Kubernetes.” K3s **is Kubernetes**. The real decision is how much packaging, customization, and control-plane responsibility your team should own. K3s reduces integration work through packaged defaults and a smaller operating surface. A kubeadm-style model exposes more platform choices when those choices need to be standardized explicitly. Managed Kubernetes changes the responsibility boundary when the Kubernetes workload model matters but self-managing the control plane does not. Choose the smallest operating model that still meets your availability, security, recovery, and platform requirements. Then expand the platform only when a real requirement justifies the additional moving parts. ### Sources - [K3s documentation](https://docs.k3s.io/) - [K3s requirements](https://docs.k3s.io/installation/requirements) - [K3s resource profiling](https://docs.k3s.io/reference/resource-profiling) - [K3s cluster datastore](https://docs.k3s.io/datastore) - [K3s high availability with embedded etcd](https://docs.k3s.io/datastore/ha-embedded) - [Kubernetes: Creating a cluster with kubeadm](https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/create-cluster-kubeadm/) - [Kubernetes production environment](https://kubernetes.io/docs/setup/production-environment/) - [Raff Kubernetes](/products/kubernetes) - [Raff Pricing](/pricing) - Technical and product details reviewed: 2026-09-16 --- ### Cloud Storage Architecture for Production Apps: Backup & Recovery URL: https://rafftechnologies.com/learn/guides/storage-recovery-architecture-production-apps Description: Design cloud storage architecture for production apps using VM disks, block storage, object storage, databases, backups, RPO/RTO, and tested recovery paths. **Cloud storage architecture is the way a production application separates runtime disks, persistent block storage, databases, durable files, backups, and restore paths so one failure does not turn into a data-recovery problem.** For most small teams, the strongest default is simple: keep the VM replaceable, keep durable files outside the VM lifecycle, give stateful services an explicit storage owner, and design backups from the recovery target rather than from whatever storage happens to be easiest to snapshot. At **Raff Technologies**, that usually means combining the infrastructure layers according to what the data actually needs: a VM for application runtime, Volumes for disk-like persistent data, Object Storage for durable file objects and archives, Managed Databases when the database host should not be your responsibility, and Data Protection for VM recovery points. The goal is not to use every storage product. It is to make sure each important byte has one clear home and one tested path back after failure. ![Architecture diagram showing VM disk Raff Volumes Object Storage Data Protection and restore testing responsibilities](https://raff-images.s3.raffusercloud.com/production_storage_responsibility_map_webp_76b0f2f098.png) ## Cloud storage architecture at a glance Start by classifying data by behavior rather than by file extension. | Data or workload | Better default | Why | |---|---|---| | Operating system and app runtime | VM disk | Rebuildable with the server | | Temporary files and caches | VM disk | Disposable when bounded and cleaned up | | Database data directory | Managed database or block volume | Stateful data needs an explicit recovery model | | Container persistent state | Block volume | Needs filesystem semantics outside the container lifecycle | | User uploads and media | Object storage | Should survive VM replacement and scale independently | | Generated exports and reports | Object storage | Durable objects do not need to live on an app server | | Backup exports and archives | Object storage or dedicated backup target | Recovery copies should not depend on the primary VM | | VM recovery points | Snapshot / backup layer | Protects infrastructure state and supports restore workflows | | Database historical recovery | Database-aware backup / PITR | Protects application data at the database layer | A practical rule is: > **VM disk for replaceable runtime. Block storage for disk-like state. Object storage for durable files. Database-aware protection for databases. Backups for recovery history.** This is a stronger architecture than using one large VM disk for the operating system, database, uploads, logs, backup files, and every future workload. ![Decision matrix comparing VM disk block volumes object storage and data protection for production apps](https://raff-images.s3.raffusercloud.com/storage_decision_architecture_matrix_webp_9e0be0e171.png) ## The VM should be replaceable even when the application is important A production VM can contain important software without becoming the permanent home of every important piece of data. The VM disk is a good place for: - the operating system; - application packages and binaries; - reverse proxy configuration; - service definitions; - deployment artifacts that can be recreated; - bounded logs; - temporary processing files; - local caches that can be rebuilt. Problems appear when the same disk also owns long-lived uploads, a growing database, backup archives, container state, and unbounded logs. That creates several forms of coupling: - storage growth forces a compute decision; - a full disk can affect the entire server; - rebuilding the VM also becomes a data migration; - recovery of the application and recovery of its data become the same operation; - one snapshot may contain several data types with different recovery requirements. The better target is not “stateless everything.” It is **replaceable compute with deliberate state boundaries**. For the wider architecture decision, use [Single VM vs Multi-VM Architecture for SaaS Apps](/learn/guides/single-vm-vs-multi-vm-saas-architecture). ## Use block storage when the workload needs a filesystem or raw disk Block storage is the right layer when the application or service expects a disk that can be formatted, mounted, read, and written like a local drive. Common examples include: - self-hosted database data; - Docker or container persistent directories; - application data that requires filesystem semantics; - search indexes; - build or processing workspaces that outgrow the system disk; - stateful services whose storage should grow independently from VM compute. A useful pattern is: ```text VM system disk → OS + application runtime Attached block volume → persistent service data ``` The main benefit is not simply more capacity. It is **separating the lifecycle of the data from the lifecycle of the VM's root disk**. Raff Volumes are the current block-storage layer for Raff VMs and can be resized independently of VM compute. Use the live [Volumes](/products/volumes) page for current behavior and pricing. For the deeper workload decision, continue with [Block Storage Volumes for Databases, Containers and App Data](/learn/guides/block-storage-volumes-databases-containers-app-data) or [When to Add a Volume Instead of Resizing a VM Disk](/learn/guides/add-volume-vs-resize-vm-disk). ## Use object storage when the application owns files, not disks Object storage is usually the cleaner home for durable files that should outlive any one VM. Typical examples include: - user uploads; - images and media; - documents; - generated reports; - CSV or export files; - software artifacts; - backup archives; - large files consumed by several services. A common production design is: ```text Application → database stores metadata, permissions and object key → object storage stores the file ``` This makes the application server easier to replace and lets file capacity grow independently from compute. Object storage is especially useful when files need to be shared across workers, accessed through APIs, retained for long periods, or delivered without depending on one server filesystem. Raff Object Storage is S3-compatible, so common S3 tooling and SDK patterns can be used against the Raff endpoint. Use the live [Object Storage](/products/object-storage) page for current compatibility and pricing details. Object storage is not automatically the right choice for every stateful workload. A PostgreSQL data directory, for example, expects block/filesystem behavior rather than ordinary S3 object semantics. Use [App Uploads: VM Disk vs Object Storage](/learn/guides/app-uploads-vm-disk-vs-object-storage) when the decision is specifically about application files. ## Databases need their own storage and recovery decision Database state deserves a separate decision because the database is often the application's source of truth. There are two broad models. ### Managed database Use a managed database when the supported service fits and the team wants the provider to operate more of the database platform, backup tooling, monitoring, maintenance, and supported availability features. ```text Application VM → private/restricted connection → Managed Database ``` The application team still owns schemas, indexes, queries, migrations, credentials, capacity decisions, and recovery validation. ### Self-hosted database Use a VM plus dedicated persistent storage when root access, custom extensions, exact version control, filesystem access, or another hard requirement justifies operating the database yourself. ```text Application → private network → Database VM → persistent block storage → database-aware backup / recovery ``` A volume helps separate database data from the system disk, but it does not remove the need for database-aware backups, restore testing, monitoring, patching, and recovery ownership. For the responsibility decision, use [Managed Database vs Self-Hosted](/learn/guides/managed-vs-self-hosted-databases). For backup design, use [Database Backup Strategy for SaaS Apps](/learn/guides/database-backup-strategy-saas-apps). ## Snapshots, backups, and replicas solve different problems Storage architecture becomes safer when recovery controls have distinct jobs. | Recovery control | Main purpose | Does not replace | |---|---|---| | Snapshot | Fast point-in-time infrastructure rollback | Independent historical backup strategy | | Scheduled VM backup | Retained VM recovery points | Database-aware recovery for every workload | | Database backup / PITR | Recover database history | Application files and other VM state | | Replica / HA node | Reduce downtime from selected failures | Historical recovery after bad writes or deletion | | Object-storage archive | Retain files or exported backups independently | Full application restore procedure | | Restore test | Prove recovery works | The backup itself | A production system may need more than one layer because the failure modes differ. For example: ```text Application VM backup + database PITR + object storage for durable uploads + tested restore runbook ``` is stronger than relying on one whole-VM snapshot to solve every failure. Use [Snapshots vs Backups](/learn/guides/snapshots-vs-backups-cloud-server) for the narrower comparison. ## Recovery architecture starts with RPO and RTO Before choosing backup frequency or retention, define the business requirement. **Recovery Point Objective (RPO)** asks how much recent data can be lost. **Recovery Time Objective (RTO)** asks how long the service can remain unavailable. Those targets should determine the protection design. A low-impact staging environment may accept a long RTO and coarse recovery point. A customer-facing database may need a much smaller recovery window and a faster restore path. Use this sequence: ```text business impact → RPO / RTO → data classification → backup method and frequency → retention → restore procedure → restore test ``` Do not reverse the process by enabling a default backup schedule first and deciding later whether it satisfies the business. ## Restore testing is what turns backups into evidence A backup job that reports success proves that data was written somewhere. It does not prove the application can be recovered. A useful restore test validates more than VM boot. Check: - the restored VM starts; - SSH/RDP or administrator access works; - application services start; - database state is usable; - attached storage is present; - object-storage access works; - secrets and configuration are available; - required private-network paths work; - DNS or test hostnames resolve correctly; - application health checks pass; - the measured restore time fits the RTO. A clean test pattern is: ```text Production backup → isolated restore environment → application and data validation → record timing and findings → update runbook → remove test resources ``` Use [Restore Testing Checklist for Production VMs](/learn/guides/restore-testing-checklist-production-vms) for the full procedure. ## Design storage around failure domains, not only capacity Storage decisions are often made from “how many GB do we need?” Production design needs one more question: > **What fails together?** If the application VM and every backup export live on the same server, one server failure can affect both the production copy and its supposed recovery copy. If app uploads exist only on local disk, replacing the app server becomes a file-recovery event. If the database, uploads, and logs all share one filesystem, a runaway log can threaten durable business data. Separate failure domains where the business impact justifies it: - runtime from durable data; - primary data from recovery copies; - app files from app compute; - database operations from application deployment where appropriate; - production access from restore-test environments. The architecture does not need to be distributed for its own sake. It needs boundaries that make failure understandable. ## A practical production app architecture A small SaaS or business application can stay simple while separating the state that matters. ![Raff production recovery architecture showing VM Managed Database Volumes Object Storage Data Protection and restore testing](https://raff-images.s3.raffusercloud.com/raff_production_recovery_architecture_webp_2be55f919c.png) ```text Users ↓ Application VM ↓ private network where appropriate Managed Database Application VM ↓ Object Storage → uploads / reports / media / archives VM and infrastructure state ↓ Data Protection → snapshots / scheduled backups Recovery process ↓ isolated restore test + runbook ``` If the workload needs self-hosted state, add a block volume deliberately rather than keeping everything on the VM root disk. This is often enough for a small team. You do not need Kubernetes, distributed storage, or multiple database replicas merely to claim the architecture is “production-grade.” Add those layers when availability, scale, or recovery requirements justify them. ## How the Raff storage layers fit together Raff's current infrastructure separates the main storage responsibilities cleanly: - [Raff VM](/products/raff-vm) — application and server runtime; - [Volumes](/products/volumes) — persistent block storage when a workload needs a disk/filesystem; - [Object Storage](/products/object-storage) — S3-compatible buckets for durable files, media, archives, and backup artifacts; - [Managed Databases](/products/managed-databases) — a separate managed data layer when your team should not operate the database host; - [Data Protection](/products/data-protection) — VM snapshots and scheduled backup workflows; - [VPC](/products/vpc) — private connectivity between infrastructure components where appropriate. The commercial decision should follow the architecture, not the other way around. Do not buy a volume because storage is available. Add it because a workload needs persistent filesystem semantics. Do not move files to object storage merely because S3 exists. Do it when the files should survive app-server replacement or be shared independently of the VM. Likewise, use a managed database when reducing database-host operations creates value, and use Data Protection according to the recovery objective rather than treating backup as a checkbox. :::cta Explore Data Protection Review Raff snapshots and scheduled backups as one layer of a complete recovery plan for your production VMs. ::: ## Cloud storage architecture checklist Before calling an application production-ready, verify: ### Data placement - [ ] The VM root disk is not the accidental home of every durable data type. - [ ] Database storage has a named owner and recovery method. - [ ] User uploads and durable files have an intentional storage layer. - [ ] Container or service state is separated where persistence requires it. - [ ] Temporary files and logs have cleanup or retention rules. ### Recovery - [ ] RPO is defined for important data. - [ ] RTO is defined for important services. - [ ] VM backups or snapshots have a documented purpose. - [ ] Database backups are database-aware where required. - [ ] Recovery copies do not depend entirely on the primary workload. - [ ] Restore steps are documented. - [ ] A restore has been tested in an isolated environment. - [ ] Measured restore time is recorded. ### Operations - [ ] Storage growth is monitored. - [ ] Disk-full conditions generate alerts before the application fails. - [ ] Access to backups and object storage is scoped. - [ ] Deleted or detached storage has an ownership and cleanup process. - [ ] The team knows which system is authoritative for every important data type. ## Common storage architecture mistakes ### Keeping uploads on the app server indefinitely It works until the app needs another server, a rebuild, or independent file capacity. Durable uploads are usually easier to operate when they are separated from the application VM lifecycle. ### Treating a larger VM disk as a complete scaling strategy Increasing disk size can solve a capacity problem while leaving recovery, ownership, and failure coupling unchanged. ### Calling a replica a backup Replication can reproduce accidental deletes and bad writes. Availability and historical recovery are separate requirements. ### Keeping backup files beside the primary data A recovery copy should not disappear with the exact system it is meant to recover. ### Never restoring a backup Backup existence and recovery readiness are different facts. Test the path back. ### Adding every storage product at launch Complexity has a cost. Start with the smallest architecture that gives each important data type an appropriate home and a recoverable path. ## Conclusion A good **cloud storage architecture** makes production data easy to locate, protect, scale, and recover. Keep replaceable runtime on the VM. Use block storage for disk-like persistent state. Use object storage for durable file objects that should outlive app servers. Give databases their own operating and recovery model. Use snapshots and backups for explicit failure scenarios, and test restores before an incident turns those assumptions into a production dependency. The strongest design is not the one with the most storage layers. It is the one where your team can answer four questions quickly: **Where does this data live? What is authoritative? What failure does its backup protect against? How do we restore it?** ## Sources - [Raff Volumes](/products/volumes) - [Raff Object Storage](/products/object-storage) - [Raff Data Protection](/products/data-protection) - [Raff Managed Databases](/products/managed-databases) - [Raff VPC](/products/vpc) - Product details reviewed: 2026-09-16 --- ### Cloud Block Storage vs Local Disk: When to Use a Volume URL: https://rafftechnologies.com/learn/guides/block-storage-vs-local-disk Description: Compare cloud block storage vs local disk by lifecycle, databases, containers, scaling, performance, backups, and when a separate persistent volume is worth using. **Cloud block storage is the better choice when application data needs a lifecycle separate from the VM. Local disk is the simpler choice when the data belongs to one server and can be rebuilt, replaced, or restored together with that server.** The distinction is primarily about **lifecycle and operational ownership**, not a universal claim that one storage type is always faster. At **Raff Technologies**, a practical default is: keep the operating system, packages, caches, temporary files, and other replaceable runtime data on the VM disk; use a separate Volume when a database, container, or application needs persistent filesystem storage that should survive VM replacement or grow independently from compute. In this guide, **local disk** means storage operationally coupled to one VM. It does not imply a specific physical disk topology underneath the cloud platform. ## Cloud block storage vs local disk: quick answer | Decision factor | Local / VM disk | Cloud block storage | |---|---|---| | Lifecycle | Coupled to one VM | Separate storage resource | | Best fit | OS, packages, caches, temp files, rebuildable runtime | Databases, container state, persistent application filesystems | | Capacity growth | Usually follows the VM/system-disk model | Can grow separately from compute | | VM replacement | Data moves/restores with the VM process | Volume can remain a separate persistent layer | | Application interface | Normal local filesystem | Normal filesystem after attach/mount | | Multi-server shared access | No | Not automatically; ordinary block volumes are usually single-host storage | | Backup replacement | No | No — persistence is not backup | | Operational work | Lowest | Attach, mount, monitor, resize, protect | A useful rule is: > **If replacing the VM should not mean replacing the data, separate that data from the VM’s boot disk.** For the broader storage decision that also compares object storage, read [Object Storage vs Block Storage vs VM Disk](/learn/guides/object-storage-vs-block-storage-vs-vm-disk). ## What cloud block storage actually is Cloud block storage presents storage to a VM as a disk-like block device. The operating system can format it with a filesystem and mount it at a normal path. A simplified Linux example looks like: ```text VM ↓ attached block device ↓ filesystem ↓ /mnt/data ↓ database / container / application ``` The important point is that the **storage resource has a lifecycle distinct from the VM’s system disk**. That separation can make several operational tasks cleaner: - storage capacity can grow without changing CPU or RAM; - persistent application data can live outside the boot disk; - a VM can be rebuilt without making the root disk the only copy of active state; - storage monitoring can be separated from operating-system disk pressure; - persistent container or service state can use a dedicated mount point; - recovery procedures can distinguish compute replacement from data recovery. Cloud block storage is still active primary storage. It is not automatically a backup, replica, or disaster-recovery system. ## What local disk means in a cloud VM “Local disk” is an overloaded term. Some cloud providers use it to describe physically local ephemeral NVMe. Others use phrases such as local storage, VM disk, root disk, system disk, or boot disk for storage tied operationally to one virtual machine. For architecture decisions, the useful question is not the marketing label. It is: **What happens to this data when the VM is rebuilt, replaced, resized, reimaged, or deleted?** Data that is naturally part of one VM’s runtime often belongs on the VM disk: - operating-system files; - packages and dependencies; - application binaries; - deployment files that can be recreated; - package and container caches; - temporary processing files; - bounded local logs; - generated artifacts that can be rebuilt safely. This keeps the design simple. A separate volume is not automatically better just because it is more “cloud-native.” ## Choose local disk for replaceable runtime Local disk is usually the right default when losing the disk together with the VM would not create an unacceptable business-data loss event. Good examples include: ### Operating system and application runtime The OS, packages, runtime binaries, service definitions, and deployment artifacts generally belong with the VM. If the server can be recreated from automation, documentation, images, or deployment tooling, keeping these files on the system disk avoids unnecessary storage complexity. ### Caches Caches are normally rebuildable. Separating them onto persistent block storage can increase cost and operational work without adding meaningful resilience. ### Temporary processing space Image transformations, build workspaces, package extraction, temporary exports, and scratch files often fit local disk well when the process can safely restart. ### Bounded logs Local logs are reasonable when retention is controlled and important logs are shipped to an external monitoring or logging destination. The key is **bounded**. An unbounded log directory on the boot disk can still fill the server and cause application failures. ## Choose cloud block storage for persistent filesystem state Use a block volume when software needs a mounted filesystem and the data should be managed separately from the VM root disk. Common fits include: - self-hosted database data directories; - persistent Docker or container state; - application data directories; - search indexes; - package or artifact repositories that require filesystem semantics; - growing storage workloads where CPU/RAM demand is stable; - service state that should not live inside the boot disk lifecycle. A clean model is: ```text VM system disk └── OS + application runtime Attached block volume └── persistent service data ``` That boundary makes it easier to explain what belongs to the server and what belongs to the workload’s durable state. ## Databases are a common block-storage use case A self-hosted database expects filesystem and disk behavior, which makes block storage a natural fit when the platform’s performance and recovery characteristics match the workload. A typical design is: ```text Application VM ↓ private network Database VM ↓ Block volume ↓ Database files ``` But moving the data directory to a volume does not make the database managed. Your team still owns: - database installation and patching; - authentication; - network exposure; - filesystem and mount health; - storage growth; - database-aware backups; - restore testing; - replication or HA where required; - upgrades and incident response. A volume improves the storage boundary. It does not remove database operations. If reducing that operational ownership matters more than root-level control, compare this architecture with [Managed Database vs Self-Hosted](/learn/guides/managed-vs-self-hosted-databases). ## Persistent container data should not depend on the container lifecycle Containers are designed to be recreated. Important data therefore needs an explicit storage owner. For filesystem-dependent state, a block volume can provide a clean persistent path: ```text VM / container host ↓ container ↓ mounted directory block volume ``` Examples include: - self-hosted database containers; - application state directories; - indexes; - plugin or extension data; - queue/service state that genuinely needs a filesystem. Do not move every file to block storage just because a container writes it. User uploads, media, reports, and other file objects shared by multiple application instances may fit [Object Storage](/products/object-storage) better. ## A separate volume helps when storage grows faster than compute One of the strongest commercial and architectural reasons to separate storage is independent scaling. Suppose an application VM has enough CPU and memory but its persistent dataset keeps growing. With storage tightly coupled to the server: ```text more data → pressure on system disk → possible server resize or migration ``` With a separate volume: ```text compute remains adequate → volume capacity grows independently ``` This prevents a storage-capacity problem from automatically becoming a compute-purchasing decision. The same logic applies in reverse. A CPU-heavy workload may need more compute without needing more persistent storage. Separating the lifecycles lets each resource scale for the reason it actually needs to scale. ## Block storage does not become shared storage automatically A common mistake is assuming that a block volume is equivalent to a shared network filesystem. It is not. Ordinary filesystems such as ext4, XFS, or NTFS generally expect one host to control the block device. Several independent servers writing to the same block device without explicit multi-attach support and a cluster-aware filesystem can corrupt data. If several application servers need the same files, consider whether the workload really needs: - **object storage** for uploads, media, exports, and artifacts; - a database for structured state; - a purpose-built shared filesystem when normal filesystem semantics are mandatory. Do not design multi-writer storage around assumptions that the platform or filesystem does not document. ## Block storage is persistent storage, not backup Separating data from the VM protects against some lifecycle problems. It does not protect against every data-loss scenario. A block volume can still contain: - accidentally deleted files; - corrupted database pages; - a destructive migration; - ransomware-encrypted data; - bad application writes; - administrator mistakes. If the bad change reaches the active volume, persistence faithfully preserves the bad change. That is why production storage architecture usually needs a separate recovery layer. Use [Snapshots vs Backups](/learn/guides/snapshots-vs-backups-cloud-server) for the recovery-control decision and [Cloud Storage Architecture for Production Apps: Backup & Recovery](/learn/guides/storage-recovery-architecture-production-apps) for the wider architecture. ## Performance depends on the workload, not the label A simple “local disk is faster” rule is too broad for production architecture. Actual storage performance depends on factors such as: - latency; - IOPS; - throughput; - queue depth; - read/write size; - sequential vs random access; - synchronous database writes; - filesystem configuration; - caching; - VM and storage contention; - platform limits. A database performing many small synchronous writes has very different requirements from a backup archive or media store. For important workloads, benchmark representative operations on the actual environment rather than relying on one sequential throughput number. Measure the metrics that affect the application: transaction latency, query latency, IOPS, throughput, queueing, and filesystem utilization. ## Local disk can still be correct for small production workloads Separating every stateful directory on day one can create more moving parts than value. A small production application may reasonably begin with one VM when: - the dataset is small; - growth is predictable; - backups are tested; - downtime tolerance is understood; - the team can restore the whole server quickly; - independent storage scaling is not yet needed. The trigger to add a volume should be a real operational requirement, such as: - persistent state needs its own lifecycle; - disk growth is outpacing compute needs; - a service needs a dedicated filesystem; - VM replacement should not also become a data migration; - root-disk pressure is creating operational risk. Complexity should solve a problem, not merely signal architectural maturity. ## Mounting a volume creates operating-system responsibility A separate block volume is not zero-operations storage. The team should manage: - filesystem creation where required; - mount point selection; - persistent mount configuration; - permissions and ownership; - filesystem utilization; - monitoring and alerts; - resize procedures; - safe detach/reattach workflows; - backup and recovery procedures. On Linux, persistent mounting should use stable identifiers rather than assuming a device name will never change. Always test a reboot. A volume that is attached but not mounted can cause an application to write into the underlying empty mount directory on the boot disk, silently splitting data across two locations. For the procedural side, the cluster also contains [Block Storage Volume Setup for Linux VMs](/learn/guides/block-storage-volume-setup-linux-vms). ## Capacity planning should include operational headroom Do not size a volume only for the current dataset. Allow for: - database and index growth; - temporary migration space; - compaction or vacuum operations; - log retention; - container image or artifact growth; - backup staging; - filesystem overhead; - future application data. Monitor both **percentage used** and **rate of growth**. A filesystem at 70% with rapidly accelerating growth may be a bigger risk than one at 85% with stable usage. ## Local disk, block storage, and object storage often work together A common production architecture is not an either/or choice. ```text VM disk ├── OS ├── application runtime ├── cache └── temporary files Block volume └── persistent database / service filesystem Object storage └── uploads / media / reports / archives Backup layer └── recovery points + tested restore process ``` Each layer has a different job. This separation can keep the server replaceable without forcing every piece of state into object storage or every file onto a block volume. ## How Raff Volumes fit this decision Raff Volumes are the current block-storage layer for Raff VMs. The live [Volumes](/products/volumes) page documents the current volume sizes, pricing, attachment behavior, online growth, snapshot support, and other product-specific limits. Because these details can change, the product page—not a dated guide—is the source of truth for current commercial values. As reviewed on **September 16, 2026**, Raff documents that Volumes: - are separate persistent block-storage resources; - attach to Raff VMs as disk devices; - can grow independently from VM compute; - can remain after the VM is deleted and be attached again; - support online growth while attached; - integrate with the platform’s snapshot/data-protection workflow. The architectural implication is more important than a fixed price quote: use a Volume when the workload needs persistent filesystem semantics and a lifecycle separate from the VM boot disk. Use [Raff VM](/products/raff-vm) for compute and runtime, [Volumes](/products/volumes) for persistent block state, [Object Storage](/products/object-storage) for API-accessed durable files, and [Data Protection](/products/data-protection) for recovery workflows. :::cta Explore Raff Volumes Use a separate block volume when your database, container, or application data needs persistent filesystem storage independent from the VM boot disk. ::: ## Decision checklist Choose **local / VM disk** when most of these are true: - [ ] The data belongs to the OS or application runtime. - [ ] It can be recreated safely. - [ ] It is cache, scratch, or temporary data. - [ ] Storage growth is modest and tracks the VM lifecycle. - [ ] Replacing the VM and its disk together is acceptable. - [ ] Simplicity is more valuable than an independent storage lifecycle. Choose **cloud block storage** when most of these are true: - [ ] The workload needs a mounted filesystem or disk device. - [ ] The data should exist independently from the boot disk. - [ ] Storage may grow without needing more CPU or RAM. - [ ] A self-hosted database or container needs persistent state. - [ ] The team can manage mounting, monitoring, backup, and recovery. - [ ] The platform’s volume lifecycle matches the recovery design. Choose **object storage** instead when most of these are true: - [ ] The data is naturally files or blobs. - [ ] Several app instances need access. - [ ] The application can use an S3-compatible API. - [ ] Files should scale independently from servers. - [ ] Mounted filesystem semantics are unnecessary. ## Common mistakes ### Putting every durable file on the boot disk This couples VM replacement, capacity growth, and data recovery unnecessarily. ### Treating a volume as a backup A persistent disk stores the current state, including accidental deletions and bad writes. Maintain independent recovery points. ### Assuming block storage is automatically shared storage Do not allow multiple writers unless the platform, filesystem, and application architecture explicitly support it. ### Forgetting persistent mounts after reboot Verify mount configuration and application startup before production use. ### Resizing the entire VM because only disk capacity is growing Independent block storage can separate a storage requirement from a compute requirement. ### Hard-coding product pricing into architecture advice Commercial values change. Use the live product and pricing pages as the current source of truth. ## Conclusion The **cloud block storage vs local disk** decision is mainly a lifecycle decision. Keep operating-system files, packages, caches, temporary data, and other replaceable runtime on the VM disk. Use cloud block storage when a database, container, or application needs persistent filesystem state that should grow or survive independently from the server’s boot disk. Then protect that persistent data with a separate recovery design. A volume can make compute replaceable, but only backups and tested restores make the data recoverable. Continue with [Block Storage Volumes for Databases, Containers and App Data](/learn/guides/block-storage-volumes-databases-containers-app-data) for workload-specific examples, or [Cloud Storage Architecture for Production Apps: Backup & Recovery](/learn/guides/storage-recovery-architecture-production-apps) for the full storage-and-recovery model. ## Frequently asked questions ### What is cloud block storage? Cloud block storage is persistent disk-like storage presented to a VM as a block device. The operating system can format and mount it with a normal filesystem while the storage resource is managed separately from the VM’s boot disk. ### What is the main difference between block storage and local disk? The main architectural difference is lifecycle. Local/VM-disk data is operationally coupled to one server, while a separate block volume can be managed, grown, protected, and retained independently from the boot disk. ### Should a database use block storage? A self-hosted database commonly fits block storage because the database expects filesystem and disk semantics. The workload still needs database-aware backups, monitoring, recovery testing, and appropriate performance validation. ### Does a block volume survive VM replacement? That depends on the cloud platform. Raff’s current Volumes product documentation states that volumes are separate resources that can remain after a VM is deleted and be attached again. Always verify the current platform behavior before designing a recovery procedure around it. ### Is block storage faster than local disk? Not universally. Performance depends on the platform, latency, IOPS, throughput, queue depth, filesystem, caching, and workload access pattern. Benchmark the real workload rather than assuming one storage label is always faster. ### Can multiple VMs write to one block volume? Do not assume so. Ordinary filesystems usually expect one host. Multi-writer access requires explicit platform support plus a filesystem or application architecture designed for concurrent writers. ### Does block storage replace backups? No. Block storage is active primary storage. It does not protect against accidental deletion, corruption, destructive migrations, compromised credentials, or other logical data-loss events. ### When should I use object storage instead of block storage? Use object storage when data is naturally files or blobs accessed through an API, such as uploads, media, reports, exports, archives, and backup artifacts. Use block storage when software expects a mounted filesystem or disk device. ## Sources - [Raff Volumes](/products/volumes) - [Raff Object Storage](/products/object-storage) - [Raff Data Protection](/products/data-protection) - [Raff VM](/products/raff-vm) - Product details reviewed: 2026-09-16 --- ### Private vs Public Admin Access: When Each Model Is Appropriate URL: https://rafftechnologies.com/learn/guides/private-vs-public-admin-access Description: Private vs public admin access for secure remote access across SSH, RDP, VPNs, bastions, break-glass recovery, and Raff VPC. **Private vs public admin access is the choice between exposing management services such as SSH or RDP through an internet-routable path and requiring administrators to enter through a controlled private or identity-based access layer.** For production workloads, the better question is usually broader: **what secure remote access model gives the team the smallest practical management surface without making recovery or day-to-day operations fragile?** For **Raff Technologies** environments, both models are possible. A low-risk VM can use tightly restricted public administration when simplicity matters, while production servers, Windows RDP workloads, databases, and multi-server environments can move behind VPC, VPN, bastion, or another controlled private path as risk and operating complexity increase. A useful rule is: > **Public administration is an exposure exception. Private administration is an access architecture. Neither replaces strong identity, least privilege, patching, logging, or access review.** For the gateway-level comparison, use [Bastion Host vs VPN vs Public SSH](/learn/guides/bastion-host-vs-vpn-vs-public-ssh). This guide focuses on the private-versus-public administration boundary and how it fits a secure remote access model. ## Private vs public admin access: quick comparison | Decision factor | Restricted public admin access | Private / controlled admin access | |---|---|---| | Internet reachability | Management service remains internet-routable | Target management service is not directly public | | Best fit | Small, low-impact, simple environments | Production, sensitive, multi-server, or multi-user environments | | Typical protocols | SSH or RDP | SSH, RDP, databases, dashboards, internal tools | | Administrator locations | Few and stable | Distributed or frequently changing | | Governance | Per-server rules and credentials | Centralized entry plus target-level authorization | | Blast radius | Depends heavily on endpoint hardening | Can reduce direct exposure and lateral reachability | | Operational complexity | Lower | Higher because VPN/gateway/access layer must be maintained | | Recovery dependency | Target stays directly reachable | Access layer itself needs a break-glass path | ### Choose restricted public administration when - the workload is temporary, disposable, or low impact; - one or two known administrators need access; - trusted source IPs are stable enough to restrict; - strong authentication is configured; - the management service is patched and monitored; - the exception has an owner and review date. ### Move toward private or controlled administration when - customer or business data is involved; - several servers or private services need administration; - Windows RDP is used routinely; - multiple employees, contractors, or MSP technicians need access; - administrator locations change frequently; - public management endpoints are becoming difficult to govern; - tenant or customer separation matters. ## Secure remote access is a system, not a single protocol **Secure remote access** combines network reachability, identity, authorization, protocol hardening, logging, lifecycle management, and recovery. A useful model is: ```text Administrator identity ↓ Approved access path ↓ Target-level authorization ↓ SSH / RDP / database / internal tool ↓ Audit + review + revocation ``` The access path answers: > Can this administrator reach the service? Identity and authorization answer: > Should this administrator be allowed to use it, and what can they do after connecting? This distinction matters. A private RDP endpoint protected only by one shared Administrator password is still weak. A public SSH endpoint can still be reasonably controlled if it is narrowly source-restricted, key-based, patched, logged, and intentionally reviewed. The strongest model combines: - restricted network reachability; - individual identities; - least privilege; - protocol hardening; - logging; - access reviews; - offboarding; - a break-glass recovery path. ## Administrative access should be separate from user traffic A public application may need HTTPS from the internet while management traffic remains restricted. ```text User plane Internet → HTTPS → Application edge Admin plane Approved administrator → Controlled access path → Infrastructure ``` Separating the two planes makes these questions easier to answer: - Who can administer production? - Which systems can each administrator reach? - Which management services are public? - How is access removed after a role or contract changes? - Which credentials can modify backups, DNS, databases, or networks? - What happens if the primary admin path fails? A private IP or VPN connection reduces reachability. It does not automatically authorize every resource on the private network. ## When public SSH or RDP can still be appropriate Public administration means the management service accepts traffic through an internet-routable endpoint. Typical examples are public SSH and public RDP. Its main advantage is simplicity: there is no separate VPN, bastion, gateway, or private route to operate. That simplicity can be reasonable for: - development VMs; - short-lived migration hosts; - low-impact internal experiments; - one-server environments with stable administrator IPs; - emergency transitional architectures. The risk increases as the environment accumulates: - more administrators; - more credentials; - more customer data; - more servers; - more Windows workloads; - more contractors; - more sensitive recovery systems. The common failure is not starting with public access. It is **failing to revisit the decision after the workload becomes important**. ## Public SSH: minimum production controls If SSH remains internet-routable, treat it as an explicit exception. Use: - individual administrator SSH keys; - no shared private keys; - password authentication disabled where practical; - restricted direct root login according to the operating model; - firewall restriction to approved source addresses where possible; - supported OpenSSH and OS versions; - login monitoring; - recurring key review; - immediate removal of temporary access. Changing the SSH port can reduce scanning noise, but it is not a primary security boundary. Use [Cloud Firewall Best Practices](/learn/guides/firewall-best-practices-cloud-servers) for the surrounding network policy. ## Private RDP is usually a stronger production default RDP is a powerful Windows management path and becomes increasingly difficult to justify as a broadly public endpoint when the server is business-critical. For production Windows workloads, prefer: - private or tightly source-restricted RDP reachability; - named administrator accounts; - strong credentials; - Network Level Authentication where supported; - limited local Administrators membership; - current Windows updates; - MFA at the VPN, gateway, or identity layer where the selected design supports it; - login monitoring and recurring access review. A private RDP service is not automatically secure, but it removes one major attack path: broad public reachability to the management protocol itself. Raff [Windows VM](/products/windows-vm) can participate in the same [VPC](/products/vpc)-based private access design as Linux workloads. ## Source-IP allowlisting is useful but limited Allowlisting trusted public source IPs is one of the simplest improvements for a small environment. It works well when: - the team is very small; - administrator locations are stable; - only one or two servers need access; - firewall changes can be reviewed manually. Its limits appear when administrators: - travel; - use changing consumer IPs; - work from several locations; - need access to many private services; - require RDP, databases, dashboards, and SSH together. Allowlisting reduces reachability. It does not centralize identity, credential lifecycle, or target-level authorization. ## Bastion vs VPN for secure remote access A bastion and a VPN both reduce the need to expose every protected server directly, but their operating models differ. | Model | Better fit | Main trade-off | |---|---|---| | Bastion host | Mainly SSH administration for a group of private servers | Bastion becomes critical infrastructure | | VPN | Mixed SSH, RDP, databases, dashboards, internal services | Peer and route lifecycle must be maintained | | Source-restricted public access | One or two servers with stable admin locations | Management service remains public | | Identity-aware access | Distributed teams needing user/device policy | More identity-system dependency | A bastion is often efficient when Linux SSH is the dominant requirement. A VPN is more flexible when several protocols and private resources need access. For the complete gateway decision, use [Bastion Host vs VPN vs Public SSH](/learn/guides/bastion-host-vs-vpn-vs-public-ssh). ## Databases and admin panels should rarely be public Direct public database administration is usually harder to justify than public SSH or RDP because databases and control panels expose high-impact operations and sensitive data directly. Prefer private or tightly controlled paths for: - PostgreSQL and MySQL administration; - Microsoft SQL Server; - Valkey and cache administration; - internal monitoring dashboards; - queue-management interfaces; - backup consoles; - infrastructure-management panels; - internal APIs. A service used only by administrators should not become public merely because making it public is convenient. ## Access lifecycle matters as much as architecture Secure remote access is not finished when the VPN or firewall rule is created. Review access after: - employee departure; - contractor or MSP engagement ending; - role change; - production launch; - environment migration; - lost or replaced administrator device; - security incident; - major network redesign. Temporary access should have: - a named user or service identity; - a defined target scope; - an owner; - an expiry or removal event; - a review record when the work ends. For recurring governance, use [Cloud Access Reviews for Small Teams](/learn/guides/cloud-access-reviews-small-teams-ssh-admin-permissions). ## Human and machine access should be separated A CI/CD runner, backup process, monitoring agent, and human administrator should not all share one credential merely because they reach the same VM. Separate: - human admin accounts; - deployment credentials; - monitoring identities; - backup/recovery credentials; - application credentials. This makes offboarding and incident containment much easier. If a deployment token leaks, the team should be able to revoke the deployment path without disabling every human administrator at the same time. ## MSPs need customer-scoped administration An MSP or managed IT provider has an additional problem: administrator access spans several customer environments. Avoid: - one shared credential across customers; - one flat private network with unrestricted lateral movement; - production access that cannot be attributed to a technician; - permanent contractor access after an engagement ends. Prefer: - named technician identities; - customer-scoped permissions; - separate credentials; - client-specific routes or access groups; - auditable access; - explicit offboarding. A central VPN or management plane can simplify operations without collapsing customer boundaries. Use [Private Cloud Networking for MSPs](/learn/guides/private-cloud-networking-for-msps) for the network-isolation model and [Secure Remote Access for MSPs](/learn/guides/secure-remote-access-for-msps-bastion-vpn-zero-trust) for the technician-access model. ## Break-glass access is part of a mature private-access design Private administration introduces an operational dependency: the VPN, bastion, identity provider, DNS, route, or firewall policy can itself fail. Important environments should document a **break-glass path**. It should define: 1. who may authorize emergency access; 2. where the recovery credential or access method is protected; 3. how operators regain access if the normal path fails; 4. which emergency changes are allowed; 5. how use is logged and reviewed; 6. how emergency credentials are rotated or disabled afterward; 7. how normal access policy is restored. Break-glass access should remain exceptional. If it becomes the normal login path, the primary access design is not operationally healthy. ## Secure remote access and recovery are linked Administrative architecture affects recovery. If a server is restored or rebuilt, confirm: - the expected private network is attached; - required VPN or gateway routes exist; - administrator identities are still valid; - SSH keys or Windows accounts are restored intentionally; - firewall rules allow the approved access path; - DNS or bastion names resolve; - emergency access still works. A successful VM restore is not enough if operators cannot reach the recovered service safely. Use [Restore Testing Checklist for Production VMs](/learn/guides/restore-testing-checklist-production-vms) for the wider recovery workflow. ## How Raff fits a secure remote access model A Raff environment can support a staged progression from simple administration to a stronger private-access architecture. ```text Stage 1 Restricted public SSH/RDP → one low-risk VM Stage 2 Raff VPC → private application/database/admin paths Stage 3 Approved VPN / gateway / bastion → multiple private resources Stage 4 Named users + scoped customer/team access → recurring review + break-glass recovery ``` Relevant Raff building blocks include: - [Raff Cloud Servers](/products/raff-vm) for Linux workloads; - [Windows VM](/products/windows-vm) for Windows workloads; - [VPC](/products/vpc) for private service and administration paths; - [Site-to-Site VPN](/products/site-to-site-vpn) where approved networks need network-to-network connectivity; - [Security](/products/security) for Raff's current platform security surface; - [Data Protection](/products/data-protection) for VM recovery workflows. Use the live [VPC](/products/vpc), [Site-to-Site VPN](/products/site-to-site-vpn), and [pricing](/pricing) pages for current implementation limits and commercial values instead of hard-coding mutable pricing into an evergreen access guide. Raff provides the infrastructure path. Your team still owns user identity, guest-OS permissions, SSH/RDP configuration, access reviews, credential rotation, and customer-specific authorization. :::cta Explore Raff VPC Move production management services onto controlled private paths when direct public SSH or RDP is no longer the right operating boundary. ::: ## Secure remote access checklist ### Public exposure - [ ] Every public management endpoint has a documented reason. - [ ] SSH/RDP source restrictions are as narrow as practical. - [ ] Databases and admin panels are not broadly public. ### Identity - [ ] Administrators use named accounts. - [ ] Shared SSH keys and shared Administrator credentials are avoided. - [ ] Human and machine identities are separated. - [ ] Former employees, vendors, and contractors are removed promptly. ### Private access - [ ] VPN/bastion membership does not automatically authorize every resource. - [ ] Target-level firewall and OS permissions remain least privilege. - [ ] Client or environment boundaries are preserved. ### Operations - [ ] Temporary access has an expiry. - [ ] Administrative logins are reviewable. - [ ] Access is reviewed after team and architecture changes. - [ ] A break-glass method exists and has been documented. ### Recovery - [ ] Restored or rebuilt servers can rejoin the intended admin path. - [ ] Required routes, DNS, firewall rules, and identities are included in recovery testing. :::cluster ## Frequently asked questions ### What is secure remote access? Secure remote access is an administrative model that combines controlled network reachability with individual identity, least privilege, protocol hardening, logging, access review, offboarding, and recovery. ### What is the difference between private and public admin access? Public admin access exposes a management service such as SSH or RDP through an internet-routable path. Private admin access requires an approved private, VPN, bastion, or identity-controlled path before the target can be reached. ### Is public SSH safe for a production server? It can be acceptable when access is tightly source-restricted, key-based, patched, logged, and intentionally reviewed. Private administration is usually easier to govern as workload impact and team size grow. ### Should RDP be publicly exposed? Broad public RDP should not be the default for an important Windows workload. Prefer private or tightly restricted reachability, named users, NLA where supported, current Windows updates, and MFA at the access layer where available. ### Is private RDP more secure than public RDP? Private RDP reduces direct internet exposure, which removes one important attack path. It still requires strong identities, least privilege, patching, logging, and recurring access review. ### Can IP allowlisting replace a VPN? For a very small environment with stable administrator IPs, allowlisting may be sufficient. It becomes less practical for distributed teams, changing locations, mixed protocols, and multiple private resources. ### When should a small team move to private admin access? Move when workloads become production-critical, sensitive data is involved, multiple people need access, several internal services must be reached, or public management endpoints become difficult to govern consistently. ### What is break-glass admin access? Break-glass access is a documented emergency path used when the normal VPN, bastion, identity provider, or network path fails. Its use should be authorized, logged, reviewed, and closed afterward. ### How does Raff support private admin access? Raff VPC can provide private paths between supported resources, while Raff Site-to-Site VPN and other controlled access patterns can connect approved networks or administrators. Raff Security and guest-OS controls provide additional layers around the management path. ## Conclusion Private and public admin access are different operating models, not absolute security labels. Restricted public SSH or RDP can fit a small, low-impact environment when exposure is tightly controlled. As workloads become production-critical, teams grow, internal services multiply, or customer separation matters, a VPN, bastion, or another controlled private-access model usually creates a clearer administrative boundary. Whichever model you choose, keep named identities, least privilege, protocol hardening, access reviews, logging, and a documented emergency path. **Reducing public reachability is valuable, but secure remote access comes from combining network control with identity, lifecycle discipline, and recovery.** ## Sources - [NIST SP 800-207: Zero Trust Architecture](https://csrc.nist.gov/pubs/sp/800/207/final) - [CISA: Require Multifactor Authentication](https://www.cisa.gov/audiences/small-and-medium-businesses/secure-your-business/require-multifactor-authentication) - [Microsoft Learn: Enable Remote Desktop](https://learn.microsoft.com/en-us/windows-server/remote/remote-desktop-services/remotepc/remote-desktop-allow-access) - [Raff VPC](/products/vpc) - [Raff Site-to-Site VPN](/products/site-to-site-vpn) - [Raff Security](/products/security) - Product details reviewed: 2026-09-16 --- ### Bastion Host vs VPN vs Public SSH: Choosing the Right Access Model URL: https://rafftechnologies.com/learn/guides/bastion-host-vs-vpn-vs-public-ssh Description: Compare a bastion host, VPN, and public SSH for secure administration of Linux, Windows RDP, databases, and private cloud servers. **A bastion host is a hardened administrative gateway placed between an administrator and private servers. A VPN creates authenticated private-network reachability. Public SSH connects directly to an internet-routable server.** The right model depends on how many systems and protocols administrators need, how much network reachability they should receive, and how easily the team can review and revoke access. For **Raff Technologies** workloads, the most useful decision is not simply “bastion host vs VPN.” It is: **what is the narrowest administrative path that still lets the team operate Linux, Windows, databases, and internal services reliably?** Use restricted public SSH for a small, low-risk Linux environment with tightly controlled sources. Use a bastion host when private servers mainly need one controlled SSH or RDP entry point. Use a VPN when administrators need several private protocols or services from their workstation. Larger or higher-risk environments can combine VPN access with a bastion for an additional privileged boundary. ## Bastion host vs VPN vs public SSH: quick answer | Access model | Best fit | Main advantage | Main risk | |---|---|---|---| | Restricted public SSH | One or a few low-risk Linux servers | Lowest operational complexity | Management endpoint remains public | | Bastion host | Several private servers, focused SSH/RDP administration | Centralizes administrative entry | Bastion can become over-privileged | | VPN/private access | Mixed SSH, RDP, databases, dashboards, internal APIs | Gives tools private network reachability | Flat VPN routes can expose too much | | VPN + bastion | Sensitive production or customer environments | Separates network entry from privileged server entry | More components to operate and recover | A useful rule is: > **Choose the smallest access surface your team can operate consistently, then separate network reachability from actual privilege.** ## What is a bastion host? A **bastion host** is a deliberately hardened server or gateway used as the administrative entry point to systems that otherwise remain private. ```text Administrator ↓ restricted access Bastion host ↓ private network Application VM / database / internal server ``` Instead of exposing SSH or RDP on every target server, the team exposes or privately reaches one controlled gateway and then connects onward over private paths. A bastion can reduce the number of public administrative endpoints, but it also concentrates trust. If every administrator shares one credential and the bastion can reach every server, the architecture has centralized risk rather than reduced it. A sound bastion baseline includes: - a supported, minimal operating system; - only required services; - named administrator accounts; - individual SSH keys or approved authentication methods; - restricted inbound reachability; - narrow private routes and target firewall rules; - patching and monitoring; - no unrelated application workloads; - a documented break-glass path. Treat the bastion as privileged infrastructure, not a general-purpose utility VM. ## What is a VPN for remote administration? A remote-access VPN creates an authenticated network path between an administrator device and approved private resources. ```text Administrator device ↓ VPN Private network ├─ SSH → Linux VM ├─ RDP → Windows VM ├─ DB client → database └─ HTTPS → internal dashboard ``` A VPN is usually a better fit when administrators need several protocols or applications rather than only terminal access to a few Linux servers. The key limitation is that **VPN connectivity creates reachability, not authorization**. A user who joins the private network should not automatically be able to reach every subnet, RDP session, database, backup system, or customer environment. Use route scope, target firewalls, operating-system permissions, and service authentication to keep access narrow after the VPN connection succeeds. ## Public SSH can still be the right answer for simple workloads Public SSH means the SSH service itself is reachable through an internet-routable address. That model can be appropriate when: - there is one low-risk or disposable Linux VM; - only one or two named administrators need access; - stable source IPs can be allowlisted; - individual SSH keys are used; - the operating system is patched; - login activity is monitored; - no sensitive private services depend on the server. Public SSH becomes harder to govern when the environment adds more people, servers, databases, customer data, Windows systems, contractors, or audit requirements. The common mistake is not beginning with public SSH. It is leaving the same exposure model in place after the system grows into production infrastructure. ## Bastion host vs VPN: the practical decision Choose a **bastion host** when: - most administration is SSH or controlled RDP; - target servers should not expose management ports directly; - a small set of entry points is easier to review; - broad workstation-to-private-network reachability is unnecessary; - administrators can work effectively through a gateway. Choose a **VPN** when: - administrators need SSH and RDP plus databases or dashboards; - several private protocols are involved; - local administration tools need direct private connectivity; - private DNS or internal web services matter; - teams operate from several locations. Use **both** when the environment needs separate trust stages: ```text Administrator ↓ VPN Management network ↓ bastion Sensitive production systems ``` The extra layer is useful only when it creates a meaningful boundary the team can actually maintain. ## Public SSH vs VPN is not a pure either-or choice SSH and VPN solve different layers of the problem. SSH authenticates a session to a Linux server. A VPN provides network connectivity. A common production design is: ```text Administrator ↓ VPN Private IP of Linux VM ↓ SSH authentication Linux server ``` In this model, SSH is still the server login mechanism, but TCP 22 does not need broad public exposure. The better question is therefore: > Should SSH be reached directly from the internet, through a bastion, or over a private access path? ## Network reachability is not the same as privilege Every remote-access model should separate four decisions: ```text Can reach the network ↓ Can reach this server and port ↓ Can authenticate ↓ Can perform privileged actions ``` Joining a VPN should not automatically grant database-owner rights. Reaching a bastion should not automatically grant root on every target. A working SSH key should not be shared between unrelated users or automation systems. Apply least privilege at each layer: - network route; - firewall/source policy; - operating-system account; - sudo or local Administrator membership; - database role; - application authorization. Use [Cloud Firewall Best Practices](/learn/guides/firewall-best-practices-cloud-servers) for the network-policy layer. ## A bastion host is not automatically safer A bastion can become a high-value failure point if it is poorly operated. Common problems include: - unrestricted public access to the bastion; - shared administrator credentials; - private keys stored on the bastion that unlock every target; - flat routes across unrelated environments; - application software installed on the gateway; - no monitoring or patch ownership; - no emergency access path if the bastion fails. Use per-user authentication and target-side authorization where possible. Avoid turning the bastion into a permanent credential warehouse. A bastion should reduce the number of trusted paths, not become one account with unrestricted reach across the infrastructure. ## A VPN is not automatically least privilege A VPN can also become too broad. Watch for: - one shared VPN profile used by several people; - stale peers after offboarding; - all users receiving the same routes; - target firewalls trusting the entire VPN range; - customer environments reachable from one flat network; - unmanaged administrator devices with broad production reach. A VPN should provide the routes required for the administrator's role, then downstream controls should narrow access further. For MSP environments, design routes and permissions around customer boundaries rather than treating every connected technician as equally trusted. ## Windows RDP usually pushes teams toward private access sooner RDP is a powerful Windows management surface and should receive a stricter exposure model as workload importance increases. For production Windows administration, prefer: - VPN or another controlled private path; - tightly restricted sources when public reachability remains necessary; - named Windows administrator accounts; - limited local Administrators membership; - Network Level Authentication where supported; - current Windows security updates; - MFA at the access layer where the selected architecture supports it; - recurring access review. Do not use a strong Administrator password as the only control around a broadly public RDP endpoint. Review [Raff Windows VM](/products/windows-vm) for the current Windows compute path and [Raff VPC](/products/vpc) for current private-networking options. ## Databases and internal tools should normally stay private Databases, internal dashboards, monitoring interfaces, queues, and backup consoles usually do not need public administration endpoints. A safer pattern is: ```text Application VM ↓ private network Database Administrator ↓ VPN or bastion Private database/admin endpoint ``` Allow only approved application and administrator sources. If a team prefers to move database operations into a managed service boundary, review the current [Managed Databases](/products/managed-databases) offering rather than exposing a self-managed database simply for administrative convenience. ## Human and machine identities need separate access paths A CI/CD runner, backup process, monitoring service, and human administrator should not share one SSH key or one privileged account merely because they connect to the same server. Separate: - human administration; - deployment automation; - monitoring; - backup and recovery; - application credentials. This improves revocation and incident containment. If a deployment credential is exposed, the team should be able to disable it without locking out every administrator. ## Small teams should optimize for understandable security A remote-access design that nobody understands will eventually accumulate permanent exceptions. ### Solo developer or disposable workload Restricted public SSH may remain appropriate when the VM is low risk and the source can be narrowly restricted. ### Small production team A bastion or VPN becomes more useful when several administrators, private databases, or multiple application servers exist. ### Mixed Linux and Windows environment A VPN/private-access model is often easier because one workstation may need SSH, RDP, database clients, and internal dashboards. ### MSP environment Customer separation becomes the primary requirement. Avoid one credential, route, gateway, or private network that gives every technician access to every client. Use [Private Cloud Networking for MSPs](/learn/guides/private-cloud-networking-for-msps) for network separation and [Secure Remote Access for MSPs](/learn/guides/secure-remote-access-for-msps-bastion-vpn-zero-trust) for technician-access design. ## When should you move away from public SSH? Revisit the model when: - a second or third production server is added; - a database moves to a separate host or managed service; - Windows/RDP is introduced; - contractors or MSP technicians require access; - administrator source IPs change frequently; - customers ask for access evidence; - several public management endpoints need independent review; - one server starts acting as a gateway to other systems. Use [Private vs Public Admin Access](/learn/guides/private-vs-public-admin-access) for the broader transition decision. ## Access lifecycle matters more than the initial architecture Every model needs recurring review of: - human users; - SSH keys; - Windows accounts; - VPN peers or memberships; - administrator groups; - firewall rules; - private routes; - temporary vendor access; - break-glass credentials. When someone leaves, remove access across the complete path. Deleting a cloud account is incomplete if an SSH key, Windows user, VPN peer, or database credential still works. Use [Cloud Access Reviews for Small Teams](/learn/guides/cloud-access-reviews-small-teams-ssh-admin-permissions) for the governance process. ## Break-glass access prevents private administration from becoming a lockout Bastions and VPNs can fail. DNS, routing, identity systems, or firewall policy can fail too. Production environments should document an emergency path answering: 1. Who may authorize emergency access? 2. Which recovery credential or console is used? 3. How is that method protected? 4. Which systems can it reach? 5. How is emergency use recorded? 6. What gets rotated afterward? 7. How is the normal access path restored? A break-glass path should remain exceptional rather than becoming the easiest everyday login method. ## Recovery testing should include the access path Restoring a VM is not enough if administrators cannot reach it afterward. During restore or rebuild testing, verify: - the expected private network is attached; - routes and firewall rules exist; - the bastion or VPN can reach the target; - SSH/RDP identities remain valid intentionally; - private DNS resolves correctly; - emergency console or break-glass access still works. Use [Restore Testing Checklist for Production VMs](/learn/guides/restore-testing-checklist-production-vms) for the wider recovery workflow. ## How this maps to Raff A Raff access architecture can evolve without hard-coding one model into every server. ```text Low-risk VM → tightly restricted public SSH Growing production environment → private VPC paths → bastion or approved VPN access Sensitive / multi-customer environment → scoped routes → named identities → target-level authorization → recurring access review ``` Relevant Raff paths to review include: - [Raff Cloud Servers](/products/raff-vm); - [Windows VM](/products/windows-vm); - [VPC](/products/vpc); - [Security](/products/security); - [Site-to-Site VPN](/products/site-to-site-vpn); - [Data Protection](/products/data-protection); - [Managed Databases](/products/managed-databases). Use the live product and [pricing](/pricing) pages for current availability, limits, and commercial values. This guide intentionally avoids hard-coded VPN pricing, peer limits, tunnel pricing, or network-capacity figures because those are mutable product details rather than durable access-architecture principles. Raff provides infrastructure building blocks. Your team still owns operating-system users, SSH keys, Windows accounts, VPN membership, target permissions, offboarding, and workload-level authorization. :::cta Explore Raff VPC Use controlled private paths when production administration should no longer depend on directly exposed management ports. ::: ## Access model checklist ### Restricted public SSH - [ ] Environment is small and low risk. - [ ] Only named administrators have access. - [ ] Source reachability is tightly restricted where practical. - [ ] Individual SSH keys are used. - [ ] The server is patched and monitored. ### Bastion host - [ ] Target management ports remain private. - [ ] The bastion runs only required services. - [ ] Administrator identities are individual. - [ ] Routes to target systems are narrow. - [ ] Bastion failure has a documented recovery path. ### VPN - [ ] Routes are limited to required networks. - [ ] VPN membership is reviewed and offboarded. - [ ] Target firewalls still enforce least privilege. - [ ] Mixed SSH/RDP/database access is intentionally scoped. ### Every model - [ ] Human and machine identities are separated. - [ ] Databases remain private where practical. - [ ] Temporary access expires. - [ ] Network reachability is separated from privilege. - [ ] Break-glass access is documented. - [ ] Restore tests include administrative reachability. :::cluster ## Frequently asked questions ### What is a bastion host? A bastion host is a hardened administrative gateway used to reach private servers without exposing every target management port directly to the public internet. ### What is the difference between a bastion host and a VPN? A bastion host is a controlled gateway for administration sessions, while a VPN creates authenticated private-network reachability to approved resources and protocols. They can also be used together. ### Is a bastion host better than a VPN? Not universally. A bastion is often simpler for focused SSH or RDP administration. A VPN is usually more practical when administrators need several private protocols, databases, dashboards, or mixed Linux and Windows access. ### Is public SSH safe for a cloud server? It can be acceptable for simple, low-risk workloads when source access is restricted, individual SSH keys are used, the operating system is patched, and access is monitored and reviewed. ### What is the difference between SSH and a VPN? SSH authenticates a session to a server. A VPN creates private network connectivity. SSH commonly runs over a VPN, so the two technologies are complementary. ### Should RDP be publicly accessible? Broad public RDP should not be the default for important Windows workloads. Prefer private or tightly restricted reachability plus named users, current patches, NLA where supported, and an appropriate MFA-capable access layer. ### Should databases be publicly accessible for administration? Usually no. Keep database administration on private or tightly controlled paths and restrict access to approved application and administrator sources. ### Can a bastion and VPN be used together? Yes. A VPN can provide entry to a private management network while a bastion creates an additional privileged boundary before sensitive servers. ### Does a VPN automatically provide least privilege? No. A VPN creates reachability. Target firewalls, operating-system accounts, database roles, and application permissions still require separate authorization. ### When should a small team stop using public SSH? Reconsider direct public SSH when the environment adds more administrators, several servers, private databases, Windows workloads, contractors, customer systems, or formal access-review requirements. ## Conclusion Bastion hosts, VPNs, and public SSH solve different parts of remote administration. Use restricted public SSH when the environment is small and direct Linux administration remains easy to control. Use a bastion host when private servers mainly need one hardened entry point. Use a VPN when administrators need private connectivity across several protocols and systems. Combine them only when the additional boundary creates enough value to justify the operational complexity. The strongest access model is the one your team can explain and maintain: narrow network reachability, named identities, target-level least privilege, predictable offboarding, and a recovery path when the normal gateway is unavailable. ## Sources - [NIST SP 800-207: Zero Trust Architecture](https://csrc.nist.gov/pubs/sp/800/207/final) - [CISA: SSH Authorized Keys](https://www.cisa.gov/eviction-strategies-tool/info-attack/T1098.004) - [Raff VPC](/products/vpc) - [Raff Security](/products/security) - [Raff Site-to-Site VPN](/products/site-to-site-vpn) - Product details reviewed: 2026-09-16 --- ### User Access Review for Cloud Servers: SSH Keys, Admins, and Permissions URL: https://rafftechnologies.com/learn/guides/cloud-access-reviews-small-teams-ssh-admin-permissions Description: Run an access review for cloud servers covering users, SSH keys, RDP, API keys, privileged access, offboarding, private-network reachability, and recovery permissions. **An access review is a recurring check of who and what can reach your systems, what each identity can do, why that access still exists, and whether it should be kept, reduced, rotated, disabled, or removed.** A useful cloud access review covers human accounts, SSH keys, Windows/RDP users, API keys, service accounts, private-network membership, recovery permissions, and other privileged paths—not only users in a cloud dashboard. For **Raff Technologies** environments, the same principle applies across Linux VMs, Windows workloads, private networking, automation, and recovery: every privileged path should have a known owner, current purpose, appropriate scope, and clear next action. The practical goal is simple: > **No privileged access should survive only because nobody remembers why it exists.** ## Access review: quick framework For every user, key, token, service account, and privileged network path, answer five questions: 1. **Who or what owns it?** 2. **Which systems can it reach?** 3. **Which actions can it perform?** 4. **Is that access still required today?** 5. **What should happen next?** Every item should end in one of five decisions: | Decision | Meaning | |---|---| | Keep | Access is justified and correctly scoped | | Reduce | Access is broader than the current role requires | | Rotate | The credential is old, shared, exposed, or difficult to attribute | | Disable | Access may be needed again but should not remain active now | | Remove | The business or technical reason no longer exists | “Reviewed” is not an outcome. If excessive or unexplained access is found, the review should produce a change, owner, or documented dependency. ## What is a user access review? A **user access review** verifies that current permissions still match current responsibilities. In cloud infrastructure, that usually means reviewing more than human user accounts. Include: - cloud/project users; - Linux accounts and SSH keys; - Windows and RDP users; - sudo and local Administrator membership; - API keys and tokens; - CI/CD and service identities; - VPN, bastion, and private-network access; - public administrative exposure; - backup and recovery permissions; - break-glass access. The complete path is: ```text Identity ↓ Credential ↓ Network reachability ↓ Authentication ↓ Privilege ↓ Resource or business action ``` Removing a contractor from a cloud dashboard is incomplete if their SSH key still works. Disabling a Windows account is incomplete if the person still knows a shared Administrator password. Rotating one API key is incomplete if an old personal token still runs in CI/CD. ## Access reviews should cover identity, credentials, privileges, and reachability together Checking only one layer creates false confidence. | Layer | Examples | Review question | |---|---|---| | Human identity | Cloud user, Linux user, Windows user | Does this person still need access? | | Credential | SSH key, password, API key, certificate | Is it attributable, protected, and current? | | Machine identity | CI/CD job, monitoring agent, backup process | Does the automation still exist and need this scope? | | Privilege | Root, sudo, local Administrator, backup deletion | Is the permission broader than required? | | Reachability | Public SSH/RDP, VPN, VPC, bastion | Can this identity reach more systems than it should? | | Recovery access | Snapshot, backup, restore, break-glass access | Can one identity remove both production and recovery? | A strong access review evaluates all of these together. ## User access review best practices for small teams Small teams do not need heavyweight governance software to run a useful review. They do need a repeatable process. ### 1. Maintain a current access inventory Track privileged access in one place with at least: | Field | Example | |---|---| | Identity | Jane Doe / deploy-api | | Type | Human / service account / SSH key | | Owner | Platform team | | Environment | Production | | Resource scope | web-01, db-prod | | Privilege | SSH user / sudo / API write | | Reason | On-call administration | | Last reviewed | 2026-09-01 | | Expiry | None / project end date | | Decision | Keep / reduce / rotate / disable / remove | The inventory does not need to mirror every operating-system detail. It needs enough information to explain why access exists and who is accountable for it. ### 2. Prioritize high-impact permissions Review identities first when they can: - create or delete infrastructure; - change firewall rules or private-network routes; - add administrators or SSH keys; - manage DNS; - view or change secrets; - export customer data; - restore or delete recovery points; - modify production databases; - change billing or account-level settings; - disable monitoring or logging. These permissions have larger failure impact than ordinary read-only access. ### 3. Prefer named identities over shared credentials Shared credentials make access reviews difficult because the team cannot reliably attribute use. Avoid long-lived shared: - root passwords; - Administrator passwords; - SSH private keys; - API tokens; - VPN credentials; - generic production accounts. Where a shared emergency credential is unavoidable, treat it as break-glass access and protect, audit, and rotate it accordingly. ### 4. Give temporary access an expiry condition Temporary access should not silently become permanent. For migration, support, contractor, or incident access, record: - owner; - exact scope; - reason; - start date; - expiry date or completion condition. ### 5. Verify changes after the review A planned change and an applied change are not the same thing. If the review says “remove SSH key,” verify that the key no longer authenticates. If a Windows account is disabled, verify sign-in is blocked. If an API token is rotated, confirm the replacement works and the old credential is rejected. ## SSH key review should be treated like user-account review SSH keys are easy to distribute and forget. Each trusted key should have a known owner, purpose, server scope, and removal condition. Investigate or remove a key when: - its owner left the team; - nobody can identify who owns it; - several people share the same private key; - the private key may have been exposed; - it is trusted by more servers than required; - the automation or project that used it has been retired. Linux access reviews should also cover: - active interactive users; - service users with shell access; - sudo groups; - direct root access; - deployment users; - old keys in `authorized_keys`; - credentials in home directories; - forgotten automation accounts. A developer who needs logs does not automatically need unrestricted sudo. ## Windows and RDP access reviews need separate attention Windows administration has different access patterns from Linux SSH. Review: - RDP users; - local Administrators membership; - shared Administrator credentials; - vendor and contractor accounts; - disabled but reusable accounts; - saved credentials on jump hosts or staff devices; - public RDP exposure; - Network Level Authentication where supported; - MFA at the access layer where the selected design supports it; - sign-in evidence where retained. A user may need Remote Desktop access without needing local Administrator rights. If the network path itself is too broad, use [Private vs Public Admin Access](/learn/guides/private-vs-public-admin-access) and [Bastion Host vs VPN vs Public SSH](/learn/guides/bastion-host-vs-vpn-vs-public-ssh) to redesign the access boundary rather than only reviewing users on the existing path. ## API keys and service accounts need owners too Machine identities often outlive human accounts because nobody notices them until an automation breaks. Review credentials used by: - CI/CD pipelines; - infrastructure automation; - monitoring; - backup jobs; - applications; - integrations and webhooks; - migration scripts; - command-line tooling. Each machine identity should answer: | Field | Review question | |---|---| | Owner | Which person or team is accountable? | | Purpose | Which live workload still needs it? | | Scope | Which resources and actions can it access? | | Storage | Where is the credential protected? | | Rotation | How can it be replaced safely? | | Evidence | Is recent use visible? | | Retirement | What event should cause removal? | A credential without an owner is difficult to rotate safely. A service identity without a current service should be disabled or removed. Do not keep long-lived secrets in source code, reusable VM images, tickets, shared chat, or broadly accessible documentation merely because updating the automation is inconvenient. ## Offboarding is the most urgent access-review event A scheduled review can wait for its planned date. Offboarding should not. When an employee, vendor, or contractor leaves, remove relevant access across: - cloud/project membership; - Linux users and SSH keys; - Windows and RDP accounts; - sudo and administrator groups; - VPN or bastion membership; - API keys and personal tokens; - source-control and CI/CD systems; - password managers and secrets; - monitoring and incident tooling; - DNS and domain administration; - billing access; - customer environments; - backup and recovery administration. Rotate shared credentials the departing person could still use. Removing the named account is not enough if copied private keys, shared passwords, or personal tokens remain valid. ## How often should access reviews happen? There is no universal review cadence for every workload. Frequency should follow risk, team change, privilege level, and contractual requirements. A practical starting model can be: | Access area | Review trigger or cadence | |---|---| | Employee offboarding | Immediately | | Contractor access | At task completion and during long engagements | | Production administrators | After material role/team changes and on a recurring schedule | | SSH/RDP access | Recurring, with frequency based on exposure and change rate | | API keys and service accounts | Recurring and after ownership changes | | Break-glass access | After every use and during periodic recovery checks | | Billing and recovery-deletion privileges | Recurring because impact is high | | Public admin exposure | After architecture changes and on a recurring schedule | Increase frequency when contractors are common, customer data is sensitive, an MSP manages many environments, or privileges change frequently. ## Privileged access review should focus on business actions Role names can hide excessive privilege. Review what an identity can actually do. Instead of asking only whether someone is an “admin,” ask whether the identity can: - create or delete infrastructure; - modify networking; - add other administrators; - export customer data; - change secrets; - delete recovery points; - modify production databases; - alter billing; - disable monitoring. A support contractor may need logs without database export rights. A deployment identity may need to update one service without being able to delete backups. Least privilege becomes easier to evaluate when access is described as actions rather than titles. ## Review network reachability together with identities A user may have limited operating-system permissions but still be able to connect to too many resources. Review: - which servers expose SSH or RDP publicly; - which source ranges are allowed; - who can join a VPN or other private-access path; - which routes those users receive; - whether one private network creates unnecessary lateral reachability; - whether databases are reachable from unrelated systems; - whether IPv6 exposure matches IPv4 policy; - whether retired hosts still appear in firewall rules. Private networking reduces exposure. It does not create implicit trust. Use [Cloud Firewall Best Practices](/learn/guides/firewall-best-practices-cloud-servers) and [Private Networking: Public vs Private Traffic](/learn/guides/private-networking-public-vs-private-traffic) for the network-policy layer. ## Break-glass access needs its own review Break-glass access is intentionally powerful and rarely used, which makes it easy to forget. Confirm: - the emergency identity or credential still works; - access is protected from casual use; - authorized users are still correct; - recovery instructions are current; - use is logged where possible; - credentials are rotated after use or exposure; - the emergency path has not become routine administration. An emergency path that cannot be used during an incident is not useful. An emergency path used every day is no longer an emergency control. ## Backup and recovery permissions deserve stricter review Recovery systems are high-impact because an identity able to delete production and every backup can remove the team's recovery options. Review who can: - create recovery points; - restore them; - change retention; - delete snapshots or backups; - access application-level exports; - alter backup credentials. Where workload impact justifies it, separate ordinary server administration from backup-deletion rights. Use [Cloud Snapshots vs Backups](/learn/guides/snapshots-vs-backups-cloud-server) and [Restore Testing Checklist for Production VMs](/learn/guides/restore-testing-checklist-production-vms) for the recovery side of the design. ## Access review evidence: activity is not authorization The access inventory shows who **can** act. Logs and activity records can help show who **did** act. Useful evidence may include: - SSH login history; - sudo activity; - Windows security events; - cloud account changes; - API-key use; - firewall and private-network changes; - deployment records; - backup restore/deletion events; - incident records. Do not keep an unexplained privilege indefinitely merely because recent activity is unclear. Investigate the owner and dependency, then make an explicit decision. ## A practical access-review meeting for small teams A lightweight review can follow this sequence: 1. Inventory users, keys, tokens, service identities, and privileged paths. 2. Assign a named owner to every item. 3. Compare each item with the owner's current role or workload. 4. Review public and private network reachability. 5. Check recent use where reliable evidence exists. 6. Choose keep, reduce, rotate, disable, or remove. 7. Assign required changes to owners. 8. Apply the changes. 9. Verify the changes took effect. 10. Confirm emergency access still works as designed. 11. Record unresolved dependencies and the next review trigger. The output should be a change list with owners and due dates, not only a completed checklist. ## MSP access reviews need customer-level separation MSPs and managed IT providers have a larger version of the same problem because administrators may reach several customer environments. Review whether: - one credential is reused across customers; - one VPN or private network creates excessive lateral access; - customer production access can be attributed to a named person; - contractors retain access after an engagement ends; - one automation token can modify unrelated tenants; - backup or recovery permissions cross customer boundaries. Prefer named users, customer-scoped permissions, separate credentials, restricted network paths, auditable access, and explicit offboarding. Use [Private Cloud Networking for MSPs](/learn/guides/private-cloud-networking-for-msps) and [Secure Remote Access for MSPs](/learn/guides/secure-remote-access-for-msps-bastion-vpn-zero-trust) for the surrounding architecture. ## How this applies to Raff infrastructure A Raff-focused access review can include: - [Raff Cloud Servers](/products/raff-vm) for Linux users, SSH keys, root/sudo access, and VM administration; - [Windows VM](/products/windows-vm) for RDP users and local Administrator access; - [Raff VPC](/products/vpc) for current private-networking paths; - [Data Protection](/products/data-protection) for recovery access, restore authority, and deletion rights; - Raff account/API credentials used for automation and administration. Use the live product and [pricing](/pricing) pages for current product availability, limits, and commercial values. This guide intentionally avoids hard-coded bandwidth, storage pricing, free-pool amounts, retention limits, and other mutable product details. Raff provides infrastructure controls and recovery capabilities. Your team still owns guest-OS accounts, SSH/RDP access, credential ownership, application authorization, contractor offboarding, and internal access-review policy. :::cta Review Your Raff Access Paths Audit Linux, Windows, private-network, automation, and recovery access together so every privileged path has a current owner and purpose. ::: ## User access review checklist ### Human access - [ ] Every privileged account belongs to a named person. - [ ] Departed users are removed immediately. - [ ] Contractor access has an expiry or review condition. - [ ] Linux sudo and Windows Administrator membership are justified. ### Credentials - [ ] SSH keys have identifiable owners. - [ ] Shared keys and passwords are being eliminated or controlled. - [ ] API keys and service accounts have owners and purposes. - [ ] Exposed or unexplained credentials are rotated. ### Reachability - [ ] Public SSH/RDP exposure is intentional. - [ ] VPN/private-network membership is current. - [ ] Private routes do not create unnecessary lateral access. - [ ] Firewall rules for retired systems are removed. ### Recovery - [ ] Backup and snapshot deletion rights are reviewed. - [ ] Break-glass access has current owners. - [ ] Emergency access is tested and protected. ### Review outcome - [ ] Every item ends in keep, reduce, rotate, disable, or remove. - [ ] Required changes have owners and due dates. - [ ] Applied changes are verified. - [ ] The next review trigger is recorded. :::cluster ## Frequently asked questions ### What is an access review? An access review checks who or what can reach systems, what each identity can do, why the access still exists, and whether it should be kept, reduced, rotated, disabled, or removed. ### What is a user access review? A user access review verifies that current permissions still match current responsibilities for human users and, in cloud environments, related credentials and privileged paths such as SSH keys, RDP access, and private-network membership. ### What should a cloud access review include? Review human users, Linux and Windows accounts, SSH keys, RDP access, API keys, service accounts, privileged actions, public and private reachability, break-glass access, and recovery permissions. ### How often should user access reviews happen? There is no universal cadence. Offboarding should happen immediately, while recurring reviews should be scheduled according to privilege level, team change, exposure, customer risk, and contractual requirements. ### What are user access review best practices? Maintain an inventory, use named owners, prioritize high-impact privileges, give temporary access an expiry condition, review identity and reachability together, and verify that removals or reductions actually took effect. ### Should SSH keys be reviewed like user accounts? Yes. Each key should have an owner, purpose, server scope, and removal condition. Unexplained or shared keys should be investigated and removed or rotated when no longer justified. ### Do API keys and service accounts belong in access reviews? Yes. Machine identities need owners, limited permissions, protected storage, a rotation method, usage evidence where available, and a defined retirement condition. ### What is a privileged access review? A privileged access review focuses on identities that can perform high-impact actions such as changing infrastructure, adding administrators, exporting data, modifying secrets, or deleting recovery points. ### Does private networking eliminate the need for access reviews? No. Private networking reduces reachability, but user identities, routes, firewall rules, operating-system permissions, application authorization, and stale credentials still require review. ### What is the most urgent access-review event? Offboarding. Access can exist across dashboards, servers, SSH keys, RDP accounts, tokens, repositories, VPNs, secrets, DNS, billing, and recovery systems, so it should be removed as soon as the role ends. ## Conclusion An access review keeps cloud privileges aligned with the people, services, and systems that exist today rather than the organization that existed when access was first granted. Review human and machine identities, credentials, privileges, network reachability, and recovery access together. Give every privileged item a named owner and current purpose, treat offboarding as immediate, and end every review with a concrete decision: **keep, reduce, rotate, disable, or remove**. If the review shows that the access path itself needs redesign, continue with [Private vs Public Admin Access](/learn/guides/private-vs-public-admin-access) or [Bastion Host vs VPN vs Public SSH](/learn/guides/bastion-host-vs-vpn-vs-public-ssh). ## Sources - [NIST SP 800-53 Rev. 5: Security and Privacy Controls](https://csrc.nist.gov/pubs/sp/800/53/r5/upd1/final) - [CISA: SSH Authorized Keys](https://www.cisa.gov/eviction-strategies-tool/info-attack/T1098.004) - [Raff VPC](/products/vpc) - [Raff Data Protection](/products/data-protection) - [Raff Pricing](/pricing) - Product details reviewed: 2026-09-16 --- ### API Rate Limiting Explained: Protecting Apps Without Blocking Real Users URL: https://rafftechnologies.com/learn/guides/api-rate-limiting-protecting-apps-real-users Description: Learn API rate limiting for 429 responses, rate limiting algorithms, token and leaky buckets, API keys, quotas, throttling, and protecting real users. **API rate limiting controls how much request traffic a client, user, API key, tenant, IP address, or service can generate within a defined period.** The goal is not simply to block traffic. Good rate limiting protects backend capacity, login flows, expensive endpoints, third-party dependencies, and fair access while giving legitimate clients a predictable way to recover when they reach a limit. For **Raff Technologies** workloads, rate limiting is usually an application or reverse-proxy decision layered on top of the compute, network, security, and observability controls around the workload. The best policy depends on who owns the traffic, how expensive the endpoint is, whether the caller is authenticated, and whether rejected work could instead be queued or slowed down. A useful rule is: > **Rate-limit the identity that owns the traffic, protect expensive paths first, and make 429 responses actionable for legitimate clients.** ## API rate limiting: quick decision framework | API surface | Main risk | Better limit key | Typical control | |---|---|---|---| | Public unauthenticated endpoint | Bots, scraping, accidental bursts | IP/source + route | Conservative burst + sustained limits | | Login | Brute force, credential stuffing | Account + source + route | Tight throttling, progressive delay | | Signup/password reset | Spam and abuse | Account/email/source | Frequency limits + abuse checks | | Authenticated API | Tenant or integration overuse | User, tenant, API key | Identity-aware quota | | Expensive search/report | CPU/database pressure | Identity + endpoint | Lower rate + concurrency limit | | File upload | Bandwidth, storage, processing | User/tenant + size + route | Size + frequency + concurrency | | Webhook receiver | Retry storms, bursts | Provider/account/event | Queue + backpressure | | Internal API | Service overload | Service identity + route | Service-aware rate/concurrency limits | | Admin action | High-impact misuse | Admin identity + action | Conservative limits + audit evidence | Do not begin with “100 requests per minute for everything.” Begin with **which resource or user experience needs protection**. ## What is API rate limiting? API rate limiting is a policy that restricts request activity according to a key, quota, time window, concurrency level, cost unit, or combination of those controls. Examples include: - 60 requests per minute per API key; - 5 login attempts per account in a short window; - 2 report-generation jobs running concurrently per tenant; - 100 uploads per day per workspace; - a short burst allowance followed by a lower sustained rate; - different limits for free and paid plans. The limit key matters as much as the number. A limit applied to the wrong identity can block legitimate users while failing to constrain the actor causing pressure. ## Why APIs need rate limits Rate limiting protects more than security. A production API may need protection from: - malicious scraping or brute force; - buggy clients retrying too aggressively; - batch jobs that accidentally loop; - one tenant consuming shared capacity; - expensive search/report endpoints; - file-processing spikes; - webhook retry storms; - external API or email-provider quotas; - sudden load on a database or queue; - plan or contract usage limits. OWASP API Security identifies unrestricted resource consumption as an API risk because requests can consume compute, memory, storage, bandwidth, database capacity, and paid third-party services. That makes rate limiting partly a **reliability and cost-control mechanism**, not just an abuse filter. ## Rate limiting vs throttling vs quotas These terms overlap but are useful to separate operationally. | Control | Main purpose | |---|---| | Rate limit | Restrict request activity over time | | Throttling | Slow or reject traffic when policy/capacity is exceeded | | Quota | Control a larger usage allowance, often per plan or billing period | | Concurrency limit | Restrict work executing at the same time | | Queue/backpressure | Absorb valuable work and process it at a safe rate | A product can use several at once. For example, an API may allow a short burst, enforce a per-minute request rate, cap daily usage, and permit only two heavy exports to run concurrently. ## 429 Too Many Requests: what it means **HTTP 429 Too Many Requests means the client has exceeded a rate policy and should reduce request activity.** RFC 6585 defines the status code and allows the response to include `Retry-After` so the client knows when to retry. A useful 429 response should help a legitimate developer recover. Include, where appropriate: - a clear error code/message; - `Retry-After` or equivalent retry guidance; - the scope of the limit, such as user, token, tenant, or route; - safe quota information; - a request/correlation ID; - documentation for public APIs. A minimal example: ```http HTTP/1.1 429 Too Many Requests Retry-After: 30 Content-Type: application/json { "error": "rate_limit_exceeded", "retry_after_seconds": 30 } ``` Do not expose internal enforcement details that make abuse easier merely to make the error verbose. ## Rate-limit headers are useful, but the standard is still evolving Public APIs often expose quota information through provider-specific headers such as `X-RateLimit-Limit`, `X-RateLimit-Remaining`, and `X-RateLimit-Reset`. The IETF HTTPAPI working group is also developing standardized `RateLimit-Policy` and `RateLimit` fields. As of May 2026, that work remains an **Internet-Draft**, not a finalized RFC, so treat it as work in progress rather than a settled standard. The durable design principle is simpler: if customers depend on your API, give them enough information to avoid unnecessary throttling and implement backoff correctly. ## Choose the right rate-limit key The key identifies who or what is consuming the quota. | Key | Good fit | Main limitation | |---|---|---| | IP address | Unauthenticated traffic and coarse abuse controls | NAT, VPNs, offices, mobile networks share IPs | | User ID | Authenticated user fairness | One user may act for a larger organization | | Tenant/account | B2B SaaS fairness | Large tenants may need higher policy limits | | API key | Integrations and automation | Shared keys reduce attribution | | Route/action | Protecting expensive operations | Usually needs another identity dimension | | Service identity | Internal APIs | Requires reliable service authentication | | Plan | Contract or product quota | Not enough for burst protection | For authenticated APIs, **user, tenant, API key, or organization** is usually more meaningful than IP alone. IP-based controls still help at the public edge, but they should not be the only fairness mechanism for logged-in users. ## Do not use one global limit for every endpoint Endpoints have different costs and risks. A health check, login request, database search, export, upload, and billing action should not automatically share one policy. Classify endpoints by: 1. **cost** — CPU, database, storage, bandwidth, external API usage; 2. **security sensitivity** — login, reset, admin, account changes; 3. **business impact** — writes versus reads, destructive actions; 4. **expected burst behavior** — UI page load, batch process, webhook; 5. **caller identity** — anonymous, user, tenant, API client, internal service. Then apply the narrowest policy that protects the actual bottleneck. ## Burst limits and sustained limits solve different problems Normal applications can create legitimate bursts. A dashboard may load several resources at once. A mobile client may synchronize after reconnecting. A batch workflow may submit several related operations quickly. A good policy often separates: - **burst capacity** for short legitimate spikes; - **sustained rate** for ongoing usage; - **quota** for longer-term allowance; - **concurrency** for expensive active work. This is why token-bucket and similar designs are popular: they can allow controlled bursts while still limiting average throughput. ## Rate limiting algorithms: fixed window, sliding window, token bucket, leaky bucket The algorithm matters, but only after the policy is clear. | Algorithm | Strength | Main trade-off | |---|---|---| | Fixed window | Simple to implement and explain | Boundary spikes near window reset | | Sliding window | Smoother recent-time enforcement | More state/calculation | | Token bucket | Allows bursts while controlling average rate | Bucket size/refill need tuning | | Leaky bucket | Smooth output rate | Bursts may be delayed or rejected | | Concurrency limiter | Protects expensive in-flight work | Does not control total request volume | ### Fixed window A counter resets on a fixed boundary such as each minute. It is easy to operate but can permit traffic spikes around the boundary. ### Sliding window The server evaluates activity across the most recent interval rather than a shared reset point. It gives smoother enforcement at higher implementation cost. ### Token bucket Tokens refill at a defined rate. Requests consume tokens. A larger bucket permits short bursts without allowing unlimited sustained traffic. ### Leaky bucket Work leaves the bucket at a controlled rate, which is useful when smoothing traffic matters more than allowing immediate bursts. For most small teams, the best algorithm is the one that matches expected client behavior and can be observed and tuned reliably. ## Rate limiting should protect expensive endpoints first If implementation time is limited, prioritize endpoints where one request can trigger disproportionate work. Start with: - login and password reset; - signup and verification; - expensive search; - reports and exports; - file uploads; - AI/compute-heavy operations; - external API calls; - email/SMS actions; - webhook receivers; - administrative writes. A cheap cached read endpoint may tolerate much higher request rates than a report that performs several database joins and generates a file. ## Rate limiting should work with queues and backpressure Some valid work should be delayed rather than rejected. Queues are useful for: - exports; - image/file processing; - webhook processing; - email delivery; - background reports; - batch jobs; - long-running tasks. A useful pattern is: ```text Request ↓ validate + authorize Accept job ↓ Queue ↓ controlled concurrency Workers ↓ Result / callback / status ``` Rate limits still matter because a queue can also be overwhelmed. The difference is that valuable work can be absorbed and processed safely instead of failing immediately. Read [Cron Jobs vs Queues vs Workflow Automation](/learn/guides/cron-jobs-queues-workflow-automation-background-work) for the wider background-work decision. ## Login rate limiting needs special treatment Authentication endpoints are both security-sensitive and user-sensitive. Avoid simplistic policies that permanently lock accounts after a small number of failures. Attackers can intentionally trigger those failures and create denial of service for real users. A stronger design can combine: - account-aware throttling; - source/IP signals; - progressive delay; - device/session context where available; - temporary challenge or verification; - monitoring for distributed attempts; - clear recovery paths. The exact policy depends on the authentication system, but the goal is to slow abuse without giving an attacker an easy way to lock legitimate users out. ## API keys and rate limits should be designed together API keys are useful rate-limit identities because they can map traffic to a known integration. Prefer: - one key per integration/customer/environment where practical; - an owner for every key; - scoped permissions; - separate development and production keys; - rotation and revocation procedures; - usage monitoring by key. A shared key across several applications makes both rate limiting and incident investigation harder. Use [API Keys for Automation](/learn/guides/raff-api-keys-automation-small-teams) for the credential-lifecycle side of the design. ## Rate limiting is not DDoS protection Rate limiting and DDoS protection can both support availability, but they solve different layers of the problem. | Control | Primary job | |---|---| | Firewall | Restrict ports, protocols, and network sources | | DDoS protection | Detect/filter high-volume or hostile traffic patterns | | WAF/application filtering | Inspect HTTP requests and web attack patterns | | API rate limiting | Allocate request capacity by endpoint and identity | | Concurrency limit | Protect active workers/dependencies | | Quota | Enforce longer-term usage policy | Application-aware rate limiting knows things network-level controls often do not: user ID, tenant, API key, endpoint cost, plan, or business action. Use [Cloud Security Fundamentals](/learn/guides/cloud-security-fundamentals) and [Cloud Firewall Best Practices](/learn/guides/firewall-best-practices-cloud-servers) for the surrounding security layers. ## Observe rate-limit behavior after launch A rate limit should not be “set and forgotten.” Track signals such as: - 429 responses by endpoint; - 429s by user/tenant/API key; - top limited clients; - request rate before and after limiting; - backend CPU/memory/database load; - queue depth; - retry behavior; - support tickets about throttling; - error rates after limit changes; - cost/resource trends on expensive endpoints. Interpret the signals carefully. If only known abusive clients hit limits, the control may be working as intended. If normal users repeatedly hit them, the limit may be too strict or the application may be generating unnecessary requests. Read [Observability for Small Teams](/learn/guides/observability-small-teams-metrics-logs-traces) for the monitoring layer. ## API rate limiting best practices A practical production baseline is: 1. **Define the resource being protected.** CPU, database, login flow, third-party API, storage, or fair tenant capacity. 2. **Choose the responsible identity.** IP, user, tenant, API key, service, or action. 3. **Protect high-cost endpoints first.** Do not spend the same engineering effort on every route. 4. **Allow normal bursts deliberately.** Avoid punishing legitimate page loads or synchronization. 5. **Use concurrency limits for expensive work.** Request count alone may not protect active workers. 6. **Queue valuable asynchronous work.** Rejecting every burst is not always the best UX. 7. **Return useful 429 responses.** Include retry guidance where possible. 8. **Document public limits.** Customers should not discover quotas only through production failures. 9. **Monitor limit hits.** Rate policy needs evidence to improve. 10. **Review policy after traffic or architecture changes.** New endpoints and larger customers can change the correct threshold. ## How API rate limiting fits Raff Rate limiting is generally implemented close to the application because the application knows the identity and business cost of each request. A Raff-hosted API can apply controls at several layers: ```text Client traffic ↓ Network/security controls ↓ Reverse proxy or gateway ↓ Application middleware ↓ Queue / workers / database ``` [Raff VM](/products/raff-vm) and [Linux VM](/products/linux-vm) can host reverse proxies, API services, containers, queues, caches, workers, and application-level limiters. [Raff VPC](/products/vpc) can keep supporting services on private paths where appropriate, while [Raff Security](/products/security) covers the current infrastructure security surface. The important ownership boundary is that Raff provides the infrastructure layer; your application still decides which user, tenant, route, API key, or business action receives which rate policy. Use the live [pricing page](/pricing) for current commercial details rather than encoding mutable plan, bandwidth, or deployment claims inside an evergreen rate-limiting guide. :::cta Deploy an API on Raff Run your API on Raff VM or Linux VM and apply rate limits at the reverse-proxy, application, queue, or service layer that best understands your traffic. ::: ## API rate limiting checklist ### Policy - [ ] The protected resource is clear. - [ ] Each high-risk endpoint has an owner. - [ ] Anonymous and authenticated traffic use appropriate keys. - [ ] Expensive endpoints have specific controls. ### Client behavior - [ ] Normal bursts are supported deliberately. - [ ] 429 responses include useful retry guidance. - [ ] Public API limits are documented. - [ ] Client retry/backoff behavior is understood. ### Backend protection - [ ] Database-heavy work has tighter controls. - [ ] Concurrency is limited where request count is insufficient. - [ ] Queues have backpressure and maximum growth controls. - [ ] Third-party dependencies cannot be flooded by one client. ### Operations - [ ] 429s are measured by endpoint and identity. - [ ] Limit changes can be rolled back. - [ ] Support can identify why a legitimate client was limited. - [ ] Policies are reviewed after incidents and major traffic changes. :::cluster ## Frequently asked questions ### What is API rate limiting? API rate limiting controls how much request traffic a client, user, API key, tenant, IP address, or service can generate during a defined period or quota window. ### What does 429 Too Many Requests mean? HTTP 429 means the client exceeded a server-defined rate policy. A useful response should tell legitimate clients how to slow down or when to retry, commonly with `Retry-After` where appropriate. ### What is the best rate limiting algorithm? There is no universal best algorithm. Fixed window is simple, sliding window is smoother, token bucket supports bursts, and leaky bucket smooths request flow. Choose based on expected client behavior and operational needs. ### What is the difference between token bucket and leaky bucket? Token bucket accumulates capacity and can allow controlled bursts. Leaky bucket releases work at a steadier rate, making it useful when smoothing traffic is more important than immediate bursts. ### Should API rate limits use IP address or API key? Use IP-based controls for coarse anonymous traffic, but authenticated APIs usually benefit from user-, tenant-, service-, or API-key-based limits because they better represent responsibility. ### Is API throttling the same as rate limiting? The terms often overlap. Rate limiting defines the usage policy, while throttling usually describes slowing or rejecting traffic when that policy or capacity boundary is reached. ### Is API rate limiting the same as DDoS protection? No. DDoS protection addresses broader attack traffic, while API rate limiting allocates application request capacity by identity, endpoint, quota, or business cost. ### Should every API endpoint have the same limit? No. Endpoint cost and risk differ. Login, uploads, reports, search, webhooks, and cheap cached reads often need different rate or concurrency policies. ### How do I avoid blocking real users with rate limits? Use identity-aware keys, allow expected bursts, apply endpoint-specific limits, return clear 429 guidance, monitor legitimate limit hits, and queue valuable work when delay is better than rejection. ### Should public APIs expose rate-limit headers? Public APIs should provide enough quota and retry information for clients to behave correctly. Header conventions vary, and the IETF RateLimit header work remains an Internet-Draft as of 2026. ## Conclusion API rate limiting works best when it is treated as a product reliability control rather than a single security number. Identify the expensive or sensitive resource, choose the identity responsible for the traffic, allow normal bursts intentionally, protect heavy work with concurrency or queues, return useful 429 responses, and monitor real behavior after launch. The correct policy will change as your API, customers, and workload architecture evolve. Keep the enforcement understandable enough that your team can explain why a request was limited and adjust the rule without breaking legitimate users. ## Sources - [OWASP API4:2023 — Unrestricted Resource Consumption](https://owasp.org/API-Security/editions/2023/en/0xa4-unrestricted-resource-consumption/) - [RFC 6585 — Additional HTTP Status Codes](https://www.rfc-editor.org/rfc/rfc6585) - [IETF HTTPAPI — RateLimit header fields for HTTP, Internet-Draft](https://datatracker.ietf.org/doc/draft-ietf-httpapi-ratelimit-headers/) - [NGINX — ngx_http_limit_req_module](https://nginx.org/en/docs/http/ngx_http_limit_req_module.html) - [Envoy — Global Rate Limiting](https://www.envoyproxy.io/docs/envoy/latest/intro/arch_overview/other_features/global_rate_limiting) - Product details reviewed: 2026-09-16 --- ### Serverless Functions vs VMs: What Small Teams Should Choose URL: https://rafftechnologies.com/learn/guides/serverless-functions-vs-vms-small-teams Description: Compare serverless functions vs VMs for small teams: workload fit, cost shape, state, scaling, operations, recovery, and when a mixed architecture works best. **Serverless functions are usually the better fit for event-driven, bursty, scheduled, or isolated units of work. Virtual machines are usually the better fit for long-running applications, persistent services, custom operating-system requirements, Docker Compose stacks, and workloads that need direct server control.** For small teams, the decision is less about which technology is newer and more about **which operating model creates less unnecessary work**. At **Raff Technologies**, the practical choice can stay incremental: use [Raff Functions](/products/serverless-functions) when the unit of work can run independently, and use [Raff VM](/products/raff-vm) when the workload needs a full server environment. A production system can use both without forcing the entire application into one model. ## Serverless functions vs VMs: quick decision | Workload | Better default | Why | |---|---|---| | Customer-facing app server | VM | Stable runtime, full environment, predictable control | | HTTP webhook | Function | Small event-driven unit of work | | Scheduled cleanup/report | Function | Runs only when triggered | | Docker Compose application | VM | Several long-lived services share one environment | | File processing after upload | Function | Event-driven and easy to isolate | | Constant queue worker | VM | Always-on process may fit capacity billing better | | Small API endpoint | Function or VM | Depends on state, traffic, runtime, and deployment model | | Self-hosted database/cache | VM or managed service | Persistent state and long-lived service behavior | | Batch job | Function or VM | Depends on duration, runtime weight, and frequency | | Custom daemon/system package | VM | Needs OS-level control | A useful rule is: > **Use a function when the unit of work can be isolated. Use a VM when the environment itself is part of the workload.** ![Decision matrix comparing Raff Functions and Raff VM for small team workloads](https://raff-images.s3.raffusercloud.com/serverless_functions_vs_vm_decision_matrix_webp_d031cd6670.png) ## What is the difference between serverless functions and virtual machines? A **virtual machine** gives your team a persistent operating-system environment. You choose the OS, install packages, run services, manage processes, configure networking, control the filesystem, and decide how the server starts, scales, and recovers. A **serverless function** gives your team a smaller execution unit. You deploy code and configuration, then the platform starts that code in response to a request, schedule, event, or other trigger. The architectural difference looks like this: ```text Virtual machine ↓ Operating system ↓ Runtime / Docker / services ↓ Application processes ``` versus: ```text Trigger ↓ Function runtime ↓ One bounded unit of application work ``` Both ultimately use compute. What changes is **how much infrastructure lifecycle your team owns**. ## Serverless functions reduce infrastructure ownership for bounded work Functions are strongest when the work has a clear start and finish. Typical examples include: - HTTP handlers; - webhooks; - cron and scheduled jobs; - image or document processing; - object-storage events; - notification fanout; - API callbacks; - light ETL steps; - form processing; - one-off future jobs; - event-driven automation. The application does not need a permanently running server only to wait for the next event. ![Architecture diagram showing HTTP cron object storage and one-off triggers running through Raff Functions](https://raff-images.s3.raffusercloud.com/raff_functions_event_driven_architecture_webp_f28cb55a8e.png) The main operational benefit is separation. A billing webhook, nightly cleanup task, or file transform does not need to share the same process lifecycle as the customer-facing application. ## VMs are stronger when the workload needs a persistent environment A VM is usually the cleaner fit when the workload wants to behave like a server rather than a task. Use a VM when you need: - a long-running application process; - Docker Engine or Docker Compose; - full SSH administration; - system packages or custom daemons; - persistent local services; - long-lived TCP connections; - direct process supervision; - custom filesystem layout; - a reverse proxy; - a continuously running worker; - self-managed databases or queues; - infrastructure tooling that expects a normal Linux server. For many early SaaS products, a VM remains a very practical architecture: ```text Internet ↓ Raff VM ├─ reverse proxy ├─ application ├─ worker └─ monitoring agent ↓ Managed Database / Object Storage where appropriate ``` That model can be easier to understand and recover than splitting an application into many deployment units before there is an operational reason to do so. ## Serverless vs VM cost depends on workload shape A VM and a function expose different cost shapes. A VM is mainly **capacity-based**: the server exists continuously and the team pays for that provisioned environment. A function is mainly **execution-based**: cost follows runtime activity more closely. That means neither is automatically cheaper. | Workload pattern | VM economics | Function economics | |---|---|---| | Runs continuously | Often natural | Continuous execution can remove much of the usage-based advantage | | Runs a few times per day | VM may sit idle | Strong fit for execution-based billing | | Highly bursty | May need spare capacity | Can follow bursts without permanent capacity | | Heavy persistent service | Strong fit | Often awkward as a function | | Short event-driven work | Possible but may waste idle server capacity | Strong fit | | Many small independent jobs | Operationally noisy on one VM | Functions can isolate them | The decision should include **engineering time** as well as infrastructure cost. A function may cost more per active unit of compute but save enough operator time to be worthwhile. A VM may be inexpensive and simple when the workload already uses most of the server continuously. Use the live [Raff Pricing](/pricing) page for current VM and Functions pricing rather than relying on numbers embedded in an evergreen guide. ## Functions are not automatically simpler Serverless removes some infrastructure responsibilities, but it introduces a different set of constraints. A function-based workload still needs decisions around: - timeout and execution limits; - retry behavior; - duplicate events; - idempotency; - concurrency; - cold starts; - secrets; - logs and metrics; - downstream database capacity; - event ordering where relevant; - deployment and rollback; - cost limits. That is why “no server to manage” should not be interpreted as “no operations.” The platform manages the execution environment. Your team still owns the application behavior. For current Raff runtime, trigger, scaling, and timeout capabilities, use the live [Raff Functions](/products/serverless-functions) product page. ## VMs are not automatically more operationally expensive VMs require patching and server ownership, but their mental model can be very straightforward. A small team may prefer: ```text ssh into server inspect process read logs restart service run migration check disk check network ``` That direct operating model can be valuable for a small application with one or two environments. A VM becomes harder to operate when many unrelated jobs accumulate on the same machine, deployments interfere with one another, capacity is difficult to allocate, or horizontal scaling requires manual coordination. The right question is not “How do we avoid servers?” It is “Which responsibilities are useful for us to own?” ## Serverless functions work well for webhooks Webhooks are a strong function use case because they are naturally event-driven. A good webhook path often looks like: ```text External provider ↓ HTTP function ↓ verify signature / authenticate source ↓ validate + store event ↓ queue or trigger downstream work ↓ respond quickly ``` The handler can be deployed independently from the main application and can scale separately when an external service sends a burst of callbacks. Production webhook design still needs: - signature or token verification; - replay awareness; - idempotency; - duplicate-event handling; - short request paths; - safe retries; - durable state outside the function runtime. Use [Serverless Functions for Webhooks](/learn/guides/serverless-functions-for-webhooks) for the detailed architecture. ## Cron and scheduled jobs often fit functions Scheduled work is another common reason to separate a task from a long-running application VM. Examples include: - cleanup tasks; - recurring imports; - billing checks; - report generation; - token rotation; - synchronization jobs; - periodic notifications; - cache refreshes. A function is attractive when the job spends most of the day doing nothing and only needs compute during a short execution window. A VM cron job remains appropriate when the task depends on local files, needs the application's full environment, runs constantly, or is operationally simpler as part of the existing server. For the wider decision between scheduled jobs, queues, and workflows, read [Cron Jobs vs Queues vs Workflow Automation](/learn/guides/cron-jobs-queues-workflow-automation-background-work). ## Long-running and heavy jobs need a workload decision, not a label Some batch jobs sit between obvious function and VM use cases. Examples include: - large imports; - ETL pipelines; - browser automation; - long AI inference; - media conversion; - large exports; - data processing. Choose a function when: - the job starts from a clear trigger; - it can run independently; - the runtime environment is reasonably portable; - failures and retries can be modeled clearly; - output is written to durable services; - usage is intermittent enough for execution-based compute to make sense. Choose a VM when: - the worker runs continuously; - the runtime requires several supporting processes; - debugging through direct OS access matters; - local persistent state is part of the design; - custom networking or system packages are central; - capacity is predictably used throughout the day. Do not choose based only on duration. Duration is one constraint among many. ## Keep durable state outside function runtimes Serverless execution environments should be treated as replaceable. Critical state should live in a persistent service designed for it. A common architecture is: ```text Function ├─ Managed Database → business records / job state └─ Object Storage → files / uploads / exports / artifacts ``` This makes retries, scaling, and replacement safer because a function instance is not the only copy of important data. Raff Functions currently supports integrations with [Managed Databases](/products/managed-databases) and [Object Storage](/products/object-storage). Verify current binding behavior and supported services on the live product page when designing production access. For file architecture, use [App Uploads: VM Disk vs Object Storage](/learn/guides/app-uploads-vm-disk-vs-object-storage). ## Portability matters more than the word serverless One serverless risk is coupling business logic too closely to one provider's event format, runtime wrapper, or deployment model. A portable function keeps most business logic independent from the platform entry point. A useful structure is: ```text platform adapter / HTTP handler ↓ application logic ↓ data and external services ``` This makes it easier to: - run the logic locally; - move it into a VM worker; - package it into a container; - change serverless platforms; - test business logic without the provider runtime. Raff Functions currently emphasizes standard language/framework handlers and also provides a Dockerfile path for other runtimes. Treat that as a portability aid, not a substitute for keeping application logic cleanly separated. ## Serverless vs containers is a related but different decision A container is a packaging format. A function is an execution model. A function may itself execute from a container image behind the platform. A VM may run several Docker containers. Kubernetes may schedule containers across many nodes. That means the real architecture can look like: ```text VM → Docker containers or Functions platform → containerized execution environment or Kubernetes → containers across nodes ``` If the question is specifically whether your containerized application should remain on one VM or move to orchestration, use [Kubernetes vs Docker Compose for Small Teams](/learn/guides/kubernetes-vs-docker-compose-small-teams). ## Failure and recovery look different The recovery model should influence the choice. ### VM recovery A VM-based application needs answers for: - how the server is recreated; - how configuration is restored; - how persistent data is recovered; - how DNS/traffic returns to the replacement; - how the team validates the restored application. ### Function recovery A function-based application needs answers for: - how a failed deployment is rolled back; - how duplicate/retried events are handled; - how downstream state is recovered; - how secrets and bindings are restored; - how event sources are reconnected; - how a backlog is processed after failure. Serverless does not remove recovery. It moves the recovery boundary from a server toward code, configuration, triggers, and persistent services. ## The strongest small-team architecture can use both Many applications do not need a one-model-only decision. ![Raff architecture diagram showing VM Managed Database Object Storage and Functions working together](https://raff-images.s3.raffusercloud.com/raff_functions_vm_mixed_architecture_webp_892b28db8a.png) A practical mixed architecture can be: | Workload | Infrastructure | |---|---| | Main application | Raff VM | | Durable records | Managed Database | | Uploads and generated files | Object Storage | | Billing webhook | Raff Function | | Image processing | Raff Function | | Scheduled report | Raff Function | | Constant worker | Raff VM | This model keeps the main application understandable while allowing isolated jobs to scale and deploy independently. The point is not to maximize the number of Functions. The point is to remove tasks from the VM **when separation improves reliability, scaling, ownership, or cost**. ## A staged path from VM to functions A small team can evolve without a large migration. ### Stage 1 — Start with the simplest reliable environment If one VM can host the application cleanly, use it. ```text Raff VM ↓ app + worker + simple scheduled work ``` ### Stage 2 — Externalize durable state Move records and files into services that do not depend on the application process. ```text Raff VM ├─ Managed Database └─ Object Storage ``` ### Stage 3 — Extract bounded event-driven work Move a webhook, cron job, or file processor into a function when doing so creates a clear operating benefit. ```text HTTP / cron / storage event ↓ Raff Function ↓ Managed Database / Object Storage ``` ### Stage 4 — Keep persistent workloads where they fit best Do not move a continuously running worker or full application server simply to make the architecture look more serverless. ### Stage 5 — Add orchestration only if coordination becomes the problem If the system eventually needs multi-node scheduling, more sophisticated service coordination, or cluster-level operations, evaluate [Raff Kubernetes](/products/kubernetes) separately. ## How Raff fits the decision Raff supports both execution models. Use [Raff VM](/products/raff-vm) when the workload needs a complete Linux server, long-running processes, Docker, SSH administration, or capacity that stays online. Use [Raff Functions](/products/serverless-functions) when the workload is better expressed as a triggered execution unit. The current product supports standard handlers and multiple trigger models, and is designed to scale execution independently from a persistent VM environment. Product limits, billing meters, runtime options, and free-tier rules can change, so verify those details on the live Functions and [Pricing](/pricing) pages before making a production or purchasing decision. The commercial decision should remain workload-driven. Raff Technologies offers both products because a VM and a function represent different operating responsibilities, not a basic and advanced version of the same infrastructure. :::cta Compare Raff Functions and VMs Use Raff Functions for bounded event-driven work and Raff VM when the workload needs a persistent server environment. Check live pricing and limits before deployment. ::: ## Serverless functions vs VMs checklist Choose **serverless functions** when most of these are true: - [ ] Work starts from a clear trigger. - [ ] The task can execute independently. - [ ] Runtime state can be discarded between executions. - [ ] Durable data lives elsewhere. - [ ] Traffic is bursty or intermittent. - [ ] Independent scaling is useful. - [ ] Retry and idempotency behavior are understood. - [ ] The platform runtime supports the workload's duration and resource needs. Choose a **VM** when most of these are true: - [ ] The workload is long-running. - [ ] Several persistent services need to run together. - [ ] Full OS or SSH access matters. - [ ] Custom packages, daemons, or networking are required. - [ ] Docker Compose is the operating model. - [ ] The server's capacity is used consistently. - [ ] Direct process and filesystem control simplifies operations. - [ ] The team prefers one environment over many independently deployed units. Use **both** when the main application wants a persistent environment but selected webhooks, scheduled jobs, or event processors benefit from independent execution. ## Frequently asked questions ### What is the main difference between serverless functions and VMs? A serverless function is a bounded execution unit started by demand or an event. A VM is a persistent operating-system environment that your team can configure and run continuously. ### Are serverless functions cheaper than VMs? Not always. Functions can be cost-efficient for intermittent or bursty execution, while VMs can be efficient for continuously used capacity. Compare the workload shape and operator effort, not only unit prices. ### When should a small team use serverless functions? Use functions for event-driven HTTP handlers, webhooks, scheduled jobs, storage events, and other work that can execute independently without depending on persistent local state. ### When should a small team use a VM? Use a VM when the application needs a full Linux environment, long-running services, Docker Compose, SSH access, custom system packages, persistent workers, or direct network and process control. ### Can serverless functions replace a full SaaS application server? They can for some architectures, but they do not need to. Many small teams keep the main application on a VM and extract only event-driven workloads that benefit from separate scaling and deployment. ### Should databases run inside serverless functions? No. Functions should generally treat their local execution environment as replaceable and keep durable records in a database service or another persistent data layer. ### Is serverless the same as containers? No. Containers are a packaging model, while serverless functions are an execution model. Functions may use containers underneath, and VMs can also run containers. ### How should I compare Raff Functions with Raff VM? Compare operating requirements first: triggers, persistence, OS control, runtime duration, scaling, debugging, and workload frequency. Then use the live Raff Functions, Raff VM, and Pricing pages for current product limits and commercial details. ## Conclusion For small teams, **serverless functions vs VMs is an operating-model decision**. Choose functions when work is bounded, triggered, replaceable, and easier to operate independently. Choose VMs when the workload needs a persistent environment, several long-running services, OS-level control, Docker Compose, or continuously available capacity. Do not force one model across the entire application. A mixed architecture often keeps the customer-facing system simple while isolating the jobs that benefit from event-driven execution. Start with the smallest reliable architecture, then extract or add infrastructure only when it removes a real operational problem. ## Sources - [Raff Functions](/products/serverless-functions) - [Raff VM](/products/raff-vm) - [Raff Pricing](/pricing) - [Serverless Functions for Webhooks](/learn/guides/serverless-functions-for-webhooks) - [Cron Jobs vs Queues vs Workflow Automation](/learn/guides/cron-jobs-queues-workflow-automation-background-work) - Product details reviewed: 2026-09-16 --- ### Serverless Function Pricing: CPU, Memory, Requests, and Egress URL: https://rafftechnologies.com/learn/guides/serverless-function-pricing-cpu-memory-egress Description: Learn serverless function pricing: memory GB-seconds, active CPU, requests, egress, free tiers, warm capacity, cost estimation, and when a VM may be cheaper. **Serverless function pricing is easiest to understand when you separate four things: how long code runs, how much memory it holds, how much CPU it actually uses, and which extra billing dimensions the provider adds around execution.** Requests, egress, warm capacity, logging, gateways, and observability can matter as much as the compute meter itself. For small teams, the practical goal is not to find the lowest-looking unit price. It is to understand **which variables make the monthly bill move** and whether the workload fits usage-based execution at all. At **Raff Technologies**, Raff Functions currently uses two primary compute meters: **memory GB-seconds** and **active CPU vCPU-seconds**. Requests and function egress are currently free, and a spend cap is enabled by default. Because pricing and product limits can change, this guide treats the exact Raff rates as a dated pricing snapshot and points purchasing decisions back to the live [Raff Functions](/products/serverless-functions) and [Pricing](/pricing) pages. If you are still deciding whether the workload belongs on functions or a persistent server, start with [Serverless Functions vs VMs](/learn/guides/serverless-functions-vs-vms-small-teams). ## Serverless function pricing at a glance Most function bills are built from a combination of these dimensions: | Pricing dimension | What it measures | Why it matters | |---|---|---| | Memory duration | Provisioned memory × execution time | Larger runtimes and longer jobs consume more GB-seconds | | CPU | CPU allocation or CPU time | CPU-heavy work can cost differently from I/O-heavy work | | Requests | Number of invocations | High-volume lightweight endpoints may accumulate request fees | | Egress | Outbound data | Large responses and downloads can dominate some bills | | Warm/minimum instances | Always-ready capacity | Improves latency but adds a baseline cost | | Logs/metrics | Observability data | High-volume telemetry can become a separate bill | | Gateways/triggers | Supporting services | HTTP gateways, queues, schedulers, or event services may add cost | The first question should therefore be: > **What exactly does the provider meter, and which parts of my workload drive those meters?** ## Current Raff Functions pricing snapshot The following public Raff Functions pricing was verified on **September 16, 2026**: | Meter | Current public rate | |---|---:| | Memory | **$0.0000035 per GB-second** | | Active CPU | **$0.000020 per vCPU-second** | | Requests | **Free** | | Function egress | **Free** | | Monthly free tier | **100,000 GB-s + 10,000 vCPU-s** | | Spend cap | **On by default** | The free tier currently activates after a one-time **$5 top-up**, which remains usable account balance rather than a separate activation fee. These values are intentionally dated. For a real purchasing estimate, check the live [Raff Functions](/products/serverless-functions) page immediately before deployment. ![Diagram showing Raff Functions pricing with memory and active CPU metered while requests egress cron logs and spend cap are included](https://raff-images.s3.raffusercloud.com/raff_functions_pricing_model_breakdown_b9c280bcc8.png) ## What does GB-second pricing mean? A GB-second combines **memory** and **time**. The basic formula is: ```text memory GB-seconds = provisioned memory in GB × execution duration in seconds × number of executions ``` Example: ```text 1,000,000 executions × 0.25 GB memory × 0.20 seconds = 50,000 GB-seconds ``` That number tells you the memory-duration footprint before any free tier or provider-specific adjustments. The most important levers are: - invocation count; - memory setting; - average duration; - p95/p99 duration; - concurrency; - warm or minimum instances; - retry volume. A common mistake is assuming that lowering memory always lowers cost. If too little memory slows execution significantly, the longer duration can offset some of the expected savings. For production estimation, measure **actual runtime behavior** rather than optimizing one meter in isolation. ## Active CPU pricing separates compute work from waiting Not every millisecond of wall-clock execution means the processor was doing useful work. A function may spend time: - calculating; - compressing; - parsing; - encrypting; - resizing media; - waiting for a database; - waiting for an external API; - waiting for object storage; - waiting on network I/O. Raff currently bills active CPU separately from memory duration. The useful mental model is: ```text Wall-clock duration = total time the function exists Active CPU time = time the code is actually executing on CPU ``` This distinction matters because a webhook that spends most of its life waiting on APIs has a different compute profile from an image-processing function that saturates CPU continuously. ### CPU-heavy function examples - image resizing; - compression; - PDF generation; - encryption; - large JSON/CSV transformation; - data processing; - some AI inference workloads. ### I/O-heavy function examples - webhooks; - API orchestration; - database reads/writes; - storage metadata operations; - external-service integrations. Understanding whether a workload is CPU-heavy or I/O-heavy is more useful than estimating cost from invocation count alone. ## Requests can matter even when each function is tiny Some function platforms add a per-request charge. That becomes important for workloads such as: - public APIs; - high-volume webhooks; - telemetry ingestion; - lightweight redirects or transformations; - very short handlers. A function that executes for only a few milliseconds may use little compute but still generate millions of billable requests. Raff Functions currently does **not** add a request fee. That simplifies one part of forecasting, but it does not make execution free: memory and active CPU still scale with usage. When comparing providers, keep request pricing as its own row instead of mixing it into compute. ## Egress can dominate a serverless bill Outbound traffic can be much more expensive than function execution when a workload returns large responses or moves files directly through compute. Typical high-egress patterns include: - file downloads; - generated reports; - image transformation endpoints; - media responses; - large API payloads; - data-export functions. Raff currently lists function egress as free. Other providers may price outbound transfer separately or route traffic through another metered service. Even when egress is not separately billed, architecture still matters. Large durable files usually belong in [Object Storage](/products/object-storage) rather than being regenerated or streamed through a function every time. A strong pattern is: ```text Function → generate / authorize / transform → store artifact in Object Storage → return object reference or download path ``` This keeps compute focused on the work that actually needs execution. ## Free tiers should be treated as discounts, not architecture Free tiers can be useful for development, early traffic, internal tools, and low-volume workloads. But a production architecture should remain sensible **after the free tier is exhausted**. Ask: - What will the workload cost without the free allowance? - How quickly will usage grow past it? - Does the free tier reset monthly? - Does it require account funding or another activation condition? - Are requests or egress excluded from the free allowance? - Do warm instances consume billable capacity? For Raff Functions, the current public free tier is **100,000 GB-seconds and 10,000 vCPU-seconds per month**, activated after the one-time $5 account top-up described above. Do not design around that number remaining unchanged indefinitely. Treat it as a current commercial benefit and verify it on the product page before relying on it. ## Estimate serverless cost from workload shape Before deploying a production function, collect these inputs: 1. Monthly executions. 2. Average and p95 duration. 3. Memory allocation. 4. CPU intensity. 5. Retry/duplicate rate. 6. Response or output size. 7. Whether warm capacity is required. 8. Supporting service costs. A useful worksheet is: | Input | Example | |---|---:| | Executions/month | 1,000,000 | | Memory | 256 MB | | Average duration | 200 ms | | Memory usage | 50,000 GB-s | | CPU profile | Mostly I/O-bound | | Response size | Small JSON | | Warm instances | No | | Primary downstream service | Managed Database | Then calculate each provider-specific meter separately. Do **not** invent an active CPU ratio if you have no measurement. For Raff, memory GB-seconds can be estimated directly from configuration and duration, but active CPU should ideally come from observed workload behavior or the live pricing calculator. :::cta Estimate with live Raff pricing Use the Raff Functions pricing calculator for current rates and workload assumptions before deploying production traffic. ::: ## Example: webhook pricing A webhook is often a strong serverless workload because it has a clear event boundary and usually performs short bursts of work. A typical flow is: ```text External provider ↓ Function ↓ verify event ↓ write durable record ↓ trigger downstream processing ↓ return response ``` Cost is driven by: - webhook volume; - retry rate; - duration; - memory; - signature verification; - database/API waiting; - logging volume. A good webhook function should return quickly and move heavy downstream work out of the request path. For architecture and security details, use [Serverless Functions for Webhooks](/learn/guides/serverless-functions-for-webhooks). ## Example: image processing pricing Image processing is much more CPU-sensitive. ```text Object upload ↓ Function ↓ resize / encode ↓ Object Storage output ``` Cost depends on: - image count; - source dimensions; - number of generated variants; - memory requirement; - CPU time; - retries; - duplicate processing. The optimization target is not only execution time. Avoid generating unnecessary sizes, avoid reprocessing existing variants, and keep output in object storage. ## Example: scheduled jobs Scheduled functions are easy to model because invocation frequency is known in advance. Examples include: - daily reports; - cleanup jobs; - subscription checks; - sync jobs; - cache refreshes; - recurring imports. Cost is usually driven by duration and the amount of database/API work performed per run. Before choosing a function, ask whether the task needs a full application environment or local server state. If yes, VM cron may remain simpler. For that wider decision, use [Cron Jobs vs Queues vs Workflow Automation](/learn/guides/cron-jobs-queues-workflow-automation-background-work). ## Warm instances change the cost shape Scale-to-zero reduces idle cost, but some latency-sensitive workloads need ready capacity. Keeping warm or minimum instances changes the economics because part of the runtime remains allocated even when user traffic is low. Raff currently offers optional warm instances and publishes their current commercial treatment on the Functions product page. Because that rate is a mutable product detail, use the live page rather than an evergreen article when calculating a production baseline. Warm capacity is most defensible when: - latency is user-visible; - cold-start measurements show a real problem; - traffic is predictable enough to justify a baseline; - the business cost of added latency exceeds the always-ready cost. Do not keep every function warm by default. ## Observability is part of serverless cost A production function needs enough observability to answer: - how many times it ran; - duration distribution; - failure rate; - retry rate; - trigger source; - logs for a specific execution; - resource usage; - usage/cost movement. Some providers bill observability separately through another logging or monitoring product. Raff currently includes function logs and core metrics with the product. Retention periods and exact observability features can change, so use the live product page for current operational limits. When comparing providers, include observability in total cost rather than pretending the compute meter is the whole platform bill. ## Spend caps reduce runaway-cost risk Functions are easy to trigger, which means a bug or retry loop can multiply usage quickly. Common causes include: - webhook retry storms; - recursive storage events; - broken cron schedules; - abusive public endpoints; - client retry loops; - unexpected batch fanout. Raff currently enables a per-account Functions spend cap by default and pauses Functions when the cap is reached. That is useful, but it is not a substitute for application safeguards. Production functions should also use: - idempotency; - retry limits; - rate limiting where appropriate; - event deduplication; - monitoring; - ownership alerts; - explicit budget reviews. For API-level protection, see [API Rate Limiting Explained](/learn/guides/api-rate-limiting-protecting-apps-real-users). ## When a VM can be cheaper Serverless pricing is attractive when usage is intermittent. It becomes less obviously advantageous as utilization becomes continuous. A VM may be economically and operationally cleaner when: - the process runs continuously; - CPU usage stays high for long periods; - several services need one environment; - Docker Compose is already the deployment model; - SSH debugging is valuable; - full filesystem or OS control is required; - the workload uses provisioned capacity consistently. A simple comparison is: ```text Function = execution-based compute + any request / egress / observability / warm-capacity charges VM = provisioned server capacity + storage / backup / operations ``` Do not compare only one unit rate. Compare the full operating model. Use [Serverless Functions vs VMs](/learn/guides/serverless-functions-vs-vms-small-teams) for the architecture decision before doing the final cost comparison. ## When Kubernetes or workers make more sense Not every high-volume function workload belongs on a VM. A worker pool or Kubernetes may fit better when: - there are many long-running workers; - jobs need queue-driven horizontal scaling; - several workloads share a container platform; - placement and resource policies matter; - multi-node orchestration is already justified. At that point, compare total cluster cost with function execution rather than forcing the workload into a binary functions-vs-VM decision. For the cluster cost side, use [Kubernetes Cost Optimization](/learn/guides/kubernetes-cost-optimization-startups). ## How Raff Functions fits pricing-sensitive workloads Raff Functions is positioned for teams that want an execution-based model without adding separate request and function-egress fees. The current product model is strongest for workloads such as: - webhooks; - scheduled jobs; - object-storage events; - lightweight APIs; - file processing; - batch/ETL work that fits the runtime model; - one-off tasks. Use [Raff Functions](/products/serverless-functions) when those workloads benefit from independent execution and scale-to-zero behavior. Use [Raff VM](/products/raff-vm) when the workload wants a persistent server environment. Use [Managed Databases](/products/managed-databases) and [Object Storage](/products/object-storage) to keep durable records and files outside ephemeral function runtimes. Current Raff Functions pricing in this guide was reviewed on **September 16, 2026**. Always verify the live product and pricing pages before quoting a customer or making a purchasing decision. ## Serverless pricing checklist Before production, confirm: - [ ] Monthly execution volume is estimated. - [ ] Average and p95 duration are measured. - [ ] Memory is sized from real workload behavior. - [ ] CPU intensity is understood. - [ ] Request pricing is included in provider comparisons. - [ ] Egress is included in provider comparisons. - [ ] Warm/minimum-instance cost is included where relevant. - [ ] Observability cost is included. - [ ] Retry and duplicate-event behavior are known. - [ ] Large files are stored outside function runtimes. - [ ] A spend cap or budget guard exists. - [ ] Free tiers are treated as a discount, not an architecture dependency. - [ ] The workload is compared with a VM or worker model if it runs continuously. - [ ] Current provider rates were verified before purchase. ## Frequently asked questions ### How does serverless function pricing work? Most platforms combine execution duration with memory or CPU usage and may add separate request, egress, warm-instance, gateway, or observability charges. ### What is a GB-second? A GB-second is one gigabyte of provisioned memory used for one second. Multiply memory in GB by duration in seconds and by the number of executions. ### What is active CPU pricing? Active CPU pricing meters the time function code is actually using CPU rather than treating all wall-clock waiting time as equivalent compute. ### Are serverless functions cheaper than VMs? They can be for intermittent or bursty workloads. VMs can be cheaper or simpler for continuously running services that use provisioned capacity consistently. ### Does Raff charge per request for Functions? As of September 16, 2026, Raff lists Functions requests as free. Verify the live product page before relying on that for a future pricing estimate. ### Does Raff charge function egress? As of September 16, 2026, Raff lists function egress as free. This does not mean all Raff products have identical transfer pricing, so verify the product-specific pricing page. ### What is the Raff Functions free tier? As of September 16, 2026, the public product page lists 100,000 GB-seconds and 10,000 vCPU-seconds per month after the required one-time $5 top-up that remains usable account balance. ### How do I estimate Raff Functions cost? Estimate memory GB-seconds from memory, duration, and execution count; estimate active CPU from observed workload behavior; then apply the current live rates and free tier using Raff's pricing calculator. ## Conclusion Serverless function pricing becomes predictable when every meter is visible. Start with memory duration and CPU behavior, then add request, egress, warm-capacity, observability, and supporting-service costs. Model retries and concurrency instead of assuming every invocation behaves like a clean benchmark. For Raff Functions, the current public model uses memory and active CPU as the primary compute meters, with requests and function egress currently free. That can simplify forecasting, but the architecture decision still comes first: use functions for bounded event-driven work and persistent infrastructure when the workload actually needs it. Estimate with current production assumptions, then verify the live [Raff Functions](/products/serverless-functions) and [Pricing](/pricing) pages before deployment. ## Sources - [Raff Functions](/products/serverless-functions) - [Raff Pricing](/pricing) - [Serverless Functions vs VMs](/learn/guides/serverless-functions-vs-vms-small-teams) - [Serverless Functions for Webhooks](/learn/guides/serverless-functions-for-webhooks) - Product and pricing details reviewed: 2026-09-16 --- ### Postgres Hosting: Managed vs Self-Hosted for SaaS URL: https://rafftechnologies.com/learn/guides/postgresql-hosting-for-saas Description: Compare Postgres hosting for SaaS across managed PostgreSQL and self-hosted PostgreSQL, including cost, connections, backups, HA, recovery, and operational ownership. **Postgres hosting** means the infrastructure and operating model used to run PostgreSQL for an application: compute, storage, connections, backups, monitoring, maintenance, scaling, and recovery. For a SaaS team, the practical choice is usually between **managed PostgreSQL hosting** and **self-hosted PostgreSQL**. Managed PostgreSQL reduces platform operations; self-hosting gives deeper host and database control but makes your team responsible for patching, backups, monitoring, failover, storage growth, upgrades, and recovery. Raff Technologies supports both paths. If standard PostgreSQL versions and extensions fit your workload, [Raff Managed PostgreSQL](/products/managed-databases/postgresql) is the lower-operations path. If you need root access, unsupported packages, custom topology, or direct host control, PostgreSQL can also run on a [Raff VM](/products/raff-vm). For most small SaaS teams, the decision should start with **operational ownership and recovery requirements**, not with the cheapest server size. Choose the operating model first, then size CPU, memory, storage, connections, backups, and availability from workload evidence. :::cta Compare Managed PostgreSQL See the current Raff PostgreSQL plans, supported versions, extensions, backup options, and high-availability choices. ::: ## Postgres hosting: managed vs self-hosted at a glance | Responsibility | Managed PostgreSQL | Self-hosted PostgreSQL | |---|---|---| | Database provisioning | Provider | Your team | | Operating-system maintenance | Provider | Your team | | Database service maintenance | Provider within service policy | Your team | | Backup platform | Provider-operated within plan scope | Your team designs and operates it | | Point-in-time recovery | Service capability when included | Your team configures and validates it | | Monitoring platform | Usually included to a defined scope | Your team selects and operates it | | Connection pooling | May be included | Your team deploys and maintains it | | High availability | Service option | Your team designs, tests, and maintains it | | Root and filesystem access | Restricted | Full control | | Schema, indexes, and queries | Your team | Your team | | Migration safety | Your team | Your team | | Application reconnect behavior | Your team | Your team | Choose **managed PostgreSQL** when the supported service fits and your team wants to reduce repetitive platform work. Choose **self-hosted PostgreSQL** when a documented requirement needs operating-system access, unsupported extensions or packages, exact patch control, direct filesystem access, or a custom replication topology. The key word is documented. “We want more control” is not enough unless someone also owns backup verification, patching, monitoring, recovery, and incidents. ## What managed PostgreSQL hosting actually changes A managed PostgreSQL service does not remove database responsibility. It changes the boundary of responsibility. The provider typically operates more of the platform layer, such as: - database provisioning; - service and operating-system maintenance; - backup infrastructure; - point-in-time recovery tooling; - monitoring and service health; - storage expansion workflows; - connection-pooling options; - supported high-availability and failover controls; - networking and access controls; - version and maintenance workflows. Your application team still owns: - schema design; - indexes; - query performance; - migrations; - application credentials and roles; - connection behavior; - capacity decisions; - data-retention policy; - recovery-point selection; - validating that the application works after recovery. This is why managed PostgreSQL is most useful when **database operations are necessary but are not your product**. ## Self-hosted PostgreSQL gives control by transferring work to your team Self-hosting PostgreSQL on a VM can be the correct architecture when the application needs capabilities outside a managed-service boundary. Typical reasons include: - root or operating-system access; - a PostgreSQL version not supported by the target managed service; - an extension or package outside the approved catalog; - custom authentication modules; - direct database-file or filesystem access; - exact patch timing; - a custom replication or clustering topology; - local processes that must run beside PostgreSQL; - infrastructure requirements defined by an internal platform or contract. The trade-off is complete lifecycle ownership: ```text VM provisioning + OS hardening + PostgreSQL installation + configuration + patching + TLS + firewall rules + monitoring + alerts + backups + restore tests + storage growth + replication + failover + major-version upgrades + incident response ``` Installing PostgreSQL is easy. Operating it safely through failures, growth, and upgrades is the real self-hosting cost. For the VM path, see [VPS for Databases](/learn/guides/vps-for-databases) and the [PostgreSQL on Ubuntu 24.04 tutorial](/learn/tutorials/install-postgresql-ubuntu-24-04). ## PostgreSQL hosting decisions should follow workload evidence There is no reliable mapping from “number of users” to a fixed PostgreSQL server size. Two SaaS products with the same user count can have very different query complexity, connection patterns, write rates, working sets, and recovery requirements. Collect these inputs before choosing a production plan: - peak active transactions; - number of application instances and workers; - pool size per application process; - p50, p95, and p99 query latency; - database and index size; - storage growth over time; - read-to-write ratio; - temporary-file activity; - WAL generation rate; - storage latency during normal and peak periods; - backup size and measured restore time; - expected growth over the next planning cycles. CPU pressure can come from legitimate query work, but it can also come from missing indexes, repeated queries, large sorts, or retry storms. Increase compute after checking whether the work itself is necessary. Memory supports PostgreSQL buffers, operating-system cache, connections, sorts, hashes, maintenance work, and extensions. Watch swapping, out-of-memory events, large temporary files, and latency that appears only under concurrency. Storage should include capacity and operational headroom: ```text production data + indexes + WAL and temporary work + expected growth + migration and maintenance headroom + safety margin ``` A database can serve traffic normally and still have a restore time that exceeds the business RTO. Restore duration is therefore a production sizing input, not just a backup detail. ## Connection budgets can fail before CPU does PostgreSQL capacity planning should include **connections**, not only CPU and RAM. Estimate planned demand as: ```text maximum app instances x pool size per instance + background workers + scheduled jobs + migration connections + monitoring + administrative reserve = planned database connection demand ``` For example, six application instances with pools of 10 connections can consume 60 potential server connections before workers, migrations, monitoring, or administration are counted. More connections do not automatically create more throughput. Excessive concurrency can increase memory pressure, lock contention, context switching, and queueing. A pooler such as PgBouncer can separate application concurrency from PostgreSQL server concurrency. Applications that depend on session-level state should still be checked for pooling compatibility. Monitor active and idle connections, pool wait time, long and idle transactions, rejected connections, connection churn during deployments, and retry behavior. A database with spare CPU can still become unavailable when every connection slot is occupied. ## Backups, PITR, replication, and high availability protect different failures Production PostgreSQL hosting should separate **availability** from **historical recovery**. | Control | Primary purpose | Main limitation | |---|---|---| | Logical backup | Portable or selective recovery | Can be slow for large full restores | | Base backup + WAL archive | Full recovery and point-in-time recovery | Requires complete retention and restore testing | | Standby replication | Availability and eligible read scaling | Usually reproduces accidental changes | | High availability | Faster recovery from selected node failures | Does not replace historical recovery | | Infrastructure snapshot | Infrastructure rollback aid | Not a complete PostgreSQL recovery strategy | | Restore test | Proves procedure and timing | Does not prevent the original incident | Replication is not a backup. A replica can receive accidental deletes, destructive updates, and bad migrations along with valid writes. Define two business targets before choosing protection layers: - **RPO:** how much recent data the business can afford to lose. - **RTO:** how long the database and application can remain unavailable. A daily dump cannot satisfy a 15-minute RPO. A standby may shorten recovery from node failure but does not provide a clean historical point before a destructive write. PITR provides historical recovery, but the team still needs to validate the restored data and reconnect the application safely. Use [PostgreSQL Replication vs Backups vs Snapshots](/learn/guides/postgresql-replication-vs-backups-vs-snapshots) for the detailed failure-mode comparison and [Database Backup Strategy for SaaS Apps](/learn/guides/database-backup-strategy-saas-apps) for retention and restore planning. ## When managed PostgreSQL is usually the better SaaS fit Managed PostgreSQL is usually the simpler starting point when: - the application uses supported PostgreSQL versions and extensions; - the team has no dedicated database operator; - backup and recovery ownership should be clearer; - connection pooling is useful; - private or restricted connectivity fits the architecture; - the workload needs a straightforward scaling path; - optional high availability is valuable; - engineering time is better spent on schema, queries, and product behavior. This is a commercial decision as much as a technical one. The managed service may cost more than one raw VM, but the comparison should include engineering time, on-call ownership, backup infrastructure, monitoring, standby capacity, restore testing, and incident recovery. If this model fits, evaluate [Raff Managed PostgreSQL](/products/managed-databases/postgresql) rather than comparing only VM prices. :::cta Explore Raff Managed PostgreSQL Compare the current managed PostgreSQL plans and decide whether the reduced operational ownership fits your SaaS workload. ::: ## When self-hosted PostgreSQL is justified Self-hosting becomes stronger when at least one hard requirement falls outside the managed service: - required extension or package is unavailable; - root access is mandatory; - filesystem access is part of the application architecture; - exact version or patch control is required; - custom replication or failover topology is necessary; - database operations are already a mature internal capability; - compliance or platform policy requires deeper infrastructure ownership. If none of these apply, self-hosting can create an internal database platform that a small product team must maintain without gaining meaningful product value. For the broader decision framework, see [Managed vs Self-Hosted Databases](/learn/guides/managed-vs-self-hosted-databases). ## What Raff Managed PostgreSQL currently provides Raff's live PostgreSQL product page currently lists PostgreSQL 14 through 16, built-in connection pooling, backups with point-in-time recovery, monitoring, TLS and IP allowlists, private networking, storage expansion, optional high availability, and extensions including pgvector and PostGIS. Current capabilities and limits should always be checked on the live [Managed PostgreSQL](/products/managed-databases/postgresql) page before production design. Raff also provides a free managed-database entry point. The live PostgreSQL page currently shows **1 GB memory, 2 GB storage, and daily backups** for the free starting tier. Raff's release notes state that the free database plan is limited to one free database per account and may pause after seven days without a connection. Treat the free tier as an evaluation, development, prototype, or light-workload starting point—not as a universal production sizing recommendation. A managed architecture can remain compact: ```text Application -> private or restricted connection Raff Managed PostgreSQL -> managed platform operations -> customer-owned schema, queries, and application behavior ``` A self-hosted architecture on [Raff VMs](/products/raff-vm) shifts more work back to the customer: ```text Application VM -> private network PostgreSQL VM -> customer-operated patching, backups, monitoring, pooling, HA, and recovery ``` The correct model is the one your team can operate and recover reliably at the required service level. ## PostgreSQL hosting buying checklist Before choosing a provider or plan, write down: 1. Required PostgreSQL **major version**. 2. Required **extensions**. 3. Current database and index size. 4. Expected monthly storage growth. 5. Peak application and worker connections. 6. Required **RPO** and **RTO**. 7. Whether **high availability** is required. 8. Backup retention requirement. 9. Private-network or public-access requirements. 10. Who owns restores and production incidents. 11. Expected migration or exit path. 12. Total operating cost, including engineering time. If these are unknown, comparing monthly plan prices is premature. ## Conclusion Postgres hosting is not only a server-size decision. Start with the responsibility boundary, then validate connections, query behavior, memory, storage growth, RPO, RTO, and restore time before choosing the production shape. Managed PostgreSQL is usually the practical choice when the supported service fits and the team wants a smaller operational surface. Self-hosting is justified when a specific technical or control requirement outweighs the additional maintenance and recovery work. For SaaS teams evaluating Raff, the next step is straightforward: compare the live [Managed PostgreSQL](/products/managed-databases/postgresql) service against the requirements above. If a hard requirement falls outside the managed boundary, evaluate PostgreSQL on a [Raff VM](/products/raff-vm) instead. :::cta Compare PostgreSQL Hosting Options Review Raff Managed PostgreSQL for lower operational ownership, or Raff VM when the workload requires host-level control. ::: ## Sources - [PostgreSQL: Connections and Authentication](https://www.postgresql.org/docs/current/runtime-config-connection.html) - [PostgreSQL: Routine Database Maintenance Tasks](https://www.postgresql.org/docs/current/maintenance.html) - [PostgreSQL: Monitoring Database Activity](https://www.postgresql.org/docs/current/monitoring.html) - [PostgreSQL: Backup and Restore](https://www.postgresql.org/docs/current/backup.html) - [PostgreSQL: High Availability, Load Balancing, and Replication](https://www.postgresql.org/docs/current/high-availability.html) - [PgBouncer: Usage and Pooling Modes](https://www.pgbouncer.org/usage) - [Raff Managed PostgreSQL](/products/managed-databases/postgresql) - [Raff Managed Databases](/products/managed-databases) - [Raff Release Notes](/release-notes) - Product details reviewed: 2026-09-16; verify the live product page and console for current versions, plan limits, features, and pricing. --- ### MySQL Hosting: Managed vs Self-Hosted for Production Apps URL: https://rafftechnologies.com/learn/guides/mysql-hosting-managed-vs-self-hosted Description: Compare MySQL hosting across managed MySQL and self-hosted MySQL, including cost, connections, backups, PITR, HA, recovery, and operational ownership. **MySQL hosting** is the infrastructure and operating model used to run a MySQL database for an application: compute, storage, connections, backups, monitoring, maintenance, scaling, and recovery. For a small product team, the practical decision is usually between a **managed MySQL database** and **self-hosted MySQL**. Managed MySQL reduces database-platform operations; self-hosting gives deeper host and configuration control but makes your team responsible for patching, backups, monitoring, replication, failover, storage growth, upgrades, and recovery. Raff Technologies supports both paths. If standard MySQL 8 capabilities fit the application, [Raff Managed MySQL](/products/managed-databases/mysql) is the lower-operations option. If the workload requires root access, custom packages, direct filesystem access, or a topology outside the managed boundary, MySQL can also run on a [Raff VM](/products/raff-vm). For most small teams, choose the operating model before comparing server sizes. Start with ownership, recovery requirements, connection demand, and workload behavior; then choose the production plan. :::cta Compare Managed MySQL See the current Raff MySQL plans, backup and recovery options, networking, monitoring, and high-availability choices. ::: ## MySQL hosting: managed vs self-hosted at a glance | Responsibility | Managed MySQL | Self-hosted MySQL | |---|---|---| | Database provisioning | Provider | Your team | | Operating-system maintenance | Provider | Your team | | MySQL service maintenance | Provider within service policy | Your team | | Backup platform | Provider-operated within plan scope | Your team designs and operates it | | Point-in-time recovery | Service capability when included | Your team configures backups and binary-log retention | | Monitoring platform | Usually included to a defined scope | Your team selects and maintains it | | Storage expansion | Service workflow | Your team plans and executes it | | High availability | Service option | Your team designs, tests, and operates it | | Root and filesystem access | Restricted | Full control | | Schema, indexes, and queries | Your team | Your team | | Migration safety | Your team | Your team | | Application reconnect behavior | Your team | Your team | Choose **managed MySQL** when the service supports the workload and your team wants to reduce repetitive database-platform work. Choose **self-hosted MySQL** when a documented requirement needs operating-system access, custom packages, direct filesystem control, exact patch timing, or a custom topology. The important distinction is ownership. A self-hosted database can be easy to create on day one and still become an operations project once it stores production data. ## What managed MySQL hosting actually changes A managed MySQL service does not remove database responsibility. It changes which layer your team operates. The provider typically owns more of the platform work, such as: - database provisioning; - operating-system and service maintenance; - backup infrastructure; - point-in-time recovery tooling; - service monitoring; - storage expansion workflows; - supported high-availability and failover controls; - network and access-control features; - maintenance and version workflows. Your application team still owns: - schema design; - indexes; - query performance; - migrations; - users and application credentials; - connection behavior; - data-retention decisions; - capacity planning; - selecting a safe recovery point; - validating the application after recovery or failover. This is why a managed MySQL database is most useful when **database operations are required but are not the product your team is building**. ## Self-hosted MySQL gives control by transferring work to your team Self-hosting can be the right architecture when a real technical or control requirement falls outside a managed-service boundary. Common reasons include: - root or operating-system access; - direct filesystem access; - exact package or patch timing; - custom plugins or packages; - unusual authentication requirements; - custom replication topology; - local processes that must run beside MySQL; - infrastructure requirements that demand host ownership. The trade-off is full lifecycle responsibility: ```text VM provisioning + OS hardening + MySQL installation + configuration + patching + TLS + firewall rules + monitoring + alerts + backups + binary-log retention + restore tests + storage growth + replication + failover + major upgrades + incident response ``` Installing MySQL is the easy part. Operating it reliably through growth, failures, and upgrades is the actual self-hosting cost. For implementation, see [Install MySQL on Ubuntu 24.04](/learn/tutorials/install-mysql-ubuntu-24-04). If your software also supports MariaDB, review [MySQL vs MariaDB for Production Apps](/learn/guides/mysql-vs-mariadb-production-apps) before changing engines. ## MySQL hosting should be sized from workload evidence A production MySQL plan should not be chosen from user count or database size alone. The database must handle query work, connections, memory pressure, temporary operations, binary logs, backups, maintenance, and growth at the same time. Collect these inputs before choosing a production plan: - peak active transactions; - queries per second during normal and peak periods; - p50, p95, and p99 query latency; - expensive statements and full scans; - data and index size; - storage growth over time; - read-to-write ratio; - connection count and pool behavior; - buffer-pool effectiveness; - temporary-table and sort activity; - storage latency and throughput; - binary-log generation rate; - backup duration; - measured restore duration; - expected growth over the next planning cycles. CPU pressure can come from necessary work, but it can also come from missing indexes, inefficient joins, reports, or retry storms. Resize after checking whether the work itself can be reduced. Memory should reflect both the working set and concurrency. MySQL uses memory for the InnoDB buffer pool, connections, sorts, temporary work, caches, and maintenance. Per-connection allocations can multiply quickly across a busy application. Storage planning should include more than current table size: ```text data + indexes + binary logs + temporary work + expected growth + migrations and maintenance + operational safety margin ``` A database can still answer queries while taking too long to restore. Recovery time is therefore part of capacity planning. ## Connections and slow queries often determine the first bottleneck A MySQL workload can run out of safe concurrency before it runs out of raw CPU. Estimate total connection demand across the application: ```text maximum application instances x pool size per instance + background workers + scheduled jobs + migrations + monitoring + administrative reserve = planned connection demand ``` A pool of 10 connections can look small until eight application replicas and several workers create independent pools. More connections do not guarantee more throughput. Excessive concurrency can increase memory use, lock contention, context switching, and queueing. Monitor: - current and peak connections; - threads running; - connection errors; - long transactions; - lock waits and deadlocks; - slow-query frequency; - temporary tables written to disk; - buffer-pool behavior; - retry storms; - deployment overlap. Investigate slow queries before increasing the plan size. More CPU and memory can hide inefficient SQL temporarily, but they do not fix the underlying query pattern. ## Backups, binary logs, replication, and HA solve different failures MySQL recovery should separate historical recovery from service continuity. | Control | Primary purpose | What it does not solve alone | |---|---|---| | Logical dump | Portable export and selected recovery | Fast full recovery for every large database | | Physical backup | Full-instance recovery | Point-in-time history without binary logs | | Binary logs | Point-in-time recovery and replication input | A complete base backup | | Replica | Availability and eligible read scaling | Recovery from a replicated bad write | | High availability | Faster recovery from selected node failures | Historical recovery | | Infrastructure snapshot | Infrastructure rollback aid | A complete database-aware recovery strategy | | Restore test | Proves procedure and duration | Prevents the original incident | Replication is not a backup. A replica usually receives accidental deletes, destructive updates, and bad migrations along with valid writes. Define two business targets before designing protection: - **RPO:** the maximum recent data loss the business can accept. - **RTO:** the maximum time the database and application can remain unavailable. If the business needs recovery to a specific minute, the recovery design must preserve a suitable base backup plus the required binary-log history. If faster recovery from a host failure is required, high availability may be justified in addition to backups. Use [Database Backup Strategy for SaaS Apps](/learn/guides/database-backup-strategy-saas-apps) for the wider recovery model and [Zero-Downtime Database Migrations](/learn/guides/zero-downtime-database-migrations-small-teams) when schema or data changes affect the recovery plan. ## When managed MySQL is usually the better fit Managed MySQL is usually the simpler starting point when: - the application uses standard MySQL behavior; - the team does not want to maintain the database host; - backup and recovery infrastructure should be provider-operated; - monitoring and slow-query visibility are valuable; - private or tightly restricted connectivity is required; - storage expansion should be a service workflow; - optional high availability may be required; - engineering time is more valuable in the application than in repetitive database operations. This is also a total-cost decision. Comparing one raw VM with a managed MySQL database is incomplete if the VM comparison excludes backups, monitoring, standby capacity, engineering time, restore testing, patching, and on-call response. If the managed model fits, evaluate [Raff Managed MySQL](/products/managed-databases/mysql) rather than comparing only infrastructure prices. :::cta Explore Raff Managed MySQL Compare current Managed MySQL plans and decide whether the reduced operational ownership fits your production workload. ::: ## When self-hosted MySQL is justified Self-hosting becomes stronger when at least one hard requirement falls outside the managed service: - root access is mandatory; - direct filesystem access is required; - a required plugin or package is unsupported; - exact patch timing matters; - a custom replication or failover topology is necessary; - database operations are already a mature internal capability; - compliance or platform requirements demand deeper host ownership. If none of these apply, self-hosting can create an internal database platform that a small product team must maintain without creating meaningful product value. For the broader ownership decision, see [Managed vs Self-Hosted Databases](/learn/guides/managed-vs-self-hosted-databases). ## What Raff Managed MySQL currently provides The live [Raff Managed MySQL](/products/managed-databases/mysql) page currently lists MySQL 8.0 with InnoDB, managed backups, continuous binary-log capture for point-in-time recovery, monitoring and slow-query insights, TLS, IP allowlists, private connectivity, storage expansion, and optional high availability using a Galera cluster. Raff also provides a free managed-database entry point. The live MySQL page currently shows **1 GB memory, 2 GB storage, and daily backups** for the free starting tier. Raff's release notes state that one free managed database per account is available across PostgreSQL, MySQL, or Valkey and that an inactive free database can pause after seven days without a connection. Current eligibility and limits should still be verified on the live product page and console. A managed architecture can stay compact: ```text Application -> private or restricted connection Raff Managed MySQL -> managed platform operations -> customer-owned schema, queries, and application behavior ``` A self-hosted architecture on [Raff VMs](/products/raff-vm) shifts more work to the customer: ```text Application VM -> private network MySQL VM -> customer-operated patching, backups, monitoring, replication, HA, and recovery ``` The right model is the one your team can operate and recover reliably at the required service level. ## MySQL hosting buying checklist Before choosing a provider or plan, document: 1. Required MySQL **major version**. 2. Required **plugins or packages**. 3. Current data and index size. 4. Expected storage growth. 5. Peak application and worker connections. 6. Required **RPO** and **RTO**. 7. Whether **high availability** is required. 8. Backup retention requirement. 9. Private-network or public-access requirements. 10. Who owns restores and production incidents. 11. Expected migration or exit path. 12. Total operating cost, including engineering time. If these are unknown, monthly plan price alone is not enough information to choose production MySQL hosting. ## Conclusion MySQL hosting is not only a provider or monthly-price decision. Start with who owns the database lifecycle, then measure connection demand, slow queries, memory pressure, storage growth, backup behavior, RPO, RTO, and restore time before choosing the production shape. Managed MySQL is usually the practical choice when the service supports the workload and the team wants a smaller operational surface. Self-hosting is justified when a specific technical or control requirement outweighs the additional maintenance, monitoring, and recovery work. For teams evaluating Raff, compare the live [Managed MySQL](/products/managed-databases/mysql) service against the checklist above. If the workload requires host-level control outside the managed boundary, evaluate MySQL on a [Raff VM](/products/raff-vm) instead. :::cta Compare MySQL Hosting Options Review Raff Managed MySQL for lower operational ownership, or Raff VM when the workload requires host-level control. ::: ## Sources - [MySQL: Backup and Recovery](https://dev.mysql.com/doc/refman/8.4/en/backup-and-recovery.html) - [MySQL: Replication](https://dev.mysql.com/doc/refman/8.4/en/replication.html) - [MySQL: Server Status Variables](https://dev.mysql.com/doc/refman/8.4/en/server-status-variables.html) - [MySQL: The Slow Query Log](https://dev.mysql.com/doc/refman/8.4/en/slow-query-log.html) - [Raff Managed MySQL](/products/managed-databases/mysql) - [Raff Managed Databases](/products/managed-databases) - [Raff Release Notes](/release-notes) - Product details reviewed: 2026-09-16; verify the live product page and console for current features, limits, availability, and pricing. --- ### Database Restore Testing: RPO, RTO, and Recovery Validation URL: https://rafftechnologies.com/learn/guides/database-restore-testing-rpo-rto-recovery-validation Description: Learn database restore testing for RPO, RTO, point-in-time recovery, application validation, recovery evidence, and managed vs self-hosted database recovery. **Database restore testing** proves that a real backup or point-in-time recovery path can return a database to a trustworthy, application-usable state within the approved Recovery Point Objective (RPO) and Recovery Time Objective (RTO). A successful backup job is not enough. Recovery can still fail because transaction logs are incomplete, credentials are unavailable, the target engine version changed, storage is undersized, extensions are missing, or the application cannot use the restored data. **Backup creation proves that recovery data exists; restore testing proves that your team can actually recover from it.** Raff Technologies supports both managed and self-hosted database recovery models. With [Managed Databases](/products/managed-databases), more of the backup and recovery platform sits inside the service boundary. With a database on a [Raff VM](/products/raff-vm), your team owns the complete database recovery chain. In both cases, the application team still owns recovery-point selection, data validation, application reconnect behavior, and the decision to return traffic. :::cta Compare Database Recovery Paths Use Managed Databases for a smaller operational surface, or self-host on Raff VM when your recovery design requires host-level control. ::: ## Database restore testing at a glance A complete restore test should prove five things: | Recovery evidence | What the test proves | |---|---| | Backup integrity | Required recovery artifacts exist and can be read | | Database recoverability | The engine restores and starts at the intended point | | RPO | The recovered data is recent enough | | RTO | The full path to usable service is fast enough | | Application validation | The restored database actually works with the application | The test is not complete when the database process starts. It is complete when the agreed application workflows can use the recovered state safely. ## Backup verification and restore testing are different controls Backup verification can detect missing or damaged recovery artifacts, but it does not prove the full recovery path. A restore drill answers operational questions such as: - Can the team find the correct recovery point quickly? - Can required backup files and transaction logs be read? - Are encryption keys and credentials available during an incident? - Can the database be restored into a clean target? - Does recovery reach the intended timestamp? - Are required schemas, extensions, roles, and permissions present? - Can the application reconnect? - Do critical reads and writes work? - Does the complete process fit the approved RPO and RTO? PostgreSQL tools such as `pg_verifybackup` can validate aspects of a base backup. MySQL backup tooling also separates backup creation, verification, and restore. These checks reduce uncertainty, but only a real restore proves that the recovery chain works end to end. ## RPO should be measured from the recovered data **Recovery Point Objective (RPO)** is the maximum acceptable data-loss window. Do not validate RPO from the backup-job timestamp alone. Validate it from the newest data the recovered application can actually use. Record: - simulated incident time; - selected backup or recovery-point time; - newest available WAL, binary log, or other transaction-log data; - actual recovered timestamp; - newest verified business record or transaction; - measured data-loss window. Example: ```text Simulated incident: 14:00 Selected recovery target: 13:52 Newest verified record: 13:50 Measured data loss: 10 minutes Approved RPO: 15 minutes Result: Pass ``` A recovery point can look recent while still failing the RPO if required logs are missing or the recovered database cannot use the newest expected state. ## RTO should include the complete path to usable service **Recovery Time Objective (RTO)** is the maximum acceptable time until the agreed service is usable again. Measure the full recovery timeline: | Phase | What to measure | |---|---| | Incident decision | Time to identify the failure and choose recovery | | Recovery-point selection | Time to locate and approve the correct point | | Recovery environment | Time to provision or prepare the target | | Data restore | Time to restore backups and transaction logs | | Database startup | Time until the engine accepts safe connections | | Validation | Time to prove data and application correctness | | Application reconnect | Time to restore dependent services | | Traffic return | Time until the agreed service is safe to reopen | A database that starts in 15 minutes can still have a two-hour RTO if validation, credentials, application reconnect, and traffic cutover take another 105 minutes. Measure **time to usable service**, not only database restore duration. ## Start every restore test with a failure scenario A recovery drill is more useful when it models an actual incident instead of restoring the easiest backup every time. Rotate scenarios such as: - accidental table deletion; - bad schema migration; - corrupted database files; - failed database upgrade; - primary-host loss; - compromised database credentials; - missing or broken transaction-log archive; - an incident discovered several days after it began; - complete database loss requiring rebuild from recovery artifacts. The failure scenario determines the recovery point, backup set, validation depth, and expected outcome. | Failure scenario | Recovery control to validate | |---|---| | Accidental deletion | PITR or historical database restore | | Bad migration | Pre-change recovery point + application validation | | Host loss | Replacement environment + database restore | | Delayed corruption | Older retained recovery point | | Credential compromise | Isolated recovery copies + rotated credentials | | Failed upgrade | Verified backup plus compatible recovery target | This also prevents a false sense of safety from repeatedly restoring only the newest recovery point. ## Use an isolated recovery target whenever the mechanism allows it Routine restore testing should avoid creating a second production incident. A safe drill usually looks like: ```text Production database -> selected recovery point -> isolated recovery target -> database validation -> application validation -> measured RPO / RTO -> cleanup ``` The isolated environment should not: - send real customer emails; - trigger payments; - replay production webhooks; - run production scheduled jobs; - write into the live database; - use production object-storage prefixes for test writes; - receive normal production traffic. Use separate credentials, test hostnames, restricted networking, and disabled side effects where practical. ## Record the exact recovery chain before starting A restore test should identify every artifact required for recovery. Record: - backup identifier; - backup timestamp; - database engine and version; - encryption-key or secret reference; - full or base backup; - dependent incremental backups if applicable; - WAL, binary logs, or other transaction logs; - restore target time; - required extensions or plugins; - expected storage capacity; - application version compatible with the recovery point. For PostgreSQL PITR, a base backup and required WAL history form one recovery chain. For MySQL PITR, a database backup plus the required binary-log range may be needed. Missing one dependency can move the actual recovery point behind the business RPO. ## Validate the database before validating the application After the database starts, verify the engine and recovered state before reconnecting normal application traffic. Check: - expected engine and major version; - recovery completed without unresolved errors; - expected databases and schemas exist; - required extensions or plugins are available; - roles and permissions are present; - migrations are at the intended state; - indexes exist and are usable; - critical tables or collections exist; - recent expected records match the recovery target; - unwanted later changes are absent when PITR is being tested. Use workload-specific validation rather than one global row count. A database can have roughly the expected number of rows while still missing a critical partition, migration, role, or transaction range. ## Application validation is part of database recovery A database restore is not operationally complete until the application can use it. Test representative business operations such as: - authentication; - one critical read; - one controlled write in the isolated environment; - API requests; - background workers; - scheduled jobs in a controlled mode; - reports or exports; - billing or order lookups; - connection-pool behavior; - file or object references connected to database records. The acceptance criteria should reflect what the business actually needs after an incident. If the database contains metadata for files stored in [Object Storage](/products/object-storage), validate that those referenced objects still exist and can be read. A database can restore successfully while the application remains broken because external durable files are missing or inconsistent. ## Credentials and encryption keys are part of RTO Recovery often stalls because the data exists but responders cannot access it. The restore runbook should identify where to obtain: - database administrator credentials; - application database credentials; - backup decryption keys; - object-storage credentials; - SSH or administrator access; - certificates and private keys; - API credentials required by the application. Do not store secret values directly in the runbook. Record where they are stored, who can retrieve them, and what emergency-access path exists if the primary identity system is unavailable. A technically valid backup is not operationally useful if the keys required to restore it disappear with the failed environment. ## Restore evidence should be measurable and reviewable Each drill should produce a compact evidence record. ```text Test date: Database: Recovery owner: Failure scenario: Backup / recovery set: Target recovery point: Actual recovery point: Restore started: Database ready: Application ready: Approved RPO: Measured RPO: Approved RTO: Measured RTO: Validation checks: Issues found: Manual workarounds: Remediation owner: Next review trigger: ``` Track trends across tests: - restore time increasing as the database grows; - missing credentials; - incomplete transaction-log retention; - engine-version incompatibility; - undocumented manual steps; - recovery targets no longer matching business requirements; - application validation taking longer than the database restore itself. A failed recovery drill is valuable when it produces remediation before a real incident. ## Restore-test cadence should follow risk, not a fixed template There is no universal monthly or quarterly cadence that fits every database. Choose restore-test cadence based on: - business impact; - RPO and RTO; - write volume; - database growth; - architecture complexity; - number of recovery dependencies; - age of the last successful recovery evidence; - changes to backup or retention policy; - changes to engine versions or extensions; - changes to credentials, networking, storage, or application dependencies; - recent incidents or failed recovery tests. Re-test after a material change to the recovery path. A test performed before a major database migration, storage redesign, or credential change may no longer represent the current architecture. ## Managed database restore testing validates a shared responsibility model With a managed database, the provider operates more of the backup and recovery platform. The customer still needs to validate the workload-level result. Before setting production RPO and RTO, verify the live service capabilities for: - backup frequency; - retention; - point-in-time recovery; - supported restore behavior; - engine versions; - high-availability options; - network and credential requirements. Then test the customer-controlled layers: - recovery-point selection; - restored data correctness; - migration state; - application reconnect; - connection pooling behavior; - application validation; - traffic-return decision. For Raff, use the current [Managed Databases](/products/managed-databases) page and engine-specific product pages as the source of truth for live recovery capabilities. :::cta Explore Managed Databases Compare the current managed recovery model before deciding whether your team should operate backups, PITR, monitoring, and database-host maintenance itself. ::: ## Self-hosted database restore testing validates the complete recovery chain A database on a [Raff VM](/products/raff-vm) gives your team deeper host-level control, but the full recovery chain becomes your responsibility. A self-hosted design may combine: ```text Database-native backup -> independent retained storage -> optional VM-level protection -> isolated recovery compute -> database validation -> application validation ``` Use database-native backups and transaction-log recovery when required for transactional consistency. Infrastructure backups and snapshots can support the wider recovery design, but they should not replace engine-aware recovery for active transactional databases. [Raff Data Protection](/products/data-protection) currently provides scheduled VM backups, configurable retention, separate backup storage, and in-place VM restore. The exact VM restore path powers down and overwrites the selected VM with the chosen recovery point, so database restore drills and VM restore drills should be designed as separate pieces of evidence where appropriate. For database backup artifacts that support an S3-compatible target, [Raff Object Storage](/products/object-storage) can provide a storage destination outside the database VM. ## Database restore testing checklist ### Before the test - [ ] Failure scenario is documented. - [ ] Database owner and recovery owner are assigned. - [ ] Approved RPO and RTO are recorded. - [ ] Exact recovery chain is identified. - [ ] Recovery target is isolated. - [ ] Required credentials and keys are available. - [ ] Application acceptance tests are defined. - [ ] Production side effects are disabled. - [ ] Cleanup or rollback path is documented. ### During recovery - [ ] Start time is recorded. - [ ] Exact backup and transaction-log inputs are recorded. - [ ] Restore completes without unresolved errors. - [ ] Database engine starts at the expected version. - [ ] Actual recovery point is measured. - [ ] Critical schemas, roles, and extensions exist. - [ ] Critical data checks pass. - [ ] Application reconnect succeeds. - [ ] Critical application workflows pass. ### Validate recovery objectives - [ ] Measured data-loss window is documented. - [ ] Measured RPO meets the approved target. - [ ] Complete recovery time is documented. - [ ] Measured RTO includes application readiness. - [ ] Measured RTO meets the approved target. ### After the test - [ ] Evidence is stored. - [ ] Errors and manual workarounds are documented. - [ ] Failed checks have named remediation owners. - [ ] Runbook is updated. - [ ] Retention or capacity changes are assigned. - [ ] Temporary recovery resources are removed. - [ ] Temporary credentials are rotated or removed. - [ ] Next test trigger is recorded. ## Common database restore-testing mistakes ### Treating backup success as recovery success A backup job can be green while the actual restore chain is broken. ### Measuring database startup instead of RTO RTO ends when the agreed service is usable, not when the database process starts. ### Validating only the newest backup Incidents discovered late may require an older retained recovery point. ### Testing database data without the application Schema, credentials, migrations, and connection behavior can still make the restored database unusable. ### Restoring into production during routine testing A routine drill should not create unnecessary customer risk. Use an isolated target when the mechanism allows it. ### Forgetting external files Database rows can reference objects that were not recovered to a compatible point. ### Using a fixed test cadence without considering architecture change Recovery evidence becomes stale when the recovery path materially changes, even if the calendar interval has not expired. ## Conclusion Database restore testing converts backup assumptions into measurable recovery evidence. A useful test proves the recovery chain, actual recovery point, database state, credentials, application behavior, and complete recovery time. Measure recovered data against RPO and the full path to usable service against RTO. Managed databases reduce the amount of recovery infrastructure your team operates, but they do not remove customer responsibility for recovery-point selection, data validation, application reconnect, and traffic return. Self-hosting gives deeper control but requires your team to operate and test the entire chain. Continue with [Database Backup Strategy for SaaS Apps](/learn/guides/database-backup-strategy-saas-apps) for the broader recovery architecture, [PostgreSQL Replication vs Backups vs Snapshots](/learn/guides/postgresql-replication-vs-backups-vs-snapshots) for PostgreSQL-specific recovery boundaries, or [Restore Testing Checklist for Production VMs](/learn/guides/restore-testing-checklist-production-vms) for full workload recovery validation. :::cta Review Raff Recovery Options Compare Managed Databases, Data Protection, Object Storage, and Raff VM based on which recovery responsibilities your team needs to own. ::: ## Sources - [PostgreSQL: Continuous Archiving and Point-in-Time Recovery](https://www.postgresql.org/docs/current/continuous-archiving.html) - [PostgreSQL: pg_restore](https://www.postgresql.org/docs/current/app-pgrestore.html) - [PostgreSQL: pg_basebackup and pg_verifybackup](https://www.postgresql.org/docs/current/app-pgbasebackup.html) - [MySQL 8.4: Backup and Recovery](https://dev.mysql.com/doc/refman/8.4/en/backup-and-recovery.html) - [MySQL 8.4: Point-in-Time Recovery](https://dev.mysql.com/doc/refman/8.4/en/point-in-time-recovery.html) - [Raff Managed Databases](/products/managed-databases) - [Raff Data Protection](/products/data-protection) - [Raff Object Storage](/products/object-storage) - Product details reviewed: 2026-09-16; verify live product pages and console for current recovery capabilities, limits, retention, and pricing. --- ### Database Reliability for Small Teams: Monitoring & Recovery URL: https://rafftechnologies.com/learn/guides/database-reliability-operations-small-teams Description: Learn database reliability for small teams across monitoring, failover, backups, PITR, recovery testing, ownership, and managed vs self-hosted operations. **Database reliability** is the operating discipline that keeps production data observable, available, recoverable, and clearly owned when normal service or infrastructure fails. For a small team, reliability is not a checklist of database features. It is a set of decisions about **what must stay healthy, how much data can be lost, how quickly service must return, and who owns each action when something breaks**. Raff Technologies supports both managed and self-hosted database operating models. [Managed Databases](/products/managed-databases) move more backup, monitoring, maintenance, and availability work into the service boundary. A database on a [Raff VM](/products/raff-vm) gives the team deeper host-level control but also makes the team responsible for the full operating lifecycle. The important distinction is that platform reliability and application correctness are not the same responsibility. Even with a managed database, the application team still owns schema design, query behavior, credentials, migrations, capacity decisions, recovery-point selection, application validation, and incident decisions. :::cta Compare Database Operating Models Use Managed Databases when reducing platform operations is the priority, or Raff VM when the workload requires host-level control. ::: ## Database reliability starts with four operating objectives Before choosing replicas, failover, backups, or managed services, define four things: | Objective | Question | What it drives | |---|---|---| | SLI | What database-dependent behavior represents healthy service? | Monitoring and telemetry | | SLO | What level of healthy behavior is acceptable? | Alerting and escalation | | RPO | How much recent data can be lost? | Backup, log, replication, and retention design | | RTO | How quickly must service return? | Failover, restore, staffing, and runbooks | A database can be technically online while the product is effectively unavailable. That is why useful SLIs should reflect application behavior, not only database process health. Examples include: - successful application reads and writes; - checkout or transaction completion; - connection-acquisition time; - p95 or p99 latency for critical operations; - failed-query rate; - background-job completion; - replica freshness where replicas serve reads. RPO and RTO should be assigned by workload. Billing, identity, orders, customer-generated production data, and internal reporting do not necessarily deserve the same recovery targets. A very short RPO or RTO also has real operational cost. It usually requires stronger replication, faster failover, protected recovery history, tested reconnect behavior, spare capacity, automation, and people who can operate the system under pressure. ## Database reliability engineering connects signals to decisions The useful part of **database reliability engineering** is not collecting every available metric. It is connecting customer impact to an action the team can take. A practical reliability loop is: ```text Customer-impact signal -> database or infrastructure cause -> owned response -> failover / rollback / restore / capacity action -> validation -> recorded evidence ``` For example, rising connection-pool wait time may explain slow customer requests before CPU becomes obviously saturated. Replication lag may matter only when a replica serves reads or is expected to satisfy a failover RPO. Backup age matters because it changes recoverability, not because a dashboard tile turned red. This framing keeps monitoring attached to operational decisions instead of producing alerts with no owner. ## Monitoring should explain user impact, not compete for attention This guide covers the reliability operating model; the detailed metric framework belongs in [Database Monitoring for Small Teams](/learn/guides/database-monitoring-small-teams). At the reliability level, track enough signals to answer whether the service is healthy and whether the recovery paths remain usable: | Signal area | Reliability question | |---|---| | Application success | Can users complete critical database-backed workflows? | | Connections | Can the application obtain connections without excessive wait or rejection? | | Queries and locks | Is workload behavior preventing useful work? | | Compute and storage | Is the system approaching a capacity limit? | | Replication | Is the continuity path current enough for its intended role? | | Backups and PITR | Is recoverable history being created? | | Restore evidence | Has historical recovery actually been proven? | | Maintenance | Are versions, certificates, or deferred changes becoming operational risk? | Not every threshold deserves an urgent alert. Capacity trends, slow storage growth, and gradual query deterioration often belong in scheduled review. Pager-level alerts should identify a condition that needs a specific action now. ## Availability and historical recovery solve different failures A reliable database architecture separates continuity from historical correctness. | Control | Primary purpose | Does not automatically protect against | |---|---|---| | Replication | Maintain another current copy | Bad writes copied to replicas | | Failover | Restore service continuity | Historical corruption or unwanted changes | | Backup | Preserve independent history | Fast continuity by itself | | PITR | Recover toward a chosen historical point | Application validation or reconnect behavior | | Infrastructure snapshot | Fast rollback in selected cases | Complete engine-aware database recovery | Replication and failover answer: **How do we keep serving when the current primary path fails?** Backups and PITR answer: **How do we recover when the current data state is wrong?** This matters because a healthy replica can contain the same accidental deletion, destructive migration, or application-written corruption as the primary. For PostgreSQL-specific protection boundaries, use [PostgreSQL Replication vs Backups vs Snapshots](/learn/guides/postgresql-replication-vs-backups-vs-snapshots). For the wider recovery design, use [Database Backup Strategy for SaaS Apps](/learn/guides/database-backup-strategy-saas-apps). ## Map failure modes to explicit controls Small teams do not need every possible database feature. They need enough independent controls for the failures that matter to the business. | Failure or requirement | Primary control | Supporting controls | |---|---|---| | Primary database unavailable | Tested failover or replacement path | Monitoring, reconnect behavior, spare capacity | | Accidental deletion | PITR or historical restore | Protected retention, restore testing | | Bad schema migration | Compatibility-first rollout + recovery point | Validation, rollback decision, PITR | | Connection saturation | Connection and pool monitoring | Capacity review, query optimization | | Storage growth | Capacity monitoring and expansion plan | Retention review, headroom policy | | Incident discovered late | Multi-point retained recovery history | Restore-point selection and validation | | Team lacks database on-call depth | Managed operating model | Clear shared-responsibility boundary | | Custom topology or unsupported extension | Self-hosted operating model | Named ownership for patching, backup, and recovery | | Backup exists but has never been restored | Restore drill | Measured RPO/RTO and application validation | This table is more useful than asking whether a provider offers “HA” or “backup” in isolation. The design should start from the failure mode and business consequence. ## Failover testing and restore testing prove different capabilities A **failover test** proves service continuity. It should answer: - is the secondary current enough for the required RPO? - can it accept the intended workload? - can applications and connection pools reconnect? - are writes directed to the correct authoritative primary? - does the service return within the target? - how is redundancy rebuilt afterward? A **restore test** proves historical recovery. It should answer: - can the recovery chain actually be restored? - can the team select a safe recovery point? - how long does recovery take at the current data size? - are roles, extensions, permissions, and dependent objects present? - can the application use the restored data safely? - does the measured recovery fit RPO and RTO? A successful failover does not prove backups or PITR. A successful restore does not prove fast continuity. Use [Database Restore Testing: RPO, RTO, and Recovery Validation](/learn/guides/database-restore-testing-rpo-rto-recovery-validation) for the detailed restore framework. ## Recovery evidence should be treated like a production signal Many teams monitor whether a backup job completed but not whether the recovery path still works. Useful recovery evidence includes: - age of the newest usable recovery point; - last successful backup or archive event; - WAL or binary-log archive health where PITR is required; - last successful failover test; - last successful restore test; - measured RPO from the last drill; - measured RTO from the last drill; - unresolved recovery workarounds; - age of the recovery runbook; - named owner for open remediation. A database can be healthy today while its ability to recover has silently degraded for weeks. ## Managed databases change the operating boundary, not the business responsibility A managed database can reduce repetitive platform work around provisioning, host maintenance, backup infrastructure, monitoring, supported recovery workflows, storage operations, and high-availability controls. The customer still owns: - schemas and data models; - query and index design; - application credentials; - migrations; - capacity choices; - workload-specific SLOs; - recovery-point selection; - application reconnect behavior; - data validation after failover or restore; - traffic-return decisions during an incident. This shared-responsibility model is the central commercial decision for small teams: **does the workload require host-level control strongly enough to justify owning the reliability work that comes with it?** Use [Managed vs Self-Hosted Databases](/learn/guides/managed-vs-self-hosted-databases) for that operating-model decision. :::cta Explore Raff Managed Databases Compare the current managed database engines and service capabilities when reducing database operations is the priority. ::: ## Engine-specific reliability belongs on the engine path Different engines need different operational details, so this reliability guide should not become the keyword owner for every engine-specific query. For PostgreSQL, use [Managed PostgreSQL](/products/managed-databases/postgresql) and [Postgres Hosting: Managed vs Self-Hosted](/learn/guides/postgresql-hosting-for-saas). For MySQL, use [Managed MySQL](/products/managed-databases/mysql) and [MySQL Hosting: Managed vs Self-Hosted](/learn/guides/mysql-hosting-managed-vs-self-hosted). For Valkey, first classify the role of the data. A rebuildable cache has different durability requirements from sessions, coordination state, queues, or business-critical durable state. [Managed Valkey](/products/managed-databases/valkey) should be evaluated against the role the workload actually gives that data. The reliability rule is simple: do not let a supporting datastore become an undocumented source of truth. ## Self-hosted databases need explicit lifecycle ownership A database on a [Raff VM](/products/raff-vm) gives the team direct control over operating system, database version, extensions, files, storage layout, replication topology, and recovery tooling. That also transfers the complete lifecycle to the team: - operating-system and database patching; - monitoring and alert ownership; - backup automation and retention; - database-native recovery; - restore testing; - replication and failover design; - security hardening; - storage planning; - connection-capacity planning; - maintenance scheduling; - incident response; - after-hours ownership. [Raff Data Protection](/products/data-protection) can support VM-level recovery where appropriate, while database-native backups and PITR remain separate responsibilities for transactional database state. The comparison should therefore use total operational ownership, not only the monthly price of a VM versus a managed database plan. ## Reliability improves when ownership is explicit Every important control should have a named owner and a known stop condition. A practical ownership matrix can look like: | Reliability area | Owner should know | |---|---| | Monitoring | Which signals represent customer impact and when to escalate | | Capacity | When storage, connections, or compute require action | | Migration safety | When to stop, rollback, or recover | | Failover | Who can initiate it and how success is validated | | Backups | Whether usable recovery history is being created | | Restore | Who selects the point and validates recovered data | | Credentials | How emergency access works if normal identity paths fail | | Incident command | Who makes consequential recovery decisions | Ownership matters most under pressure. Reliability work that “the team” owns often becomes work nobody can safely execute during an incident. ## Database reliability runbooks should organize decisions, not commands A useful runbook should describe the decision path for common incidents: 1. customer-visible symptom; 2. signals that confirm the condition; 3. immediate safety objective; 4. authorized containment action; 5. failover, rollback, restore, or rebuild path; 6. person authorized to approve consequential action; 7. checks that prove recovery; 8. cleanup and follow-up work. Useful scenarios include: - connection exhaustion; - slow-query or lock storms; - storage pressure; - replication lag or disconnection; - failed backups; - failed migrations; - suspected corruption; - primary failure; - certificate or credential expiry; - suspected privileged compromise. The most valuable rule is to decide the stop condition and recovery owner **before** production pressure appears. ## Database reliability checklist for small teams Before treating a production database as operationally ready, confirm: 1. Critical database-backed user workflows have defined SLIs. 2. RPO is documented for important data. 3. RTO is documented for important services. 4. Monitoring connects database signals to customer impact. 5. Connection and storage capacity have action thresholds. 6. Availability controls and historical recovery controls are treated separately. 7. Backups or PITR create independent recovery history where required. 8. Failover has been tested when continuity depends on it. 9. Restore has been tested when recovery depends on it. 10. Measured recovery results are stored as evidence. 11. Migration rollback or recovery decisions are documented. 12. Credentials required during recovery remain accessible. 13. Managed-vs-self-hosted responsibility is explicit. 14. Each critical reliability action has a named owner. ## Conclusion Database reliability for small teams is an operating model built around service objectives, customer-impact monitoring, availability controls, historical recovery, testing, and ownership. Define SLI, SLO, RPO, and RTO before choosing infrastructure features. Use failover for continuity and backups or PITR for historical correctness. Test those paths separately. Measure recovery evidence instead of assuming backup success means recoverability. Managed databases reduce the amount of platform work a small team must operate, while self-hosting provides deeper control at the cost of owning the complete lifecycle. The right boundary is the one that matches the workload's actual requirements and the team's ability to operate it reliably. Continue with [Database Monitoring for Small Teams](/learn/guides/database-monitoring-small-teams), [Database Backup Strategy for SaaS Apps](/learn/guides/database-backup-strategy-saas-apps), and [Managed vs Self-Hosted Databases](/learn/guides/managed-vs-self-hosted-databases) for the detailed decision paths. :::cta Compare Raff Database Options Choose the operating model based on how much database reliability work your team needs to own. ::: ## Sources - [PostgreSQL: Monitoring Database Activity](https://www.postgresql.org/docs/current/monitoring.html) - [PostgreSQL: High Availability, Load Balancing, and Replication](https://www.postgresql.org/docs/current/high-availability.html) - [PostgreSQL: Backup and Restore](https://www.postgresql.org/docs/current/backup.html) - [MySQL 8.4: Replication](https://dev.mysql.com/doc/refman/8.4/en/replication.html) - [MySQL 8.4: Backup and Recovery](https://dev.mysql.com/doc/refman/8.4/en/backup-and-recovery.html) - [Raff Managed Databases](/products/managed-databases) - [Raff Managed PostgreSQL](/products/managed-databases/postgresql) - [Raff Managed MySQL](/products/managed-databases/mysql) - [Raff Managed Valkey](/products/managed-databases/valkey) - [Raff Data Protection](/products/data-protection) - Product details reviewed: 2026-09-16; verify live product pages and console for current engine availability, recovery features, limits, and pricing. --- ### Database Monitoring for Small Teams: Metrics & Alerts URL: https://rafftechnologies.com/learn/guides/database-monitoring-small-teams Description: Learn database monitoring for small teams across performance, connections, slow queries, locks, capacity, replication, backups, restore evidence, tools, and alerts. **Database monitoring** is the practice of tracking the signals that show whether a production database is healthy, degrading, approaching a limit, or losing its ability to recover safely. For a small team, effective database monitoring does not mean collecting every metric. It means connecting **customer impact → database behavior → action → recovery confirmation** with as little noise as possible. Raff Technologies supports both managed and self-hosted database operating models. [Managed Databases](/products/managed-databases) can reduce the amount of host- and engine-level monitoring work a team must operate itself, while a database on a [Raff VM](/products/raff-vm) gives deeper control and makes the team responsible for the complete monitoring stack. The monitoring model should answer five questions quickly: 1. Are users or critical jobs affected? 2. Which database behavior is most likely causing the impact? 3. Is the condition stable, recovering, or getting worse? 4. Does the team still have enough capacity and recovery coverage? 5. Who owns the response, and what proves recovery? :::cta Compare Database Operating Models Use Managed Databases when reducing database-platform operations matters, or Raff VM when the workload requires full host-level control. ::: ## Database monitoring should start with customer impact A database can report normal CPU and memory while users are seeing timeouts, blocked transactions, stale reads, or failed background jobs. That is why production monitoring should begin with application behavior and then work inward toward the database cause. | Monitoring layer | Primary question | Useful signals | |---|---|---| | User impact | Can customers complete database-dependent work? | Request success, transaction latency, job failures, connection wait time | | Workload behavior | What is the database doing? | Slow queries, lock waits, long transactions, query errors | | Capacity | Is the database approaching a practical limit? | Connections, storage growth, CPU, memory pressure, I/O latency | | Continuity | Can another path keep service running? | Replica health, lag, failover readiness | | Recovery | Can the team recover correct historical data? | Backup age, PITR/log continuity, restore-test evidence | The most useful alert pairs customer impact with enough database context to guide the first safe action. ## Database performance monitoring needs workload context **Database performance monitoring** is more useful when it explains why application work is becoming slower or less reliable, rather than simply showing resource percentages. Start with these workload questions: - Are critical requests slower than their normal baseline? - Are more queries failing? - Are applications waiting for database connections? - Are a small number of query families consuming most execution time? - Are lock waits or long transactions blocking useful work? - Is storage or I/O becoming the bottleneck? - Did performance change after a deployment, migration, or traffic shift? A practical performance-monitoring path is: ```text Application latency or errors -> connection availability -> query behavior -> locks / transactions -> CPU / memory / I/O / storage -> recent deploy or migration -> owned response ``` This order prevents teams from treating high CPU as the diagnosis when it may only be the symptom of a query regression, lock storm, connection surge, or maintenance task. ## Connection monitoring should protect headroom before exhaustion Database connection exhaustion can make a healthy database appear unavailable to the application. Track: - configured connection limit; - active connections; - idle connections; - waiting or rejected connections; - idle-in-transaction sessions; - pool size per application component; - connection acquisition latency; - connection age; - administrative reserve. Plan total connection demand across the whole application: ```text application instances × pool size + workers + scheduled jobs + migrations + monitoring sessions + admin reserve = planned connection demand ``` The common failure is increasing pool sizes independently across services until the database becomes the shared bottleneck. More connections do not automatically create more throughput. They can increase memory use, lock pressure, queueing, and context switching. A useful connection alert should answer: - are users waiting for connections now? - which service is consuming the pool? - is demand caused by traffic growth, a leak, autoscaling, or long transactions? - how much administrative headroom remains? ## Slow-query monitoring should measure total workload impact A query is operationally important when it is slow enough, frequent enough, or blocking enough to affect the service. Monitor normalized query families by: - execution count; - total execution time; - mean and percentile latency where available; - rows processed versus rows returned; - temporary work or spills; - lock-wait time; - plan changes; - endpoint, worker, or job generating the query where available. A one-second query that runs once per day can matter less than a 40 ms query executed hundreds of thousands of times. Conversely, one long migration or reporting query can block production even when its execution count is one. The useful question is therefore not simply **“Which query is slow?”** It is **“Which query family is consuming or blocking the most useful work?”** ## Locks and transaction age reveal stalls that CPU graphs can miss Track: - waiting sessions; - blocking sessions; - deadlocks; - long-running transactions; - idle-in-transaction age; - migration duration; - lock-wait duration. A lock alert should show both the waiter and the blocker where possible. The response also needs a safe decision path. Terminating a blocker can roll back a large transaction, increase I/O, or create application errors. A runbook should define who can authorize that action and what must be checked first. Long-lived transactions are especially useful early-warning signals because they can create lock risk, delay cleanup, complicate schema changes, and increase recovery or maintenance work before CPU becomes obviously abnormal. ## Capacity monitoring should use headroom and rate of change A single percentage threshold is rarely enough for database capacity. | Capacity area | Monitor | Better question | |---|---|---| | CPU | Sustained utilization + workload change | Is useful demand rising, or did a query regress? | | Memory | Pressure, swapping, per-session demand | Can current concurrency fit safely? | | Storage | Free space + growth rate | How long until capacity becomes unsafe? | | I/O | Latency, queueing, waits | Is storage becoming the bottleneck? | | Connections | Usage + wait/rejection rate | How much safe concurrency remains? | A database at 70% storage utilization and growing 0.1% per month is a different operational problem from one at 70% and growing 2% per day. Capacity planning should also include temporary requirements from: - index builds; - schema migrations; - restores; - large imports; - transaction-log growth; - maintenance; - replica catch-up. Classify responses by urgency: - **Page** — user impact exists or a hard limit is imminent. - **Urgent ticket** — a safe boundary will be crossed soon. - **Scheduled review** — growth is predictable and there is time to resize or optimize deliberately. ## Replication monitoring should reflect the replica's role Replication lag has different meaning depending on why the replica exists. | Replica role | Monitoring risk | |---|---| | Read scaling | Users may receive stale results | | Analytics | Reports may operate on delayed data | | Failover | Promotion may expose a larger data-loss window | | Recovery feed | Recovery coverage may degrade | | Maintenance standby | Planned switchover may take longer | Monitor whether the replica is: - connected; - receiving changes; - applying changes; - recovering lag after a spike; - retaining excessive logs because it cannot keep up. Thresholds should follow the product requirement. Five minutes of lag may be acceptable for analytics and unacceptable for permissions, subscriptions, billing, or inventory. Do not treat a connected replica as automatically safe for failover. Promotion also depends on replay position, expected data loss, client routing, fencing, capacity, and application reconnect behavior. For the availability-versus-history distinction, use [PostgreSQL Replication vs Backups vs Snapshots](/learn/guides/postgresql-replication-vs-backups-vs-snapshots). ## Backup and restore monitoring belongs beside performance monitoring A database can be performing perfectly while its recovery path is silently failing. Track recovery-readiness signals such as: - last successful backup time; - age of the newest usable recovery point; - expected backup interval; - WAL, binary-log, or other transaction-log continuity where PITR is required; - retention status; - backup access or credential failures; - backup-size anomalies; - last successful restore-test date; - measured restore duration; - measured RPO and RTO from the last drill; - application validation result. A green backup job proves that a backup process completed. It does not prove that the recovery point is usable or that the database can return within the required RTO. Separate two types of recovery monitoring: - **Recovery coverage alert** — act quickly when backup or log continuity is broken and the approved RPO is at risk. - **Recovery evidence alert** — create follow-up work when restore testing is stale or measured recovery is approaching the approved RTO. Use [Database Backup Strategy for SaaS Apps](/learn/guides/database-backup-strategy-saas-apps) for recovery design and [Database Restore Testing: RPO, RTO, and Recovery Validation](/learn/guides/database-restore-testing-rpo-rto-recovery-validation) for the detailed restore-testing framework. ## Database monitoring metrics should map to actions A compact production metric set is more useful than a large dashboard nobody owns. | Signal | Why it matters | Typical action path | |---|---|---| | Application DB error rate | Direct customer impact | Inspect connection, query, and dependency failures | | Connection wait/rejection | Capacity or pool failure | Identify consuming service, leak, or pool sizing issue | | Query latency / total time | Performance regression | Identify query family and recent change | | Lock wait / transaction age | Concurrency stall | Find blocker and evaluate safe intervention | | Storage headroom | Hard capacity risk | Resize, clean, or change growth plan | | I/O latency | Storage bottleneck | Identify workload or storage pressure | | Replication lag | Freshness/failover risk | Determine whether secondary still satisfies its role | | Backup/PITR continuity | Recovery-point risk | Repair recovery chain | | Restore-test age | Recovery confidence | Schedule and execute validation | This metric set should be adapted to the engine and workload. It is not a universal threshold template. ## Database alerts should protect the team's attention Small teams should classify alerts before creating them. | Alert class | Meaning | Expected response | |---|---|---| | Page | Active user impact or immediate data/recovery risk | Respond now | | Urgent ticket | Rapidly approaching safe limit | Resolve in a defined window | | Scheduled review | Trend or maintenance concern | Review during operations cycle | | Dashboard only | Investigation context | No standalone response | | Recovery evidence | Proof of backup/restore readiness | Retain and review periodically | Every paging alert should include: - affected service and environment; - customer or job impact; - current value and recent baseline; - likely correlated causes; - owner and escalation path; - first safe diagnostic action; - runbook link; - recovery confirmation criteria. Review alerts after incidents and false positives. Remove alerts that do not lead to a decision, merge duplicate symptoms, and do not suppress customer-impact signals simply because maintenance is scheduled. ## Database monitoring tools are secondary to monitoring design Searches for **database monitoring tools** often mix several different needs: engine metrics, query analysis, application tracing, infrastructure telemetry, alert routing, and managed-service visibility. A monitoring stack may combine: - database-native statistics and logs; - infrastructure metrics; - application performance monitoring or tracing; - centralized logs; - query-performance views; - alert routing; - managed database telemetry; - restore and backup evidence. Choose tooling only after defining what must be detected and who acts on it. Evaluate a database monitoring tool or platform against questions such as: 1. Can it correlate database behavior with application impact? 2. Does it expose connection, query, lock, capacity, and replication signals relevant to the engine? 3. Can the team alert on rates of change, not only fixed thresholds? 4. Can it distinguish page-worthy incidents from trend review? 5. Can responders see enough context without jumping across many dashboards? 6. Does it support the ownership and runbook model the team actually uses? 7. Can recovery-readiness signals be monitored somewhere in the same operating process? The best monitoring architecture is not the one with the most charts. It is the one that helps the team recognize important conditions early and make the correct decision quickly. ## Managed databases reduce some monitoring work, not all monitoring responsibility With a managed database, more host- and engine-level collection, maintenance, backup infrastructure, and service telemetry can sit inside the provider boundary. The application team still needs to monitor: - customer transaction success; - workload-specific latency; - application connection behavior; - query and endpoint behavior; - migration impact; - capacity decisions; - business validation after failover or restore; - whether the current service capabilities still meet RPO and RTO requirements. For Raff, compare the current [Managed Databases](/products/managed-databases), [Managed PostgreSQL](/products/managed-databases/postgresql), [Managed MySQL](/products/managed-databases/mysql), and [Managed Valkey](/products/managed-databases/valkey) pages for the live service boundary and available capabilities. Product capabilities, engine availability, retention, monitoring features, and limits can change, so the live product page and console should remain the source of truth for production design. :::cta Explore Raff Managed Databases Compare managed database options when your team wants to reduce host-level monitoring, maintenance, backup, and recovery operations. ::: ## Self-hosted database monitoring includes the full infrastructure stack A database on a [Raff VM](/products/raff-vm) gives the team full engine and operating-system control. That also means the team owns: - host metrics; - database metrics; - query and lock visibility; - database logs; - OS logs; - backup monitoring; - PITR/log-archive monitoring; - replication monitoring; - patch and certificate monitoring; - alert routing; - restore-test evidence; - monitoring-system availability itself. [Raff Data Protection](/products/data-protection) can support VM-level recovery where appropriate, but transactional database recovery should still use engine-aware backup and restore design when required by the workload. This is why the managed-vs-self-hosted decision should compare total operational ownership, not only the infrastructure price. ## Database monitoring checklist for small teams Before treating the monitoring model as production-ready, confirm: 1. Critical database-backed user workflows are monitored. 2. Application error and latency signals can be correlated with database behavior. 3. Connection wait, rejection, and headroom are visible. 4. Important query families can be identified by total workload impact. 5. Lock waits and long transactions are visible. 6. Storage growth and capacity headroom are tracked. 7. I/O and compute pressure can be distinguished from query or lock problems. 8. Replication lag thresholds reflect the replica's actual role. 9. Backup and PITR continuity are monitored where required. 10. Restore-test age and measured recovery results are reviewed. 11. Page, urgent-ticket, scheduled-review, and dashboard signals are separated. 12. Every important alert has a named owner and first safe action. 13. Managed-vs-self-hosted monitoring responsibility is explicit. 14. Alerts are reviewed after incidents and false positives. ## Conclusion Database monitoring for small teams should connect customer impact to a compact set of performance, capacity, replication, and recovery signals. Start with application success and latency. Then use connection availability, query behavior, locks, storage growth, I/O, replication lag, backup coverage, and restore evidence to explain what is happening and what should happen next. Monitoring tools matter, but the operating model matters more. Managed databases can reduce platform-level monitoring and maintenance work, while self-hosting gives deeper visibility and control at the cost of owning the complete monitoring lifecycle. Continue with [Database Reliability for Small Teams](/learn/guides/database-reliability-operations-small-teams), [Database Backup Strategy for SaaS Apps](/learn/guides/database-backup-strategy-saas-apps), or [Managed vs Self-Hosted Databases](/learn/guides/managed-vs-self-hosted-databases) for the next decision layer. :::cta Compare Raff Database Options Choose the database operating model based on how much monitoring, maintenance, recovery, and host-level control your team needs to own. ::: ## Sources - [PostgreSQL: Monitoring Database Activity](https://www.postgresql.org/docs/current/monitoring.html) - [PostgreSQL: Statistics](https://www.postgresql.org/docs/current/monitoring-stats.html) - [PostgreSQL: High Availability and Replication](https://www.postgresql.org/docs/current/high-availability.html) - [MySQL 8.4: Performance Schema](https://dev.mysql.com/doc/refman/8.4/en/performance-schema.html) - [MySQL 8.4: Slow Query Log](https://dev.mysql.com/doc/refman/8.4/en/slow-query-log.html) - [MySQL 8.4: Replication Status](https://dev.mysql.com/doc/refman/8.4/en/replication-administration-status.html) - [Raff Managed Databases](/products/managed-databases) - [Raff Managed PostgreSQL](/products/managed-databases/postgresql) - [Raff Managed MySQL](/products/managed-databases/mysql) - [Raff Managed Valkey](/products/managed-databases/valkey) - Product details reviewed: 2026-09-16; verify live product pages and console for current monitoring, recovery, engine availability, limits, and pricing. --- ### Database Incident Runbook: Connection Exhaustion, Disk Pressure, and Failover URL: https://rafftechnologies.com/learn/guides/database-incident-runbook Description: Use this database incident runbook to triage connection exhaustion, disk pressure, query storms, failover, restore decisions, recovery validation, and follow-up. A **database incident runbook** is a decision framework for detecting impact, stabilizing the system, choosing containment or recovery, validating service, and recording what must change afterward. For a small team, the runbook should be short enough to use during an outage and specific enough to prevent risky improvisation. The first objective is not perfect root-cause analysis. It is to **protect data, stop customer impact from widening, preserve a trustworthy recovery path, and make the next decision explicit**. Raff Technologies supports both managed and self-hosted database operating models. [Managed Databases](/products/managed-databases) can move more infrastructure, backup-platform, monitoring, and availability operations into the service boundary. A database on a [Raff VM](/products/raff-vm) gives deeper host-level control, but the team owns the complete incident path. A practical incident sequence is: ```text Detect impact -> establish ownership -> preserve evidence -> classify failure mode -> contain safely -> fail over / roll back / restore when justified -> validate application + data + protection -> rebuild redundancy -> record corrective work ``` :::cta Compare Database Operating Models Choose Managed Databases when reducing platform incident work matters, or Raff VM when the workload requires full host-level control. ::: ## Database incident response starts with impact and ownership A database alert becomes an incident when it threatens customer workflows, data correctness, recovery objectives, or the team's ability to control the system safely. Severity should follow impact rather than one infrastructure metric. A lightweight scheme might look like: | Severity | Practical definition | Response | |---|---|---| | SEV-1 | Critical writes fail, primary is unavailable, or data integrity may be at risk | Immediate incident command and recovery decision | | SEV-2 | Partial customer degradation, replica failure, or urgent capacity pressure | Named owner and active mitigation | | SEV-3 | Contained degradation or warning without material customer impact | Investigate and create preventive work | The exact labels are a team convention, not a universal standard. What matters is that severity determines ownership, communication, and decision authority. Assign these responsibilities even when one person performs several roles: - **Incident commander** — coordinates decisions, timeline, and communication. - **Database responder** — evaluates engine, sessions, locks, replication, and recovery state. - **Application responder** — confirms customer impact, pools, retries, workers, and validation. - **Infrastructure responder** — checks host, storage, compute, and networking where relevant. - **Communications owner** — keeps internal and external stakeholders aligned. The incident commander should not become the only person executing commands. Coordination and execution are different jobs. NIST SP 800-61 Rev. 3 treats incident response as part of broader cybersecurity risk management and emphasizes preparation, detection, response, recovery, and improvement. A database runbook applies the same principle to service and data decisions without turning the incident into a command checklist. ## Start triage with five questions Before a consequential change, answer: 1. Which customer workflows are failing? 2. Are reads, writes, or both affected? 3. Is data correctness uncertain? 4. Is the condition stable, recovering, or getting worse? 5. Does the system still have a safe continuity or historical recovery path? Collect a minimum evidence set: | Evidence area | Questions | |---|---| | Application | Error rate, latency, pool waits, failed jobs, affected endpoints | | Database | Active/waiting sessions, locks, long transactions, engine logs | | Capacity | Storage headroom, growth, CPU, memory, I/O, connections | | Replication | Replica state, lag, replay/apply position, errors | | Infrastructure | Host health, process state, networking, recent events | | Recovery | Newest usable recovery point, backup/PITR continuity, last restore evidence, RPO/RTO | Preserve timestamps. A simple timeline is often enough: ```text 14:02 alert fired 14:04 customer write errors confirmed 14:07 connection pool saturation identified 14:10 noncritical workers paused 14:14 new connection success recovered 14:22 retry storm isolated ``` Do not begin with a broad restart unless the runbook already explains why restart is safe. Restarting can remove evidence, trigger crash recovery, prolong downtime, or turn degradation into complete unavailability. For the monitoring layer that should trigger this runbook, use [Database Monitoring for Small Teams](/learn/guides/database-monitoring-small-teams). ## Classify the active failure mode before choosing the action The dominant failure mode determines the safest containment path. | Failure mode | Immediate safety objective | Lower-risk containment | Escalation decision | |---|---|---|---| | Connection exhaustion | Preserve admin access and reduce new demand | Pause noncritical workers, reduce retries, correct pool pressure | Add capacity only after understanding resource impact | | Disk pressure | Preserve write and recovery capability | Stop avoidable growth, pause large jobs, add verified capacity | Fail over only if secondary and fencing conditions are safe | | Lock/query storm | Restore useful concurrency | Stop offending workload or selected sessions | Roll back change if workload will immediately return | | Replica failure/lag | Protect freshness and failover readiness | Remove stale replica from reads, reduce pressure | Rebuild/resync if it cannot recover safely | | Primary failure | Establish one authoritative writer | Confirm standby/replacement readiness | Promote only after RPO, fencing, and reconnect checks | | Corruption or compromise | Stop propagation and preserve evidence | Restrict writes and isolate affected path | Restore from a known-good point when active state is untrusted | This is the core database incident-response rule: **match the action to the failure mode instead of applying a generic restart or scale-up response.** ## Connection exhaustion needs demand control before limit increases Connection exhaustion occurs when applications or operators cannot obtain usable database sessions. Common causes include: - leaked connections; - oversized pools; - retry storms; - autoscaling that multiplies independent pools; - long-running or idle transactions; - blocked sessions accumulating behind locks; - reporting or administration consuming remaining capacity; - a slow database causing requests to hold connections longer. Containment order: 1. Confirm connection acquisition is the customer-impacting bottleneck. 2. Preserve or establish administrative access. 3. Reduce new demand by pausing noncritical workers, reports, or retries. 4. Identify blocked, idle-in-transaction, leaked, or unexpectedly long sessions. 5. Terminate only sessions whose business and rollback effects are understood. 6. Correct pool and retry behavior. 7. Increase server-side limits only when memory and workload impact are understood. 8. Validate that new connections and critical transactions recover. Do not treat `max_connections` as the diagnosis. More sessions can increase memory use, context switching, lock pressure, and I/O while leaving the original workload problem unchanged. A connection incident is resolved only when the application pool stabilizes. Database process availability alone does not prove recovery. ## Disk pressure requires write safety and known ownership Disk pressure can stop writes, disrupt transaction logging, break replication, or make recovery harder. Identify what is growing before deleting anything: - database tables and indexes; - WAL, binary logs, or other transaction logs; - retained logs caused by replication state; - temporary query files; - local backup artifacts; - application logs; - failed maintenance output; - migrations, index builds, or table rewrites. Containment order: 1. Confirm the affected filesystem and remaining headroom. 2. Stop avoidable growth such as imports, reports, maintenance, or duplicate backup work. 3. Preserve database-managed and transaction-log files. 4. Add or extend verified capacity when supported. 5. Remove only files with known ownership and known recovery consequences. 6. Check replication and recovery chains after capacity is restored. 7. Validate writes, logging, backups, and application behavior. Manual deletion of unknown database-managed files can turn a capacity incident into a recovery incident. The runbook should document what is safe to clean and what must never be removed ad hoc. ## Lock or query storms require controlled workload reduction A database can remain technically available while useful work is blocked by one transaction, migration, or query family. Confirm: - which sessions are waiting; - which session or transaction is blocking them; - how long the blocker has been active; - which application or job owns it; - what rollback would cost; - whether a deployment or migration caused the change. A safe response often prioritizes reducing the offending workload over increasing infrastructure. Possible actions include: - pause a noncritical worker; - stop a reporting job; - disable an expensive feature path; - reduce retries; - roll back a recent application change; - terminate a specific session after understanding rollback effects. The decision should be reversible whenever possible. ## Database failover is a data-authority decision **Database failover** moves the writer role from an unhealthy primary to a standby or replacement system. It is not simply a restart or routing change. Before promotion, establish: - the current primary is unavailable or can be fenced from writes; - standby health is understood; - replica freshness and expected data loss are known; - the recovery point fits the approved RPO, or an explicit exception is accepted; - the application can discover and authenticate to the new writer; - pools and workers can reconnect; - monitoring and backup paths can follow the new topology; - there is a plan to rebuild redundancy afterward. Use this decision test: | Question | Safer to promote when | Do not promote when | |---|---|---| | Is the old primary still writing? | It is fenced or definitively unavailable | Write authority is ambiguous | | Is standby freshness known? | Position/lag satisfies RPO or exception is approved | Recovery point is unknown | | Is standby health understood? | Storage, replication, and engine state are known | Corruption or unresolved errors exist | | Can clients reconnect? | Endpoint, credentials, pools, and workers are understood | Application path is uncertain | | Can redundancy be rebuilt? | A post-failover plan exists | Promotion creates an unmanaged single point indefinitely | The split-brain risk matters: two systems must not both believe they are the authoritative writer. After promotion, the incident is not finished merely because traffic works. Rebuilding redundancy, backups, monitoring, and recovery coverage is part of recovery. For the architectural distinction between failover and historical recovery, use [Database Reliability for Small Teams](/learn/guides/database-reliability-operations-small-teams). ## Rollback, failover, restore, and rebuild are different decisions These actions solve different problems: | Action | Use when | Key risk | |---|---|---| | Rollback | A recent application/schema change caused the failure and can be reversed safely | Compatibility or partial-change state | | Failover | Current primary path is unavailable but a trustworthy secondary exists | Data loss or dual-writer state | | Restore/PITR | Current data state itself is wrong or untrustworthy | Choosing the wrong recovery point | | Rebuild | Instance/topology is no longer trustworthy or repair is slower/riskier | Longer service recovery and configuration drift | A team under pressure should not treat these as interchangeable. When historical recovery is required, use [Database Restore Testing: RPO, RTO, and Recovery Validation](/learn/guides/database-restore-testing-rpo-rto-recovery-validation). ## Recovery validation must cover service, data, and protection Recovery is complete only when customer workflows work and the database has returned to a protected state. ### Validate the database - expected writer role is established; - connections succeed; - no unresolved recovery errors remain; - storage has safe headroom; - session and lock behavior are stable. ### Validate data correctness - critical schemas/tables are present; - expected recent transactions exist when they should; - unwanted transactions are absent when recovery targeted an earlier point; - roles, permissions, and required extensions are available; - application-visible totals or invariants are plausible. ### Validate the application - pools create new sessions; - critical reads and writes succeed; - workers and scheduled jobs resume safely; - important business flows work; - error rate and latency return to an acceptable range. ### Validate protection state - backups resume; - transaction-log/PITR continuity is healthy where required; - replicas are healthy or rebuilding; - monitoring reflects the new topology; - temporary emergency access is reviewed; - the team again has a usable recovery path. A service that is online but has no current backup, replica, or recovery coverage may still be in an incident state. ## Communication should state facts, decisions, and uncertainty An incident update should include: - current customer impact; - confirmed failure mode; - containment already applied; - current data-integrity or recovery risk; - next decision and owner; - what will prove recovery; - time or trigger for the next update. Avoid promising a restoration time before the recovery path has been measured. Communicate what is known, what remains uncertain, and which decision is being tested next. Preserve an incident record: | Field | Evidence | |---|---| | Timeline | Detection, impact, containment, recovery | | Scope | Applications, databases, regions, workflows | | Decisions | Sessions terminated, traffic shed, failover, restore, rollback | | Data risk | RPO exception, missing data, validation findings | | Recovery | Actual RTO, application checks, backup/replica state | | Follow-up | Named owner, due date, verification method | ## Post-incident work should remove a failure mode, not only describe it A useful review asks: - Why did the failure occur? - Why did existing controls not prevent or contain it? - Why did detection take the observed time? - Why did recovery take the observed time? - Which decision in the runbook was unclear? - Which corrective action will be tested, not merely documented? Classify follow-up work into: - monitoring and detection; - application pool and retry behavior; - capacity and storage headroom; - query or schema changes; - replication/failover controls; - backup and restore readiness; - access and credentials; - runbook quality; - ownership and communication. Post-incident review is complete when corrective work has an owner and a verification method. ## Managed databases change the incident responsibility boundary With a managed database, more infrastructure operations can sit inside the provider boundary. That may include parts of provisioning, platform maintenance, backup infrastructure, service telemetry, supported recovery workflows, and availability controls depending on the service. The application team still owns: - customer-impact detection; - query and schema behavior; - connection pools and retries; - application credentials; - migration decisions; - workload-specific RPO/RTO requirements; - recovery-point selection when applicable; - application validation; - traffic-return decisions; - incident communication. For Raff, use the live [Managed Databases](/products/managed-databases), [Managed PostgreSQL](/products/managed-databases/postgresql), [Managed MySQL](/products/managed-databases/mysql), and [Managed Valkey](/products/managed-databases/valkey) pages to verify the current service boundary and available capabilities. :::cta Explore Raff Managed Databases Compare current managed database options when reducing platform-level incident and recovery operations is important to your team. ::: ## Self-hosted databases require a complete incident path With a database on a [Raff VM](/products/raff-vm), the team owns the full response path: - host capacity; - database configuration; - monitoring and alerting; - connection limits; - logs; - storage; - replication; - backup/PITR design; - failover; - restore; - patching; - on-call response. [Raff Data Protection](/products/data-protection) can provide an additional VM-level recovery layer where appropriate, but transactional database recovery should remain distinct when the workload needs engine-aware backups or PITR. The operating-model comparison should therefore include **who can respond safely at 02:00 when connections are exhausted, storage is almost full, or the primary is unavailable**, not only infrastructure price. ## Database incident runbook checklist Before relying on the runbook in production, confirm: 1. Incident severity is based on customer/data impact. 2. An incident commander is named. 3. Database, application, infrastructure, and communications ownership are clear. 4. Consequential actions have approval rules. 5. Administrative database access is preserved during connection exhaustion. 6. Safe demand-reduction steps are documented. 7. Disk cleanup boundaries are explicit. 8. Lock/query containment includes rollback consequences. 9. Failover requires freshness, fencing, reconnect, and RPO checks. 10. Restore/PITR has a separate decision path from failover. 11. Recovery validation includes application and data correctness. 12. Backup/replication protection is re-established before incident closure. 13. Communication templates state impact and uncertainty clearly. 14. Post-incident work has owners and verification criteria. ## Conclusion A database incident runbook gives a small team an ordered way to protect data and restore customer service under pressure. Start with impact and ownership. Preserve evidence, classify the dominant failure mode, and prefer reversible containment before consequential changes. Connection exhaustion, disk pressure, query storms, failover, and historical recovery require different decisions. The incident is not complete when the database process starts. Validate customer workflows, data correctness, backup/PITR coverage, replication, monitoring, and the new topology. Then turn the incident into verified corrective work. Continue with [Database Monitoring for Small Teams](/learn/guides/database-monitoring-small-teams), [Database Reliability for Small Teams](/learn/guides/database-reliability-operations-small-teams), and [Database Restore Testing](/learn/guides/database-restore-testing-rpo-rto-recovery-validation) for the detection, architecture, and recovery layers. :::cta Compare Raff Database Options Choose the operating model based on how much incident response, recovery, and host-level control your team needs to own. ::: ## Sources - [NIST SP 800-61 Rev. 3: Incident Response Recommendations](https://csrc.nist.gov/pubs/sp/800/61/r3/final) - [PostgreSQL: Monitoring Database Activity](https://www.postgresql.org/docs/current/monitoring.html) - [PostgreSQL: High Availability, Load Balancing, and Replication](https://www.postgresql.org/docs/current/high-availability.html) - [PostgreSQL: Log-Shipping Standby Servers and Failover](https://www.postgresql.org/docs/current/warm-standby.html) - [MySQL 8.4: Too Many Connections](https://dev.mysql.com/doc/refman/8.4/en/too-many-connections.html) - [MySQL 8.4: How MySQL Handles a Full Disk](https://dev.mysql.com/doc/refman/8.4/en/full-disk.html) - [MySQL 8.4: Replication Solutions](https://dev.mysql.com/doc/refman/8.4/en/replication-solutions.html) - [Raff Managed Databases](/products/managed-databases) - [Raff Data Protection](/products/data-protection) - Sources and product wording reviewed: 2026-09-16; verify live product pages and console for current service capabilities, limits, and recovery boundaries. --- ### MongoDB Hosting: Self-Hosted vs Managed for Production URL: https://rafftechnologies.com/learn/guides/mongodb-hosting Description: Compare MongoDB hosting and MongoDB database hosting options across managed vs self-hosted deployment, providers, production architecture, backups, security, scaling, and total operating cost. **MongoDB hosting** means running MongoDB on infrastructure you operate yourself or using a managed database service that operates more of the database platform for you. For production teams, the important decision is not simply where MongoDB runs. It is **who owns patching, replica sets, backups, restore tooling, monitoring, failover, capacity changes, and database incidents**. Raff Technologies supports **self-hosted MongoDB on cloud VMs today**. Raff Managed MongoDB is listed on the live Managed Databases page as **rolling out**, so it should not be treated as a deployable production dependency until availability is confirmed in the Raff console. If you need MongoDB on Raff now, the practical path is a [Raff VM](/products/raff-vm) with private networking and a MongoDB architecture your team operates. If reducing database-platform responsibility matters more than host-level control, compare managed MongoDB services and verify whether Raff Managed MongoDB is available for your account when you deploy. :::cta Deploy MongoDB on a Raff VM Use a Raff VM when you need MongoDB today with full operating-system control, private networking, and your own topology and recovery design. ::: ## MongoDB database hosting: quick decision | Decision area | Self-hosted MongoDB | Managed MongoDB | |---|---|---| | Operating-system access | Full control | Usually abstracted | | MongoDB installation | Your team | Provider | | Patching and maintenance | Your team | Mostly provider-operated | | Replica-set deployment | Your team | Service-dependent | | Backups | Your design and tooling | Provider tooling within service scope | | Restore workflow | Your team owns full process | Provider workflow + application validation | | Monitoring | Your stack | Usually included to a defined scope | | Failover operations | Your team designs and tests | Usually provider-operated when HA is enabled | | Custom agents/packages | Flexible | Often restricted | | Schema and indexes | Your team | Your team | | Application credentials | Your team | Your team | | Query performance | Your team | Your team | | Best fit | Teams needing host/topology control | Teams prioritizing lower operations burden | **Choose self-hosted MongoDB** when a documented requirement needs root access, custom packages, specific topology, exact maintenance timing, or deep control over MongoDB configuration. **Choose managed MongoDB** when standard service capabilities fit and the team wants the provider to own more of the database platform. The wrong reason to self-host is that starting one `mongod` process is easy. The right reason is that the control you gain is worth the ongoing operating responsibility. ## What MongoDB hosting actually includes MongoDB hosting is more than compute and storage. A production deployment needs answers for: - where database nodes run; - how application traffic reaches them; - authentication and authorization; - TLS and private networking; - replica-set topology; - backups and retention; - historical or point-in-time recovery requirements; - monitoring and alerting; - version upgrades; - storage growth; - failover behavior; - restore testing; - on-call ownership. Two MongoDB hosting providers can expose the same database engine while giving the customer very different operational responsibilities. That responsibility boundary is what should drive the decision. ## How to compare MongoDB hosting providers For commercial searches such as **MongoDB hosting**, **MongoDB database hosting**, or **MongoDB hosting providers**, compare equivalent production capabilities rather than headline RAM alone. ### Availability model Ask whether the product is: - one database node; - a replica set; - a multi-zone replica set; - a sharded cluster; - or simply a VM on which you build those layers yourself. A single server and a production replica set are not equivalent hosting products. ### Backup and recovery scope Check: - backup frequency; - retention; - whether historical or point-in-time recovery is available; - whether restores create a new deployment or replace the existing one; - whether recovery can be tested safely; - whether backups remain usable when the primary deployment fails; - who validates the application after restore. “Backups included” is not enough to define recoverability. ### Private networking and access control Evaluate: - private endpoints or VPC connectivity; - IP allowlists or firewall controls; - TLS; - scoped database credentials; - authentication logging; - whether normal application-to-database traffic can remain off the broad public internet. ### Version and maintenance policy Check which MongoDB versions are actually deployable and how the provider handles: - minor updates; - major upgrades; - maintenance windows; - rollback limitations; - compatibility testing. Self-hosting gives more control here, but the team also owns testing and rollback planning. ### Observability Production teams usually need visibility into: - connections; - operation latency; - slow queries; - index behavior; - storage growth; - replication lag; - elections and failovers; - CPU and memory pressure; - backup state. Managed hosting can provide more of this within the service. Self-hosted deployments need an explicit monitoring model. See [Database Monitoring for Small Teams](/learn/guides/database-monitoring-small-teams) for the broader monitoring framework. ### Scaling model Understand whether scaling means: - resizing one node; - increasing storage; - adding replica members; - adding read capacity; - introducing sharding; - or migrating to another service tier. Compare the scale path you are likely to use, not the largest cluster shown on a pricing page. ### Total operating cost The real comparison can include: - compute; - storage; - replica members; - backups and retention; - data transfer; - high availability; - monitoring; - support; - engineering maintenance; - incident and on-call work. The infrastructure bill is only one part of MongoDB hosting cost. ## Self-hosted MongoDB fits workloads that need deeper control A cloud VM is a practical MongoDB hosting model when the team needs direct operating-system and database control. Common reasons include: - custom operating-system packages; - exact MongoDB version selection; - exact upgrade timing; - direct access to MongoDB configuration and logs; - custom monitoring or security agents; - specific TLS or authentication integrations; - custom replica-set placement; - backup tooling controlled by the team; - integration with private infrastructure; - requirements outside a managed database catalog. A development environment may run one MongoDB node. A production environment that requires database-level availability normally needs a replica-set design rather than assuming one VM is highly available. A simple self-hosted production pattern can look like: ```text Application -> private network -> MongoDB replica set -> primary -> secondary -> secondary Backup target -> separate recovery location ``` This architecture adds resilience, but it also adds systems your team must patch, monitor, secure, back up, and recover. For installation, use [How to Install MongoDB on Ubuntu 24.04](/learn/tutorials/install-mongodb-ubuntu-24-04). ## Managed MongoDB fits teams that want less database-platform work Managed MongoDB is useful when the application needs MongoDB semantics but operating MongoDB infrastructure does not create product differentiation. Depending on the provider and plan, a managed service may reduce work around: - provisioning nodes; - replica-set operations; - host patching; - routine maintenance; - backup scheduling; - restore tooling; - metrics and alerting; - storage expansion; - failover; - controlled upgrades. The application team still owns: - document structure; - embedding versus references; - indexes; - aggregation pipelines; - transaction boundaries; - credentials; - query behavior; - data-retention decisions; - application behavior during failover; - validation after restore. Managed MongoDB solves an operations problem. It does not make MongoDB the correct data model for an application that is fundamentally relational. If the engine choice is still open, compare [MongoDB vs PostgreSQL](/learn/guides/mongodb-vs-postgresql), [MongoDB vs MySQL](/learn/guides/mongodb-vs-mysql), or [MySQL vs PostgreSQL vs MongoDB](/learn/guides/mysql-vs-postgresql-vs-mongodb). ## Self-hosted MongoDB vs managed MongoDB cost The cheapest server is not necessarily the cheapest production system. A useful self-hosted model is: ```text Self-hosted MongoDB TCO = database infrastructure + storage + backup storage + monitoring + maintenance engineering + incident/on-call work + upgrade and recovery work ``` A managed model is closer to: ```text Managed MongoDB TCO = managed service price + HA / storage / backup charges where applicable + application-side database engineering ``` Self-hosting can be economically attractive when the team already has mature database automation and can spread operational work across many deployments. Managed hosting can be economically attractive when database operations would otherwise consume scarce engineering time or create unacceptable incident risk. Do not compare one inexpensive VM with a managed production replica set. Compare equivalent availability, backup, monitoring, recovery, and support assumptions. ## Production MongoDB needs replica-set planning MongoDB replica sets provide redundancy and election behavior for self-managed deployments. Replication does **not** replace backups. Replication can copy unwanted changes such as: - accidental deletes; - destructive updates; - application bugs; - incorrect data mutations. Replication supports service continuity. Backups provide historical recovery. Production planning should define: - replica-set member count; - member placement; - election behavior; - application retry behavior; - replication-lag monitoring; - how failed members are rebuilt; - how the cluster is validated after failover. If those responsibilities are not something the team can operate confidently, that strengthens the case for a managed service. ## MongoDB backup and restore should start from RPO and RTO Define two targets first: - **RPO** — how much recent data the application can afford to lose. - **RTO** — how long the application can tolerate the database being unavailable or in recovery. Then design: - backup frequency; - retention; - backup location; - restore procedure; - restore testing; - recovery ownership; - application cutover after recovery. A successful backup job is not the same as a successful recovery plan. For self-hosted MongoDB, use a MongoDB-aware or topology-appropriate backup method. For managed MongoDB, verify exactly what the provider's backup and restore scope includes. For a general production recovery framework, use [Database Restore Testing: RPO, RTO, and Recovery Validation](/learn/guides/database-restore-testing-rpo-rto-recovery-validation). ## MongoDB should not depend on broad public exposure For self-hosted MongoDB, prefer private networking or tightly restricted access. A production security baseline includes: - enable access control; - separate administrative and application users; - use least privilege; - restrict port `27017` to trusted paths; - prefer private application-to-database traffic; - use TLS where required by the network path; - rotate credentials; - remove unused users; - monitor authentication failures; - keep the operating system and MongoDB maintained. For a same-VM development setup, binding MongoDB only to localhost may be appropriate. For multi-server production, use private addresses and explicit firewall policy rather than broad public listeners. ## MongoDB sizing starts with the working set There is no universal MongoDB VM size. Size from measured workload signals: | Signal | Why it matters | |---|---| | Active working set | Determines how much frequently accessed data and indexes compete for memory | | Index size | Influences memory and storage pressure | | Document size | Affects storage, network transfer, and read/write behavior | | Read/write ratio | Changes CPU, storage, and replica pressure | | Connection count | Affects concurrency and memory use | | Aggregation complexity | Can increase CPU and temporary working requirements | | Storage growth | Drives capacity and backup planning | | Replication lag | Shows whether secondaries can keep up | | Backup duration | Affects recovery planning | | Replica count | Multiplies infrastructure and storage requirements | Start development workloads small if appropriate, then size production from observed data. Do not solve every MongoDB problem by adding CPU or RAM. Missing indexes, inefficient aggregation pipelines, uncontrolled document growth, poor schema boundaries, and retry loops can remain slow on larger infrastructure. ## Common MongoDB hosting architectures ### Development: single VM ```text Application -> MongoDB on one VM ``` Suitable for development, prototypes, tests, and noncritical internal workloads. It is not a substitute for a high-availability production design. ### Production: separate application and database ```text Internet -> application -> private network -> MongoDB ``` This reduces database exposure and lets application and database resources change independently. ### Production HA: replica set ```text Application -> private network -> MongoDB replica set -> member A -> member B -> member C ``` This improves database-level availability but increases operational responsibility when self-hosted. ### Managed MongoDB ```text Application -> restricted or private database endpoint Managed MongoDB service ``` The provider operates more of the database platform while the application team continues to own data model and query behavior. ## MongoDB hosting on Raff today Raff currently has two relevant paths, but only one should be considered generally available without checking the console. ### Self-hosted MongoDB on Raff VM A [Raff VM](/products/raff-vm) gives the team a full Linux environment and host-level control. For MongoDB, your team owns: - installation; - authentication and authorization; - version and upgrade decisions; - replica-set design; - monitoring; - MongoDB-aware backup and restore design; - restore testing; - capacity planning; - database security configuration; - incident response. A common Raff architecture is: ```text Public traffic -> application VM -> Raff VPC -> MongoDB VM or replica set ``` [Raff VPC](/products/vpc) can keep database traffic on private network paths rather than exposing MongoDB directly to the public application path. [Raff Data Protection](/products/data-protection) can provide an additional VM-level recovery layer where appropriate, but it should not replace MongoDB-aware recovery design when the workload requires transactional or historical database recovery. :::cta Explore Raff VM Review Raff VM options for self-hosted MongoDB when you need a deployable MongoDB path today with full host-level control. ::: ### Raff Managed MongoDB is still rolling out The live [Raff Managed Databases](/products/managed-databases) page currently lists MongoDB as **rolling out**. It also describes planned/current product positioning around replica sets and continuous backup, but the console should remain the source of truth for whether MongoDB can actually be deployed for your account and region. Do not make a production architecture depend on Raff Managed MongoDB until deployment availability is confirmed. The practical decision is: ```text Need MongoDB on Raff now -> self-host on Raff VM Want Raff Managed MongoDB -> check live console availability -> if not deployable, use Raff VM or another suitable managed MongoDB service ``` This wording is deliberate: a product can appear in a public roadmap or rollout state before it is ready for every production account. ## MongoDB hosting checklist before production Before treating a deployment as production-ready, confirm: - [ ] MongoDB is not broadly exposed to the public internet. - [ ] Authentication and least-privilege users are configured. - [ ] Production availability requirements are documented. - [ ] Replica-set topology matches those requirements. - [ ] RPO and RTO are defined. - [ ] Backup storage is appropriate for the failure modes you need to survive. - [ ] A restore has been tested. - [ ] Monitoring covers connections, operation latency, storage, replication, and node health. - [ ] Upgrade responsibility is clear. - [ ] Storage growth is monitored. - [ ] Application retry and failover behavior is tested. - [ ] An engineer or provider clearly owns database incidents. If several of these are difficult for the team to sustain, that is a strong reason to prefer managed MongoDB when a suitable managed service is actually available. ## Conclusion: choose MongoDB hosting from the responsibility boundary MongoDB hosting is not only a server choice. It determines who owns the database lifecycle when the system needs maintenance, scaling, recovery, or incident response. Choose self-hosted MongoDB when host-level control, custom topology, or exact maintenance control is a real requirement and the team can sustain the operating work. Choose managed MongoDB when standard capabilities fit and reducing operational burden is more valuable than unrestricted host control. On Raff, the deployable path today is self-hosted MongoDB on [Raff VM](/products/raff-vm). Raff Managed MongoDB is still marked as rolling out, so confirm availability in the live console before depending on it. For the broader operating-model decision, continue with [Managed vs Self-Hosted Databases](/learn/guides/managed-vs-self-hosted-databases). ## Sources - [MongoDB Production Notes for Self-Managed Deployments](https://www.mongodb.com/docs/manual/administration/production-notes/) - [MongoDB Deploy a Self-Managed Replica Set](https://www.mongodb.com/docs/manual/tutorial/deploy-replica-set/) - [MongoDB Backup Methods for Self-Managed Deployments](https://www.mongodb.com/docs/v8.0/core/backups/) - [MongoDB Security Checklist for Self-Managed Deployments](https://www.mongodb.com/docs/manual/administration/security-checklist/) - [Raff VM](/products/raff-vm) - [Raff VPC](/products/vpc) - [Raff Data Protection](/products/data-protection) - [Raff Managed Databases](/products/managed-databases) - Product status reviewed: 2026-09-16; verify the live product page and Raff console for current MongoDB availability and service capabilities. --- ### MongoDB Atlas vs Self-Hosted MongoDB: Cost, Control & Operations URL: https://rafftechnologies.com/learn/guides/mongodb-atlas-vs-self-hosted Description: Compare MongoDB Atlas vs self-hosted MongoDB across pricing, operations, control, backups, high availability, auto-scaling, security, and total cost. **MongoDB Atlas vs self-hosted MongoDB** is mainly a choice between managed database operations and infrastructure control. Atlas operates more of the database platform for you: provisioning, replica-set infrastructure, monitoring, backups, failover, and supported scaling workflows. Self-hosting gives your team operating-system access, custom topology, direct configuration control, and freedom to choose the surrounding infrastructure—but your team also owns the database lifecycle. Raff Technologies supports the self-hosted side of this decision today through [Raff VM](/products/raff-vm). Raff Managed MongoDB is still listed as rolling out, so this guide does **not** present Raff as a like-for-like managed Atlas replacement. The practical decision is: - choose **Atlas** when reducing database-platform work matters more than host-level control; - choose **self-hosted MongoDB** when root access, custom topology, exact maintenance control, or infrastructure flexibility is a real requirement and your team can sustainably operate MongoDB. :::cta Compare the Self-Hosted Path Review Raff VM when you want to operate MongoDB yourself with full host-level control and private networking. ::: ## MongoDB Atlas vs self-hosted MongoDB at a glance | Responsibility | MongoDB Atlas | Self-hosted MongoDB | |---|---|---| | Infrastructure provisioning | Managed by Atlas | Your team | | MongoDB installation | Managed | Your team | | Replica-set infrastructure | Managed according to deployment type | Your team designs and operates it | | Host patching | Managed | Your team | | Database backups | Atlas capabilities depend on deployment/configuration | Your team selects and operates tooling | | Restore workflow | Atlas tooling + your application validation | Your team owns full workflow | | Monitoring | Atlas telemetry and alerts | Your monitoring stack | | Failover | Managed for supported Atlas architectures | Your team designs, tests, and operates it | | Scaling | Atlas-supported scaling workflows | Your process or automation | | Root / OS access | No | Yes | | Schema and indexes | Your team | Your team | | Query behavior | Your team | Your team | | Application credentials | Your team | Your team | | Recovery validation | Your team | Your team | The engine can be MongoDB in both cases. The difference is **how much of the platform around MongoDB your application team must own**. For the broader operating-model question, see [MongoDB Hosting: Self-Hosted vs Managed](/learn/guides/mongodb-hosting). ## MongoDB Atlas pricing should be compared with equivalent self-hosted architecture MongoDB's official pricing page currently lists three main Atlas deployment options: | Atlas option | Current published starting price | Positioning | |---|---:|---| | Free | $0/hour | Learning and exploration | | Flex | $0.011/hour, with monthly usage up to $30 | Development and testing | | Dedicated | From $0.08/hour; MongoDB lists a $56.94/month starting point | Production workloads | MongoDB currently lists Flex with 5 GB storage and Dedicated starting with 10 GB storage, 2 GB RAM, and 2 vCPUs. Actual Atlas cost varies by deployment size, cloud provider, region, storage, transfer, backups, additional services, and configuration. Those prices should not be compared directly with the price of one VM. A fair comparison is closer to: ```text Atlas total cost = Atlas deployment + storage / backup / transfer / add-ons where applicable + application-side database engineering Self-hosted MongoDB total cost = database VMs + storage + backup infrastructure + monitoring + maintenance engineering + on-call + upgrades + restore testing + incident response ``` A self-hosted environment can have a lower infrastructure bill while still costing more operationally. It can also be the better economic choice when the team already has mature database automation and can spread that operating work across many workloads. The important rule is to compare **equivalent availability and recovery assumptions**. A single self-hosted MongoDB VM is not equivalent to a managed production replica-set architecture with managed failover and backup tooling. ## Atlas reduces platform operations Atlas is designed to transfer more database-platform work to the service. MongoDB's current Atlas architecture guidance describes a default deployment architecture based on replica sets, redundancy, and automatic failover. Atlas distributes replica-set members across availability zones where supported by the selected cloud region and can restore or replace failed members after an election. That removes several operational tasks from the application team: - provisioning replica-set nodes; - replacing failed infrastructure; - orchestrating supported failover behavior; - maintaining the underlying database hosts; - integrating platform telemetry; - operating supported backup infrastructure; - performing supported scaling workflows. The application team still owns the workload itself: - document model; - indexes; - aggregation pipelines; - credentials; - application retry behavior; - schema/data migrations; - business RPO and RTO requirements; - recovery-point decisions; - application validation after recovery. Managed does not mean responsibility-free. It changes the boundary. ## Atlas auto-scaling is operational convenience, not unlimited burst capacity Atlas supports compute and storage auto-scaling for eligible deployments. MongoDB documents both reactive and predictive cluster-tier scaling for supported dedicated clusters. Storage auto-scaling can increase storage capacity as disk usage grows. This can reduce manual capacity work, but it should not be treated as a substitute for capacity planning. MongoDB's own documentation notes that sudden high-speed workload bursts may arrive faster than infrastructure can be scaled. The useful comparison is therefore: | Capacity task | Atlas | Self-hosted | |---|---|---| | Detect sustained resource pressure | Platform telemetry available | Your monitoring | | Resize compute | Supported scaling workflows | Manual or automated by your team | | Increase storage | Atlas storage scaling options | Your storage/VM process | | Define min/max capacity | Service configuration | Your automation and infrastructure policy | | Handle abrupt spikes | Still requires workload planning | Still requires workload planning | Self-hosting can automate the same broad capacity decisions, but your team owns the automation, testing, and failure handling. ## Self-hosted MongoDB gives deeper infrastructure control Self-hosting becomes attractive when control is a requirement rather than simply a preference. Examples include: - root access; - custom operating-system packages; - exact MongoDB binary and upgrade timing; - direct filesystem and log access; - custom monitoring/security agents; - specific TLS or authentication integrations; - custom replica-set placement; - custom backup tooling; - non-standard network architecture; - infrastructure automation already standardized by the team. The trade-off is that the team owns the consequences of those choices. A production self-hosted topology may look like: ```text Application -> private network -> MongoDB replica set -> node A -> node B -> node C Monitoring Backup / recovery target Documented incident runbook ``` The exact number and placement of nodes should follow availability requirements and failure domains. Three VMs do not automatically mean high availability if they share the same underlying failure boundary or if failover is untested. For implementation, use [How to Install MongoDB on Ubuntu 24.04](/learn/tutorials/install-mongodb-ubuntu-24-04). ## High availability and disaster recovery are different A major mistake in Atlas vs self-hosted comparisons is treating replica failover and backups as the same protection. They solve different problems: - **High availability** keeps service operating through infrastructure/node failures. - **Historical recovery** helps recover from unwanted data changes such as accidental deletion or corruption. MongoDB's Atlas architecture documentation explicitly separates high availability from disaster recovery. Atlas documents managed backup capabilities including cloud snapshots and continuous cloud backup/PIT recovery options depending on deployment and configuration. The correct backup policy still depends on application RPO and RTO. Self-hosted teams must build the equivalent recovery chain themselves. That means defining: - RPO; - RTO; - backup method; - backup frequency; - retention; - recovery location; - restore workflow; - recovery credentials; - application cutover; - restore validation; - restore-test cadence. For the broader recovery framework, use [Database Restore Testing: RPO, RTO, and Recovery Validation](/learn/guides/database-restore-testing-rpo-rto-recovery-validation). ## Monitoring responsibility changes substantially Atlas includes database telemetry and alerting within the service boundary, while a self-hosted deployment needs a monitoring stack owned by the team. Whichever model you choose, monitor signals that answer operational questions: - can applications obtain connections? - are operations slowing down? - are expensive queries or aggregations increasing? - is storage approaching an unsafe state? - are secondaries keeping up? - did an election or topology change occur? - is backup/recovery coverage current? - does the application still work after failover? A dashboard is not enough. Every important alert should map to an owner and a response action. See [Database Monitoring for Small Teams](/learn/guides/database-monitoring-small-teams) and [Database Incident Runbook](/learn/guides/database-incident-runbook) for those operating layers. ## Security: Atlas abstracts hosts; self-hosting expands your responsibility Atlas removes direct host administration from the customer side, but application and database access still require deliberate configuration. The team still needs to manage: - database users; - least privilege; - network access rules; - private connectivity where required; - application secrets; - TLS expectations; - key rotation; - audit and operational review. With self-hosted MongoDB, the team also owns the operating system and database host: - OS patching; - firewall policy; - exposed services; - package integrity; - SSH/admin access; - host logging; - MongoDB process configuration. That additional control is useful when required, but it increases the security surface your team must maintain. ## When Atlas is usually the cleaner operating model Atlas generally makes sense when most of these statements are true: - standard MongoDB service boundaries fit the workload; - the team does not need root access; - reducing platform/on-call work matters; - managed backups and failover are valuable; - integrated monitoring is preferred; - supported scaling workflows reduce operational burden; - the team wants to focus primarily on application-side database engineering. The trade-off is less host-level freedom and a managed-service cost structure. ## When self-hosting is usually the cleaner operating model Self-hosting generally makes sense when most of these statements are true: - root or OS access is genuinely required; - custom topology or infrastructure placement matters; - exact patch/upgrade timing matters; - custom agents/packages are required; - the team already has database automation and on-call coverage; - the team can test failover and restore procedures; - lower infrastructure cost remains meaningful after operational labor is included. The trade-off is that your team owns the platform around MongoDB. ## Self-hosted MongoDB on Raff Raff is the self-hosted path in this comparison. A [Raff VM](/products/raff-vm) gives your team a Linux environment with host-level control. [Raff VPC](/products/vpc) can be used to keep application-to-database traffic on private network paths, and [Raff Data Protection](/products/data-protection) can provide an additional VM-level recovery layer where appropriate. For MongoDB itself, your team remains responsible for: - installation; - version management; - authentication and authorization; - replica-set design; - monitoring; - database-aware backup and recovery; - restore testing; - capacity planning; - failover procedures; - incident response. Do not treat VM-level protection as a replacement for MongoDB-aware recovery when the workload needs transactional or historical database recovery. Current Raff VM pricing and plan resources should be verified on the live [pricing page](/pricing) rather than hard-coded into an Atlas comparison. The cost comparison changes with VM size, node count, storage, backup architecture, and required availability. :::cta Explore Raff VM Compare current Raff VM resources if self-hosted MongoDB fits your control and operations requirements. ::: ## Is Raff a MongoDB Atlas alternative? For **self-hosted MongoDB infrastructure**, Raff can be an alternative path: you can run MongoDB on Raff VMs and own the full database stack. For a **fully managed MongoDB service**, Raff should not currently be described as a direct Atlas replacement. Raff Managed MongoDB is still marked as rolling out, so deployment availability must be confirmed in the live Raff console. That distinction matters for commercial comparisons: ```text Need managed MongoDB with platform operations included -> evaluate Atlas or another deployable managed MongoDB service Need self-hosted MongoDB with host-level control -> evaluate Raff VM and other infrastructure providers Want Raff Managed MongoDB specifically -> verify current live-console availability first ``` This keeps the buying decision aligned with what is actually deployable. ## MongoDB Atlas vs self-hosted decision checklist Choose the model only after answering: 1. Do we require root or OS access? 2. Do we require custom topology or host agents? 3. Who patches the database hosts? 4. Who operates replica sets and failover? 5. What are our RPO and RTO? 6. Who owns backup retention and restore testing? 7. Who receives database alerts after hours? 8. How will capacity be increased? 9. How will an application reconnect after failover? 10. How much engineering/on-call time belongs in TCO? 11. Are we comparing equivalent production architectures? 12. Can the chosen team/provider prove recovery, not just backup completion? If the self-hosted answers are vague, the lower VM bill may be hiding operational cost and risk. ## Conclusion MongoDB Atlas vs self-hosted MongoDB is not a simple SaaS-price-versus-VM-price comparison. Atlas transfers more provisioning, backup-platform, monitoring, failover, and scaling work to a managed service. Self-hosting gives deeper infrastructure control but makes your team responsible for the full database operating path. Use Atlas when managed operations are worth more than unrestricted host access. Use self-hosting when control is a real requirement and your team can operate MongoDB reliably through upgrades, capacity events, failover, backup recovery, and incidents. On Raff today, MongoDB should be treated as a self-hosted VM workload unless the Raff console confirms Managed MongoDB availability for your account. ## Sources - [MongoDB Atlas Pricing](https://www.mongodb.com/pricing) - [MongoDB Atlas High Availability](https://www.mongodb.com/docs/atlas/architecture/current/high-availability/) - [MongoDB Atlas Auto-Scaling](https://www.mongodb.com/docs/atlas/cluster-autoscaling/) - [MongoDB Atlas Backups](https://www.mongodb.com/docs/atlas/architecture/current/backups/) - [MongoDB Production Notes for Self-Managed Deployments](https://www.mongodb.com/docs/manual/administration/production-notes/) - [Raff VM](/products/raff-vm) - [Raff VPC](/products/vpc) - [Raff Data Protection](/products/data-protection) - [Raff Managed Databases](/products/managed-databases) - Competitor pricing and product details reviewed: 2026-09-16; verify current MongoDB and Raff product pages before purchase or production planning. --- ### MongoDB vs PostgreSQL: Which Database Fits Your App? URL: https://rafftechnologies.com/learn/guides/mongodb-vs-postgresql Description: Compare MongoDB vs PostgreSQL across data modeling, JSON, transactions, performance, scaling, and operations to choose the database that fits your application. **MongoDB vs PostgreSQL** is primarily a data-model decision: MongoDB is built around documents, while PostgreSQL is built around relational tables, constraints, joins, and transactions—with JSONB available when part of the data needs document-like flexibility. For most application teams, the useful question is not which database is universally better. It is **whether the product is naturally organized around bounded documents or around relationships that should be enforced and queried across entities**. Raff Technologies supports both paths today: PostgreSQL is available through [Raff Managed PostgreSQL](/products/managed-databases/postgresql), while MongoDB can be self-hosted on a [Raff VM](/products/raff-vm). Raff Managed MongoDB is still in rollout, so MongoDB should currently be treated as a self-hosted Raff workload unless the live console confirms otherwise. :::cta Compare Database Operating Models Choose the data model first, then compare managed PostgreSQL with self-hosted database infrastructure on Raff. ::: ## MongoDB vs PostgreSQL: quick decision | Workload signal | MongoDB | PostgreSQL | |---|---|---| | Data is naturally one bounded document | Strong fit | Possible with JSONB | | Core data has many relationships | Possible with references | Strong fit | | Foreign-key enforcement matters | No relational foreign-key model | Strong fit | | Multi-entity transactions are common | Supported, but may indicate relational shape | Natural fit | | Fields vary significantly by record | Strong fit | Strong when variation is bounded in JSONB | | Reporting needs joins across entities | Possible, but model-dependent | Strong fit | | Application usually reads a whole aggregate | Strong fit | Possible | | Permissions, billing, ownership, audit are tightly related | Possible with careful modeling | Strong fit | | Native document tooling is central | Strong fit | Not the primary model | | PostgreSQL extensions are important | No | Strong fit | Choose **MongoDB** when documents are the real unit of business data and most reads and writes stay within that boundary. Choose **PostgreSQL** when relationships, constraints, reporting, joins, and multi-entity transactions are central to the product. Choose **PostgreSQL with JSONB** when the application is fundamentally relational but selected fields need flexible metadata. This page owns the **MongoDB vs PostgreSQL / Postgres decision**. For hosting after you choose MongoDB, use [MongoDB Hosting: Self-Hosted vs Managed](/learn/guides/mongodb-hosting). For the managed-vs-self-hosted infrastructure decision, use [Managed vs Self-Hosted Databases](/learn/guides/managed-vs-self-hosted-databases). ## MongoDB and PostgreSQL solve different modeling problems MongoDB stores BSON documents inside collections. Documents can contain nested objects and arrays, so related information can live together when the application normally reads and writes it as one aggregate. PostgreSQL stores data in relational tables and provides constraints, joins, transactions, indexes, and SQL. It also supports `json` and `jsonb`, which lets a relational application keep selected flexible fields without moving the entire data model to a document database. The main architectural difference is therefore not simply SQL versus NoSQL. It is the default data boundary: ```text MongoDB -> document is often the primary aggregate PostgreSQL -> relationships between rows and tables are first-class ``` MongoDB can model relationships, and PostgreSQL can store document-like JSON. The decision is about which model makes the dominant application behavior simpler and safer. ## Start with the unit of data, not the feature list Before comparing performance or scaling, describe the application's dominant business objects. Ask: 1. What does one normal read return? 2. What does one normal write change? 3. Which entities must remain consistent together? 4. Which relationships must the database enforce? 5. How often do reports cross entity boundaries? 6. Which fields are stable and which genuinely vary? 7. How will the model change as the product grows? If a business object is naturally self-contained and normally loaded as one unit, MongoDB can map cleanly to that shape. If a business operation routinely crosses users, organizations, permissions, subscriptions, payments, invoices, orders, or other related entities, PostgreSQL usually maps more directly to the product's integrity model. ## MongoDB fits bounded document aggregates MongoDB is strongest when information that belongs together is commonly stored and retrieved together. Examples can include: - content blocks with type-specific fields; - catalogs with variable attributes; - configurable forms and workflows; - configuration documents; - imported records that preserve source shape; - profiles with optional nested sections; - applications already designed around MongoDB-native document patterns. Embedding can reduce extra reads because related data lives in the same document. MongoDB also supports multi-document transactions. That means it is not limited to single-document atomicity. But transaction support does not erase the importance of document modeling: if ordinary product behavior constantly requires coordinating many independently changing documents, the application may be pushing against the document boundary. Flexible structure also needs governance. Production teams still need: - validation rules where appropriate; - index planning; - limits on document growth; - ownership rules for duplicated data; - clear embedding-versus-reference decisions; - retention and deletion behavior; - backup and recovery procedures. Schema flexibility should come from a real product need, not from avoiding data-model decisions. ## PostgreSQL fits relational and hybrid workloads PostgreSQL is usually the stronger fit when business rules depend on relationships that should remain valid even when application code fails. Common examples include: - organizations, users, memberships, and roles; - subscriptions, invoices, payments, and credits; - orders and inventory commitments; - projects and permissions; - marketplaces with buyers, sellers, products, and transactions; - reporting across several related entities; - audit and compliance-oriented records. Foreign keys, unique constraints, check constraints, and transactions let the database enforce part of the product's integrity model. PostgreSQL also covers many hybrid workloads through JSONB. A practical pattern can look like: ```text id organization_id name status created_at metadata_jsonb ``` Stable fields that drive ownership, permissions, uniqueness, filtering, billing, or reporting remain explicit columns. Flexible metadata can live in JSONB. This is often simpler than introducing MongoDB when only a small part of the record is variable. ## MongoDB vs PostgreSQL for JSON data JSON support is one of the areas where the engines can appear similar while encouraging different architectures. MongoDB is document-native. The document is the primary storage and query model. PostgreSQL JSONB is a flexible data type inside a relational database. Use MongoDB when: - document shape is central to the product; - nested data is normally read together; - flexible fields are a first-class part of most records; - MongoDB-specific document and aggregation behavior fits the application. Use PostgreSQL JSONB when: - the relational model remains primary; - only selected attributes vary; - joins and constraints still matter; - reporting crosses related entities; - one relational operating model is preferable. Do not put an entire relational domain into JSONB simply to avoid designing tables, and do not move to MongoDB solely because one metadata field is flexible. ## Transactions: both support them, but the default modeling assumptions differ PostgreSQL transactions are central to its relational model. Multiple related rows and tables can participate in one transaction while constraints protect relational integrity. MongoDB supports transactions across multiple documents and collections, including supported distributed topologies. The distinction is architectural: - MongoDB works best when many operations remain within a well-designed document boundary. - PostgreSQL is naturally suited to transactions spanning related entities. If your routine business operation looks like this: ```text create order -> reserve inventory -> create payment record -> update account balance -> write audit event ``` then the relational model deserves serious consideration because the product itself is relationship-heavy. If an operation normally changes one aggregate document and its nested fields, MongoDB may map more naturally. ## MongoDB vs PostgreSQL performance depends on the workload There is no useful universal answer to “Is MongoDB faster than PostgreSQL?” DataForSEO shows **`mongodb vs postgresql performance`** as a separate commercial-intent query, but a generic benchmark would be misleading because performance depends on schema design, query shape, indexes, transactions, concurrency, memory, storage, and topology. Use representative workload evidence instead. | Signal | What to inspect | |---|---| | Read shape | Whole-document retrieval vs joins and filtered projections | | Write shape | One aggregate vs several related entities | | Latency | p50, p95, and p99 of representative operations | | Index behavior | Useful indexes, scans, index size, and write amplification | | Concurrency | Locks, waits, active transactions, retries | | Working set | Memory needed by active data and indexes | | Storage | Latency, throughput, data growth, maintenance | | Replication | Lag and recovery behavior | | Recovery | Backup and restore duration | | Growth | Vertical scaling, replicas, partitioning, or sharding requirements | If performance is the reason for a migration, test production-like data and queries before changing engines. Moving an inefficient model to a different database often moves the problem rather than solving it. ## Scaling is not a one-line MongoDB-versus-Postgres comparison MongoDB includes native sharding for distributing data across shards. That is useful when the workload has a genuine horizontal partitioning requirement and the team can choose and operate an appropriate shard key strategy. PostgreSQL can scale vertically, use read replicas, partition tables, and separate workload paths. Distributed PostgreSQL architectures also exist, but they add their own system design and should not be treated as identical to MongoDB sharding. Before choosing an engine because of “scale,” define what actually needs to scale: - write throughput; - read throughput; - storage capacity; - geographic distribution; - analytics/reporting; - tenant count; - connection count; - availability requirements. The better engine is the one whose scaling path fits the workload you actually expect to operate. ## Operational ownership can outweigh engine features Database selection changes more than application queries. It changes tooling, skills, runbooks, backup methods, monitoring, migrations, failover behavior, and on-call responsibility. Before switching MongoDB to PostgreSQL or PostgreSQL to MongoDB, inventory: - drivers and ORM behavior; - schema or document validation; - indexes; - transactions; - aggregation pipelines or SQL; - extensions or stored logic; - authentication and roles; - backup and restore procedures; - replica or sharding topology; - export/import duration; - application cutover; - rollback requirements. A stable MongoDB application with a clean document model may be safer to keep on MongoDB. A stable PostgreSQL application with a clear relational model may be safer to keep on PostgreSQL. Migration should solve a documented product, scale, reliability, or operations requirement that is worth the migration risk. ## Hosting comes after the engine decision Do not choose PostgreSQL only because one managed service is available, or MongoDB only because one infrastructure option is cheaper. First choose the data model. Then choose how to operate it. ### If PostgreSQL fits Raff provides a live [Managed PostgreSQL](/products/managed-databases/postgresql) path for teams that want less database-platform work. Teams that require deeper host-level control can also self-host PostgreSQL on [Raff VM](/products/raff-vm). ### If MongoDB fits MongoDB can be self-hosted on [Raff VM](/products/raff-vm) today. Your team then owns MongoDB installation, version management, security, replica-set design, monitoring, database-aware backup and recovery, restore testing, capacity planning, and incident response. Raff Managed MongoDB is still listed as rolling out. Do not treat it as a generally deployable managed service until the live console confirms availability. For that operating-model decision, continue with [MongoDB Atlas vs Self-Hosted MongoDB](/learn/guides/mongodb-atlas-vs-self-hosted) and [MongoDB Hosting](/learn/guides/mongodb-hosting). :::cta Explore Raff Database Options Use Managed PostgreSQL when PostgreSQL fits your data model, or Raff VM when you need full control over a self-hosted database stack. ::: ## Decision checklist for a new application Before choosing MongoDB or PostgreSQL, answer: - [ ] What is the natural business aggregate? - [ ] Which relationships must stay valid? - [ ] Are joins a routine product requirement? - [ ] Are flexible fields central or only supplemental? - [ ] Do several entities need to change atomically? - [ ] Is JSONB enough for the flexible part of the model? - [ ] Does the application need MongoDB-native document behavior? - [ ] What does the reporting model look like? - [ ] How will the workload scale? - [ ] Who owns database operations? - [ ] What are the backup and recovery requirements? - [ ] Is a migration from an existing engine actually justified? If you cannot answer these questions yet, benchmark and prototype the data model before making infrastructure decisions. ## Conclusion: choose from the data boundary MongoDB vs PostgreSQL is fundamentally a modeling decision. Choose MongoDB when bounded documents are the natural read/write unit and document-oriented behavior is central to the product. Choose PostgreSQL when relationships, constraints, joins, reporting, and multi-entity transactions define the application. For many SaaS products, PostgreSQL with JSONB covers a relational core plus bounded flexible metadata without adding another database engine. MongoDB remains a strong fit when the document model is genuinely central rather than incidental. On Raff, Managed PostgreSQL is a live managed path, while MongoDB can be self-hosted on Raff VM and Managed MongoDB remains in rollout. Choose the engine first; then choose the operating model that is actually deployable and supportable. ## Sources - [MongoDB Data Modeling](https://www.mongodb.com/docs/manual/data-modeling/) - [MongoDB Transactions](https://www.mongodb.com/docs/manual/core/transactions/) - [MongoDB Sharding](https://www.mongodb.com/docs/manual/sharding/) - [PostgreSQL JSON Types](https://www.postgresql.org/docs/current/datatype-json.html) - [PostgreSQL JSON Functions and Operators](https://www.postgresql.org/docs/current/functions-json.html) - [PostgreSQL Constraints](https://www.postgresql.org/docs/current/ddl-constraints.html) - [Raff Managed PostgreSQL](/products/managed-databases/postgresql) - [Raff Managed Databases](/products/managed-databases) - [Raff VM](/products/raff-vm) - Product status reviewed: 2026-09-17; verify live Raff product pages and console for current availability and service capabilities. --- ### SQL vs NoSQL for SaaS Apps: Relational, Document, and Key-Value Trade-Offs URL: https://rafftechnologies.com/learn/guides/sql-vs-nosql-for-saas-apps Description: Compare SQL vs NoSQL across relational, document, and key-value models, including data modeling, performance, scaling, SaaS use cases, and operations. **SQL vs NoSQL** is not a simple old-versus-new database choice. It is a decision about how your application should represent relationships, enforce integrity, handle flexible records, serve its dominant access patterns, and recover after failure. For many SaaS products, a relational database is the lowest-friction starting point for core business records such as accounts, permissions, subscriptions, invoices, orders, and ownership. A document database becomes attractive when one bounded document is the natural read/write unit. A key-value database fits fast supporting state such as caches, sessions, rate limits, idempotency keys, and queue coordination. Raff Technologies supports these different operating models through managed relational and key-value databases, plus self-hosted database workloads on [Raff VM](/products/raff-vm). MongoDB is still marked as rolling out in Raff's managed database catalog, so production teams should confirm live-console availability before depending on it as a managed service. :::cta Explore Raff Database Options Choose the data model first, then compare the managed or self-hosted path that matches your workload. ::: ## SQL vs NoSQL: quick decision | Workload signal | Relational / SQL | Document | Key-value | |---|---|---|---| | Many related business entities | Strong fit | Possible, but relationship-heavy modeling can become complex | Poor fit | | Foreign keys and constraints matter | Strong fit | Application-managed | Not the primary model | | One bounded object is usually read/written together | Possible | Strong fit | Possible only for simple keyed values | | Flexible nested fields dominate | Possible with JSON columns | Strong fit | Value-format dependent | | SQL reporting and joins matter | Strong fit | Possible, but model-dependent | Poor fit | | Exact-key lookups dominate | Possible | Possible | Strong fit | | Cache/session/rate-limit state | Usually not the first choice | Usually not the first choice | Strong fit | | Multi-entity transactions are common | Natural fit | Supported by some document databases, but may indicate a relational domain | Usually not the right model | Use **SQL / relational** when relationships, constraints, reporting, and cross-entity transactions define the product. Use a **document database** when the document itself is the natural aggregate and most reads and writes stay inside that boundary. Use a **key-value database** when the application already knows the key and needs fast supporting state with clear expiry, persistence, and recovery rules. This page owns the broad **SQL vs NoSQL / relational vs document vs key-value** decision. For engine selection after that, use [MySQL vs PostgreSQL vs MongoDB](/learn/guides/mysql-vs-postgresql-vs-mongodb). ## SQL and NoSQL describe different data models A relational database organizes data into tables, rows, and typed columns. Relationships can be represented and enforced through primary keys, foreign keys, unique constraints, check constraints, and transactions. NoSQL is an umbrella term rather than one database architecture. It includes document, key-value, graph, wide-column, and other models. That distinction matters because “SQL vs NoSQL” can hide several different decisions: ```text relational vs document relational vs key-value one durable source of truth vs several specialized stores managed vs self-hosted operations ``` The useful question is not which category is generally faster or more scalable. It is which model makes the application's normal reads, writes, integrity rules, and recovery path easiest to operate correctly. ## Relational databases fit relationship-heavy SaaS cores A typical SaaS product often contains tightly related business records such as: - users and organizations; - memberships and roles; - permissions and entitlements; - subscriptions and plans; - invoices, payments, and credits; - orders and line items; - projects and ownership; - account and billing state; - audit references. These relationships are often part of the product's correctness rules. For example: ```text organization -> users -> memberships -> subscriptions -> invoices -> payments ``` When a membership must point to a real organization, an invoice must belong to the correct account, or several financial records must change together, relational constraints and transactions can reduce the amount of integrity logic that application code must enforce alone. A relational database is usually a strong starting point when the workload needs: - multi-entity transactions; - foreign-key relationships; - joins across several business entities; - uniqueness and integrity constraints; - reporting and exports; - several access paths over the same data; - predictable migrations; - mature SQL tooling. That does not mean every field needs a dedicated relational column. PostgreSQL JSONB and MySQL JSON can hold bounded flexible metadata while important identity, ownership, billing, and permission fields stay explicit. ## Document databases fit bounded aggregates A document database stores related fields together in a document, often with nested objects and arrays. This model works well when one document is a natural product boundary and the application usually reads or changes that aggregate as one unit. Common document-oriented candidates include: - content blocks with type-specific fields; - catalogs with variable attributes; - user-created forms; - workflow definitions; - configuration records; - imported third-party payloads; - profiles with optional nested sections; - event documents with variable properties. A document model is especially useful when: - nested data belongs together; - most reads return the full aggregate; - fields vary substantially between record types; - cross-record relationships are limited; - duplication is deliberate and maintainable; - document growth has a known boundary. Reconsider the model when ordinary application behavior repeatedly requires: - many-to-many relationships; - frequent cross-document joins or references; - distributed transactions as a routine path; - duplicated fields that must be synchronized everywhere; - relationship-heavy permissions or billing logic; - reporting that reconstructs a relational model outside the database. Flexible schema does not mean schema-free. Production document systems still need validation, index ownership, embedding-versus-reference rules, retention, backups, and recovery testing. ## Key-value databases fit fast supporting state A key-value database retrieves a value through a known key. That makes it a strong fit when the lookup path is simple and the application does not need relational queries across the stored data. Common uses include: - caches; - sessions; - rate-limit counters; - idempotency keys; - short-lived authentication state; - distributed coordination; - queues and streams; - worker state; - counters and leaderboards; - temporary computed values. The key production question is whether the value can be rebuilt. For a normal cache, it usually should be. The durable database remains the source of truth, while the cache stores a faster copy with a defined TTL and invalidation policy. For sessions, queues, locks, and other operational state, loss may still affect users even if permanent business records survive. Those roles need explicit persistence, retry, expiry, and failure rules. Do not casually make a key-value store the only copy of critical records such as: - invoices or payments; - subscriptions and entitlements; - orders; - customer-created content; - audit records; - durable file metadata; - jobs whose loss would create customer data loss. Key-value databases can be durable, but durable use requires a recovery design proportional to the importance of the data. ## Relational vs document database: choose from the data boundary The most useful SQL-vs-NoSQL comparison starts with the authoritative unit of data. | Decision question | Relational signal | Document signal | |---|---|---| | What is the natural unit? | Several related entities | One bounded aggregate | | Which relationships must be enforced? | Foreign keys, uniqueness, many-to-many rules | Mostly contains/embedded relationships | | What must change atomically? | Several rows or tables | Usually one document | | How is data read? | Filters, joins, reports, several access paths | Whole aggregate or nested sections | | How does shape vary? | Stable fields with controlled flexible metadata | Record shape varies significantly | | How is integrity protected? | Database constraints + application logic | Application/document validation + modeling rules | An invoice, for example, is not just a JSON payload. It belongs to an account, contains line items, may reference payments and credits, and affects financial reporting. That is a strong relational signal. A page-builder component with nested content, variable settings, and one clear owner may be a document signal. The data boundary should drive the model—not whether one engine is marketed as more modern or more scalable. ## SQL vs NoSQL performance depends on workload design There is no universal performance winner. Performance depends on: - data model; - indexes; - query shape; - join or aggregation complexity; - transaction scope; - working-set size; - memory; - storage latency; - concurrency; - network path; - connection behavior; - replication and topology; - exact engine version and configuration. A document database may be efficient when the application retrieves one complete aggregate from one indexed document. A relational database may be efficient when the workload requires indexed joins, filters, constraints, and reports across several entities. A key-value system may be efficient when the application already has the exact key and needs one small value or atomic counter operation. A model mismatch often matters more than the database brand. If performance is the reason for considering a migration, benchmark representative production-like data and queries before changing models. ## SQL vs NoSQL scaling is about the bottleneck, not the label The statement “NoSQL scales and SQL does not” is too broad to guide a production architecture. Relational databases can scale through stronger nodes, read replicas, connection pooling, partitioning, workload separation, and distributed architectures where justified. Document databases can use replication and sharding, but sharding introduces its own shard-key, routing, balancing, transaction, and operational decisions. Key-value systems can partition keys, but memory pressure, hot keys, persistence, and failover still need planning. Before changing database models for “scale,” define the actual constraint: - write throughput; - read throughput; - query latency; - storage growth; - connection saturation; - tenant count; - hot tenants or keys; - geographic distribution; - analytics/reporting pressure; - backup and restore time; - operations capacity. Choose the model that makes the dominant workload natural, then scale from measurements. ## SaaS workload examples | SaaS workload | Strong starting model | Why | |---|---|---| | Accounts, teams, roles, permissions | Relational | Relationships and integrity define access | | Billing, subscriptions, invoices | Relational | Transactions, reporting, and auditability matter | | Orders and inventory commitments | Relational | Cross-entity consistency matters | | Page-builder or form definitions | Document or relational JSON | Self-contained and structurally variable | | Product attributes that vary by category | Document or relational JSON | Flexible attributes may be bounded | | External webhook payload archive | Document or object storage + index | Payload shape varies and original data may need preservation | | Account-summary cache | Key-value | Rebuildable from the durable database | | Sessions and rate limits | Key-value | Exact-key access and expiry are central | | Background-job coordination | Key-value / stream | Fast worker coordination and retry state | | Completed customer-visible job state | Relational | Durable product state should survive queue loss | These are starting points, not absolute rules. Existing architecture, team expertise, integrations, recovery requirements, and operating maturity can change the right answer. ## JSON support can delay an unnecessary second database Teams sometimes add a document database because a small subset of fields is flexible. That may be unnecessary. Relational databases can keep stable business fields explicit while storing bounded flexible metadata in a JSON column. A hybrid record might look like: ```text id organization_id name status created_at metadata_json ``` This approach works well when: - the record has a clear relational identity; - only part of the schema varies; - joins and reporting still matter; - one backup and recovery system is preferable; - flexible fields have documented ownership and indexes. Do not put critical billing, authorization, ownership, uniqueness, or frequently queried fields inside opaque JSON simply to avoid relational design. Move to a dedicated document database when the document model itself is the dominant access pattern. ## Polyglot persistence needs one source of truth per fact Using SQL and NoSQL together can be useful. It also creates synchronization and recovery work. Before adding another store, define: 1. **Source of truth** — which system owns each fact? 2. **Derived copies** — which data can be rebuilt? 3. **Synchronization** — how do changes propagate? 4. **Consistency window** — how stale may a secondary copy become? 5. **Failure behavior** — what happens when one store is unavailable? 6. **Recovery order** — how are stores restored to a compatible point? 7. **Deletion behavior** — how do retention/privacy changes propagate? 8. **Ownership** — who monitors, backs up, and restores each store? 9. **Migration path** — how can the data leave later? The largest risk is dual ownership: two systems should not both appear authoritative for the same fact unless a conflict rule is explicit. Prefer rebuildable secondary stores where possible. A cache can be repopulated. A search index can be reconstructed. An analytics projection may be replayed. Durable business state is harder to reconcile after conflicting writes. ## Managed vs self-hosted is a separate decision After choosing the database model, decide who should operate it. A managed database can reduce host-level work such as provisioning, patching, backup infrastructure, monitoring, and availability operations. The application team still owns schema design, queries, indexes, credentials, migrations, capacity decisions, retention, and application validation after recovery. A self-hosted database gives deeper host and topology control but leaves the operating model with your team. Raff currently provides managed [PostgreSQL](/products/managed-databases/postgresql), [MySQL](/products/managed-databases/mysql), and [Valkey](/products/managed-databases/valkey). Raff's managed database catalog still marks MongoDB as **rolling out**, so confirm current live-console availability before designing a production dependency around managed MongoDB. Teams that need host-level control can run supported database workloads on [Raff VM](/products/raff-vm). For the operating-model decision, use [Managed vs Self-Hosted Databases](/learn/guides/managed-vs-self-hosted-databases). :::cta Explore Managed Databases Review the currently deployable relational and key-value database options on Raff, then match the service to your application's data model. ::: ## SQL vs NoSQL decision checklist Before approving the architecture, confirm: - [ ] The authoritative unit of data is defined. - [ ] Core relationships and uniqueness rules are known. - [ ] The required atomic write boundary is documented. - [ ] Normal read/write patterns are understood. - [ ] Flexible fields are separated from stable business fields. - [ ] Document embedding/reference choices match access patterns. - [ ] Key-value data has TTL, eviction, and persistence rules where relevant. - [ ] Every secondary store has a named source of truth. - [ ] Backup and restore testing cover every durable store. - [ ] Multi-store recovery order is documented. - [ ] Export and migration paths are understood. - [ ] The team can operate the selected model. - [ ] A second database solves a measured problem. ## Conclusion SQL vs NoSQL is a choice about data boundaries, integrity, access patterns, and recovery—not a universal performance ranking. Use a relational database when relationships, constraints, joins, reporting, and cross-entity transactions are central. Use a document database when bounded documents are the natural unit of data. Use a key-value database for fast keyed state with explicit expiry, persistence, and recovery rules. Use multiple models only when each store has a clearly defined responsibility and each important fact has one authoritative owner. On Raff, managed PostgreSQL, MySQL, and Valkey provide deployable managed paths today, while MongoDB remains in rollout. Choose the data model first, then choose the operating model that is currently available and supportable. ## Sources - [PostgreSQL Constraints](https://www.postgresql.org/docs/current/ddl-constraints.html) - [PostgreSQL Transactions](https://www.postgresql.org/docs/current/tutorial-transactions.html) - [PostgreSQL JSON Types](https://www.postgresql.org/docs/current/datatype-json.html) - [MongoDB Data Modeling](https://www.mongodb.com/docs/manual/data-modeling/) - [MongoDB Transactions](https://www.mongodb.com/docs/manual/core/transactions/) - [Valkey Introduction](https://valkey.io/topics/introduction/) - [Valkey Persistence](https://valkey.io/topics/persistence/) - [Raff Managed Databases](/products/managed-databases) - [Raff Managed PostgreSQL](/products/managed-databases/postgresql) - [Raff Managed MySQL](/products/managed-databases/mysql) - [Raff Managed Valkey](/products/managed-databases/valkey) - [Raff VM](/products/raff-vm) - Product status reviewed: 2026-09-17; verify the live Raff product page and console for current availability and service capabilities. --- ### MySQL vs MariaDB for Production Apps: Hosting and Operations URL: https://rafftechnologies.com/learn/guides/mysql-vs-mariadb-production-apps Description: Compare MySQL vs MariaDB for production apps across compatibility, performance, migration risk, backups, and managed or self-hosted operations. **MySQL vs MariaDB** is no longer a choice between two interchangeable versions of the same database. They share a common history and many familiar SQL concepts, but modern releases have separate roadmaps, defaults, compatibility boundaries, tooling, and operational behavior. For most production teams, the safest default is straightforward: **keep the engine your application, vendor, drivers, and operators already support unless a documented requirement justifies migration**. Choose MySQL when MySQL compatibility, vendor support, or a managed MySQL service is important. Choose MariaDB when the application explicitly supports MariaDB and your team can operate the selected MariaDB release confidently. Raff Technologies provides a live [Managed MySQL](/products/managed-databases/mysql) path for teams that want to reduce database-host operations. Teams that specifically need MariaDB, root access, custom packages, or deeper host control can self-host on [Raff VM](/products/raff-vm). :::cta Explore Managed MySQL Choose MySQL first when the engine fits your application, then compare Raff Managed MySQL with a self-hosted deployment. ::: ## MySQL vs MariaDB: quick answer | Decision area | MySQL | MariaDB | |---|---|---| | Core model | Relational SQL database | Relational SQL database | | Shared lineage | Original MySQL project | Fork created from MySQL | | Current compatibility | Broad protocol/query compatibility, but not identical to MariaDB | Broad protocol/query compatibility, but not identical to MySQL | | Best fit | Apps, vendors, and tooling explicitly aligned with MySQL | Apps and teams explicitly aligned with MariaDB | | Managed path on Raff | Yes — Managed MySQL | Self-host on Raff VM today | | Host-level control | Self-host when required | Self-host when required | | Migration risk | Version-specific | Version-specific | | Performance | Workload-dependent | Workload-dependent | Choose **MySQL** when: - your application/vendor support matrix names MySQL; - you want a managed MySQL service; - your tooling, drivers, backups, and operational knowledge already center on MySQL; - migration would not solve a concrete production problem. Choose **MariaDB** when: - your application explicitly supports or requires MariaDB; - your team already operates MariaDB reliably; - MariaDB-specific features or ecosystem requirements matter; - you are prepared to own the hosting model available to you. Do not migrate between them because one is described as generally faster, newer, or more open. Test the exact source and target versions against the real application. ## MySQL and MariaDB share a history, not one roadmap MariaDB began as a fork of MySQL, so the two systems still share many concepts: - SQL tables and indexes; - joins and transactions; - familiar client protocols and connection patterns; - users and privileges; - InnoDB-family transactional storage in common deployments; - logical dumps and replication concepts; - widespread support across PHP and web frameworks. That shared lineage can create a false sense that the engines remain drop-in replacements across modern releases. Production differences can appear in areas such as: - authentication defaults and plugins; - JSON implementation and functions; - optimizer behavior; - replication and GTID behavior; - system variables and defaults; - SQL modes and reserved words; - collations and character sets; - plugins and storage engines; - backup tooling; - release cadence and upgrade paths. A driver successfully opening a connection to both engines proves very little about migration safety. Treat **engine + major version + application version** as one compatibility target. ## MariaDB vs MySQL compatibility should be tested, not assumed Compatibility is the most important part of this comparison for an existing production app. Before approving a switch, inventory: - application/vendor-supported database engines; - ORM and driver versions; - authentication method; - SQL modes; - stored procedures and triggers; - generated columns; - JSON columns and functions; - full-text/search behavior if used; - collations and character sets; - replication requirements; - backup and restore tools; - monitoring integrations; - migration tooling; - rollback constraints. A common mistake is testing only basic CRUD operations. A useful compatibility test also exercises: ```text schema migrations background jobs reports imports/exports authentication scheduled tasks large queries transaction-heavy workflows backup + restore failover/reconnect behavior ``` If your application comes from a third-party vendor, its support matrix should carry more weight than generic claims that MariaDB and MySQL are compatible. ## JSON is one area where the engines should not be treated as identical Both MySQL and MariaDB can work with JSON-shaped data, but teams should not assume identical storage semantics, functions, indexing behavior, or edge cases across versions. If an application relies heavily on JSON columns or engine-specific JSON functions, test those paths explicitly before migration. The broader architecture question is also worth asking: if most important fields are relational and only bounded metadata is flexible, keeping those core fields relational may be simpler than redesigning the application around another database model. For a broader relational-versus-document decision, see [SQL vs NoSQL for SaaS Apps](/learn/guides/sql-vs-nosql-for-saas-apps). ## MySQL vs MariaDB performance has no universal winner `mysql vs mariadb performance` is a useful search query but a poor architecture shortcut. Performance depends on: - schema design; - indexes; - query plans; - working-set size; - memory; - storage latency; - concurrency; - connection pools; - transaction length; - lock contention; - engine version; - configuration; - replication topology; - the actual workload being measured. One engine may perform better on one query pattern and worse on another. Before migrating for performance, measure the current bottleneck: | Signal | What to investigate first | |---|---| | Slow reads | Query plan, indexes, scans, working set | | Slow writes | Locks, transaction size, storage latency | | High DB CPU | Expensive queries, scans, concurrency | | Connection errors | Pool sizing, leaks, connection limits | | High latency under load | Contention, storage, memory, query mix | | Replica lag | Write volume, long transactions, replica capacity | | Slow reporting | Query design, indexes, workload separation | Changing engines is one of the more expensive ways to solve a database performance problem. Optimize and benchmark with representative data before deciding that the engine itself is the constraint. ## Connection planning matters more than many teams expect Production database capacity is not only CPU and RAM. Estimate connection demand across the whole application: ```text web/application instances x pool size + workers + scheduled jobs + migrations + monitoring + admin reserve = expected connection demand ``` A database can have spare CPU and still fail because application pools collectively request too many connections. When scaling the app tier, connection demand can rise much faster than database traffic if every new application instance opens a large pool. Before simply increasing database connection limits, check whether pools are oversized, connections are held unnecessarily, or worker autoscaling is unbounded. ## MySQL and MariaDB migrations are data-model and operations projects Switching between MySQL and MariaDB is not just changing a package name. A production migration should include: 1. **Inventory** — schemas, users, routines, triggers, plugins, drivers, and dependencies. 2. **Compatibility review** — identify source/target differences for the exact versions. 3. **Recovery proof** — create a usable backup and restore it before migration day. 4. **Rehearsal** — migrate production-like data in a non-production environment. 5. **Application validation** — test reads, writes, reports, jobs, and migrations. 6. **Performance comparison** — benchmark important queries and workflows. 7. **Cutover design** — define the write freeze or supported synchronization method. 8. **Validation** — compare row counts, checksums or domain-specific invariants where practical. 9. **Rollback conditions** — decide what failure triggers rollback before the cutover begins. 10. **Post-cutover monitoring** — watch errors, latency, locks, connections, and data consistency. Do not assume that copying a database data directory between engines is a safe migration method. Use engine-supported logical or physical migration methods appropriate for the exact versions involved. ## Managed MySQL vs self-hosted MySQL or MariaDB After choosing the engine, choose who owns the operations. | Responsibility | Managed MySQL | Self-hosted MySQL / MariaDB | |---|---|---| | Host provisioning | Provider | Your team | | OS maintenance | Provider | Your team | | Database package maintenance | Managed service policy | Your team | | Backup platform | Managed-service responsibility | Your team | | Monitoring platform | Service-provided scope | Your team | | Host/root access | Restricted | Available | | Custom packages/modules | Limited by service | Your team decides | | Schema and queries | Your team | Your team | | Application migrations | Your team | Your team | | Recovery validation | Shared responsibility | Your team | Choose **managed MySQL** when the service supports your workload and reducing host-level operations is more valuable than direct server control. Choose **self-hosted MySQL** when you need exact package/configuration control, root access, custom topology, or capabilities outside the managed-service boundary. Choose **self-hosted MariaDB** when MariaDB is the required engine and your team can own patching, backups, restores, monitoring, security, storage, and incidents. For the full responsibility model, use [Managed vs Self-Hosted Databases](/learn/guides/managed-vs-self-hosted-databases). ## Backups, replication, and high availability solve different failures Do not treat replicas as backups. A bad delete, bad update, or destructive application migration can be replicated to another node just as successfully as a valid write. | Control | Main purpose | |---|---| | Backup | Recover historical data/state | | Transaction/binlog history | Enable eligible point-in-time recovery and replication workflows | | Replica | Availability and/or read scaling | | High availability | Reduce downtime for selected infrastructure failures | | Restore test | Prove recovery actually works | A production database should have explicit recovery objectives: - **RPO** — how much data can you lose? - **RTO** — how long can recovery take? Then design backups, log retention, replicas, and restore testing around those targets. Use [Database Backup Strategy for SaaS Apps](/learn/guides/database-backup-strategy-saas-apps) and [Database Restore Testing](/learn/guides/database-restore-testing-rpo-rto-recovery-validation) for the broader recovery framework. ## Choose based on application support first Use this decision order instead of starting with benchmark claims. ### 1. What does the application support? If the software vendor or application explicitly supports one engine, that is usually the first constraint. ### 2. Are you already running one engine successfully? Keeping a stable engine avoids migration risk unless a meaningful requirement has changed. ### 3. Do you require a managed service? If reduced operational burden is a requirement, confirm that the needed engine is available as a managed product with the required capabilities. Raff's managed path for this database family is **Managed MySQL**. ### 4. Do you require host-level control? Root access, custom packages, custom topology, or exact maintenance timing can justify self-hosting. ### 5. Is migration solving a real problem? A migration should solve something measurable: compatibility, operations, supportability, feature requirements, recovery, or cost of ownership. If the reason is only “MariaDB/MySQL is faster,” the decision is incomplete. ## Common production scenarios | Scenario | Practical starting point | |---|---| | Existing MySQL SaaS app | Keep MySQL unless requirements changed | | Existing MariaDB app | Keep MariaDB unless requirements changed | | New app with MySQL vendor dependency | MySQL | | Team wants managed operations and MySQL fits | Managed MySQL | | MariaDB explicitly required | MariaDB, with an operating model your team can support | | WordPress/PHP app supporting both | Follow tested stack/plugin/vendor support, then choose operations model | | Root access required | Self-hosted MySQL or MariaDB | | Custom topology/modules required | Self-hosting if managed service cannot support them | | Migration considered only for speed | Benchmark first; do not migrate from generic claims | ## Raff deployment paths Raff provides two relevant infrastructure paths. ### Managed MySQL Use [Raff Managed MySQL](/products/managed-databases/mysql) when MySQL fits the application and the team wants to reduce database-host operations. The application team still owns: - schema design; - queries and indexes; - application credentials; - application migrations; - capacity decisions; - application behavior during failures; - validation after restore or failover. Service capabilities, versions, limits, retention, networking, and availability options can change over time, so verify the current product page and console rather than relying on an old article specification. ### Self-hosted MySQL or MariaDB Use [Raff VM](/products/raff-vm) when the workload requires MariaDB or host-level control. Self-hosting transfers more responsibility to your team: - OS and database patching; - firewall/service exposure; - TLS/authentication configuration; - monitoring; - backups; - restore testing; - storage management; - replication/HA if used; - upgrades; - incident response. Keep database access private or tightly restricted, and avoid broad public exposure of port `3306`. :::cta Compare MySQL Deployment Paths Use Managed MySQL to reduce host-level database operations, or Raff VM when MySQL/MariaDB requires direct server control. ::: ## MySQL vs MariaDB production checklist Before choosing or migrating, confirm: - [ ] The application/vendor supports the exact engine and major version. - [ ] Drivers and ORMs are tested against that target. - [ ] Authentication behavior is compatible. - [ ] SQL modes and reserved words have been reviewed. - [ ] JSON-dependent application paths have been tested. - [ ] Stored procedures, triggers, and events have been tested if used. - [ ] Important query plans are benchmarked with representative data. - [ ] Connection demand is budgeted. - [ ] Backup and restore procedures are proven. - [ ] RPO and RTO are defined. - [ ] Migration rollback conditions are documented. - [ ] Hosting responsibility is assigned. - [ ] Managed-service requirements have been verified against the live product. ## Conclusion MySQL vs MariaDB for production apps is mainly a compatibility, migration-risk, and operational-ownership decision. Keep MySQL when your application, vendors, drivers, and operations are already aligned with MySQL. Keep MariaDB when the application is explicitly supported on MariaDB and your team understands the selected release. Do not migrate between them based on generic performance claims. For teams choosing MySQL, Raff Managed MySQL provides the managed path. Teams that require MariaDB or direct host control can self-host on Raff VM. If PostgreSQL or MongoDB is also under consideration, continue with [MySQL vs PostgreSQL vs MongoDB](/learn/guides/mysql-vs-postgresql-vs-mongodb). If the engine is already decided and the remaining question is hosting, use [Managed vs Self-Hosted Databases](/learn/guides/managed-vs-self-hosted-databases). ## Sources - [MySQL: Reference Manual](https://dev.mysql.com/doc/refman/8.4/en/) - [MySQL: Backup and Recovery](https://dev.mysql.com/doc/refman/8.4/en/backup-and-recovery.html) - [MariaDB: Differences Between MariaDB and MySQL](https://mariadb.com/kb/en/mariadb-vs-mysql-compatibility/) - [MariaDB: Backup and Restore](https://mariadb.com/docs/server/server-usage/backup-and-restore) - [Raff Managed MySQL](/products/managed-databases/mysql) - [Raff Managed Databases](/products/managed-databases) - [Raff VM](/products/raff-vm) - Product status reviewed: 2026-09-17; verify current versions, limits, networking, retention, and availability options on the live Raff product page and console. --- ### One Database vs Multiple Databases for Small SaaS Teams URL: https://rafftechnologies.com/learn/guides/one-database-vs-multiple-databases-for-saas Description: Decide when a small SaaS should use one database or multiple databases across workloads, services, tenants, recovery boundaries, and managed database roles. **Most small SaaS teams should start with one primary database and add another durable database only when a measured boundary justifies it.** Multiple databases can improve isolation, workload independence, team ownership, or scaling, but every additional stateful system also adds migrations, credentials, monitoring, recovery, synchronization, and incident work. Raff Technologies supports both approaches. Teams can keep a simple relational source of truth on [Managed PostgreSQL](/products/managed-databases/postgresql) or [Managed MySQL](/products/managed-databases/mysql), add [Managed Valkey](/products/managed-databases/valkey) for cache and other supporting state, or self-host database workloads on [Raff VM](/products/raff-vm) when host-level control is required. The important question is not "How many databases should a SaaS have?" It is **which system owns each fact, why another database is needed, and whether the team can operate every recovery path it creates.** :::cta Explore Managed Databases Start with the data model and ownership boundary, then compare managed PostgreSQL, MySQL, and Valkey for the workloads that actually need separation. ::: ## One database vs multiple databases: quick decision | Situation | Better starting point | |---|---| | Small team, one product, strongly related transactional data | One primary relational database | | Files, uploads, exports, or media | Keep metadata in the database; move objects to Object Storage | | Cache, sessions, rate limits, or short-lived coordination | Add a key-value store such as Valkey | | Analytics queries disrupt customer-facing transactions | Separate the analytical workload | | A service has a genuinely independent data model and owner | Consider a service-owned database | | A tenant requires stronger technical or contractual isolation | Consider schema-per-tenant or database-per-tenant | | Different domains need different recovery or scaling policies | Consider separate durable databases | | The reason is only "microservices should have many databases" | Stay simpler until the boundary is real | A second database should remove a real constraint. It should not exist only to make the architecture look more distributed. ## One primary relational database is the safest default for many small SaaS teams A single PostgreSQL or MySQL database keeps the hardest state-management responsibilities together: - transactions; - constraints; - schema migrations; - access control; - backup policy; - point-in-time recovery where available; - monitoring; - restore testing; - reporting consistency. A common early architecture is: ```text Application ↓ Primary PostgreSQL or MySQL ↓ Object Storage for files ``` This is usually a strong fit when: - one engineering team owns most of the product; - users, organizations, permissions, billing, projects, and subscriptions are closely related; - business operations need transactions across several tables; - the schema changes frequently; - reporting benefits from a consistent relational view; - one recovery plan is easier to operate than several. One database does **not** mean one poorly structured schema. Teams can separate domains using schemas, table ownership, permissions, naming conventions, modules, and service boundaries without immediately creating another durable database. ## Multiple databases make sense when the boundary is operationally real A multi-database architecture becomes useful when the systems genuinely need different behavior. | Boundary | Stay with one database when | Split when | |---|---|---| | Workload | Queries coexist without meaningful contention | Reporting, analytics, batch jobs, or search disrupt transactional traffic | | Data model | Relational tables plus bounded JSON fit the workload | Another model clearly matches the access pattern better | | Team ownership | One team owns the domain | Separate teams/services require independent ownership | | Scaling | One database can scale with tuning, pooling, replicas, or vertical growth | A workload needs independent capacity or topology | | Recovery | The same RPO/RTO applies | One domain needs a different recovery or availability objective | | Tenant isolation | Logical controls satisfy requirements | Contractual or technical requirements demand a stronger boundary | | Lifecycle | Data shares retention and backup policy | Logs, events, or archives require materially different retention | Every additional **durable** database creates another: - credential boundary; - schema and migration lifecycle; - monitoring surface; - backup and restore path; - capacity budget; - failure mode; - incident dependency. The operational cost should be smaller than the problem the split removes. ## Workload separation often provides value before database-per-service For small SaaS teams, the first useful split is often not another transactional database. ### Move files out of the database Large uploads, generated exports, media, and binary artifacts are usually easier to operate in [Object Storage](/products/object-storage). The relational database can retain object ownership, metadata, permissions, and references. ```text PostgreSQL/MySQL └─ object_id, owner, metadata, permissions Object Storage └─ actual file/blob ``` This reduces pressure on the transactional store without creating another writable business source of truth. ### Separate cache and short-lived state [Raff Managed Valkey](/products/managed-databases/valkey) can support workloads such as: - cache; - sessions; - rate limits; - idempotency keys; - short-lived coordination; - selected queue/worker patterns. A clean boundary is: ```text PostgreSQL/MySQL = durable source of truth Valkey = supporting state ``` If a Valkey key becomes impossible to reconstruct and the business cannot tolerate losing it, that data should be treated as durable state with an explicit persistence and recovery design. See [Redis Cache Strategy for SaaS Apps](/learn/guides/redis-cache-queue-strategy-saas-apps) for the cache, queue, session, rate-limit, and durability boundary. ### Separate analytics when it harms transactional performance Reporting and analytics can generate scans, aggregations, and batch work that compete with customer-facing requests. A safer model is often: ```text Authoritative transactional database ↓ replication / events / exports ↓ Derived analytics system ``` The analytical system is easier to recover when it can be rebuilt from an authoritative source. ## Database-per-service trades transaction simplicity for independence In a database-per-service architecture, each service owns its persistent data and other services do not directly read or write its tables. AWS and Microsoft both document this pattern as a way to reduce coupling between services, while also noting the added complexity around cross-service queries, transactions, consistency, and operating multiple stores. | Area | Shared primary database | Database per service | |---|---|---| | Initial operations | Simpler | More systems to operate | | Cross-domain transactions | Native database transactions | Workflow, events, or compensation often required | | Schema ownership | Shared governance | Clearer service ownership | | Reporting | Direct relational queries possible | Aggregation/read models often needed | | Data duplication | Usually lower | Often higher | | Independent scaling | More limited | Stronger | | Deployment autonomy | More coordination | Greater independence | | Backup/recovery | One main recovery system | Several recovery paths | | Incident surface | Smaller | Larger | For a small team, database-per-service should usually follow a real service boundary rather than create one artificially. A useful intermediate state is possible: services may share the same physical database platform while keeping separate schemas or ownership boundaries. Microsoft notes that the main coupling problem is services sharing the same schema or directly reading and writing the same tables—not necessarily sharing the same physical database server. ## Cross-database transactions are where complexity becomes visible With one relational database, a business operation can often commit atomically: ```text create subscription + record invoice + assign entitlement = one transaction ``` Once those facts live in independently owned databases, the same operation can span several systems. Now the architecture needs answers for: - partial failure; - retries; - idempotency; - event delivery; - duplicate processing; - stale reads; - compensating actions; - reconciliation. This does not make multiple databases wrong. It means distributed state requires explicit failure semantics. If a team cannot explain what happens when database A commits and database B is unavailable, the multi-database design is not finished. ## One source of truth matters more than the number of databases A healthy multi-database system has explicit ownership. Before duplicating data, document: 1. **Authority** — which system owns the business fact? 2. **Copy type** — is another copy authoritative, derived, cached, or historical? 3. **Synchronization** — how does data move? 4. **Consistency window** — how stale may a copy become? 5. **Failure behavior** — what happens when the source or destination is unavailable? 6. **Recovery order** — which system is restored first? 7. **Deletion flow** — how do retention/privacy deletions propagate? 8. **Reconciliation** — how are missing or divergent records detected? Derived systems are usually easier to operate because authority remains clear. Examples: - a cache can be repopulated; - a search index can be rebuilt; - an analytical projection can be regenerated; - a file thumbnail can be recreated from an original object. Two independently writable databases both claiming to own the same subscription status or account balance are much harder to reason about. ## Database-per-tenant is mainly an isolation decision Multi-tenant SaaS commonly uses one of three broad models: | Model | Advantage | Trade-off | |---|---|---| | Shared database, shared schema | Lowest operational overhead | Isolation is mostly logical/application-enforced | | Shared database, separate schemas | Stronger namespace separation | Migrations and permissions become more complex | | Database per tenant | Strong technical isolation | Provisioning, migrations, monitoring, and recovery multiply with tenant count | Database-per-tenant can make sense when: - contracts require stronger isolation; - customers need independent backup/restore operations; - dedicated capacity is part of the commercial model; - tenant workloads vary enough to need independent sizing; - regulatory or technical requirements justify the boundary. It is usually not the best default for an early SaaS product with many small tenants. Ten tenants with ten databases create ten credential sets, migration targets, health checks, backup histories, and restore paths. At larger tenant counts, the control plane for provisioning and migrations becomes a product of its own. ## Recovery is the hidden cost of a multi-database architecture A multi-database design can work well during normal operation and still fail badly during recovery if restoration order and consistency are undefined. With several durable databases, ask: - must they recover to the same point in time? - what if database A is restored to 10:05 and database B to 10:12? - can events or logs replay the missing interval? - which database is authoritative after partial recovery? - which features remain disabled until synchronization completes? - how do you verify cross-system consistency before reopening writes? Derived stores make the recovery sequence cleaner: ```text Restore authoritative database ↓ Validate core records and invariants ↓ Rebuild/resynchronize derived systems ↓ Validate dependent features ↓ Resume normal traffic ``` Use [Database Backup Strategy for SaaS Apps](/learn/guides/database-backup-strategy-saas-apps) and [Database Restore Testing](/learn/guides/database-restore-testing-rpo-rto-recovery-validation) to define RPO, RTO, restoration evidence, and recovery validation. ## Monitoring also multiplies with every durable store Each database needs enough observability to identify whether a failure comes from the application, connection pool, queries, capacity, storage, replication, or the database service itself. For each durable store, define at minimum: - connection usage; - query/error rate; - latency; - capacity/storage headroom; - backup age; - restore-test age; - replication/failover state where relevant; - owner and escalation path. The [Database Monitoring for Small Teams](/learn/guides/database-monitoring-small-teams) guide covers the core metrics and alerting model. The [Database Incident Runbook](/learn/guides/database-incident-runbook) covers triage, containment, failover/rollback/restore, validation, and follow-up. ## Managed databases reduce host operations, not architecture responsibility A managed database can reduce repetitive platform work, but it does not decide data ownership or consistency for the application. A practical Raff architecture might look like: ```text Application on Raff VM / app runtime ↓ Managed PostgreSQL or MySQL = authoritative relational state ↓ Managed Valkey = cache / sessions / supporting state ↓ Object Storage = files / exports / binary objects ``` Raff's current [Managed Databases](/products/managed-databases) catalog provides managed database options for different workloads. Product capabilities, versions, limits, networking, recovery options, and availability features can change, so verify the live product page and console rather than relying on an old guide specification. Teams that need root access, custom packages, unsupported topology, or another self-managed database setup can use [Raff VM](/products/raff-vm). Managed infrastructure can reduce host operations. The application team still owns: - data model; - schema boundaries; - source-of-truth decisions; - queries and indexes; - migrations; - tenant isolation; - credentials; - cross-system consistency; - validation after recovery. :::cta Compare Database Deployment Paths Use Managed Databases when the supported engine fits and you want less host-level work, or Raff VM when direct database-host control is required. ::: ## A practical decision framework Before adding another durable database, answer these questions in order. ### 1. What measured problem are we solving? Examples include: - analytics contention; - incompatible access patterns; - independent scaling; - tenant isolation; - separate recovery objectives; - organizational ownership. If the problem is hypothetical, keep the architecture simpler. ### 2. Can the current database solve it first? Check whether the real fix is: - indexing; - query optimization; - connection pooling; - better schema boundaries; - workload scheduling; - read replicas where appropriate; - moving files/blobs out of the database; - adding a cache rather than another source of truth. ### 3. Who owns the new data store? A database without a named operational owner creates ambiguous incident responsibility. ### 4. What is authoritative? For every duplicated field, define the source of truth before production traffic is allowed. ### 5. How will it fail and recover? Document retry, rollback, restore order, reconciliation, and degraded behavior. ## SaaS multi-database checklist Before approving another database, confirm: - [ ] The current constraint is measured. - [ ] A simpler schema/query/pooling/storage change was considered first. - [ ] The new database has one clear responsibility. - [ ] Its authoritative data is documented. - [ ] Any duplicate data is classified as authoritative, derived, cached, or historical. - [ ] Synchronization and retry behavior are defined. - [ ] Cross-database partial failures are handled. - [ ] Backup and restore requirements exist for every durable store. - [ ] Recovery order is documented. - [ ] Monitoring and incident ownership exist. - [ ] Tenant/security boundaries are clear. - [ ] Migration and rollback paths exist. - [ ] The team can explain why the added operations are worth the boundary. ## Conclusion For most small SaaS teams, **one primary relational database remains the best starting point**. Add supporting systems such as Object Storage or Valkey when they have a clear role, and add another durable database only when workload, ownership, data model, tenant isolation, scaling, or recovery requirements justify it. The goal is not to keep the database count artificially low. The goal is to ensure that every new stateful system has **one responsibility, one source-of-truth rule, one owner, and one recovery plan**. Continue with [SQL vs NoSQL for SaaS Apps](/learn/guides/sql-vs-nosql-for-saas-apps) if the next decision is the data model, or [Managed vs Self-Hosted Databases](/learn/guides/managed-vs-self-hosted-databases) if the next decision is who should operate the database. ## Sources - [AWS Prescriptive Guidance: Database-per-service pattern](https://docs.aws.amazon.com/prescriptive-guidance/latest/modernization-data-persistence/database-per-service.html) - [AWS Prescriptive Guidance: Shared-database-per-service pattern](https://docs.aws.amazon.com/prescriptive-guidance/latest/modernization-data-persistence/shared-database.html) - [Microsoft Azure Architecture Center: Data considerations for microservices](https://learn.microsoft.com/en-us/azure/architecture/microservices/design/data-considerations) - [Raff Managed Databases](/products/managed-databases) - [Raff Managed PostgreSQL](/products/managed-databases/postgresql) - [Raff Managed MySQL](/products/managed-databases/mysql) - [Raff Managed Valkey](/products/managed-databases/valkey) - Product status reviewed: 2026-09-17. Verify current engine availability and product capabilities on the live Raff product pages and console. --- ### MySQL Performance Bottlenecks: Queries, Indexes, and Connections URL: https://rafftechnologies.com/learn/guides/mysql-performance-bottlenecks-queries-indexes-connections Description: Diagnose MySQL performance bottlenecks across slow queries, indexes, connections, locks, memory, and storage before scaling production database capacity. MySQL performance problems are usually easier to solve when the team identifies **which layer is actually constraining work** instead of resizing the database first. For small production teams, the highest-value bottleneck sequence is usually: slow or repeated queries, ineffective indexes, connection pressure, memory pressure, storage latency, and only then raw CPU capacity. A larger instance can hide poor access patterns temporarily, but it rarely fixes them. This guide owns MySQL performance diagnosis across queries, indexes, connections, memory, and storage. For the hosting decision, use [MySQL Hosting: Managed vs Self-Hosted for Production Apps](/learn/guides/mysql-hosting-managed-vs-self-hosted). For backup and recovery, use [MySQL Binary Logs, Backups, and Point-in-Time Recovery](/learn/guides/mysql-binary-logs-backups-point-in-time-recovery). :::cluster ## Start with the symptom, not the server size A useful performance investigation begins by describing what changed: - request latency increased; - one endpoint became slow; - CPU rose at the same traffic level; - connections reached their ceiling; - lock waits increased; - disk latency spiked; - temporary tables moved to disk; - replication lag grew; - a deployment caused a sudden regression; - a report or background job now competes with customer traffic. That symptom narrows the search space. | Symptom | First signals to inspect | |---|---| | One endpoint is slow | query latency, execution plan, rows examined | | Many endpoints slow together | connections, CPU, storage, locks | | CPU high | top statements, full scans, joins, repeated queries | | Connections exhausted | pool size, active vs idle sessions, connection churn | | Disk latency high | buffer-pool misses, temporary files, large scans | | Writes slow | locks, fsync/storage latency, binary-log pressure | | Replication lag | write burst, replica SQL/applier pressure, long transactions | The goal is to identify the dominant constraint before changing capacity. ## Slow-query analysis should be the first diagnostic layer MySQL's slow query log can record statements whose execution time exceeds the configured threshold and, optionally, queries that do not use indexes. It is most useful when combined with workload context rather than treated as a list of “bad queries.” Prioritize statements by a combination of: ```text frequency × execution time × rows examined × business importance ``` A query that takes two seconds once per day is different from a 150 ms query executed thousands of times per minute. Look for: - full table scans; - repeated N+1 queries; - large joins with weak predicates; - unbounded `ORDER BY` or `GROUP BY` work; - functions applied to indexed columns in ways that prevent efficient access; - `%prefix` wildcard patterns that cannot use a normal leading index effectively; - unnecessary `SELECT *` over wide tables; - repeated reporting queries against transactional tables; - queries that return few rows but examine very many. MySQL's `EXPLAIN` and `EXPLAIN ANALYZE` help show how the optimizer intends to execute a query and, with `ANALYZE`, how the real execution behaved. Do not optimize from the SQL text alone. Inspect the plan and the actual data distribution. ## Indexes should match predicates and access order An index is valuable only when it reduces the work needed for important reads without creating excessive write and storage overhead. Common indexing mistakes include: - missing indexes on frequent filters or joins; - redundant single-column indexes when a composite index already covers them; - composite indexes with columns in the wrong order for the workload; - indexes on low-selectivity fields that do little pruning; - adding every suggested index without measuring write cost; - indexing fields that are rarely queried; - keeping obsolete indexes after workload changes. For a composite index such as: ```text (account_id, status, created_at) ``` queries beginning with `account_id` can often benefit strongly, while queries filtering only on `created_at` may not use the composite index effectively. A practical index-design process is: 1. identify the high-value query; 2. list equality predicates; 3. list range predicates; 4. list join columns; 5. inspect sort/group requirements; 6. build the narrowest useful index; 7. compare execution plan and measured latency; 8. check write and storage impact. **Indexes should be justified by real access patterns, not by the number of columns available.** ## Connection pressure can break a database with low CPU A MySQL instance can become unavailable even when CPU and memory graphs look moderate if every allowed connection is occupied. Connection demand is cumulative across the whole application: ```text application replicas × pool size + workers + scheduled jobs + migrations + monitoring + admin sessions = possible connection demand ``` Eight application replicas with a pool of 20 connections can create 160 possible connections before background workers or administrative sessions are counted. Monitor: - current connections; - maximum observed connections; - `Threads_connected`; - `Threads_running`; - aborted connections; - connection creation rate; - idle-session duration; - pool wait time on the application side; - deployments that temporarily double application replicas. A large pool is not automatically faster. Excessive concurrency can increase memory use, lock contention, and context switching. Keep an operational reserve so administrators and monitoring can still connect during an incident. ## InnoDB buffer-pool behavior explains many storage symptoms For InnoDB workloads, memory is especially important because the buffer pool caches table and index pages. When the active working set fits the buffer pool well, many reads avoid storage. When it does not, storage I/O can rise sharply and query latency can become more variable. Useful signals include: - buffer-pool hit behavior; - reads from disk versus logical reads; - dirty-page pressure; - flushing activity; - page churn; - overall memory pressure and swapping. Do not chase a universal buffer-pool ratio. Workloads differ. Instead, correlate buffer-pool misses with storage latency and query slowdown. A database with a large total dataset can still perform well if the frequently accessed working set is smaller and well-indexed. Conversely, a modest database can perform poorly if queries repeatedly scan cold data. ## Temporary tables and sorting reveal query-shape pressure Complex joins, sorts, and grouping operations can require temporary work. When temporary work spills to disk, latency may rise substantially compared with in-memory execution. Watch for: - large `GROUP BY` operations; - large sorts; - reporting queries over long ranges; - joins that multiply row counts unexpectedly; - query plans using temporary tables and filesorts; - application requests that request entire datasets and sort them at the database layer. The fix may be a better index, narrower query, precomputed summary, pagination strategy, or moving analytical work away from the transactional database. Increasing memory can help only when the query shape is already reasonable. ## Lock waits and long transactions create hidden latency Not every slow query is computationally expensive. A fast statement can wait behind another transaction. Investigate: - long-running transactions; - row-lock waits; - deadlocks; - application code that opens a transaction before doing remote work; - bulk updates touching many rows; - schema changes that create metadata-lock contention; - jobs that update rows in inconsistent order. Keep transactions as short as business correctness allows. A useful application rule is: ```text begin transaction → read/write only the data needed → commit ``` Avoid holding a database transaction open while waiting for user input, external APIs, large file operations, or unrelated application work. ## CPU pressure is often a query symptom High CPU should trigger a query investigation before a capacity increase. Common causes include: - full scans; - inefficient joins; - missing indexes; - repeated identical queries; - expensive expressions; - large sorts or aggregations; - retry storms; - too much concurrency; - reporting mixed with transactional traffic. Compare CPU growth with: - query rate; - rows examined; - statement latency; - active connections; - deployment timing; - traffic level. If CPU doubles while traffic is flat after a release, the most likely explanation is a workload regression rather than a sudden need for twice the hardware. ## Storage latency matters when memory cannot hide I/O Database storage performance affects reads, writes, log flushing, temporary work, backups, and recovery. Watch: - read/write latency; - IOPS and throughput saturation; - disk queueing; - free space; - binary-log growth; - temporary-file growth; - backup overlap with peak traffic. A database running near full disk capacity is also an operational risk. Large schema changes, index creation, temporary tables, binary logs, and restore procedures all require headroom. Keep a margin for maintenance and growth rather than sizing storage to current table size alone. ## Performance tuning should be evidence-driven A safe tuning workflow is: ```text measure baseline → identify dominant bottleneck → change one major variable → compare the same workload → keep or revert ``` Avoid changing many server parameters at once. If latency improves or degrades, you should know why. For production tuning, keep a short change record: - timestamp; - workload state; - parameter or index changed; - before/after query plan; - before/after latency; - CPU/memory/storage impact; - rollback step. This makes future incidents easier to understand. ## Managed MySQL reduces platform work, not query ownership [Raff Managed MySQL](/products/managed-databases/mysql) currently includes monitoring and slow-query visibility together with managed backups, PITR, TLS, private networking, storage expansion, maintenance workflows, and optional HA. That helps reduce the operating work around the database host and service. The application team still owns: - query design; - indexes; - schema shape; - connection pools; - transaction boundaries; - workload separation; - validating a scaling decision. For self-hosted MySQL on [Raff VMs](/products/raff-vm), the team also owns MySQL configuration, host metrics, storage behavior, patching, backups, and incident response. The performance rule we use at Raff is simple: **resize after you can name the resource constraint; optimize first when the evidence points to unnecessary work.** ## MySQL performance checklist - [ ] The user-facing symptom is defined. - [ ] Slow statements are ranked by frequency and impact. - [ ] `EXPLAIN` / `EXPLAIN ANALYZE` is reviewed for important queries. - [ ] Indexes match actual filter and join patterns. - [ ] Redundant or unused indexes are reviewed. - [ ] Application pool capacity is summed across all replicas. - [ ] Administrative connection reserve exists. - [ ] Long transactions and lock waits are monitored. - [ ] Buffer-pool misses are correlated with storage latency. - [ ] Temporary work and large sorts are monitored. - [ ] Storage has capacity and maintenance headroom. - [ ] Parameter changes are tested one major variable at a time. - [ ] Performance baselines are captured before scaling. ## Conclusion MySQL performance tuning works best when the team diagnoses the bottleneck in layers: query work, indexing, connections, locking, memory, storage, and finally compute capacity. The most expensive mistake is often scaling a database to compensate for work that should not be happening. Measure the workload, inspect the execution path, and change only what the evidence supports. Continue with [MySQL Binary Logs, Backups, and Point-in-Time Recovery](/learn/guides/mysql-binary-logs-backups-point-in-time-recovery) for recovery design, or [Database Monitoring for Small Teams](/learn/guides/database-monitoring-small-teams) for the cross-engine monitoring framework. :::cta mysql Use managed monitoring and slow-query insights while keeping query and schema optimization in your application team. ::: ## Sources - [MySQL 8.4: Optimization](https://dev.mysql.com/doc/refman/8.4/en/optimization.html) - [MySQL 8.4: The Slow Query Log](https://dev.mysql.com/doc/refman/8.4/en/slow-query-log.html) - [MySQL 8.4: EXPLAIN](https://dev.mysql.com/doc/refman/8.4/en/explain.html) - [MySQL 8.4: InnoDB Buffer Pool](https://dev.mysql.com/doc/refman/8.4/en/innodb-buffer-pool.html) - [MySQL 8.4: Server Status Variables](https://dev.mysql.com/doc/refman/8.4/en/server-status-variables.html) - [Raff Managed MySQL](/products/managed-databases/mysql) - Sources reviewed: 2026-08-24 --- ### Redis vs Valkey: Compatibility, Operations, and Migration URL: https://rafftechnologies.com/learn/guides/redis-vs-valkey-compatibility-migration Description: Compare Redis vs Valkey across protocol compatibility, clients, persistence, modules, operations, and safe migration for cache, sessions, and queues. Redis and Valkey are closely related in-memory data stores that share the Redis Serialization Protocol and a large set of commands and client-library patterns, but they are no longer one interchangeable project. For teams choosing between them, the useful questions are **application compatibility, operational ownership, persistence and module requirements, licensing/project direction, and how safely an existing Redis workload can be migrated**. This guide owns the Redis-vs-Valkey decision and migration boundary. For hosting choice, use [Redis Hosting: Managed Valkey vs Self-Hosted Redis](/learn/guides/redis-hosting). For cache/queue architecture, use [Redis Cache Strategy for SaaS Apps](/learn/guides/redis-cache-queue-strategy-saas-apps). :::cluster ## Redis and Valkey share a common operational heritage Valkey began as a fork of Redis OSS 7.2 and continues to use RESP, familiar data structures, persistence concepts, replication, ACLs, transactions, Lua scripting, and common Redis client patterns. That shared heritage is why many applications can migrate with limited code change. But compatibility should be tested rather than assumed. | Area | What to verify before migration | |---|---| | Client library | Does the client work against the target Valkey version? | | Commands | Are all commands used by the application supported with the same semantics? | | Modules | Are required modules available and compatible? | | Persistence | Are the source RDB/AOF files supported by the target version? | | ACL/auth | Do users, permissions, and credential workflows map correctly? | | Cluster topology | Are slot, replication, failover, and discovery assumptions compatible? | | Monitoring | Do dashboards and alerts recognize Valkey metrics/identifiers? | | Automation | Do provisioning and backup scripts rely on Redis-specific packaging or paths? | The safest migration is based on the exact workload, not a generic compatibility percentage. ## Valkey documents direct compatibility with Redis OSS 7.2-era data Valkey's migration documentation states that Valkey can load Redis OSS 7.2 RDB and AOF files and supports Redis OSS modules using the module API, subject to module compatibility. That is especially useful for teams migrating older Redis OSS deployments. Later Redis Community Edition releases have evolved independently. File-level or command-level compatibility across every newer release should therefore be checked against the source and target versions rather than assumed from the shared origin. A migration plan should record: ```text source Redis version → client versions → commands/modules in use → persistence format → target Valkey version → compatibility test ``` Version awareness matters more than the brand names alone. ## Application protocol compatibility is only the first layer An application can connect successfully and still have operational incompatibilities. Test workloads that depend on: - Lua scripts; - transactions and WATCH/MULTI behavior; - streams and consumer groups; - sorted sets and blocking commands; - pub/sub; - ACLs; - cluster-mode routing; - keyspace notifications; - persistence/restart behavior; - modules; - client-side caching or newer protocol capabilities. Create a representative test suite that exercises the commands actually used in production. A simple connectivity check such as `PING` proves very little about migration safety. ## Client libraries should be tested for discovery and naming assumptions Many Redis clients work with Valkey because they speak RESP and use standard commands. Some ecosystems now expose explicit Valkey support or separate Valkey-oriented packages. Do not change client libraries merely because the server changes if the current library is supported and stable. Instead verify: - connection URI format; - TLS behavior; - authentication; - cluster/sentinel-style discovery assumptions; - retry and reconnect logic; - command compatibility; - metrics and error parsing. The migration goal is the smallest safe change set. Changing server, client library, topology, and persistence settings at the same time makes rollback and diagnosis harder. ## Persistence compatibility needs a deliberate path Redis and Valkey both support RDB and AOF persistence concepts, but migration should use a supported source-target path. For a small standalone workload, approaches can include: - stop source writes, copy a compatible RDB/AOF artifact, start target, validate; - export/import application data through a migration tool; - replicate or dual-write through a tested migration workflow; - rebuild the target entirely when the workload is disposable cache. The correct path depends on downtime tolerance and whether the data is authoritative. For cache-only workloads, rebuilding can be safer than carrying old persistence state forward. For sessions or queues, the team needs a plan for state that cannot simply disappear during cutover. ## Redis vs Valkey is also an operating-model decision The choice is not only about protocol compatibility. Teams should compare: | Decision factor | Redis | Valkey | |---|---|---| | Existing production standard | Strong if already standardized | Requires migration validation | | RESP/client familiarity | Strong | Strong | | Open-source ecosystem direction | Redis project-specific | Linux Foundation-hosted Valkey project | | Managed service availability | Provider-dependent | Increasing managed-service availability | | Existing modules/tooling | Verify current Redis ecosystem | Verify Valkey compatibility | | Team runbooks | Existing Redis runbooks may already exist | Runbooks may need naming/packaging updates | The business question is whether changing projects creates enough benefit to justify migration work and operational validation. ## Migration should reduce simultaneous changes A controlled migration uses stages. ### 1. Inventory the source Record: - Redis version; - topology; - dataset size; - memory policy; - persistence mode; - modules; - ACLs; - clients; - commands used; - peak operations per second; - acceptable downtime/data loss. ### 2. Build the target with equivalent boundaries Match the relevant: - memory capacity; - networking; - TLS/authentication; - persistence requirements; - eviction policy; - backup/recovery workflow. ### 3. Test application compatibility Replay representative traffic or integration tests against Valkey. Measure: - command errors; - latency; - reconnect behavior; - queue/stream semantics; - session behavior; - memory growth; - persistence restart. ### 4. Choose a data-transfer model | Workload | Typical migration model | |---|---| | Disposable cache | Start empty and warm naturally | | Sessions | Short controlled cutover or compatible data copy | | Queues | Drain/freeze or migrate pending state carefully | | Rate limits | Decide whether reset is acceptable | | Mixed workloads | Separate roles before migration where practical | ### 5. Cut over with rollback criteria Define before the change: - DNS/endpoint switch method; - source write-freeze window if needed; - validation queries; - error-rate threshold for rollback; - how long the source remains available; - who approves completion. Migration is safer when rollback is a planned branch, not an improvised reaction. ## A cache migration can be intentionally simpler When Redis contains only rebuildable cache data, preserving every key may create unnecessary risk. A clean migration can be: ```text provision Valkey → validate connectivity/auth → point a small traffic slice at target → switch application → allow cache to warm → monitor origin database load ``` The main risk becomes cache-miss pressure rather than data loss. Protect the primary database from a sudden cold-cache stampede by staging traffic, pre-warming expensive keys, or temporarily increasing application-side request coalescing where appropriate. ## Queues and sessions require stronger validation A queue or session store is not as disposable as a read cache. For queues, validate: - pending jobs; - consumer-group state; - retries; - idempotency; - job duplication or loss during cutover. For sessions, validate: - TTLs; - logout impact; - serialization format; - authentication behavior after reconnect. If the migration can cause state loss, quantify it before deciding the cutover method. ## Raff's managed Redis-compatible path is Valkey Raff currently provides [Managed Valkey](/products/managed-databases/valkey) for managed Redis-compatible cache, queues, sessions, and related workloads. This matters for content and architecture language: Raff should not describe the product as “Managed Redis.” The managed engine is Valkey; Redis can still be self-hosted on [Raff VMs](/products/raff-vm) when exact Redis control is required. A practical Raff decision path is: ```text Need managed Redis-compatible operations → validate application against Managed Valkey Need exact Redis version/modules/host control → self-host Redis on Raff VM ``` At Raff, the migration rule is to **test the exact commands and state the application depends on, then change as few other variables as possible during cutover**. ## Redis-to-Valkey migration checklist - [ ] Source Redis version is recorded. - [ ] Target Valkey version is selected. - [ ] Client libraries are tested. - [ ] Required commands and modules are inventoried. - [ ] RDB/AOF compatibility is verified if files will be copied. - [ ] ACL/TLS behavior is tested. - [ ] Eviction and persistence settings are mapped. - [ ] Cache, session, queue, and lock roles are classified. - [ ] Data-transfer method matches workload criticality. - [ ] Cold-cache impact is planned. - [ ] Cutover and rollback steps are documented. - [ ] Source remains available until target validation is complete. ## Conclusion Valkey is highly compatible with the Redis OSS lineage, but production migration should be version- and workload-specific. For many standard cache workloads, migration can be straightforward because the protocol, clients, and command model remain familiar. For modules, persistence files, clusters, queues, and session state, test the exact behavior before cutover. Choose Valkey when its project and managed-service path fit the workload. Keep Redis when exact Redis-specific requirements justify it. The goal is not to migrate for the label; it is to choose the operating model the team can run and recover confidently. :::cta valkey Validate your current Redis-compatible application against Raff Managed Valkey before planning production cutover. ::: ## Sources - [Valkey: Migration from Redis](https://valkey.io/topics/migration/) - [Valkey: Compatibility](https://valkey.io/topics/compatibility/) - [Valkey: Introduction](https://valkey.io/topics/introduction/) - [Redis Documentation](https://redis.io/docs/latest/) - [Raff Managed Valkey](/products/managed-databases/valkey) - Sources reviewed: 2026-08-24 --- ### Kafka Retention: Durability, Replication & Data-Loss Trade-Offs URL: https://rafftechnologies.com/learn/guides/kafka-retention-durability-replication-data-loss Description: Design Kafka retention across time and size limits, delete vs compact cleanup, replication, ISR durability, consumer replay windows, and storage capacity. Kafka retention determines how long records remain available in a topic before they become eligible for deletion or compaction. It is a storage-lifecycle policy, not a durability guarantee by itself. For production teams, retention needs to answer three separate questions: **how long consumers may need old events, how much storage that history will consume, and whether replication and producer acknowledgements provide the durability the business expects while the data is retained**. This guide owns Kafka retention and durability trade-offs. For partition and replication design, use [Kafka Partitions: Keys, Replication & Scaling Trade-Offs](/learn/guides/kafka-partitions-keys-replication-scaling). For consumer recovery, use [Kafka Consumer Groups: Lag, Rebalances & Recovery Planning](/learn/guides/kafka-consumer-groups-lag-rebalances). :::cluster ## Kafka retention and replication solve different problems | Control | Primary purpose | Does not guarantee | |---|---|---| | `retention.ms` | Time-based history window | Replica availability | | `retention.bytes` | Size-based history bound per partition | Exact time window under all traffic levels | | `cleanup.policy=delete` | Remove old segments | Recovery from lost replicas | | `cleanup.policy=compact` | Retain latest value per key over time | Full event history | | Replication factor | Keep multiple copies | Historical retention forever | | `min.insync.replicas` + producer acks | Define write durability conditions | Long-term event retention | A topic can retain seven days of data and still lose recent acknowledged records if durability settings are weak. A strongly replicated topic can also delete records after the configured retention window. ## Time-based retention should follow replay needs `retention.ms` defines how long Kafka retains log segments for topics using delete-based cleanup. Choose the window from actual recovery and product needs: - maximum expected consumer outage; - time needed to deploy a fixed consumer; - replay requirements after a bug; - audit or downstream reconstruction needs; - incident-detection delay; - data-governance limits. A useful starting formula is: ```text maximum consumer outage + repair / deployment time + replay safety margin = minimum useful retention window ``` If a consumer can be down for 36 hours during a serious incident, a 24-hour retention window cannot support full replay afterward. ## Size-based retention can shorten the effective history window `retention.bytes` limits how much log data a partition can retain. Under high traffic, the size limit may be reached before the time limit. This means a team cannot promise “seven days of replay” from `retention.ms` alone when a smaller byte cap may delete older segments first. Estimate retained storage from observed write volume: ```text ingest bytes per second × 86,400 seconds/day × retention days × replication factor + operational headroom ``` For example, a topic ingesting an average 2 MB/s produces about 172.8 GB of raw log data per day before replication overhead. Seven days is roughly 1.21 TB before multiplying for replicas and allowing for peaks, segment overhead, and other topics. Use measured compressed/on-disk growth from your own cluster for final capacity planning. ## Delete and compact cleanup policies serve different data models Kafka supports delete-based retention, log compaction, or both depending on topic configuration. ### Delete policy Use `cleanup.policy=delete` when the topic is an event history and records can disappear after a defined time or size window. Typical examples: - application events; - logs; - transient integration events; - telemetry; - replayable processing streams. ### Compact policy Compaction preserves the latest value for each key while allowing older superseded records to be removed over time. This fits state-like topics such as: - latest customer configuration; - entity state changes keyed by ID; - changelog topics; - materialized-state reconstruction. Compaction is not the same as “keep everything forever.” It intentionally discards older values for the same key once compaction conditions are met. ### Delete + compact Some workloads use both policies so key history is compacted while old segments can still age out. Choose this only when the team understands both lifecycle effects. ## Retention should be longer than normal consumer lag A lagging consumer needs the underlying records to remain present long enough to catch up. Monitor: - current maximum lag; - event age at the consumer; - catch-up throughput; - incoming producer rate; - oldest retained offset/time; - expected repair window. If the consumer is falling behind faster than it can recover, increasing retention only delays data loss. The real problem may be consumer throughput, partition count, downstream dependency latency, or application errors. Retention is a recovery budget, not a substitute for fixing an unhealthy consumer. ## Replication protects retained records from node failure Replication factor determines how many broker copies exist for a partition. In-sync replicas identify the replicas considered caught up enough to participate in durability and leadership decisions. For stronger write durability, production teams commonly combine: ```text replication factor > 1 + appropriate min.insync.replicas + producer acks=all ``` The exact numbers depend on cluster size and availability goals. The principle is that retention controls **how long** records should exist, while replication controls **how many healthy copies** exist during that window. Do not reduce replication simply because the topic has short retention. A 15-minute topic can still be business-critical during those 15 minutes. ## `min.insync.replicas` creates a durability/availability trade-off When producers use `acks=all`, `min.insync.replicas` can require a minimum number of in-sync replicas before writes are accepted. A stricter configuration can reduce the chance of acknowledged data being lost after broker failures, but it can make writes unavailable when too few replicas are healthy. That is an intentional trade-off: | Priority | Configuration direction | |---|---| | Stronger acknowledged-write durability | Higher ISR requirement with sufficient replicas | | Higher write availability during degraded replica health | Lower ISR requirement, accepting more durability risk | The business should choose the failure behavior rather than inherit defaults accidentally. ## Long retention increases more than disk cost Longer history affects: - broker storage capacity; - recovery/rebalance time; - backup or archive volume if used; - partition movement duration; - disk replacement and rebuild time; - operational impact of reassignments; - compliance and deletion obligations. Do not set “infinite” retention as a default merely because storage is available today. Define why the history is needed and who owns its lifecycle. ## Kafka is not automatically a permanent archive Kafka can hold long histories, but teams should decide whether the event log is the authoritative archive or an operational streaming layer. For long-term retention, alternatives may include: ```text Kafka topic → consumer / sink → object storage or analytical store ``` This can allow Kafka retention to follow operational replay needs while another system owns multi-month or multi-year history. The correct boundary depends on query access, restore requirements, cost, and governance. ## Retention changes need a rollout plan Reducing retention can delete older segments once they become eligible. Treat large changes as potentially destructive. Before changing a production topic: 1. record current settings; 2. confirm consumers do not need older offsets; 3. estimate storage impact; 4. verify archive requirements; 5. change one topic group at a time; 6. monitor segment deletion and consumer health; 7. keep a rollback plan for settings, while recognizing already-deleted data cannot be recreated from configuration rollback alone. Increasing retention is usually safer but can still create disk-pressure risk. ## Managed Kafka reduces broker operations, not retention design [Raff Managed Kafka](/products/managed-databases/kafka) reduces the host and broker-platform work around Kafka. The application team still owns topic lifecycle, keys, retention requirements, consumer recovery expectations, and the business meaning of event loss. A managed service cannot determine whether a payments event should live for 24 hours, seven days, or be archived indefinitely. That decision belongs to the workload owner. At Raff, the useful retention rule is: **keep Kafka history long enough to survive the realistic repair-and-replay window, then archive elsewhere when the business needs longer history than the streaming platform should carry operationally.** ## Kafka retention checklist - [ ] Each topic has a documented replay window. - [ ] `retention.ms` reflects outage and repair time. - [ ] `retention.bytes` will not unexpectedly shorten that window. - [ ] Delete vs compact policy matches the data model. - [ ] Replication is sized independently from retention duration. - [ ] Producer acknowledgements and ISR requirements match durability goals. - [ ] Consumer lag remains well inside the retained window. - [ ] Disk capacity includes replication and traffic peaks. - [ ] Long-term archive requirements are separate from Kafka where appropriate. - [ ] Retention reductions are treated as destructive changes. ## Conclusion Kafka retention is a balance between replay safety, storage growth, consumer recovery, and data lifecycle. Set the retention window from the longest realistic repair-and-replay requirement, verify byte limits do not shorten it, and keep replication/durability settings as a separate design decision. Use compaction for latest-value state, delete retention for bounded event history, and external archives when business history should outlive Kafka's operational window. :::cta kafka Run Kafka with managed broker operations while keeping retention and durability policy aligned to your application recovery needs. ::: ## Sources - [Apache Kafka Topic Configuration](https://kafka.apache.org/documentation/#topicconfigs) - [Apache Kafka Broker Configuration](https://kafka.apache.org/documentation/#brokerconfigs) - [Apache Kafka Operations](https://kafka.apache.org/documentation/#operations) - [Raff Managed Kafka](/products/managed-databases/kafka) - Sources reviewed: 2026-08-24 --- ### ClickHouse Performance Tuning: ORDER BY, Keys & Query Optimization URL: https://rafftechnologies.com/learn/guides/clickhouse-query-performance-order-by-keys-memory Description: Improve ClickHouse query performance with better ORDER BY and sorting keys, lower scan volume, and controlled memory, joins, and concurrency. ClickHouse performance tuning starts with a simple question: **how many rows and bytes does the query read before it returns the result?** For MergeTree tables, `ORDER BY` and the sorting key are usually the first places to look because they control physical row order and determine how effectively ClickHouse can skip data. Raff Technologies recommends fixing the read path before adding compute. If an analytical query returns a small result but scans a large share of the table, increasing CPU or memory may reduce latency temporarily without fixing the underlying query-design problem. For most production workloads, use this sequence: 1. check rows and bytes read; 2. verify that filters align with the sorting key; 3. review selected columns and `PREWHERE`; 4. inspect aggregation, join, and memory pressure; 5. test realistic concurrency; 6. resize infrastructure only after the query path is understood. This guide covers ClickHouse query optimization across `ORDER BY`, primary and sorting keys, filters, memory, joins, and concurrency. For lifecycle design, see [ClickHouse Partitioning & TTL](/learn/guides/clickhouse-partitioning-ttl-mergetree-retention). For repeated aggregations, see [ClickHouse Materialized Views](/learn/guides/clickhouse-materialized-views-pre-aggregation-query-trade-offs). For infrastructure ownership, see [Managed ClickHouse vs Self-Hosted ClickHouse](/learn/guides/managed-clickhouse-vs-self-hosted-clickhouse). ## ORDER BY is physical storage design in ClickHouse In MergeTree-family tables, `ORDER BY` determines how rows are sorted on disk. That ordering lets ClickHouse maintain a sparse primary index over granules and skip ranges that cannot satisfy a filter. This is different from an OLTP database where a primary key often means uniqueness and row identity. | ClickHouse concept | Main role | |---|---| | `ORDER BY` | physical row sorting and data locality | | `PRIMARY KEY` | sparse indexing expression, often same as ORDER BY prefix | | `PARTITION BY` | coarse lifecycle boundary | | skipping indexes | additional pruning for selected patterns | The sorting key should follow the dominant query filters, not the application's entity identifier by default. ## Put frequent selective filters early in the sorting key Suppose dashboards usually query: ```text account_id = ? AND event_time BETWEEN ? AND ? ``` A table ordered by: ```sql ORDER BY (account_id, event_time) ``` can keep rows for an account close together and use time as the next pruning dimension. An ordering of only: ```sql ORDER BY event_time ``` may be better for global time-range scans but less efficient for tenant-specific dashboards. The correct key comes from the actual workload. Collect the most important queries and record: - equality filters; - range filters; - grouping dimensions; - sort requirements; - query frequency; - expected time range. Then design the ordering to reduce the data read by the highest-value workload. ## Low-cardinality-first is a useful heuristic, not a universal rule ClickHouse guidance often recommends considering lower-cardinality columns earlier when they are frequently filtered, followed by more selective dimensions and time. But no universal column order replaces testing. For multi-tenant analytics, an account/tenant dimension can be valuable early even when cardinality is high if nearly every customer-facing query filters by it. The test is whether the key improves pruning for the workload. Measure: - rows read; - bytes read; - query duration; - mark/granule pruning; - compression and storage impact. A key that looks elegant on paper but reads most of the table is not effective. ## Primary key does not need to enforce uniqueness ClickHouse primary keys are sparse indexes and do not provide uniqueness enforcement like a conventional transactional primary key. Duplicate rows are possible unless the table engine and ingestion model handle them deliberately. This means a source event ID should not automatically become the ClickHouse primary/sorting key just because it is unique. A random/high-cardinality ID often provides poor locality for time- or account-oriented analytical queries. Keep business uniqueness and ClickHouse physical ordering as separate design questions. ## Measure rows and bytes read before tuning CPU Query latency should be interpreted alongside scan volume. A useful diagnosis table is: | Symptom | Likely direction | |---|---| | High rows read, few rows returned | filtering/order-key problem | | Low rows read, high CPU | expensive aggregation/expression/join | | High memory, GROUP BY | cardinality or aggregation strategy | | Good single query, poor concurrent latency | concurrency/resource contention | | Query slowed after data growth | pruning/working-set issue | | Time range reads too much | order key / partition / predicate issue | If a query returns 500 rows but reads 500 million, adding vCPU should not be the first response. Reduce unnecessary reads first. :::cta Explore ClickHouse Run production analytics on Raff Managed ClickHouse while keeping schema and query optimization in your data team. ::: ## PREWHERE can reduce I/O for selective filters ClickHouse can use `PREWHERE` to read filtering columns first and avoid reading other columns for rows that will be discarded. The optimizer can apply PREWHERE automatically in many cases, but query design still matters. Avoid selecting wide unused columns: ```sql SELECT * ``` when a dashboard needs only a few fields. Columnar storage is most efficient when the query reads only the required columns. A narrow projection plus selective filters can reduce both I/O and decompression work substantially. ## Data types affect memory and scan efficiency Choose the narrowest correct types. Examples include: - avoid storing numbers as String; - use appropriate integer widths; - use Date/DateTime types for time; - consider LowCardinality for suitable repeated string dimensions; - avoid unnecessary Nullable use when null semantics are not required. Data type decisions affect: - compressed size; - memory during grouping/joining; - comparison cost; - index effectiveness. Do not change types solely for theoretical savings; validate compatibility and measured query behavior. ## GROUP BY memory follows cardinality and concurrency Aggregations build in-memory state according to grouping dimensions and aggregate functions. A query grouping by a low-cardinality region is very different from grouping by millions of user IDs. Estimate group cardinality before running large production aggregations. Watch: - peak query memory; - number of groups; - concurrent heavy queries; - spill/external aggregation behavior; - result-set size. If the same high-cardinality aggregation runs constantly, a materialized view or pre-aggregated table may be more efficient than repeating it at query time. ## Joins should be sized from the right-hand side and workload ClickHouse supports several join algorithms and can adapt based on settings and memory. For production designs, ask: - how large is each side? - can dimensions be denormalized at ingestion? - is the joined table reused frequently? - does a dictionary or precomputed representation fit? - does join memory fit under concurrency? Do not denormalize everything blindly, but remember that analytical systems often benefit from moving stable relationships into a query-friendly structure. A complex join repeated for every dashboard request can become a better candidate for ingestion-time transformation. ## Materialized views fit repeated expensive aggregations When the same stable aggregation dominates query cost, pre-aggregation can reduce rows and CPU dramatically. Use [ClickHouse Materialized Views](/learn/guides/clickhouse-materialized-views-pre-aggregation-query-trade-offs) when: - query pattern is stable; - aggregate grain is known; - source data can rebuild the result; - added write/storage cost is acceptable. Do not create a materialized view before fixing an obviously poor base-table ordering key. The two optimizations solve different layers. ## Query concurrency can be the bottleneck even when one query is fast Benchmarking one query at a time can hide production contention. Measure representative concurrency: ```text 1 query 10 concurrent queries 50 concurrent queries ``` according to actual workload. Watch how: - p95 latency; - memory; - CPU; - disk throughput; - merge activity; - query failures change as concurrency rises. A query that uses 8 GB of memory comfortably alone may become impossible when ten copies run together. Capacity planning should use the production concurrency model, not only individual query speed. ## Background merges compete with queries for resources ClickHouse performs merges continuously for MergeTree tables. High ingest, too many small parts, TTL work, or mutations can increase background CPU and disk activity. If query latency worsens only during merge pressure, the fix may involve: - larger insert batches; - fewer parts; - scheduling heavy mutations; - storage headroom; - capacity separation. Use [ClickHouse Monitoring](/learn/guides/clickhouse-monitoring-queries-merges-replication-alerts) to correlate foreground query cost with background work. ## Benchmark with realistic data distribution A query benchmark on 1% of production data can choose a completely different execution profile. Use representative: - table size; - time range; - tenant distribution; - high/low-cardinality dimensions; - hot and cold periods; - concurrent load. Record: ```text query pattern rows read bytes read elapsed time memory result rows concurrency ``` Then compare before and after schema or query changes. This produces evidence that survives data growth better than an isolated millisecond result. ## Managed ClickHouse reduces infrastructure tuning, not query design [Raff Managed ClickHouse](/products/managed-databases/clickhouse) reduces the work around database hosts, monitoring, backups, storage expansion, scaling workflows, and optional HA. The data/application team still owns: - `ORDER BY` and primary-key design; - query filters; - selected columns; - joins; - aggregation cardinality; - materialized views; - workload/concurrency behavior. At Raff, the performance rule is: **before resizing ClickHouse, identify how many rows and bytes the important query reads and whether the physical ordering is helping it skip data.** ## Query-performance checklist - [ ] Top query patterns are ranked by business importance and frequency. - [ ] `ORDER BY` matches dominant filters. - [ ] Primary key is treated as sparse-index design, not uniqueness enforcement. - [ ] Rows/bytes read are measured. - [ ] Queries select only required columns. - [ ] Data types fit the workload. - [ ] GROUP BY cardinality and memory are understood. - [ ] Repeated joins are reviewed for denormalization/precomputation. - [ ] Repeated aggregations are evaluated for materialized views. - [ ] Tests include realistic concurrency. - [ ] Merge/mutation pressure is correlated with query latency. - [ ] Capacity increases follow measured resource constraints. ## Conclusion ClickHouse performance tuning begins with physical data access. Design `ORDER BY` around the dominant analytical filters, measure rows and bytes read, then optimize aggregation, joins, memory, and concurrency. Partitioning, materialized views, and larger compute can all help, but they work best after the base table makes important queries read as little unnecessary data as possible. :::cta Explore Managed ClickHouse Use managed infrastructure while keeping ClickHouse physical query design and workload optimization in your data team. ::: ## Sources - [ClickHouse Choosing a Primary Key](https://clickhouse.com/docs/best-practices/choosing-a-primary-key) - [ClickHouse MergeTree](https://clickhouse.com/docs/engines/table-engines/mergetree-family/mergetree) - [ClickHouse Query Optimization](https://clickhouse.com/docs/optimize/query-optimization) - [ClickHouse PREWHERE](https://clickhouse.com/docs/optimize/prewhere) - [Raff Managed ClickHouse](/products/managed-databases/clickhouse) - Sources reviewed: 2026-08-24 --- ### Database Backup Strategy for SaaS Apps: Recovery Framework URL: https://rafftechnologies.com/learn/guides/database-backup-strategy-saas-apps Description: Build a database backup strategy for SaaS apps using RPO, RTO, point-in-time recovery, retention, isolation, disaster recovery, and tested restores. A **database backup strategy** is the recovery plan that defines how production data is captured, retained, isolated, restored, and tested against the application's acceptable data-loss and downtime limits. For a SaaS team, backup is not a checkbox. The real question is whether the team can recover the **right data**, to the **right point in time**, within the required recovery window. Raff supports both managed and self-hosted database models, so the first decision is which recovery responsibilities should stay with your team and which can move into the managed service boundary. A production strategy starts with four things: **RPO, RTO, independent recovery history, and restore testing**. Replication and high availability help keep a database service available. Backups and point-in-time recovery preserve history. Infrastructure snapshots can speed rollback. None replaces the others. :::cluster ## Database backup strategy at a glance | Recovery requirement | Primary control | What it protects | What it does not replace | |---|---|---|---| | Rapid service continuity | HA or replication | Node or service failure | Historical recovery | | Recovery from bad data changes | Backup + PITR | Accidental deletes, bad migrations, corruption | Availability architecture | | Fast infrastructure rollback | VM or volume snapshot | Failed server or storage changes | Database-aware recovery | | Longer recovery history | Multi-point retention | Delayed incident discovery | Restore validation | | Independent failure boundary | Separate retained copies | Host, credential, or control-plane loss | Database consistency | | Recovery confidence | Restore testing | Broken procedures and unrealistic RTO assumptions | Prevention of the original incident | A production strategy should assign each protection layer one clear job. ![Diagram showing production database backup, object storage retention, and restore testing workflow](https://raff-images.s3.raffusercloud.com/database_backup_restore_strategy_flow_webp_bce33ae672.png) ## RPO and RTO should be defined before backup frequency **Recovery Point Objective (RPO)** defines how much recent data the business can afford to lose. **Recovery Time Objective (RTO)** defines how long the database and application can remain unavailable before recovery becomes unacceptable. ![RPO and RTO explainer showing data loss window and recovery time for SaaS database backups](https://raff-images.s3.raffusercloud.com/database_backup_rpo_rto_explainer_webp_62e7d1b9f3.png) The numbers below are illustrative examples, not universal targets: | Objective | Business question | Illustrative example | |---|---|---| | RPO | How much recent data can we lose? | At most 15 minutes of writes | | RTO | How long can the service remain unavailable? | Critical workflows restored within 1 hour | Different targets create different technical requirements. | Recovery target | Practical implication | |---|---| | RPO near 24 hours | A verified daily recovery point may fit a low-change workload | | RPO near 1 hour | More frequent recovery points or transaction-log recovery are needed | | RPO measured in minutes | Continuous WAL/binlog capture or managed PITR becomes important | | RTO of several hours | A documented manual restore may be acceptable | | RTO near 1 hour | Restore, validation, credentials, and traffic cutover need rehearsed steps | | RTO measured in minutes | Availability architecture may be required in addition to backups | Backup frequency does **not** automatically equal RPO. A scheduled job can fail, a recovery point can be unusable, or required transaction logs can be missing. The newest **usable** recovery point must meet the target. RTO is also wider than restore speed. It includes detection, decision-making, replacement infrastructure, data restoration, validation, application reconnect, and returning traffic safely. Use [RPO vs RTO for Cloud Backups](/learn/guides/cloud-server-backup-rpo-rto-snapshots) when the business targets themselves are still unclear. ## Database disaster recovery needs more than one protection layer A **database disaster recovery** design must cover both infrastructure failure and logical data failure. Replication or high availability can help when a database node disappears. They are much less useful when the application successfully commits the wrong data and that change is copied to every healthy replica. A useful recovery model looks like this: ```text Availability -> HA / replication where required Historical recovery -> backups + PITR Infrastructure rollback -> VM / volume snapshots Independent retention -> separate storage or service boundary Recovery evidence -> restore testing ``` Map controls to actual incidents: | Failure scenario | Stronger recovery control | |---|---| | Primary host failure | HA, replica, or replacement path | | Accidental row deletion | PITR or database-aware restore | | Bad schema migration | Verified pre-change recovery point + restore plan | | Database corruption | Independent database recovery history | | VM or disk failure | Database backup plus infrastructure rebuild/recovery | | Compromised production credential | Isolated retained copies with narrower access | | Bug discovered days later | Multi-point retention | | App server loss | Rebuild or VM recovery; not a database backup problem | | User-file loss | Object-storage recovery/versioning policy where applicable | This is why **replication is not backup**, and **snapshots are not a complete database recovery strategy**. For PostgreSQL specifically, see [PostgreSQL Replication vs Backups vs Snapshots](/learn/guides/postgresql-replication-vs-backups-vs-snapshots). ## Managed and self-hosted databases move the recovery boundary The database operating model changes who owns the recovery platform. | Responsibility | Managed database | Self-hosted database | |---|---|---| | Backup infrastructure | Provider operates within service scope | Your team designs and operates it | | Host patching | Provider scope | Your team | | PITR tooling | Service capability when supported | Your team configures and monitors it | | Backup monitoring | Provider baseline + customer oversight | Your team | | Retention configuration | Within service capabilities | Your team designs it | | Restore-point selection | Customer | Customer | | Restore validation | Customer | Customer | | Schema and migration safety | Customer | Customer | | Application cutover after recovery | Customer | Customer | A managed service can reduce repetitive platform work, but it cannot decide whether a restored data state is correct for your application. For self-hosted PostgreSQL, a common historical recovery path combines physical backups with WAL retention when PITR is required. MySQL can use database-aware backups plus binary logs for point-in-time recovery. The correct method is the one that can satisfy the required RPO and RTO at the current data size. If your workload fits a managed service, compare [Raff Managed Databases](/products/managed-databases). For engine-specific decisions, see [Postgres Hosting](/learn/guides/postgresql-hosting-for-saas) and [MySQL Hosting](/learn/guides/mysql-hosting-managed-vs-self-hosted). :::cta Deploy a Database Now Build your recovery path. ::: ## Retention protects against incidents discovered late Keeping only the newest backup is not enough. A bug may overwrite data on Monday but remain unnoticed until Friday. A destructive migration can appear successful until an older workflow is used. A compromised credential can modify data repeatedly over several days. In all of these cases, the newest backup may already contain the damage. Retention should preserve multiple useful recovery points. Depending on business risk, this can include: - frequent recent recovery points for short RPO; - daily points for recent history; - longer weekly or monthly retention where justified; - explicit pre-migration recovery points; - separate policies for production and non-production data; - retention long enough to cover realistic incident-detection delays. Do not copy a generic retention schedule without connecting it to actual business risk, data sensitivity, and recovery needs. ## Backup isolation reduces shared failure risk A backup stored only on the database host shares the same infrastructure failure boundary. A recovery copy removable by the same broad production credentials can share the same security failure boundary. For self-hosted databases, a separate storage target can provide a useful boundary for database dumps or compatible backup artifacts. [Raff Object Storage](/products/object-storage) can serve as an S3-compatible destination where the backup tooling supports object storage. But moving a backup file to object storage is not enough by itself. The recovery chain still needs: - successful backup completion; - integrity or consistency checks appropriate to the engine; - credentials that remain available during recovery; - retention controls; - a documented restore process; - a tested application recovery path. For VM-level protection, [Raff Data Protection](/products/data-protection) provides infrastructure backup and snapshot workflows. Keep VM-level protection separate from database-native recovery: one protects infrastructure state, while the other protects recoverable database history. Current Raff Data Protection pricing is **$0.06/GB-month for snapshots** and **$0.06/GB-month for backup storage above the free pool**. Backup retention can be configured from **1 to 365 days**. These controls complement database-aware recovery rather than replacing it. ## Restore testing proves whether the backup strategy works A backup that has never been restored is an unverified recovery option. A useful restore test follows the complete path: ```text Choose recovery point -> restore into isolated target -> start database -> validate schema and known records -> connect the application safely -> run critical read/write checks -> measure recovered data age -> measure total recovery time -> document gaps ``` The age of the recovered data validates the practical RPO. The time until critical workflows operate again validates the practical RTO. A database service starting successfully is not enough. The test should verify: - expected schemas and objects; - known records for the chosen recovery point; - application credentials; - migration state; - critical read flows; - a safe write in the isolated environment; - related object files if the application depends on them; - application reconnect behavior; - the total elapsed recovery time. Restore tests should run away from production when possible. A recovered test environment should not send live emails, charge payments, trigger customer webhooks, or run production scheduled jobs. **Operational insight from Raff:** recovery reviews separate backup success from restore evidence. A green backup job does not prove that credentials, dependencies, application validation, and traffic cutover will work during an incident. Assign a named recovery owner and record measured recovery time instead of assuming the backup schedule proves readiness. Use [Restore Testing Checklist for Production VMs](/learn/guides/restore-testing-checklist-production-vms) for the broader infrastructure validation path. ## Database migrations require an explicit recovery decision High-risk schema or data migrations should not begin until the team knows how recovery would work. Before the change, document: - which recovery point will be used if rollback is required; - whether the backup or PITR chain is current; - whether the required transaction logs are retained; - expected restore duration; - how the application behaves against the restored schema; - what happens to writes created after the chosen recovery point; - who has authority to stop the migration and recover. A pre-change VM or volume snapshot can provide useful short-term rollback for a self-hosted database, but it should not replace a database-aware recovery path. An application rollback also does not automatically reverse a schema or data migration. For managed databases, confirm the required recovery coverage before the change. For self-hosted databases, confirm that the recovery artifacts exist outside the database host and that the restore process is understood. ## Monitoring should include recovery readiness, not only database health Most production dashboards focus on CPU, memory, storage, query latency, and availability. A recovery strategy needs operational signals too. Useful recovery-readiness checks include: - age of the newest usable backup; - last successful backup completion; - WAL or binary-log archive health where PITR is required; - retention status; - backup-storage capacity; - replication lag where HA is used; - time since last successful restore test; - measured restore duration from the last test; - credential or permission failures affecting recovery paths. A database can be healthy today while its recovery path has silently degraded for weeks. ## Raff supports managed and self-hosted recovery paths ![Architecture diagram showing Raff VM, Managed Database, Object Storage, and restore testing for SaaS backups](https://raff-images.s3.raffusercloud.com/raff_saas_database_backup_architecture_webp_b8feecccae.png) For teams that want a smaller operational surface, [Raff Managed Databases](/products/managed-databases) provides managed database workflows for supported engines. Current backup, PITR, retention, HA, engine availability, and plan limits should be verified on the live product pages and console before production design. A managed path can look like: ```text Application -> private or restricted connection Raff Managed Database -> managed backup/recovery platform -> customer validates restored state and application cutover ``` A self-hosted path can look like: ```text Application VM -> private network Database VM -> database-aware backups -> separate retained recovery storage -> isolated restore test ``` Use a [Raff VM](/products/raff-vm) when the workload needs host-level database control and your team can own backup monitoring, PITR configuration, retention, restore testing, patching, and incidents. Use [Raff Object Storage](/products/object-storage) where compatible backup artifacts need an independent S3-compatible destination. Use [Raff Data Protection](/products/data-protection) for VM-level snapshots and backup workflows. Keep these infrastructure controls distinct from engine-native database recovery. ## Database backup strategy checklist Before calling the recovery design production-ready, confirm: 1. Business **RPO** is documented. 2. Business **RTO** is documented. 3. Backup type matches the database engine and recovery objective. 4. PITR logs are retained when point-in-time recovery is required. 5. More than one useful recovery point is retained. 6. Critical copies do not share every failure and credential boundary with production. 7. Restore credentials and procedures are available during an incident. 8. Migration recovery is defined before risky changes. 9. Backup and archive health are monitored. 10. A full restore has been tested recently enough to represent the current architecture. 11. Recovered data age has been measured against RPO. 12. End-to-end recovery time has been measured against RTO. 13. Application validation and traffic cutover are part of the runbook. ## Conclusion A SaaS database backup strategy should begin with the failure the business needs to survive. Define RPO and RTO first, then choose database-aware backups, PITR, retention, isolation, availability controls, infrastructure recovery points, and restore tests that satisfy those targets. Managed databases can reduce the amount of recovery infrastructure your team operates, but the application team still owns restore-point selection, data validation, safe migrations, credentials, and application cutover. Self-hosting provides deeper control but transfers the complete recovery chain to your team. The most useful evidence is not a green backup job. It is a successful restore with measured data age and measured recovery time. Continue with [PostgreSQL Replication vs Backups vs Snapshots](/learn/guides/postgresql-replication-vs-backups-vs-snapshots), [Managed vs Self-Hosted Databases](/learn/guides/managed-vs-self-hosted-databases), or [VPS Database Hosting](/learn/guides/vps-for-databases) for the next architecture decision. ## Sources - [PostgreSQL: Backup and Restore](https://www.postgresql.org/docs/current/backup.html) - [PostgreSQL: Continuous Archiving and Point-in-Time Recovery](https://www.postgresql.org/docs/current/continuous-archiving.html) - [MySQL: Backup and Recovery](https://dev.mysql.com/doc/refman/8.4/en/backup-and-recovery.html) - [NIST SP 800-34 Rev. 1](https://csrc.nist.gov/pubs/sp/800/34/r1/final) - [Raff Managed Databases](/products/managed-databases) - [Raff Object Storage](/products/object-storage) - [Raff Data Protection](/products/data-protection) - Product and pricing details reviewed: 2026-09-17. --- ### Database Hosting Services: How to Choose for Production Apps URL: https://rafftechnologies.com/learn/guides/database-hosting-services-production-apps Description: Compare database hosting services for production apps by engine support, backups, PITR, HA, private networking, connections, pricing, migration, and support. A **database hosting service** gives an application a remote database endpoint without requiring the application team to own every layer of the database host. For production use, the important differences between providers are **recovery, availability, networking, scaling, pricing, migration support, and what the provider actually operates after deployment**. Raff offers managed PostgreSQL, MySQL, Valkey, ClickHouse, and Kafka, while teams that need host-level control can self-host a database on [Raff VM](/products/raff-vm). If you are still deciding between those operating models, start with [Managed Database vs Self-Hosted](/learn/guides/managed-vs-self-hosted-databases). This guide assumes you want database hosting and focuses on **how to evaluate the service itself**. ## A production database hosting service should cover the full lifecycle A production database hosting service should provide more than a running PostgreSQL, MySQL, Valkey, ClickHouse, Kafka, or another database process. Evaluate whether the service provides: - supported database engines and versions; - clear compute, memory, and storage sizing; - backups and a documented restore path; - point-in-time recovery where supported; - monitoring and query visibility; - TLS and access controls; - private networking options; - storage expansion; - high availability or replica options; - maintenance and version-upgrade policy; - migration support; - predictable billing. A database can be easy to create and still be difficult to operate safely. The buyer decision should focus on the **production lifecycle**, not only provisioning speed. ## Database hosting and ordinary web hosting solve different problems The phrase "database hosting" is used for several different products. | Hosting model | What you get | Typical fit | |---|---|---| | Shared web-hosting database | Database bundled with a website plan | Small websites with limited database requirements | | Database on a VM/VPS | Full host and database control | Teams that need root access or custom configuration | | Managed database service | Database endpoint plus provider-operated platform tasks | Production apps that want lower operational overhead | | Serverless database | Usage-based or autoscaling database abstraction | Variable workloads where the engine and service model fit | For most production SaaS and business applications, the practical comparison is between a **managed database service** and operating the database directly on a VM. This page focuses on the managed-service buyer decision. For VM-based database hosting, use [VPS Database Hosting](/learn/guides/vps-for-databases). ## Engine fit should come before provider branding Choose the database engine before comparing provider features. | Workload | Common starting engine | |---|---| | General SaaS or transactional application | PostgreSQL | | Existing MySQL ecosystem, WordPress, or Laravel workloads | MySQL | | Cache, sessions, queues, or rate limits | Valkey or Redis-compatible | | Analytical workloads | ClickHouse | | Streaming or event backbone | Kafka | | Document-oriented workloads | MongoDB | The provider should support the engine version and capabilities your application actually uses. Check: - exact major version; - required extensions or plugins; - collations and character sets; - connection protocol and client compatibility; - replication or HA model; - supported backup and recovery features; - migration path from the current database. Do not choose a provider first and then force the application into whichever engine happens to be easiest to buy. :::cluster ## Backups are useful only when the restore path is understood A database hosting service should explain both **how backups are created** and **how recovery works**. Ask: 1. How often are backups created? 2. How long are they retained? 3. Is point-in-time recovery available? 4. Can you restore to a new database without overwriting production? 5. What is the expected restore workflow? 6. Are backups included in the plan price? 7. Is restore testing supported? For a transactional production database, the recovery conversation should include: - **RPO:** how much recent data the business can lose; - **RTO:** how long recovery may take; - historical recovery after accidental changes; - restore validation; - application reconnect behavior. Replication does not replace backups. If an accidental delete or destructive migration reaches the primary database, replicas can reproduce the same change. Use [Database Restore Testing](/learn/guides/database-restore-testing-rpo-rto-recovery-validation) for a deeper recovery framework. ## High availability should describe failure behavior clearly "High availability" can mean different things across services. Ask what happens when the primary database node fails: - Is there a standby or replica? - Is failover automatic? - Does the application endpoint remain the same? - How much data can be lost during failover? - How long does promotion normally take? - Is the standby synchronous or asynchronous? - How is HA priced? - Is failover tested by the provider? A buyer should be able to describe the failure path before enabling HA. For a small team, a simpler HA model with a clear responsibility boundary can be easier to operate than a topology with more configuration but unclear ownership. ## Private networking should be part of the production design A production database normally should not require broad public exposure. A common architecture is: ```text Internet ↓ HTTPS Application ↓ private network Managed database ``` Evaluate whether the database hosting service supports: - private endpoints or VPC connectivity; - TLS for external connections; - IP allowlists; - scoped database credentials; - credential rotation; - connection auditing or access visibility. Private networking reduces unnecessary public routing but does not replace database authentication, least privilege, or TLS requirements. If your application runs on Raff, [Raff VPC](/products/vpc) provides a private-network path between supported services and compute resources. ## Connection limits can be a production bottleneck A database hosting plan can have enough compute and still fail because application connections are exhausted. Estimate total demand across all processes: ```text application replicas × pool size + background workers + scheduled jobs + migrations + admin sessions + monitoring = possible connection demand ``` Ten application replicas with a pool of 20 connections can create **200 possible database connections** before workers or administrative sessions are counted. When evaluating a provider, ask: - connection limit per plan; - whether pooling is included; - whether a proxy or pooler costs extra; - how scaling affects connection limits; - whether idle connections can be controlled; - how maintenance or failover affects client reconnects. The useful plan is the one whose resource and connection model matches the application, not simply the one with the largest RAM number. ## Storage cost should include growth, backups, and operational headroom Database storage needs capacity for more than table data. Plan for: ```text data + indexes + transaction logs / WAL / binary logs + temporary work + migrations + backup and recovery overhead + expected growth ``` When comparing database hosting cost, check whether the advertised price includes: - base storage; - storage expansion; - IOPS or performance tiers; - backups; - backup overage; - snapshots where applicable; - network transfer; - HA standby resources; - monitoring or query insights. A low base price can become a larger production bill when critical capabilities are separate line items. ## Predictable pricing is part of the production decision Database hosting cost usually follows one of three models: | Pricing model | Strength | Trade-off | |---|---|---| | Fixed plan sizes | Easier budgeting | Can overprovision intermittent workloads | | Usage-based or serverless | Can fit variable workloads | Monthly cost can be harder to predict | | Component-based | Fine-grained control | Compute, storage, I/O, transfer, proxies, and backups can become separate charges | Before choosing a provider, model the expected production bill with: - required RAM and vCPU; - required storage; - HA enabled if needed; - backup retention; - network transfer; - connection pooling or proxy; - monitoring; - expected growth. Raff paid PostgreSQL, MySQL, and Valkey plans start at **$7.99/month**. Current paid ClickHouse plans start at **$59.99/month**, while Kafka starts at **$79.99/month**. Use the live [pricing page](/pricing) before purchase because plan sizes and commercial terms can change. ## Migration support can reduce switching risk The difficult part of changing database hosts is often not provisioning the new database. It is moving production data safely. A useful provider migration path should address: - source and target engine versions; - baseline data copy; - ongoing-write synchronization when needed; - replication or change-capture compatibility; - final cutover; - validation; - rollback; - application endpoint changes. Ask whether migration support is included, paid, self-service, or documentation-only. For important production databases, migration assistance can reduce switching risk and engineering time. Use [Database Migration Checklist for Managed Databases](/learn/guides/managed-database-migration-checklist) before moving a production workload. **Customer pattern from Raff:** in small-team infrastructure discussions, database hosting decisions usually become clearer once recovery ownership and peak connection demand are written down before comparing plans. :::cta Deploy a Database Now Try managed databases free. ::: ## Support quality matters during incidents and migrations Database hosting is an infrastructure product, so support quality should be evaluated around failure conditions rather than sales responsiveness. Ask: - Can you reach a real engineer? - Is support ticket-only? - Is migration help available? - Can support help explain failover or restore workflows? - Is there an SLA? - How are incidents communicated? - Can the team explain which layer is provider-owned and which remains customer-owned? A provider should not promise to optimize your schema or application automatically. It should be clear who owns the database host, backups, maintenance, failover platform, and service-level incident response. ## Free database hosting is useful for compatibility testing Free database hosting can be valuable for: - testing an ORM or driver; - validating engine compatibility; - development and staging; - prototyping migrations; - evaluating provider UX and networking. It should not be treated as proof that the production plan will satisfy recovery objectives, connection demand, storage growth, availability requirements, or support needs. Raff currently provides permanent free tiers for three managed engines: | Engine | Free tier | Main ceiling | |---|---|---| | PostgreSQL | $0/month, 1 vCPU, 1 GB RAM, 2 GB storage | 60 direct connections, 200 pooled connections | | MySQL | $0/month, 1 vCPU, 1 GB RAM, 2 GB storage | 60 connections | | Valkey | $0/month, 512 MB memory, 2 GB storage | 500 connections | ClickHouse and Kafka do not currently have free tiers. Use the free tier to validate the application path, then size production from actual memory, storage, connection, recovery, and availability requirements. ## A provider comparison matrix should use workload-specific requirements Instead of assigning arbitrary universal weights, classify each requirement by how important it is to your workload. | Requirement | What to verify | Your priority | |---|---|---| | Engine and version fit | Exact engine, version, extensions, protocol | Required / preferred / optional | | Recovery | Backups, PITR, restore workflow, retention | Required / preferred / optional | | Availability | HA topology, failover behavior, endpoint continuity | Required / preferred / optional | | Networking and security | Private access, TLS, allowlists, credential controls | Required / preferred / optional | | Cost predictability | Full production estimate, storage, HA, transfer | Required / preferred / optional | | Scaling and connections | Compute growth, storage growth, connection ceilings | Required / preferred / optional | | Migration and support | Migration assistance, rollback support, escalation path | Required / preferred / optional | A requirement marked "required" should act as a gate. A provider that misses it should not compensate by scoring higher on a less important feature. ## Raff's managed database path is designed for a clear operating boundary [Raff Managed Databases](/products/managed-databases) currently supports **PostgreSQL, MySQL, Valkey, ClickHouse, and Kafka**. The platform also gives teams an alternative operating model. If the workload needs root access, custom packages, direct filesystem control, or a topology outside the managed-service boundary, the engine can run directly on [Raff VM](/products/raff-vm). A practical decision path is: ```text Want provider-operated database platform tasks -> Raff Managed Databases Need host-level database control -> self-host on Raff VM ``` The commercial decision should still be made from the workload: engine compatibility, recovery, connection demand, availability, storage growth, migration risk, and operating responsibility. ## Production database hosting checklist Before choosing a database hosting service, confirm: - [ ] Required engine and version are supported. - [ ] Extensions or plugins are compatible. - [ ] Backup frequency and retention are documented. - [ ] PITR requirements are met where applicable. - [ ] Restore workflow has been tested or demonstrated. - [ ] HA failure behavior is understood. - [ ] Private networking is available where required. - [ ] TLS and access controls are supported. - [ ] Connection limits fit maximum application scale. - [ ] Pooling or proxy requirements and cost are clear. - [ ] Storage growth and expansion pricing are known. - [ ] Backup, transfer, monitoring, and HA fees are included in TCO. - [ ] Migration and rollback path is documented. - [ ] Support escalation path is clear. - [ ] Production cost can be estimated before launch. ## Database hosting services should be compared by production responsibility A database hosting service should be evaluated by **engine support, recovery, availability, networking, scaling, pricing, migration support, and the responsibility boundary after deployment**. Start with exact engine compatibility. Then compare the complete production configuration: backups, PITR, HA, storage growth, connection limits, private networking, migration, support, and the expected monthly cost. For Raff, permanent free PostgreSQL and MySQL tiers provide a $0 path for compatibility testing, while paid PostgreSQL, MySQL, and Valkey plans start at $7.99/month. Use [Managed Databases](/products/managed-databases) when you want more database-platform operations handled by the provider, or [Raff VM](/products/raff-vm) when host-level control is a hard requirement. ## Sources - [PostgreSQL: Backup and Restore](https://www.postgresql.org/docs/current/backup.html) - [PostgreSQL: High Availability](https://www.postgresql.org/docs/current/high-availability.html) - [MySQL: Backup and Recovery](https://dev.mysql.com/doc/refman/8.4/en/backup-and-recovery.html) - [MySQL: Replication](https://dev.mysql.com/doc/refman/8.4/en/replication.html) - [Raff Managed Databases](/products/managed-databases) - [Raff Managed PostgreSQL](/products/managed-databases/postgresql) - [Raff Managed MySQL](/products/managed-databases/mysql) - [Raff Managed Valkey](/products/managed-databases/valkey) - [Raff Managed ClickHouse](/products/managed-databases/clickhouse) - [Raff Managed Kafka](/products/managed-databases/kafka) - [Raff Pricing](/pricing) - Product and pricing details reviewed: 2026-09-17. Verify live product pages before relying on current pricing, limits, HA behavior, or migration support. --- ### Database Migration Checklist for Managed Databases URL: https://rafftechnologies.com/learn/guides/managed-database-migration-checklist Description: Use this database migration checklist to assess compatibility, prepare the target, prove recovery, synchronize data, control cutover, validate production, and plan rollback. A **database migration checklist** is a control framework for moving production data from one database environment to another without losing track of compatibility, recovery, write authority, validation, and rollback. For most small teams, the practical plan has six phases: **assess the source, prepare the target, prove recovery, move and synchronize data, perform a controlled cutover, then validate before retiring the source**. The copy itself is only one part of the project. At **Raff**, teams can migrate supported workloads into [Managed Databases](/products/managed-databases) when they want to reduce host-level database operations, or continue on [Raff VM](/products/raff-vm) when the workload requires operating-system or filesystem control. If PostgreSQL or MySQL is already selected, review the live [Managed PostgreSQL](/products/managed-databases/postgresql) and [Managed MySQL](/products/managed-databases/mysql) pages before planning production compatibility around a specific feature or version. This guide owns the **migration checklist and go/no-go process**. For synchronization, expand-contract schema changes, staged backfills, and low-downtime cutovers, use [Zero-Downtime Database Migrations](/learn/guides/zero-downtime-database-migrations-small-teams). ## The migration checklist has six control gates | Phase | Main question | Evidence required before continuing | |---|---|---| | 1. Assess | Is the target compatible with the real workload? | Engine/version, extensions, clients, dependencies, data size, write rate | | 2. Prepare | Is the target production-ready? | Networking, credentials, capacity, backups, monitoring, connection model | | 3. Prove recovery | Can the team recover if migration fails? | Tested source recovery point, rollback owner, RPO/RTO | | 4. Move and sync | Is the target complete and current enough? | Transfer logs, counts/checks, synchronization health, lag threshold | | 5. Cut over | Which database is authoritative now? | Go/no-go approval, final sync, endpoint switch, write control | | 6. Validate | Can the application safely stay on the target? | Business workflows, data checks, jobs, integrations, backups, monitoring | A migration should not advance because the previous command completed. It should advance because the evidence for the next risk boundary exists. ## 1. Start the migration plan with the target state Before choosing export/import, replication, change data capture, or another migration method, document what production should look like after the move. Record: - source engine and version; - target engine and version; - required extensions, plugins, collations, and character sets; - application runtime and database drivers; - stored procedures, triggers, generated columns, scheduled events, or database jobs; - users, roles, and permission model; - current data size and expected growth; - peak write rate; - peak connection demand; - connection pooling behavior; - application-to-database network path; - backup and point-in-time recovery requirements; - monitoring and alert ownership; - availability requirements; - maintenance expectations; - migration owner; - go/no-go approver; - rollback approver. This is where provider compatibility should be checked. For Raff, use the live Managed PostgreSQL or Managed MySQL page and console as the source of truth for current engine availability, supported capabilities, networking, backup and recovery behavior, connection model, limits, and optional availability features. Do not build a production migration around engine versions or product limits copied from an older guide. A target is compatible only when the **application, data model, operational requirements, and recovery path** all fit. ## 2. Inventory every database client before data moves The main web application is rarely the only client of a production database. Inventory every reader and writer: - web or API application instances; - background workers; - scheduled jobs; - queue consumers; - reporting services; - analytics or ETL jobs; - admin tools; - migration tools; - monitoring accounts; - integration services; - operations scripts. Then record how each client discovers and authenticates to the database: | Client dependency | What to record | |---|---| | Endpoint | Hostname, DNS, direct or pooled endpoint, port | | Credentials | Secret location, role, rotation path | | TLS | Required mode, certificate assumptions | | Pooling | Pool size, recycle behavior, timeout | | Network | VPC/private path, firewall, allowlist | | Deploy behavior | How config changes reach running processes | | Reconnect | Whether the client caches connections or endpoints | A migration can copy every row correctly and still fail because one worker continues writing to the old source or one long-lived pool never reconnects. The checklist should track **clients**, not only database objects. ## 3. Choose the migration method from downtime and rollback requirements Use the least complex method that satisfies the business requirement. | Migration condition | Practical starting method | Main trade-off | |---|---|---| | Small database, maintenance window acceptable | Logical export/import | More downtime, simpler authority and rollback | | Same engine, shorter interruption required | Baseline copy plus ongoing synchronization | More synchronization, lag, and rollback complexity | | Provider-to-provider move | Export/import or supported replication path | Feature and endpoint differences | | Major-version change | Tested supported upgrade or logical migration | Compatibility validation required | | Cross-engine migration | Logical transformation plus application changes | Highest compatibility and validation scope | | Large, write-heavy workload | Baseline plus change synchronization plus controlled cutover | Requires strong lag, consistency, and rollback controls | A maintenance window is not a migration failure. For a small team, a planned write interruption can be safer than a replication and failback system the team cannot operate confidently. Use [Zero-Downtime Database Migrations](/learn/guides/zero-downtime-database-migrations-small-teams) when the business requirement justifies staged synchronization, expand-contract, dual compatibility, or near-zero-downtime techniques. :::cluster ## 4. Prove source recovery before changing production authority A current backup is necessary. A **tested recovery path** is stronger evidence. Before migration day, define: - approved RPO; - approved RTO; - newest usable recovery point; - expected restore duration; - source retention after cutover; - rollback deadline; - person authorized to restore or roll back; - application validation required after recovery. At minimum, confirm that the recovery path can return a usable copy of the source database and that the application can connect to it in an isolated environment. A recovery test should answer: 1. Can the backup or recovery chain actually be restored? 2. Are the expected schemas, roles, permissions, and extensions present? 3. Can the application authenticate? 4. Are critical records available? 5. Does the measured recovery time fit the migration's rollback assumptions? A backup job marked successful does not prove that the rollback path will work under production pressure. Use [Database Backup Strategy for SaaS Apps](/learn/guides/database-backup-strategy-saas-apps) and [Database Restore Testing](/learn/guides/database-restore-testing-rpo-rto-recovery-validation) for the broader recovery framework. ## 5. Make the target production-ready before the copy starts Provisioning the target is not the same as preparing it for cutover. Verify: - target engine and version compatibility; - required extensions and features; - schema compatibility; - storage capacity and growth headroom; - connection limits; - connection pooling path; - TLS requirements; - users and roles; - private networking or scoped public access; - application credentials; - backup and recovery configuration; - monitoring and alerts; - availability settings where required; - maintenance expectations; - application configuration for the new endpoint. Then run representative application tests against the target before migration day where possible: - authentication; - critical reads; - critical writes; - transactions; - background jobs; - reports; - migration framework operations; - connection-pool behavior; - reconnect after connection interruption; - application startup with the target endpoint. A SQL connection succeeding proves connectivity. It does not prove production compatibility. Raff's PostgreSQL and MySQL free tiers start at **$0/month**, which gives teams a low-cost target for early application-compatibility checks. :::cta Deploy a Database Now Create the target, then validate migration readiness. ::: ## 6. Separate baseline transfer from ongoing synchronization For low-downtime migrations, treat the initial copy and ongoing-change synchronization as different operating phases. ```text Source database -> baseline copy Target database -> ongoing synchronization Lag + consistency reach approved cutover state -> final write-control phase -> target becomes authoritative ``` During the baseline transfer, record: - transfer start and finish time; - source data size; - target data size; - row or object counts where useful; - excluded objects; - failed objects; - schema differences; - transfer errors or retries. During synchronization, monitor: - replication or change-capture health; - current lag; - lag trend; - retained source logs; - schema compatibility; - target write capacity; - network stability; - unsupported objects or DDL changes; - synchronization errors. Do not cut over because a synchronization process is merely "running." Define what **ready for cutover** means before migration day. Examples of readiness criteria include: - no unresolved synchronization errors; - lag below the agreed threshold; - required objects validated; - source backup and recovery current; - target monitoring active; - application change prepared; - rollback owner available. **Operational insight from Raff:** treat replication lag, recovery readiness, and write authority as separate cutover gates rather than one "replication is running" signal. ## 7. Freeze risky change before the cutover window Migration risk increases when the application schema, source database, and target database all change at once. Before the final window, define a temporary change policy for: - schema migrations; - extension or plugin changes; - large imports; - index rebuilds; - bulk jobs; - major application deployments; - credential rotation; - network changes. This does not mean the whole business must stop changing for days. It means the migration window should not overlap avoidable structural changes that can invalidate compatibility or synchronization assumptions. ## 8. Use an explicit go/no-go checkpoint Immediately before cutover, the migration owner should be able to answer these questions with evidence: - Is the source recovery path current? - Is the target healthy? - Are synchronization errors resolved? - Is lag within the approved threshold? - Have schema and dependency checks passed? - Are all application clients accounted for? - Are the endpoint and credentials ready? - Are monitoring and alerts active on the target? - Is the rollback path still practical? - Are the go/no-go and rollback approvers available? If a condition is unknown, treat it as a decision risk rather than assuming it is safe. ## 9. Keep one authoritative database during cutover The most important database migration rule is simple: > **At every stage, the team should know which database is authoritative for new writes.** A controlled cutover can look like this: | Phase | Authoritative system | Write behavior | |---|---|---| | Before cutover | Source | Normal production writes | | Final synchronization | Source | Writes controlled according to migration plan | | Endpoint switch | Transition explicitly owned | Prevent accidental split authority | | After switch | Target | Approved clients write to target | | Rollback window | Defined in runbook | Source and target write policy remains explicit | A practical sequence is: 1. Confirm go/no-go evidence. 2. Freeze or control writes according to the plan. 3. Let final synchronization complete. 4. Run final database consistency checks. 5. Switch application endpoint, secrets, or configuration. 6. Recycle clients or pools that retain old connections. 7. Verify target reads. 8. Verify controlled target writes. 9. Verify workers, jobs, integrations, and reporting clients. 10. Declare the target authoritative. 11. Start the rollback observation window. Avoid a period where some systems write to the source and others write to the target without an explicit reconciliation design. ## 10. Validate business correctness, not only row counts Database-level validation should include relevant technical checks such as: - expected schemas and tables; - key row or object counts; - recent records; - primary and foreign keys; - indexes; - sequences or auto-increment state; - users and permissions; - extensions or plugins; - representative checksums or samples where useful. Application validation should include the business workflows that matter: - sign-in; - tenant or account lookup; - critical create or update flow; - billing or subscription lookup where applicable; - background workers; - scheduled jobs; - integrations; - reports and exports; - connection-pool behavior; - latency and error rates. The provider can help prove database state. The application team is usually the only party that can prove whether migrated data is **correct for the business**. ## 11. Rollback needs a trigger, deadline, and write policy "Keep the old database online" is not a complete rollback plan. Document: - conditions that trigger rollback; - rollback approver; - rollback deadline; - endpoint-switch method; - source state during the observation window; - whether the source remains read-only or writable; - how target-only writes will be handled; - how divergence will be detected; - when rollback becomes impractical; - when the old source can be retired. Useful rollback triggers can include: - sustained application error rate above the agreed threshold; - critical workflow failure; - unresolved data mismatch; - missing required database capability; - unacceptable latency; - connection exhaustion; - failed workers or integrations; - inability to meet an agreed recovery objective. Rollback becomes harder after the target begins accepting new writes. The runbook should explain what happens to those writes if the source must become authoritative again. ## 12. Managed databases change the operating boundary after migration Migrating to a managed database changes who operates parts of the database platform, but it does not transfer application responsibility. Use the live Raff Managed Databases and engine-specific product pages to verify the current provider-managed scope before cutover. Depending on the selected service and current capabilities, the managed platform can reduce work around: - database host provisioning; - platform maintenance; - managed backup and recovery workflows; - service monitoring; - storage operations; - supported availability features; - private connectivity. The application team still owns: - schema and data model; - queries and indexes; - application credentials; - migrations; - connection pooling behavior; - capacity decisions; - recovery-point selection where applicable; - application reconnect behavior; - business validation; - cutover and rollback decisions. Teams that need operating-system access, custom packages, unsupported extensions or topology, or another hard host-level requirement can use [Raff VM](/products/raff-vm) instead of forcing the workload into a managed service. For teams evaluating provider help rather than only the execution checklist, continue with [Database Migration Services: Costs, Process & Provider Checklist](/learn/guides/database-migration-services-provider-checklist). ## The production checklist should be signed off before source retirement ### Discovery - [ ] Source engine and version are documented. - [ ] Target engine and version are confirmed from the live service. - [ ] Required extensions, plugins, and collations are compatible. - [ ] All application readers and writers are inventoried. - [ ] Data size, write rate, and growth are measured. - [ ] Peak connection demand is understood. - [ ] Migration owner, go/no-go approver, and rollback approver are assigned. ### Recovery - [ ] RPO and RTO are documented. - [ ] Current source recovery point exists. - [ ] Restore path has been tested. - [ ] Restore duration is known. - [ ] Source retention after cutover is defined. - [ ] Rollback deadline is documented. ### Target readiness - [ ] Networking is configured. - [ ] TLS and access controls are validated. - [ ] Users and roles exist. - [ ] Storage and capacity headroom are sufficient. - [ ] Connection limits and pooling fit application demand. - [ ] Monitoring and alerts are active. - [ ] Backup and recovery behavior is understood. - [ ] Representative application tests pass. ### Data movement - [ ] Baseline transfer completed without unexplained omissions. - [ ] Transfer errors and retries are reviewed. - [ ] Data and schema checks are recorded. - [ ] Ongoing synchronization is healthy when used. - [ ] Cutover lag threshold is defined. - [ ] Schema-change freeze is active for the required window. ### Go/no-go - [ ] Source recovery is current. - [ ] Target health is confirmed. - [ ] Synchronization errors are resolved. - [ ] Lag is inside the approved threshold. - [ ] Endpoint or configuration change is ready. - [ ] Every database client has a cutover owner. - [ ] Rollback remains practical. ### Cutover - [ ] Write authority is explicit. - [ ] Final synchronization completes. - [ ] Final data checks pass. - [ ] Endpoint, secrets, and configuration are switched. - [ ] Long-lived clients and pools are recycled where required. - [ ] Critical reads succeed. - [ ] Controlled writes succeed. - [ ] Workers, jobs, and integrations use the target. - [ ] Target is formally declared authoritative. ### Validation and completion - [ ] Business-critical workflows pass. - [ ] Error rate and latency are acceptable. - [ ] Target backups and recovery are verified. - [ ] Monitoring reflects the target environment. - [ ] Rollback observation window is completed. - [ ] Temporary migration credentials and access are removed. - [ ] Documentation and runbooks are updated. - [ ] Source retirement is approved before deletion. ## Common migration mistakes create authority and recovery gaps ### Treating the migration as a data-copy job A complete migration also changes endpoints, credentials, recovery, monitoring, application behavior, and operational ownership. ### Assuming a managed target is automatically compatible Verify the exact engine, features, extensions, connection behavior, networking, and recovery requirements against the live target service. ### Cutting over because replication is running Use measurable readiness conditions such as lag, errors, validation, and recovery status. ### Testing only row counts Business workflows, permissions, sequences, jobs, integrations, and connection behavior can fail even when broad counts match. ### Keeping both databases writable without an authority rule This can create divergence that turns rollback into a data-reconciliation incident. ### Retiring the source immediately Keep the source according to the documented rollback and retention plan until the team has enough evidence to decommission it safely. ## A safe migration ends after recovery and rollback controls are proven A database migration checklist should control **compatibility, recoverability, authority, validation, and rollback** from the first assessment through source retirement. Prepare the target before data moves. Prove the source recovery path before cutover. Use measurable synchronization and go/no-go criteria. Keep one authoritative writer. Validate application behavior after the switch, and retire the source only after the rollback window and recovery controls are confirmed. For Raff Managed PostgreSQL or MySQL migrations, use the live product pages and console to confirm current compatibility and service capabilities before the final production cutover. If the broader operating model is still undecided, return to [Managed Database vs Self-Hosted](/learn/guides/managed-vs-self-hosted-databases). ## Sources - [PostgreSQL: Backup and Restore](https://www.postgresql.org/docs/current/backup.html) - [PostgreSQL: Logical Replication](https://www.postgresql.org/docs/current/logical-replication.html) - [MySQL 8.4: Replication](https://dev.mysql.com/doc/refman/8.4/en/replication.html) - [MySQL 8.4: Backup and Recovery](https://dev.mysql.com/doc/refman/8.4/en/backup-and-recovery.html) - [Raff Managed Databases](/products/managed-databases) - [Raff Managed PostgreSQL](/products/managed-databases/postgresql) - [Raff Managed MySQL](/products/managed-databases/mysql) - [Raff VPC](/products/vpc) - Product details reviewed: 2026-09-17. Verify live product pages and console for current engine availability, versions, migration support, backup and recovery behavior, networking, limits, and pricing. --- ### MySQL vs PostgreSQL vs MongoDB: How to Choose the Right Database URL: https://rafftechnologies.com/learn/guides/mysql-vs-postgresql-vs-mongodb Description: Compare MySQL, PostgreSQL, and MongoDB by data model, ecosystem, performance, scaling, and operations to narrow a three-engine database decision. MySQL vs PostgreSQL vs MongoDB is a **three-database selection guide** for teams that have not yet narrowed the choice to two engines. MySQL and PostgreSQL are relational databases; MongoDB is document-oriented. The goal here is to decide which overall data model, query pattern, ecosystem, and operating model best fits the application. Raff supports managed PostgreSQL and MySQL, while MongoDB can be self-hosted on [Raff VM](/products/raff-vm). If your shortlist is already **MongoDB vs MySQL**, use the dedicated [MongoDB vs MySQL comparison](/learn/guides/mongodb-vs-mysql). If the decision is PostgreSQL vs MySQL or MongoDB vs PostgreSQL, use those dedicated two-engine comparisons instead. This page intentionally stays at the broader three-way decision level. ## MySQL, PostgreSQL, and MongoDB fit different application shapes ![Database decision framework comparing PostgreSQL, MySQL, and MongoDB for relational apps, PHP ecosystems, and document-first workloads.](https://raff-images.s3.raffusercloud.com/database_decision_framework_png_74549e0119.png) MySQL and PostgreSQL are relational database management systems. They organize structured data into tables and support SQL, indexes, joins, constraints, and transactions. MongoDB is a document database. It stores BSON documents in collections and is designed around document-shaped records that may contain nested objects and arrays. | Decision area | MySQL | PostgreSQL | MongoDB | |---|---|---|---| | Primary model | Relational | Relational with extensive extension and JSONB capabilities | Document | | Relationship handling | Foreign keys and joins | Foreign keys, joins, constraints, advanced relational querying | Embedding or references | | Flexible fields | Native JSON type | JSON and JSONB | Native document structure | | Transactions | InnoDB transactions | Relational transactions | Single-document atomicity plus multi-document transactions | | Strong ecosystem fit | WordPress, WooCommerce, PHP and established MySQL apps | SaaS, data-rich relational apps, extension-driven workloads | Document-first apps and MongoDB-native stacks | | Query style | SQL | SQL | MongoDB Query Language and aggregation | | Typical scaling path | Optimize, resize, cache, replicas, then more complex architectures if needed | Optimize, resize, pooling, replicas, partitioning, then more complex architectures if needed | Replica sets and native sharding when horizontal distribution is required | The practical distinction is the shape of the product's data. A subscription system with users, organizations, invoices, permissions, and payments is relational. A configuration record or catalog item with bounded nested attributes may be naturally document-shaped. ## The decision framework starts with data relationships Use requirements that are expensive to change later. | Workload signal | MySQL | PostgreSQL | MongoDB | |---|---|---|---| | WordPress or WooCommerce | Strong default | Usually unnecessary | Poor fit | | Existing MySQL application with stable operations | Strong reason to stay | Change only for a documented requirement | Change only for a documented requirement | | New SaaS app with many related entities | Viable | Strong default | Use only if the domain is genuinely document-first | | Complex joins and reporting | Viable | Strong fit | Usually more modeling friction | | Flexible metadata inside a relational core | JSON columns | Strong fit with JSONB | Possible, but may add a second data model unnecessarily | | Self-contained documents with variable fields | Possible | Possible with JSONB | Strong fit | | PostgreSQL extensions such as PostGIS or pgvector are required | No equivalent extension model | Strong fit | Different ecosystem | | Vendor software explicitly requires MySQL | Strong fit | No | No | | Native document sharding is a product requirement | Different architecture required | Different architecture required | Strong fit | | Team already operates one engine reliably | Keep it unless requirements disagree | Keep it unless requirements disagree | Keep it unless requirements disagree | Choose **MySQL** when the surrounding application or software ecosystem already expects MySQL and the relational model fits. Choose **PostgreSQL** when the product is relational and benefits from PostgreSQL-specific capabilities, JSONB, extensions, richer query patterns, or an existing PostgreSQL standard. Choose **MongoDB** when the document itself is the natural read and write boundary and most application behavior stays inside that boundary. **Customer pattern from Raff:** small teams usually narrow this decision faster when they write down relationship complexity, required extensions, and existing engine expertise before comparing hosting plans. Once the engine decision is clear, the next question is operational: managed or self-hosted. For PostgreSQL and MySQL, Raff provides dedicated [Managed PostgreSQL](/products/managed-databases/postgresql) and [Managed MySQL](/products/managed-databases/mysql) paths. If you still need to compare operating responsibility, start with [Managed vs Self-Hosted Databases](/learn/guides/managed-vs-self-hosted-databases). :::cluster :::cta Deploy a Database Now Choose your database engine. ::: ## MySQL is a practical fit for established relational web workloads MySQL is a relational database commonly used by websites, content management systems, ecommerce software, PHP applications, and established business systems. It is a strong fit when: - WordPress or WooCommerce is part of the stack; - vendor software explicitly supports or requires MySQL; - the team already has tested MySQL backup and recovery procedures; - schemas and query patterns are stable; - SQL reporting and relational integrity matter; - the application already performs reliably on MySQL. Modern MySQL deployments commonly use InnoDB, which provides transactions, row-level locking, crash recovery, and foreign-key support. MySQL also provides a native JSON data type and JSON functions, so bounded flexible metadata does not automatically require a document database. For the relational two-engine decision, continue with [PostgreSQL vs MySQL](/learn/guides/postgresql-vs-mysql). If MySQL is already the chosen engine, compare [Managed MySQL](/products/managed-databases/mysql) with [MySQL Hosting: Managed vs Self-Hosted](/learn/guides/mysql-hosting-managed-vs-self-hosted) before deciding how much database operations work your team wants to own. ## PostgreSQL fits relational and hybrid application workloads PostgreSQL is a relational database with strong data-integrity features, extensive SQL capabilities, JSONB, and an extension model that can add specialized functionality. It is a strong fit when: - a SaaS product has many related entities; - transactions span several business records; - reporting and complex joins are important; - relational data needs bounded flexible metadata; - JSONB queries and indexes are useful; - an approved PostgreSQL extension is required; - the team already standardizes on PostgreSQL. A common hybrid pattern keeps core product fields relational while using JSONB only for flexible metadata: ```text id organization_id status created_at metadata_jsonb ``` This preserves explicit ownership, relationships, constraints, and common filters while allowing selected attributes to vary. For the dedicated PostgreSQL decision, use [Postgres Hosting: Managed vs Self-Hosted for SaaS](/learn/guides/postgresql-hosting-for-saas) or [MongoDB vs PostgreSQL](/learn/guides/mongodb-vs-postgresql). If PostgreSQL is already the selected engine, review [Managed PostgreSQL](/products/managed-databases/postgresql) as the commercial next step rather than restarting the engine comparison. ## MongoDB fits applications built around bounded documents MongoDB stores BSON documents in collections and supports nested fields, arrays, indexes, replica sets, transactions, aggregation, and sharding. It is a strong fit when: - one document is the natural business aggregate; - records have variable but governed fields; - most reads retrieve the whole aggregate; - nested objects belong with the parent record; - document-oriented tooling is already part of the stack; - horizontal document sharding is a real requirement rather than a future possibility. The warning sign is relationship pressure. If ordinary product behavior repeatedly requires cross-collection references, multi-document transactions, relationship-heavy reporting, and repeated reconstruction of business entities, the application may be fighting the document model. For the direct MySQL comparison, use [MongoDB vs MySQL](/learn/guides/mongodb-vs-mysql). This page should remain the broader three-engine chooser. ## Performance and scaling depend on workload evidence There is no useful universal winner for MySQL vs PostgreSQL vs MongoDB performance. Database performance depends on schema or document design, indexes, query shape, working set, connection behavior, transaction scope, memory, storage latency, concurrency, and the exact engine version and configuration. Use representative evidence: | Signal | What to inspect | |---|---| | Query latency | p50, p95, and p99 for real application operations | | Query plans | scans, joins, aggregation stages, indexes, and estimated versus actual work | | Concurrency | active transactions, waits, locks, retries, and deadlocks | | Connections | application pools, workers, jobs, and administrative sessions | | Memory | working set, cache effectiveness, temporary work, and swapping | | Storage | latency, throughput, growth, and maintenance behavior | | Write behavior | transaction size, log generation, document growth, and contention | | Recovery | backup duration and measured restore time | ![Comparison matrix showing MySQL, PostgreSQL, and MongoDB strengths across ecosystem fit, relational querying, JSON support, and document flexibility.](https://raff-images.s3.raffusercloud.com/mysql_postgresql_mongodb_comparison_matrix_png_12b3e4a9ec.png) Scaling should follow the measured bottleneck. Fix inefficient queries and indexes before introducing distributed architecture. Resize memory or storage when the working set demands it. Add replicas when read or availability requirements justify them. Introduce sharding or more complex partitioning only when simpler approaches no longer meet the workload. If performance is the reason for considering a migration, reproduce production-like data, concurrency, and queries first. An engine migration is too disruptive to justify with an unrelated benchmark. ## Operations and recovery can outweigh feature differences Choosing an engine also chooses a set of operating responsibilities. Teams must account for patching, upgrades, monitoring, credentials, network access, backups, retention, restore testing, replication, high availability, connection management, storage growth, migrations, and incident response. A managed database transfers more of the platform work to the provider, while the application team still owns schemas, queries, indexes, credentials, migrations, capacity decisions, and application behavior during recovery. A self-hosted database provides deeper operating-system and database control, but the team owns the complete database operating model. Use [Managed vs Self-Hosted Databases](/learn/guides/managed-vs-self-hosted-databases) when the engine is chosen but the hosting model is still undecided. ## Raff supports different deployment paths by engine Raff Managed Databases currently supports **PostgreSQL, MySQL, Valkey, ClickHouse, and Kafka**. PostgreSQL and MySQL therefore have managed paths on Raff. MongoDB is not currently a Raff Managed Database engine, but it can run as a self-hosted workload on [Raff VM](/products/raff-vm). The practical sequence is: ```text Choose the data model -> choose the engine -> choose managed or self-hosted operations -> size and validate the production workload ``` Do not reverse that sequence by choosing an engine only because one hosting option looks convenient today. ## Conclusion: use this page for the three-engine decision MySQL, PostgreSQL, and MongoDB can all support production applications, but they encourage different data and operating models. Choose MySQL when the application ecosystem already expects MySQL and relational SQL fits the workload. Choose PostgreSQL when relationships, constraints, richer SQL, JSONB, extensions, or an existing PostgreSQL standard matter. Choose MongoDB when bounded documents are genuinely the application's natural read and write unit. Once the shortlist reaches two engines, move to the dedicated comparison rather than continuing to broaden the decision here: [PostgreSQL vs MySQL](/learn/guides/postgresql-vs-mysql), [MongoDB vs PostgreSQL](/learn/guides/mongodb-vs-postgresql), or [MongoDB vs MySQL](/learn/guides/mongodb-vs-mysql). ## Sources - [PostgreSQL documentation](https://www.postgresql.org/docs/current/) - [MySQL 8.4 Reference Manual](https://dev.mysql.com/doc/refman/8.4/en/) - [MongoDB Data Modeling](https://www.mongodb.com/docs/manual/data-modeling/) - [MongoDB Transactions](https://www.mongodb.com/docs/manual/core/transactions/) - [Raff Managed Databases](/products/managed-databases) - [Raff Managed PostgreSQL](/products/managed-databases/postgresql) - [Raff Managed MySQL](/products/managed-databases/mysql) - Product details reviewed: 2026-09-17. --- ### VPS Database Hosting: What Small Teams Should Know URL: https://rafftechnologies.com/learn/guides/vps-for-databases Description: Compare VPS database hosting with managed databases, including control, cost, backups, recovery, networking, and operational ownership for small teams. **VPS database hosting** means running PostgreSQL, MySQL, MariaDB, MongoDB, Valkey or Redis-compatible software, or another database engine on a virtual machine your team controls. For small teams, the important question is not whether a database can run on a VPS. It can. The real decision is **whether host-level control is valuable enough to justify owning patching, backups, monitoring, storage growth, failover, and recovery**. Raff supports both operating models. Teams that need full host control can run databases on a [Raff VM](/products/raff-vm). Teams that want less database-platform work can use [Raff Managed Databases](/products/managed-databases), which currently supports PostgreSQL, MySQL, Valkey, ClickHouse, and Kafka. MongoDB is not currently a Raff Managed Database engine, but it can be self-hosted on Raff VM. For most small teams, the decision should start with **operational ownership and recovery requirements**, not the lowest monthly infrastructure price. ![Decision matrix comparing VPS database hosting and managed databases by workload size, team skill, cost, backups, availability, scaling, and security.](https://raff-images.s3.raffusercloud.com/vps_database_hosting_decision_matrix_a129d0fa38.png) ## VPS database hosting vs managed databases | Decision factor | VPS database hosting | Managed database | |---|---|---| | Operating-system access | Full control | Restricted | | Database installation | Your team | Provider | | OS and database patching | Your team | Provider within service policy | | Backup platform | Your team designs and operates it | Provider-operated within plan scope | | Restore testing | Your team | Shared responsibility; application validation remains yours | | Monitoring platform | Your team builds or integrates it | Usually included to a defined scope | | High availability | Your team designs and operates it | Available where supported by the service | | Storage expansion | Your team plans and executes it | Service workflow | | Custom packages/extensions | Broad control | Limited to supported catalog | | Root/filesystem access | Yes | Usually no | | Typical fit | Hard host-level control requirements | Teams reducing recurring database operations | A VPS database fits when a **specific requirement needs root access, filesystem control, custom packages, exact maintenance timing, or a topology outside the managed-service boundary**. A managed database fits when the supported engine and features match the workload and the team would rather spend engineering time on the application than on database-host operations. For the broader ownership model, see [Managed Database vs Self-Hosted](/learn/guides/managed-vs-self-hosted-databases). :::cluster ## When a database VPS is the right choice A database VPS remains useful when self-hosting solves a real technical or operational requirement. Typical reasons include: - MariaDB or another engine outside the managed catalog; - MongoDB, which is not currently a Raff Managed Database engine; - PostgreSQL extensions or packages outside a managed provider's supported set; - custom authentication modules; - direct database-file or filesystem access; - exact package, version, or patch timing; - custom replication or clustering topology; - database-adjacent processes that must run on the same host; - migration, recovery, testing, or forensic environments requiring complete host access. A simple self-hosted architecture can look like: ```text Application VM -> private VPC Database VM -> customer-operated monitoring, backups, patching, and recovery ``` If the application and database still share one VM, that can be reasonable for early or low-risk workloads. Separation becomes useful when the database needs a different scaling, security, maintenance, or recovery lifecycle. See [Separate App and Database Server](/learn/guides/separate-app-database-server). Self-hosting should solve a hard requirement. Installing PostgreSQL or MySQL is easy; operating and restoring it reliably is the expensive part. ## When managed databases are the better fit A managed database is a practical starting point when the provider supports the required engine, version, extensions, networking, and recovery model. The commercial value is operational. A managed service can reduce the amount of work your team owns around provisioning, operating-system and service maintenance, backup infrastructure, point-in-time recovery tooling where supported, monitoring, storage expansion, supported high-availability and failover workflows, private connectivity, and maintenance operations. Your application team still owns schemas, indexes, query performance, migrations, credentials, connection behavior, capacity decisions, recovery-point selection, and validating the application after a restore. Raff Managed Databases currently supports **PostgreSQL, MySQL, Valkey, ClickHouse, and Kafka**. PostgreSQL and MySQL also have permanent **$0 free tiers** with 1 vCPU, 1 GB RAM, and 2 GB storage for compatibility testing. Paid PostgreSQL and MySQL plans start at **$7.99/month**. If PostgreSQL or MySQL is already selected, use the engine-specific guides: [Postgres Hosting: Managed vs Self-Hosted](/learn/guides/postgresql-hosting-for-saas) and [MySQL Hosting: Managed vs Self-Hosted](/learn/guides/mysql-hosting-managed-vs-self-hosted). **Customer pattern from Raff:** small teams usually lean toward managed databases when backup, restore, patching, and database-host incidents are competing with product work. Self-hosting remains useful when the workload has a concrete host-level requirement. ## VPS database cost should include operations, not only VM price A self-hosted database can have a lower infrastructure invoice and still have a higher total operating cost. A realistic VPS database cost model includes: ```text VM compute + block storage + backup storage + monitoring + optional standby capacity + engineering time + patching + restore testing + incident response + major upgrades ``` A managed database cost model includes: ```text managed database plan + optional HA or replicas + additional storage where applicable + application engineering time ``` Compare both models against the same RPO, RTO, availability, security, and performance target. Comparing one self-hosted VM with a managed HA database is not a fair cost comparison because the operational outcomes differ. For a small team, engineering attention is often the hidden database cost. If the same engineer is responsible for product work and database operations, backup failures, disk growth, upgrades, and incidents compete directly with application development. :::cta Explore Managed Databases Choose your database path. ::: ## Storage and memory still determine database behavior Whether the database is self-hosted or managed, workload evidence should drive capacity decisions. ![Diagram showing how NVMe storage affects database queries, indexes, transaction logs, backups, restores, and application latency.](https://raff-images.s3.raffusercloud.com/database_storage_performance_on_vps_e23f3f0faf.png) For a self-hosted database VPS, monitor data and index size, storage growth, transaction-log growth, storage latency, temporary files, backup size, restore duration, memory pressure, swapping, and CPU saturation under representative queries. A database volume should include operational headroom: ```text data + indexes + transaction logs + temporary work + migration and maintenance headroom + expected growth + recovery safety margin ``` For self-hosted databases that need storage independent from the VM system disk, [Raff Volumes](/products/volumes) provide block storage that can be managed separately from the VM lifecycle. Volumes currently cost **$0.08/GB-month**. See [Database Storage on Block Volumes](/learn/guides/database-storage-block-volumes-layout-monitoring-recovery) for layout and recovery considerations. Managed databases reduce host-level storage work but do not remove capacity planning. The application team still needs to understand growth, query behavior, connections, and recovery objectives. ## Connection budgets can fail before CPU does Database capacity is not only vCPU and RAM. Connection behavior can become the first practical limit. Estimate total planned demand across every process: ```text maximum application instances x pool size per instance + background workers + scheduled jobs + migrations + monitoring + administrative reserve = planned database connection demand ``` A database can have available CPU and still reject application traffic because every connection slot is occupied. For a self-hosted database, your team owns server limits, pooling, and monitoring. For a managed service, connection limits and built-in pooling depend on the engine and plan. Monitor active and idle connections, connection acquisition time, long-running transactions, rejected connections, pool queue depth, deployment overlap, retry storms, and slow-query behavior. A larger database plan does not automatically fix oversized application pools. ## Backups and restore testing determine whether self-hosting is responsible A self-hosted database should not become business-critical before its recovery path exists. ![Diagram showing a VPS database backup and recovery model with scheduled backups, separate storage, retention, restore testing, and recovery steps.](https://raff-images.s3.raffusercloud.com/database_backup_recovery_model_webp_7e0fee6c1e.png) Define two business targets: - **RPO:** how much recent data the business can afford to lose. - **RTO:** how long the database and application can remain unavailable. Then map controls to actual failure modes: | Failure | Useful protection | |---|---| | Database host failure | Replacement VM, replica, or HA path | | Accidental deletion | Database-aware backup or PITR | | Bad migration | Pre-change recovery point plus tested rollback | | Disk loss | Independent database backup and rebuild path | | Compromised credentials | Isolated retained recovery copies | | Delayed corruption discovery | Multi-point retention | Replication is not a backup. A replica can faithfully reproduce an accidental deletion or destructive migration. For self-hosted databases, [Raff Data Protection](/products/data-protection) can add VM-level backup and snapshot controls, while database-native backups remain necessary for transactional recovery. [Object Storage](/products/object-storage) can be used for compatible backup artifacts kept away from the database VM. Managed databases move more of the backup platform into the service boundary, but the application team still owns recovery-point selection and application validation. Use [Database Backup Strategy for SaaS Apps](/learn/guides/database-backup-strategy-saas-apps) for the complete recovery framework. ## Private networking should be the default database path A database should not receive broad public exposure merely because it runs on a VPS. For separated application and database servers, prefer a private network path: ```text Internet -> HTTPS Application VM -> private VPC Database VM or Managed Database ``` [Raff VPC](/products/vpc) provides private networking between supported Raff resources. Private networking does not replace database authentication, least privilege, TLS where required, firewall policy, or scoped credentials; it removes unnecessary public routing from the normal application-to-database path. For a self-hosted database, restrict the database port to approved application and administrative sources. For a managed database accessed externally, use the service's supported TLS, allowlist, and credential controls. ## Which Raff database path should you choose? Choose **Raff VM for a self-hosted database** when root or filesystem access is required, a custom package or extension is mandatory, exact patch timing matters, custom replication or clustering is required, the engine is outside the managed catalog, or your team already has mature database operations and a concrete reason for host control. Choose **Raff Managed Databases** when the supported engine and features fit, host-level control is unnecessary, and your team wants less patching, backup-platform, monitoring, storage, and failover work. If PostgreSQL fits, compare [Raff Managed PostgreSQL](/products/managed-databases/postgresql). If MySQL fits, compare [Raff Managed MySQL](/products/managed-databases/mysql). For cache, sessions, queues, or Redis-compatible data structures, review [Managed Valkey](/products/managed-databases/valkey). ## VPS database hosting buying checklist Before choosing a VPS database or managed service, document the required database engine and version, extensions or packages, whether root access is mandatory, current data size and growth, peak connection demand, RPO and RTO, HA requirement, backup retention, network requirements, incident ownership, and total operating cost including engineering time. If these are unknown, comparing only monthly VM and managed-service prices is premature. ## Conclusion VPS database hosting is useful when a workload genuinely needs operating-system, filesystem, package, version, extension, or topology control. It should not be the automatic starting point just because a database can run on a VM. Use a managed database when the supported service fits and reducing recurring database-platform work is more valuable than host control. Use a Raff VM when a documented requirement makes that additional control worth the operational responsibility. The useful decision is not "Can I run this database on a VPS?" It is **"Which operating model can my team run and recover reliably?"** Continue with [Managed Database vs Self-Hosted](/learn/guides/managed-vs-self-hosted-databases), [Postgres Hosting](/learn/guides/postgresql-hosting-for-saas), or [MySQL Hosting](/learn/guides/mysql-hosting-managed-vs-self-hosted) for the next decision layer. ## Sources - [Raff Managed Databases](/products/managed-databases) - [Raff Managed PostgreSQL](/products/managed-databases/postgresql) - [Raff Managed MySQL](/products/managed-databases/mysql) - [Raff Managed Valkey](/products/managed-databases/valkey) - [Raff VM](/products/raff-vm) - [Raff VPC](/products/vpc) - [Raff Data Protection](/products/data-protection) - [PostgreSQL: Backup and Restore](https://www.postgresql.org/docs/current/backup.html) - [MySQL: Backup and Recovery](https://dev.mysql.com/doc/refman/8.4/en/backup-and-recovery.html) - Product and pricing details reviewed: 2026-09-17. --- ### Database Migration Services: Costs, Process & Provider Checklist URL: https://rafftechnologies.com/learn/guides/database-migration-services-provider-checklist Description: Compare database migration services by scope, cost, downtime, provider responsibilities, validation, and rollback before choosing a migration provider or consultant. A **database migration service** helps a team move production data to a new database environment while coordinating compatibility, target preparation, transfer, synchronization, cutover, validation, and rollback. For buyers, the important question is not whether a provider has a migration tool. It is **which migration responsibilities the provider owns, which remain with your team, and what evidence is required before production cutover**. Raff supports assisted migrations into [Managed Databases](/products/managed-databases) for supported workloads. If you are still deciding between provider-managed and self-hosted operations, start with [Managed Database vs Self-Hosted](/learn/guides/managed-vs-self-hosted-databases). This guide focuses on the next decision: how to compare migration services, consultants, tools, cost drivers, and provider scope. For the execution runbook, use [Database Migration Checklist for Managed Databases](/learn/guides/managed-database-migration-checklist). For synchronization and low-downtime implementation patterns, use [Zero-Downtime Database Migrations](/learn/guides/zero-downtime-database-migrations-small-teams). ## Database migration services differ mainly in responsibility ownership The right migration model depends on operational risk, not only database size. | Migration model | Best fit | What the buyer owns | What the provider or tool owns | |---|---|---|---| | DIY database-native migration | Small, well-understood same-engine move | Planning, transfer, cutover, validation, rollback | Little or none | | Cloud migration tool | Team already has database operations expertise | Architecture, compatibility, application cutover, validation | Full load and synchronization mechanics | | Destination-provider assistance | Moving into a supported managed database | Application changes, business validation, final approvals | Target setup and supported migration assistance | | Database migration consultant | Complex or business-critical migration | Internal business decisions and application validation | Discovery, migration design, execution support, coordination | | Modernization project | Engine change or major redesign | Product and application decisions | Schema conversion, data transformation, migration program | A 20 GB database with many writers, strict downtime requirements, custom extensions, and difficult rollback can require more migration work than a larger database with a quiet maintenance window. ## A migration tool does not replace a migration service Migration tools automate mechanics such as: - initial data loading; - replication or change data capture; - ongoing synchronization; - transformation for supported objects; - lag visibility; - task retries. A production migration still needs human ownership for questions such as: - Is the exact source engine and version supported? - Are extensions, plugins, collations, users, and stored routines compatible? - Which applications, workers, jobs, and integrations use the source? - How are credentials and network rules changed? - What synchronization lag is acceptable? - Who controls writes during cutover? - Who validates business-critical records? - What triggers rollback? - What happens to writes created on the target after cutover? A **tool** primarily moves or synchronizes data. A **service** defines the responsibility boundary around that move. That distinction matters when evaluating AWS DMS, Google Cloud Database Migration Service, Azure database-migration tooling, a specialist consultant, or assistance from the destination database provider. ## A complete migration service starts with discovery and compatibility A credible migration scope should establish the real source and target state before production data moves. Discovery should cover: - source engine and version; - target engine and version; - database size and growth rate; - write volume; - connection demand; - extensions and plugins; - stored procedures, functions, triggers, events, and generated values; - character sets and collations; - users, roles, and permissions; - application drivers; - connection pooling; - application and worker clients; - networking and TLS; - backup and recovery state; - downtime tolerance; - recovery point objective (RPO) and recovery time objective (RTO); - rollback constraints. A useful discovery output separates three states: | Result | Meaning | |---|---| | Supported as-is | No known migration blocker for this requirement | | Supported with change | Application, schema, network, or operational change required | | Unsupported or unresolved | Must be solved before production cutover | If unsupported items are still unknown on migration day, the risk has not disappeared. It has only been deferred. ## Target preparation should finish before the migration window The target should be production-ready before the final transfer or synchronization phase begins. Target preparation can include: - provisioning the managed database or target host; - selecting initial capacity; - configuring private networking or scoped access; - creating credentials and roles; - validating TLS requirements; - enabling required extensions and features; - configuring backups and recovery; - configuring monitoring and alerts; - testing application connectivity; - confirming connection limits and pooling behavior. A destination-provider migration service reduces coordination because the same organization operates the target platform. Buyers still need the provider to state exactly what is included. ## Baseline transfer and synchronization solve different parts of the move For a small database with an acceptable maintenance window, a logical export and import can be enough. For larger or busier workloads, migration often starts with a baseline copy while the source remains active. The service should explain how it validates that baseline, including transfer logs, failed objects, skipped objects, row or object counts, schema differences, and representative integrity checks. When the final outage must be short, continuous or repeated synchronization keeps the target close to the source after the baseline copy. Ask: - How is lag measured? - What lag threshold allows cutover? - Which data definition language changes or objects are not replicated? - Who monitors synchronization? - What happens when synchronization fails? - How much source log retention is required? - What happens if lag grows during the cutover window? **Operational insight from Raff:** treat replication lag, recovery readiness, and write authority as separate cutover gates rather than assuming that a running replication task is enough evidence to switch production. ## Go or no-go ownership should be explicit before cutover A migration service should identify who has authority to proceed. Before cutover, the team should know: - who confirms target health; - who confirms synchronization health; - who approves the final write-control step; - who changes application endpoints or secrets; - who recycles long-lived connection pools; - who validates reads and writes; - who declares the target authoritative; - who can trigger rollback. A controlled sequence is: ```text confirm target and recovery readiness -> control writes -> complete final synchronization -> validate target state -> switch endpoint or configuration -> recycle cached connections -> validate reads and writes -> verify workers and integrations -> declare target authoritative ``` If the provider manages only the database side while your team owns application configuration, that boundary is workable. It must be documented before the maintenance window. ## Technical validation and business validation are separate responsibilities The migration provider can validate technical database state, including: - schemas and objects; - synchronization status; - key row or object counts; - users and permissions; - connection success; - database health. The application team should validate business meaning, including: - authentication; - tenant or account data; - billing and subscription records; - critical writes; - background jobs; - scheduled jobs; - reports; - integrations; - customer-facing workflows. A migration is not complete because the database server accepts queries. ## Rollback must be defined before the target accepts production writes The provider scope should define the backward path before the target becomes authoritative. Ask: - How long is the source retained? - Is the source read-only after cutover? - Who can approve rollback? - How is traffic or configuration returned to the source? - How are target-only writes handled? - When does rollback stop being practical? - What observation or support window follows cutover? - Who approves source retirement? A migration service that describes only the forward path is incomplete. ## The provider checklist should translate marketing language into concrete scope Use this table when comparing providers or consultants. | Responsibility | What to verify | |---|---| | Source discovery | Who inventories engine, versions, clients, size, write rate, and dependencies? | | Compatibility assessment | Who identifies unsupported features before migration? | | Schema conversion | Is heterogeneous conversion included or separately scoped? | | Target provisioning | Who configures capacity, networking, users, monitoring, and backups? | | Baseline transfer | How is initial data load performed and verified? | | Synchronization | Is change data capture or replication included when low downtime is required? | | Replication monitoring | Who watches lag, errors, and retained logs? | | Application endpoint change | Provider, customer, or shared? | | Go or no-go decision | Who can authorize production cutover? | | Validation | Which technical checks are provider-owned and which business checks are customer-owned? | | Rollback | Is the backward path documented before target writes? | | Post-cutover support | How long does an engineer remain engaged after the switch? | | Source retirement | Who approves shutdown, credential removal, and cleanup? | Words such as **white-glove**, **managed migration**, or **zero downtime** should be translated into these responsibilities. :::cluster ## Database migration service cost follows complexity and risk There is no useful universal database-migration price because effort follows workload complexity and cutover risk more than raw database size. The main cost drivers are: ### Database size and transfer time Larger datasets increase transfer, verification, retry, and temporary storage requirements. ### Write rate A constantly changing database can be harder to migrate than a larger but mostly static one. Write volume affects synchronization lag, log retention, cutover timing, and rollback complexity. ### Same-engine vs cross-engine migration PostgreSQL-to-PostgreSQL or MySQL-to-MySQL preserves more behavior than a cross-engine move. Heterogeneous migrations can require: - schema conversion; - data-type changes; - query changes; - stored-procedure rewrites; - application-driver changes; - additional performance testing. ### Downtime requirement A maintenance window simplifies the project. A low-downtime requirement adds baseline loading, change synchronization, lag monitoring, more rehearsal, write-control logic, and a more complex rollback path. ### Source and target compatibility gaps Major-version changes, unsupported extensions, custom plugins, authentication differences, and provider-specific behavior add assessment and testing work. ### Number of database clients Ten services sharing one database create ten cutover surfaces if they cache endpoints, credentials, or long-lived connections. ### Validation requirements Financial, audit-heavy, or regulated workloads need deeper reconciliation than a basic application with representative workflow checks. ### Support window An overnight or weekend production cutover with dedicated engineers has a different services cost than a flexible daytime migration. ## Migration pricing models should be compared by scope first | Pricing model | What it means | Typical fit | |---|---|---| | Included destination-provider assistance | Supported migration help is bundled with the destination platform | Teams already moving to that provider | | Usage-based migration tooling | Pay for migration or replication resources | Internal teams operating the project | | Fixed project fee | Defined scope and deliverables | Well-discovered migration with predictable boundaries | | Time and materials | Pay for engineering or consulting effort | Complex or uncertain project | | Ongoing managed engagement | Migration is part of broader database or cloud operations | Team outsourcing more than the one-time move | Compare **scope before price**. A free migration that covers only data movement can leave more work with your team than a paid engagement covering discovery, compatibility, cutover, rollback, and post-cutover support. A simple same-engine migration with a maintenance window can also make a consultant unnecessary. ## Zero-downtime migration needs a workload-specific definition Continuous replication can keep the target current while the source remains live, reducing the final transfer window. Application users can still see interruption from: - write-control periods; - application restarts; - pool recycling; - endpoint or configuration changes; - credential changes; - long-running transactions; - lag catch-up; - client retry behavior. Ask every provider to define the exact start and end points used to measure downtime. Raff describes assisted migration options for supported Managed Database moves. Production planning should still validate source compatibility, synchronization health, client reconnect behavior, write authority, and rollback design against the current live product scope before scheduling cutover. For the implementation patterns behind low-downtime moves, use [Zero-Downtime Database Migrations](/learn/guides/zero-downtime-database-migrations-small-teams). :::cta Deploy a Database Now Create target, then validate readiness. ::: ## Migration services become more useful as operational risk increases DIY is more realistic when most of these are true: - same source and target engine; - small or moderate database; - acceptable maintenance window; - few database clients; - no unusual extensions or features; - tested backup and restore path; - straightforward rollback; - an engineer can own the complete cutover window. Provider assistance becomes more useful as these conditions appear: - business-critical database; - short downtime tolerance; - high write rate; - large dataset; - continuous synchronization requirement; - many application clients; - difficult rollback after target writes; - limited database-operations capacity; - destination-provider-specific networking or recovery requirements. A specialist consultant becomes more relevant when the migration also includes engine conversion, major schema redesign, custom extensions, compliance-heavy data handling, multiple databases, or application modernization. ## Provider questions should expose the real migration boundary Ask these before production scheduling: 1. Which exact source and target engines and versions are supported? 2. Which extensions, plugins, objects, or topologies are unsupported? 3. Is schema conversion included or only data movement? 4. How are database clients and dependencies discovered? 5. Will the migration use a maintenance-window copy or continuous synchronization? 6. How is replication lag measured? 7. What lag or error criteria block cutover? 8. Who owns application connection-string, secret, or DNS changes? 9. Who attends the production cutover? 10. Who has go or no-go authority? 11. What technical validation does the provider perform? 12. What business validation remains with our team? 13. What conditions trigger rollback? 14. How are target-only writes handled after rollback? 15. How long is the source retained? 16. Are network-transfer or egress charges separate? 17. What happens if the migration must be repeated? 18. Which backup, recovery, and monitoring controls are active on the target? 19. What post-cutover support window is included? 20. When can the old database be safely retired? If the answers remain vague, the production scope is incomplete. ## Raff migration assistance is destination-specific and workload-dependent The current [Raff Managed Databases](/products/managed-databases) product path supports assisted migrations for eligible workloads rather than requiring every customer to operate a migration project alone. Migration scope can depend on source engine, version, topology, networking, data size, write behavior, and cutover requirements. Verify the current product page and source compatibility before building a production schedule around a specific migration method or service commitment. Raff's PostgreSQL, MySQL, and Valkey free tiers start at $0/month, which gives teams a low-cost way to validate application connectivity before choosing a paid plan. Raff migration assistance is most relevant when the destination is a supported [Managed PostgreSQL](/products/managed-databases/postgresql) or [Managed MySQL](/products/managed-databases/mysql) deployment and the source fits the current migration path. If the workload requires host-level control, unsupported database components, or a topology outside the managed service boundary, [Raff VM](/products/raff-vm) can remain the self-hosted target. ## Database migration provider checklist ### Provider fit - [ ] Exact source and target engines are supported. - [ ] Version compatibility is confirmed from current documentation. - [ ] Unsupported features are documented. - [ ] Source database size and write rate are measured. - [ ] Downtime requirement is agreed. - [ ] RPO and RTO are documented. ### Scope - [ ] Discovery responsibility is explicit. - [ ] Schema-conversion responsibility is explicit. - [ ] Target provisioning responsibility is explicit. - [ ] Application endpoint or configuration changes have an owner. - [ ] Go or no-go and rollback approvers are named. ### Data movement - [ ] Baseline-transfer method is documented. - [ ] Synchronization method is documented when required. - [ ] Lag has a measurable threshold. - [ ] Transfer or synchronization errors have an owner. - [ ] Network and egress costs are understood. ### Cutover - [ ] Source recovery is current. - [ ] Target health is confirmed. - [ ] Write authority is explicit. - [ ] Endpoint or secret change is ready. - [ ] Workers, jobs, and integrations are included. - [ ] Critical reads and writes are validated. ### Rollback - [ ] Rollback triggers are written before cutover. - [ ] Source-retention period is defined. - [ ] Target-only write handling is documented. - [ ] Rollback deadline is explicit. - [ ] Split authority between source and target is prevented. ### After migration - [ ] Target backups and recovery are active. - [ ] Monitoring and alerts are active. - [ ] Business validation is approved. - [ ] Temporary migration access is removed. - [ ] Post-cutover support window is complete. - [ ] Source retirement is approved. ## Database migration services should be compared on responsibility, not tool names Database migration services should be compared on **responsibility, compatibility, cutover ownership, validation, rollback, and post-cutover support**. A simple same-engine migration with a maintenance window can be appropriate for an internal team. A migration service becomes more useful as write rate, client count, downtime pressure, compatibility differences, and rollback complexity increase. If Raff Managed PostgreSQL or MySQL is the intended destination, confirm current source compatibility and migration scope first. Then build the production plan around measurable migration health, application reconnect behavior, business validation, and a documented rollback path. If the broader operating model is still undecided, return to [Managed Database vs Self-Hosted](/learn/guides/managed-vs-self-hosted-databases). ## Sources - [AWS Database Migration Service](https://aws.amazon.com/dms/) - [Google Cloud Database Migration Service](https://cloud.google.com/database-migration) - [Azure Database Migration Service overview](https://learn.microsoft.com/en-us/azure/dms/dms-overview) - [PostgreSQL Logical Replication](https://www.postgresql.org/docs/current/logical-replication.html) - [MySQL Replication](https://dev.mysql.com/doc/refman/8.4/en/replication.html) - [Raff Managed Databases](/products/managed-databases) - [Raff Managed PostgreSQL](/products/managed-databases/postgresql) - [Raff Managed MySQL](/products/managed-databases/mysql) - Product and migration details reviewed: 2026-09-17. Verify live Raff product pages before relying on current migration scope, engine or version support, pricing, or limits. --- ### ClickHouse Backup & Replication: Availability, Recovery & Restore URL: https://rafftechnologies.com/learn/guides/clickhouse-backup-replication-recovery Description: Design ClickHouse backups and replication for availability and recovery: separate replicas from historical backups, define RPO/RTO, monitor Keeper, and test restores. ClickHouse replication and backups protect different failure classes. Replication keeps additional current copies of data available across selected node failures. Backups provide an independent recovery path after destructive changes, cluster loss, or historical data problems. For production analytics, the essential rule is **replication improves availability; backups preserve recoverability**. A replicated cluster can reproduce accidental deletes or bad mutations across every replica, while a backup can still be too slow to satisfy an availability objective. This guide owns ClickHouse backup, replication, and restore strategy. For deployment ownership, use [Managed ClickHouse vs Self-Hosted ClickHouse](/learn/guides/managed-clickhouse-vs-self-hosted-clickhouse). For monitoring, use [ClickHouse Monitoring: Queries, Merges, Replication & Alerts](/learn/guides/clickhouse-monitoring-queries-merges-replication-alerts). :::cluster ## Replication and backups solve different failures | Failure | Replication helps? | Backup helps? | |---|---:|---:| | One replica/node fails | Yes | Usually not the fastest path | | One storage device fails | Yes, with healthy other replicas | Yes | | Accidental delete/mutation replicates | No | Yes, if backup predates it | | Bad schema/derived-data change | Often copies the problem | Historical restore/rebuild can help | | Entire cluster is lost | No surviving replica | Yes | | Region/site failure | Only if topology spans it | Yes if backup is independent | | Data needs historical recovery | No | Yes | Do not call a replica a backup merely because it contains the same rows. ## ReplicatedMergeTree protects current data availability Self-managed ClickHouse commonly uses ReplicatedMergeTree-family tables for replication. Replicas coordinate state using ClickHouse Keeper. A simplified topology is: ```text ClickHouse replica A ↕ ClickHouse Keeper quorum ↕ ClickHouse replica B ``` Replication can allow another replica to continue serving data when one node becomes unavailable, depending on query routing and application behavior. But the topology itself creates operational responsibilities: - Keeper availability; - replica synchronization; - lag and queue monitoring; - failed replica recovery; - storage capacity on every replica; - schema consistency; - load-balancer or client routing. Replication factor should follow failure tolerance, not a generic “three is always best” rule. ## ClickHouse Keeper is part of the availability design Keeper coordinates metadata and replicated-table operations in self-managed replicated clusters. If the coordination layer becomes unavailable, replicated tables may be unable to perform some writes or metadata operations even while existing local data remains readable. That means Keeper needs its own: - quorum design; - monitoring; - disk and latency health; - backup/recovery thinking where configuration state matters; - upgrade and maintenance plan. A two-replica data topology with a fragile coordination layer is not a complete HA design. ## Backups need an independent failure domain A backup stored only on the same host or storage system as the ClickHouse data does not protect against that system's loss. Production backup design should identify: - backup destination; - credential isolation; - schedule; - retention; - encryption/access controls; - restore environment; - expected restore duration; - validation procedure. ClickHouse supports backup and restore operations for tables, databases, and metadata using supported backup destinations and mechanisms. The business question is how much history must remain recoverable and how quickly it must return to service. ## RPO and RTO should drive the recovery design Two objectives organize the decision: - **RPO (Recovery Point Objective):** maximum acceptable data loss. - **RTO (Recovery Time Objective):** maximum acceptable recovery duration. Examples: ```text RPO 24 hours + RTO 8 hours → daily backup may be plausible if restore is fast enough RPO 15 minutes + RTO 30 minutes → backup-only design may be insufficient → stronger availability and ingestion replay may be required ``` Analytical systems often have another recovery source: the upstream event stream or object store from which ClickHouse can be rebuilt. If source data is replayable, document that path and measure how long a rebuild actually takes. “We can replay Kafka” is not an RTO until the throughput and procedure are tested. ## Backups and ingestion replay can complement each other A ClickHouse recovery strategy can combine: ```text schema/configuration backup + ClickHouse data backup + upstream raw event archive + replay procedure ``` For append-only analytics, an upstream durable log or object-storage archive can provide a second way to recover data after the last backup. But replay has limits: - source retention may expire; - transformations may have changed; - duplicate handling must be safe; - rebuilding materialized views can take time; - external reference data may no longer match historical state. Test replay with representative volume before treating it as the primary disaster-recovery plan. ## Backup frequency should match change and rebuild cost A small, easily replayable dataset may not need the same backup schedule as a large customer-facing analytics cluster. Consider: - daily ingest volume; - upstream replay window; - materialized-view complexity; - schema-change frequency; - customer-facing history; - rebuild time; - backup storage cost; - operational impact of backup jobs. The correct schedule is the one that meets RPO without creating unacceptable system pressure. ## Restore testing is more important than backup success A successful backup job proves that files were written, not that the system can be recovered. A ClickHouse restore test should verify: - backup metadata is readable; - tables/databases restore into a clean target; - expected row counts and date ranges exist; - users/permissions/configuration are rebuilt as required; - materialized views and derived tables are correct; - replicas can be re-established; - applications reconnect; - critical analytical queries match expected results; - restore duration fits the RTO. Schedule restore tests after major version, topology, or backup-method changes. ## Replication lag is a recovery warning A replica that exists but is far behind is less useful during failover. Monitor: - replica queue size; - delay/lag; - read-only state; - part fetch failures; - Keeper connectivity; - disk capacity; - mutation backlog; - consistency of table definitions. An HA design should define when a replica is considered healthy enough to receive production traffic. Do not route to a stale replica solely because the process is running. ## Mutations and deletes can propagate to replicas Replicated tables distribute current logical state. That is why replication is not historical protection. Before high-risk operations such as large `ALTER`, mutation, or deletion: - verify backup/recovery state; - estimate mutation cost; - monitor replica queues; - consider testing against a copy; - define rollback or restore procedure. For retention-driven deletion, use [ClickHouse Partitioning & TTL](/learn/guides/clickhouse-partitioning-ttl-mergetree-retention) so lifecycle behavior is explicit rather than ad hoc. ## Managed ClickHouse changes who operates replication and backups [Raff Managed ClickHouse](/products/managed-databases/clickhouse) currently provides managed backup workflows and optional high availability, reducing the platform work around database hosts, Keeper, monitoring, and recovery infrastructure. The customer team still owns: - RPO and RTO requirements; - deciding what historical point is correct; - validating data after restore; - upstream replay logic; - schema and analytical correctness; - application reconnect behavior. For self-hosted ClickHouse on [Raff VMs](/products/raff-vm), the team owns the full replication and backup platform. At Raff, the recovery rule is: **every availability mechanism needs an independent historical recovery path, and every backup policy needs a measured restore test.** ## ClickHouse recovery checklist - [ ] RPO and RTO are documented. - [ ] Replication factor matches node-failure tolerance. - [ ] Keeper is treated as production infrastructure. - [ ] Replica lag and queues are monitored. - [ ] Backups leave the primary failure domain. - [ ] Backup retention covers historical recovery needs. - [ ] Upstream replay window is documented if used. - [ ] Materialized views can be rebuilt or restored. - [ ] Large mutations/deletes have recovery protection. - [ ] Restore tests measure real elapsed time. - [ ] Application reconnect/failover behavior is tested. ## Conclusion ClickHouse replication and backups are complementary, not interchangeable. Use replication to keep current analytical data available through selected node failures, backups to preserve historical recovery, and upstream replay when it is genuinely durable and fast enough to meet recovery objectives. A production design is complete only when the team has tested both failover and restore. :::cta Explore ClickHouse Use managed backups and optional HA while keeping RPO, RTO, and analytical recovery requirements explicit. ::: ## Sources - [ClickHouse Backup and Restore](https://clickhouse.com/docs/operations/backup) - [ClickHouse ReplicatedMergeTree](https://clickhouse.com/docs/engines/table-engines/mergetree-family/replication) - [ClickHouse Keeper](https://clickhouse.com/docs/guides/sre/keeper/clickhouse-keeper) - [Raff Managed ClickHouse](/products/managed-databases/clickhouse) - Sources reviewed: 2026-08-24 --- ### ClickHouse Materialized Views: Pre-Aggregation & Query Trade-Offs URL: https://rafftechnologies.com/learn/guides/clickhouse-materialized-views-pre-aggregation-query-trade-offs Description: Use ClickHouse materialized views for pre-aggregation without losing correctness: compare incremental vs refreshable views, backfills, target tables, and write trade-offs. ClickHouse materialized views move repeated transformation or aggregation work from query time toward ingestion time. They can make stable analytical queries much cheaper, but they also create another data pipeline whose correctness, backfills, and storage need to be operated. For production teams, the decision is not simply whether materialized views are fast. It is **whether a repeated query pattern is stable enough to justify maintaining a derived representation**. This guide owns materialized-view design and pre-aggregation trade-offs. For the broader physical architecture, use [ClickHouse Architecture for Production Analytics](/learn/guides/clickhouse-architecture-production-analytics). For ordering and query execution, use [ClickHouse Query Performance: ORDER BY, Keys & Memory Trade-Offs](/learn/guides/clickhouse-query-performance-order-by-keys-memory). :::cluster ## Materialized views trade write work for read efficiency A normal query performs its aggregation when the user asks for the result: ```text raw events → query scans rows → filter / group / aggregate → result ``` An incremental materialized view can shift part of that work to insert time: ```text raw events inserted → materialized-view transformation → aggregate / derived table updated → later query reads much less data ``` This is useful when the same expensive calculation is requested repeatedly. | Workload | Materialized view fit | |---|---| | Stable dashboard metric queried constantly | Strong | | Hourly/daily rollups over large event tables | Strong | | Repeated transformation into a query-friendly table | Strong | | One-off exploratory analysis | Weak | | Business logic changing every few days | Weak | | Queries with many unpredictable dimensions | Often weak | The performance gain comes from avoiding repeated work, not from a special cache that automatically understands every future query. ## Incremental materialized views process inserted blocks ClickHouse incremental materialized views execute as data is inserted into the source table and write transformed results to a target table. A common pattern is: ```sql CREATE MATERIALIZED VIEW events_hourly_mv TO events_hourly AS SELECT toStartOfHour(event_time) AS hour, account_id, count() AS events FROM events GROUP BY hour, account_id; ``` The target table then serves queries that need hourly event counts without rescanning the full raw event history. The target engine and aggregate types must match the transformation. For additive rollups, teams often use engines such as SummingMergeTree or AggregatingMergeTree according to the aggregation model. The key architectural point is that the view processes incoming data. It does not magically rebuild historical rows already present before the view was created. ## Backfills need a separate plan Creating a materialized view on an existing large table creates an immediate question: what about old data? Production options include: - create the target table and populate historical data with a controlled `INSERT ... SELECT`; - create the view for new writes, then backfill an older non-overlapping time range; - rebuild the derived table from source data during a maintenance window; - maintain a versioned target during a major logic change and cut queries over after validation. Avoid double counting. If live inserts are already feeding the materialized view, a historical backfill must exclude the same time/data range or use an idempotent design. A safe sequence can be: ```text choose cutover timestamp T → create target + MV for data >= T → backfill source data < T → validate totals → switch queries ``` For high-volume systems, define the boundary explicitly rather than running an unrestricted backfill while live ingestion continues. ## Materialized views need correctness tests Pre-aggregation makes queries cheaper by storing derived state. That state must remain trustworthy. Validate: - row counts by period; - aggregate totals against raw source queries; - handling of duplicate events; - late-arriving events; - null/default behavior; - schema changes; - data type precision; - target-table merge behavior; - backfill overlap. A dashboard that is fast but subtly wrong is worse than a slower query whose behavior is understood. At Raff, the practical rule is: **treat a materialized view as a production data pipeline, not as a query optimization checkbox.** Give it an owner, validation query, and rebuild path. ## Late and corrected data can complicate pre-aggregation Analytical event streams are rarely perfectly ordered. Consider: ```text 10:00 event occurs 10:01 hourly aggregate updated 10:20 corrected/late event arrives for 10:00 ``` An incremental view can process the late row, but the resulting correctness depends on the target engine and aggregation semantics. Updates and deletes are more complex than append-only data because materialized views react to inserted blocks rather than behaving like a continuously recomputed relational view. If source facts can be corrected frequently, decide whether to: - model corrections as compensating events; - periodically rebuild affected aggregates; - use a refreshable materialized view for appropriate workloads; - query raw data for correctness-sensitive ranges. The data-change model should be chosen before the aggregate engine. ## Refreshable materialized views fit periodic recomputation ClickHouse also supports refreshable materialized views, which recompute results on a schedule rather than only transforming incoming inserts. They can fit when: - the result depends on joins or broader source state; - periodic freshness is acceptable; - incremental logic would be difficult to maintain correctly; - the full refresh cost is bounded. Incremental and refreshable views solve different problems: | Model | Best when | |---|---| | Incremental | high ingest, append-oriented data, stable aggregation | | Refreshable | periodic recomputation, broader joins/state, bounded dataset | Do not choose refreshable views for a huge dataset merely to avoid thinking about incremental design. Estimate the full refresh cost and schedule impact first. ## Pre-aggregation should follow real query evidence Before building a materialized view, measure the query you want to optimize: - frequency; - p50/p95 latency; - rows/bytes read; - CPU and memory; - dimensions filtered/grouped; - time range; - business importance. Then ask whether an improved `ORDER BY`, projection, narrower query, or better table design can solve the problem without another derived table. A materialized view is justified when repeated work remains substantial after the base table is reasonably designed. ## More materialized views increase write amplification Each materialized view attached to an ingest path creates additional writes and transformations. With several views: ```text one source insert → raw table → MV A target → MV B target → MV C target ``` This can increase: - insert latency; - CPU use; - part creation; - merge activity; - storage consumption; - schema-change coordination. Do not create one view for every dashboard tile. Consolidate stable rollups where dimensions and grain align. ## Target-table ordering still matters A materialized view does not remove physical-design decisions from the target table. Choose target `ORDER BY` based on how the pre-aggregated data will be queried. For example, if dashboards filter by account and time, a target ordered around account and time may prune much more effectively than a target ordered only by time. The full query-performance framework belongs in [ClickHouse Query Performance](/learn/guides/clickhouse-query-performance-order-by-keys-memory), but the rule here is simple: **pre-aggregation reduces rows; good ordering reduces how many of those rows must still be read.** ## Managed ClickHouse changes operations, not view design [Raff Managed ClickHouse](/products/managed-databases/clickhouse) can reduce the infrastructure work around ClickHouse, including host lifecycle, backups, monitoring, scaling workflows, and optional HA. Your data team still owns: - source schema; - materialized-view query; - target engine; - ordering key; - backfill logic; - correctness validation; - rebuild procedures. Managed infrastructure cannot know whether a customer dashboard should count a late event or how a corrected event changes a business aggregate. ## Materialized-view checklist - [ ] The source query is frequent and materially expensive. - [ ] The aggregation grain is stable. - [ ] Raw source data remains recoverable. - [ ] Target engine matches aggregation semantics. - [ ] Target `ORDER BY` matches read patterns. - [ ] Historical backfill has a non-overlap plan. - [ ] Late/corrected events have defined behavior. - [ ] Derived totals are validated against source queries. - [ ] Write amplification is monitored. - [ ] Rebuild procedure is documented. ## Conclusion ClickHouse materialized views are most valuable when they replace repeated, stable analytical work with a maintained derived table. Use incremental views for append-oriented transformations and rollups, refreshable views when periodic recomputation is the better fit, and keep raw data available so derived state can be validated or rebuilt. The optimization is successful only when it improves query cost without making analytical correctness harder to trust. :::cta Explore ClickHouse Run ClickHouse with managed infrastructure while keeping materialized-view and analytical data-model ownership with your team. ::: ## Sources - [ClickHouse Materialized Views](https://clickhouse.com/docs/materialized-view) - [ClickHouse Incremental Materialized Views](https://clickhouse.com/docs/materialized-view/incremental-materialized-view) - [ClickHouse Refreshable Materialized Views](https://clickhouse.com/docs/materialized-view/refreshable-materialized-view) - [Raff Managed ClickHouse](/products/managed-databases/clickhouse) - Sources reviewed: 2026-08-24 --- ### ClickHouse Partitioning & TTL: MergeTree & Retention Trade-Offs URL: https://rafftechnologies.com/learn/guides/clickhouse-partitioning-ttl-mergetree-retention Description: Design ClickHouse partitioning and TTL for MergeTree tables: keep partitions coarse, use ORDER BY for queries, and automate safe retention without part explosion. ClickHouse partitioning and TTL rules manage data lifecycle at different layers. `PARTITION BY` groups MergeTree data into coarse operational units; TTL rules automate retention and other lifecycle actions. Neither should be used as a substitute for a well-designed `ORDER BY` key. For production analytics, the useful question is **how to make retention, deletion, and maintenance predictable without creating thousands of tiny partitions or forcing queries to scan poorly ordered data**. This guide owns ClickHouse partitioning and TTL decisions. For row ordering and query pruning, use [ClickHouse Query Performance: ORDER BY, Keys & Memory Trade-Offs](/learn/guides/clickhouse-query-performance-order-by-keys-memory). For broader architecture, use [ClickHouse Architecture for Production Analytics](/learn/guides/clickhouse-architecture-production-analytics). :::cluster ## Partitioning, ordering, and TTL have different jobs | Mechanism | Primary job | Common misuse | |---|---|---| | `ORDER BY` | Physical row ordering and data skipping | Treating it as presentation sorting | | Primary key | Sparse index used to skip ranges | Copying OLTP primary-key patterns | | `PARTITION BY` | Coarse lifecycle/maintenance boundary | Creating a partition for every tenant or day without need | | TTL | Automated retention/lifecycle action | Using it without capacity and deletion monitoring | The most important rule is: **partition for operations; order for queries.** A query can still perform poorly inside a perfectly chosen partition if the sorting key does not match the dominant filters. ## Partition only when a coarse boundary has operational value A good partition key helps with operations such as: - dropping old periods efficiently; - detaching or moving a defined data slice; - managing retention by month or another coarse period; - isolating data with a real lifecycle boundary. For time-series analytics, monthly partitions are often easier to operate than daily partitions when the workload does not require daily administrative boundaries. For example: ```sql PARTITION BY toYYYYMM(event_time) ORDER BY (account_id, event_time) ``` Here the partition groups data by month for lifecycle work, while ordering by account and time helps queries that filter on account and time ranges. The partition key should come from a lifecycle requirement, not from a desire to speed every query. ## Too many partitions create metadata and merge overhead High-cardinality partition keys can create too many small independent data sets. Problematic examples include partitioning directly by: - customer ID when there are thousands of customers; - request ID; - user ID; - a high-cardinality event property; - overly granular time buckets for modest datasets. Each partition can contain its own parts and merge work. Excessive partitions make part counts, metadata, inserts, and maintenance harder to operate. A better design often keeps tenants together in a coarse time partition and puts tenant/account fields early in `ORDER BY`. That preserves query pruning without creating a separate partition for every tenant. ## TTL makes retention explicit in table design ClickHouse TTL expressions can automate lifecycle actions such as deleting data after a specified age. A simple retention rule can look conceptually like: ```sql TTL event_time + INTERVAL 90 DAY DELETE ``` This expresses a business rule: data becomes eligible for deletion after 90 days. Use TTL when: - retention is predictable; - data age is encoded in a reliable timestamp; - expiration should happen continuously rather than through manual partition drops; - the team can monitor storage and background merge activity. Do not choose 90 days, 30 days, or any other duration from convention. Tie it to product, recovery, and data-governance requirements. ## TTL deletion is asynchronous, not an exact wall-clock delete TTL work is applied through background merges. Rows do not necessarily disappear at the exact second their TTL expires. This matters operationally: ```text row reaches TTL → becomes eligible → background merge processes eligible data → storage is reclaimed ``` If storage is tight, do not assume expired data will free space immediately. Monitor: - disk growth; - merge backlog; - part count; - oldest retained data; - TTL completion behavior; - available capacity during traffic peaks. TTL is a policy. Merge capacity determines how quickly that policy is physically realized. ## Partition drops are faster for large coarse deletions When all data in an old partition can be removed together, dropping a partition can be operationally simpler than row-level TTL deletion. This makes a coarse time partition valuable for datasets with clean retention boundaries. Example: ```text monthly partitions Jan 2026 Feb 2026 Mar 2026 ... ``` If the business retention rule says everything before February can be deleted, removing a whole January partition avoids rewriting unrelated newer rows. TTL and partition drops can coexist: TTL handles continuous lifecycle, while partitions provide an efficient administrative unit for large boundaries and maintenance. ## Partition pruning helps only when filters use the partition expression Queries can skip whole partitions when predicates align with the partition key, but partition pruning should be treated as a secondary optimization. A monthly time partition helps queries constrained to specific months. It does not make an account-only query efficient if every month still needs to be read and the `ORDER BY` key does not help. Design priority should usually be: ```text dominant query filters → ORDER BY → lifecycle / maintenance need → PARTITION BY → TTL ``` That order prevents partitioning from compensating for the wrong sorting key. ## TTL can also support movement and tiering in some designs ClickHouse TTL features can be used for lifecycle actions beyond deletion, depending on storage policy and deployment architecture. The strategic question is whether older data needs: - deletion; - movement to a different volume; - a lower-cost storage tier; - aggregation before raw detail expires. Each additional lifecycle stage increases operational complexity. Use tiering only when the retained data volume and access pattern justify it. For small teams, a simple, observable retention rule is often safer than a multi-stage policy that few people can explain during an incident. ## Retention must preserve recovery and business needs Before shortening TTL, identify whether old data is needed for: - customer-facing history; - model/trend analysis; - incident investigation; - regulatory or contractual retention; - rebuilding materialized views; - correcting historical aggregates; - replaying ingestion after pipeline bugs. A short TTL can lower storage cost and still create a much larger recovery problem later. If raw data must be retained longer than the ClickHouse operational dataset, consider exporting or archiving it before expiry. ## TTL and materialized views need coordinated lifecycle rules Derived tables may need a different retention period from raw source data. For example: ```text raw events → 30 days hourly aggregate → 12 months monthly aggregate → multiple years ``` That can be efficient when detailed events are useful only for recent troubleshooting while long-term reporting needs coarser summaries. But verify derived data before raw data expires. Once the only detailed source is deleted, rebuilding or correcting aggregates becomes harder. Use [ClickHouse Materialized Views](/learn/guides/clickhouse-materialized-views-pre-aggregation-query-trade-offs) for the pre-aggregation design. ## Managed ClickHouse reduces lifecycle operations but not retention ownership [Raff Managed ClickHouse](/products/managed-databases/clickhouse) reduces host-level database operations and provides managed storage, monitoring, backups, scaling workflows, and optional HA. The data team still decides: - partition key; - `ORDER BY` key; - TTL duration; - archival requirements; - which derived tables outlive raw data; - when a lifecycle change is safe. At Raff, the operational rule is: **do not partition more finely than the lifecycle needs, and do not expire source data before you can prove the business no longer needs it for recovery or rebuilds.** ## Partitioning and TTL checklist - [ ] `ORDER BY` is designed from query filters first. - [ ] Partitioning has a real lifecycle/maintenance purpose. - [ ] Partition cardinality stays coarse. - [ ] Tenant/user IDs are not used as high-cardinality partitions without a hard requirement. - [ ] TTL duration is tied to business retention. - [ ] TTL behavior and merge backlog are monitored. - [ ] Storage headroom does not rely on instant TTL deletion. - [ ] Large historical deletes can use partition boundaries where appropriate. - [ ] Derived-table retention is coordinated with raw-data TTL. - [ ] Archive/recovery needs are confirmed before shortening retention. ## Conclusion ClickHouse partitioning and TTL are lifecycle tools, not replacements for physical query design. Keep partitions coarse and operationally meaningful, use `ORDER BY` for the dominant query path, and make retention explicit with TTL only after recovery and business-history needs are understood. This keeps MergeTree data easier to query, merge, delete, and operate as it grows. :::cta Explore ClickHouse Use managed ClickHouse infrastructure while keeping partition and retention policy aligned with your data lifecycle. ::: ## Sources - [ClickHouse Custom Partitioning Key](https://clickhouse.com/docs/engines/table-engines/mergetree-family/custom-partitioning-key) - [ClickHouse TTL Guide](https://clickhouse.com/docs/guides/developer/ttl) - [ClickHouse MergeTree](https://clickhouse.com/docs/engines/table-engines/mergetree-family/mergetree) - [Raff Managed ClickHouse](/products/managed-databases/clickhouse) - Sources reviewed: 2026-08-24 --- ### ClickHouse Monitoring: Queries, Merges, Replication & Alerts URL: https://rafftechnologies.com/learn/guides/clickhouse-monitoring-queries-merges-replication-alerts Description: Monitor ClickHouse query latency, rows read, memory, parts, merges, mutations, replication, Keeper, disk growth, and ingestion freshness with actionable alerts. ClickHouse monitoring should answer whether the analytical service can ingest fresh data, merge it, answer important queries, replicate it, and retain enough capacity to recover from spikes. For production teams, process uptime alone is not enough. A ClickHouse server can be reachable while dashboards are stale, background merges are falling behind, replicas are unhealthy, or important queries are exhausting memory. This guide owns ClickHouse monitoring and alert design. For physical query design, use [ClickHouse Query Performance: ORDER BY, Keys & Memory Trade-Offs](/learn/guides/clickhouse-query-performance-order-by-keys-memory). For backup and HA, use [ClickHouse Backup & Replication](/learn/guides/clickhouse-backup-replication-recovery). :::cluster ## Monitor four layers instead of one dashboard A useful model separates: | Layer | Main question | Example signals | |---|---|---| | Query service | Can users get results within objectives? | latency, errors, memory, bytes/rows read | | Ingestion | Is new data arriving and becoming queryable? | insert failures, freshness delay, rejected inserts | | Background work | Can ClickHouse keep parts healthy? | active parts, merge backlog, mutations | | Replication/storage | Can data survive and remain synchronized? | replica queues, lag, disk capacity, Keeper health | The alerting rule is: **page on service impact or imminent data risk; keep diagnostic metrics on dashboards unless they imply an actionable condition.** ## Query monitoring should focus on important workloads ClickHouse exposes detailed query history through system tables such as `system.query_log` when configured. For customer-facing or operational queries, track: - p50/p95/p99 duration; - failed queries; - rows and bytes read; - memory usage; - result size; - query frequency; - exceptions; - user/workload identity. A query that becomes twice as expensive but is run once a week may be less urgent than a dashboard query whose p95 rises by 200 ms across thousands of executions. Group queries by normalized pattern, application endpoint, dashboard, or workload instead of alerting on every raw SQL string. ## Rows and bytes read explain inefficient query paths Latency alone tells you a query is slow. Rows and bytes read help explain why. A regression pattern can look like: ```text same result size + same traffic + rows read increase 20x → likely pruning / ORDER BY / filter regression ``` Correlate expensive queries with schema and deployment changes. If a query scans much more data than expected, inspect the sorting key and filters before increasing compute. ## Memory needs workload-level alerting Large GROUP BY operations, joins, sorts, and broad scans can consume substantial memory. Monitor: - per-query memory; - server memory pressure; - out-of-memory exceptions; - concurrent expensive queries; - spill/external-processing behavior where configured; - workload changes after deployments. Avoid a universal “memory above 80%” pager. A short analytical burst can be normal. Page when sustained memory pressure is causing failed queries, OOM risk, or service degradation. ## Parts and merges reveal ingestion health MergeTree inserts create parts that ClickHouse merges in the background. Too many small inserts can create excessive parts and merge pressure. Monitor: - number of active parts; - part creation rate; - ongoing merges; - merge queue/backlog; - merge duration; - disk bandwidth during merges; - rejected inserts related to part pressure. A common chain is: ```text many tiny inserts → too many parts → merge backlog grows → disk/CPU pressure → queries slow → inserts may eventually be rejected ``` The fix is often better batching or ingestion design, not only larger servers. ## Mutations need separate visibility ALTER mutations and other background data changes can consume significant resources and remain in progress for long periods. Track: - pending mutations; - age of oldest mutation; - failures; - parts remaining; - query/merge pressure while mutations run. Treat large production mutations as change events. Record when they started so a later CPU or disk spike has context. ## Data freshness is a business-level metric A ClickHouse cluster can be healthy while the ingestion pipeline is stale. Define a freshness signal such as: ```text current time - newest expected event time ``` or compare source and ClickHouse ingestion checkpoints. Alert when freshness crosses the application's actual objective. For a customer analytics dashboard, 15 minutes of stale data may be an incident even if every ClickHouse process and replica is green. This is why infrastructure monitoring must be paired with pipeline outcomes. ## Replica monitoring should prove failover readiness For replicated tables, monitor: - replica delay; - replication queue size; - read-only state; - parts to fetch; - failed fetches; - Keeper connectivity; - replica exceptions; - schema consistency. A replica is not useful for recovery merely because it exists. Define a health condition that means it is current enough to receive traffic. Use [ClickHouse Backup & Replication](/learn/guides/clickhouse-backup-replication-recovery) for the recovery architecture behind these signals. ## Disk monitoring needs growth and headroom, not only percentage used ClickHouse continuously creates parts, merges them, performs mutations, builds backups, and may retain historical data through TTL policies. Monitor: - current free space; - daily/weekly growth rate; - bytes by table/partition; - backup storage consumption; - temporary/merge space pressure; - TTL deletion progress. Forecast time-to-full: ```text free bytes / average daily net growth = approximate days of headroom ``` Do not wait for a static 90% disk alert if growth shows the cluster will run out in two days. ## Keeper health belongs in replicated-cluster monitoring Self-managed replicated ClickHouse depends on ClickHouse Keeper for coordination. Monitor: - quorum/member availability; - request latency; - session/connectivity errors; - storage health; - leadership changes; - resource pressure. A healthy set of data replicas with an unhealthy coordination layer can still create write and metadata problems. Keeper should have its own runbook and owner. ## Alert severity should map to action Use three broad classes: | Class | Example | |---|---| | Page | important queries failing; disk exhaustion imminent; offline/unusable replicas threaten availability; ingestion freshness outside critical objective | | Investigate/ticket | sustained merge backlog; rising query cost; capacity headroom shrinking; replica lag without immediate availability impact | | Dashboard/context | CPU, network throughput, query volume, part counts within baseline | Every page should name: - condition; - duration; - user/data impact; - owner; - first diagnostic step. An alert that says only “CPU > 80%” transfers diagnosis to the person being paged. ## Baselines are better than borrowed universal thresholds Collect normal ranges for: - insert rate; - query latency; - rows/bytes read; - parts per active partition; - merge throughput; - memory; - replica delay; - disk growth; - data freshness. Then alert on sustained deviations tied to impact. A nightly ETL workload may legitimately use most CPU for 20 minutes. The same load at midday after a deployment may be abnormal. Context matters. ## Managed ClickHouse reduces platform monitoring work, not application observability [Raff Managed ClickHouse](/products/managed-databases/clickhouse) provides managed database infrastructure and monitoring/query visibility so teams do not need to operate every host-level component themselves. The data/application team still needs to define: - which queries matter; - acceptable dashboard latency; - freshness objective; - ingestion correctness; - materialized-view validity; - business-level recovery criteria. At Raff, the monitoring rule is: **alert on a broken analytical outcome first, then correlate queries, parts, merges, replicas, memory, and storage to explain it.** ## ClickHouse monitoring checklist - [ ] Important query patterns have latency/error objectives. - [ ] Rows/bytes read are visible for query regressions. - [ ] Per-query and server memory pressure are monitored. - [ ] Ingestion freshness has an application-level metric. - [ ] Active parts and merge backlog are monitored. - [ ] Long mutations are visible. - [ ] Replica lag/queues/read-only state are monitored. - [ ] Keeper health is monitored for self-managed HA. - [ ] Disk growth is forecast, not only thresholded. - [ ] Alerts distinguish page vs investigation vs dashboard context. - [ ] Every page has an owner and first response step. ## Conclusion ClickHouse monitoring should prove that data is fresh, queries are usable, background work is keeping up, replicas are recoverable, and storage has enough headroom. Start from customer or pipeline outcomes, then use ClickHouse-specific query, merge, part, replica, and Keeper signals to diagnose the cause. This produces fewer alerts and faster incident response than treating every host metric as equally important. :::cta Explore ClickHouse Use managed ClickHouse monitoring while keeping query and data-freshness objectives tied to your application. ::: ## Sources - [ClickHouse Monitoring](https://clickhouse.com/docs/operations/monitoring) - [ClickHouse System Tables](https://clickhouse.com/docs/operations/system-tables) - [ClickHouse Query Log](https://clickhouse.com/docs/operations/system-tables/query_log) - [ClickHouse Replicas System Table](https://clickhouse.com/docs/operations/system-tables/replicas) - [Raff Managed ClickHouse](/products/managed-databases/clickhouse) - Sources reviewed: 2026-08-24 --- ### Database Storage on Block Volumes: Layout, Monitoring, and Recovery URL: https://rafftechnologies.com/learn/guides/database-storage-block-volumes-layout-monitoring-recovery Description: Plan database storage on block volumes for PostgreSQL and MySQL, including layout, capacity headroom, I/O monitoring, backups, and recovery. **Database storage on block volumes** means placing a self-hosted database's persistent files on attached disk-like storage instead of making the VM's root disk the only home for database state. For most small teams, a practical starting point is **one dedicated database volume, enough growth headroom, database-aware backups, and monitoring that connects Linux storage signals with database behavior**. Split data, transaction logs, or temporary work across additional volumes only when measurements or recovery requirements justify the extra complexity. At **Raff**, this architecture usually means a [Raff VM](/products/raff-vm) for the database host and a [Raff Volume](/products/volumes) for persistent disk-like database state. Teams that do not need host-level database control should also compare [Raff Managed Databases](/products/managed-databases), because a block volume separates storage from the VM lifecycle but does not make PostgreSQL or MySQL managed. ## Database storage on block volumes: quick decision | Situation | Better starting point | |---|---| | Development or disposable database | VM system disk may be enough | | Production self-hosted PostgreSQL/MySQL | One dedicated database volume | | Database storage grows faster than VM compute | Dedicated volume | | Measured WAL/redo contention | Consider a separate log volume only after testing | | Large temporary jobs threaten primary data capacity | Consider a separate temporary-work volume | | Team does not want to own filesystem, patching, backups, and recovery | Managed database | | Need root access, custom packages, or exact storage layout | Raff VM + Volume | The default should be simple. A storage layout is useful only if your team can monitor, back up, restore, and explain it during an incident. :::cluster ## Why separate database storage from the VM system disk A database writes more than table rows. Its active storage may include: - table and index files; - transaction logs such as PostgreSQL WAL or MySQL redo logs; - temporary files; - engine metadata; - control files; - replication-related state; - maintenance working space. If all of that shares the VM root disk with the operating system, application logs, package updates, and other services, one storage problem can affect the whole host. A clearer layout is: ```text Raff VM system disk -> OS -> database packages -> configuration -> service logs Raff Volume -> database persistent files Independent database backup / PITR path -> historical recovery ``` The value is **lifecycle separation**: - database capacity can grow without forcing a compute resize; - the VM can be rebuilt without treating the root disk as the only database copy; - database storage gets its own alerts and capacity plan; - the operating-system filesystem is less exposed to database growth; - recovery responsibilities become easier to document. A dedicated volume is still **primary active storage**. It is not a backup. For the broader block-storage decision, see [Block Storage for Databases & Containers](/learn/guides/block-storage-volumes-databases-containers-app-data). ## One dedicated database volume is usually the practical default It is tempting to create separate devices for data, indexes, WAL/redo, temporary files, and backups from day one. For a small team, that often increases operational surface before it solves a measured problem. | Layout | When it fits | Main trade-off | |---|---|---| | Database on root disk | Low-risk or temporary environments | OS and database share capacity/failure pressure | | One dedicated database volume | Most self-hosted production databases | Mixed database I/O shares one device | | Separate data and transaction-log volumes | Measured write/log contention or distinct capacity needs | More mounts, alerts, recovery ordering, and configuration | | Separate temporary-work volume | Large sorts/imports/rebuilds threaten primary data space | More storage to operate and clean up | | Managed database | Host-level database storage should not be your responsibility | Less OS/filesystem control | Choose a second storage boundary only when the benefit is clear. Good reasons include: - measured I/O contention between data and transaction logs; - materially different growth rates; - a temporary workload that can exhaust primary database storage; - a recovery or maintenance procedure that benefits from separation; - a database architecture that already has operators who can manage multiple paths safely. Poor reasons include generic claims that separate disks are always faster or that production databases must have many volumes. ## Capacity planning should use headroom and time-to-full A database volume can look healthy by percentage used and still be heading toward an incident quickly. Track: - allocated capacity; - current used/free space; - database data size; - index size; - WAL, redo, and binary-log growth; - temporary-file growth; - migration or index-build requirements; - daily/weekly growth rate; - estimated time to full; - expansion lead time; - recovery headroom. A useful planning model is: ```text current data + indexes + transaction-log headroom + temporary / maintenance work + expected growth + recovery safety margin = required working capacity ``` The rate of change matters more than one static percentage. A volume at 70% utilization with stable monthly growth may be comfortable. The same 70% during a large migration that is adding several GiB per hour can be urgent. ### Capacity alerts should answer an operational question A useful alert is not simply "disk is 80% full." It should help answer: - how quickly is usage growing? - what is creating the growth? - when will the safe headroom be exhausted? - can capacity be expanded before that point? - is the growth expected or caused by a broken retention/replication/maintenance process? A resize can solve a capacity deadline. It does not solve runaway logs, failed archiving, abandoned temporary files, or a workload that will immediately consume the new space. ## Database storage monitoring needs device and engine signals together For block-backed database storage, track at least five infrastructure dimensions: | Signal | What it tells you | |---|---| | Capacity | How much usable filesystem space remains | | Latency | How long reads/writes take | | IOPS | How many I/O operations are completing | | Throughput | How many bytes are moving per second | | Queueing / wait | Whether demand is arriving faster than storage completes it | Interpret these together. High IOPS with low latency may be healthy. Moderate IOPS with rising latency and sustained queueing may indicate saturation. High throughput during a planned backup may be expected; the same pattern during peak customer traffic may explain application latency. The useful diagnostic question is: > **Which database activity is producing storage pressure, and is the storage layer completing that work within the workload's latency budget?** The [Database Monitoring for Small Teams](/learn/guides/database-monitoring-small-teams) guide covers the wider monitoring and alerting model. ## PostgreSQL storage monitoring should connect WAL, checkpoints, and I/O PostgreSQL keeps the database cluster under `PGDATA` and uses WAL for durability and recovery. Monitor the database and filesystem together. Useful PostgreSQL evidence includes: - `pg_stat_io` where supported by the deployed PostgreSQL version; - `pg_stat_wal` for WAL generation and write/sync behavior; - checkpointer statistics; - database-level temporary-file activity; - long-running transactions; - archiving state where WAL archiving is used; - replication-slot or replica state where it affects WAL retention; - filesystem capacity and latency for the database paths. Examples of patterns worth investigating: - WAL growing much faster than normal; - storage latency rising during checkpoints; - temporary files consuming unexpected capacity; - a replication or archive problem retaining more WAL than planned; - index creation or schema maintenance consuming temporary headroom; - long-running transactions delaying cleanup or maintenance. Do not split WAL onto another volume merely because PostgreSQL supports separate paths. Do it when measurements show that the additional storage boundary improves the workload and your recovery procedure covers it. ## MySQL and InnoDB monitoring should connect redo, temporary work, and filesystem pressure A MySQL data directory can contain InnoDB tablespaces, redo files, temporary data, binary logs, and other server-managed files. Useful MySQL evidence includes: - Performance Schema file-I/O summaries; - InnoDB pending reads/writes; - redo-log and checkpoint progress; - buffer-pool behavior; - binary-log growth and retention; - temporary-table/filespace growth; - filesystem capacity, latency, throughput, and queueing. Do not treat high device utilization as the diagnosis by itself. The storage pressure may come from: - foreground queries; - flushing/checkpoints; - backup activity; - imports; - index or schema operations; - large temporary work; - insufficient memory causing more disk reads; - binary-log or retention behavior. Find the workload cause before changing database or storage settings. **Operational insight from Raff:** when storage pressure appears, separating the database volume is useful only after the team identifies whether capacity, latency, temporary work, or transaction-log growth is actually driving the incident. :::cta volumes Choose your storage path. ::: ## Mount state is part of database correctness A block volume can be attached in the cloud control plane while the guest operating system still has a mount or startup problem. Production documentation should record: - filesystem type; - stable device identifier or UUID; - mount path; - database service ownership/permissions; - boot behavior; - dependency between the mount and database service startup; - expected behavior when the volume is unavailable. One dangerous failure mode is: ```text expected database mount missing -> mount directory exists on root disk -> database/service starts against the wrong path -> new state is written somewhere unintended ``` For a database, the exact failure behavior depends on engine configuration and directory structure, but the principle is the same: **the service should not silently start against an unintended empty path**. Verify storage mounts before starting or restarting stateful services after maintenance. ## A block volume does not replace database-aware backups A volume stores the current active state, including bad state. It can preserve: - accidental deletes; - destructive schema changes; - corrupted files; - application-written bad data; - ransomware-encrypted state; - mistakes made by privileged operators. That is why recovery needs an independent historical path. A useful control map is: | Control | Main job | |---|---| | Block volume | Active persistent database storage | | Volume/VM snapshot | Infrastructure recovery point for selected scenarios | | Database backup | Engine-aware historical recovery | | PITR / transaction-log recovery | Recover toward a selected historical point | | Replica / HA | Service continuity for selected failures | | Restore test | Prove the recovery path works | Do not call a replica a backup. Do not call a persistent volume a backup. Do not assume a block-level snapshot is automatically database-consistent without an engine-aware procedure. For the full design, use [Database Backup Strategy for SaaS Apps](/learn/guides/database-backup-strategy-saas-apps) and [Database Restore Testing](/learn/guides/database-restore-testing-rpo-rto-recovery-validation). ## Map each storage failure to a recovery source A storage design is incomplete until the team knows what happens when each layer fails. | Failure | Typical recovery path | |---|---| | VM OS failure, volume healthy | Replace/rebuild VM and reattach/reconnect storage according to documented platform workflow | | Accidental row/table deletion | Database backup or PITR | | Bad schema migration | Rollback or historical database recovery | | Filesystem/database corruption | Known-good database recovery point | | Volume nearing full | Stop avoidable growth, restore headroom, expand when appropriate, fix root cause | | Volume unavailable/lost | Restore database to replacement storage | | Incorrect mount/permissions | Restore expected mount and ownership, then validate database state | | Complete host + storage loss | Independent database backup + rebuild runbook | The team should also know the **recovery order**: ```text restore/provision storage -> restore database state -> validate database -> reconnect application -> validate business workflows -> verify new backups/recovery coverage ``` Recovery is not complete merely because the database process starts. ## Managed databases change the storage responsibility boundary A dedicated block volume is appropriate when the team wants a **self-hosted database** and accepts host-level storage ownership. That ownership includes: - filesystem layout; - mount configuration; - capacity forecasting; - database storage telemetry; - OS and database patching; - backup design; - restore testing; - replication/HA when needed; - incidents. If the application does not require root access, custom packages, direct filesystem access, or a topology outside the managed-service boundary, a managed database can reduce that operational surface. Use [Managed Database vs Self-Hosted](/learn/guides/managed-vs-self-hosted-databases) for the responsibility decision. ## How Raff Volumes fit a self-hosted database [Raff Volumes](/products/volumes) provide block storage for workloads that need persistent disk-like storage attached to Raff VMs. Current Volumes pricing is **$0.08/GB-month**. A simple database architecture is: ```text Application -> private/restricted network Raff VM running PostgreSQL/MySQL -> Raff Volume for persistent database state -> database-aware backup / recovery path ``` Use the live Volumes product page as the source of truth for current size limits, attachment behavior, resize behavior, snapshots, and other provider-specific capabilities. For teams that want less host-level database ownership, compare [Raff Managed Databases](/products/managed-databases). For VM-level recovery controls that complement, but do not replace, database-aware recovery, review [Raff Data Protection](/products/data-protection). If compatible database backup artifacts need an independent S3-compatible destination, [Raff Object Storage](/products/object-storage) can be considered as part of the backup architecture. ## Database volume readiness checklist Before putting a production database on a block volume, confirm: - [ ] The volume has one documented purpose and owner. - [ ] The database state is intentionally separate from the VM root disk. - [ ] Filesystem type, mount path, stable identifier, permissions, and startup dependency are documented. - [ ] The engine's data, transaction-log, temporary, and tablespace paths are known. - [ ] Current data and index size are measured. - [ ] Growth rate and time-to-full are monitored. - [ ] Maintenance and migration headroom are included in capacity planning. - [ ] Capacity, latency, IOPS, throughput, and queueing are visible. - [ ] Engine-level storage signals are correlated with device metrics. - [ ] Backups are independent from active database storage. - [ ] Snapshot consistency assumptions are documented. - [ ] RPO and RTO are defined for important data. - [ ] Restore testing includes database startup and application validation. - [ ] Recovery paths exist for deletion, corruption, migration failure, and infrastructure loss. - [ ] The team has explicitly chosen self-hosting over a managed database responsibility model. ## Common mistakes ### Treating the volume as a backup A block volume is active state. It reflects bad writes and deletions too. ### Splitting storage before measuring contention Additional volumes increase mounts, monitoring, configuration, backup, and recovery complexity. Add them for a measured reason. ### Monitoring only percentage used Track growth rate and time-to-full so the team knows how quickly the condition is changing. ### Watching Linux metrics without database context Storage latency is more useful when correlated with WAL/redo, checkpoints, query workload, temporary files, backups, and migrations. ### Keeping backups on the same failure path Historical recovery should not depend entirely on the active database storage. ### Hard-coding mutable product pricing into architecture guidance Use the live Raff Volumes and pricing pages for current commercial values. ## Conclusion Database storage on block volumes works well when the volume is treated as an **explicit state boundary**, not merely extra disk space. For most small teams self-hosting PostgreSQL or MySQL, start with one dedicated database volume. Monitor capacity, growth rate, latency, IOPS, throughput, queueing, and the database signals that explain those changes. Add separate log or temporary-work volumes only when workload evidence justifies the complexity. Then design recovery independently from active storage. A volume can make compute and storage lifecycles easier to manage, but database-aware backups, PITR where required, and tested restores are what make the data recoverable. Continue with [Block Storage for Databases & Containers](/learn/guides/block-storage-volumes-databases-containers-app-data) for the broader storage decision, [Database Monitoring for Small Teams](/learn/guides/database-monitoring-small-teams) for alerts and metrics, or [Database Backup Strategy](/learn/guides/database-backup-strategy-saas-apps) for recovery design. ## Sources - [PostgreSQL: Database File Layout](https://www.postgresql.org/docs/current/storage-file-layout.html) - [PostgreSQL: Monitoring Database Activity](https://www.postgresql.org/docs/current/monitoring.html) - [PostgreSQL: Write-Ahead Log](https://www.postgresql.org/docs/current/runtime-config-wal.html) - [MySQL 8.4: The MySQL Data Directory](https://dev.mysql.com/doc/refman/8.4/en/data-directory.html) - [MySQL 8.4: InnoDB Disk I/O and File Space Management](https://dev.mysql.com/doc/refman/8.4/en/innodb-disk-management.html) - [MySQL 8.4: Performance Schema File I/O Summary Tables](https://dev.mysql.com/doc/refman/8.4/en/performance-schema-file-summary-tables.html) - [Raff Volumes](/products/volumes) - [Raff Managed Databases](/products/managed-databases) - [Raff Data Protection](/products/data-protection) - Product and pricing details reviewed: 2026-09-17. --- ### Cloud Backup Strategy: RPO, Retention & Restore Testing URL: https://rafftechnologies.com/learn/guides/cloud-server-backup-strategies Description: Learn cloud backup strategy for servers using RPO, RTO, retention, isolation, database-aware recovery, and restore testing across production workloads. A cloud backup strategy is a recovery framework that defines what must be recoverable, how much data loss is acceptable, how quickly service must return, how long recovery points are retained, and how restoration is tested. For production servers, the strongest strategy does not depend on one snapshot or one scheduled backup. It separates short-term rollback, retained server recovery, database-aware recovery, independently stored copies, and restore validation so each failure has an appropriate recovery path. In Raff infrastructure reviews, the recurring gap is not usually a missing backup schedule; it is a schedule without a named restore owner, a measured recovery time, or a clear answer for which recovery point should be used after a destructive change. This guide explains how to design a cloud backup strategy around Recovery Point Objective (RPO), Recovery Time Objective (RTO), retention, isolation, snapshots, database-aware protection, and restore testing. For the narrower database model, use [Database Backup Strategy for SaaS Apps](/learn/guides/database-backup-strategy-saas-apps). ## Cloud backup strategy starts with the failure the business must survive A backup method should be selected after the failure scenarios are understood. Start by listing incidents that would materially affect the workload: - accidental deletion; - failed deployment or operating-system upgrade; - database corruption or a bad migration; - ransomware or compromised administrator credentials; - VM or attached-storage loss; - loss of uploaded files or generated assets; - account or platform access failure; - failure discovered days after it began; - loss of configuration, secrets, certificates, or deployment state. Then assign a recovery control to each failure. | Protection layer | Primary job | Strong fit | Main limitation | |---|---|---|---| | Pre-change snapshot | Fast rollback | Failed upgrades, package changes, configuration mistakes | Usually a short-term infrastructure checkpoint | | Scheduled VM backup | Retained server recovery | VM loss, filesystem recovery, server rebuild | May not provide database transaction semantics | | File or object copy | Recover selected files | Uploads, exports, configuration archives | Does not rebuild the complete service | | Logical database backup | Portable or selective database recovery | Object-level restore, migration, additional recovery copy | Full restore can be slow at larger scale | | Physical database backup + logs | Database-native historical recovery | Point-in-time recovery and full database reconstruction | Engine-specific and operationally more complex | | Replication or high availability | Service continuity | Node failure and selected infrastructure faults | Usually reproduces valid-looking destructive writes | | Independent retained copy | Reduces shared failure risk | Credential, account, or infrastructure failure | Requires separate access and restoration planning | **A cloud backup strategy is complete only when every material failure has a documented recovery source and a tested restore path.** This distinction also prevents a common mistake: treating availability as backup. A replica can help a service stay online after a node fails, but it can also reproduce an accidental deletion immediately. ## RPO and RTO determine frequency and recovery depth Recovery Point Objective and Recovery Time Objective should be written before choosing backup frequency or retention. - **RPO** is the maximum acceptable amount of recent data loss. - **RTO** is the maximum acceptable time until the agreed service is usable again. A daily backup may fit a 24-hour RPO for a low-change internal workload. It is unlikely to fit a production database where losing several hours of writes is unacceptable. A fast backup schedule also does not guarantee a short RTO. Restoring a server can include provisioning compute, attaching storage, restoring databases, loading secrets, reconnecting dependencies, validating customer workflows, and changing traffic routes. | Requirement | Backup implication | Recovery implication | |---|---|---| | RPO near 24 hours | Verified daily recovery point may be enough | Historical precision is less demanding | | RPO near 1 hour | More frequent copies or log-based recovery may be needed | Backup monitoring becomes more important | | RPO measured in minutes | Database-native continuous recovery may be required | Missing transaction logs can invalidate the target | | RTO of several hours | Manual restoration can be acceptable | Runbook must still be complete | | RTO near 1 hour | Provisioning and validation need rehearsal | Automation and clear ownership matter | | RTO measured in minutes | Availability architecture may be required in addition to backup | Failover and restore are separate controls | Use [RPO vs RTO for Cloud Backups](/learn/guides/cloud-server-backup-rpo-rto-snapshots) when the recovery targets themselves still need to be defined. **Raff recovery planning should measure RPO from the newest usable recovery point and RTO through application readiness, not database startup alone.** ## Snapshots and backups should have different jobs Snapshots are useful because they can create a rapid infrastructure rollback point around a known change. Good snapshot moments include: - operating-system updates; - major application releases; - database migrations; - storage changes; - firewall or network reconfiguration; - package and runtime upgrades; - extension or driver changes. The snapshot is most valuable when the failure is discovered quickly and the team wants to return the infrastructure to a recent checkpoint. A retained backup has a different job. It preserves recovery history beyond one immediate rollback window and should remain useful after newer snapshots already contain the problem. Do not treat snapshots as the only production recovery layer because they may share: - the same platform or administrative account as production; - the same deletion authority; - the same application-consistency limitations; - a retention period too short for late discovery. Use [Cloud Snapshots vs Backups](/learn/guides/snapshots-vs-backups-cloud-server) for the detailed comparison. ## Retention protects against failures discovered late The newest recovery point is not always the correct recovery point. A bug can corrupt records for several days before anyone notices. A compromised credential can be abused repeatedly. A migration can appear successful while damaging an edge case that is discovered later. Retention should preserve enough history to survive the likely detection window. A practical policy can combine: - frequent recent recovery points for short RPO; - daily retained points for recent operational recovery; - weekly or monthly points when business or legal requirements justify longer history; - explicit pre-change recovery points before high-risk operations; - different retention for production, development, and replaceable workloads. The schedule should come from business risk rather than a copied template. Document: - how long each recovery class is retained; - who can shorten retention; - who can delete recovery points; - whether deletion uses the same credentials as production administration; - where encryption keys and restore credentials are kept; - what happens when storage or retention limits are reached. A longer retention period is useful only when the team can locate and restore the correct point. ## Recovery copies should not share every production failure boundary A copy stored only on the production VM is not sufficient. One server loss, ransomware event, administrator mistake, or disk failure can remove both the workload and its recovery data. Important workloads should reduce shared failure paths where practical. That can mean using: - a separate storage service; - narrower backup credentials; - a separate administrative role or account; - retention controls that are harder to change accidentally; - independently stored exports or backup objects; - a recovery copy outside the server being protected. The familiar 3-2-1 backup rule can be a useful planning heuristic: three copies, two storage types, and one copy separated from the primary environment. It should not be treated as proof of recoverability. A team can satisfy the copy count and still fail recovery because credentials, versions, keys, dependencies, or runbooks are missing. The better question is: **which single incident could remove production and every recovery copy at the same time?** For file-based backup artifacts and exports, [Raff Object Storage](/products/object-storage) can provide an S3-compatible storage destination separate from the VM filesystem. The application or backup tool still needs a tested restore process and appropriate access controls. ## Databases need engine-aware recovery in addition to server protection A VM backup or block-level snapshot captures infrastructure state. An active database has its own transaction, log, consistency, and recovery semantics. Important PostgreSQL, MySQL, and other transactional databases should use recovery methods appropriate to the engine and RPO. Depending on the database, that can include: - logical dumps; - physical or base backups; - write-ahead log or binary-log retention; - point-in-time recovery; - managed backup and recovery features; - replicas or high availability for service continuity. These controls solve different failures. | Database failure | Better leading control | |---|---| | Primary host fails | Replication, HA, or managed failover where required | | Accidental row deletion | Point-in-time recovery or selective restore | | Bad schema migration | Verified backup/PITR plus a pre-change recovery point | | Database corruption | Known-good database-aware recovery copy | | Failed OS or package change | Infrastructure snapshot plus verified database backup | | Complete host loss | Independent database backup and replacement infrastructure | Raff Managed Databases can reduce host-level backup, monitoring, maintenance, and recovery operations for supported engines. The application team still owns schema safety, recovery-point selection, data validation, credentials, migrations, and the decision to return traffic after recovery. Self-hosted databases on Raff VMs give the team more control, but the team must operate the complete database backup chain and prove it through restore testing. For PostgreSQL specifically, [PostgreSQL Replication vs Backups vs Snapshots](/learn/guides/postgresql-replication-vs-backups-vs-snapshots) separates availability, historical recovery, and infrastructure rollback. ## A backup strategy should protect the complete service Recovering the VM disk or database is not enough when the service also depends on configuration and external state. Inventory the complete recovery set: - database records; - uploaded files and object storage; - application configuration; - environment variables and secrets; - TLS certificates and encryption keys; - DNS and routing information; - package, runtime, and database versions; - container definitions or deployment manifests; - users, roles, and access policies; - scheduled jobs and worker configuration; - licensing information for Windows or commercial software; - monitoring and alerting configuration. A service can have perfect data backups and still miss its RTO because the team cannot reconstruct credentials, networking, or compatible software versions. Keep recovery documentation somewhere that remains accessible when production is unavailable. ## Restore testing turns backup assumptions into evidence A completed backup job proves that a copy operation ran. A restore test proves that the recovery path still works. A complete drill should verify: 1. The correct recovery point can be identified. 2. Required credentials and encryption keys are available. 3. Replacement compute and storage can be prepared. 4. Files or database data restore without unresolved integrity errors. 5. The operating system and application start with compatible versions. 6. DNS, certificates, networking, and secrets can be recreated. 7. Critical read and write workflows succeed. 8. The newest recovered data meets the approved RPO. 9. Total service recovery meets the approved RTO. 10. Failed or manual steps are added to the runbook with an owner. Test in an isolated environment where possible. A restored production application should not accidentally send real email, payment events, webhooks, scheduled jobs, or other external side effects during validation. Use [Database Restore Testing](/learn/guides/database-restore-testing-rpo-rto-recovery-validation) for database-specific validation. **A successful restore is stronger recovery evidence than a green backup dashboard.** ## The decision framework matches protection depth to workload impact The same backup design should not be applied to a disposable development VM and a revenue-producing database. | Workload | Practical starting strategy | |---|---| | Disposable development VM | Rebuild automation; snapshot before important experiments | | Marketing website | Scheduled content protection, pre-change snapshots, documented rebuild path | | Internal business application | Retained server backups, configuration protection, recurring restore test | | Production SaaS application | Server recovery, database-aware protection, file/object recovery, isolated retained copies | | Revenue-critical database | PITR where required, retained history, separate failover and restore tests | | Windows business server | Application data, system configuration, users, licensing notes, tested recovery runbook | Choose deeper protection when: - data cannot be recreated; - customers or revenue depend on the service; - the RPO is short; - the RTO is short; - recovery requires several systems in a specific order; - failures may be discovered late; - the same credentials can modify production and backups; - the last complete restore test is unknown. Choose a simpler strategy when the workload is reproducible, low-impact, and a longer recovery window is acceptable. ## Raff separates VM, object, and managed database recovery paths Raff provides different recovery layers rather than one backup mechanism for every workload. A practical architecture can look like: ```text Raff VM ↓ Data Protection for VM-level recovery points Database workload ↓ Database-aware backup or Raff Managed Database recovery workflow Uploads, exports, and compatible backup artifacts ↓ Raff Object Storage Recovery process ↓ Isolated restore test + application validation ``` Use [Raff Data Protection](/products/data-protection) for VM-level protection and recovery workflows. Use [Raff Managed Databases](/products/managed-databases) when the team wants supported database backup and recovery operations handled within a managed service boundary. Use [Raff Object Storage](/products/object-storage) for compatible backup artifacts, exports, and file data that should live independently from one VM filesystem. The responsibility boundary still matters. Raff can operate infrastructure recovery mechanisms, but the application owner must define the business RPO and RTO, choose the correct recovery point, validate the restored service, and decide when customer traffic can safely return. From Raff infrastructure work, the most useful improvement is often not adding another copy. It is assigning one recovery owner, documenting the complete service, and timing an isolated restore from start to usable application. ## The production checklist makes recovery reviewable Before approving a cloud backup strategy, confirm: - [ ] Critical data and configuration are inventoried. - [ ] RPO and RTO are written for each important workload. - [ ] Snapshots have a defined short-term rollback role. - [ ] Retained backups cover failures discovered later. - [ ] Important databases use database-aware recovery methods. - [ ] At least one recovery layer is separated from the production VM. - [ ] Backup credentials and deletion authority are documented. - [ ] Secrets, certificates, and encryption keys are recoverable. - [ ] Uploads and file objects have their own recovery plan. - [ ] Replication is not being treated as historical backup. - [ ] A named person owns restoration. - [ ] The full service has been restored in isolation. - [ ] Measured recovered data age meets the RPO. - [ ] Measured service recovery time meets the RTO. - [ ] The runbook has been updated after the latest drill. :::cluster ## Conclusion A cloud backup strategy is a recovery architecture, not a collection of copies. Define the failures the workload must survive, set RPO and RTO, give snapshots and retained backups different jobs, keep important recovery copies outside the production server's failure path, and use database-aware methods for transactional data. Then test the complete service until the measured recovery point and recovery time meet the business targets. Continue with [RPO vs RTO for Cloud Backups](/learn/guides/cloud-server-backup-rpo-rto-snapshots) to define recovery targets or [Database Backup Strategy for SaaS Apps](/learn/guides/database-backup-strategy-saas-apps) for database-specific protection. :::cta Explore Data Protection Review Raff recovery options after defining the failure scenarios, retention, RPO, RTO, and restore process your workload requires. ::: ## Sources - [NIST SP 800-34 Rev. 1: Contingency Planning Guide](https://csrc.nist.gov/pubs/sp/800/34/r1/final) - [CISA Cybersecurity Performance Goals](https://www.cisa.gov/cybersecurity-performance-goals) - [Raff Data Protection](/products/data-protection) - [Raff Object Storage](/products/object-storage) - [Raff Managed Databases](/products/managed-databases) - Product details reviewed: 2026-08-12 --- ### PostgreSQL Performance Tuning: A Framework for Small SaaS Teams URL: https://rafftechnologies.com/learn/guides/postgresql-performance-tuning-small-saas Description: PostgreSQL performance tuning for SaaS teams: query plans, indexes, vacuum, statistics, locks, connection pressure, and capacity decisions. PostgreSQL performance tuning is the process of finding which execution path or resource is limiting useful database work, then changing the smallest layer that addresses the evidence. For a small SaaS team, the order matters more than the number of settings changed. A slow endpoint can come from an inefficient query plan, a missing or poorly matched index, stale planner statistics, lock contention, connection pressure, maintenance lag, storage pressure, or simply a workload that has outgrown its current capacity. Treating every symptom as a memory or CPU problem usually creates more variables without proving the cause. the operating rule we use for database performance is straightforward: **measure the bottleneck, change one layer, then measure the same workload again.** This guide focuses on that decision framework. Monitoring and alerts have their own owner page, connection pooling has its own owner page, and host-level CPU, memory, disk, and network diagnosis should remain separate from PostgreSQL-specific tuning. ## PostgreSQL tuning starts with the bottleneck, not a setting A tuning change is useful only when it addresses the part of the workload that is actually limiting useful work. For a SaaS application, the first question should be: **where is time being spent?** | Evidence | Likely tuning domain | Typical next question | |---|---|---| | One or a few statements dominate database time | query plan, schema, indexes | why is this statement doing so much work? | | Many sessions wait on locks | transaction scope and locking | which transaction is blocking useful work? | | Pool wait rises while database resources remain healthy | connection/concurrency model | is application concurrency larger than the database budget? | | CPU is high and query plans show expensive scans, joins, or sorts | query/index/schema first | can the same result be produced with less work? | | Temporary work or memory pressure grows | query shape and per-operation memory | are sorts/hashes spilling or multiplying across concurrency? | | Dead-row maintenance or stale estimates become visible | vacuum and statistics | are maintenance and planner statistics keeping up with change rate? | | Storage I/O is saturated | access pattern, indexes, working set, storage | is the database reading or writing more pages than necessary? | | PostgreSQL looks healthy but the product is slow | application or network path | is the bottleneck outside the database? | This is where PostgreSQL performance tuning differs from generic server optimization. Host-level CPU, RAM, disk I/O, and network diagnosis belongs in [Cloud Server Performance Bottlenecks](/learn/guides/cloud-server-performance-bottlenecks-cpu-ram-disk-network). Database metrics and alert design belong in [Database Monitoring for Small Teams](/learn/guides/database-monitoring-small-teams). The tuning page owns the decision that follows those signals: **which PostgreSQL lever should change first?** ## Query plans separate expensive work from misleading symptoms PostgreSQL creates a query plan for each statement. `EXPLAIN` shows the plan PostgreSQL expects to use, while `EXPLAIN ANALYZE` executes the statement and adds actual execution evidence. That makes query plans one of the most useful bridges between a slow application operation and a defensible tuning decision. A useful review looks for relationships between: - estimated rows and actual rows; - sequential scans and indexed access; - join strategy and row counts; - repeated loops; - sorting or hashing work; - rows removed by filters; - buffer activity where available; - the part of the plan that consumes most of the observed time. Large differences between estimated and actual row counts can indicate that the planner does not have a good statistical picture of the data distribution or that the query shape is difficult to estimate. The correct response may be updated statistics, a different query, a more appropriate index, or a schema change—not a global planner override. `EXPLAIN ANALYZE` should also be treated carefully because it **actually executes the statement**. A diagnostic command against an `UPDATE`, `DELETE`, `INSERT`, or other write operation can therefore have real side effects unless it is deliberately contained. For small teams, the practical rule is to use query plans as evidence, not as a scorecard. A sequential scan is not automatically bad, and an index scan is not automatically good. PostgreSQL may correctly choose a sequential scan when a large share of a table must be read. ## Indexes help only when they match real access patterns Indexes are a common way to improve PostgreSQL performance because they can reduce the amount of table data that must be examined for selective queries. They also carry costs: storage, write amplification, maintenance work, and planner complexity. An index decision should therefore begin with a repeated access pattern, not with a rule such as “index every column used in a filter.” Good index candidates commonly have several of these characteristics: - the query matters to user-facing latency or important background work; - the predicate or join is selective enough to avoid reading a large share of the table; - the access pattern occurs often enough to justify maintenance cost; - the index order matches the way columns are filtered or sorted; - the improvement is visible in the query plan and measured workload; - the index does not substantially duplicate an existing one. An index is a weaker candidate when the table is tiny, the query returns a large proportion of rows, writes dominate the workload, or the index would exist only for a rare low-value query. The important operating question is not “does this table have indexes?” It is **whether the real workload has the right indexes and whether those indexes reduce useful work enough to justify their cost.** This also prevents a common tuning failure: adding several indexes at once, seeing latency improve, and never learning which change mattered or what write cost was introduced. ## Vacuum and statistics keep planner evidence usable PostgreSQL uses multi-version concurrency control, so updates and deletes do not simply overwrite the old row version in place. Routine vacuuming is part of normal PostgreSQL operation, and PostgreSQL includes autovacuum to automate `VACUUM` and `ANALYZE` work. For performance tuning, vacuum and statistics matter for two different reasons: - **VACUUM** helps PostgreSQL manage row versions that are no longer needed and supports ongoing storage and transaction-ID housekeeping. - **ANALYZE** collects statistics that the planner uses when estimating row counts and choosing query plans. The useful tuning question is therefore not “should we run VACUUM?” The better question is **whether routine maintenance and statistics are keeping up with this table's change pattern.** Warning signs can include: - planner estimates that repeatedly diverge from actual row counts; - high-churn tables whose maintenance cannot keep pace; - large volumes of obsolete row versions; - tables whose growth or write rate changed substantially; - query plans that shift after statistics are refreshed; - maintenance work competing with peak application traffic. Avoid jumping from these signals straight to aggressive manual maintenance or blanket autovacuum changes. The correct policy depends on table size, update/delete rate, workload timing, storage behavior, and the evidence from PostgreSQL statistics. For self-hosted PostgreSQL, your team owns those settings and their side effects. In a managed service, the platform owns more of the maintenance infrastructure, while the application team still owns query shape, schema design, indexes, and workload behavior. ## Connection pressure can look like a query-performance failure Application latency can rise even when individual SQL statements remain reasonably efficient. A common example is connection or concurrency pressure: many application instances, workers, scheduled jobs, and background services compete for a finite database connection budget. Requests then wait for a connection, or too much concurrent database work increases contention. That problem should not be solved inside this guide by inventing a larger pool. The dedicated [PostgreSQL Connection Pooling](/learn/guides/postgresql-connection-pooling-pgbouncer) guide owns PgBouncer modes, pool sizing, connection budgets, and fleet-wide concurrency. The performance-tuning boundary is narrower: - if **pool wait is high but the database has headroom**, investigate connection allocation and application concurrency; - if **the database is saturated while many sessions execute expensive work**, reducing query cost or concurrency may matter more than expanding the pool; - if **locks dominate wait time**, inspect transaction scope and blockers before adding compute; - if **the same query is slow even at low concurrency**, query/index/statistics work should lead. This distinction matters because raising connection ceilings can make a query-performance problem worse by allowing more expensive work to execute simultaneously. ## The decision framework chooses the next tuning lever The safest tuning order is evidence-driven and reversible where possible. | Symptom and evidence | First tuning lever | Do not do first | |---|---|---| | One query dominates database time | query plan, query shape, index fit | resize the whole database without reviewing the statement | | Estimated rows differ materially from actual rows | statistics, data distribution, query shape | force a planner method globally | | Selective lookup scans far more data than expected | index and predicate fit | add several overlapping indexes at once | | Lock waits dominate latency | transaction duration and locking behavior | add CPU and assume contention disappears | | Pool wait is high but PostgreSQL has headroom | connection/concurrency model | tune unrelated SQL statements | | PostgreSQL is CPU-bound because many costly queries run concurrently | query cost plus concurrency | raise connection limits | | Temporary work or memory pressure grows under concurrency | query shape and memory multiplication | raise per-operation memory globally | | Vacuum/statistics lag behind a high-churn table | maintenance policy and table workload | run disruptive maintenance without measuring the cause | | I/O is saturated by broad scans | query/index/access pattern, then storage capacity | treat faster storage as the only fix | | Queries are efficient and resources are predictably saturated | capacity or architecture | keep micro-tuning healthy queries | Use **query and schema changes first** when a small number of statements produce disproportionate work. Use **index changes** when repeated access patterns can avoid unnecessary scanning or sorting and the write cost is acceptable. Use **maintenance/statistics changes** when the planner or row-version housekeeping is not keeping pace with the data's change pattern. Use **connection/concurrency changes** when the bottleneck is the amount of simultaneous work rather than the cost of one statement. Use **configuration changes** only when there is evidence that a PostgreSQL setting is constraining the measured workload. Settings such as `work_mem` are particularly easy to misread because memory can be used by multiple query operations and across many concurrent sessions. Use **more capacity** when the workload is already efficient enough and the remaining constraint is sustained compute, memory, or storage demand. A larger database is a valid tuning decision when it follows evidence; it is a poor default when query work is obviously wasteful. ## Managed PostgreSQL changes the tuning ownership boundary [Raff Managed PostgreSQL](/products/managed-databases/postgresql) currently supports PostgreSQL 14, 15, and 16 with monitoring, built-in connection pooling, managed backups and point-in-time recovery, private connectivity, storage expansion, and optional high availability. Those capabilities reduce the amount of database-platform work a small team needs to operate, but they do **not** make application performance automatic. The application team still owns: - schema and data-model design; - SQL query quality; - index selection; - transaction scope; - migrations; - application concurrency; - driver or ORM behavior; - workload growth; - capacity decisions; - validation after a tuning change. Raff owns more of the platform boundary for a managed database, including service maintenance and the managed features exposed by the product. For a self-hosted PostgreSQL deployment on a [Raff VM](/products/raff-vm), the team also owns PostgreSQL configuration, autovacuum policy, operating-system behavior, storage setup, patching, monitoring infrastructure, and database-host incidents. That creates a useful decision rule: **choose managed PostgreSQL when the supported service fits and database-host customization is not the source of product value; self-host only when a documented requirement needs the extra control.** For the broader ownership decision, use [PostgreSQL for SaaS Apps](/learn/guides/postgresql-for-saas-apps) and [Managed vs Self-Hosted Databases](/learn/guides/managed-vs-self-hosted-databases). ## Performance tuning needs a re-measurement loop A performance change is incomplete until the same workload is measured again. The tuning loop should preserve a simple sequence: ```text baseline → identify dominant bottleneck → change one meaningful layer → repeat the same representative workload → compare latency, work, waits, and resource use → keep, revise, or roll back the change ``` Changing one meaningful layer at a time is particularly useful for small teams because it keeps cause and effect understandable. If a query rewrite, two indexes, a memory change, and a larger database all arrive in the same deployment, the team may know that performance improved without knowing why. Re-measurement also catches moved bottlenecks. An index may make one query fast enough that lock contention becomes the next constraint. A query rewrite may reduce CPU while increasing write cost. A larger memory setting may reduce temporary I/O but create pressure under higher concurrency. The goal of PostgreSQL performance tuning is therefore not a permanently “tuned” configuration. It is an operating habit: **use production-representative evidence to keep the workload inside acceptable latency and capacity boundaries as the application changes.** :::cluster ## Conclusion PostgreSQL performance tuning works best when a small SaaS team treats it as a prioritization problem rather than a search for universal settings. Start with the dominant symptom, use query plans and workload evidence to identify where PostgreSQL is doing unnecessary or blocked work, then choose the smallest useful lever: query shape, index design, statistics and vacuum, transaction behavior, connection concurrency, configuration, or capacity. Keep monitoring, pooling, host-level performance, HA, and recovery in their own owner pages so each problem has a clear decision path. For the broader production model, return to [PostgreSQL for SaaS Apps](/learn/guides/postgresql-for-saas-apps). If your team wants the platform to own more of PostgreSQL operations while you retain responsibility for queries, schema, indexes, and application behavior, review Raff Managed PostgreSQL. :::cta Explore Managed Databases Compare Raff Managed PostgreSQL and other managed database options for production workloads. ::: ## Sources - [PostgreSQL: Performance Tips](https://www.postgresql.org/docs/current/performance-tips.html) - [PostgreSQL: Using EXPLAIN](https://www.postgresql.org/docs/current/using-explain.html) - [PostgreSQL: Indexes](https://www.postgresql.org/docs/current/indexes.html) - [PostgreSQL: VACUUM](https://www.postgresql.org/docs/current/sql-vacuum.html) - [PostgreSQL: ANALYZE](https://www.postgresql.org/docs/current/sql-analyze.html) - [PostgreSQL: Resource Consumption](https://www.postgresql.org/docs/current/runtime-config-resource.html) - [Raff Managed PostgreSQL](/products/managed-databases/postgresql) - Product details reviewed: 2026-08-12 --- ### Kafka Partitions: Keys, Replication & Scaling Trade-Offs URL: https://rafftechnologies.com/learn/guides/kafka-partitions-keys-replication-scaling Description: Learn Kafka partitions, keys, replication, partition count, skew, and scaling trade-offs so you can plan ordering, parallelism, and growth safely. Kafka partitions are ordered log segments that divide a topic into independent units for storage, ordering, replication, and parallel processing. The important design decision is not whether to use partitions; every Kafka topic is partitioned. It is **how many partitions the topic should have, which record key should control placement, and how replication should protect those partitions without confusing fault tolerance with application parallelism.** our operating view is that partition count should be treated as an application contract before it is treated as a broker tuning knob. A poor key can create hot partitions even in a large cluster, while an oversized partition count can add operational complexity without fixing the actual bottleneck. This guide continues from [Kafka Architecture for Small Teams](/learn/guides/kafka-architecture-small-teams). That connector owns the Kafka foundation; this page owns the deeper decisions around partition keys, partition count, skew, replication factor, and later scaling changes. ## Kafka partitions define the unit of order and parallel work A Kafka topic can contain multiple partitions, and each partition is an ordered sequence of records. Kafka preserves record order within a partition rather than across the entire topic. That makes a partition two things at once: - an **ordering boundary** for related events; and - a **parallelism boundary** for producers, brokers, and consumer work. The architecture consequence is simple: adding partitions can create more independent work, but it also creates more places where ordering, replication, placement, recovery, and monitoring must be understood. The [current Apache Kafka introduction](https://kafka.apache.org/43/getting-started/introduction/) describes topics as partitioned across brokers for scalability and notes that records with the same key are written to the same partition. That same-key behavior is why partition design starts with event correctness rather than a target partition number. The connector guide already covers topics, consumer groups, retention, and the general Kafka operating model. From this point onward, the useful question is narrower: **what should determine the partition boundary for this workload?** ## Partition keys define the ordering domain A partition key should represent the entity whose events need to remain together for ordered processing. Examples can include: - an account ID when account events must remain ordered; - an order ID when each order has an independent event sequence; - a device ID for telemetry that must be processed in device order; - a tenant ID only when tenant-wide ordering is genuinely required. The key should match the **smallest business ordering domain that must remain consistent**. Choosing a broader key than necessary reduces distribution. Choosing a key unrelated to the real ordering requirement can spread dependent events across partitions and move the ordering problem into the application. Key cardinality also matters. A key with many reasonably distributed values can spread work across partitions. A key with only a few dominant values can concentrate traffic even when the topic has many partitions. This creates a useful test: | Key question | Good signal | Risk signal | |---|---|---| | Does the key match the required ordering boundary? | dependent events share a key | dependent events can land separately | | Are there enough distinct keys? | many active values can distribute | very few values dominate traffic | | Is traffic reasonably balanced across keys? | no single entity dominates | one tenant, account, or device dominates | | Will the key remain stable? | key semantics persist over time | key definition may change with product logic | At Raff, we treat the partition key as a **correctness decision first, distribution decision second**. More partitions cannot repair a key that funnels most of the workload into one ordering domain. ## Partition count should follow concurrency, traffic, and growth There is no universal correct partition count for a Kafka topic. The count should be large enough for the required parallelism and expected growth, but not chosen from an arbitrary rule such as “more partitions are always better.” Use four inputs: 1. **Required ordering.** How many independent ordering domains can safely run in parallel? 2. **Consumer concurrency.** How many consumers may need to process this topic concurrently within one consumer group? 3. **Traffic and storage distribution.** Does the workload need more independent shards to spread sustained work? 4. **Growth headroom.** How likely is the topic to require more parallelism later? Partition count matters because one partition is assigned to at most one active consumer within a consumer group at a time. Ten consumers cannot create ten-way partition-level parallelism on a four-partition topic. The reverse matters too. Creating hundreds of partitions for a workload that needs only a few independent workers adds metadata, replica placement, leadership, recovery, and monitoring surface without necessarily improving the application. Do not use a fabricated “messages per second per partition” rule. Real capacity depends on record size, compression, acknowledgements, replication, storage, network, producer batching, consumer behavior, and broker resources. A better planning question is: ```text required parallel workers + expected throughput growth + ordering constraints + operational headroom = partition-count decision ``` If traffic later exceeds the design, first identify whether the limit is partition parallelism, broker capacity, consumer processing time, or key skew. Those require different fixes. ## Hot partitions are usually a distribution problem A hot partition occurs when one partition receives substantially more work than its peers. The cause is often the key distribution rather than the raw number of partitions. Consider a SaaS event topic keyed by tenant ID. If one tenant produces 60% of all events and tenant-wide ordering is required, that tenant's records must remain together. Increasing the topic from 12 partitions to 24 does not split that one tenant's ordered stream across two partitions automatically. The design options are then application decisions: - keep strict tenant-wide ordering and provision for the hot key; - narrow the ordering domain, such as tenant + resource, if the business logic permits it; - separate unusually large workloads into a dedicated topic; - redesign downstream processing so one entity does not serialize unrelated work. This is why “add partitions” should not be the default answer to uneven throughput. Use this diagnosis before changing the topic: | Symptom | Likely first investigation | |---|---| | One partition much busier than peers | key distribution and hot entities | | All partitions busy | aggregate topic capacity and broker resources | | Consumers lag while brokers are comfortable | consumer processing and concurrency | | More consumers do not increase throughput | partition count or a single hot partition | | Storage pressure is concentrated | partition placement, key distribution, retention, and broker capacity | Detailed lag, rebalance, and recovery behavior belongs in the upcoming Kafka consumer-groups guide. The partition page should stop at identifying whether partition design is constraining the consumer layer. ## Replication factor changes fault tolerance, not application parallelism Partition count and replication factor solve different problems. A topic with 12 partitions and a replication factor of 3 still has **12 logical partitions** for application ordering and consumer parallelism. The additional replicas provide redundant copies of those partitions; they do not turn the topic into 36 independent application partitions. The [Apache Kafka 4.3 operations guide](https://kafka.apache.org/43/operations/basic-kafka-operations/) describes replication factor separately from partition count because one controls replica copies while the other controls topic sharding. | Setting | Primary purpose | Does it increase consumer-group parallelism? | |---|---|---| | Partition count | ordering domains and parallel work | Yes, when consumers can use the additional partitions | | Replication factor | redundant copies and broker-failure tolerance | No | | Broker count | physical capacity and replica placement | Not by itself | | Consumer count | processing workers | Only up to available assigned partitions | Kafka documentation commonly illustrates production replication with multiple copies; the exact factor should follow the failure tolerance, cluster size, durability expectations, and placement model of the workload. A higher replication factor also consumes more storage and replication traffic. It should therefore be chosen as a reliability decision, not as a performance shortcut. The deeper relationship between replication, acknowledgements, retention, and data-loss tolerance belongs in [Kafka Retention: Durability, Replication & Data-Loss Trade-Offs](/learn/guides/kafka-retention-durability-replication) once that cluster page is published. ## Increasing partition count later can change routing assumptions Partition count is not always permanent, but changing it later has consequences. Kafka supports increasing the partition count of a topic. However, the current operations documentation warns that key-based partition assignment can change when the number of partitions changes. A producer that maps a key across `N` partitions may map that same key differently after the topic has `N + x` partitions. That means teams should not assume that adding partitions preserves the historical location of every key. Two effects matter: 1. **New records may route differently.** A key that previously mapped to partition 2 may map to another partition after the count changes, depending on the producer's partitioning strategy. 2. **Existing records are not automatically reshuffled into the new partition layout.** Historical data remains where it was written while new traffic can use the expanded set. For applications that depend on uninterrupted per-key ordering across the change, this requires planning. The safe approach is to treat partition expansion as an architecture change with producer, consumer, and ordering implications rather than a routine capacity toggle. Kafka's current operations guide also states that **partition count cannot be reduced**. That asymmetry is another reason not to create a very large count without a workload reason. At Raff, the practical rule is to leave reasonable growth headroom but avoid speculative over-partitioning. A partition increase should have a documented reason such as consumer concurrency, sustained throughput, or a deliberate change in workload distribution. ## The decision framework separates key, partition, replica, and broker choices Partition planning becomes clearer when four decisions are kept separate. | Requirement | Primary design lever | Question to answer | |---|---|---| | Preserve event order for an entity | Partition key | What is the smallest required ordering domain? | | Increase independent processing | Partition count | How many parallel units does the workload need? | | Avoid one overloaded shard | Key distribution | Are traffic-heavy keys skewing one partition? | | Tolerate broker failure | Replication factor and placement | How many copies and failure domains are required? | | Add physical capacity | Broker capacity/count | Is the cluster resource-bound rather than partition-bound? | | Scale consumers | Consumer count + partitions | Are enough partitions available for useful workers? | | Expand later | Partition-count change plan | Will key routing or ordering assumptions change? | Use this sequence before changing infrastructure: ```text 1. Define the ordering domain. 2. Choose a stable, well-distributed key where possible. 3. Estimate required consumer concurrency and throughput headroom. 4. Choose partition count from those requirements. 5. Choose replication from failure tolerance, not parallelism. 6. Verify broker capacity and replica placement. 7. Revisit the design when measurements show a specific bottleneck. ``` The same framework helps diagnose scaling actions: | Observed constraint | Most likely action | |---|---| | One key dominates one partition | revisit key or topic boundary | | All partitions saturated but brokers have room | evaluate more partitions | | Brokers are resource-bound across many partitions | add/resize broker capacity or use managed scaling | | Consumer count exceeds partitions | more consumers alone will not help | | Failure tolerance is insufficient | review replication and placement | | Lag grows with healthy brokers | inspect consumer processing before changing partition count | This separation prevents a common architecture mistake: using broker capacity, partition count, and replication factor as interchangeable scaling controls. ## Managed Kafka changes execution ownership, not partition design A managed Kafka service can take ownership of more broker lifecycle and infrastructure work, but the application team still owns the partition model. Your team still decides: - topic boundaries; - partition keys; - required ordering; - partition count and growth expectations; - consumer concurrency; - acceptable skew; - retention requirements; - application behavior when routing or topology changes. The provider can execute more of the underlying broker operations, capacity work, maintenance, and supported service changes. That distinction is the same operating-model boundary described in [Managed Kafka vs Self-Hosted Kafka](/learn/guides/managed-kafka-vs-self-hosted-kafka). Raff maintains a dedicated [managed Kafka product path](/products/managed-databases/kafka). Product availability, supported versions, plan sizes, and pricing can change independently of this architecture guide, so use the live product page for current service details. For design work, the durable sequence remains: **key correctness -> partition distribution -> consumer parallelism -> replication requirements -> broker capacity.** :::cluster ## Conclusion Kafka partitions should be designed from ordering and workload requirements, not from a generic partition-count formula. Choose the key first because it defines which events must remain together. Choose the partition count from required parallelism, expected traffic, and growth. Treat hot partitions as a distribution problem before assuming more partitions will help. Then choose replication independently for broker-failure tolerance. Partition expansion is possible, but it can change key-routing assumptions and Kafka does not support reducing the count afterward. That makes early headroom useful, but speculative over-partitioning unnecessary. Return to [Kafka Architecture for Small Teams](/learn/guides/kafka-architecture-small-teams) for the broader event-streaming model, then continue with the Kafka consumer-groups guide for lag, rebalances, offsets, and recovery behavior. :::cta Explore Managed Databases Review Raff managed database and Kafka options once your topic, key, partition, and replication requirements are defined. ::: ## Sources - [Apache Kafka 4.3: Introduction](https://kafka.apache.org/43/getting-started/introduction/) - [Apache Kafka 4.3: Basic Kafka Operations](https://kafka.apache.org/43/operations/basic-kafka-operations/) - [Raff Managed Kafka](/products/managed-databases/kafka) - Product path reviewed: 2026-08-12; exact Kafka versions, plans, availability, and pricing intentionally deferred to the live product page. --- ### Kafka Consumer Groups: Lag, Rebalances & Recovery Planning URL: https://rafftechnologies.com/learn/guides/kafka-consumer-groups-lag-rebalances Description: Understand Kafka consumer groups, consumer lag, rebalances, offsets, and recovery planning for reliable production event processing. A Kafka consumer group is a set of consumers that share a group ID and divide topic partitions among themselves so an application can process a stream in parallel while each partition is owned by one group member at a time. For production teams, the important questions begin after that definition: **how much lag is acceptable, what causes rebalances, when should offsets be committed, and how will the group recover after a crash, slow dependency, deployment, or replay?** These decisions determine whether a consumer failure is a short catch-up event or a backlog that outlives the topic's recovery window. our operating rule is to treat consumer lag as a recovery-budget signal before treating it as a reason to add workers. More consumers help only when partitions and downstream capacity allow them to do useful work. This guide continues from [Kafka Architecture for Small Teams](/learn/guides/kafka-architecture-small-teams) and [Kafka Partitions: Keys, Replication & Scaling Trade-Offs](/learn/guides/kafka-partitions-keys-replication-scaling). Those pages own the topic and partition model; this page owns consumer-group behavior, lag, rebalances, offsets, and recovery planning. ## Consumer groups distribute partition ownership across workers Consumers with the same `group.id` cooperate as one logical application. Kafka assigns the group's subscribed partitions across active members, allowing multiple consumer instances to process different partitions concurrently. That creates a simple capacity boundary: a group cannot use more active partition-level workers than the topic provides partitions. If a topic has eight partitions, a ninth consumer in the same group cannot create a ninth independently assigned partition. The detailed partition-count decision belongs in the [Kafka partitions guide](/learn/guides/kafka-partitions-keys-replication-scaling). At the consumer-group layer, the important question is whether the available partition ownership is being converted into useful application throughput. A group should therefore have a clear application owner and workload purpose. Separate applications that must each receive the stream normally use separate consumer groups. Instances of the same horizontally scaled application normally share a group so they divide the work. The group model also creates an operational contract: | Group responsibility | Question the team must answer | |---|---| | Partition ownership | How many workers can do useful work concurrently? | | Offset progress | What processing point is safe to resume from? | | Rebalance behavior | What happens to in-flight work when ownership changes? | | Lag | How far behind is each partition and the group overall? | | Recovery | Can the group catch up before retained events expire? | | Side effects | Are retries and replays safe for downstream systems? | A healthy broker does not guarantee a healthy consumer application. The broker may continue accepting and retaining events while one consumer group falls steadily behind. ## Consumer lag measures backlog, not business latency by itself Consumer lag is the distance between the latest available position in a partition and the consumer group's committed or current processing position, depending on the metric being used. Lag is useful because it shows whether the group is keeping up with incoming work. But a lag value is usually a **record count**, not a direct measure of elapsed time or customer impact. A lag of 10,000 records can mean very different things: - seconds behind on a high-volume telemetry stream; - hours behind on a low-volume billing stream; - one hot partition while the rest of the group is current; - a short deployment spike that is already draining; - a sustained deficit where production exceeds processing capacity. For operational decisions, pair lag with event age, producer rate, consumer processing rate, and the topic's retention window. | Lag pattern | First interpretation | |---|---| | Brief spike that quickly drains | restart, deployment, or short dependency slowdown | | Steady lag at a stable level | consumer is behind but matching current production rate | | Continuously increasing lag | sustained processing capacity deficit or blocked downstream work | | Lag concentrated in one partition | key skew, hot partition, or partition-specific processing issue | | Group-wide lag after scaling/deploy | rebalance or cold-start effects | | Low lag but stale product behavior | investigate downstream processing and commit correctness | At Raff, we use **recovery headroom** as the more useful question: if this group stopped making progress now, how long would the team have to detect the problem, restore processing, and catch up before the oldest required events leave retention? A conceptual recovery budget is: ```text retention window - detection time - repair or restart time - catch-up time = recovery headroom ``` That is more actionable than a universal lag threshold because event rates and business criticality differ by workload. ## Rebalances move partition ownership and can interrupt useful work A rebalance occurs when Kafka needs to change which consumer owns which partitions in a group. Common causes include: - a consumer joining the group; - a consumer leaving or crashing; - a process restart or deployment; - a consumer failing to poll within its allowed interval; - a subscription change; - a change to the subscribed topic's partition count. The Apache Kafka 4.3 `ConsumerRebalanceListener` documentation notes that partition reassignment can be triggered by group membership changes, subscription changes, or administrative partition-count changes. Kafka's consumer configuration also defines `max.poll.interval.ms` as the maximum delay between `poll()` calls before a consumer can be considered failed and its partitions reassigned. The cost of a rebalance is application-specific. It can include: - temporarily reduced processing while ownership changes; - partition-local caches warming again; - state or connections being recreated; - in-flight records needing careful handoff; - offset commits around revoked partitions; - duplicate processing when work completed but its offset was not committed; - delayed catch-up when many consumers restart together. This is why frequent rebalances are not merely a broker metric. They can become application latency and recovery events. A practical distinction is whether the rebalance is **expected** or **churn**. Scaling a group from four to eight workers is expected. A group that repeatedly loses and rejoins the same members because processing exceeds poll timing or because instances are unstable has an operating problem. ## Kafka 4.3 supports classic and newer consumer rebalance protocols Current Apache Kafka 4.3 supports two consumer-group rebalance protocols: the earlier `classic` protocol and the newer `consumer` protocol introduced through KIP-848. Apache Kafka documents the newer Consumer protocol as generally available since Kafka 4.0. Its fully incremental design reduces the need for a global synchronization barrier and is intended to improve consumer-group scalability and rebalance time. In Kafka 4.3, the client can enable it with `group.protocol=consumer`; the classic protocol remains supported. This matters because not every rebalance recommendation applies identically to both protocols. With the newer Consumer protocol: - heartbeat and session-timeout control move more toward broker-side configuration; - assignment is server-side; - the protocol uses incremental assignment behavior; - some classic client settings, including `heartbeat.interval.ms`, `session.timeout.ms`, and `partition.assignment.strategy`, are not used in the same way. Teams should therefore identify which protocol their clients use before applying tuning advice copied from older Kafka material. The durable operational goal is the same in either case: **avoid unnecessary ownership churn and make partition handoff safe when it does occur.** ## Offset commits define the restart point, not whether work was correct Kafka consumers track progress through offsets. A committed offset gives the consumer group a restart position after a process exits or partition ownership moves. Apache Kafka stores committed consumer-group offsets through the group coordinator, and current Kafka clients support both automatic and manual offset commits. The application design question is **when an offset becomes safe to commit relative to the side effect the record causes.** Consider a consumer that reads an order event and writes to another system. If the application commits the offset before completing the side effect, then crashes, the restarted group can resume after a record whose business work never completed. If the application completes the side effect first and crashes before committing the offset, the record may be delivered again after restart. The downstream operation must then tolerate duplicate processing or provide its own idempotency control. | Commit relationship | Main failure risk | |---|---| | Commit before business work completes | skipped business work after failure | | Business work before commit | duplicate work after failure | | Atomic/transactional coordination where supported | lower mismatch risk, with added design complexity | This is why offset management and application correctness cannot be separated. Kafka 4.3's consumer configuration enables automatic commits by default for standard clients, with periodic background commits. That default is convenient, but production applications should deliberately decide whether its timing matches the application's processing and side-effect model. Manual commits provide tighter control, but manual does not automatically mean correct. The commit must still represent a processing point the application can safely resume from. ## Offset reset is a recovery decision rather than a routine tuning control Kafka's `auto.offset.reset` setting defines what a consumer should do when it has no valid committed offset for a partition, including cases where the old offset no longer exists because retained data has been deleted. Kafka 4.3 currently supports behaviors including `earliest`, `latest`, `by_duration`, and `none`. These options carry business consequences: | Reset choice | Operational meaning | |---|---| | Earliest | replay retained history from the oldest available offset | | Latest | begin from the newest available position and skip retained backlog | | By duration | resume from a time-relative position supported by current Kafka clients | | None | fail instead of silently choosing a reset position | There is no universally safe default for every application. For analytics, replaying retained events may be acceptable. For payments or workflow orchestration, silently jumping to the latest offset can skip required business events. Conversely, replaying a large retained history without idempotent consumers can repeat side effects. Offset resets should therefore be part of a documented recovery procedure with a known answer to three questions: 1. What data can be replayed safely? 2. What data must never be skipped? 3. Which downstream side effects are idempotent or deduplicated? This guide intentionally stops at the decision model rather than providing reset commands. Command-level offset manipulation is an operational procedure and should be reviewed against the exact consumer group and incident before execution. ## Recovery planning connects lag, retention, and catch-up capacity A consumer group is recoverable only if the required events remain available long enough for the group to resume and catch up. The recovery plan should consider four intervals: - **detection time:** how long before the team knows the group is unhealthy; - **repair time:** how long to restore the consumer or its downstream dependency; - **backlog growth:** how much new work arrives while the group is impaired; - **catch-up time:** how long restored consumers need to drain the accumulated backlog. A team can have seven days of retention and still have poor recovery if a slow consumer needs six days to drain a two-day backlog. The useful relationship is: ```text catch-up throughput > incoming throughput ``` If restored processing only matches current production, the backlog never shrinks. The group needs temporary or permanent excess processing capacity, a reduction in per-record work, or a change in downstream constraints. Recovery planning should also define the validation step after the lag reaches zero. Zero lag means the group has caught up to the stream position; it does not prove that every downstream side effect, database write, notification, or derived state is correct. For business-critical streams, recovery should end with application-level verification rather than a green lag graph alone. ## The decision framework separates scaling, rebalance, and recovery problems Consumer-group incidents become easier to diagnose when the symptom is mapped to the correct control. | Symptom | Primary decision | Avoid assuming | |---|---|---| | Lag increases across all partitions | consumer/downstream throughput | that more partitions are automatically required | | One partition carries most lag | partition key or workload skew | that more consumers will fix one hot partition | | Consumers repeatedly leave and rejoin | poll timing, process stability, protocol behavior | that the broker is necessarily overloaded | | Lag spikes during every deployment | rollout and rebalance behavior | that sustained capacity is insufficient | | Group recovers but repeats side effects | offset/side-effect ordering and idempotency | that lag itself is the problem | | Offset no longer exists | retention and recovery policy | that `latest` is safe | | More consumers sit idle | available partition ownership | that worker count equals useful parallelism | | Lag reaches zero but product remains stale | downstream validation | that Kafka processing is correct end-to-end | Use this decision order: ```text 1. Confirm whether lag is group-wide or partition-specific. 2. Compare incoming rate with processing and catch-up rate. 3. Check whether a rebalance or member churn explains the change. 4. Verify offset progress and commit behavior. 5. Verify downstream dependencies and side effects. 6. Compare recovery time with the remaining retention window. 7. Scale consumers only when partitions and downstream capacity can use them. ``` This keeps three different problems separate: **partition design, consumer execution, and recovery safety.** The upcoming Kafka monitoring guide will own metric selection, broker health, under-replicated partitions, and alert design. For the broader observability model today, [Database Monitoring for Small Teams](/learn/guides/database-monitoring-small-teams) explains how to choose signals and escalation boundaries without turning dashboards into an operations strategy. ## Managed Kafka moves broker operations but leaves group correctness with the application A managed Kafka service can own more of the broker lifecycle, infrastructure, replication operations, and service maintenance. It does not decide how your consumer application commits offsets or handles repeated business work. The application team still owns: - group IDs and workload boundaries; - consumer concurrency; - acceptable lag and event-age targets; - processing time and downstream backpressure; - commit timing; - idempotency and retry behavior; - replay and offset-reset policy; - validation after recovery. Raff maintains a dedicated [Managed Kafka product path](/products/managed-databases/kafka). Because availability, versions, plan sizes, and pricing can change faster than editorial guidance, use the live product page for current service details rather than treating this guide as a product specification. The operating boundary remains straightforward: a managed platform can reduce the broker pager, but **consumer lag and business recovery still belong to the application team.** :::cluster ## Conclusion Kafka consumer groups turn partitions into horizontally distributed application work, but production reliability depends on more than adding consumers. Treat lag as a recovery signal, distinguish short rebalance spikes from sustained capacity deficits, and make offset commits represent a processing point the application can safely resume from. Recovery plans should account for detection, repair, backlog growth, catch-up capacity, retention, and downstream validation. When lag rises, diagnose **where** it is growing and **why** before scaling. A hot partition, a blocked dependency, a rebalance loop, and insufficient consumer capacity can produce similar dashboards but require different fixes. Return to [Kafka Partitions](/learn/guides/kafka-partitions-keys-replication-scaling) when partition ownership limits useful concurrency, and use [Managed Kafka vs Self-Hosted Kafka](/learn/guides/managed-kafka-vs-self-hosted-kafka) when the unresolved question is who should own the broker platform. :::cta Explore Managed Databases Review Raff Managed Kafka and other managed database options once your consumer-group, recovery, and application ownership requirements are clear. ::: ## Sources - [Apache Kafka 4.3: Consumer Rebalance Protocol](https://kafka.apache.org/43/operations/consumer-rebalance-protocol/) - [Apache Kafka 4.3: Consumer Configuration](https://kafka.apache.org/43/generated/consumer_config.html) - [Apache Kafka 4.3: Consumer Offset Tracking](https://kafka.apache.org/43/implementation/distribution/) - [Apache Kafka 4.3: ConsumerRebalanceListener](https://kafka.apache.org/43/javadoc/org/apache/kafka/clients/consumer/ConsumerRebalanceListener.html) - [Raff Managed Kafka](/products/managed-databases/kafka) - Product path reviewed: 2026-08-12. --- ### Kafka Metrics: Broker Health, Replication & Alerting URL: https://rafftechnologies.com/learn/guides/kafka-metrics-broker-health-replication-alerts Description: Understand Kafka metrics for broker health, replication, consumer progress, request pressure, and alert design for reliable production event streams. Kafka metrics are runtime measurements that show whether brokers, replicas, producers, and consumers are healthy enough to keep an event stream available and current. The useful question is not how many metrics Kafka exposes. It is which signals tell you that a production outcome is at risk. For small teams, monitoring works best when it separates infrastructure health from application progress. [Kafka Architecture for Small Teams](/learn/guides/kafka-architecture-small-teams) owns the topic, partition, and ownership model; this guide owns metric selection, broker and replication health, signal correlation, and alert design. Raff's Kafka metrics model uses **2 layers**: broker/replica health and application stream progress. At Raff, we treat consumer lag as a recovery-budget signal rather than a standalone instruction to add workers. A broker can be healthy while an application falls behind, and a lag spike can be harmless while replicas are temporarily moving. ## Kafka metrics need infrastructure and stream context A useful Kafka monitoring model answers two different questions at the same time: 1. **Can the cluster serve the stream safely?** This is the broker and replica layer: partition availability, replication state, request handling, network processing, storage health, and controller state. 2. **Is the application keeping up with the stream?** This is the producer and consumer layer: produce errors, fetch progress, consumer lag, event age, throttling, and application processing failures. Apache Kafka 4.3 exposes broker, controller, replica, producer, consumer, and coordinator metrics through its monitoring interfaces, including JMX. The official monitoring reference lists metrics such as `UnderReplicatedPartitions`, `UnderMinIsrPartitionCount`, `OfflinePartitionsCount`, request-handler idle ratio, network-processor idle ratio, client request timings, and consumer lag. The important design choice is to avoid turning that catalog into one undifferentiated dashboard. Some metrics describe a failure state. Others describe pressure. Others are useful only when correlated with an application symptom. | Signal class | Examples | Main question | |---|---|---| | Availability | offline partitions, offline replicas, unavailable leaders | Can Kafka serve the required data? | | Replication | under-replicated partitions, under-min-ISR partitions, ISR shrink/expand activity | Is redundancy degrading? | | Broker pressure | request-handler idle ratio, network-processor idle ratio, request latency, queue pressure | Is broker capacity becoming constrained? | | Stream progress | consumer lag, fetch rate, event age | Is the application keeping up? | | Client health | produce/fetch errors, retries, throttling, request time | Are clients communicating and processing normally? | | Storage health | log directory state, disk utilization, partition size | Can the broker continue storing and serving data? | The operating rule is simple: **monitor symptoms first, then use supporting metrics to explain the symptom.** A dashboard is diagnostic context. An alert should represent a condition somebody can act on. ## Broker metrics expose request and resource pressure Broker metrics are most useful when they show either loss of service or sustained pressure that can become loss of service. Apache Kafka's 4.3 monitoring reference identifies `OfflinePartitionsCount` as the number of non-internal topic partitions that are offline. That is materially different from a performance warning: an offline partition means some topic data cannot currently be served through an active leader. Request handling also deserves attention. Kafka exposes `RequestHandlerAvgIdlePercent` and `NetworkProcessorAvgIdlePercent` as ratios between 0 and 1. Apache's documentation describes values above roughly 0.3 as desirable for those idle ratios. Treat that number as a reference from the Kafka project, not as a universal pager threshold for every workload. A sustained fall in idle capacity becomes more meaningful when request latency, queue time, client timeouts, or throughput changes at the same time. One low idle sample during a burst is weaker evidence than a trend where multiple related signals move together. Monitor broker health in groups: - **Request path:** request rate, request latency, queue time, handler idle ratio. - **Network path:** network processor idle ratio, connection behavior, bytes in/out. - **Storage path:** disk utilization, log-directory status, partition size, I/O service time. - **Controller path:** offline partition count, metadata processing errors, controller health. Do not make raw CPU or memory percentage the only broker alarm. Resource utilization explains pressure, but Kafka-specific service signals show whether that pressure is affecting the broker's work. A broker at high CPU with stable request latency and healthy replicas is a different incident from a broker at moderate CPU with offline partitions or failed storage. Start with service impact, then inspect host resources. ## Replication metrics show whether partition redundancy is degrading Replication metrics reveal whether Kafka still has the replica state required to tolerate failures and satisfy the configured durability model. Apache Kafka documents `UnderReplicatedPartitions` as the count of partitions whose in-sync replica set is smaller than the full replica set, with an expected steady-state value of zero. It separately exposes `UnderMinIsrPartitionCount` for partitions whose in-sync replica count has fallen below `min.insync.replicas`. Those two conditions should not be collapsed into one generic "replication warning." | Replication signal | What it means | Operational interpretation | |---|---|---| | Under-replicated partitions | one or more replicas are not in the in-sync set | redundancy is degraded; investigate persistence and duration | | Under-min-ISR partitions | ISR is below the configured minimum | write availability or durability expectations may be threatened, depending on producer settings | | Offline partitions | no active leader is serving the partition | direct availability problem | | ISR shrink activity | replicas are leaving the in-sync set | determine whether this is planned movement or instability | | ISR expansion activity | replicas are returning to the in-sync set | recovery may be underway | | Offline log directory | a broker log directory is unavailable | storage failure may affect replicas on that broker | The [Kafka Partitions guide](/learn/guides/kafka-partitions-keys-replication-scaling) owns replication-factor and partition-design choices. This guide uses those decisions as monitoring context rather than re-explaining them. Alerting should also account for planned operations. A brief under-replicated state during controlled partition reassignment is not equivalent to an unexplained, persistent loss of replica health. The metric is the signal; duration, scope, and change context determine urgency. A stronger alert condition therefore combines at least two dimensions: **severity of the state and persistence of the state**. Add application impact when available. ## Producer and consumer signals connect cluster health to application impact Kafka can remain technically available while the product built on it becomes stale. Producer and consumer metrics close that gap. For producers, watch error rates, retries, request latency, throughput, and throttling. A producer that is timing out or being throttled can reduce event freshness even when every partition is online. For consumers, lag is important but should not stand alone. Apache Kafka's monitoring guidance recommends watching maximum consumer lag and fetch request rate. In application operations, event age can be even easier to map to business impact because it answers how old the data being processed actually is. The detailed lag, rebalance, offset, and recovery model belongs in [Kafka Consumer Groups: Lag, Rebalances & Recovery Planning](/learn/guides/kafka-consumer-groups-lag-rebalances). Keep the monitoring layer narrower: - Is lag growing, stable, or draining? - Is the problem isolated to one group or broad across groups? - Did broker or replication health change at the same time? - Did producer rate, consumer fetch rate, or throttling change? - Is event age crossing the application's freshness objective? - Did a deployment or planned operation explain the movement? A useful correlation pattern is: ```text application symptom -> consumer or producer progress -> broker request health -> replica / partition health -> host and storage context ``` This ordering prevents a common failure mode: starting with dozens of infrastructure graphs before confirming which user-facing or data-processing outcome changed. Consumer lag also should not cannibalize the consumer-group decision page. This guide treats lag as one monitoring signal. The Consumer Groups guide owns why lag grows, how rebalances affect it, offset behavior, catch-up capacity, and recovery planning. ## The alert framework separates pages from diagnostic signals Kafka alerting becomes manageable when every signal is assigned a response class before it fires. Use three classes: | Response class | Use when | Kafka examples | |---|---|---| | Page | service or data availability is at immediate risk and a person must act now | offline partitions; persistent under-min-ISR state tied to write risk; widespread client failures | | Ticket / investigate | degradation is real but does not require immediate interruption | sustained under-replication without current impact; rising request latency with remaining headroom | | Dashboard / context | metric explains incidents but is not actionable by itself | raw CPU, bytes in/out, partition counts, short ISR movement during planned work | The exact threshold depends on workload and business tolerance. Avoid universal rules such as "page whenever lag is above 10,000" or "page whenever CPU exceeds 80%." Neither number says whether the stream is current, recoverable, or unavailable. A better alert definition contains four parts: 1. **Condition:** the specific Kafka or application state. 2. **Duration:** how long it must persist before it is considered abnormal. 3. **Impact:** what availability, freshness, or recovery objective is threatened. 4. **Owner:** the team or service responsible for the next action. For example, a useful consumer alert is not simply "lag > X." It is closer to "lag is increasing for the payments group for a sustained period, event age is outside its freshness objective, and catch-up rate is below incoming rate." The exact values come from that workload's baseline and recovery budget. Similarly, under-replicated partitions should carry context about whether a reassignment or broker maintenance operation is in progress. Offline partitions deserve a higher response class because availability is already affected. For a broader, engine-neutral alert model, [Database Monitoring for Small Teams](/learn/guides/database-monitoring-small-teams) owns the generic monitoring and escalation framework. This page applies the decision to Kafka-specific signals. ## Raff Managed Kafka changes ownership, not observability A managed Kafka service can reduce the broker operations a small team must perform, but it does not remove the need to observe the application that produces and consumes events. Raff Managed Kafka is available through the [managed Kafka product path](/products/managed-databases/kafka). Raff Managed Kafka starts at **$79.99/month for 2 vCPU, 4 GB RAM, and 80 GB storage**. Product pricing and plan details should still be checked on the live product surface when making a deployment decision. The ownership boundary is more useful than a feature checklist: | Layer | Managed-platform responsibility | Application-team responsibility | |---|---|---| | Broker platform | service lifecycle and underlying broker operations | understand service health and escalation state | | Topics and partitions | platform provides Kafka capability | choose topic boundaries, keys, partition strategy | | Replication | platform operates the managed service | understand application durability requirements | | Producers | none of the application's business behavior is transferred | errors, retries, throughput, request behavior | | Consumers | none of the consumer's business correctness is transferred | lag, event age, offsets, rebalances, retries, side effects | | Business freshness | platform cannot define it | set freshness objectives and validate outcomes | At Raff, the monitoring decision is therefore ownership-first. Broker and replica signals tell you when the managed service layer needs attention; producer, consumer, and business-freshness signals tell you when the application team needs to act. The same incident can cross both boundaries, which is why correlation matters more than a single all-green dashboard. Use [Managed Kafka vs Self-Hosted Kafka](/learn/guides/managed-kafka-vs-self-hosted-kafka) when the unresolved decision is whether your team should operate the broker platform itself. Use this guide after that choice to decide what must remain visible either way. :::cluster ## Conclusion Kafka metrics are useful only when they reduce the time between a real problem and the correct response. Monitor broker availability, request pressure, replication state, client errors, and stream progress as related layers. Treat offline partitions and persistent replica degradation differently from raw capacity signals. Treat consumer lag as one input to freshness and recovery, not as a universal scaling command. For Kafka workloads, managed broker operations can reduce infrastructure ownership, but application teams still need clear signals for producer behavior, consumer progress, event freshness, and recovery. Return to [Kafka Architecture for Small Teams](/learn/guides/kafka-architecture-small-teams) for the cluster-wide decision model, then use the Consumer Groups and Partitions guides when monitoring points to a design or recovery problem. :::cta Explore Managed Databases Compare Raff managed data services once your Kafka health signals, alert ownership, and application recovery requirements are clear. ::: ### Sources - [Apache Kafka 4.3 Monitoring](https://kafka.apache.org/43/operations/monitoring/) - [Apache Kafka 4.3 Operations](https://kafka.apache.org/43/operations/) - [Raff Managed Kafka](/products/managed-databases/kafka) - Product and source paths reviewed: 2026-08-12. --- ### Managed vs Self-Managed Kubernetes: What Every Team Needs to Know URL: https://rafftechnologies.com/learn/guides/managed-vs-self-managed-kubernetes Description: Compare managed vs self-managed Kubernetes across control-plane ownership, upgrades, HA, recovery, cost, and team fit—and see when a managed Kubernetes service makes sense. Managed vs self-managed Kubernetes is a decision about **who owns the cluster platform**, not whether the application still uses Kubernetes. In a managed model, the provider operates some or all control-plane lifecycle responsibilities. In a self-managed model, your team owns the control plane, datastore, availability, upgrades, certificates, networking choices, and cluster recovery as well as the workloads running on top. For small teams, that ownership boundary matters more than feature count. **Raff Technologies** supports both self-managed Kubernetes on cloud VMs and a managed Kubernetes service, so the practical question is not whether a team *can* operate Kubernetes itself. It is whether control-plane operation is valuable work for that team to keep. This guide compares the two operating models through responsibility, availability, upgrades, customization, recovery, staffing, and total operating cost. If you are still deciding whether Kubernetes is necessary at all, start with [Container Infrastructure: Docker, K3s, and Kubernetes](/learn/guides/container-infrastructure-docker-k3s-kubernetes). This page assumes the cluster decision has already been made. ## Managed and self-managed Kubernetes share the same workload model Managed and self-managed Kubernetes expose the same core Kubernetes concepts: nodes, pods, deployments, services, namespaces, configuration, secrets, persistent volumes, policies, and the Kubernetes API. The difference is the infrastructure responsibility beneath those workloads. A self-managed cluster typically looks like this: ```text Your team ├── control-plane availability ├── datastore health and recovery ├── certificates ├── cluster upgrades ├── networking and cluster add-ons ├── worker nodes ├── workload configuration ├── application releases └── application and data recovery ``` A managed cluster moves part of that stack to the provider: ```text Provider └── managed control plane Your team ├── worker capacity ├── workloads ├── policies and configuration ├── application releases ├── persistent application data └── application recovery ``` The exact boundary differs between providers, so “managed Kubernetes” should never be interpreted as “the provider operates everything.” Kubernetes production guidance still requires teams to plan for workload capacity, access, resilience, networking, storage, monitoring, and recovery regardless of how the control plane is delivered. For teams comparing K3s with a more explicit self-managed Kubernetes distribution, [K3s vs Kubernetes: Which Cluster Model Fits Your Team?](/learn/guides/k3s-vs-full-kubernetes-cluster-model) owns that narrower distribution decision. ## Control-plane ownership creates the largest operational difference The Kubernetes control plane coordinates the state of the cluster. When your team owns it, the control plane becomes part of your production system. Self-management adds responsibility for areas such as: - API server availability - cluster datastore health - control-plane certificates - scheduler and controller availability - control-plane node capacity - control-plane security updates - version compatibility during upgrades - backup and restore of cluster state - failure recovery during incidents None of these responsibilities are inherently unreasonable. The question is whether they belong inside the team's intended platform scope. For a platform team operating many clusters, owning those controls can create consistency and flexibility. For a five-person product team, the same work can consume time that would otherwise go into the application, deployment process, observability, or customer-facing reliability. This is the central difference between buying compute for Kubernetes and buying a managed Kubernetes operating boundary. ## Upgrades and high availability become recurring platform work A self-managed cluster is not finished after installation. Kubernetes versions change. Cluster components need security updates. Nodes need maintenance. Datastore health must be protected. Control-plane availability has to be designed before a failure rather than during one. A highly available self-managed control plane normally requires multiple control-plane nodes, a reliable datastore, stable networking, and a procedure for upgrades and failure recovery. Kubernetes documents separate production considerations around availability, access, certificates, networking, upgrades, and resilience because the cluster itself is a distributed system. Managed Kubernetes changes who performs part of that work. The provider operates the managed control plane and its lifecycle according to the service model, while the customer remains responsible for the worker and workload side of the cluster. That boundary can reduce the number of infrastructure failure modes a small team must diagnose directly. It does not remove the need for maintenance windows, workload compatibility checks, node upgrades, application testing, or rollback plans. A managed control plane can be healthy while a bad deployment is broken. It can also be healthy while a persistent workload has lost data. Management reduces platform ownership; it does not transfer application ownership. ## The decision framework starts with work your team wants to own The best operating model is the one whose responsibilities match the team's expertise, staffing, and need for control. | Decision area | Managed Kubernetes | Self-managed Kubernetes | |---|---|---| | Control-plane lifecycle | Provider-owned | Team-owned | | Control-plane HA | Delivered by service model | Designed and operated by team | | Cluster datastore | Provider manages control-plane datastore | Team selects, protects, backs up, and restores it | | Control-plane upgrades | Provider-managed process | Team plans and executes | | Worker nodes | Customer responsibility | Customer responsibility | | Workload configuration | Customer responsibility | Customer responsibility | | Application releases | Customer responsibility | Customer responsibility | | Persistent application data | Customer responsibility | Customer responsibility | | Platform customization | More bounded by service | Maximum control | | Incident surface | Smaller control-plane surface | Full cluster stack | | Best fit | Teams that want Kubernetes without making the control plane a product | Teams with explicit platform requirements and ownership | Choose **managed Kubernetes** when: - the Kubernetes API and workload model create value, but control-plane work does not - the team has limited platform engineering capacity - predictable cluster availability matters more than deep control-plane customization - upgrades and control-plane recovery are not differentiating capabilities - the application team wants a clearer infrastructure responsibility boundary Choose **self-managed Kubernetes** when: - the control plane itself must follow organization-specific architecture - networking, datastore, certificates, or cluster components require unusual customization - the organization already has dedicated platform engineering ownership - several clusters must follow a common internally operated lifecycle - regulatory or architectural constraints require deeper control than a managed service exposes **Raff's operating rule is that self-management should solve a named requirement. “We want full control” is only useful when the team can name the control it actually needs.** :::cluster ## Self-managed Kubernetes buys control by adding responsibility Self-managed Kubernetes has real advantages. The team can decide how the cluster is assembled, which Kubernetes distribution to run, how the datastore is deployed, which networking implementation to use, how ingress works, how certificates are handled, which observability stack is installed, and how upgrades are automated. That control matters when the cluster is becoming an internal platform. A mature platform team may prefer self-management because it wants: - standardized cluster bootstrapping - custom network topology - specific storage integrations - strict add-on control - private or unusual infrastructure environments - its own upgrade cadence - custom control-plane observability - infrastructure portability across several environments Those are legitimate reasons to own Kubernetes. The mistake is assuming that self-management is automatically cheaper because the Kubernetes software is open source. The software license may cost nothing, but operating the control plane consumes compute, engineering time, monitoring, testing, maintenance windows, and incident-response capacity. If the team already has those capabilities, the additional burden may be modest. If it does not, control-plane ownership can become one of the most expensive parts of a “cheap” cluster. ## Managed Kubernetes reduces platform work without removing workload work Managed Kubernetes is most valuable when it removes platform tasks the team does not want to differentiate on. The provider can take ownership of the managed control plane while the customer continues working with normal Kubernetes APIs and workload objects. The application team still needs to understand Kubernetes well enough to operate its workloads correctly. Managed Kubernetes does **not** remove responsibility for: - container images - resource requests and limits - deployment health - readiness and liveness behavior - autoscaling policy - secrets and application credentials - namespace and workload policy - persistent application data - database recovery - application observability - release and rollback procedures - cost and worker-node capacity That is an important distinction for small teams. Managed Kubernetes is not Kubernetes without operations. It is Kubernetes with a narrower platform-operations boundary. A team can therefore benefit from managed Kubernetes and still need strong Kubernetes skills. The skills move toward workloads, policy, capacity, and application reliability instead of control-plane assembly and recovery. ## Total operating cost is larger than the cluster invoice Raw infrastructure cost is easy to compare because it appears on an invoice. Platform operating cost is harder because much of it appears as engineering time. A useful total-cost model is: ```text Total Kubernetes cost = control-plane cost + worker compute + storage and networking + monitoring and backups + engineering time + upgrade work + incident ownership + recovery testing ``` Self-managed Kubernetes can have a lower direct service fee. That does not guarantee a lower total operating cost. Managed Kubernetes can have a control-plane charge or higher service price. That does not guarantee it is more expensive once platform labor and recovery risk are included. For small teams, compare at least these four cost categories: | Cost | Managed | Self-managed | |---|---|---| | Direct control-plane charge | Provider-dependent | Your control-plane compute | | Platform engineering | Lower control-plane workload | Higher cluster-lifecycle workload | | Incident ownership | Shared boundary | Full cluster boundary | | Customization opportunity | More constrained | Broader | The financially sensible option depends on the team. A company with a platform group may already have the engineering capability to operate clusters efficiently. A small SaaS team with two backend engineers may pay far more in interrupted product work than it saves on infrastructure. For broader Kubernetes spend, use [Kubernetes Cost Optimization for Startups](/learn/guides/kubernetes-cost-optimization-startups) rather than turning this ownership guide into a pricing guide. ## Raff supports both ownership models Raff supports self-managed Kubernetes on VMs and managed Kubernetes as separate operating models. For self-management, teams can build K3s or another Kubernetes distribution on [Raff VMs](/products/raff-vm). The team owns the guest OS, Kubernetes distribution, control-plane lifecycle, datastore recovery, upgrades, and node operations; the exact compute cost depends on the VM plan and cluster topology selected. For teams that do not want to own the control plane, [Raff Managed Kubernetes](/products/kubernetes) provides a managed cluster path with node pools, autoscaling, built-in monitoring and logs, private VPC networking, and a managed public endpoint with DNS and TLS support. The current Raff standard control plane is **$0/month**. A three-master HA control plane is **$30/month**, and worker nodes start at **$9.99/month**. Dedicated cluster storage is available from 10 GB to 1,000 GB at **$0.10/GB-month**. If the managed ownership model fits your team, use the [Raff Kubernetes product page](/products/kubernetes) for the live worker-node plans, cluster pricing, and current platform features rather than treating this decision guide as the pricing source of truth. Those prices make the ownership comparison unusually direct. A team can evaluate self-managed VMs against a $0 standard managed control plane without treating management as a premium layer by default. The decision still should not be made on control-plane price alone. Choose self-managed infrastructure when owning the platform creates necessary control. Choose managed Kubernetes when the control plane is operational work Raff can carry while your team keeps ownership of applications, workloads, data, and capacity. ## Common ownership mistakes create unnecessary Kubernetes work ### Choosing self-management for theoretical flexibility Flexibility has value only when the team uses it. If no current requirement depends on custom datastore behavior, control-plane networking, unusual add-ons, or a specific lifecycle model, the team may be buying operational surface rather than useful flexibility. ### Assuming managed Kubernetes eliminates Kubernetes expertise Managed clusters still require workload expertise. A provider cannot decide the correct resource request, health probe, autoscaling policy, deployment strategy, secret boundary, or application recovery procedure for your software. ### Comparing only control-plane fees A $0 software license is not a $0 platform. Include the compute needed for control-plane nodes and the time spent on upgrades, backups, monitoring, security patching, and incident recovery. ### Moving application responsibility to the provider mentally A managed control plane does not make application data automatically recoverable. Databases, persistent volumes, object storage, secrets, and application configuration still need explicit backup and recovery decisions. ### Building a platform team before the workload needs one Kubernetes can justify dedicated platform engineering at sufficient scale. Small teams should not create that organizational requirement before the workload creates the need. ## Managed vs self-managed Kubernetes is ultimately an ownership decision Managed and self-managed Kubernetes can run the same kinds of workloads. The difference is how much of the cluster platform your team chooses to carry. Self-management is appropriate when deep control is a real requirement and the team has the engineering capacity to own upgrades, availability, datastore recovery, security, and control-plane incidents. Managed Kubernetes is appropriate when Kubernetes itself is useful but operating the control plane is not differentiating work. Continue with [Container Infrastructure: Docker, K3s, and Kubernetes](/learn/guides/container-infrastructure-docker-k3s-kubernetes) for the broader operating-model map and [K3s vs Kubernetes](/learn/guides/k3s-vs-full-kubernetes-cluster-model) if your remaining question is which self-managed distribution model to use. :::cta cluster Use Raff Managed Kubernetes when your team needs the Kubernetes workload model without making control-plane operations part of its product work. ::: ### Sources - [Kubernetes production environment](https://kubernetes.io/docs/setup/production-environment/) - [Creating highly available clusters with kubeadm](https://kubernetes.io/docs/setup/production-environment/tools/kubeadm/high-availability/) - [Kubernetes cluster administration](https://kubernetes.io/docs/concepts/cluster-administration/) - [Raff Kubernetes](/products/kubernetes) - [Raff VM](/products/raff-vm) --- ### Kubernetes Network Policy: Default Deny, Ingress & Egress URL: https://rafftechnologies.com/learn/guides/kubernetes-network-policies-small-teams Description: Learn Kubernetes NetworkPolicy with default-deny, ingress, egress, selectors, DNS rules, examples, rollout checks, and production verification. Kubernetes NetworkPolicy controls which network connections are allowed to and from selected Pods. The safest small-team pattern is to **map required traffic first, verify that the cluster network enforces NetworkPolicy, then move toward default-deny with explicit allow rules**. **Raff Technologies** keeps Kubernetes worker infrastructure private by default, but private infrastructure networking and Kubernetes NetworkPolicy solve different problems. The VPC defines the infrastructure boundary; NetworkPolicy defines allowed workload traffic inside the cluster. A practical production model is: VPC / private cluster network → Services → NetworkPolicy → Pods → application authentication This page owns the Kubernetes NetworkPolicy decision model: default deny, ingress, egress, selectors, DNS, rollout, and verification. It does not replace the broader [Kubernetes Networking and Storage Architecture](/learn/guides/kubernetes-networking-storage-architecture) or the application-level [Kubernetes Security Best Practices](/learn/guides/kubernetes-security-best-practices-rbac-secrets-pod-security). ## What is a Kubernetes NetworkPolicy? A NetworkPolicy is a namespace-scoped Kubernetes API resource that selects Pods and defines allowed network traffic for ingress, egress, or both. NetworkPolicy is primarily a Layer 3 / Layer 4 control. It can match traffic using constructs such as: - Pod selectors; - namespace selectors; - IP blocks; - protocols; - ports. It does **not** decide whether an authenticated user may call an API endpoint, whether a secret is valid, or whether an application role may modify data. The other important prerequisite is enforcement. Kubernetes requires a network plugin that implements NetworkPolicy. Creating a NetworkPolicy object on a cluster whose networking stack does not enforce it does not create isolation. Before treating NetworkPolicy as a security control, test the actual cluster. ## Pods are non-isolated until a policy selects them Kubernetes treats ingress and egress isolation independently. By default, a Pod is non-isolated for ingress and non-isolated for egress. Restrictions begin when a NetworkPolicy selects the Pod for that direction. That means these are separate states: | State | Ingress | Egress | |---|---|---| | No selecting policy | Allowed | Allowed | | Ingress policy only | Restricted by allowed ingress rules | Still allowed | | Egress policy only | Still allowed | Restricted by allowed egress rules | | Both directions selected | Restricted | Restricted | This is why a default-deny ingress policy does not automatically block outbound traffic, and a default-deny egress policy does not automatically block inbound traffic. ## NetworkPolicies are additive, not ordered firewall rules NetworkPolicy rules do not behave like a top-to-bottom firewall list. When multiple policies select the same Pod for the same direction, their allowed traffic is combined. The effective result is the union of the allowed connections. For Pod A to connect to Pod B: - Pod A's effective egress policy must allow the connection; and - Pod B's effective ingress policy must allow the connection. If either side blocks the flow, the connection fails. This matters operationally because adding a second policy does not override the first. If one policy already allows a path, a second policy cannot "deny" that same path by being evaluated later. Small teams should therefore think in terms of **allowed traffic sets**, not policy order. ## Start with a default-deny baseline only after mapping dependencies A default-deny policy is a useful production baseline because it changes the model from broad implicit trust to explicit allowed paths. A combined ingress-and-egress default deny can look like this: ~~~yaml apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: default-deny-all spec: podSelector: {} policyTypes: - Ingress - Egress ~~~ This selects all Pods in the namespace and allows no ingress or egress until another policy permits required flows. Do not deploy this blindly to an existing production namespace. Map at least: - ingress-controller or Gateway traffic; - internal API calls; - database and cache access; - DNS; - metrics and log collection; - external APIs; - object storage; - identity providers; - payment, email, webhook, or other SaaS dependencies. A deny-first model is strongest when the allow-list reflects the application's actual dependency graph. ## Allow one workload to reach another with selectors A typical policy may allow frontend Pods to reach API Pods on one application port. For example, in the API namespace: ~~~yaml apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: allow-frontend-to-api spec: podSelector: matchLabels: app: api policyTypes: - Ingress ingress: - from: - namespaceSelector: matchLabels: kubernetes.io/metadata.name: frontend podSelector: matchLabels: app: web ports: - protocol: TCP port: 8080 ~~~ This expresses an application relationship rather than relying on Pod IP addresses. The standardized namespace label kubernetes.io/metadata.name is useful when a policy must target one named namespace. For other namespace labels, treat label changes as security-sensitive configuration because changing a trusted label can change the effective traffic boundary. ## Default-deny egress can break DNS immediately DNS is one of the most common failures after teams introduce egress isolation. A default-deny egress policy also blocks DNS unless a separate rule allows traffic to the cluster DNS service. The exact labels and namespace used by DNS can vary by cluster implementation, so inspect your cluster before copying a policy. A common verification flow is: ~~~text kubectl get svc -A | grep -i dns kubectl get pods -A --show-labels | grep -i dns ~~~ Then create a narrowly scoped egress rule that matches the actual DNS service and required ports. Do not assume a copied kube-dns or CoreDNS selector matches every cluster. After applying egress restrictions, verify both: ~~~text kubectl exec -- nslookup kubernetes.default.svc.cluster.local kubectl exec -- nslookup example.com ~~~ Internal and external DNS can fail for different reasons. ## Ingress and egress policies should follow the application traffic graph A small SaaS stack may need only a few flows: ~~~text public routing layer ↓ web Pods ↓ api Pods ↓ database api Pods → DNS api Pods → payment API monitoring → selected metrics endpoints ~~~ From that graph, derive policy boundaries. ### Ingress policy Use ingress rules to answer: > Who is allowed to connect to this workload? Good candidates include: - APIs that should only accept traffic from the web tier; - databases or database proxies that should only accept application traffic; - admin services that should only accept traffic from a management namespace; - metrics endpoints that should only accept traffic from monitoring. ### Egress policy Use egress rules to answer: > Where is this workload allowed to connect? Good candidates include: - a known database service; - DNS; - an object-storage endpoint; - a small set of internal APIs; - specific CIDRs where IP-based policy is stable and appropriate. Standard Kubernetes NetworkPolicy does not provide a portable domain-name policy model for arbitrary SaaS domains. If outbound policy must follow changing DNS names, confirm what your CNI, service mesh, or egress gateway supports instead of assuming a standard NetworkPolicy can express it safely. ## NetworkPolicy does not replace Services, VPCs, TLS, or RBAC NetworkPolicy is one security layer. | Layer | Responsibility | |---|---| | VPC / private networking | Infrastructure reachability boundary | | Service | Stable workload discovery | | Gateway / Ingress | Public application routing | | NetworkPolicy | Allowed Pod network flows | | TLS | Transport encryption and endpoint identity where configured | | RBAC | Kubernetes API authorization | | Application auth | Business-level user and service authorization | A private VPC does not mean every Pod should trust every other Pod. A NetworkPolicy cannot decide whether a logged-in user may delete a record. RBAC cannot stop one already-running Pod from opening a TCP connection to another workload. Treat these controls as complementary. Use [Kubernetes Services Explained](/learn/guides/kubernetes-services-ingress-load-balancers) for service reachability and [Kubernetes Security Best Practices](/learn/guides/kubernetes-security-best-practices-rbac-secrets-pod-security) for RBAC, ServiceAccounts, Secrets, and Pod Security. ## Multi-tenant clusters need stronger network boundaries NetworkPolicy becomes especially important when unrelated workloads share a cluster. Examples include: - MSP customers; - multiple internal teams; - staging and production workloads; - shared platform services; - client-specific namespaces. A useful boundary can be: ~~~text client-a namespace ─X→ client-b namespace client-a namespace → shared monitoring client-b namespace → shared monitoring platform ingress → approved application ports ~~~ NetworkPolicy is not a complete multi-tenancy model by itself. RBAC, namespace ownership, Secrets, admission controls, node placement, storage isolation, and operational access also matter. For MSP-specific architecture, use [Kubernetes Multi-Tenancy for MSPs](/learn/guides/multi-tenant-kubernetes-for-msps). ## Test the deny path, not only the allow path A policy is not verified because kubectl accepted the YAML. After a policy change, test: 1. a connection that should succeed; 2. a connection that should fail; 3. DNS resolution; 4. ingress or Gateway traffic; 5. database/cache connectivity; 6. monitoring and logging; 7. any required external API. Example: ~~~text # Expected allow kubectl exec -- curl -sS http://api:8080/health # Expected deny kubectl exec -- curl --connect-timeout 3 http://api:8080/health ~~~ Use disposable test Pods where appropriate rather than changing production workloads solely to test networking. Remember that policy application is implemented by the network plugin and may not be instantaneous during changes. Do not design deployment logic around an assumption that policy transitions happen atomically everywhere. ## A safe rollout sequence for existing production clusters For an existing application, use this order: ### 1. Inventory traffic Document Service-to-Service, namespace-to-namespace, and external dependencies. ### 2. Verify NetworkPolicy enforcement Apply a small test policy in a non-critical namespace and prove that a denied connection actually fails. ### 3. Start with one namespace Do not introduce cluster-wide isolation across every workload at once. ### 4. Add explicit allow rules Allow only known application paths. ### 5. Add default-deny ingress Ingress isolation is often easier to reason about first because callers are usually better understood. ### 6. Add egress restrictions carefully Map DNS and external APIs before denying outbound traffic. ### 7. Verify after every change Test both positive and negative cases. This staged rollout is easier to debug than applying a large policy bundle and discovering hidden dependencies during an incident. ## How NetworkPolicy maps to Raff Kubernetes Raff Kubernetes keeps worker nodes on private cluster networking and provides a managed public endpoint for traffic that should enter the cluster. The live product also includes VPC isolation, node pools, autoscaling, monitoring, logs, and standard Kubernetes tooling. That infrastructure boundary is separate from workload policy. NetworkPolicy should still be designed around application flows and verified on the actual cluster before it is treated as an active security control. The production rule is simple: **Private infrastructure reduces exposure. NetworkPolicy reduces unnecessary trust between workloads.** For current cluster capabilities and pricing, use the [Raff Kubernetes product page](/products/kubernetes) rather than relying on a security guide as a pricing source of truth. ## Kubernetes NetworkPolicy checklist Before calling a namespace isolated, verify: ### Enforcement - [ ] The cluster network plugin supports NetworkPolicy. - [ ] A test deny rule has been proven to block traffic. ### Ingress - [ ] Public routing traffic is explicitly allowed where needed. - [ ] Internal APIs accept traffic only from expected callers. - [ ] Database/cache traffic is scoped to required workloads. ### Egress - [ ] DNS is explicitly accounted for. - [ ] Required external APIs are documented. - [ ] Observability traffic still works. - [ ] Object storage and managed-service dependencies are covered. ### Operations - [ ] Namespace and Pod labels used in policies are controlled. - [ ] Both allowed and denied flows are tested. - [ ] Policy changes have a rollback path. - [ ] The team can explain why each allowed path exists. ## Final recommendation Do not start by writing dozens of NetworkPolicy objects. Start by drawing the application's required traffic graph. Verify that the cluster actually enforces NetworkPolicy. Then introduce default-deny boundaries one namespace at a time and add only the flows the application requires. For a small team, a short, explainable set of policies that is tested regularly is stronger than a large policy library nobody understands. Continue with [Kubernetes Networking and Storage Architecture](/learn/guides/kubernetes-networking-storage-architecture) for the infrastructure model, [Kubernetes Services Explained](/learn/guides/kubernetes-services-ingress-load-balancers) for Service and traffic exposure, and [Kubernetes Security Best Practices](/learn/guides/kubernetes-security-best-practices-rbac-secrets-pod-security) for the wider cluster-security baseline. :::cta cluster Deploy Raff Kubernetes on private cluster networking, then apply workload policies around the traffic your applications actually require. ::: ### Sources - [Kubernetes — Network Policies](https://kubernetes.io/docs/concepts/services-networking/network-policies/) - [Kubernetes — Declare Network Policy](https://kubernetes.io/docs/tasks/administer-cluster/declare-network-policy/) - [Raff — Managed Kubernetes](/products/kubernetes) --- ### Kubernetes Persistent Storage: PVs, PVCs & StorageClasses URL: https://rafftechnologies.com/learn/guides/kubernetes-persistent-storage-volumes-storage-classes-backups Description: Understand Kubernetes persistent storage, PVs, PVCs, StorageClasses, access modes, reclaim policies, StatefulSets, snapshots, and backup boundaries. Kubernetes persistent storage keeps application data available beyond the lifecycle of an individual Pod. The core model is simple: **Pods are replaceable; persistent state should not be tied to one Pod instance.** For most teams, the storage path looks like this: Pod → PersistentVolumeClaim (PVC) → PersistentVolume (PV) → StorageClass / storage backend **Raff Technologies** provides dedicated storage for stateful Kubernetes workloads, but the same production rule applies: a volume that survives Pod replacement is not the same thing as a backup. This guide owns the Kubernetes storage decision model: PVs, PVCs, StorageClasses, access modes, reclaim policy, binding behavior, StatefulSets, snapshots, and backup boundaries. For implementation steps, the separate persistent-storage tutorial should own the YAML and verification flow rather than duplicating it here. ## What is Kubernetes persistent storage? Kubernetes persistent storage is the set of resources and storage integrations that let workload data survive ordinary Pod replacement. Without persistent storage, data written only to a container or Pod-local filesystem can disappear when the Pod is recreated. Persistent storage separates the application lifecycle from the storage lifecycle. The important objects are: | Object | Responsibility | |---|---| | PersistentVolume (PV) | Represents storage available to the cluster | | PersistentVolumeClaim (PVC) | Requests storage for a workload | | StorageClass | Describes how a class of storage is provisioned and managed | | CSI driver / storage implementation | Connects Kubernetes to the underlying storage system | For application teams, the PVC is normally the main contract. The workload asks for storage; the cluster decides how the matching storage is provisioned. ## PV vs PVC: what is the difference? A **PersistentVolume** is the storage resource. A **PersistentVolumeClaim** is the workload's request to use storage. Think of it as: PVC = "I need 20 GiB of storage with these characteristics." PV = "Here is the storage resource that satisfies the request." When dynamic provisioning is available, a team often creates only the PVC. The StorageClass and storage driver provision the underlying PV automatically. That is usually more portable than making every application define infrastructure-specific PV objects. A minimal conceptual PVC can look like: ~~~yaml apiVersion: v1 kind: PersistentVolumeClaim metadata: name: app-data spec: accessModes: - ReadWriteOnce resources: requests: storage: 20Gi ~~~ The exact StorageClass, access modes, expansion behavior, and provisioning model depend on the cluster. ## StorageClass defines how storage is provisioned A Kubernetes StorageClass describes a category of storage and the rules used to provision it. Important StorageClass properties can include: - the storage provisioner; - provider-specific parameters; - reclaim policy; - volume binding mode; - whether volume expansion is allowed. Application teams should know which StorageClass they are requesting. "PVC created successfully" is not enough if the team does not understand the lifecycle and failure behavior behind that class. A useful production review asks: 1. Which StorageClass is this PVC using? 2. Is the storage dynamically provisioned? 3. Can the volume expand? 4. What reclaim policy applies? 5. Does topology affect where the Pod can run? 6. What backup or recovery path protects the data? ## Immediate vs WaitForFirstConsumer binding Storage topology can affect scheduling. With **Immediate** binding, Kubernetes may bind or provision storage as soon as the PVC is created. With **WaitForFirstConsumer**, binding or provisioning is delayed until Kubernetes knows where the consuming Pod is being scheduled. That distinction matters when the underlying storage has topology constraints. Conceptually: Immediate: PVC → provision storage → later schedule Pod WaitForFirstConsumer: PVC → schedule Pod context → provision compatible storage For topology-aware storage, WaitForFirstConsumer can reduce the risk of provisioning a volume in a location that conflicts with the workload's scheduling requirements. The StorageClass should own that infrastructure policy so application YAML does not need to encode provider-specific topology logic. ## Access modes do not mean what many teams assume Kubernetes supports several PersistentVolume access modes. Common modes include: - ReadWriteOnce (RWO) - ReadOnlyMany (ROX) - ReadWriteMany (RWX) - ReadWriteOncePod (RWOP) A common mistake is reading **ReadWriteOnce** as "only one Pod can ever mount this volume." RWO is defined around a single **node**. Multiple Pods on the same node may still access the volume depending on the storage implementation. ReadWriteOncePod is the stricter model intended for a single Pod when supported by the CSI stack. Choose the access mode from the application requirement: | Requirement | Storage implication | |---|---| | One stateful replica writes the filesystem | RWO/RWOP may fit | | Multiple replicas need one shared writable filesystem | RWX-capable storage is required | | Replicas can rebuild state | Persistent storage may not be needed | | Data is a database | Database-aware recovery matters more than generic shared disk | | Data is user uploads | Object storage may be a cleaner architecture | Do not select a shared-write access mode merely "for flexibility." Shared writable filesystems add coordination and failure behavior the application must actually need. ## StatefulSet helps identity, but it does not replace storage design StatefulSets are useful for workloads that need stable Pod identity or ordered lifecycle behavior. They can also create per-Pod PVCs through volumeClaimTemplates. For example, a three-replica StatefulSet can create separate storage claims for each replica rather than one shared volume. Conceptually: stateful-app-0 → PVC 0 → PV 0 stateful-app-1 → PVC 1 → PV 1 stateful-app-2 → PVC 2 → PV 2 But StatefulSet does not make the application data highly available by itself. If replica 0 owns a volume and that application's replication model is broken, Kubernetes cannot infer how to reconstruct the business data merely because the workload is a StatefulSet. Application replication, storage durability, backup, and restore remain separate responsibilities. ## Reclaim policy controls deletion lifecycle Reclaim policy determines what happens to the underlying storage after a claim is released. Two important policies are: ### Delete The backing storage is normally deleted when the dynamically provisioned PV is released. This can be appropriate for disposable environments, but it creates a sharp deletion boundary for important state. ### Retain The PV and underlying storage are preserved for manual recovery or reuse. Retain can provide an extra safety boundary around accidental PVC deletion, but it also creates operational cleanup work. The decision should follow the value of the data. | Data | Reclaim policy to evaluate | |---|---| | Disposable test environment | Delete | | Rebuildable cache | Delete | | Business-critical filesystem data | Retain may be safer | | Database storage | Retain may help, but backups are still required | Reclaim policy is not a backup policy. Retaining a corrupted volume preserves corrupted data. Retaining a volume after a destructive migration preserves the destructive result. ## Volume expansion needs both platform and filesystem support Some StorageClasses allow PVC expansion. When supported, teams can increase requested storage without replacing the workload's entire storage architecture. But three separate layers may be involved: 1. the PVC request; 2. the underlying storage capacity; 3. the filesystem inside the volume. A larger volume allocation does not automatically mean every filesystem or application uses the extra capacity immediately. Before relying on online expansion, verify the behavior of the actual StorageClass and workload. Capacity planning should also leave headroom. Waiting until a stateful workload is at 99% disk usage before expanding it creates avoidable operational risk. ## Persistent storage vs object storage vs managed databases Not every form of application state belongs on a PVC. Use the state type to choose the system. | State | Better starting point | |---|---| | Application image/code | Container registry | | Database records | Managed database or database-specific storage model | | Shared uploads and media | Object storage in many architectures | | Durable mounted filesystem | PVC / PV | | Cache | Rebuildable cache or cache service | | Logs and metrics | Observability system | | Backup archives | Separate backup destination | For small teams, a stateless Kubernetes application connected privately to a managed database and object storage is often easier to operate than a cluster where every workload carries local persistent state. PersistentVolumes are valuable when the application genuinely requires filesystem semantics. They should not be the default answer to every data problem. ## Snapshots are not the same as backups Kubernetes VolumeSnapshot resources can provide point-in-time storage snapshots when the cluster and CSI storage implementation support them. Snapshots are useful, but they do not automatically provide: - application consistency; - off-cluster recovery; - independent credentials; - long-term retention; - restore verification. A snapshot taken while an application is actively writing may capture a storage-consistent or crash-consistent point without guaranteeing application-level consistency. For databases and other transactional systems, the backup method should understand the application where necessary. The layers are different: | Protection layer | Protects mainly against | |---|---| | Persistent volume | Pod replacement | | Storage replication | Loss of a storage component | | Snapshot | Point-in-time storage state | | Application/database backup | Logical recovery | | Tested restore | Proves the recovery path actually works | Production storage should have a recovery design beyond "the PVC still exists." ## Back up the business state, not only the Kubernetes object A PVC manifest is easy to recreate. The business data inside the volume is what matters. For every important PVC, document: - what data the volume contains; - whether the application can be paused or quiesced for backup; - backup frequency; - retention; - recovery point objective (RPO); - recovery time objective (RTO); - restore destination; - who owns restore testing. The [Kubernetes Backup and Disaster Recovery Strategy](/learn/guides/kubernetes-backup-disaster-recovery-strategy) covers the broader recovery model. A strong recovery test restores data into a usable application, not merely into a storage device. ## How Raff Kubernetes storage fits this model Raff Kubernetes provides dedicated storage nodes for stateful workloads. The current public Kubernetes pricing lists: - storage nodes from **10 GB to 1,000 GB**; - **$0.10/GB-month** pricing; - 100 GB at **$10/month**; - replicated storage for stateful workloads; - free same-region cluster-to-storage traffic. Use the [Raff Kubernetes product page](/products/kubernetes) as the live source for platform behavior and pricing. This is separate from Raff's standalone Block Storage Volumes product for VMs. Do not assume the VM block-storage price is the Kubernetes storage-node price. The architecture boundary remains: Kubernetes workload → PVC/PV → cluster storage → backup/recovery Storage durability reduces infrastructure failure risk. It does not replace application-aware backups or restore testing. ## Production persistent-storage checklist Before shipping a stateful Kubernetes workload, verify: ### Workload fit - [ ] The application genuinely needs mounted persistent filesystem state. - [ ] A managed database or object storage is not a better fit. ### PVC and StorageClass - [ ] The intended StorageClass is explicit or understood. - [ ] Requested capacity includes growth headroom. - [ ] The access mode matches the workload. - [ ] Expansion behavior is understood. - [ ] Volume binding mode fits topology requirements. ### Lifecycle - [ ] Reclaim policy is understood. - [ ] Accidental PVC deletion behavior is known. - [ ] StatefulSet volumeClaimTemplates are understood where used. ### Recovery - [ ] Persistent storage is not treated as a backup. - [ ] Snapshot support is verified before relying on it. - [ ] Business-critical data has a backup method. - [ ] Retention and RPO/RTO are documented. - [ ] A restore has been tested. ## Final recommendation Use PersistentVolumes when a Kubernetes workload genuinely needs durable mounted filesystem state. Let PVCs express application storage requirements and let StorageClasses define the platform provisioning behavior. Choose access modes deliberately, understand reclaim and binding policies, and keep application state outside the cluster when a managed database or object storage is the better system. Most importantly, design recovery separately from persistence. A PVC that survives a Pod replacement proves persistence. A tested restore proves recoverability. Continue with [Kubernetes Networking and Storage Architecture](/learn/guides/kubernetes-networking-storage-architecture) for the wider platform model, [Kubernetes Cluster Sizing](/learn/guides/kubernetes-cluster-sizing) for capacity planning, and [Kubernetes Backup and Disaster Recovery Strategy](/learn/guides/kubernetes-backup-disaster-recovery-strategy) for recovery design. :::cta cluster Deploy Raff Kubernetes and add dedicated persistent storage only where your workload requires durable filesystem state. ::: ### Sources - [Kubernetes — Persistent Volumes](https://kubernetes.io/docs/concepts/storage/persistent-volumes/) - [Kubernetes — Storage Classes](https://kubernetes.io/docs/concepts/storage/storage-classes/) - [Kubernetes — Volumes](https://kubernetes.io/docs/concepts/storage/volumes/) - [Kubernetes — StatefulSets](https://kubernetes.io/docs/concepts/workloads/controllers/statefulset/) - [Kubernetes — Volume Snapshots](https://kubernetes.io/docs/concepts/storage/volume-snapshots/) - [Raff — Managed Kubernetes](/products/kubernetes) --- ### Kubernetes Cluster Management for Small Teams: Operations Guide URL: https://rafftechnologies.com/learn/guides/kubernetes-cluster-management-small-teams Description: Kubernetes cluster management for small teams: capacity, upgrades, recovery, autoscaling, monitoring, security, and cost. Kubernetes cluster management is the ongoing work of keeping a production cluster **schedulable, recoverable, observable, secure, upgradeable, and cost-controlled after the cluster is created**. For a small team, the operating model matters more than the number of Kubernetes tools installed. **Raff Technologies** can remove much of the control-plane administration through managed Kubernetes, but workload ownership still remains with the application team: capacity, requests and limits, upgrade compatibility, recovery, autoscaling boundaries, monitoring, and security all need explicit decisions. This guide is the connector for the **Kubernetes Operations & Cost** cluster. It owns the broad operating model and routes each specialist question to a deeper guide rather than duplicating them here. The small-team operating loop is: **capacity → workload policy → upgrades → recovery → scaling → observability → security → cost review** If any one of those areas depends on someone remembering what to do during an incident, the cluster is not yet operationally mature. ## What does Kubernetes cluster management include? Kubernetes cluster management is the recurring day-2 work required to keep workloads healthy after deployment. For most small teams, it includes eight responsibilities: 1. Worker capacity and scheduling 2. Resource requests and limits 3. Version upgrades and maintenance 4. Backup and disaster recovery 5. Autoscaling 6. Monitoring and observability 7. Security and access control 8. Cost and workload governance These areas are connected, but they fail differently. A capacity problem appears as Pending Pods or degraded failover. A bad request/limit policy creates poor scheduling, throttling, or OOM failures. An upgrade problem appears during maintenance. A backup problem appears when data must be restored. An observability problem appears when the team cannot explain why users are failing. That is why the correct question is not "Do we have Kubernetes monitoring?" It is: > **Can the team detect, understand, and recover from the failures the cluster is expected to experience?** ## Managed Kubernetes reduces platform work, not workload ownership A managed control plane changes the responsibility boundary. | Responsibility | Managed platform can handle | Application team still owns | |---|---|---| | Control-plane operation | API server, etcd, control-plane availability | Choose required availability level | | Worker infrastructure | Provisioning and node lifecycle tooling | Capacity, minimum nodes, placement strategy | | Kubernetes version delivery | Platform upgrade mechanism | Workload compatibility and maintenance approval | | Node health | Infrastructure visibility and lifecycle actions | Replica design and disruption tolerance | | Persistent data | Storage infrastructure | Backup, retention, restore testing | | Monitoring | Baseline cluster/node visibility | Application SLOs, alerts, escalation | | Security baseline | Private infrastructure and platform controls | RBAC, service accounts, workload policy | | Billing | Usage and plan visibility | Rightsizing and cost boundaries | This distinction prevents a common mistake: assuming that a managed control plane means the provider now owns application reliability. It does not. For the ownership decision itself, use [Managed vs Self-Managed Kubernetes](/learn/guides/managed-vs-self-managed-kubernetes). ## Capacity management starts with schedulable worker headroom Cluster capacity is not the sum of advertised node CPU and memory. The scheduler must also account for: - workload resource requests; - node allocatable capacity; - taints and tolerations; - affinity and anti-affinity; - node selectors; - Pod topology rules; - system workloads; - the failure headroom the cluster must preserve. A cluster can look lightly utilized and still fail to schedule a Pod because no node satisfies the workload's constraints. A small-team capacity review should answer: - How much allocatable CPU and memory exists? - How much is committed through requests? - What happens if one worker disappears? - Which workloads require separate pools? - Which Pods are currently Pending and why? - Is growth limited by CPU, memory, storage, or placement constraints? If the cluster is expected to survive one worker failure, remaining nodes must have enough room to absorb critical workloads. That is not wasted capacity. It is capacity tied to a named failure scenario. Use [Kubernetes Cluster Sizing](/learn/guides/kubernetes-cluster-sizing) for the full sizing model and [Kubernetes Node Pools](/learn/guides/kubernetes-node-pools) for workload separation and scaling boundaries. ## Requests and limits turn application behavior into scheduler policy Resource requests and limits connect workload behavior to scheduling. Requests tell Kubernetes what capacity a workload needs for placement. Limits constrain maximum resource use. Poor values create two opposite problems: - over-requesting wastes worker capacity and can prevent Pods from scheduling; - under-requesting can create contention, OOM failures, throttling, and misleading autoscaling behavior. The operating process should be: **measure → set → observe → adjust** For each production workload, record: - baseline CPU; - peak CPU; - baseline memory; - peak memory; - startup bursts; - minimum replica count; - latency or throughput sensitivity. Then review declarations when workload behavior changes. Do not treat requests and limits as one-time deployment settings. Use [Kubernetes Requests vs Limits](/learn/guides/kubernetes-requests-vs-limits) for the deeper resource-governance model. ## Upgrades need compatibility, sequence, and rollback ownership Kubernetes upgrades are operational changes, not routine package updates. A safe maintenance path should answer: 1. Which version is the cluster moving to? 2. Which APIs or controllers could be affected? 3. Have workloads been tested against the target version? 4. Which nodes are drained first? 5. Do PodDisruptionBudgets and replica counts permit safe movement? 6. Is critical data recoverable before maintenance starts? 7. What proves the upgrade succeeded? 8. What is the recovery plan if it does not? The current Raff Kubernetes platform supports **in-place cluster upgrades**, including rolling node-by-node upgrades while the cluster API remains reachable. Automatic patch upgrades can use a maintenance window, or teams can keep upgrades manual. Raff also drains nodes before removal and honors PodDisruptionBudgets, reducing the chance that node lifecycle actions unexpectedly force-kill workloads. Those platform capabilities make the maintenance mechanism safer, but the application team still owns compatibility. Use [Kubernetes Upgrade Strategy](/learn/guides/kubernetes-upgrade-strategy) for version planning, maintenance windows, risk, and rollback. ## Backup and disaster recovery protect application state A Kubernetes cluster definition can often be recreated. Business data may not be. Separate recovery into three layers: | Layer | Example | Recovery question | |---|---|---| | Declarative configuration | Deployments, Services, policies | Can the workload definition be recreated? | | Persistent business data | Database records, files, queues | Can the actual business state be restored? | | External dependencies | DNS, secrets, APIs, object storage | Can the application reconnect safely? | A copy of YAML is not a database backup. Replicated storage is not the same as an application-consistent restore point. A PersistentVolume that survives Pod replacement does not prove that yesterday's valid state can be recovered. For every critical workload, document: - RPO; - RTO; - backup method; - retention; - restore owner; - restore test cadence. Use [Kubernetes Backup and Disaster Recovery Strategy](/learn/guides/kubernetes-backup-disaster-recovery-strategy) for the full recovery model and [Kubernetes Persistent Storage](/learn/guides/kubernetes-persistent-storage-volumes-storage-classes-backups) for the live-storage boundary. ## Autoscaling needs both signals and hard boundaries Autoscaling answers two different questions: **How many workload replicas should run?** and **How much worker capacity should exist to place them?** Horizontal Pod Autoscaler changes workload replica counts from metrics. Node autoscaling changes worker capacity when Pods cannot be scheduled or when capacity remains unused. The two mechanisms interact. A workload can scale from three to ten replicas and create Pending Pods. Worker autoscaling can then add capacity. When demand falls, the reverse can happen. The operating policy should define: - minimum replicas; - maximum replicas; - worker-pool minimums; - worker-pool maximums; - scale-up trigger; - scale-down tolerance; - workloads that must never scale to zero; - acceptable cost ceiling. Raff Kubernetes worker pools currently autoscale between configured minimum and maximum values and use scheduler-aware fit checks for scale-up plus utilization and reschedule simulation for scale-down. Autoscaling should always have a budget boundary. Unlimited scaling is not resilience. Use [Kubernetes Autoscaling](/learn/guides/kubernetes-autoscaling-hpa-node-scaling-cost) for the deeper HPA, node-scaling, and cost model. ## Monitoring should answer operational questions A cluster-management dashboard is useful only when it helps the team make a decision. At minimum, operations should be able to answer: - Are control-plane components healthy? - Are worker nodes healthy? - Are Pods restarting? - Are Pods Pending? - Is CPU or memory pressure increasing? - Are deployments progressing? - Did behavior change after a release? - Is the problem cluster-wide or limited to one workload? Raff Kubernetes currently exposes cluster and node CPU/memory, workload views, live Pod logs, an activity feed, and control-plane health signals including etcd latency, component restarts, and API-server errors. Application teams still need workload-specific indicators such as: - request success rate; - latency; - queue depth; - business-event failures; - error budgets; - application traces where useful. Infrastructure monitoring tells you what the cluster is doing. Application observability tells you whether users are getting the intended result. Use [Kubernetes Monitoring: Metrics, Logs, Events, and Traces](/learn/guides/kubernetes-monitoring-metrics-logs-events-traces) for the deeper signal model. ## Security management is recurring configuration review Kubernetes security changes as teams, namespaces, applications, and dependencies change. A recurring review should include: - RBAC permissions; - cluster-admin access; - ServiceAccounts; - Secrets; - Pod Security; - NetworkPolicy; - image provenance and patching; - public exposure; - administrative kubeconfig access. A private VPC reduces public infrastructure exposure. It does not automatically mean every Pod should trust every other Pod. Likewise, a NetworkPolicy controls network reachability but does not replace RBAC or application authorization. Use [Kubernetes Security Best Practices](/learn/guides/kubernetes-security-best-practices-rbac-secrets-pod-security) for the broader security baseline and [Kubernetes Network Policy](/learn/guides/kubernetes-network-policies-small-teams) for workload-level network isolation. ## Cost optimization comes after reliability basics Cost belongs inside cluster management, but it should not be the first operating priority. Prioritize: 1. Can critical workloads reschedule? 2. Can business data be restored? 3. Can failures be detected quickly? 4. Is administrative access controlled? 5. Are upgrades repeatable? 6. Are requests and limits based on evidence? 7. Are scaling limits bounded? 8. Is idle capacity or workload sprawl creating waste? Only then optimize aggressively. The most common cost levers are: - rightsizing worker plans; - right-sizing requests; - deleting unused workloads; - setting autoscaling minimums and maximums deliberately; - separating workload classes into appropriate node pools; - moving suitable data services out of the cluster; - reviewing observability retention and storage growth. Use [Kubernetes Cost Optimization](/learn/guides/kubernetes-cost-optimization-startups) for the cost-specific framework. ## A small-team Kubernetes operations checklist A useful review cadence is risk-based rather than calendar theater. ### Continuously - critical workload health; - failed Pods and jobs; - node failure; - control-plane health; - capacity pressure; - alerting for user-impacting failures. ### Weekly - restart patterns; - Pending Pods; - unusual resource growth; - autoscaling behavior; - failed backup jobs; - unexpected cost changes. ### Monthly - requests and limits; - unused workloads; - RBAC and administrative access; - storage growth; - backup retention; - node-pool fit. ### Before upgrades - target version; - API compatibility; - workload validation; - disruption budgets; - restore state; - maintenance sequence. ### Periodically - restore test; - failure-capacity assumption; - scaling limits; - security baseline; - namespace and multi-tenancy model. The exact cadence should follow workload criticality. The important point is that operations become recurring decisions rather than emergency memory. ## How Raff Kubernetes maps to this operating model The live Raff Kubernetes product currently includes: - **$0 standard control plane**; - optional three-master HA for **$30/month**; - worker nodes starting at **$9.99/month**; - 2 vCPU / 4 GB worker nodes at **$17.99/month**; - dedicated Kubernetes storage at **$0.10/GB-month**; - private VPC networking; - managed public endpoint with DNS and TLS; - node pools; - worker-pool autoscaling; - built-in monitoring and logs; - control-plane health visibility; - in-place cluster upgrades; - Kubernetes API, CLI, and Terraform support. For live pricing and current platform scope, use the [Raff Kubernetes product page](/products/kubernetes) rather than treating this operations guide as the permanent pricing source of truth. The value of managed Kubernetes for a small team is not that day-2 operations disappear. It is that the provider removes control-plane infrastructure work so the team can focus on the operational decisions that actually affect application reliability. ## Final operating model A small team does not need a dedicated platform department to operate Kubernetes responsibly. It needs a clear responsibility model. Keep enough worker headroom for the failure scenarios you claim to support. Set requests from measured workload behavior. Treat upgrades as planned compatibility changes. Protect application state independently from the cluster. Bound autoscaling. Monitor signals that explain user impact. Review security continuously. Optimize cost after recovery and reliability basics are covered. That is Kubernetes cluster management. Continue with [Kubernetes Cluster Sizing](/learn/guides/kubernetes-cluster-sizing), [Kubernetes Requests vs Limits](/learn/guides/kubernetes-requests-vs-limits), [Kubernetes Upgrade Strategy](/learn/guides/kubernetes-upgrade-strategy), [Kubernetes Backup and Disaster Recovery](/learn/guides/kubernetes-backup-disaster-recovery-strategy), [Kubernetes Autoscaling](/learn/guides/kubernetes-autoscaling-hpa-node-scaling-cost), [Kubernetes Monitoring](/learn/guides/kubernetes-monitoring-metrics-logs-events-traces), and [Kubernetes Security Best Practices](/learn/guides/kubernetes-security-best-practices-rbac-secrets-pod-security) for each specialist decision. :::cta cluster Run Raff Kubernetes with a managed control plane, then apply this operating model to the workloads your team owns. ::: ### Sources - [Kubernetes — Cluster Administration](https://kubernetes.io/docs/concepts/cluster-administration/) - [Kubernetes — Managing Resources for Containers](https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/) - [Kubernetes — Version Skew Policy](https://kubernetes.io/releases/version-skew-policy/) - [Kubernetes — Safely Drain a Node](https://kubernetes.io/docs/tasks/administer-cluster/safely-drain-node/) - [Raff — Managed Kubernetes](/products/kubernetes) - [Raff — Release Notes](/release-notes) --- ### Kubernetes Cluster Sizing: Nodes, Capacity & Headroom URL: https://rafftechnologies.com/learn/guides/kubernetes-cluster-sizing Description: Size Kubernetes clusters using Node Allocatable, workload requests, worker shape, rollout overlap, N+1 failure headroom, and autoscaling boundaries. Kubernetes cluster sizing is the process of choosing enough **allocatable worker capacity** for normal workload demand, deployments, maintenance, failures, and expected growth. The safest small-team model is: **required worker capacity = workload requests + system overhead + rollout overlap + failure reserve + planned growth** Do not size a cluster from the raw CPU and memory printed on a node plan alone. Kubernetes schedules Pods against **Node Allocatable**, and workload requests, placement constraints, DaemonSets, and failure headroom determine how much capacity is actually usable. **Raff Technologies** separates the managed control plane from worker capacity, so teams can size workers from application demand rather than treating control-plane resources as workload capacity. This guide owns the cluster-sizing decision: requests, allocatable capacity, node count, worker shape, N+1 failure tolerance, rollout headroom, and autoscaling boundaries. ## Start with Node Allocatable, not raw node capacity A node's advertised capacity is not the same as the resources available to application Pods. Kubernetes exposes **Node Allocatable** after accounting for resources reserved for the operating system, Kubernetes system daemons, and eviction thresholds. The scheduler uses allocatable capacity as the ceiling for Pod placement. The sizing chain is: ~~~text raw node capacity - system-reserved resources - kube-reserved resources - eviction reserve = Node Allocatable Node Allocatable - DaemonSet / platform requests - application requests = remaining schedulable capacity ~~~ This is why two nodes with the same advertised vCPU and memory can provide different effective application capacity if their system workloads and reservations differ. For an existing cluster, inspect the real value rather than estimating it: ~~~bash kubectl get nodes kubectl describe node ~~~ Look for the **Capacity** and **Allocatable** sections. Use the measured allocatable values in capacity planning. ## Resource requests are the scheduler's primary sizing signal Kubernetes does not place Pods from observed average CPU alone. The scheduler primarily considers resource **requests** when deciding whether a Pod fits on a node. For every production workload, collect: - CPU request per Pod; - memory request per Pod; - minimum replica count; - maximum or expected rollout replica count; - node-selector, affinity, taint, and topology constraints; - required persistent-storage topology; - DaemonSet overhead on eligible nodes. Then calculate baseline requested capacity. For one workload: ~~~text baseline CPU request = CPU request per Pod × minimum replicas baseline memory request = memory request per Pod × minimum replicas ~~~ Repeat for all workloads that must run at the same time. Observed usage still matters because requests should be tuned from real behavior. But the sizing model must understand what Kubernetes will actually reserve for scheduling. Use [Kubernetes Requests vs Limits](/learn/guides/kubernetes-requests-vs-limits) for request and limit tuning. ## Calculate the baseline workload before choosing nodes Do not start with a preferred node plan. Start with the workload. Create a table like: | Workload | CPU request / Pod | Memory request / Pod | Required replicas | Total CPU | Total memory | |---|---:|---:|---:|---:|---:| | Web | measured value | measured value | required floor | calculate | calculate | | API | measured value | measured value | required floor | calculate | calculate | | Worker | measured value | measured value | required floor | calculate | calculate | | System workloads | measured separately | measured separately | per node/cluster | calculate | calculate | Then add deployment and failure requirements. This avoids a common mistake: buying a few nodes first and adjusting requests until workloads happen to fit. Capacity planning should work in the opposite direction. ## Size for rollout overlap, not only steady state A rolling deployment can temporarily run old and new Pods at the same time. For a Deployment, surge behavior depends on rollout configuration such as maxSurge and maxUnavailable. That means the cluster may need more schedulable capacity during deployment than during steady state. If a critical service normally runs four replicas and the rollout policy permits extra replicas, those temporary Pods must still fit somewhere. Include the actual deployment strategy in sizing. Ask: - How many extra Pods can a rollout create? - Can those Pods fit while all existing replicas are still healthy? - Does anti-affinity force the new replicas onto different nodes? - Would the rollout stall because the cluster is too tightly packed? A cluster that only fits its steady-state workload may be undersized for normal maintenance. ## Add explicit failure headroom Failure reserve should correspond to a named availability target. For many small production clusters, the most useful test is: > **Can the required workload still schedule if one worker is unavailable?** This is often called an **N+1** capacity model. The test is not simply whether total capacity remains above total requests. Placement constraints also matter. For each worker pool: 1. remove the largest or most important eligible worker from the capacity model; 2. calculate the remaining allocatable CPU and memory; 3. verify that required workload requests can still fit; 4. confirm topology, affinity, taints, and storage constraints do not prevent rescheduling. If required Pods cannot fit, the cluster may be healthy during normal operation but unable to tolerate the node failure or maintenance drain you expect it to survive. ## Maintenance drains use the same spare capacity as failures Planned maintenance looks similar to a temporary node failure from the scheduler's perspective. When a node is drained, its evictable workloads need another eligible node. Before calling a cluster production-ready, test: ~~~bash kubectl drain --ignore-daemonsets ~~~ Do this only in an appropriate test or maintenance context with a rollback plan. The operational question is: **Can the cluster drain one worker without leaving required workloads Pending or violating the service's availability objective?** If not, either: - increase baseline worker capacity; - reduce or correct workload requests; - change placement constraints; - adjust replica design; - use an autoscaling strategy that can add capacity early enough for the maintenance process. Do not rely on emergency node creation as the only plan for routine maintenance. ## Choose worker size from workload shape After calculating required capacity, choose worker shapes. Larger and smaller workers trade different risks. ### Larger workers Advantages: - fewer nodes to operate; - less repeated DaemonSet overhead; - more room for Pods with large requests; - potentially better bin packing for mixed workloads. Trade-offs: - losing one node removes more cluster capacity; - one large workload can create a larger blast radius; - scaling occurs in larger capacity increments. ### Smaller workers Advantages: - smaller failure unit; - finer-grained scaling; - workloads can be spread across more nodes. Trade-offs: - more per-node overhead; - more DaemonSet replicas; - more nodes to manage; - more potential resource fragmentation. The useful rule is: **Choose nodes large enough for the largest normal Pod, but not so large that losing one node removes more capacity than your failure model can absorb.** ## CPU and memory ratios matter more than total capacity alone A cluster can have enough total resources and still be unable to schedule Pods. Example: ~~~text remaining cluster capacity: 8 vCPU 4 GiB memory new Pod request: 1 vCPU 6 GiB memory ~~~ The cluster has plenty of CPU, but the Pod cannot fit because memory is the constrained resource. The opposite can happen for CPU-heavy workloads. Track both: - requested CPU / allocatable CPU; - requested memory / allocatable memory. Do not average them into one utilization number. Also inspect the largest Pod requests. One oversized Pod can determine the minimum node shape even if total cluster utilization is low. ## Placement constraints can create local capacity shortages Total cluster capacity is not always usable by every Pod. Scheduling can be constrained by: - nodeSelector; - node affinity; - pod anti-affinity; - taints and tolerations; - topology spread constraints; - storage topology; - architecture requirements; - dedicated node pools. A cluster may have 20 GiB of free memory overall while a specific workload has no eligible node with 4 GiB free. For this reason, capacity planning should be performed **per eligible worker pool**, not only across the whole cluster. Use [Kubernetes Node Pools](/learn/guides/kubernetes-node-pools) when workloads require different scaling, isolation, or capacity classes. ## Pod density is a ceiling, not a target Kubernetes v1.37 documents large-cluster configurations of up to: - 110 Pods per node; - 5,000 nodes; - 150,000 total Pods; - 300,000 total containers. These are scalability limits under validated large-cluster conditions, not recommended small-team utilization targets. A production node can reach CPU, memory, network, storage, or operational limits long before it reaches the maximum Pod count. Pod density is also affected by: - per-Pod networking overhead; - logging; - image pulls; - DaemonSets; - container count; - ephemeral storage; - application startup behavior. Size from workload resources and operational behavior first. ## Headroom should have a reason There is no universal Kubernetes headroom percentage that fits every cluster. Instead, reserve capacity for specific requirements: | Headroom | What it protects | |---|---| | Node-failure reserve | Required workloads still fit after one worker is lost | | Maintenance reserve | Workloads can move during drains/upgrades | | Rollout reserve | Surge replicas fit during deployments | | Autoscaler warm-up | Existing workers absorb short-term demand while new nodes join | | Growth reserve | Known near-term workload growth does not force emergency changes | Avoid an unexplained rule such as "always leave 30% free." A lower reserve may be acceptable for a development environment. A customer-facing workload with strict availability may need more. Document the reason for the reserve and review it as workload behavior changes. ## Autoscaling does not replace the safe minimum fleet Autoscaling is a capacity mechanism, not instant failover. When Pods become unschedulable, adding a node still takes time: 1. the scheduler identifies Pending Pods; 2. the autoscaler decides additional capacity is needed; 3. infrastructure is provisioned; 4. the node joins the cluster; 5. system workloads start; 6. the node becomes Ready; 7. workloads are scheduled. Your minimum worker pool should therefore be able to support the workload conditions that must survive immediately. Use autoscaling for additional demand above the safe baseline. Define: - minimum node count; - maximum node count; - expected worker shape; - scale-up triggers; - scale-down policy; - acceptable provisioning latency; - maximum acceptable monthly capacity. Use [Kubernetes Autoscaling](/learn/guides/kubernetes-autoscaling-hpa-node-scaling-cost) for the deeper interaction between HPA and node scaling. ## Minimum cluster size depends on the availability target There is no universal number of worker nodes for every Kubernetes cluster. A development cluster may intentionally accept a small topology. A production cluster should derive node count from: - required replicas; - failure tolerance; - placement rules; - maintenance model; - worker shape; - expected traffic; - autoscaling behavior. For Raff Managed Kubernetes specifically, the current product maintains a **two-worker floor** for autoscaled node pools. That platform constraint is not a universal Kubernetes recommendation. It is a Raff product behavior and should be combined with the workload's own availability target. If your application must remain healthy after one worker is unavailable, verify the remaining worker capacity—not simply the node count. ## Control-plane sizing is separate from worker sizing In self-managed Kubernetes, the team must size and operate the control plane, including the API server and datastore. In managed Kubernetes, worker sizing can be handled independently. Raff currently offers: - a **$0 standard managed control plane**; - optional three-master HA for **$30/month**. Worker resources are billed separately and should be sized from workload demand. For production workloads, control-plane HA is an availability decision. It does not add application worker capacity. Use [Managed vs Self-Managed Kubernetes](/learn/guides/managed-vs-self-managed-kubernetes) for the ownership trade-off. ## Current Raff worker shapes Current Raff Kubernetes worker plans include: | Worker | vCPU | Memory | Monthly price | |---|---:|---:|---:| | Starter | 1 | 2 GB | $9.99 | | Standard | 2 | 4 GB | $17.99 | | Performance | 4 | 8 GB | $33.99 | | High Memory | 8 | 16 GB | $71.99 | | Large | 8 | 32 GB | $119.99 | | Scale | 16 | 64 GB | $229.99 | Dedicated Kubernetes storage is priced separately at **$0.10/GB-month**, from 10 GB to 1,000 GB per storage node. Use the [Raff Kubernetes product page](/products/kubernetes) for live pricing and product constraints because worker plans can change over time. The correct workflow is still: **calculate required capacity first → choose worker shapes second → calculate cost third.** Do not reverse that order. ## A practical sizing worksheet Use this sequence for a new or existing cluster. ### Step 1 — Inventory minimum workloads List every production workload and its minimum replica count. ### Step 2 — Sum CPU and memory requests Calculate requested CPU and memory for the minimum healthy workload set. ### Step 3 — Measure platform overhead Use real Node Allocatable and system Pod requests where possible. ### Step 4 — Add rollout overlap Account for surge replicas and maintenance behavior. ### Step 5 — Define failure tolerance Decide whether one worker or another named failure must be tolerated without waiting for new capacity. ### Step 6 — Apply placement constraints Split the model by node pool or eligibility class. ### Step 7 — Choose worker shapes Select nodes that fit both aggregate capacity and the largest individual Pods. ### Step 8 — Verify N+1 capacity Remove one worker from the model and recalculate. ### Step 9 — Set autoscaling boundaries Choose safe minimums and explicit maximums. ### Step 10 — Validate with production data After launch, compare: - requests vs actual usage; - Pending Pod events; - deployment surge behavior; - node drains; - autoscaler activity; - worker utilization; - cost. Sizing is a recurring capacity decision, not a one-time launch calculation. ## Common Kubernetes sizing mistakes ### Using utilization instead of requests Observed utilization alone does not tell you whether the scheduler can place another Pod. ### Using requests without validating them Bad requests produce bad sizing. Review requests against actual workload behavior. ### Ignoring Node Allocatable Raw node capacity overstates what application Pods can use. ### Ignoring deployment surge Clusters that fit steady state can still fail during rolling updates. ### Ignoring failure domains Total capacity can look sufficient while one worker pool lacks the resources to tolerate a node loss. ### Letting autoscaling define the minimum Autoscaling is not instant. Establish a safe baseline first. ### Buying node shapes before calculating workloads Capacity requirements should determine node selection, not the other way around. ## Final sizing rule Start with workload requests and measured Node Allocatable. Add system overhead, rollout overlap, a named failure reserve, and justified growth headroom. Then choose worker shapes that fit both the aggregate demand and the largest individual Pods. Finally, test whether the cluster still meets its availability objective when one eligible worker is unavailable. That is a defensible Kubernetes sizing model. Continue with [Kubernetes Node Pools](/learn/guides/kubernetes-node-pools) for workload separation, [Kubernetes Requests vs Limits](/learn/guides/kubernetes-requests-vs-limits) for request tuning, [Kubernetes Autoscaling](/learn/guides/kubernetes-autoscaling-hpa-node-scaling-cost) for dynamic capacity, and [Kubernetes Cluster Management](/learn/guides/kubernetes-cluster-management-small-teams) for the full day-2 operating model. :::cta cluster Size the safe worker baseline first, then deploy Raff Kubernetes with explicit node-pool and autoscaling boundaries. ::: ### Sources - [Kubernetes — Resource Management for Pods and Containers](https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/) - [Kubernetes — Reserve Compute Resources for System Daemons](https://kubernetes.io/docs/tasks/administer-cluster/reserve-compute-resources/) - [Kubernetes — Considerations for Large Clusters](https://kubernetes.io/docs/setup/best-practices/cluster-large/) - [Raff — Managed Kubernetes](/products/kubernetes) --- ### Kubernetes Node Pools: Workload Separation and Scaling URL: https://rafftechnologies.com/learn/guides/kubernetes-node-pools Description: Learn when Kubernetes node pools make sense, how labels, affinity, taints, autoscaling, failure capacity, and worker shapes affect workload placement. Kubernetes node pools are groups of worker nodes that share an infrastructure profile, such as the same compute shape, scaling policy, or workload purpose. They become useful when one cluster contains workloads that should not all run on the same kind of worker. A general application tier may fit balanced nodes, while memory-heavy services, CPU-sensitive workloads, batch jobs, or stronger placement boundaries may justify a separate pool. **Raff Technologies** supports multiple worker pools inside one managed Kubernetes cluster, with a plan, node count, and autoscaling bounds set per pool. The goal is not to create a pool for every application. It is to create another pool only when a workload class has a real difference in compute shape, placement, isolation, maintenance, or scaling behavior. Use [Kubernetes Cluster Sizing](/learn/guides/kubernetes-cluster-sizing) first if total worker capacity is still unclear. This guide owns the next decision: **how should that capacity be divided into node pools without fragmenting the cluster unnecessarily?** ## What is a Kubernetes node pool? A Kubernetes node pool is an infrastructure-managed group of worker nodes that share a common configuration. The core Kubernetes API defines Nodes and scheduling primitives; it does not define one universal NodePool object that every platform must use. Managed Kubernetes providers commonly group similar Nodes into node pools, node groups, or worker pools. Kubernetes still schedules Pods to **Nodes**. Pool-aware placement is usually expressed through: - node labels; - nodeSelector; - node affinity; - taints and tolerations; - topology rules; - provider-managed pool configuration. A simple cluster may have one pool: General pool → web + API + workers A larger cluster may use: General pool → web / API Memory pool → memory-heavy services CPU pool → latency-sensitive or compute-heavy services Batch pool → queue workers / scheduled jobs The extra pools are useful only when those workload classes need meaningfully different infrastructure behavior. ## Start with one general pool For a small team, one general-purpose pool is usually the cleanest starting point. A shared pool gives the Kubernetes scheduler more freedom to place Pods across available capacity. Create another pool only when you can state the reason clearly. | Workload difference | Separate pool usually helps? | Why | |---|---:|---| | Same CPU/memory profile and same scaling behavior | No | Shared capacity improves scheduling flexibility | | Memory-heavy workloads waste capacity on general nodes | Yes | A memory-oriented node shape can fit better | | Latency-sensitive workloads need dedicated CPU behavior | Often | A CPU-optimized pool can isolate the compute profile | | Batch workloads scale differently from APIs | Often | Independent min/max node counts become useful | | One workload needs reserved worker capacity | Often | Dedicated placement protects capacity | | Teams merely own different applications | Usually no | Namespaces and policy may be enough | | One microservice is slightly larger | Usually no | A new pool may create more fragmentation than value | | Workloads need different maintenance or placement rules | Often | The pool becomes a real operational boundary | The test is simple: > **Would this workload still need a separate pool if the application names changed?** If not, the boundary is probably organizational rather than infrastructural. ## Labels and node affinity place workloads on eligible workers Node labels describe characteristics the scheduler can use for placement. A node pool may expose or receive labels such as: workload-class=memory environment=production pool=batch Pods can then use nodeSelector or node affinity. **nodeSelector** is a simple hard match. **Node affinity** is more expressive and can be either required or preferred. Kubernetes currently distinguishes: - requiredDuringSchedulingIgnoredDuringExecution — the Pod cannot schedule unless the rule matches; - preferredDuringSchedulingIgnoredDuringExecution — the scheduler prefers matching nodes but can use other eligible nodes. Use a hard rule only when the workload genuinely requires that pool. Every required placement rule reduces scheduler flexibility. A cluster can have idle CPU and memory overall while a Pod remains Pending because the pool it is allowed to use is full. For optimization rather than strict placement, prefer a soft rule. ## Taints and tolerations protect dedicated pools Affinity helps attract workloads to selected nodes. Taints solve the opposite problem: they repel Pods that do not have a matching toleration. For a dedicated memory pool, a strong pattern is: Dedicated node pool: - label: workload-class=memory - taint: dedicated=memory:NoSchedule Target workload: - required node affinity for workload-class=memory - matching toleration for dedicated=memory This does two jobs: 1. the workload is directed toward the intended pool; 2. unrelated workloads do not consume the dedicated capacity accidentally. A toleration alone does **not** force a Pod onto a tainted node. It only makes that node eligible again. If placement must be explicit, combine the toleration with nodeSelector or node affinity. Kubernetes documents this same pattern for dedicated nodes. Taints and tolerations are scheduling controls, not security boundaries. RBAC, NetworkPolicy, namespace policy, Secrets, and application authorization remain separate concerns. ## Node pools should align with scaling behavior A separate pool is most useful when its workloads have a distinct demand pattern. For example: General application pool: traffic-driven web/API replicas Batch pool: queue-driven workers Memory pool: memory-bound processing CPU-optimized pool: latency-sensitive or sustained compute workloads Node autoscaling reacts to unschedulable Pods and the constraints that affect where those Pods can run. Kubernetes also considers constraints such as node affinity and storage requirements when deciding what capacity is needed. Actual Pod usage is not the only direct input; accurate requests remain important. This means pool design and autoscaling design are connected. If a batch workload is restricted to a batch pool, only capacity eligible for that workload solves its scheduling problem. ## Too many pools fragment capacity Every new pool creates another scheduling boundary. That can improve isolation or efficiency, but it can also strand usable resources. Imagine: Pool A: 2 GB free Pool B: 2 GB free Pool C: 2 GB free The cluster has 6 GB free in total. A Pod requiring 3 GB cannot use that combined capacity if it is restricted to one pool and no eligible node has 3 GB available. More pools also mean: - more minimum nodes; - more autoscaling settings; - more labels and taints; - more maintenance scenarios; - more opportunities for Pending Pods despite idle cluster capacity. For a small team, a good default is: **one broad general pool + only the specialized pools that solve a measurable problem.** Use [Kubernetes Cost Optimization](/learn/guides/kubernetes-cost-optimization-startups) when the question is broader efficiency rather than scheduling architecture. ## Test failure capacity inside each pool Cluster-wide spare capacity can hide a pool-specific failure. Example: General pool: 4 workers Memory pool: 2 workers If a memory-heavy workload is restricted to the memory pool, the four general workers do not automatically provide failover capacity. For every important pool, ask: > **If one worker in this pool is unavailable, can the remaining eligible nodes still run the required workloads?** Check: - minimum healthy replicas; - allocatable CPU and memory after one worker loss; - rollout overlap; - PodDisruptionBudgets; - affinity and anti-affinity; - persistent-volume topology; - autoscaler provisioning time; - whether another pool is intentionally eligible as fallback. This is the node-pool version of the N+1 test used in [Kubernetes Cluster Sizing](/learn/guides/kubernetes-cluster-sizing). ## Separate pools can support stronger workload boundaries A dedicated node pool can provide a useful compute-placement boundary for: - MSP customer workloads; - regulated or sensitive applications; - noisy batch jobs; - production workloads separated from non-production compute; - CPU-optimized workloads; - memory-heavy services. But a separate pool is not a complete multi-tenancy architecture. If two customers share a cluster, also consider: - namespaces; - RBAC; - NetworkPolicy; - Secrets; - storage isolation; - quotas; - administrative access. For MSP-specific architecture, use [Kubernetes Multi-Tenancy for MSPs](/learn/guides/multi-tenant-kubernetes-for-msps). ## Raff Kubernetes node pools Raff Managed Kubernetes currently supports multiple node pools in one cluster. Each pool can have its own worker plan, node count, and autoscaling bounds. Current shared-CPU worker plans are: | Worker plan | vCPU | RAM | Monthly price | |---|---:|---:|---:| | K8s Starter | 1 | 2 GB | $9.99 | | K8s Standard | 2 | 4 GB | $17.99 | | K8s Performance | 4 | 8 GB | $33.99 | | K8s High Memory | 8 | 16 GB | $71.99 | | K8s Large | 8 | 32 GB | $119.99 | | K8s Scale | 16 | 64 GB | $229.99 | Raff also publishes CPU-Optimized Kubernetes workers for workloads that need a different CPU model. Current pricing and plan availability should always be checked on the [Raff Kubernetes product page](/products/kubernetes). The standard control plane is currently **$0/month**, and the optional three-master HA control plane is **$30/month**. Dedicated Kubernetes storage is separate at **$0.10/GB-month**. Raff worker pools can autoscale between configured minimum and maximum values, and the platform currently maintains a **two-node floor**. A sensible progression is: Stage 1 — one general pool Stage 2 — add one specialized pool when workload behavior proves the need Stage 3 — give pools independent autoscaling boundaries Stage 4 — add stronger placement isolation only when the service model requires it The objective is not maximum pool variety. It is a small number of worker groups whose purpose can be explained in one sentence each. ## Common node-pool mistakes ### One pool per application Application ownership is not a sufficient infrastructure reason. Shared workers are often more efficient when workloads have similar requirements. ### Labels without taints on dedicated capacity Labels can guide workload placement but do not necessarily keep unrelated Pods away. ### Tolerations without affinity A toleration makes a tainted node eligible. It does not force the workload onto that node. ### Hard affinity everywhere Required placement rules can create Pending Pods even when other cluster capacity is idle. ### Inaccurate resource requests Autoscaling and scheduling depend on requests and constraints. Bad requests create bad capacity signals. ### Assuming another pool is failover capacity Free capacity in a different pool helps only if the workload is eligible to schedule there. ### Setting minimums too high in every pool Every specialized pool with a persistent minimum can create idle cost. Review minimum node counts against the availability requirement of that workload class. ## Node-pool decision checklist Create a separate pool only if at least one of these is true: - [ ] the workload needs a different CPU/memory shape; - [ ] the workload needs CPU-optimized capacity; - [ ] it has a distinct autoscaling pattern; - [ ] dedicated capacity is required; - [ ] placement rules or maintenance differ; - [ ] failure capacity must be managed independently; - [ ] a stronger compute-separation boundary is justified. Then verify: - [ ] labels identify the pool clearly; - [ ] hard affinity is used only where necessary; - [ ] dedicated pools use taints when general workloads must stay out; - [ ] requests reflect real workload behavior; - [ ] the pool can tolerate its required failure scenario; - [ ] min/max autoscaling bounds are explicit; - [ ] the reason for the pool is still valid after workload changes. ## Final recommendation Start with one general Kubernetes worker pool. Add another pool when a workload class truly differs in compute shape, scheduling, isolation, maintenance, or scaling behavior. Use affinity to control eligibility, taints and tolerations to protect dedicated capacity, and per-pool autoscaling only after minimum safe capacity is understood. Keep the number of pools small enough that Kubernetes still has useful scheduling flexibility. Continue with [Kubernetes Cluster Sizing](/learn/guides/kubernetes-cluster-sizing) for total capacity, [Kubernetes Autoscaling](/learn/guides/kubernetes-autoscaling-hpa-node-scaling-cost) for dynamic capacity, and [Kubernetes Cluster Management](/learn/guides/kubernetes-cluster-management-small-teams) for the broader operations model. :::cta cluster Use Raff Kubernetes node pools when workloads need distinct worker plans, placement rules, or scaling boundaries inside one managed cluster. ::: ### Sources - [Kubernetes — Assigning Pods to Nodes](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/) - [Kubernetes — Taints and Tolerations](https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration/) - [Kubernetes — Node Autoscaling](https://kubernetes.io/docs/concepts/cluster-administration/node-autoscaling/) - [Raff — Managed Kubernetes](/products/kubernetes) --- ## Comparisons ### AWS Lambda Alternative 2026: Pricing, Performance & Features URL: https://rafftechnologies.com/learn/compare/aws-lambda-alternative Description: Considering AWS Lambda? Raff Functions has free requests and egress, active-CPU billing, and standard jobs up to 24 hours. Raff wins on free requests, free function egress, active-CPU pricing, portable handlers, and execution windows beyond Lambda's 15-minute limit. AWS Lambda wins on AWS-native integrations, a 99.95% regional SLA, global infrastructure, mature governance, Durable Functions, Managed Instances, and more than a decade of production history. Lambda's larger monthly free tier can be cheaper for small workloads, while Raff can become easier to forecast as request volume, outbound traffic, or execution length grows. Choose AWS Lambda when AWS integration is the architectural advantage; choose Raff when simpler billing, longer jobs, and portability matter more. The practical decision is workload shape rather than a single unit price. AWS Lambda includes 1 million requests and 400,000 GB-seconds each month, while Raff Functions includes 100,000 GB-seconds and 10,000 active vCPU-seconds and charges $0 for requests. Standard Lambda invocations stop at 15 minutes; Raff supports 1 hour by default and up to 24 hours on request. AWS also offers capabilities Raff does not currently match, including Durable Functions, Managed Instances, and a much broader event and governance ecosystem. ## AWS Lambda vs Raff: which is right for you? AWS Lambda is the safer default when the surrounding application is already AWS-native. Raff Functions is the clearer alternative when the function can remain a portable HTTP, cron, webhook, storage-event, or bounded background workload. | Decision factor | Choose Raff | Choose AWS Lambda | |---|---|---| | Existing platform | You want Functions with Raff compute, databases, object storage, Apps, and direct support | Your workload already depends on IAM, S3, DynamoDB, SQS, Kinesis, EventBridge, API Gateway, or CloudWatch | | Billing shape | Free requests and egress plus memory and active-CPU meters are easier to model | Lambda's 1M-request and 400k-GB-s free tier covers much of the workload | | Execution length | Jobs may exceed 15 minutes | Each standard invocation fits inside 900 seconds | | Portability | Standard application-style handlers and a Dockerfile path matter | AWS event models and service-specific integration are acceptable | | Geography | One `us-east` public region fits | You need AWS's broad regional footprint | | Governance | A smaller operating surface and direct support fit the team | IAM, Organizations, CloudTrail, Config, partner tooling, and enterprise controls are requirements | From an infrastructure-design perspective, our preference is to keep business logic portable and treat triggers as adapters wherever the application does not genuinely need provider-specific behavior. That makes it easier to move a function into a container, VM, or another execution model when duration, concurrency, or dependency requirements change. For the broader architecture decision, read [Serverless Functions vs VMs for Small Teams](/learn/guides/serverless-functions-vs-vms-small-teams) and [Portable Serverless Handlers: Avoiding Lambda Lock-In](/learn/guides/portable-serverless-handlers-avoid-lock-in). ## AWS Lambda overview [AWS Lambda](https://aws.amazon.com/lambda/) is Amazon Web Services' event-driven serverless compute service. Standard Lambda Functions are billed by request and execution duration, with a monthly free tier of 1 million requests and 400,000 GB-seconds. Lambda's core advantage is its surrounding platform. It integrates with Amazon S3, SQS, SNS, DynamoDB, Kinesis, EventBridge, API Gateway, Step Functions, CloudWatch, IAM, Secrets Manager, and many other AWS services. For an application already standardized on AWS, keeping event processing inside that architecture can reduce integration work and avoid unnecessary cross-provider data movement. Standard Lambda Functions support managed runtimes, custom runtimes, zip packages, and compatible Linux container images. A standard invocation can run for up to 900 seconds, and the default account concurrency quota is 1,000 concurrent executions per Region, with quota increases available. AWS has also expanded Lambda beyond the original short-lived function model. **Lambda Durable Functions** add checkpointed steps and waits for long-running multi-step applications; waiting can suspend compute billing while the workflow is paused. **Lambda Managed Instances** run Lambda functions on fully managed EC2 capacity, with request charges, EC2 instance charges, and a 15% management fee on the EC2 on-demand instance price. These are genuine AWS advantages for teams that want to stay inside the Lambda programming model while extending it to workflow or steady-state compute patterns. ## Raff overview [Raff Functions](/products/serverless-functions) is event-driven compute for HTTP handlers, webhooks, cron schedules, one-off future tasks, object-storage events, AI jobs, ETL, imports, exports, and batch workloads. Raff bills memory at **$0.0000035 per GB-second** and active CPU at **$0.000020 per vCPU-second**. Requests are free, function egress is free, and a spend cap is enabled by default. The monthly free tier includes **100,000 GB-seconds and 10,000 active vCPU-seconds** after the one-time account top-up requirement. Raff supports standard application-style handlers including Python FastAPI/ASGI, Node.js standard `http`, TypeScript, JavaScript Web Fetch, Go `net/http`, and a Dockerfile path for other languages or custom runtimes. The goal is to keep application logic close to ordinary web or worker code rather than require a Raff-specific handler contract. Execution windows are materially longer than standard Lambda Functions: **1 hour by default and up to 24 hours on request**. Raff currently serves Functions from one public region, `us-east`, so it does not match AWS's geographic reach or integration catalog. Raff supports **3,000+ customers and 15,000+ production VMs** under a **99.9% platform SLA**. Raff Technologies was verified at **4.5/5** on August 16, 2026, and G2 is 4.6/5. ## AWS Lambda pricing vs Raff pricing The pricing comparison changes with workload shape. AWS Lambda can cost less for small functions that remain inside its larger free tier; Raff can cost less when requests, active duration, or function egress become meaningful. AWS standard on-demand Lambda Functions in US East use a request rate of **$0.20 per 1 million requests** after the free tier and an x86 duration example rate of **$0.0000166667 per GB-second**. Raff has no request charge and meters memory plus active CPU separately. The examples below apply both monthly free tiers. AWS estimates model standard x86 Lambda Functions in US East. Raff estimates use the stated active vCPU seconds rather than assuming CPU remains active for the full wall-clock duration. Connected services, logs, databases, queues, gateways, storage, and network products are excluded. | Monthly workload | Raff Functions | AWS Lambda | Decision signal | |---|---:|---:|---| | 1M requests, 128 MB, 100 ms, 10k active vCPU-s | $0.00 | $0.00 | Both fit their free tiers | | 3M requests, 256 MB, 200 ms, 60k active vCPU-s | About $1.18 | About $0.40 | Lambda's larger free tier wins | | 10M requests, 512 MB, 300 ms, 500k active vCPU-s | About $14.70 | About $20.13 | Raff's request model starts to matter | | 5M requests, 1 GB, 1 s, 1M active vCPU-s | About $36.95 | About $77.47 | Raff is lower in this workload model | | 1M requests, 2 GB, 5 s, 1M active vCPU-s | About $54.45 | About $160.00 | Duration dominates the Lambda example | **Comparison class:** these are planning models for standard on-demand functions, not performance-equivalent benchmarks. They do not compare Lambda Durable Functions, Managed Instances, Provisioned Concurrency, Lambda@Edge, or connected AWS services. ### Additional AWS Lambda billing lines Lambda can add charges for Provisioned Concurrency, extra ephemeral storage above the included amount, response streaming beyond the included allowance, data transfer, CloudWatch, API Gateway, event-source services, ECR, VPC components, Durable Functions operations/data retention, or Managed Instances. That flexibility is a genuine AWS strength because teams can choose more specialized execution models. It also means the full architecture bill can contain more line items than the Lambda function duration alone. ### Automated backups and recovery Neither standard AWS Lambda Functions nor Raff Functions automatically backs up external application databases or arbitrary durable state. Functions should be treated as reproducible compute, with durable application data stored in databases or object storage that has its own recovery policy. AWS Lambda versioning can preserve function code and configuration, while Durable Functions checkpoint workflow progress. Those mechanisms are useful for function and workflow recovery, but they are not substitutes for database backups. On Raff, VM snapshots/backups are handled separately through [Raff Data Protection](/products/data-protection), while database and object-storage recovery should be designed around the relevant product. :::cta Deploy a Function Now Deploy HTTP, cron, webhook, storage-event, or long-running workloads on Raff Functions. ::: ## Bandwidth and transfer policy Raff Functions charges **$0 for function egress**. AWS Lambda applies Amazon EC2 data-transfer pricing when data moves into or out of the Region where the function executes, while several same-Region AWS service paths are free. For a US East internet-egress planning example, AWS provides **100 GB/month free data transfer out** aggregated across eligible AWS services and Regions. After that allowance, the standard schedule begins at $0.09/GB for the first 10 TB, $0.085/GB for the next 40 TB, $0.07/GB for the next 100 TB, and $0.05/GB above 150 TB. Using 1 TB = 1,024 GB and assuming the 100 GB shared AWS free allowance is available to this workload: | Monthly internet egress | Raff Functions | AWS transfer charge | |---:|---:|---:| | 1 TB | $0 | About $83.16 | | 5 TB | $0 | About $451.80 | | 10 TB | $0 | About $912.60 | | 50 TB | $0 | About $4,394.70 | The AWS figures are not universal Lambda bills. Data transfer between Lambda and services such as S3, DynamoDB, SQS, Kinesis, ECR, SNS, EFS, and several others is free when the traffic remains in the same AWS Region. VPC, NAT, API Gateway, CloudFront, inter-Region, or other service paths can change the total. For large files, the better pattern on either platform is usually to write the file to object storage and return a signed or controlled download path rather than proxy every byte through a function response. ## Feature comparison: AWS Lambda vs Raff | Feature | Raff Functions | AWS Lambda | |---|---|---| | Standard function timeout | 1 hour default; up to 24 hours on request | 15 minutes | | Requests | $0 | 1M free/month, then $0.20/M | | Function egress | $0 | AWS transfer rules depend on path | | Free compute | 100k GB-s + 10k active vCPU-s | 400k GB-s | | Handler model | Standard application-style handlers | Lambda handler/event model plus frameworks/adapters | | Container path | Dockerfile | Compatible Linux images through ECR | | HTTP endpoints | Included live URLs | Function URLs or API Gateway | | Schedules | Timezone-aware cron + one-off future runs | EventBridge Scheduler / rules | | Object events | Raff Object Storage | Amazon S3 | | Queue/stream integrations | Narrower | Extensive SQS, SNS, Kinesis, DynamoDB, Kafka, EventBridge integrations | | Durable workflow model | Long timeout for bounded jobs | Durable Functions with steps, waits, replay, and retention | | Managed instance model | Separate Raff VM/App products | Lambda Managed Instances | | Region footprint | 1 public region: `us-east` | Broad AWS regional availability | | Governance | Simpler Raff account model | IAM, Organizations, CloudTrail, Config, enterprise tooling | AWS wins on service integrations, regional reach, governance, durable workflow primitives, and Managed Instances. Raff wins on free requests/egress, longer standard execution windows, active-CPU billing, and a narrower portability-oriented handler model. ## Features and reliability: Raff vs AWS Lambda This page has **0 controlled Raff-vs-Lambda performance benchmarks**, so it does not declare either platform faster. Serverless performance depends on runtime, package size, architecture, configured memory, cold starts, warm capacity, downstream services, network path, and application code. ### Availability commitments AWS Lambda's current service commitment is **99.95% Monthly Uptime Percentage per AWS Region**. Raff publishes a **99.9% platform SLA**. AWS therefore has the stronger published Lambda-specific availability commitment. ### Regional footprint AWS currently operates **39 geographic Regions and 123 Availability Zones** across its global infrastructure, and Lambda is broadly available across commercial AWS Regions. Raff Functions currently exposes **1 public region, `us-east`**. AWS is the clear choice when multi-region placement, regional failover, or data-residency choice is required. ### Execution model breadth AWS Lambda now spans standard Functions, Durable Functions, and Managed Instances, with additional variants such as Provisioned Concurrency and Lambda@Edge. That gives AWS more ways to keep a workload inside the Lambda programming model as its execution pattern changes. Raff uses a simpler boundary: standard Functions for event-driven workloads, then Raff Apps or VMs when persistent compute is the better fit. This keeps the product surface smaller but does not match AWS's breadth. ### Operational trust AWS Lambda has more than a decade of production history and is embedded in AWS's mature identity, audit, support, and event ecosystem. Raff is a newer platform with **3,000+ customers, 15,000+ production VMs, a 99.9% platform SLA, Trustpilot 4.5/5, and G2 4.6/5**. The correct reliability comparison is architectural. A highly available function does not compensate for a single-point-of-failure database, non-idempotent retries, weak secret handling, or an untested recovery path. ## When you should choose AWS Lambda over Raff - **AWS-native events** — S3, SQS, SNS, DynamoDB, Kinesis, EventBridge, API Gateway, and other AWS services integrate directly. - **Stronger published SLA** — Lambda commits to 99.95% Monthly Uptime Percentage per Region versus Raff's 99.9% platform SLA. - **Global placement** — AWS operates 39 geographic Regions and 123 Availability Zones; Raff Functions exposes 1 public region. - **Enterprise governance** — IAM, Organizations, CloudTrail, Config, account policies, partner tooling, and mature procurement workflows are deeper. - **Durable workflows** — Lambda Durable Functions add checkpointed steps, waits, replay, and configurable retention for multi-step workloads. - **Steady-state Lambda workloads** — Lambda Managed Instances combine the Lambda programming model with managed EC2 capacity. - **Small free-tier workloads** — 1 million requests and 400,000 GB-seconds can cover more small applications before billing begins. ## When you should choose Raff over AWS Lambda - **Long standard executions** — Raff supports 1 hour by default and up to 24 hours on request; standard Lambda Functions stop at 15 minutes. - **Request-heavy APIs** — Raff charges $0 for requests instead of a per-request line after the Lambda free tier. - **Outbound traffic** — Raff charges $0 for function egress, while AWS transfer cost depends on destination and architecture. - **I/O-heavy handlers** — Raff bills active CPU separately from memory, so waiting time is not modeled exactly like CPU-active time. - **Portable application code** — standard HTTP-style handlers make it easier to move logic toward containers or VMs later. - **Smaller operating surface** — HTTP, cron, one-off tasks, and object-storage events can be deployed without assembling as many adjacent services. ## Migrating from AWS Lambda to Raff 1. **Inventory every Lambda dependency.** Record runtimes, memory, timeout, environment variables, layers, images, IAM roles, triggers, destinations, dead-letter queues, concurrency, VPC access, CloudWatch alarms, Durable Functions, and connected services. 2. **Map each trigger to Raff.** Convert Function URLs/API Gateway to HTTP handlers, suitable EventBridge schedules to Raff cron or one-off runs, and S3 events to Raff Object Storage events. **Gotcha:** SQS, SNS, Kinesis, DynamoDB Streams, Step Functions, and many EventBridge integrations do not have direct one-to-one Raff equivalents. 3. **Extract portable business logic.** Move validation, transformations, database calls, and application rules out of Lambda-specific `event` and `context` handling. Keep AWS event parsing in a thin adapter until cutover. **Gotcha:** IAM role assumptions and AWS service credentials must be replaced with scoped Raff credentials or bindings. 4. **Create and configure the Raff function.** Choose a standard handler or Dockerfile, set memory and timeout, add environment variables/secrets, and connect required databases or object storage. 5. **Test production-shaped events.** Verify responses, retries, idempotency, logs, memory, active CPU, database connections, external APIs, presigned URLs, scheduled work, and failure behavior before production traffic moves. 6. **Cut over gradually and retain rollback.** Route a small share of HTTP traffic or switch one schedule/event source at a time, monitor both sides, keep Lambda available through the rollback window, then remove AWS triggers and permissions after verification. Lambda layers, ECR images, API Gateway authorizers, VPC-only services, CloudWatch dashboards, Durable Functions state, and provider-specific retry semantics can all increase migration effort. Do not collapse a multi-step AWS workflow into one long Raff invocation unless failure visibility and idempotency remain explicit. ## About AWS Lambda [AWS Lambda](https://aws.amazon.com/lambda/) is Amazon Web Services' serverless compute service for event-driven applications and backend workloads. It supports managed and custom runtimes, container images, numerous AWS event sources, Provisioned Concurrency, Durable Functions, and Managed Instances. Standard Functions are billed by request and duration, while specialized Lambda execution models introduce their own pricing components. ## Conclusion: AWS Lambda or Raff? AWS Lambda is the stronger choice when AWS-native integration, global placement, a 99.95% regional SLA, enterprise governance, Durable Functions, or Managed Instances are part of the requirement. Raff is the stronger alternative when the workload fits `us-east` and the priorities are free requests, free function egress, active-CPU billing, portable handlers, and standard executions beyond 15 minutes. The pricing evidence is workload-specific rather than one-sided: Lambda can be cheaper inside its larger free tier, while Raff becomes lower in several request- or duration-heavy planning examples. The architecture should decide the provider before a single unit rate does. For next-step design, read [Long-Running Serverless Functions for AI, ETL, and Batch Jobs](/learn/guides/long-running-serverless-functions-ai-etl-batch) or [Serverless Function Pricing: CPU, Memory, Requests, and Egress](/learn/guides/serverless-function-pricing-cpu-memory-egress). --- ### AWS S3 Pricing 2026: Storage, Egress & Raff Comparison URL: https://rafftechnologies.com/learn/compare/raff-object-storage-vs-aws-s3 Description: AWS S3 pricing in 2026: storage cost per GB, request fees, egress pricing, storage classes, and Raff Object Storage comparison. AWS S3 pricing in 2026 is built from several separate cost components: **storage, API requests, data retrieval, and data transfer**. For S3 Standard in US East, storage starts at **$0.023 per GB-month for the first 50 TB**. PUT, COPY, POST, and LIST requests are billed separately, GET requests are billed separately, and public internet egress is charged after AWS's shared monthly free-transfer allowance. Raff Object Storage uses a simpler model: **$7/month for the first 100 GB**, **1 TB of egress included**, **$0 API request fees**, $0.07/GB-month above the first 100 GB, and $0.01/GB for egress above the included 1 TB. That means AWS S3 can be cheaper for low-egress storage-only workloads, while Raff can be materially cheaper once public transfer and request volume become important. For example, 100 GB stored with no internet egress is about **$2.30/month on S3 Standard before requests** versus **$7 on Raff**. At 100 GB stored and 1 TB of internet egress, the same AWS example is about **$85.46/month before requests**, while Raff remains $7. This guide explains the actual AWS S3 cost model, storage-class pricing, request charges, egress, and how those costs compare with Raff Object Storage. ## AWS S3 pricing in 2026 Amazon S3 does not have one fixed monthly plan. Your bill depends on what storage class you use, how much data you store, how many requests your applications make, whether data is retrieved from colder classes, and where the data is transferred. For a typical S3 Standard workload, the most important pricing components are: 1. storage per GB-month; 2. PUT, COPY, POST, and LIST requests; 3. GET and other read requests; 4. data transfer out to the internet; 5. cross-region or special transfer paths; 6. optional features and management services; 7. retrieval charges for colder storage classes. That is why an S3 pricing estimate should model workload behavior rather than only multiply storage by a per-GB number. ## AWS S3 Standard storage pricing per GB For **S3 Standard in US East**, current storage pricing starts at: | Monthly S3 Standard storage | Price per GB-month | |---:|---:| | First 50 TB | $0.023 | | Next 450 TB | $0.022 | | Over 500 TB | $0.021 | At the first-tier rate: | Stored data | Approx. S3 Standard storage cost | |---:|---:| | 100 GB | $2.30/month | | 500 GB | $11.50/month | | 1 TB | about $23.55/month | | 10 TB | about $235.52/month | These figures are **storage only**. They do not include requests, public internet transfer, retrieval, replication, or other AWS services. This distinction matters because `AWS S3 pricing per GB` often sounds like one number, but storage cost is only one part of the bill. ## AWS S3 request pricing S3 Standard also meters API requests. In US East, current Standard request pricing includes approximately: | Request type | Price | |---|---:| | PUT, COPY, POST, LIST | $0.005 per 1,000 requests | | GET and other read requests | $0.0004 per 1,000 requests | Examples: | Monthly request volume | Approx. request cost | |---:|---:| | 1 million PUT-class requests | $5 | | 1 million GET requests | $0.40 | | 10 million GET requests | $4 | | 100 million GET requests | $40 | For many small workloads, request charges are modest. For workloads with millions or billions of object operations, request pricing becomes another cost dimension to forecast. Raff currently charges **$0 for object API requests**, so request volume does not add a separate billing line there. ## AWS S3 data transfer pricing Public internet transfer is where S3 costs can change quickly. AWS currently provides a shared **100 GB/month free data-transfer allowance** across eligible AWS services and Regions. After that, standard internet-transfer pricing applies. A typical U.S. schedule starts at: | Monthly public internet egress | Standard AWS transfer rate | |---:|---:| | First 10 TB after free allowance | $0.09/GB | | Next 40 TB | $0.085/GB | | Next 100 TB | $0.07/GB | | Above 150 TB | $0.05/GB | Actual transfer charges can differ when traffic uses CloudFront, same-region AWS paths, private endpoints, cross-region architectures, accelerated transfer, negotiated enterprise pricing, or other AWS services. For a simplified S3 Standard example using 1 TB = 1,024 GB and assuming the full 100 GB free-transfer allowance is available: | Internet egress | Approx. AWS transfer cost before storage/requests | |---:|---:| | 1 TB | about $83.16 | | 5 TB | about $451.80 | | 10 TB | about $912.60 | | 50 TB | about $4,394.70 | Raff includes **1 TB of egress** in its $7 base Object Storage plan and charges **$0.01/GB above 1 TB**. ## AWS S3 storage-class pricing One of AWS S3's biggest advantages is its range of storage classes. Teams can trade access frequency, retrieval behavior, minimum storage duration, resilience model, and price against one another. Common classes include: - S3 Standard; - S3 Intelligent-Tiering; - S3 Standard-Infrequent Access; - S3 One Zone-Infrequent Access; - S3 Express One Zone; - S3 Glacier Instant Retrieval; - S3 Glacier Flexible Retrieval; - S3 Glacier Deep Archive. Cold and archive classes can have much lower storage prices than S3 Standard, but may introduce retrieval charges, minimum storage durations, delayed access, or different availability characteristics. That flexibility is a real AWS advantage. If the workload has predictable hot, warm, and archival tiers, S3 can optimize them independently. Raff intentionally uses a simpler general-purpose object-storage model rather than reproducing AWS's full storage-class matrix. ## AWS S3 pricing calculator: what to include A realistic AWS S3 cost estimate should include more than stored GB. Before comparing providers, model: 1. average stored GB or TB; 2. chosen S3 storage class; 3. monthly PUT/LIST request volume; 4. monthly GET request volume; 5. retrieval volume from colder storage classes; 6. public internet egress; 7. cross-region transfer; 8. replication; 9. lifecycle transitions; 10. versioning growth; 11. Object Lock retention; 12. CloudFront or other delivery architecture; 13. data-processing or analytics services that read from S3. This is also why two companies storing the same 1 TB of data can receive very different S3 bills. ## AWS S3 vs Raff pricing Raff Object Storage uses a base bundle plus simple overages. AWS S3 uses component pricing. The table below uses **S3 Standard in US East**, the shared 100 GB monthly internet-transfer allowance, and the standard public-transfer schedule. AWS request charges are excluded from scenario totals and shown separately above. | Workload | Raff Object Storage | AWS S3 Standard | What it means | |---|---:|---:|---| | 100 GB stored, 0 GB internet egress | $7.00/month | about $2.30/month before requests | AWS is cheaper for storage-only use | | 100 GB stored, 1 TB internet egress | $7.00/month | about $85.46/month before requests | Raff's included egress changes the economics | | 500 GB stored, 1 TB internet egress | $35.00/month | about $94.66/month before requests | Raff remains lower in this transfer-heavy example | | 1 TB stored, 1 TB internet egress | about $71.68/month | about $106.71/month before requests | Both storage and transfer matter | | 1 TB stored, 5 TB internet egress | about $112.64/month | about $475.35/month before requests | Public transfer dominates the AWS example | These examples do not imply identical durability architecture, region coverage, storage classes, governance features, or service parity. They compare cost for general-purpose object storage workloads. ## When AWS S3 is cheaper AWS S3 is often cheaper when: - the workload stores data but sends little of it to the public internet; - S3 Standard's $0.023/GB-month storage rate is the main cost driver; - colder data can move into IA or Glacier classes; - data stays inside AWS and avoids standard public egress; - the application already depends heavily on AWS services; - storage-class optimization is more important than billing simplicity. At 100 GB stored with no public egress, S3 Standard costs about $2.30/month before requests, which is below Raff's $7 base plan. ## When Raff Object Storage is cheaper Raff becomes more attractive when: - public internet egress is high or unpredictable; - the workload regularly downloads backups, exports, media, or static assets; - API request volume is large enough to create another AWS cost line; - the team values one simple storage model over multiple classes and retrieval rules; - the application already runs on Raff infrastructure. Raff's current Object Storage plan includes **100 GB of storage, 1 TB egress, and API requests for $7/month**. Storage above 100 GB is $0.07/GB-month and egress above 1 TB is $0.01/GB. :::cta Create a Bucket Now Create S3-compatible object storage with 100 GB and 1 TB egress included. ::: ## AWS S3 vs Raff feature comparison Pricing is only one side of the decision. AWS S3 has a much deeper feature and governance surface. | Feature | AWS S3 | Raff Object Storage | |---|---|---| | API | Native Amazon S3 API | S3-compatible | | S3 Standard storage | $0.023/GB-month first 50 TB in US East | $7 first 100 GB; $0.07/GB-month above | | Included internet egress | 100 GB shared AWS allowance | 1 TB included | | Request fees | Metered by request type | $0 | | Storage classes | Many | One general-purpose model | | Bucket versioning | Yes | Not currently native | | Lifecycle rules | Yes | Not currently native | | Object Lock | Yes | Not currently native | | Same-region replication | Yes | No equivalent native feature | | Cross-region replication | Yes | No equivalent native feature | | Presigned URLs | Yes | Yes | | Multipart uploads | Yes | Yes | | Global regions | Broad AWS global footprint | Current public region: us-east | AWS S3 clearly wins when versioning, lifecycle automation, immutable retention, cross-region replication, archive classes, or deep AWS integration are requirements. Raff wins when the workload primarily needs standard S3-compatible object operations with a smaller, easier-to-predict billing surface. ## S3 compatibility and migration Raff Object Storage supports common S3-compatible workflows through `s3.raffusercloud.com`. Common tools include: - AWS CLI; - Boto3 and other AWS SDKs; - rclone; - s3cmd; - Cyberduck; - multipart uploads; - presigned URLs; - bucket policies; - ACLs. S3 compatibility does **not** mean full AWS feature parity. Applications that rely on IAM role assumptions, S3 event notifications, lifecycle transitions, Object Lock, access points, cross-region replication, Storage Lens, or AWS-specific analytics integrations need additional migration work. ## AWS S3 durability and availability AWS S3 publishes unusually specific durability targets. S3 Standard is designed for **99.999999999% durability** and **99.99% availability**, with redundant storage across at least three Availability Zones. Raff publishes a **99.9% platform SLA** but does not publish an equivalent eleven-nines Object Storage durability target. If procurement requires a documented object-durability design, AWS has the stronger published position. That difference should be treated as a real architecture consideration rather than hidden behind price comparison. ## AWS S3 regions and replication AWS S3 is available across AWS's global region footprint and supports same-region and cross-region replication. Raff currently exposes Object Storage from `us-east`. That can fit workloads whose users, recovery design, and data-placement requirements are compatible with that geography, but AWS is the stronger choice when multi-region object placement or specific data residency is required. ## When you should choose AWS S3 over Raff Choose AWS S3 when: - you need versioning, lifecycle policies, Object Lock, replication, or advanced storage classes; - you need global region choice or multi-region data placement; - your application already depends on IAM, Lambda, CloudFront, Athena, Glue, EventBridge, or other AWS-native services; - archive economics matter more than a simple single storage class; - procurement requires AWS's published durability model; - most traffic stays inside AWS and public egress is low. AWS S3's main advantage is not the headline storage rate alone. It is the combination of global architecture, data-governance controls, storage classes, and ecosystem depth. ## When you should choose Raff over AWS S3 Choose Raff when: - your workload needs straightforward S3-compatible buckets; - public egress is meaningful or unpredictable; - you want 1 TB egress bundled into the base plan; - you want $0 API request fees; - the application already runs on Raff compute; - you prefer a smaller billing surface over AWS's storage-class and request matrix. For uploads, media, exports, backups, static assets, build artifacts, and ordinary application-object storage, the simpler pricing model can be easier to forecast. ## Migrating from AWS S3 to Raff 1. **Inventory the S3 estate.** Record bucket names, regions, object counts, sizes, storage classes, versioning, lifecycle policies, Object Lock, replication, encryption, bucket policies, IAM dependencies, and event integrations. 2. **Check feature dependencies.** Identify AWS-specific features that do not map directly to Raff. 3. **Provision Raff Object Storage.** Create the target bucket and credentials and confirm `us-east` satisfies the workload. 4. **Transfer objects.** Use rclone, AWS CLI with the Raff endpoint, an SDK migration, or another verified copy process. 5. **Verify object integrity.** Compare object counts and checksums and test uploads, downloads, multipart operations, presigned URLs, policies, and application reads/writes. 6. **Cut over application endpoints.** Change the S3 endpoint only after validation. 7. **Keep AWS available through a rollback window.** Remove old buckets, replication rules, IAM policies, and other AWS resources only after production verification. Version history, lifecycle rules, Glacier classes, Object Lock, replication, and AWS event integrations do not move as ordinary object data. They must be redesigned or replaced deliberately. ## Frequently asked questions ### How much does AWS S3 cost per GB? S3 Standard in US East currently starts at $0.023 per GB-month for the first 50 TB. That is storage-only pricing; API requests, retrieval, and internet transfer can add separate charges. ### How much does 1 TB of AWS S3 cost per month? At the first-tier S3 Standard storage rate, 1 TB is roughly $23.55/month using 1 TB = 1,024 GB. Public egress, API requests, and other services can increase the total. ### Is AWS S3 expensive? It depends on workload behavior. S3 Standard storage itself can be inexpensive, but public egress, request volume, retrieval, replication, and other services can materially increase the monthly bill. ### Does AWS S3 charge for requests? Yes. S3 Standard meters request types separately. PUT, COPY, POST, and LIST operations are currently about $0.005 per 1,000 requests, while GET-class requests are about $0.0004 per 1,000 in US East. ### Does AWS S3 charge for bandwidth? Yes. AWS provides a shared monthly free-transfer allowance, then charges public internet egress using tiered rates. The first standard U.S. tier is currently $0.09/GB after the allowance. ### Is Raff cheaper than AWS S3? It depends on the workload. At 100 GB stored with no internet egress, S3 Standard is about $2.30/month before requests versus Raff at $7. At 100 GB stored and 1 TB of public egress, Raff remains $7 while the AWS example is about $85.46 before requests. ### What is the cheapest S3 storage class? AWS offers multiple lower-cost archive and infrequent-access classes, including Glacier options. The cheapest class depends on access frequency, retrieval needs, minimum storage duration, and recovery-time requirements. ### Does Raff support the S3 API? Raff provides S3-compatible Object Storage and works with common S3 tooling such as AWS CLI, SDKs, rclone, s3cmd, multipart upload, and presigned URLs. It does not reproduce every AWS S3 feature. ## Sources - [Amazon S3 pricing](https://aws.amazon.com/s3/pricing/) - [Amazon S3 product overview](https://aws.amazon.com/s3/) - [Raff Object Storage](/products/object-storage) - [S3-Compatible Object Storage: Use Cases for Developers](/learn/guides/s3-compatible-object-storage-use-cases-for-developers) - Pricing verified: 2026-08-28 ## Conclusion: AWS S3 pricing vs Raff AWS S3 pricing starts with inexpensive per-GB storage, but the complete bill depends on storage class, API requests, retrieval, and transfer. S3 Standard in US East begins at $0.023/GB-month and gives teams access to AWS's deep storage-class, replication, lifecycle, Object Lock, region, and ecosystem capabilities. Raff Object Storage takes the opposite approach: $7/month includes 100 GB, 1 TB egress, and API requests, with simple storage and transfer overages. Choose **AWS S3** when global architecture, advanced governance, archive classes, replication, or AWS-native integrations matter most. Choose **Raff** when standard S3-compatible workflows and predictable transfer/request economics are the stronger priority. --- ### Vultr Alternative 2026: Pricing, Performance & Features URL: https://rafftechnologies.com/learn/compare/raff-vs-vultr Description: Considering Vultr? Compare Raff at $17.99/mo for 2 vCPU, 4 GB and 80 GB NVMe with Vultr VPS pricing, bandwidth, backups and 2026 tradeoffs. Raff is a Vultr alternative for teams comparing VPS and cloud hosting on price, bandwidth, storage, and operating simplicity. Raff currently lists **2 vCPU / 4 GB / 80 GB NVMe at $17.99/month** and **4 vCPU / 8 GB / 160 GB NVMe at $33.99/month**, with unmetered VM bandwidth on a standard 3 Gbps port. Vultr is stronger for global placement, GPU infrastructure, bare metal, file storage, CDN, Direct Connect, load balancing, and specialized AI services. The May 11, 2026 benchmark on this page is preserved only as a historical test snapshot and is **not** used to claim a current performance winner. For buyers searching for a **Vultr VPS alternative, Vultr cloud hosting alternative, or a cheaper Vultr alternative**, the practical question is whether you need Vultr's global infrastructure breadth or a simpler `us-east` VM platform with lower published shared-VM prices and unmetered transfer. For the broader location decision, review [how to choose a U.S. cloud server for latency and compliance](/learn/guides/choose-us-cloud-server-latency-compliance). ## Vultr vs Raff: which is right for you? The choice comes down to global infrastructure breadth versus simpler VM economics. | Decision factor | Choose Raff | Choose Vultr | |---|---|---| | Geography | Your workload fits `us-east` | You need deployment across 33 cloud data center regions | | Shared VM pricing | You want published monthly pricing with NVMe capacity and unmetered transfer included | You want multiple shared-compute families and global region choice | | Bandwidth | High or unpredictable outbound traffic makes per-GB overage undesirable | Your transfer fits Vultr's plan allocation and account bandwidth model | | Storage | Included plan NVMe plus separately available block storage fits the workload | Local-NVMe behavior, Vultr Block Storage, File System, or broader storage options matter | | Specialized infrastructure | VMs, managed databases, Kubernetes, Apps, Functions, and object storage cover the stack | You need GPU, bare metal, CDN, Direct Connect, global load balancing, or Serverless Inference | | Operational model | A smaller product surface and direct support are valuable | A larger global infrastructure catalog is more important | Vultr is not simply a more expensive VPS provider. Its geographic reach and specialized infrastructure are real advantages. Raff is more relevant when the workload can run in `us-east` and the buyer values lower published shared-VM pricing, unmetered transfer, and a compact application-infrastructure stack. ## Vultr overview Vultr is a global cloud infrastructure provider founded in 2014. Its platform includes shared Cloud Compute, dedicated compute families, VX1, Cloud GPU, Bare Metal, managed Kubernetes, managed databases, block and object storage, file storage, CDN, load balancers, Direct Connect, container registry, VPC networking, Serverless Inference, API, CLI, and Terraform support. Vultr announced Milan in May 2026 as its **33rd cloud data center region**. That geographic footprint remains one of its clearest advantages over Raff. Vultr Cloud Compute is shared-CPU infrastructure, while Optimized Cloud Compute and VX1 provide dedicated CPU options for workloads that need more predictable allocation. Pricing and plan availability can vary by region, so Vultr's order screen remains the authority for a specific deployment. ## Raff overview Raff serves customers from one public region named `us-east`. Current General Purpose monthly plans include: - **2 vCPU / 2 GB / 40 GB NVMe — $12.99** - **2 vCPU / 4 GB / 80 GB NVMe — $17.99** - **4 vCPU / 4 GB / 80 GB NVMe — $24.99** - **2 vCPU / 8 GB / 160 GB NVMe — $27.99** - **4 vCPU / 8 GB / 160 GB NVMe — $33.99** - **8 vCPU / 8 GB / 160 GB NVMe — $48.99** - **8 vCPU / 16 GB / 240 GB NVMe — $71.99** Every current Cloud Server plan includes unmetered bandwidth on a standard 3 Gbps public port, private networking, DDoS protection, root access, API/Terraform tooling, monitoring, and NVMe storage according to the selected plan. Raff's current pricing page also advertises a **free backup-and-snapshot pool up to 50 GB** that grows with the VM fleet. Raff reports **3,000+ customers and 15,000+ VMs** with a **99.9% uptime SLA**. Trustpilot showed **4.5/5** when checked on August 18, 2026. Vultr has a much longer operating history and a much larger public deployment footprint, so review scores should be read alongside the very different review-base sizes. ## Vultr pricing vs Raff pricing For shared VPS-style workloads, Raff General Purpose is the most useful starting point. The Vultr High Performance references below were last verified for this comparison on **August 10, 2026**; Vultr notes that exact pricing can vary by region, so buyers should confirm the selected location before purchase. | Shared class | Raff General Purpose | Vultr High Performance reference | Buying takeaway | |---|---:|---:|---| | 2 vCPU / 2 GB | **$12.99** — 40 GB NVMe | **$18** — 60 GB NVMe / 4 TB | Raff lower; Vultr includes more disk and transfer allowance | | 2 vCPU / 4 GB | **$17.99** — 80 GB NVMe | **$24** — 100 GB NVMe / 5 TB | Raff about 25% lower; Vultr includes 20 GB more disk | | 4 vCPU / 8 GB | **$33.99** — 160 GB NVMe | **$48** — 180 GB NVMe / 6 TB | Raff about 29% lower; Vultr includes 20 GB more disk | | 8 vCPU / 16 GB | **$71.99** — 240 GB NVMe | **$96** — 350 GB NVMe / 8 TB | Raff about 25% lower; Vultr includes more disk and transfer allowance | Raff now also has a **4 vCPU / 4 GB / 80 GB plan at $24.99/month** and a **2 vCPU / 8 GB / 160 GB plan at $27.99/month**. These shapes give buyers additional CPU-first and memory-first options without forcing an artificial one-to-one Vultr match. ### Backup pricing Vultr automatic backups add **20%** to the instance's base hourly or monthly price. Raff's current public pricing instead advertises a free backup-and-snapshot storage pool up to **50 GB** across the VM fleet; additional protection should be sized separately when the free pool is not enough. ### Billing model Vultr bills standard server products hourly with a **672-hour monthly cap**. A stopped server continues billing because the resources remain reserved; billing ends when the server is destroyed. Raff offers published subscription pricing plus hourly PAYG options, so always-on monthly comparisons are straightforward while short-lived workloads can still use hourly billing. :::cta Deploy Your Server Compare current Raff VM sizes with unmetered bandwidth and included NVMe storage. ::: ## Bandwidth and transfer policy Vultr counts outbound transfer against account bandwidth limits and charges **$0.01 per GB** when the allocated quota is exceeded. Inbound transfer is not metered. Vultr's account calculation includes a monthly free-bandwidth allocation plus bandwidth accrued by running instances. Raff VM bandwidth is unmetered on a standard 3 Gbps public port. That makes the cost model easier to forecast for public APIs, downloads, SaaS traffic, replication, media delivery, and other workloads whose outbound traffic can change sharply from month to month. The tradeoff is geographic reach. Vultr lets a team choose from many more deployment regions, while Raff currently uses one public `us-east` region. ## Feature comparison: Vultr vs Raff | Area | Raff | Vultr | |---|---|---| | Shared compute | General Purpose | Regular Performance, High Performance, High Frequency | | Dedicated compute | CPU-Optimized | Optimized Cloud Compute and VX1 | | Current 2 vCPU / 4 GB shared anchor | $17.99 / 80 GB NVMe | $24 / 100 GB NVMe / 5 TB, last verified Aug. 10 | | VM internet transfer | Unmetered, standard 3 Gbps port | Plan/account allowance, then $0.01/GB | | Backups | Free backup-and-snapshot pool up to 50 GB advertised on current pricing page | Automatic backups add 20% | | Managed Kubernetes | Available | Vultr Kubernetes Engine | | Managed databases | PostgreSQL, MySQL, Valkey, ClickHouse, Kafka | PostgreSQL, MySQL, Valkey, Kafka | | Application platform | Raff Apps | Marketplace and one-click applications | | General-purpose functions | Raff Functions | No directly equivalent general-purpose function product identified | | AI inference | Not positioned as a separate inference product | Serverless Inference | | GPU / bare metal | Not offered in the current Raff VM catalog | Available | | CDN / Direct Connect / file storage | Not part of the current Raff comparison scope | Available | | Public regions | 1 (`us-east`) | 33 | Vultr wins on geographic reach, GPU and bare-metal infrastructure, global networking products, file storage, CDN, and specialized AI inference. Raff is more focused on conventional VM and application infrastructure with fewer billing dimensions. ## Performance benchmarks: Raff vs Vultr **Historical benchmark — May 11, 2026. This section is not a current performance claim.** The preserved test compared a Raff 2 vCPU / 4 GB benchmark VM with a Vultr High Performance 2 vCPU / 4 GB shared-CPU VM. It was a single test window, the regions differed, and Raff's commercial catalog has changed since then. The results therefore should not be used to declare a present-day performance winner. ### Historical methodology | Field | Test detail | |---|---| | Test date | May 11, 2026 | | Raff VM | 2 vCPU / 4 GB / 80 GB benchmark instance in `us-east` | | Vultr VM | High Performance 2 vCPU shared / 4 GB / 100 GB local NVMe in Chicago | | Operating system | Ubuntu 24.04 LTS | | Tools | sysbench 1.0.20, fio 3.36, iperf3 3.16, redis-benchmark 7.x, SQLite benchmark | | Runs | Single pass | | Test cost | Paid at standard rates by Raff; no Vultr sponsorship or rebate | ### Historical results | Benchmark | Raff | Vultr | Observed result in that test window | |---|---:|---:|---| | Redis SET | 157,356 req/s | 70,596 req/s | Raff higher | | Redis GET | 157,356 req/s | 70,596 req/s | Raff higher | | Memory random write | 6,099 MiB/s | 2,790 MiB/s | Raff higher | | Memory random read | 5,541 MiB/s | 5,259 MiB/s | Raff slightly higher | | Memory sequential read | 131 GB/s | 127 GB/s | Raff slightly higher | | CPU single-thread | 1,662 events/s | 1,824 events/s | Vultr higher | | Disk QD1 random-read P99 | 807 µs | 53 µs | Vultr lower latency | | Disk QD32 random read | ≈75,000 IOPS | ≈210,000 IOPS | Vultr higher | | Disk sequential read | 2.4 GB/s | 4.6 GB/s | Vultr higher | | SQLite inserts | 331,000 inserts/s | 424,000 inserts/s | Vultr higher | The useful lesson from the old test is workload sensitivity: Raff led the Redis and memory-heavy measurements in that window, while Vultr led several CPU and local-disk measurements. A fresh comparison would need matched regions where practical, matched memory/storage assumptions, at least three runs, and application-level testing before making new performance claims. ## When you should choose Vultr over Raff Choose Vultr when: - You need deployment across 33 cloud data center regions. - You need GPU, bare metal, VX1, or other specialized compute families. - CDN, Direct Connect, file storage, or Vultr's load-balancing products are requirements. - Your architecture depends on global placement rather than one `us-east` region. - You want a broader infrastructure catalog under one provider. - Serverless Inference is relevant to your AI workload. - The larger operating history and deployment footprint matter to procurement. ## When you should choose Raff over Vultr Choose Raff when: - A **2 vCPU / 4 GB / 80 GB VM at $17.99/month** fits your workload. - A **4 vCPU / 8 GB / 160 GB VM at $33.99/month** fits your growth path. - Unmetered VM bandwidth is more useful than a fixed transfer allowance plus overage. - Included plan NVMe capacity and fewer pricing dimensions make budgeting easier. - Your users and compliance requirements fit `us-east`. - You need VMs, managed databases, Kubernetes, Apps, Functions, and object storage without a hyperscale service catalog. - A smaller provider relationship with direct human support is valuable to your team. Compare nearby decisions with [Raff versus DigitalOcean](/learn/compare/raff-vs-digitalocean), [Raff versus Hetzner](/learn/compare/raff-vs-hetzner), and [Raff versus AWS Lightsail](/learn/compare/raff-vs-aws-lightsail). :::cluster ## Migrating from Vultr to Raff 1. **Inventory the Vultr estate.** Record instances, plan families, regions, operating systems, disks, block storage, VPCs, firewall groups, IPs, load balancers, DNS, backups, snapshots, managed databases, and object-storage dependencies. 2. **Classify portable services.** Standard Linux/Windows VMs, files, containers, and common databases are usually portable. CDN, Direct Connect, file storage, load-balancer behavior, or Serverless Inference integrations need replacement planning. 3. **Choose the Raff target size.** Select General Purpose for shared-vCPU workloads and CPU-Optimized where dedicated CPU allocation is required. Do not size a new workload from the May benchmark alone. 4. **Move application and data layers.** Redeploy stateless services from source control, transfer files with rsync or equivalent tools, and use native database dump/restore or replication workflows. 5. **Recreate networking and security.** Build VPC/private networking, firewall rules, IP configuration, monitoring, credentials, and backup policy before cutover. 6. **Validate the full workload.** Test TLS, application health, database consistency, storage mounts, jobs, outbound integrations, third-party allowlists, and restore procedures. 7. **Cut over with rollback.** Lower DNS TTL, perform the final sync, update records, monitor production, and keep the Vultr environment until the rollback window closes. Vultr reserved IPs do not move between providers, and local-NVMe data should be treated differently from durable attached storage. Document those dependencies before migration. ## About Vultr [Vultr](https://www.vultr.com/) is a global cloud infrastructure provider offering shared and dedicated compute, VX1, GPU, bare metal, Kubernetes, managed databases, storage, CDN, load balancing, Direct Connect, networking, and Serverless Inference across 33 cloud data center regions. ## Conclusion: Vultr or Raff? For buyers comparing **Vultr alternatives, Vultr VPS pricing, and Vultr cloud hosting options**, Raff is strongest when the workload fits `us-east` and predictable VM economics matter more than global infrastructure breadth. Raff currently lists **2 vCPU / 4 GB / 80 GB at $17.99/month** and **4 vCPU / 8 GB / 160 GB at $33.99/month**, with unmetered VM bandwidth. Vultr remains stronger for global regions, GPU, bare metal, file storage, CDN, Direct Connect, load balancing, and specialized AI infrastructure. The May 11 benchmark remains on this page as historical evidence only. It is not used to claim that Raff or Vultr is faster today. Continue with [the U.S. cloud server decision guide](/learn/guides/choose-us-cloud-server-latency-compliance) or review [Raff VM plans](/products/raff-vm). --- ### Oracle Cloud Alternative 2026: Pricing, Performance & Features URL: https://rafftechnologies.com/learn/compare/raff-vs-oracle-cloud Description: Considering Oracle Cloud? Compare Raff at $33.99/mo for 4 vCPU, 8 GB and 160 GB NVMe with OCI E6 pricing, bandwidth, Free Tier and tradeoffs. Raff is an Oracle Cloud alternative for conventional application infrastructure when a workload fits `us-east` and the priorities are lower published VM pricing, included NVMe capacity, unmetered bandwidth, and a smaller operating surface. Oracle Cloud Infrastructure is stronger when the architecture needs 50+ public cloud regions, Oracle Database services, flexible AMD, Intel, or Arm shapes, bare metal, GPUs, enterprise governance, multicloud interconnects, or Always Free resources. For a current **spec-level** comparison, Raff General Purpose provides **4 vCPU / 8 GB / 160 GB NVMe for $33.99/month**, while OCI `VM.Standard.E6.Flex` at 2 OCPUs / 8 GB plus 160 GB of Balanced Block Volume storage is approximately **$62.28/month** before backups, paid support, premium software, and services beyond the included network allowance. Raff has no controlled Oracle Cloud benchmark within the last 90 days, so this page compares verified pricing, architecture, included resources, and platform fit without declaring a performance winner. ## Oracle Cloud vs Raff: which is right for you? Oracle Cloud Infrastructure and Raff solve different operating problems. OCI is a global enterprise cloud with flexible infrastructure and deep Oracle-native services; Raff is a smaller cloud platform designed to reduce packaging and billing complexity. | Decision factor | Choose Raff | Choose Oracle Cloud Infrastructure | |---|---|---| | Geography | Your workload fits one region named `us-east` | You need 50+ public cloud regions, sovereign realms, or specific country placement | | VM economics | You want a published VM plan with listed NVMe capacity and unmetered transfer | You can model OCPU, memory, boot volume, performance units, backups, and services separately | | CPU architecture | Conventional x86 VM plans fit the workload | You need flexible AMD, Intel, Arm, bare metal, GPU, or HPC shapes | | Databases | You need managed PostgreSQL, MySQL, Valkey, ClickHouse, or Kafka | You need Autonomous Database, Exadata, Oracle Database, MySQL HeatWave, or Oracle licensing integration | | Application platform | You need VMs, Kubernetes, databases, Apps, Functions, and storage in a compact platform | You need OKE, OCI Functions, Container Instances, API Gateway, analytics, AI, and enterprise integration | | Free usage | You prefer a paid production plan with clear included resources | Your eligible workload can remain inside OCI Always Free limits and available capacity | | Operations | Direct support and a smaller product surface are valuable | Compartments, IAM policies, tenancy governance, quotas, and enterprise controls are required | Raff is not a replacement for every OCI product. It is most relevant as an Oracle Cloud VM alternative for conventional Linux and Windows application infrastructure where predictable cost matters more than Oracle-native platform depth. For the wider location decision, review [how to choose a U.S. cloud server for latency and compliance](/learn/guides/choose-us-cloud-server-latency-compliance). ## Oracle Cloud Infrastructure overview Oracle Cloud Infrastructure is Oracle's public cloud platform for compute, networking, storage, databases, containers, analytics, AI, security, identity, governance, and hybrid or multicloud deployments. Oracle currently describes a footprint of **50+ public cloud regions across 28 countries**, including commercial, government, sovereign, and multicloud locations. OCI Compute supports flexible AMD, Intel, and Arm virtual machine shapes. On x86 shapes, **1 OCPU equals 2 vCPUs**. `VM.Standard.E6.Flex` is the newer AMD Standard Flex generation and allows teams to adjust OCPU and RAM rather than selecting only fixed bundles. Oracle's current E6 shape supports up to 126 OCPUs and up to 1,454 GB of memory, with network bandwidth scaling by OCPU. Oracle also provides Ampere Arm shapes through `VM.Standard.A1.Flex`. OCI's Always Free documentation currently includes **1,500 A1 OCPU-hours and 9,000 GB-hours per month**, equivalent to 2 OCPUs and 12 GB of memory for Always Free tenancies, plus **200 GB of combined boot/block volume storage**, five volume backups, and **20 GB of combined Object and Archive Storage**. Always Free capacity can be unavailable in a preferred availability domain, and idle compute instances can be reclaimed under Oracle's published policy. OCI's strongest differentiators are Oracle Database services, Autonomous Database, Exadata, MySQL HeatWave, flexible compute, bare metal, high-performance networking, enterprise identity and governance, and interconnect options with other hyperscalers. ## Raff overview Raff serves customers from one public region named `us-east`. The current platform includes: - General Purpose shared-vCPU VMs - CPU-Optimized dedicated-vCPU VMs - Linux and Windows operating systems - Managed Kubernetes - Managed PostgreSQL, MySQL, Valkey, ClickHouse, and Kafka - Raff Apps - Raff Functions - S3-compatible Object Storage - Block Storage Volumes at $0.08/GB-month - Snapshots at $0.06/GB-month - Private networking, firewall controls, DDoS protection, IPv4, and IPv6 - API, CLI, Terraform, web console, VNC, resize, and custom OS workflows Current General Purpose shared-vCPU plans include: - **2 vCPU / 2 GB / 40 GB NVMe — $12.99/month** - **2 vCPU / 4 GB / 80 GB NVMe — $17.99/month** - **4 vCPU / 4 GB / 80 GB NVMe — $24.99/month** - **2 vCPU / 8 GB / 160 GB NVMe — $27.99/month** - **4 vCPU / 8 GB / 160 GB NVMe — $33.99/month** - **8 vCPU / 8 GB / 160 GB NVMe — $48.99/month** - **8 vCPU / 16 GB / 240 GB NVMe — $71.99/month** Raff also offers CPU-Optimized plans for workloads that need dedicated-vCPU allocation. This refresh does not publish CPU-Optimized prices because the current buyer-facing comparison is anchored to the live General Purpose catalog. VM bandwidth is unmetered on a standard **3 Gbps** public port. Raff's current data-protection model uses a **free backup-and-snapshot storage pool** rather than the older three-slot model; additional protection storage is priced separately when the included pool is exceeded. Raff reports **3,000+ customers and 15,000+ VMs**, publishes a **99.9% uptime SLA**, and currently shows **4.5/5 on Trustpilot** and **4.6/5 on G2**. ## Oracle Cloud pricing vs Raff pricing The current table compares Raff General Purpose with OCI `VM.Standard.E6.Flex`. This is a **spec-level buying comparison, not a claim of equal CPU allocation or equal performance**: Raff General Purpose uses shared vCPU, while OCI E6 uses Oracle's OCPU-based Standard Flex model. OCI estimates use **$0.03 per OCPU-hour**, **$0.002 per GB-hour**, 730 hours per month, and Balanced Block Volume storage at **$0.0425 per GB-month**. | Published CPU / memory / storage class | Raff General Purpose | OCI E6 Flex + Balanced storage | Difference before other OCI add-ons | |---|---:|---:|---:| | 2 vCPU / 4 GB / 80 GB | **$17.99** | $27.74 compute + $3.40 storage = **$31.14** | Raff about 42% lower | | 4 vCPU / 8 GB / 160 GB | **$33.99** | $55.48 compute + $6.80 storage = **$62.28** | Raff about 45% lower | | 8 vCPU / 16 GB / 240 GB | **$71.99** | $110.96 compute + $10.20 storage = **$121.16** | Raff about 41% lower | OCI flexible shapes can be right-sized more precisely than Raff's fixed published tiers. A team can choose a different memory-to-OCPU ratio and potentially avoid paying for unused RAM. OCI also gives buyers more processor, accelerator, and infrastructure options. Raff's advantage is the lower published VM price, included listed NVMe capacity, and a simpler bandwidth model. ### Oracle Cloud Free Tier OCI's Always Free resources remain a meaningful advantage for eligible experiments and small workloads. Oracle's current detailed documentation includes: - Up to two AMD `VM.Standard.E2.1.Micro` instances - Ampere A1 Always Free compute allocation - **200 GB** combined boot and Block Volume storage - **Five** Always Free volume backups - **20 GB** combined Object and Archive Storage for Always Free-only accounts - Additional Always Free platform resources The tradeoffs matter. Ampere A1 is Arm rather than x86, so third-party binaries and proprietary software must support the architecture. Free compute can also be unavailable because of regional capacity, and Oracle documents reclamation criteria for idle Always Free compute. ### What OCI compute pricing does not include OCI VM compute pricing does not include: - Boot and data Block Volume capacity - Balanced or higher Block Volume performance units where applicable - Block Volume backups and retained snapshots beyond free allocations - Paid support - Load Balancer capacity where used - Database licenses or premium operating systems where applicable - Public egress above the included monthly allowance - Additional OCI services used by the workload OCI Balanced Block Volume totals **$0.0425/GB-month** at the standard balanced configuration used in this comparison. Raff includes the listed plan NVMe capacity and unmetered VM bandwidth. Its current protection model provides a free backup-and-snapshot storage pool, with additional protection storage billed when usage exceeds that pool. :::cta Deploy Your Server Compare current Raff VM plans with included NVMe storage and unmetered bandwidth. ::: ## Bandwidth and transfer policy Oracle Cloud has one of the more generous hyperscaler egress policies. OCI includes the first **10 TB of outbound data per month** and advertises outbound pricing starting at **$0.0085/GB above 10 TB**. Inbound transfer and many intra-region transfer paths are free under OCI's published networking model. Raff VM plans include unmetered bandwidth on a standard **3 Gbps** public port. Raff does not add a per-GB internet egress line item to normal VM plans. | Monthly outbound transfer | Raff | OCI public internet egress | |---:|---:|---:| | 1 TB | Included | Included in first 10 TB | | 5 TB | Included | Included in first 10 TB | | 10 TB | Included | Included in first 10 TB | | 20 TB | Included | About **$85** for 10 TB above allowance | | 50 TB | Included | About **$340** for 40 TB above allowance | OCI is unusually competitive on bandwidth for a hyperscaler. Below 10 TB/month, both Raff and OCI avoid a variable public-egress charge. Above 10 TB, Raff remains simpler because transfer stays included, while OCI's published overage rate remains relatively low. OCI also offers Site-to-Site VPN and FastConnect for hybrid networking. Oracle's global network and many regions are stronger for distributed or hybrid systems; Raff is simpler for a single-region `us-east` application stack. ## Feature comparison: Oracle Cloud vs Raff ### Compute | Feature | Raff | Oracle Cloud Infrastructure | |---|---|---| | Shared compute | General Purpose shared vCPU | Flexible and fixed VM shapes | | Dedicated compute | CPU-Optimized family available | Bare metal and specialized compute options | | Current pricing anchor | $33.99 — 4 vCPU / 8 GB / 160 GB | E6 Flex ≈ $62.28 with matched 160 GB Balanced storage | | CPU architectures | x86 VM catalog | AMD, Intel, Arm, GPU, and HPC families | | Flexible CPU/RAM ratio | Fixed published plans | Flexible OCPU and RAM configuration | | Bare metal | Not in current public VM catalog | Available | | Preemptible capacity | Not in current public VM catalog | Available for supported shapes | | GPUs and HPC | Not in current public VM catalog | Broad GPU, RDMA, HPC, and AI infrastructure | | Custom images | Available | Available | OCI clearly wins on architecture choice and infrastructure breadth. Raff offers fewer choices but a shorter buying path for ordinary application infrastructure. ### Networking | Feature | Raff | Oracle Cloud Infrastructure | |---|---|---| | Public egress | Unmetered at 3 Gbps | First 10 TB/month free; from $0.0085/GB above | | Private networking | Available | VCN, peering, DRG, and private endpoints | | Firewall | Included platform controls | Security Lists, Network Security Groups, OCI Network Firewall | | IPv4 and IPv6 | Available | Available | | Load balancing | Not used as a Raff advantage in this comparison | Flexible Load Balancer and Network Load Balancer | | Site-to-site VPN | Standard integration pattern | OCI Site-to-Site VPN | | Dedicated connectivity | External provider integration | FastConnect | | Geography | One `us-east` region | 50+ public cloud regions | OCI wins on global, hybrid, and enterprise network architecture. Raff wins when a single-region workload benefits from fewer network products and no transfer meter. ### Storage & Backups | Feature | Raff | Oracle Cloud Infrastructure | |---|---|---| | VM storage | Listed NVMe capacity included | Boot volume billed separately outside free allocations | | Additional block storage | Volumes at $0.08/GB-month | Multiple Block Volume performance tiers | | On-demand snapshots | $0.06/GB-month | Block Volume and boot-volume backups | | Automated protection baseline | Free backup-and-snapshot storage pool | Oracle-defined or custom backup policies | | Performance controls | Plan-dependent | VPUs, IOPS, throughput, autotuning, elastic performance | | Object storage | S3-compatible Object Storage | Object Storage and Archive Storage | OCI offers deeper storage-performance tuning and enterprise policy controls. Raff provides a simpler VM-storage and protection workflow. ### Platform Features | Feature | Raff | Oracle Cloud Infrastructure | |---|---|---| | Managed Kubernetes | Available | Oracle Kubernetes Engine | | Managed relational databases | PostgreSQL and MySQL | Autonomous Database, Oracle Database, MySQL HeatWave, PostgreSQL services | | Managed data services | Valkey, ClickHouse, Kafka | Oracle-native database, analytics, streaming, integration, and data services | | Functions | Raff Functions | OCI Functions | | Application platform | Raff Apps | Container Instances, Functions, OKE, API Gateway, DevOps services | | Oracle software integration | General Linux and Windows hosting | Deep Oracle Database and enterprise-application integration | | AI and analytics | Focused application platform | OCI Generative AI, Data Science, analytics, GPUs, and HPC | | API, CLI, Terraform | Available | Extensive APIs, OCI CLI, Resource Manager, Terraform ecosystem | OCI wins on Oracle-native databases, enterprise integration, analytics, AI, and specialized services. Raff covers a compact application stack for teams that do not need the wider Oracle portfolio. ### Pricing & Billing | Feature | Raff | Oracle Cloud Infrastructure | |---|---|---| | Billing choices | Subscription terms plus hourly PAYG options | Usage-based billing and enterprise commitments | | Compute sizing | Fixed published plans | Flexible OCPU and memory | | VM disk included | Yes | Boot volume billed separately outside free allocations | | Internet egress | Unmetered | First 10 TB/month free, then low overage pricing | | Protection baseline | Free backup-and-snapshot storage pool | Policies and retained backups configured separately | | Free tier | No permanent free VM tier | Always Free resources and trial credits where eligible | OCI provides more flexibility and a valuable free tier. Raff requires less cost modeling for an ordinary paid production server. ### Trust & Operations | Feature | Raff | Oracle Cloud Infrastructure | |---|---|---| | Scale signal | 3,000+ customers; 15,000+ VMs | Global enterprise cloud operated by Oracle | | Public rating | Trustpilot 4.5/5; G2 4.6/5 | Broad enterprise customer and partner ecosystem | | SLA | 99.9% | Service- and architecture-specific SLAs | | Support | Direct 24/7 support | Documentation, partners, enterprise support, and Oracle support programs | | Governance | Focused platform controls | Tenancies, compartments, IAM policies, quotas, Cloud Guard, Security Zones | | Compliance | Focused provider program | Extensive global and industry-specific compliance portfolio | OCI wins on enterprise governance, compliance breadth, support programs, and ecosystem depth. Raff offers a more direct operating relationship and a smaller surface to manage. ### Infrastructure | Feature | Raff | Oracle Cloud Infrastructure | |---|---|---| | Public region model | One region named `us-east` | 50+ regions across 28 countries | | Availability architecture | Raff region model | Availability domains and fault domains where supported | | CPU architectures | x86 | AMD, Intel, Arm, GPU, bare metal, HPC | | Multicloud | Standard internet and partner integrations | Interconnect options with other major clouds in selected regions | | Hybrid cloud | Standard integration patterns | Dedicated Region, Cloud@Customer, FastConnect, and edge options | | Best fit | Predictable U.S.-East application infrastructure | Oracle databases, global enterprise, regulated, AI, HPC, and multicloud systems | ## Performance benchmarks: Raff vs Oracle Cloud Raff has not completed a controlled, matched Oracle Cloud Infrastructure benchmark within the last 90 days. This page therefore does **not** claim that Raff or OCI is faster. A valid benchmark would need to match: - OCI region and Raff `us-east` network test paths - Linux distribution, kernel, and tuning - x86 architecture on both sides - Oracle OCPU-to-vCPU mapping - Raff General Purpose or CPU-Optimized class - Block Volume size, VPUs, caching, IOPS, and throughput - At least three passes per test - CPU, memory, fio, PostgreSQL, Redis, HTTP, and network workloads - Full monthly cost including OCI compute and storage Ampere A1 should not be used as the primary benchmark opponent for Raff's x86 plans because Arm and x86 compatibility, instruction sets, compiler behavior, and workload optimization differ. OCI E6 Flex would be the cleaner current x86 comparison, but its flexible memory and storage-performance settings must be recorded. Until that test exists, use the pricing and feature sections to make the decision. ## When you should choose Oracle Cloud over Raff Choose Oracle Cloud when: - You need deployment across 50+ public cloud regions. - Your organization runs Oracle Database, Exadata, Autonomous Database, or Oracle enterprise applications. - You need flexible OCPU and RAM ratios rather than fixed VM bundles. - Arm, Intel, AMD, bare metal, GPU, HPC, or RDMA infrastructure is required. - OCI Always Free resources fit an experimental or small Arm-compatible workload. - Your architecture requires compartments, advanced IAM policies, Cloud Guard, Security Zones, or enterprise governance. - OKE, MySQL HeatWave, OCI Functions, Data Science, Generative AI, analytics, or integration services are central. - FastConnect, sovereign-cloud options, Cloud@Customer, or multicloud interconnects are required. ## When you should choose Raff over Oracle Cloud Choose Raff when: - You want **2 vCPU / 4 GB / 80 GB NVMe for $17.99/month**. - You want **4 vCPU / 8 GB / 160 GB NVMe for $33.99/month**. - You want unmetered VM bandwidth rather than a 10 TB allowance and usage meter above it. - The current free backup-and-snapshot storage pool fits your ordinary protection needs. - Your workload uses conventional Linux or Windows VMs, managed databases, Kubernetes, Apps, Functions, and object storage. - Your users and compliance requirements fit `us-east`. - You do not need Oracle Database, Exadata, Arm, GPU, bare metal, HPC, or Oracle enterprise governance. - You prefer direct support and fewer billing dimensions. Compare nearby decisions with [Raff versus Google Cloud](/learn/compare/raff-vs-google-cloud), [Raff versus Azure Virtual Machines](/learn/compare/raff-vs-azure-virtual-machines), and [Raff versus AWS Lightsail](/learn/compare/raff-vs-aws-lightsail). :::cluster ## Migrating from Oracle Cloud to Raff 1. **Inventory the OCI tenancy.** Record Compute instances, shapes, OCPUs, memory, architecture, boot and block volumes, VPUs, VCNs, subnets, security lists, NSGs, public IPs, load balancers, DNS, IAM policies, compartments, backups, and managed-service dependencies. 2. **Classify portable and OCI-native components.** Standard x86 Linux or Windows VMs, containers, files, and common databases are usually portable. Autonomous Database, Oracle Database systems, Exadata, OKE-specific controllers, MySQL HeatWave, OCI Vault, Functions, Streaming, and private service endpoints need replacement or hybrid planning. 3. **Resolve architecture compatibility.** Ampere A1 workloads are Arm. Confirm that container images, packages, binaries, agents, and proprietary software have x86 builds before moving to Raff's x86 VM catalog. 4. **Choose the Raff compute class.** Use General Purpose for shared-vCPU workloads or CPU-Optimized where dedicated-vCPU allocation is required. Match RAM, usable disk, public IPs, private networking, firewall exposure, and protection requirements. 5. **Move applications and data.** Redeploy from source control, transfer files with rsync or secure copy, move compatible object data with S3 tools, and migrate databases using native dump/restore, replication, or application-level export. 6. **Validate before cutover.** Test TLS, SSH or RDP, application health, database consistency, storage mounts, scheduled jobs, outbound email, IPv6, backups, restores, monitoring, and third-party allowlists through a temporary hostname. 7. **Cut over and remove residual OCI charges.** Lower DNS TTL, perform the final sync, update A and AAAA records, monitor production, retain OCI for rollback, then delete unused instances, boot volumes, block volumes, backups, reserved IPs, load balancers, gateways, and paid services. Operational gotchas: - OCI public IP addresses cannot move to Raff. Update DNS, security allowlists, payment providers, SMTP relays, VPN peers, and partner integrations. - OCI Block Volume backups are not directly attachable to Raff. Use file-, image-, database-, or application-level migration methods. - Ampere A1 Arm binaries do not automatically run on x86 VMs. Rebuild containers and packages for `amd64` where required. - Oracle Database licensing, support contracts, and application dependencies require separate commercial and technical review. ## About Oracle Cloud Infrastructure [Oracle Cloud Infrastructure](https://www.oracle.com/cloud/) is Oracle's global public cloud platform for compute, networking, storage, databases, containers, analytics, AI, security, governance, and hybrid or multicloud deployment. Its strongest differentiation is the combination of Oracle Database services, flexible infrastructure, enterprise controls, and 50+ public cloud regions. ## Conclusion: Oracle Cloud or Raff? Raff is the stronger Oracle Cloud alternative for ordinary production servers when the workload fits `us-east` and predictable VM economics matter more than global enterprise breadth. - **Current VM pricing:** Raff 4 vCPU / 8 GB / 160 GB is $33.99; OCI E6 Flex at 2 OCPUs / 8 GB plus 160 GB Balanced storage is approximately $62.28 before backups and additional services. - **Bandwidth:** Raff is unmetered on a standard 3 Gbps port; OCI includes 10 TB/month and charges from $0.0085/GB above it. - **Protection:** Raff uses a free backup-and-snapshot storage pool; OCI backup policies and retained data are separately configured outside applicable Free Tier allocations. - **Free tier:** OCI offers meaningful Always Free compute, block storage, backups, and object/archive storage for eligible accounts; Raff focuses on paid production plans. - **Platform:** OCI wins on 50+ regions, Oracle Database, flexible shapes, Arm, bare metal, GPUs, HPC, enterprise governance, and multicloud products. - **Performance evidence:** no matched benchmark is available, so neither provider is declared faster. Choose Oracle Cloud for Oracle-native databases, global enterprise systems, free-tier experiments, specialized compute, governance, or multicloud infrastructure. Choose Raff for `us-east` Linux and Windows application stacks that benefit from included NVMe, unmetered bandwidth, managed databases, Kubernetes, Apps, Functions, and direct support. Continue with [the U.S. cloud server decision guide](/learn/guides/choose-us-cloud-server-latency-compliance) or review [Raff VM plans](/products/raff-vm). --- ### Azure Virtual Machines Alternative 2026: Pricing, Performance & Features URL: https://rafftechnologies.com/learn/compare/raff-vs-azure-virtual-machines Description: Considering Azure Virtual Machines? Compare Raff at $33.99/mo for 4 vCPU, 8 GB and 160 GB NVMe with Azure VM pricing, bandwidth and tradeoffs. Raff is an Azure Virtual Machines alternative when a workload fits `us-east` and the priorities are lower published VM pricing, included NVMe capacity, unmetered bandwidth, and a smaller operating surface. Azure Virtual Machines is stronger when the architecture needs more than 70 regions, availability zones, Microsoft identity and licensing integrations, GPUs, confidential computing, scale sets, hybrid connectivity, or Azure-native managed services. At the 4 vCPU / 8 GB shared-class comparison point, Raff General Purpose is **$33.99/month** with 160 GB NVMe and unmetered bandwidth, while Azure `B4ls v2` in East US is about **$107.31/month for Linux compute only** before managed disk, outbound transfer, snapshots, and support. Raff has not completed a controlled Azure benchmark within the last 90 days, so this page compares current pricing, CPU behavior, included resources, and platform fit without declaring a performance winner. For buyers searching for an **Azure VM alternative, Azure VPS, Azure Virtual Machines pricing, or a cheaper Azure alternative**, the practical decision is whether Microsoft's global platform breadth matters more than simpler `us-east` VM economics. For the broader location decision, review [how to choose a U.S. cloud server for latency and compliance](/learn/guides/choose-us-cloud-server-latency-compliance). ## Azure Virtual Machines vs Raff: which is right for you? The choice is between Azure's globally distributed enterprise platform and Raff's simpler infrastructure package. | Decision factor | Choose Raff | Choose Azure Virtual Machines | |---|---|---| | Geography | Your users and compliance requirements fit one region named `us-east` | You need more than 70 regions, availability zones, or specific data-residency options | | VM economics | You want listed NVMe capacity and unmetered transfer in the published VM price | You can model compute, disk, transfer, snapshots, licenses, and network services separately | | CPU behavior | You want shared-vCPU General Purpose or a dedicated-vCPU product family | You want burstable B-series, fixed-performance families, Spot VMs, confidential VMs, GPUs, or specialized sizes | | Windows | You need a straightforward hosted Windows VM workflow | You need Azure Hybrid Benefit, Microsoft Entra integration, Azure Virtual Desktop, or enterprise Microsoft agreements | | Application platform | You need VMs, Kubernetes, managed databases, Apps, Functions, and storage in a compact platform | You need AKS, Azure SQL, Cosmos DB, Functions, App Service, Fabric, AI services, or deep Microsoft integration | | Networking | Public egress is large or unpredictable | You need ExpressRoute, Virtual WAN, global load balancing, Front Door, or complex hybrid networks | Raff is not a replacement for every Azure service. It is most relevant as an Azure VM alternative for conventional Linux and Windows servers where predictable infrastructure cost matters more than hyperscaler breadth. ## Azure Virtual Machines overview Azure Virtual Machines is Microsoft's infrastructure-as-a-service compute product for Linux and Windows workloads. Azure currently provides **more than 70 regions globally**, with availability-zone support in many regions and a large portfolio of networking, security, backup, monitoring, identity, and hybrid services. Azure offers many VM families: burstable B-series, general-purpose D-series, memory-optimized E-series, compute-optimized F-series, storage-optimized L-series, GPU families, confidential VMs, and specialized high-performance computing options. That breadth is a major advantage, but it also means that Azure VM pricing depends on family, region, OS, purchase model, disk, IP, transfer, and support. This comparison uses the current **Bsv2 low-memory Linux family in East US** because it provides clean 2 vCPU / 4 GB, 4 vCPU / 8 GB, and 8 vCPU / 16 GB sizes. `B2ls v2`, `B4ls v2`, and `B8ls v2` each have a **30% base CPU performance level** and use CPU credits to burst toward full vCPU performance. They have no local temporary storage and rely on Azure Managed Disks. Azure supports pay-as-you-go, Spot VMs, savings plans, and one-year or three-year reservations. Discounts can materially reduce compute cost, but they do not eliminate every surrounding storage, transfer, backup, support, or software charge. ## Raff overview Raff serves customers from one public region named `us-east`. Its current platform includes: - General Purpose shared-vCPU VMs - CPU-Optimized dedicated-vCPU VMs - Linux and Windows operating systems - Managed Kubernetes - Managed PostgreSQL, MySQL, Valkey, ClickHouse, and Kafka - Raff Apps - Raff Functions - S3-compatible Object Storage - Block Storage Volumes at $0.08/GB-month - Snapshots at $0.06/GB-month - Private networking, firewall controls, DDoS protection, IPv4, and IPv6 - API, CLI, Terraform, web console, VNC, resize, and custom OS workflows Current General Purpose plans include: - **2 vCPU / 2 GB / 40 GB NVMe — $12.99/month** - **2 vCPU / 4 GB / 80 GB NVMe — $17.99/month** - **4 vCPU / 4 GB / 80 GB NVMe — $24.99/month** - **2 vCPU / 8 GB / 160 GB NVMe — $27.99/month** - **4 vCPU / 8 GB / 160 GB NVMe — $33.99/month** - **8 vCPU / 8 GB / 160 GB NVMe — $48.99/month** - **8 vCPU / 16 GB / 240 GB NVMe — $71.99/month** Raff also offers CPU-Optimized plans for workloads that require dedicated-vCPU allocation. This refresh does not publish CPU-Optimized prices because the buyer-facing comparison is anchored to the current General Purpose catalog. VM bandwidth is unmetered on a standard **3 Gbps** public port. Raff's current data-protection model uses a **free backup-and-snapshot storage pool** rather than the older three-slot model; additional protection storage is billed when the included pool is exceeded. Raff reports **3,000+ customers and 15,000+ VMs**, publishes a **99.9% uptime SLA**, and currently shows **4.5/5 on Trustpilot** and **4.6/5 on G2**. ## Azure Virtual Machines pricing vs Raff pricing The table below compares Raff General Purpose shared-vCPU plans with Azure Bsv2 low-memory Linux pay-as-you-go compute in East US. Azure figures are monthly equivalents at 730 hours and exclude managed disk, outbound transfer, snapshots, premium software, support, and other network services. | Matched resource class | Raff General Purpose | Azure Bsv2 Linux, East US | Difference before Azure add-ons | |---|---:|---:|---:| | 2 vCPU / 4 GB | **$17.99** with 80 GB NVMe | `B2ls v2` about **$30.37 compute only** | Raff about 41% lower | | 4 vCPU / 8 GB | **$33.99** with 160 GB NVMe | `B4ls v2` about **$107.31 compute only** | Raff about 68% lower | | 8 vCPU / 16 GB | **$71.99** with 240 GB NVMe | `B8ls v2` about **$215.35 compute only** | Raff about 67% lower | This is a **resource-and-price comparison, not a performance-equivalent match**. Raff General Purpose uses shared vCPU, while Azure Bsv2 uses a CPU-credit burst model with a 30% baseline on the selected sizes. For sustained CPU demand, Azure buyers should compare a non-burstable family, and Raff buyers should evaluate the dedicated-vCPU CPU-Optimized family. ### What Azure's compute price does not include The Azure Bsv2 compute figure does not include: - An OS managed disk - Additional data disks - Standard SSD transaction charges where applicable - Snapshot storage - Internet data transfer beyond the free allowance - Load Balancer, Application Gateway, Front Door, NAT Gateway, VPN, or ExpressRoute where used - Azure Backup or Site Recovery resources - Paid support - Windows Server or SQL Server software charges where applicable Azure Managed Disks are billed by disk type, capacity or performance tier, redundancy, and—in some cases—transactions. Azure snapshots are billed separately from the VM compute charge. Raff includes the listed NVMe capacity and unmetered VM transfer. Its current protection model uses a free backup-and-snapshot storage pool, with additional protection storage billed when the included pool is exceeded. ### Windows Server pricing and licensing Azure Windows VM pricing includes a Windows Server software component in the pay-as-you-go rate. Qualified customers can reduce eligible Windows Server licensing costs with Azure Hybrid Benefit when the applicable Microsoft licensing requirements are met. Raff provides hosted Windows VMs through its Windows VM product. Azure is stronger when an organization already operates Microsoft licensing agreements, Entra ID, Azure Virtual Desktop, or hybrid Microsoft infrastructure. Raff is simpler when the requirement is a conventional hosted Windows server without the surrounding Azure governance stack. :::cta Deploy Your Server Compare current Raff VM plans with included NVMe storage and unmetered bandwidth. ::: ## Bandwidth and transfer policy Raff VM plans include unmetered bandwidth on a standard **3 Gbps** public port. There is no per-GB public internet egress line item on normal VM plans. Azure internet ingress is free. For internet egress routed through Microsoft's Premium Global Network from North America or Europe, Azure currently includes the first **100 GB per month**, then charges **$0.087/GB for the next 10 TB**, **$0.083/GB for the next 40 TB**, and lower tiered rates at larger volumes. Microsoft defines 1 TB as 1,000 GB on the pricing page. | Monthly outbound transfer | Raff | Azure Premium Network from North America | |---:|---:|---:| | 1 TB | Included | About **$78.30** | | 5 TB | Included | About **$426.30** | | 10 TB | Included | About **$861.30** | | 20 TB | Included | About **$1,691.70** | | 50 TB | Included | About **$4,181.70** | Azure can lower some transfer costs through CDN, Front Door, routing preference, private connectivity, or architectures that keep traffic inside eligible boundaries. Inter-region transfer, cross-zone patterns, NAT, load balancing, and hybrid services can have separate pricing rules. Raff is easier to budget for public APIs, SaaS traffic, downloads, media, remote desktops, backup replication, and unexpected traffic spikes. Azure is stronger when global routing, private backbone paths, hybrid connectivity, and Microsoft network services are deliberately designed into the architecture. ## Feature comparison: Azure Virtual Machines vs Raff ### Compute | Feature | Raff | Azure Virtual Machines | |---|---|---| | Shared or burstable compute | General Purpose shared vCPU | B-series CPU-credit burstable VMs | | Dedicated compute | CPU-Optimized family available | Multiple fixed-performance and specialized families | | Current 4 vCPU / 8 GB anchor | $33.99 with 160 GB NVMe | `B4ls v2` about $107.31 compute only | | Bsv2 CPU baseline | Not applicable | 30% on B2ls/B4ls/B8ls v2 | | Autoscaling | Application/platform dependent | Virtual Machine Scale Sets | | Spot VMs | Not in current public VM catalog | Available with eviction risk | | GPUs and confidential VMs | Not in current public VM catalog | Available | | Linux and Windows | Available | Available; licensing affects price | Azure wins on VM-family breadth, accelerators, autoscaling, Spot capacity, confidential computing, and specialized infrastructure. Raff offers a shorter decision path for ordinary application infrastructure. ### Networking | Feature | Raff | Azure Virtual Machines | |---|---|---| | Public internet transfer | Unmetered at 3 Gbps | Tiered egress after 100 GB/month | | Private networking | Available | Virtual Network, peering, Private Link, Virtual WAN | | Firewall | Included platform controls | Network Security Groups, Azure Firewall, policy tooling | | IPv4 and IPv6 | Available | Available; SKU and architecture details vary | | Load balancing | Not used as a Raff advantage in this comparison | Load Balancer, Application Gateway, Front Door available | | Hybrid connectivity | Standard VPN integration patterns | VPN Gateway and ExpressRoute | | Geography | One `us-east` region | More than 70 regions | Azure is the stronger global and hybrid network platform. Raff is the simpler option for a `us-east` application stack with predictable public transfer. ### Storage & Backups | Feature | Raff | Azure Virtual Machines | |---|---|---| | Base VM storage | Included NVMe capacity | Managed disk billed separately | | Additional block storage | Volumes at $0.08/GB-month | Standard HDD, Standard SSD, Premium SSD, Premium SSD v2, Ultra Disk | | Snapshots | $0.06/GB-month | Full and incremental snapshot products | | Protection baseline | Free backup-and-snapshot storage pool | Azure Backup or snapshot schedules configured separately | | Disaster recovery | Backup, snapshots, and application design | Azure Site Recovery and broader enterprise DR tooling | | Object storage | S3-compatible Object Storage | Azure Blob Storage | Azure offers more storage tiers, performance controls, redundancy options, and enterprise recovery products. Raff provides a simpler VM-storage and protection workflow. ### Platform Features | Feature | Raff | Azure | |---|---|---| | Managed Kubernetes | Available | Azure Kubernetes Service | | Managed databases | PostgreSQL, MySQL, Valkey, ClickHouse, Kafka | Azure SQL, PostgreSQL, MySQL, Cosmos DB, and more | | Functions | Raff Functions | Azure Functions | | Application platform | Raff Apps | App Service, Container Apps, AKS, Functions | | Identity | Focused platform access controls | Microsoft Entra ID and enterprise IAM ecosystem | | Analytics and AI | Focused infrastructure platform | Fabric, Azure AI, and broad data services | | API, CLI, Terraform | Available | Extensive ARM APIs, Azure CLI, Bicep, Terraform ecosystem | Azure clearly wins on specialized services and Microsoft enterprise integration. Raff covers a compact application stack for teams that do not need the wider Azure portfolio. ### Pricing & Billing | Feature | Raff | Azure Virtual Machines | |---|---|---| | Billing choices | Subscription terms plus hourly PAYG options | Pay-as-you-go, reservations, savings plans, Spot | | Disk in advertised VM price | Included | Usually separate | | Internet transfer | Unmetered | Tiered after free allowance | | Protection baseline | Free backup-and-snapshot storage pool | Separately configured and billed | | Windows licensing | Hosted Windows VM product | License-included PAYG or eligible Azure Hybrid Benefit | | Cost optimization | Published plan choices and longer terms | Reservations, savings plans, Spot, Hybrid Benefit, Advisor | Azure provides more optimization levers. Raff requires less optimization work to understand the ordinary monthly VM bill. ### Trust & Operations | Feature | Raff | Azure | |---|---|---| | Scale signal | 3,000+ customers; 15,000+ VMs | Global hyperscale cloud | | Public rating | Trustpilot 4.5/5; G2 4.6/5 | Broad enterprise review and partner ecosystem | | SLA | 99.9% | SLA depends on VM and availability architecture | | Support | Direct 24/7 support | Documentation, community, partners, and paid support plans | | Compliance scope | Focused provider program | Extensive global and industry certifications | Azure wins on enterprise history, compliance breadth, global partner coverage, and architecture options. Raff offers a more direct support and product relationship. ### Infrastructure | Feature | Raff | Azure | |---|---|---| | Public region model | One region named `us-east` | More than 70 regions | | Availability zones | Raff region model | Available across many Azure regions | | Global private backbone | Focused provider network | Microsoft global network | | Hybrid cloud | Standard integration patterns | Azure Arc, ExpressRoute, VPN, Azure Local, enterprise tooling | | Best fit | Predictable `us-east` VM and managed application workloads | Global, regulated, Microsoft-centric, hybrid, AI, and enterprise systems | ## Performance benchmarks: Raff vs Azure Virtual Machines Raff has not completed a controlled, matched Azure Virtual Machines benchmark within the last 90 days. This page therefore does **not** claim that Raff or Azure is faster. A valid benchmark would need to match: - Region and network test endpoints - Linux distribution and kernel - vCPU and RAM - Shared, burstable, or dedicated CPU behavior - Azure CPU-credit balance and baseline utilization - Disk type, capacity, caching, IOPS, throughput, and transaction settings - Raff General Purpose or CPU-Optimized class - At least three passes per test - CPU, memory, fio, database, HTTP, and network workloads - Full monthly price including Azure disk and transfer assumptions The Bsv2 family is especially unsuitable for a casual one-pass comparison because CPU credits affect sustained performance. `B2ls v2`, `B4ls v2`, and `B8ls v2` have a 30% baseline and can burst when credits are available. Raff General Purpose uses shared vCPU, while CPU-Optimized uses dedicated vCPU; selecting the wrong Raff class would also distort the result. Until a controlled test is completed, use this page for pricing and architectural fit rather than performance claims. ## When you should choose Azure Virtual Machines over Raff Choose Azure when: - You need more than 70 regions, availability zones, or country-specific deployment options. - Your company standardizes on Microsoft Entra ID, Azure Policy, Defender for Cloud, Azure Monitor, or Microsoft enterprise agreements. - You need Azure Hybrid Benefit for eligible Windows Server licenses. - The workload requires Azure Virtual Desktop, AKS, Azure SQL, Cosmos DB, App Service, Functions, Fabric, or Azure AI services. - You need Virtual Machine Scale Sets, Spot VMs, confidential computing, GPUs, or HPC. - ExpressRoute, Virtual WAN, Private Link, Front Door, or advanced hybrid networking is central to the design. - Azure Backup, Site Recovery, enterprise governance, or extensive compliance certifications are mandatory. - The workload must operate across multiple regions or zones. ## When you should choose Raff over Azure Virtual Machines Choose Raff when: - You want **2 vCPU / 4 GB / 80 GB NVMe for $17.99/month**. - You want **4 vCPU / 8 GB / 160 GB NVMe for $33.99/month**. - You want unmetered VM bandwidth rather than tiered public egress. - The current free backup-and-snapshot storage pool fits ordinary protection requirements. - Your application uses conventional VMs, managed databases, Kubernetes, Apps, Functions, and object storage rather than deep Azure-native dependencies. - Your users and compliance requirements fit `us-east`. - You prefer direct support and fewer billing dimensions. Compare nearby decisions with [Raff versus Google Cloud](/learn/compare/raff-vs-google-cloud), [Raff versus Oracle Cloud](/learn/compare/raff-vs-oracle-cloud), and [Raff versus AWS Lightsail](/learn/compare/raff-vs-aws-lightsail). :::cluster ## Migrating from Azure Virtual Machines to Raff 1. **Inventory the Azure estate.** Record VMs, size families, managed disks, disk caching, snapshots, public IPs, Virtual Networks, NSGs, load balancers, NAT, DNS, Entra ID dependencies, extensions, backup vaults, and managed-service connections. 2. **Classify portable and Azure-native components.** Standard Linux or Windows servers, application files, containers, and common databases are usually portable. AKS, Azure SQL, Cosmos DB, Managed Identity, Key Vault, Private Link, Azure Files, Service Bus, and Azure Virtual Desktop need replacement or hybrid planning. 3. **Choose the Raff compute class.** Use General Purpose for shared-vCPU workloads or CPU-Optimized where dedicated-vCPU allocation is required. Match RAM, usable storage, IP requirements, private networking, firewall exposure, and protection requirements. 4. **Move applications and data.** Redeploy from source control, transfer files with rsync or secure copy, migrate databases with native dump/restore or replication, and move compatible object data through S3 tools. Windows applications may require service, registry, scheduled-task, and license validation. 5. **Rebuild identity and secrets.** Replace Managed Identity, Key Vault references, domain assumptions, Azure extensions, metadata-service calls, and Entra-dependent authentication where they are not portable. 6. **Validate before cutover.** Test TLS, application health, RDP or SSH access, database consistency, storage mounts, scheduled jobs, outbound email, backups, restore procedures, monitoring, and third-party allowlists through a temporary hostname. 7. **Cut over and remove residual charges.** Lower DNS TTL, perform the final sync, update A and AAAA records, monitor production, retain Azure for rollback, then delete unused VMs, disks, snapshots, public IPs, load balancers, NAT resources, backup vault data, and monitoring resources. Operational gotchas: - Azure public IP addresses cannot move to Raff. Update DNS, security allowlists, payment providers, SMTP relays, VPN peers, and vendor integrations. - Azure managed-disk snapshots are not directly attachable to Raff. Use file-, image-, application-, or database-level migration. - Windows Server activation, RDS access, SQL Server licensing, and third-party application licenses must be checked separately. - Managed Identity, Key Vault, Azure VM extensions, and Instance Metadata Service calls can fail after migration. ## About Azure Virtual Machines [Azure Virtual Machines](https://azure.microsoft.com/en-us/products/virtual-machines) is Microsoft's IaaS compute service for Linux and Windows. It operates within Azure's global network of more than 70 regions and connects to Microsoft's networking, identity, storage, database, analytics, AI, hybrid, security, and management services. ## Conclusion: Azure Virtual Machines or Raff? Raff is more suitable for ordinary production servers when the workload fits `us-east` and predictable infrastructure economics matter more than global enterprise breadth. Azure is more suitable when global placement, Microsoft integration, specialized VM families, or hybrid architecture are central requirements. - **Linux VM pricing:** Raff 4 vCPU / 8 GB / 160 GB is $33.99; Azure `B4ls v2` is about $107.31 for compute alone before disk and transfer. - **Bandwidth:** Raff is unmetered on a standard 3 Gbps port; Azure includes 100 GB and then uses tiered internet-egress pricing. - **Protection:** Raff uses a free backup-and-snapshot storage pool; Azure Backup and snapshots are separately configured and billed. - **CPU model:** Raff General Purpose is shared-vCPU; Azure Bsv2 is CPU-credit burstable with a 30% baseline on the selected sizes. - **Platform:** Azure wins on more than 70 regions, Microsoft integration, hybrid networking, scale sets, accelerators, enterprise governance, and specialized services. - **Performance evidence:** no matched benchmark is available, so neither provider is declared faster. Choose Azure for global, regulated, hybrid, Microsoft-centric, AI, or deeply Azure-native systems. Choose Raff for `us-east` Linux and Windows servers that benefit from included NVMe capacity, unmetered bandwidth, managed databases, Kubernetes, Apps, Functions, and direct support. Continue with [the U.S. cloud server decision guide](/learn/guides/choose-us-cloud-server-latency-compliance) or review [Raff Windows VM](/products/windows-vm) and [Raff VM](/products/raff-vm). --- ### Google Cloud Alternative 2026: Pricing, Performance & Features URL: https://rafftechnologies.com/learn/compare/raff-vs-google-cloud Description: Considering Google Cloud? Compare Raff at $33.99/mo for 4 vCPU, 8 GB and 160 GB NVMe with Google Cloud pricing, bandwidth and tradeoffs. Raff is a practical Google Cloud alternative when a workload fits `us-east` and the priorities are lower VM list pricing, included NVMe capacity, unmetered bandwidth, and a smaller operating surface. Google Cloud is stronger when the architecture needs global regions, advanced IAM and governance, accelerators, global networking, or specialized services such as BigQuery and Vertex AI. For a current **spec-level** comparison, Raff General Purpose provides **4 vCPU / 8 GB / 160 GB NVMe for $33.99/month**, while Google Cloud lists `c4-highcpu-4` at **$0.170104/hour**, or about **$124.18 for 730 hours of compute before disk, external IPv4, egress, snapshots, support, or other services**. The May 16, 2026 benchmark on this page is preserved only as historical evidence from the configurations tested then; it is not a benchmark of Raff's current $33.99 General Purpose tier. Among Google Cloud alternatives and competitors, Raff is best evaluated as a **Compute Engine and Google Cloud VPS alternative** rather than as a replacement for every Google Cloud service. It fits buyers comparing cloud VM pricing, included storage, bandwidth, and operational simplicity; Google Cloud remains stronger when the architecture depends on its global or specialized products. For the wider location decision, review [how to choose a U.S. cloud server for latency and compliance](/learn/guides/choose-us-cloud-server-latency-compliance). ## Google Cloud vs Raff: which is right for you? The decision is less about provider size and more about operating model. Raff packages conventional cloud-server resources into a simpler monthly price, while Google Cloud provides a much broader global infrastructure and managed-service catalog. For teams comparing Google Cloud alternatives, the most useful filter is whether the workload needs a simpler VM-centric platform or the full Google Cloud service catalog. | Decision factor | Choose Raff | Choose Google Cloud | |---|---|---| | Geography | Your users and systems fit `us-east` | You require deployment across multiple Google Cloud regions or zones | | VM economics | You want RAM, listed NVMe capacity and unmetered bandwidth in one published plan price | You prefer granular resource pricing and can model separate compute, disk, IP and transfer charges | | CPU model | Shared-vCPU General Purpose plans fit the workload, or you select a Raff CPU-Optimized tier separately | You need specific Google machine families, commitments, Spot capacity, GPUs, TPUs or custom shapes | | Application platform | You need VMs, managed databases, Kubernetes, Apps, Functions and storage in a compact platform | You need GKE, Cloud SQL, AlloyDB, Spanner, BigQuery, Cloud Run, Vertex AI or other Google-native services | | Operations | A smaller product surface and direct support are valuable | Enterprise identity, policy, observability, procurement and multi-project governance are central | Raff is not a replacement for every Google Cloud service. It is most relevant as a Compute Engine alternative for conventional Linux and Windows application infrastructure where predictable monthly economics matter more than hyperscaler breadth. ## Google Cloud overview Google Cloud is a global hyperscale platform whose infrastructure products include Compute Engine, Google Kubernetes Engine, Cloud Storage, Cloud SQL, Virtual Private Cloud, load balancing, Cloud CDN and security services. Its broader catalog extends into analytics, AI, serverless computing, data engineering, databases, identity, observability and hybrid cloud. If your team uses **Google Cloud VPS** as shorthand for a Google-hosted virtual server, Compute Engine is the relevant product family for the VM-level comparison on this page. Google Cloud continues to operate across dozens of regions and more than one hundred zones. That geographic breadth remains one of its clearest advantages over Raff: teams can place workloads closer to users, spread systems across failure domains and build multi-region architectures. For a 4 vCPU / 8 GiB C4 high-CPU configuration, Google Cloud currently lists `c4-highcpu-4` at **$0.170104/hour**. At 730 hours, that is approximately **$124.18/month for compute alone**. Persistent storage, external IPv4 where used, internet egress, snapshots and support are separate billing dimensions. Google Cloud also offers committed-use discounts and Spot VMs. These can reduce compute cost, but they change the commercial assumptions through commitment length or interruption risk. ## Raff overview Raff serves customers worldwide from one public region named `us-east`. Current General Purpose cloud-server plans include: - **2 vCPU / 4 GB / 80 GB NVMe — $17.99/month** - **4 vCPU / 4 GB / 80 GB NVMe — $24.99/month** - **4 vCPU / 8 GB / 160 GB NVMe — $33.99/month** - **8 vCPU / 8 GB / 160 GB NVMe — $48.99/month** - **8 vCPU / 16 GB / 240 GB NVMe — $71.99/month** General Purpose uses shared vCPU. Raff also offers CPU-Optimized plans for workloads that need dedicated vCPU allocation; those tiers should be compared separately rather than treating the $33.99 General Purpose plan as a dedicated-CPU equivalent. Every current cloud-server plan includes unmetered bandwidth on a standard 3 Gbps public port, IPv4/IPv6 options, private networking, firewall controls, DDoS protection, root access, resize workflows, API/Terraform tooling and NVMe storage according to the selected plan. Raff also offers Managed Kubernetes, Managed Databases, Apps, Functions, Object Storage and additional block storage. Raff reports **3,000+ customers and 15,000+ VMs**, publishes a **99.9% uptime SLA**, and currently shows **4.5/5 on Trustpilot**. Google Cloud has far greater geographic scale and service breadth; Raff's advantage is a smaller operating surface and simpler pricing for conventional application infrastructure. ## Google Cloud pricing vs Raff pricing The current pricing comparison below uses **General Purpose Raff plans** against Google Cloud C4 high-CPU configurations with the same published vCPU and memory counts where available. This is a **spec-level buying comparison, not a claim of equal CPU allocation or equal performance**: Raff General Purpose uses shared vCPU, while Google Cloud C4 is a different compute architecture. | Published vCPU / memory | Raff General Purpose | Google Cloud C4 high-CPU compute only | What is excluded from Google price | |---|---:|---:|---| | 2 vCPU / 4 GB | **$17.99** with 80 GB NVMe | `c4-highcpu-2` ≈ **$62.09/mo** | Disk, external IPv4 where used, egress, snapshots, support | | 4 vCPU / 8 GB | **$33.99** with 160 GB NVMe | `c4-highcpu-4` ≈ **$124.18/mo** | Disk, external IPv4 where used, egress, snapshots, support | | 8 vCPU / 16 GB | **$71.99** with 240 GB NVMe | `c4-highcpu-8` ≈ **$248.35/mo** | Disk, external IPv4 where used, egress, snapshots, support | The 4 vCPU / 8 GB row is the clearest current buying anchor. Raff includes **160 GB NVMe and unmetered VM bandwidth for $33.99/month**. Google Cloud's approximately **$124.18/month** figure is compute only, so the final bill depends on the disk, IP, transfer and other services selected. For teams looking for a cheaper Google Cloud alternative for conventional VM hosting, this is the most useful current pricing comparison on the page. Raff also has a **4 vCPU / 4 GB / 80 GB plan at $24.99/month**. Google C4 high-CPU does not provide a directly matching 4 vCPU / 4 GiB shape, so this page does not force an artificial one-to-one comparison for that tier. Google Cloud discounts can materially reduce eligible compute pricing through one-year or three-year commitments, while Spot VMs can reduce cost for interruption-tolerant workloads. Those options can be attractive when their operating constraints fit the workload. :::cta Deploy Your Server Compare current Raff VM tiers with unmetered bandwidth and included NVMe storage. ::: ## Bandwidth and transfer policy Raff cloud-server bandwidth is unmetered on a standard 3 Gbps public port, so ordinary VM internet traffic does not create a per-GB egress line item. Google Cloud uses a more granular network-pricing model. Internet data transfer, inter-region traffic, Cloud NAT, load balancing, CDN and other paths can each have separate pricing rules. This gives architects more control but also creates more billing dimensions. For public APIs, SaaS responses, downloads, media delivery, backup replication and traffic spikes, Raff's unmetered model can be easier to forecast. Google Cloud can be stronger when workloads benefit from its global network, regional placement, CDN, private service access or broader networking products. ## Feature comparison: Google Cloud vs Raff | Area | Raff | Google Cloud | |---|---|---| | VM model | General Purpose shared vCPU plus CPU-Optimized dedicated vCPU tiers | Multiple machine families, custom shapes, Spot and specialized compute | | Current 4 vCPU / 8 GB buying anchor | $33.99 with 160 GB NVMe, shared vCPU | `c4-highcpu-4` ≈ $124.18 compute-only at 730 hours | | VM internet transfer | Unmetered, standard 3 Gbps port | Metered according to route, destination and service | | VM storage | Listed NVMe capacity included | Persistent Disk or Hyperdisk billed separately | | Managed Kubernetes | Available | GKE Standard and Autopilot | | Managed databases | PostgreSQL, MySQL, Valkey, ClickHouse, Kafka | Cloud SQL, AlloyDB, Spanner, Memorystore and more | | Application platform | Raff Apps | Cloud Run, App Engine and GKE-based options | | Functions | Raff Functions | Cloud Run functions and event services | | AI and analytics | Focused application platform | Vertex AI, BigQuery, GPUs and TPUs | | Geography | One public region, `us-east` | Global multi-region and multi-zone footprint | | Governance | Focused platform controls | Organization, folders, projects, IAM, policy and audit ecosystem | Google Cloud clearly wins on global reach, specialized infrastructure, enterprise governance, accelerators and managed-service breadth. Raff is more compelling when the workload is conventional, fits `us-east`, and benefits from a simpler server price with storage and unmetered bandwidth included. ## Performance benchmarks: Raff vs Google Cloud **The benchmark below is historical and is not used as proof of current $33.99 General Purpose performance.** It was run on **May 16, 2026** against different configurations and should be read only as a snapshot of that test window. The Raff test used a **4 vCPU / 8 GB CPU-Optimized VM with 120 GB storage under the earlier catalog**. The Google Cloud test used `c4-standard-4` with **4 vCPU / 15 GiB RAM** and Hyperdisk Balanced. The memory sizes, storage architecture and regions were not identical. ### Historical methodology | Parameter | Raff | Google Cloud | |---|---|---| | Test date | May 16, 2026 | May 16, 2026 | | Instance | Earlier CPU-Optimized 4 vCPU / 8 GB | `c4-standard-4`, 4 vCPU / 15 GiB | | Storage | 120 GB plan storage | Hyperdisk Balanced | | Region | Raff `us-east` | `us-central1` | | Tools | fio 3.36, iperf3 3.16, Geekbench 6 | Same tools | | Run count | One test window | One test window | ### Historical results | Benchmark | Raff | Google Cloud | Observed result in that test window | |---|---:|---:|---| | fio 4K total read/write | 108 MiB/s / 27.6k IOPS | 16 MB/s / 3.99k IOPS | Raff higher | | fio 64K total read/write | 1,048 MiB/s / 16.8k IOPS | 244 MB/s / ≈3.9k IOPS | Raff higher | | fio 512K total read/write | 2,135 MiB/s / 4.3k IOPS | 794 MB/s | Raff higher | | fio 1M total read/write | 2,251 MiB/s / 2.25k IOPS | 794 MB/s | Raff higher | | Geekbench 6 single-core | 2,266 | 2,001 | Raff higher | | Geekbench 6 multi-core | 6,840 | 4,450 | Raff higher | | Amsterdam iperf3 | 1.89 / 2.72 Gbps | 1.26 / 8.98 Gbps | Mixed | | Los Angeles iperf3 | Partial Raff result | 2.12 / 3.00 Gbps | Incomplete direct comparison | These results should not be generalized to current Raff General Purpose plans, all Google Cloud machine families, or future hardware. A future performance refresh should use matched memory, clearly recorded storage settings, at least three runs per test and an application-level benchmark. ## When you should choose Google Cloud over Raff Choose Google Cloud when: - You need deployment across multiple regions or zones. - Enterprise IAM, organization policy, audit and governance are mandatory. - The architecture depends on GKE, Cloud SQL, AlloyDB, Spanner, BigQuery, Cloud Run, Pub/Sub, Dataflow or Vertex AI. - You need GPUs, TPUs, Spot VMs, custom machine types or other specialized compute. - You need Google's global load balancing, CDN, Cloud Armor, Cloud NAT, Interconnect or hybrid-networking portfolio. - Commitments or Spot pricing fit your workload economics. - Multi-region residency, compliance or latency requirements cannot be met from `us-east`. ## When you should choose Raff over Google Cloud Choose Raff when: - You want a **Google Cloud VPS or Compute Engine alternative** for conventional Linux or Windows workloads rather than a replacement for every Google Cloud service. - A **4 vCPU / 8 GB / 160 GB** shared-vCPU VM at **$33.99/month** fits the workload. - You want unmetered VM bandwidth rather than a route- and destination-based egress model. - You prefer included plan storage rather than separately sizing and pricing VM disk capacity. - Your stack uses conventional VMs, managed databases, Kubernetes, Functions, Apps and object storage rather than specialized hyperscaler services. - Your users and compliance requirements fit `us-east`. - A smaller product surface and direct support reduce operational overhead for your team. Compare nearby decisions with [Raff versus AWS Lightsail](/learn/compare/raff-vs-aws-lightsail), [Raff versus DigitalOcean](/learn/compare/raff-vs-digitalocean), and [Raff versus Vultr](/learn/compare/raff-vs-vultr). :::cluster ## Migrating from Google Cloud to Raff 1. **Inventory the Google Cloud estate.** Record Compute Engine instances, machine families, disks, snapshots, images, static IPs, VPCs, firewall policies, load balancers, Cloud NAT, DNS, service accounts, secrets, monitoring and managed-service dependencies. 2. **Classify portable and non-portable components.** Linux VMs, application files, containers and common databases are usually portable. BigQuery, Spanner, Vertex AI, Google-specific IAM integrations and private Google service paths need replacement or a hybrid design. 3. **Choose the Raff target tier.** Use General Purpose for shared-vCPU workloads and CPU-Optimized where dedicated vCPU allocation is required. Do not select a target solely from the old May benchmark. 4. **Move application and data layers.** Redeploy stateless applications from source control, transfer files with rsync or equivalent tools, and migrate databases with native dump/restore or replication workflows. 5. **Validate before cutover.** Test TLS, application health, database consistency, storage mounts, outbound services, firewall rules, backups, monitoring and third-party allowlists. 6. **Cut over with rollback.** Lower DNS TTL, perform the final sync, update records, monitor production and retain the Google Cloud environment until the rollback window closes. 7. **Remove residual Google Cloud charges.** Review VMs, disks, reserved IP addresses, snapshots, images, load balancers, NAT and logging resources after verification. ## About Google Cloud [Google Cloud Compute Engine](https://cloud.google.com/compute) is Google's infrastructure-as-a-service VM platform. It connects to a global portfolio that includes Google Kubernetes Engine, Cloud Storage, Cloud SQL, Cloud Run, BigQuery, Vertex AI and extensive networking and security services. ## Conclusion: Google Cloud or Raff? For buyers comparing **Google Cloud alternatives and competitors at the VM layer**, Raff is strongest when the workload fits `us-east` and simpler monthly economics matter more than hyperscaler breadth. The current **4 vCPU / 8 GB / 160 GB Raff General Purpose plan is $33.99/month** and includes its listed NVMe capacity plus unmetered VM bandwidth. Google Cloud's `c4-highcpu-4` is approximately **$124.18/month for 730 hours of compute alone**, before storage and other separately billed resources. This is a current **pricing/spec comparison**, not a claim that the two CPU allocation models perform identically. Google Cloud remains the stronger choice for global placement, enterprise governance, accelerators, analytics, AI and specialized managed services. Raff is better aligned with teams that want a Google Cloud VPS or Compute Engine alternative for conventional cloud infrastructure, fewer billing dimensions and a compact managed application stack. The May 16, 2026 benchmark remains on this page only as historical test evidence. It should not be treated as a benchmark of the current $33.99 General Purpose tier. Continue with [the U.S. cloud server decision guide](/learn/guides/choose-us-cloud-server-latency-compliance) or review [Raff VM plans](/products/raff-vm). --- ### Kamatera Alternative 2026: Pricing, Performance & Features URL: https://rafftechnologies.com/learn/compare/raff-vs-kamatera Description: Considering Kamatera? Raff is $17.99/mo for 2 vCPU, 4 GB and 80 GB NVMe against Kamatera Type A at $22 with 5 TB traffic. Kamatera is a cloud provider that sells servers by configuration rather than by plan: you pick cores, RAM, disk and region in a calculator and it prices the result. Raff Technologies is a US cloud provider where the virtual machine is one product among several, alongside managed databases, object storage, Functions and Kubernetes on the same account. Both run NVMe storage and both offer shared and dedicated CPU. At a matched 2 cores, 4 GB and 80 GB in New York, Kamatera's budget Type A configuration is $22/month and Raff General Purpose is $17.99/month. ## Kamatera VPS and Raff at a glance **Kamatera** has no fixed plan list. Every server is configured from four CPU types, 256 MB to 128 GB of RAM, 20 GB to 4 TB of NVMe storage, and 21 data centers. The four types are its own descriptions: - **Type A — Availability**, the budget tier - **Type B — General Purpose**, marked Recommended, where "CPU threads are dedicated with reserved resources guaranteed" - **Type T — Burstable**, for spiky workloads - **Type D — Dedicated**, the high-performance tier Every configuration includes **5 TB of traffic**, with additional transfer at $0.01/GB and additional storage at $0.05/GB-month. Billing is hourly, charged by the minute, with no long-term contract. Kamatera also sells cPanel, Plesk and Microsoft SQL Server licensing as add-ons, offers Windows Server and Windows Desktop images, and has optional managed service and extended daily backup. Its footprint is wide: Sydney, Toronto, Hong Kong, Frankfurt, Tel Aviv, Milan, Tokyo, Bucharest, Singapore, Madrid, Stockholm, Amsterdam, London, and eight US locations including New York, Chicago, Dallas, Los Angeles and Santa Clara. **Raff Technologies** runs 15,000+ VMs for 3,000+ customers from us-east, with a 99.90% monthly uptime SLA backed by service credits, rated 4.5/5 on Trustpilot and 4.6/5 on G2. VMs run AMD EPYC with DDR5 ECC memory and NVMe storage in two lines: General Purpose with shared vCPU from $4.99/month, and CPU-Optimized with dedicated vCPU from $15.99/month, scaling to 16 vCPU and 32 GB. Every plan includes a 3 Gbps port with unmetered transfer, automated Daily or Weekly backup schedules, uncapped snapshots, firewall controls, private networking and full root access. Past the VM, Raff sells S3-compatible object storage at $7/month for 100 GB and 1 TB of egress, managed PostgreSQL, MySQL, Valkey, ClickHouse and Kafka from $7.99/month, managed Kubernetes with a free control plane and workers from $9.99/month, Functions with a free monthly tier, block volumes at $0.08/GiB-month, and Raff Apps from $3/month. ## Kamatera VPS pricing vs Raff pricing Because Kamatera prices per configuration, the comparison has to be built by matching a shape and reading the total. The figures below were configured on Kamatera's own calculator on 2026-08-20, New York, Ubuntu Server, with the included 5 TB of traffic. **Class matters here.** Raff General Purpose is shared vCPU with no CPU guarantee, which matches **Type A**. Raff CPU-Optimized is dedicated vCPU, which matches **Type B and Type D** — Kamatera describes Type B as giving each vCPU a dedicated CPU thread with reserved resources. ### Shared vCPU: Raff General Purpose against Kamatera Type A | Shape | Raff General Purpose | Kamatera Type A | |---|---|---| | 2 cores / 4 GB / 80 GB | **$17.99** — unmetered, 3 Gbps | $22 — 5 TB included | | 4 cores / 8 GB (≈150 GB) | **$33.99** at 160 GB | $47 at 150 GB | Raff is **18% to 28% cheaper** at both shapes, with more disk at the larger one and no transfer cap. ### Dedicated vCPU: Raff CPU-Optimized against Kamatera Type B and D | Shape | Raff CPU-Optimized | Kamatera Type B | Kamatera Type D | |---|---|---|---| | 2 cores / 4 GB / 80 GB | **$36.99** | $45 | $70 | | 4 cores / 8 GB | **$72.99** at 120 GB | $95 at 150 GB | — | Raff is **18% to 23% cheaper than Type B** and **47% cheaper than Type D** at the matched shape. *Kamatera prices configured on kamatera.com on 2026-08-20 for the New York data center with Ubuntu Server and the included 5 TB traffic allowance; add-on licensing, managed service and extended backup excluded. Storage steps differ between the two providers, so the 150 GB and 160 GB rows are the closest available match rather than identical.* Raff is cheaper at every CPU class Kamatera sells. That is the whole pricing story, and it holds whether you compare budget against budget or dedicated against dedicated. ### What Kamatera charges for separately Two rates are worth knowing before configuring. Transfer beyond the included 5 TB is **$0.01/GB**, so an extra 5 TB adds $50/month. Storage beyond the configured disk is **$0.05/GB-month**, which is more than half again what Raff charges for block volumes at $0.08/GiB-month once you account for the units. Raff includes unmetered transfer on every plan, so there is no equivalent line to calculate. ### Automated backups Raff includes a free backup and snapshot storage pool — 50 GB per account plus 10–15% of each VM's disk — with Daily and Weekly schedules you configure, retention from 1 to 365 days, and uncapped snapshots. Storage above the pool is $0.06/GB-month. Kamatera offers extended daily backup as a paid add-on at configuration time, so price it in rather than assuming it is included. ## Kamatera VPS performance vs Raff This is a clean pairing: both machines are shared-CPU, both are 2 cores with 4 GB, and both sit in the same region — Kamatera in New York, Raff in us-east. ### Methodology Raff figures are internal, measured March–May 2026 on a General Purpose 2 vCPU / 4 GB instance in us-east. Kamatera figures are third-party, from VPSBenchmarks, on an "Availability 4GB 2 cores" configuration in New York running Ubuntu 26.04, trial started 24 June 2026 — a Type A server, which Kamatera's own spec sheet marks as neither dedicated nor burstable, the same shared-CPU basis as Raff General Purpose. The benchmarked Kamatera configuration lists at $19.00/month with 40 GB of disk. ### Results | Metric | Raff General Purpose | Kamatera Type A | Notes | |---|---:|---:|---| | Geekbench 6 single-core | **2,266** | 1,126 | Raff 2.01x higher | | Geekbench 6 multi-core | **4,057** | 1,979 | Raff 2.05x higher | | fio 4K read, 50/50 mix | **48,670 IOPS** | 46,691 IOPS | Level, Raff 4% higher | | fio 1M sequential read | 2,491 MB/s | **2,985 MB/s** | Kamatera 1.20x higher | | fio 1M sequential write | 1,257 MB/s | **3,183 MB/s** | Kamatera 2.53x higher | | iperf3 to NYC, upload | 9,574 Mbps | 9,626 Mbps | Level | | iperf3 to NYC, download | 3,635 Mbps | **9,523 Mbps** | Kamatera 2.62x higher | | Processor | AMD EPYC, DDR5 ECC | Intel Xeon Sapphire Rapids | | ### What the results tell us **Raff is roughly twice as fast per core.** 2,266 against 1,126 on Geekbench 6 single-core, and 4,057 against 1,979 multi-core, on the same shared-CPU basis in the same region. For anything bound by application logic — API workers, rendering, request handling, queue consumers — that is the number that decides throughput, and it is not close. Raff also costs less: $17.99/month with 80 GB against the benchmarked $19.00 with 40 GB. **Kamatera wins on sequential disk and download.** Sequential 1M write measured 3,183 MB/s against Raff's 1,257, and download to New York 9,523 Mbps against 3,635. The download figure reflects a real capability difference rather than a measurement artifact: Raff publishes a 3 Gbps port, and the Kamatera box is clearly on a faster interface. If your workload is dominated by large sequential writes or by pulling large volumes of data inbound, Kamatera's configuration is the stronger one in this test. **Random I/O is level.** 48,670 IOPS against 46,691 on the same 50/50 4K job — within noise, and the pattern most databases actually run. Read it as a trade: Raff for CPU-bound work at lower cost, Kamatera for sequential throughput and inbound bandwidth. ## Kamatera vs Raff: features and reliability ### Compute Kamatera configures from 1 to 104 cores and 256 MB to 128 GB of RAM across four CPU classes — a far wider range than Raff's 16 vCPU and 32 GB ceiling, and finer-grained at the bottom. Raff offers General Purpose from $4.99/month and CPU-Optimized from $15.99/month, on AMD EPYC with DDR5 ECC memory, and resizes on demand: stop the VM, switch plan, restart, with the difference settled to the account balance and a `resize` API endpoint for CPU, RAM and disk. ### Networking Raff includes a 3 Gbps port with unmetered transfer, private networking, VPC, firewall controls and site-to-site VPN gateways. Kamatera includes 5 TB of traffic per server with additional transfer at $0.01/GB, and offers multiple public IPs at configuration time. ### Storage Both use NVMe. Kamatera lets you configure the boot disk from 20 GB to 4 TB and attach up to four additional volumes at $0.05/GB-month. Raff separates storage into VM disk, block volumes at $0.08/GiB-month that resize independently, and S3-compatible object storage at $7/month for 100 GB with 1 TB of egress. ### Support Raff provides 24/7 human support through live chat, with a first response typically under 10 minutes. No bots triaging you first, and no support tier to buy: a single $4.99 VM reaches the same engineers as a hundred production machines, through the same queue. Kamatera offers an optional paid managed service tier, so confirm what is included at your service level before buying. ### Platform and licensing This is where the two catalogs diverge, and each has something the other lacks. Kamatera sells **licensed software as part of the server**: cPanel in three sizes, Plesk in three sizes, Microsoft SQL Server from Express to Enterprise per vCPU, Microsoft Office Standard per user, plus Windows Server 2016 through 2025 and Windows Desktop images. Raff covers most of that list through its SPLA program: Windows Server Standard at **$15.00/month per instance**, multi-user RDP licensed with **RDS User SALs at $8.00/month per user**, and SQL Server and Office licensing on the same bill. Bring-your-own-licence is supported at create time. What Kamatera adds that Raff does not sell is **cPanel and Plesk** hosting control panels, and Windows Desktop images. Raff sells **managed services around the server**: managed PostgreSQL, MySQL, Valkey, ClickHouse and Kafka from $7.99/month, object storage at $7/month, Functions with a free tier of 100,000 GB-seconds and 10,000 vCPU-seconds per month, Raff Apps from $3/month, and managed Kubernetes with a free control plane. They connect over private networking, share one API, one CLI and one bill. The distinction is straightforward: Kamatera helps you build a bigger server, Raff helps you build a smaller one with managed pieces beside it. ## When you should choose Kamatera over Raff - **Users outside the United States** — 21 data centers across Europe, Asia, Australia, the Middle East and North America against Raff's single us-east region - **cPanel or Plesk on one bill** — hosting control panels configured into the server, plus Windows Desktop images; Raff licenses Windows Server, RDS, SQL Server and Office but not these - **Sequential-throughput and inbound-heavy workloads** — measured 2.53x higher 1M sequential write and 2.62x higher download to New York in third-party testing - **Very large or very small servers** — up to 104 cores and 128 GB RAM, or down to 256 MB, against Raff's 16 vCPU / 32 GB ceiling and 1 GB floor - **Exact configurations** — cores, RAM and disk chosen independently, rather than fitting a workload to a fixed plan - **Short-lived workloads** — hourly billing charged by the minute makes brief tests and burst capacity cheap - **Burstable workloads** — the Type T tier has no Raff equivalent ## When you should choose Raff over Kamatera - **CPU-bound applications** — measured 2.01x faster single-core and 2.05x faster multi-core than a same-class Kamatera Type A server in the same region ([VPS for application hosting](/learn/guides/vps-for-application-hosting)) - **Lower cost at every CPU class** — 18% to 28% below Type A on shared vCPU, 18% to 23% below Type B and 47% below Type D on dedicated - **Egress-heavy applications** — unmetered transfer on a 3 Gbps port against 5 TB included and $0.01/GB after - **Database-backed products** — managed PostgreSQL, MySQL, Valkey, ClickHouse and Kafka from $7.99/month over private networking, instead of self-hosting and licensing your own ([VPS for databases](/learn/guides/vps-for-databases)) - **Stacks that outgrow one server** — object storage at $7/month, Functions with a free monthly tier, Raff Apps from $3/month and managed Kubernetes with a free control plane - **Backups without an add-on** — Daily and Weekly schedules on a free storage pool with 1 to 365 day retention, against extended daily backup priced as an option - **24/7 human support at no extra tier** — live chat to the same engineers at any account size, first response typically under 10 minutes ## Migrating from Kamatera to Raff 1. **Match the CPU class, not the core count** — a Kamatera Type A core and a Type D core are different products. Type A maps to Raff General Purpose, Type B and D to CPU-Optimized. 2. **Check your region requirement** — Raff serves us-east only. If you are running in Frankfurt, Tokyo or Tel Aviv for latency or data residency, this migration will not preserve that. 3. **Inventory your licences first** — licences bought through Kamatera do not transfer. Raff relicenses Windows Server at $15.00/month per instance, RDS User SALs at $8.00/month per user, and SQL Server and Office through the same SPLA program; cPanel and Plesk it does not sell, so price those separately. 4. **Right-size on utilisation, and test sequential paths** — Kamatera configurations are often built larger than needed because the calculator makes it easy. Measure actual usage first, and if your workload is dominated by large sequential writes, benchmark it on Raff before committing. 5. **Move data in order** — files with rsync or SCP, then database dumps into managed Postgres or MySQL, then static assets to object storage. Keep the Kamatera server running throughout. 6. **Cut over and stop the clock** — lower DNS TTL beforehand, switch, then terminate the Kamatera server rather than stopping it, since hourly billing continues while resources are allocated. ## About Kamatera Kamatera is a cloud infrastructure provider offering configurable cloud servers, block storage, load balancers, private networking and managed services from 21 data centers across North America, Europe, Asia, Australia and the Middle East. Servers are priced by configuration rather than by fixed plan, starting at $4/month. See [Kamatera pricing](https://www.kamatera.com/pricing/) for current rates and the configuration calculator. ## Conclusion: Kamatera or Raff? The comparison resolves across four axes: - **Price** — Raff wins at every CPU class: 18–28% below Type A, 18–23% below Type B, 47% below Type D at matched shapes - **Performance** — split: Raff 2.01x faster per core on the same class in the same region; Kamatera 2.53x higher sequential write and 2.62x higher download - **Reach** — Kamatera wins, 21 data centers against Raff's single us-east region - **Configurability** — Kamatera wins, with independent core/RAM/disk selection, a 104-core ceiling, and cPanel and Plesk on the same bill; both providers license Windows Server, RDS, SQL Server and Office - **Managed services** — Raff wins, with managed databases from $7.99/month, object storage, Functions, Apps and Kubernetes on one account over private networking If your users are outside the United States, you need cPanel or Plesk bundled into the server bill, or you want a server shape Raff does not sell, choose Kamatera. If your users are in North America and you want lower cost per server plus managed databases and storage beside it, choose Raff. Raff runs 15,000+ VMs for 3,000+ customers and is rated 4.5/5 on Trustpilot, with a 99.90% monthly uptime SLA in writing. --- ### DigitalOcean Kubernetes Alternative 2026: Pricing, Performance & Features URL: https://rafftechnologies.com/learn/compare/digitalocean-kubernetes-alternative Description: Considering DigitalOcean Kubernetes? Raff is $17.99/mo for 2 vCPU/4 GB with $0 egress; DOKS is $24/mo with broader regions. Raff wins on lower comparable worker prices, a $30 HA control-plane add-on, $0 public egress, and a simpler small-team cost model. DigitalOcean Kubernetes wins on broader regional placement, dedicated CPU and GPU node choices, mature DigitalOcean integrations, and a 99.95% HA control-plane SLA. Choose DigitalOcean Kubernetes when region choice or specialized worker classes are requirements; choose Raff when `us-east`, lower published worker prices, and predictable transfer costs fit the workload. Two 2 vCPU / 4 GB workers with HA cost $65.98/month on Raff versus $88/month on DigitalOcean before storage, load balancers, and other attached services. DigitalOcean Kubernetes and Raff both remove day-to-day control-plane administration while leaving application architecture, workload sizing, policies, and data protection with the customer. The standard control plane is $0 on both platforms, but their surrounding economics differ: Raff's 2 vCPU / 4 GB worker is $17.99/month, while DigitalOcean's Basic 2 vCPU / 4 GiB worker is $24/month. DOKS offers a wider infrastructure catalog and geographic footprint; Raff focuses on one public `us-east` region, $0 public egress, lower cluster-storage pricing, and a smaller operating surface for teams that do not need every cloud primitive. ## DigitalOcean Kubernetes vs Raff: which is right for you? DigitalOcean Kubernetes is the stronger choice for global placement, specialized node classes, and DigitalOcean-native infrastructure. Raff is the stronger choice when the cluster can run in `us-east` and monthly worker, HA, storage, and transfer costs need to stay easy to forecast. | Decision factor | Choose Raff | Choose DigitalOcean Kubernetes | |---|---|---| | 2 vCPU / 4 GB worker | $17.99/month | $24/month Basic | | HA control plane | $30/month | $40/month | | Geography | `us-east` fits | You need broader DOKS region choice | | Worker classes | General Kubernetes worker tiers fit | Dedicated CPU, storage-optimized, or GPU nodes are required | | Public egress | You want $0 public egress | Pooled node transfer plus $0.01/GiB overage fits | | Persistent storage | $0.10/GB-month cluster storage fits | DigitalOcean Volumes at $0.10/GiB-month fit | | Operations | Built-in Raff cluster workflow is enough | API, `doctl`, Terraform, registry, VPC, and wider DigitalOcean integrations matter | A specific first-hand decision rule from Raff's infrastructure work is to price the cluster around the steady worker floor before adding optional platform services. For a small team, two always-on workers, HA, storage, and outbound traffic usually explain more of the bill than the nominal $0 control plane. ## DigitalOcean Kubernetes overview [DigitalOcean Kubernetes](https://www.digitalocean.com/products/kubernetes), or DOKS, is DigitalOcean's managed Kubernetes service. DigitalOcean operates the Kubernetes control plane while customers manage node pools, workloads, policies, application availability, persistent data, and recovery design. DOKS worker nodes use DigitalOcean Droplet sizes. Current Basic Regular prices include **$12/month for 1 vCPU / 2 GiB**, **$24/month for 2 vCPU / 4 GiB**, and **$48/month for 4 vCPU / 8 GiB**. DigitalOcean also offers dedicated CPU, memory-focused, storage-focused, and GPU compute options for teams whose workloads need different node characteristics. The standard DOKS control plane is free. The HA control plane costs **$40/month** and carries a **99.95% control-plane SLA**. DOKS supports node-pool autoscaling, automatic version workflows, VPC networking, DigitalOcean Volumes, DigitalOcean Load Balancers, Container Registry, API access, `doctl`, and Terraform. DigitalOcean's strongest advantages are its broader regional footprint, specialized worker classes, mature automation tooling, and the ability to connect Kubernetes to a larger DigitalOcean product catalog without leaving the provider. ## Raff overview [Raff Kubernetes](/products/kubernetes) is a managed Kubernetes service with a free standard control plane, optional three-master HA, worker-node autoscaling, built-in monitoring, managed cluster networking, and a deployment workflow designed for small teams and operators that want Kubernetes without maintaining the control plane themselves. Current worker tiers are: | Worker | vCPU | RAM | SSD | Monthly price | |---|---:|---:|---:|---:| | K8s Starter | 1 | 2 GB | 50 GB | $9.99 | | K8s Standard | 2 | 4 GB | 80 GB | $17.99 | | K8s Performance | 4 | 8 GB | 120 GB | $33.99 | | K8s High Memory | 8 | 16 GB | 180 GB | $71.99 | | K8s Large | 8 | 32 GB | 240 GB | $119.99 | | K8s Scale | 16 | 64 GB | 480 GB | $229.99 | The standard control plane costs **$0**. Optional HA with three masters and etcd quorum costs **$30/month**. Cluster storage is **$0.10/GB-month**, with a 10 GB minimum, 100 GB default, and 1 TB maximum; replicated cluster storage requires at least two nodes. Cluster-to-storage traffic is not metered. Raff Kubernetes prices public egress at **$0**. Raff currently reports **3,000+ customers, 15,000+ production VMs, and a 99.9% platform SLA**. Raff's Trustpilot rating was verified at **4.5/5** on August 16, 2026, with G2 at 4.6/5. Raff gives up DigitalOcean's geographic and machine-class breadth in exchange for a more compact `us-east` operating and billing model. ## DigitalOcean Kubernetes pricing vs Raff pricing Both services charge $0 for the standard managed control plane. The meaningful price comparison therefore starts with worker nodes and then adds HA, storage, outbound traffic, load balancing, databases, and any other services the workload actually uses. | Buying position | Raff Kubernetes | DigitalOcean Kubernetes | Decision signal | |---|---:|---:|---| | 1 vCPU / 2 GB worker | $9.99/month | $12/month Basic | Raff is $2.01 lower | | 2 vCPU / 4 GB worker | $17.99/month | $24/month Basic | Raff is $10.01 lower | | 4 vCPU / 8 GB worker | $33.99/month | $48/month Basic | Raff is $17.01 lower | | HA control plane | $30/month | $40/month | Raff add-on is $10 lower | | Persistent storage | $0.10/GB-month | $0.10/GiB-month | Raff has the lower published unit price | **Comparison class:** these rows compare published resource shapes and prices, not measured Kubernetes performance. DigitalOcean Basic workers use a shared-CPU Droplet class; Raff does not publish an identical DigitalOcean CPU-scheduling taxonomy, so vCPU counts alone are not benchmark equivalence. A two-node 2 vCPU / 4 GB cluster costs **$35.98/month** on Raff and **$48/month** on DOKS before HA. With HA enabled, the totals become **$65.98** and **$88** respectively before storage and surrounding services. ### Bandwidth cost math DigitalOcean pools outbound-transfer allowances from worker nodes and charges **$0.01/GiB** above the pooled account allowance. A current $12 Basic worker includes 2,000 GiB, while the $24 2 vCPU / 4 GiB Basic worker includes 4,000 GiB of transfer. Raff Kubernetes prices public egress at $0. For a two-node DOKS cluster using the $24 worker shape, the two nodes contribute **8,000 GiB** of listed transfer allowance before account-level pooling effects from other eligible resources. | Public outbound traffic | Raff egress charge | DOKS overage from an 8,000 GiB two-worker allowance | |---:|---:|---:| | 4,000 GiB | $0 | $0 | | 8,000 GiB | $0 | $0 | | 10,000 GiB | $0 | $20 | | 20,000 GiB | $0 | $120 | The DOKS examples isolate worker transfer and overage. A real DigitalOcean account can pool eligible transfer across resources, so the invoice can differ from a single-cluster example. ### Automated backups Neither managed control plane should be treated as an automatic backup of Kubernetes application data. DOKS manages the control plane, but customers still need a recovery plan for PersistentVolume data, databases, object storage, manifests, secrets, and application-level state. DigitalOcean Volumes used by Kubernetes cost **$0.10/GiB-month** and support snapshots, but snapshots are a separately managed protection mechanism rather than a blanket DOKS workload-backup policy. Teams running stateful workloads should define snapshot or backup schedules and test restores instead of assuming control-plane HA protects data. Raff follows the same separation of responsibilities. Managed control-plane availability does not replace workload backups. Raff cluster storage, managed databases, object storage, and application configuration each need recovery procedures appropriate to the state they hold. :::cta cluster Deploy a Raff Kubernetes cluster with a $0 standard control plane; add three-master HA for $30/month when required. ::: ## Bandwidth and transfer policy Raff Kubernetes prices public egress at **$0**, and cluster-to-Raff-cluster-storage traffic is not metered. That makes outbound traffic a fixed-cost decision from the Kubernetes side rather than an additional per-GiB line item. DigitalOcean includes outbound-transfer allowances with worker Droplets and pools eligible transfer at the account level. Basic worker allowances range by selected size; the current 2 vCPU / 4 GiB Basic size includes **4,000 GiB**. Usage above the pooled allowance is billed at **$0.01/GiB**. DigitalOcean's model can work well when workloads stay inside pooled allowances. Raff's model is simpler for APIs, downloads, media, package distribution, or other workloads where outbound transfer can be large or uneven from month to month. ## Feature comparison: DigitalOcean Kubernetes vs Raff | Feature | Raff Kubernetes | DigitalOcean Kubernetes | |---|---|---| | Standard control plane | $0 | $0 | | HA control plane | $30/month | $40/month | | 2 vCPU / 4 GB worker | $17.99/month | $24/month Basic | | Node-pool autoscaling | Yes | Yes | | Dedicated CPU worker class | No separately published class | Yes | | GPU workers | No published Kubernetes GPU tier | Yes | | Public regions | 1 — `us-east` | Broader global DOKS footprint | | Public egress | $0 | Pooled allowance, then $0.01/GiB | | Persistent storage | Raff cluster storage | DigitalOcean Volumes through CSI | | Storage unit price | $0.10/GB-month | $0.10/GiB-month | | Full `kubectl` workflow | Yes | Yes | | Monitoring | Built into Raff cluster workflow | DigitalOcean monitoring plus user-selected tooling | | API / CLI / Terraform | Raff platform workflows | API, `doctl`, Terraform | | Container registry | Compatible external registries | Native DigitalOcean Container Registry integration | | Managed data options | PostgreSQL, MySQL, Valkey, ClickHouse, Kafka | DigitalOcean Managed Databases catalog | DigitalOcean wins on region choice, specialized workers, GPU availability, native registry integration, and mature DigitalOcean automation. Raff wins on the published worker examples above, HA add-on price, cluster-storage unit price, and $0 public Kubernetes egress. ## Features and reliability: Raff vs DigitalOcean Kubernetes This comparison includes **0 controlled Raff-versus-DigitalOcean Kubernetes workload benchmarks**, so it does not declare either platform faster. A valid Kubernetes performance comparison would require matched CPU scheduling, Kubernetes versions, node counts, CNI behavior, storage paths, regions, Pod requests, application images, and repeated workload runs. ### Control-plane reliability DigitalOcean's HA control plane carries a **99.95% SLA**, which is a stronger numerical control-plane commitment than Raff's **99.9% platform SLA**. DigitalOcean should be preferred when that specific contractual figure is a hard requirement. Raff's HA option uses three masters with etcd quorum and costs $30/month. DigitalOcean's HA control plane costs $40/month. The lower Raff price does not make application workloads automatically highly available: replica count, Pod disruption behavior, worker capacity, ingress, storage, and external dependencies still determine application resilience. ### Worker and scaling choices DigitalOcean has the wider worker catalog. DOKS can use shared Basic Droplets as well as dedicated and specialized compute families, including GPU options. This is a genuine advantage for workloads that need stronger CPU isolation, memory-heavy nodes, local-storage characteristics, or accelerators. Raff exposes a smaller set of Kubernetes worker tiers from 1 vCPU / 2 GB through 16 vCPU / 64 GB. That narrower catalog makes ordinary small-team sizing simpler but does not cover every specialized DigitalOcean use case. ### Stateful recovery DigitalOcean Volumes and Raff cluster storage both persist independently of an individual Pod, but persistence is not the same as backup. Kubernetes operators still need to define what is copied, how often it is copied, where recovery data lives, how databases are made consistent, and how restore procedures are tested. ### Trust and operating evidence DigitalOcean has the deeper public operating history and review base. Its Trustpilot profile was **4.6/5** when checked for this refresh. Raff's current Trustpilot signal is **4.5/5**, alongside **3,000+ customers and 15,000+ production VMs**. The much larger DigitalOcean review sample is a genuine trust advantage; neither review score should replace architecture or SLA evaluation. ## When you should choose DigitalOcean Kubernetes over Raff Choose DigitalOcean Kubernetes when: - **Broader region choice is required.** DOKS supports deployment beyond Raff's single public `us-east` region. - **Dedicated CPU nodes matter.** DigitalOcean offers dedicated compute families in addition to shared Basic workers. - **GPU workers are required.** DigitalOcean offers GPU infrastructure that Raff Kubernetes does not currently publish. - **A 99.95% HA control-plane SLA is mandatory.** Raff publishes a 99.9% platform SLA. - **DigitalOcean-native integrations reduce work.** DOKS connects naturally to VPCs, Container Registry, Volumes, Load Balancers, Managed Databases, API, `doctl`, and Terraform. - **A larger public review history matters.** DigitalOcean's Trustpilot profile currently contains versus Raff's 16. - **Your pooled transfer allowance is sufficient.** DOKS overage starts only after eligible account-level allowances are exhausted. ## When you should choose Raff over DigitalOcean Kubernetes Choose Raff Kubernetes when: - **Published worker price matters.** Raff is $17.99/month at 2 vCPU / 4 GB versus $24/month for the DOKS Basic shape. - **HA cost matters.** Raff's three-master HA add-on is $30/month versus $40/month for DOKS HA control plane. - **Public egress should stay at $0.** DOKS charges $0.01/GiB after pooled allowances. - **Cluster storage cost matters.** Raff cluster storage is $0.10/GB-month, effectively level with $0.10/GiB-month for DigitalOcean Volumes. - **The workload fits `us-east`.** DigitalOcean's broader region map adds little if one eastern-U.S. region already satisfies the architecture. - **A smaller product surface is preferable.** Raff combines Kubernetes with VMs, managed databases, object storage, Apps, Functions, and private networking without requiring the team to choose among as many compute families. - **Built-in cluster monitoring fits the operating model.** Raff packages monitoring into its managed Kubernetes workflow. Raff currently reports **3,000+ customers and 15,000+ production VMs**. For the broader decision, read [Kubernetes vs Docker Compose for Small Teams](/learn/guides/kubernetes-vs-docker-compose-small-teams) and [Kubernetes Cost Optimization](/learn/guides/kubernetes-cost-optimization-startups). ## Migrating from DigitalOcean Kubernetes to Raff 1. **Inventory the DOKS cluster.** Record Kubernetes version, node pools, autoscaling limits, namespaces, Helm releases, CRDs, ingress controllers, DigitalOcean Load Balancers, Volumes, storage classes, registry integrations, secrets, policies, DNS, and external allowlists. 2. **Create the Raff target cluster.** Select the control-plane model, worker sizes, node counts, autoscaling ranges, cluster storage, private networking, and monitoring configuration. 3. **Replace provider-specific integrations.** Convert DigitalOcean storage classes, load-balancer annotations, registry credentials, VPC assumptions, and CSI/CCM dependencies to the Raff equivalents. **Gotcha:** provider-specific Kubernetes annotations can survive YAML exports and fail silently on the target platform. 4. **Move persistent data.** Use database-native exports, application replication, backup tools, or verified copy workflows for persistent volumes. **Gotcha:** Kubernetes manifests recreate resource definitions; they do not contain the application data stored inside volumes or external databases. 5. **Deploy and verify workloads.** Apply CRDs and operators first, then namespaces, configuration, workloads, services, ingress, policies, storage, and observability. Test readiness, autoscaling, jobs, restore procedures, and failure behavior on the target cluster. 6. **Cut over with rollback.** Lower DNS TTL to **300 seconds**, perform the final state synchronization, update DNS and allowlists, monitor production, and keep DOKS available until the rollback window closes. Stateless manifests and Helm releases are usually the easiest part of a DOKS-to-Raff move. Persistent volumes, DigitalOcean-specific annotations, registry authentication, external IP allowlists, autoscaler assumptions, and version-dependent CRDs create most of the migration risk. ## About DigitalOcean Kubernetes [DigitalOcean Kubernetes](https://www.digitalocean.com/products/kubernetes) is the managed Kubernetes service from **DigitalOcean Holdings, Inc.**, a publicly traded cloud company headquartered in New York. DOKS provides a managed control plane, node pools, autoscaling, persistent-volume integration, regional deployment, and connections to DigitalOcean networking, registry, database, API, CLI, and Terraform workflows. ## Conclusion: DigitalOcean Kubernetes or Raff? The DigitalOcean-Kubernetes-versus-Raff decision resolves across four measured axes: cluster cost, infrastructure breadth, reliability commitments, and transfer/storage economics. - **Cluster cost:** two 2 vCPU / 4 GB workers plus HA total **$65.98/month on Raff** versus **$88/month on DOKS** before storage and surrounding services. - **Infrastructure breadth:** DigitalOcean offers broader regions, dedicated CPU classes, GPU nodes, and a larger native cloud catalog; Raff deliberately exposes a smaller Kubernetes footprint in `us-east`. - **Reliability:** DOKS has a **99.95% HA control-plane SLA**; Raff publishes a **99.9% platform SLA** and offers three-master HA for $30/month. - **Transfer and storage:** Raff public Kubernetes egress is **$0** and cluster storage is **$0.10/GB-month**; DOKS uses pooled transfer with $0.01/GiB overage and DigitalOcean Volumes at $0.10/GiB-month. Choose DigitalOcean Kubernetes when geographic reach, specialized compute, DigitalOcean-native integrations, or the 99.95% HA control-plane SLA are hard requirements. Choose Raff when `us-east` is sufficient and lower published worker/HA/storage prices plus $0 public egress make the cluster easier to budget. Raff currently reports **3,000+ customers, 15,000+ production VMs, Trustpilot 4.5/5, G2 4.6/5, and a 99.9% platform SLA**. Continue with [Kubernetes vs Docker Compose for Small Teams](/learn/guides/kubernetes-vs-docker-compose-small-teams), [Kubernetes Cost Optimization](/learn/guides/kubernetes-cost-optimization-startups), and [K3s vs Kubernetes](/learn/guides/k3s-vs-full-kubernetes-cluster-model). --- ### Linode Kubernetes Engine Alternative 2026: Pricing, Features & Operations URL: https://rafftechnologies.com/learn/compare/linode-kubernetes-alternative Description: Considering Linode Kubernetes? Raff's 2 vCPU/4 GB worker is $17.99/mo, with $30 HA and $0 public egress in us-east. Raff wins on lower comparable worker pricing, a $30 HA control-plane add-on, $0 public egress, and private VPC networking on its standard managed Kubernetes service. Linode Kubernetes Engine wins on broader regional availability, dedicated and high-memory worker choices, GPU support, mature Akamai Cloud tooling, and an Enterprise tier with a dedicated HA control plane. Choose LKE when geographic reach, specialized workers, or LKE Enterprise scale are requirements; choose Raff when `us-east` fits and predictable worker, HA, storage, and transfer costs matter more. Three 2 vCPU / 4 GB workers plus HA cost $83.97/month on Raff versus at least $132/month on standard LKE in North America before storage, NodeBalancers, and other attached services. Linode Kubernetes Engine and Raff both remove routine control-plane administration while leaving workload architecture, resource requests, policies, application availability, persistent data, and recovery with the customer. Standard LKE and Raff both advertise a $0 base control plane, but the production cost floor differs once worker nodes and HA are included: Akamai's current North America LKE table lists three Shared 4 GB workers at $72/month and its HA add-on starts at $60/month, while Raff prices three 2 vCPU / 4 GB workers at $53.97/month and three-master HA at $30/month. LKE offers a wider infrastructure and geographic surface; Raff focuses on `us-east`, lower published worker and storage prices, private-by-default cluster networking, and $0 public egress. ## Linode Kubernetes Engine vs Raff: which is right for you? Linode Kubernetes Engine is the stronger choice when your cluster needs Akamai's broader core-region footprint, dedicated CPU or GPU node options, or the Enterprise tier's dedicated HA control plane and higher cluster limits. Raff is the stronger fit when the workload belongs in `us-east` and you want a smaller managed Kubernetes cost surface with lower published worker, HA, storage, and transfer costs. | Decision factor | Choose Raff | Choose Linode Kubernetes Engine | |---|---|---| | 2 vCPU / 4 GB worker | $17.99/month | $24/month Shared CPU | | Three 2 vCPU / 4 GB workers | $53.97/month | $72/month | | HA control plane | $30/month | Starts at $60/month, region-dependent | | Standard private cluster network | Each cluster gets a private VPC | Standard LKE lists VPC-isolated networking as unavailable; Enterprise includes it | | Public egress | $0, unmetered up to 3 Gbps | Worker plans include transfer; Akamai lists overage pricing | | Persistent storage | $0.10/GB-month | Block Storage $0.10/GB-month | | Geography | `us-east` fits | You need LKE across Akamai core compute regions | | Specialized workers | Raff worker tiers are sufficient | Dedicated CPU, High Memory, or GPU nodes are required | | Enterprise Kubernetes | Standard managed Kubernetes is enough | LKE Enterprise's dedicated HA plane and higher limits are required | A practical comparison rule from Raff's infrastructure work is to separate the **free-control-plane headline** from the **production floor**. Worker nodes, HA, persistent storage, public traffic, load balancing, and surrounding services determine what a real cluster costs; the $0 control plane by itself does not. This comparison uses published service capabilities and prices. It does not treat equal vCPU and RAM counts as proof of equal compute performance because the providers do not publish an identical CPU-scheduling and hardware taxonomy for these Kubernetes worker tiers. ## Linode Kubernetes Engine overview [Linode Kubernetes Engine](https://techdocs.akamai.com/cloud-computing/docs/linode-kubernetes-engine), or LKE, is Akamai Cloud's managed Kubernetes service. Akamai manages the control plane while customers configure node pools, workloads, policies, application availability, storage, and recovery. Akamai currently offers two Kubernetes tiers: - **LKE** is the standard service. Its fully managed control plane uses shared resources and is provided at no additional charge. It is **not highly available by default**; HA is an optional paid add-on. - **LKE Enterprise** uses a dedicated HA control plane and adds enterprise-oriented networking, scaling, security, and load-balancing capabilities. It is available to approved customers in limited regions and costs **$300/month per cluster**, plus worker nodes and other consumed resources. Standard LKE supports up to **250 worker nodes and 1,000 Pods**. LKE Enterprise raises those published limits to **500 nodes and 5,000 Pods**, uses Cilium instead of standard LKE's Calico CNI, provides VPC-isolated pod networking, and can use Premium NodeBalancers. Both tiers support node-pool autoscaling, node-pool data encryption, automated Kubernetes version updates, GPU workers, and Akamai App Platform. For worker capacity, LKE can use Shared CPU, Dedicated CPU, and High Memory Linode plans, with GPU support also documented. This is one of LKE's clearest advantages over a smaller Kubernetes worker catalog: teams can choose among more compute classes when CPU isolation, memory density, or accelerators are architectural requirements. Akamai also exposes mature operational tooling around LKE through Cloud Manager, the Linode CLI, API access, and Terraform. That tooling matters for teams already standardized on Akamai Cloud automation. ## Raff overview [Raff Kubernetes](/products/kubernetes) is a managed Kubernetes service with a **$0 standard control plane**, optional three-master HA, node-pool autoscaling, multiple worker pools, built-in monitoring and logs, a managed public endpoint, and private-by-default cluster networking. Current Raff worker tiers are: | Worker | vCPU | RAM | Monthly price | |---|---:|---:|---:| | K8s Starter | 1 | 2 GB | $9.99 | | K8s Standard | 2 | 4 GB | $17.99 | | K8s Performance | 4 | 8 GB | $33.99 | | K8s High Memory | 8 | 16 GB | $71.99 | | K8s Large | 8 | 32 GB | $119.99 | | K8s Scale | 16 | 64 GB | $229.99 | The standard control plane remains **$0 at every listed worker size**. The HA option promotes the control plane to three masters with etcd quorum for **$30/month**. Dedicated cluster storage is **$0.10/GB-month**, and the current product page lists public bandwidth as truly unmetered at up to **3 Gbps with $0 egress fees**. Every Raff cluster gets a private VPC and a managed public endpoint for traffic that should be exposed. That differs from standard LKE's current feature table, which lists VPC-isolated networking as an Enterprise-only capability. Teams should still design Kubernetes NetworkPolicies, service exposure, ingress, secrets, and application-level controls deliberately; a private network is a foundation, not a complete security policy. Raff currently reports **15,000+ VMs** on its platform and publishes a **99.9% uptime SLA**. The product trade-off is straightforward: Raff exposes a narrower public-region and worker-class footprint than Akamai, but makes the standard small-team cluster model easier to price in `us-east`. ## Linode Kubernetes Engine pricing vs Raff pricing The cleanest LKE-to-Raff comparison starts with the standard managed control plane and worker floor, then adds HA and storage. Akamai's current North America pricing page lists the standard LKE control plane at no additional cost and three **Shared 4 GB** nodes at **$72/month total**. That Shared 4 GB plan corresponds to **2 vCPUs, 4 GB RAM, 80 GB storage, and 4 TB transfer per node**. The optional LKE HA control plane starts at **$60/month per cluster, depending on region**. Raff prices its K8s Standard worker at **$17.99/month for 2 vCPU / 4 GB**, so three workers total **$53.97/month**. Raff HA is **$30/month**. | Buying position | Raff Kubernetes | Linode Kubernetes Engine | Difference | |---|---:|---:|---:| | One 2 vCPU / 4 GB worker | $17.99/month | $24/month Shared CPU | Raff is $10.01 lower | | Three 2 vCPU / 4 GB workers | $53.97/month | $72/month | Raff is $30.03 lower | | HA control plane | $30/month | Starts at $60/month | Raff is at least $30 lower | | Three workers + HA | $83.97/month | At least $132/month | Raff is at least $60.03 lower | | Persistent storage | $0.10/GB-month | $0.10/GB-month | Raff is $0.02/GB-month lower | | LKE Enterprise control plane | No separate enterprise tier | $300/month plus resources | LKE adds a dedicated enterprise tier | **Comparison class:** these rows compare published resource shapes and prices, not measured application performance. Shared CPU scheduling, underlying hardware, CNI behavior, storage paths, Kubernetes versions, and cluster configuration can affect real workload results. The LKE Enterprise price is not directly comparable to Raff's $30 HA add-on because Enterprise includes a different control-plane and networking model. Its **$300/month** fee buys dedicated HA control-plane resources and enterprise capabilities rather than simply replicating the standard shared control plane. For small and midsize production clusters, the more useful comparison is standard LKE plus HA versus Raff plus HA. On that basis, three 2 vCPU / 4 GB workers produce a published monthly floor of **$83.97 on Raff** versus **at least $132 on LKE** before attached storage, load balancing, databases, or other services. ### Persistent storage cost Akamai Block Storage is currently **$0.10/GB-month** in North America: 100 GB costs $10/month. Raff Kubernetes storage is **$0.10/GB-month**, so 100 GB costs $10/month. Neither storage price is a backup policy. Persistent volumes survive Pod replacement, but databases and application state still need a backup schedule, consistency model, retention policy, and tested restore procedure. :::cta cluster Deploy a Raff Kubernetes cluster with a $0 standard control plane; add three-master HA for $30/month when your availability model requires it. ::: ## Bandwidth and transfer policy Raff Kubernetes currently includes truly unmetered public bandwidth at up to **3 Gbps** and prices public egress at **$0**. Same-platform cluster-to-storage traffic is also not metered. Akamai's Shared CPU plans include a transfer allowance with each worker. The current North America Shared 4 GB plan includes **4 TB of transfer per node**, and Akamai's regional pricing page lists outbound transfer overage at **$0.005/GB**. The exact invoice can depend on the account's eligible transfer pool and the mix of attached services, so a production estimate should be built from the actual node and service configuration rather than a single-node allowance alone. For a three-node Shared 4 GB LKE cluster, the pricing table lists **12 TB aggregate transfer** across those workers. That is a substantial included allowance and may be entirely sufficient for many workloads. Raff's advantage is not that LKE always produces a bandwidth bill; it is that Raff removes the public-egress variable from the Kubernetes bill altogether. This matters most for workloads with large or unpredictable outbound traffic: APIs with bursty responses, downloads, package distribution, media delivery, build artifacts, and data-heavy customer exports. For low-egress internal applications, the difference may be operationally irrelevant. ## Feature comparison: Linode Kubernetes Engine vs Raff | Feature | Raff Kubernetes | Linode Kubernetes Engine | |---|---|---| | Standard managed control plane | $0 | $0 | | HA control plane | Three masters, $30/month | Optional, starts at $60/month | | 2 vCPU / 4 GB worker | $17.99/month | $24/month Shared CPU | | Node-pool autoscaling | Yes | Yes | | Multiple node pools | Yes | Yes | | Dedicated CPU worker class | No separately published Kubernetes class | Yes | | GPU workers | No published Kubernetes GPU tier | Yes | | Standard private/VPC-isolated cluster model | Private VPC included | Standard LKE feature table: No; Enterprise: Yes | | Standard CNI | Standard Kubernetes networking managed by Raff | Calico | | Enterprise CNI | No separate enterprise tier | Cilium on LKE Enterprise | | Public region model | `us-east` | Most Akamai core compute regions | | Public egress | $0 | Included transfer, then applicable overage | | Persistent storage | $0.10/GB-month | Block Storage $0.10/GB-month | | Built-in monitoring/logs | Yes | Control-plane monitoring plus ecosystem tooling | | API / CLI / Terraform | Raff API, CLI, Terraform workflows | Cloud Manager, Linode CLI, API, Terraform | | Enterprise Kubernetes tier | No separate tier | LKE Enterprise, $300/month plus resources | | Published standard cluster scale | Size through Raff worker/node-pool model | Up to 250 nodes / 1,000 Pods | | Published enterprise scale | No separate enterprise limit | Up to 500 nodes / 5,000 Pods | LKE's strongest advantages are infrastructure breadth, geography, specialized compute, GPU support, and an Enterprise tier designed for larger deployments. Raff's strongest advantages are the lower published worker and HA examples above, lower storage unit price, private cluster networking in the standard service, and $0 public egress. The platforms also differ in how much product surface they ask a small team to choose from. Akamai offers more infrastructure classes and enterprise variants. Raff deliberately offers fewer Kubernetes worker tiers and one public region. Neither model is universally better: breadth is valuable when you need it, while a smaller decision surface can be useful when you do not. ## Features and reliability: Raff vs Linode Kubernetes Engine This comparison includes **0 controlled Raff-versus-Linode Kubernetes Engine workload benchmarks**, so it does not declare either service faster. A useful performance test would need matched Kubernetes versions, node counts, CPU classes, Pod requests, CNI configuration, storage paths, regions, images, traffic patterns, and repeated runs. ### Control-plane availability Standard LKE uses shared control-plane resources and is **not HA by default**. Akamai's HA add-on replicates etcd and the API server from one to three replicas and replicates other control-plane components, with the feature starting at $60/month. Akamai documents a **99.9% uptime guarantee for the control plane and worker-node API service** when HA is enabled. LKE Enterprise makes the control plane dedicated and highly available by default. That is a genuine advantage for teams that need a larger managed-Kubernetes operating envelope, and it is not the same product position as standard LKE. Raff's optional HA model also uses three masters with etcd quorum and costs $30/month. Raff publishes a **99.9% uptime SLA** for the Kubernetes service. In both cases, control-plane HA does not make an application automatically highly available: replicas, worker headroom, Pod disruption behavior, ingress, persistent data, and external dependencies still determine whether the workload survives failures. ### Allocatable worker capacity Akamai changed LKE resource allocation for clusters created on or after **April 21, 2026** by reserving some node CPU and memory for system daemons. Akamai notes that tightly packed workloads may need additional node capacity as a result. This is a useful reminder for both providers: size Kubernetes against **allocatable** worker capacity and failure headroom, not only the vCPU and RAM printed on the plan card. For Raff, use [Kubernetes Cluster Sizing](/learn/guides/kubernetes-cluster-sizing) to model allocatable worker capacity and [Kubernetes Node Pools](/learn/guides/kubernetes-node-pools) when workloads need distinct compute or scaling boundaries. ### Stateful recovery Both platforms separate managed control-plane operations from application data protection. Akamai continuously backs up control-plane metadata for recovery, but that does not replace customer backups for databases, PersistentVolumes, object data, manifests, and application state. Raff follows the same workload-responsibility principle: cluster availability and application recovery are related but separate concerns. ## When you should choose Linode Kubernetes Engine over Raff Choose Linode Kubernetes Engine when: - **Broader geographic placement is required.** Standard LKE is available across most Akamai core compute regions, while Raff currently exposes one public `us-east` region. - **Dedicated CPU workers matter.** LKE can use Dedicated CPU plans in addition to Shared CPU and High Memory workers. - **GPU workers are required.** Akamai documents GPU support for both LKE and LKE Enterprise; Raff does not currently publish a Kubernetes GPU worker tier. - **You need a larger published cluster envelope.** Standard LKE publishes limits of 250 nodes and 1,000 Pods, while Enterprise raises those to 500 nodes and 5,000 Pods. - **A dedicated enterprise control plane is required.** LKE Enterprise provides a dedicated HA control plane, Cilium, VPC-isolated pod networking, and enterprise load-balancing options. - **Your team already uses Akamai Cloud automation.** Cloud Manager, Linode CLI, API, Terraform, NodeBalancers, Block Storage, and App Platform can reduce integration work inside an existing Akamai estate. - **Included transfer covers your workload.** Three Shared 4 GB LKE workers list 12 TB of aggregate transfer, which can be enough for many applications without overage. These are substantive advantages. A team should not choose Raff simply because its comparable published worker price is lower if region placement, GPU capacity, dedicated CPU, or LKE Enterprise capabilities are hard requirements. ## When you should choose Raff over Linode Kubernetes Engine Choose Raff Kubernetes when: - **Published worker cost is a primary constraint.** The 2 vCPU / 4 GB Raff worker is $17.99/month versus $24/month for LKE's Shared 4 GB worker in North America. - **Production HA should stay inexpensive.** Raff three-master HA is $30/month; standard LKE HA starts at $60/month depending on region. - **You want $0 public egress.** Raff removes outbound-transfer overage from the Kubernetes bill instead of relying on a finite included allowance. - **Persistent storage unit cost matters.** Raff storage is $0.10/GB-month, level with Akamai Block Storage at $0.10/GB-month in North America. - **Private networking should be part of the standard cluster model.** Raff places every cluster in a private VPC; Akamai's current comparison table reserves VPC-isolated networking for LKE Enterprise. - **The workload belongs in `us-east`.** Akamai's region breadth provides no practical benefit when one eastern-U.S. region already satisfies latency, residency, and resilience requirements. - **A smaller operational surface is preferable.** Raff's worker catalog and cluster workflow are narrower than Akamai's, which can make sizing and cost review simpler for ordinary small-team workloads. Raff currently reports **15,000+ VMs** and publishes a **99.9% uptime SLA**. For operating-model context before changing providers, read [Managed Kubernetes vs Self-Managed Kubernetes](/learn/guides/managed-vs-self-managed-kubernetes). ## Migrating from Linode Kubernetes Engine to Raff A Kubernetes migration is portable at the API level, but provider integrations and persistent data still require explicit work. Treat the move as an application and infrastructure migration rather than a `kubectl get -o yaml` exercise. 1. **Inventory the LKE cluster.** Record Kubernetes version, LKE tier, node pools, autoscaling ranges, namespaces, Helm releases, CRDs, NetworkPolicies, ingress, NodeBalancers, Block Storage claims, storage classes, secrets, DNS, external allowlists, CI/CD credentials, and backup workflows. 2. **Create the Raff target cluster.** Select the control-plane mode, worker sizes, node counts, autoscaling ranges, private VPC, persistent storage, public endpoint, and monitoring configuration. 3. **Replace provider-specific integrations.** Review Linode Cloud Controller Manager behavior, NodeBalancer annotations, Block Storage CSI classes, Akamai-specific load-balancer settings, and any App Platform assumptions. **Gotcha:** provider-specific annotations can survive an export and either fail or behave differently on the destination. 4. **Move persistent data separately.** Kubernetes manifests recreate resource definitions; they do not contain the data inside Block Storage volumes or external databases. Use database-native replication/export, application-aware backups, or a verified copy workflow appropriate to the state. 5. **Deploy and verify workloads.** Apply CRDs and operators before dependent resources, then verify Pods, Services, ingress, NetworkPolicies, PVCs, jobs, autoscaling, logs, readiness, and restore procedures. **Gotcha:** standard LKE uses Calico while LKE Enterprise uses Cilium, so policy and networking behavior deserve explicit validation. 6. **Cut over with a written rollback path.** Lower DNS TTL to **300 seconds** before the window, synchronize final state, update DNS and allowlists, monitor production, and keep the LKE environment recoverable until the rollback window closes. For workloads moving from Docker Compose into Kubernetes at the same time, do not combine both transitions blindly. Use the [Docker Compose to Managed Kubernetes Migration Checklist](/learn/guides/docker-compose-to-managed-kubernetes-migration) first so state, probes, configuration, traffic ownership, and rollback are explicit before provider migration adds another variable. ## About Linode Kubernetes Engine [Linode Kubernetes Engine](https://www.akamai.com/products/kubernetes) is the managed Kubernetes product within Akamai Cloud. Akamai acquired Linode in 2022 and continues to use the LKE product name across its current Kubernetes documentation and pricing. The standard LKE service provides a managed shared control plane at no additional charge, worker-node pools using eligible Linode compute plans, autoscaling, Kubernetes version management, Block Storage integration, NodeBalancer integration, and access through Cloud Manager, CLI, API, and Terraform workflows. LKE Enterprise is a distinct paid tier for approved customers. It adds a dedicated HA control plane, higher published node and Pod limits, VPC-isolated networking, Cilium, Premium NodeBalancer support, and more upgrade control. Current published pricing is **$300/month per Enterprise cluster plus consumed resources**. That product breadth is important when evaluating a Linode Kubernetes alternative: Raff competes most directly with **standard LKE for small and midsize managed clusters**, not with every capability in the Enterprise tier. ## Conclusion: Linode Kubernetes Engine or Raff? The Linode-Kubernetes-versus-Raff decision comes down to four practical axes: worker and HA cost, geographic and compute breadth, networking/transfer economics, and the scale of the Kubernetes operating model. - **Cluster cost:** three 2 vCPU / 4 GB workers plus HA total **$83.97/month on Raff** versus **at least $132/month on standard LKE in North America** before storage and attached services. - **Infrastructure breadth:** LKE offers broader regions, Dedicated CPU, High Memory, GPU support, and an Enterprise tier; Raff exposes a smaller worker catalog in `us-east`. - **Networking and transfer:** Raff includes a private VPC in the standard cluster model and $0 public egress; standard LKE uses included worker transfer and reserves VPC-isolated networking for Enterprise in its current feature table. - **Storage:** Raff cluster storage is **$0.10/GB-month**, level with Akamai Block Storage in North America. Choose LKE when geographic reach, specialized compute, Akamai-native integrations, or the Enterprise tier solve a requirement you can name. Choose Raff when `us-east` is sufficient and lower published worker, HA, storage, and transfer costs make the production floor easier to forecast. Continue with [Managed Kubernetes vs Self-Managed Kubernetes](/learn/guides/managed-vs-self-managed-kubernetes), [Kubernetes Cluster Sizing](/learn/guides/kubernetes-cluster-sizing), and [Kubernetes Node Pools](/learn/guides/kubernetes-node-pools). --- ### Vultr Kubernetes Engine Alternative 2026: Pricing, Features & Operations URL: https://rafftechnologies.com/learn/compare/vultr-kubernetes-alternative Description: Compare Vultr Kubernetes Engine and Raff on VKE pricing, $0 control planes, workers, storage, bandwidth, regions, networking, and operations. Raff is the stronger Vultr Kubernetes alternative when your workloads fit `us-east` and you want a known $17.99/month 2 vCPU / 4 GB worker price, $0 public egress, and a $30/month three-master HA option. Vultr Kubernetes Engine is stronger when broader geographic placement, a wider virtual-compute catalog, Cloud GPU workers, Vultr-native Load Balancers, or lower-cost HDD Block Storage are requirements. Both providers currently publish a $0 standard managed control plane, so the real decision is not the headline Kubernetes fee; it is the cost and operating model around workers, networking, storage, load balancing, and failure headroom. Choose Vultr when its regional and compute breadth solve requirements you can name; choose Raff when a smaller `us-east` footprint with unmetered 3 Gbps bandwidth and zero egress charges produces the simpler production bill. Vultr Kubernetes Engine (VKE) and Raff both remove routine control-plane administration while keeping workload design, resource requests, application availability, data protection, and recovery with the customer. Vultr's current VKE pricing documentation says the fully managed control plane is provided at no additional cost and charges only for provisioned resources such as worker nodes, Load Balancers, and Block Storage. Raff follows the same $0-standard-control-plane model but publishes its Kubernetes worker, HA, storage, and transfer prices directly on the Kubernetes product page. The providers diverge most clearly on geography and infrastructure breadth: Vultr operates a much larger global cloud footprint and supports multiple virtual compute families, including Cloud GPU, while Raff currently concentrates managed Kubernetes in one public `us-east` region. ## Vultr Kubernetes Engine vs Raff: which is right for you? Vultr Kubernetes Engine is the stronger choice if you need to place clusters nearer users outside Raff's public region, mix node pools across a broader compute catalog, run GPU-accelerated Kubernetes workloads, or use Vultr's native Load Balancer, Block Storage, DNS, API, CLI, and Terraform ecosystem. Raff is the stronger choice when `us-east` is acceptable and you want published worker pricing plus a cluster bill with $0 egress and a known $30 HA add-on. | Decision factor | Choose Raff | Choose Vultr Kubernetes Engine | |---|---|---| | Standard control plane | $0 | $0 | | 2 vCPU / 4 GB worker | $17.99/month | Uses Vultr regional Cloud Compute pricing for `vc2-2c-4gb` | | HA control plane | Three masters for $30/month | Optional HA; current VKE pricing docs do not publish a separate HA surcharge | | Public egress | $0, unmetered up to 3 Gbps | Plan bandwidth allowance, then $0.01/GB overage | | Private networking | Private VPC for every cluster | Existing VPC or automatically provisioned same-region VPC | | Persistent storage | $0.10/GB-month | HDD $0.025/GB-month; NVMe $0.10/GB-month | | Managed load balancing | Managed public endpoint included | Vultr Load Balancer starts at $10/month | | Geography | `us-east` | Much broader Vultr global cloud footprint | | Specialized compute | Smaller Kubernetes worker catalog | Cloud Compute, Optimized/High Frequency classes, Cloud GPU, VX virtual compute | A practical Raff comparison rule is to price the **production path**, not the Kubernetes control-plane headline. Workers, failure headroom, public traffic, load balancing, storage class, and backups explain more of a real cluster bill than whether the control plane itself is advertised as free. This article therefore avoids a misleading matched-worker dollar claim where Vultr's current price cannot be verified directly. Vultr's official VKE and provisioning docs identify `vc2-2c-4gb` as a 2 vCPU / 4 GB Cloud Compute plan and direct buyers to Vultr's live regional pricing for the current hourly or monthly rate. That live pricing page was not reliably retrievable during this review, so the comparison keeps the Vultr worker price dynamic rather than copying an older number. ## Vultr Kubernetes Engine overview [Vultr Kubernetes Engine](https://www.vultr.com/kubernetes/), or VKE, is Vultr's fully managed Kubernetes service. Vultr manages the Kubernetes control plane and reconciles worker-node pools while customers choose cluster versions, node-pool capacity, autoscaling policy, networking, storage, workload configuration, and application recovery. The current VKE pricing model is straightforward at the top level: the **managed control plane costs $0**, and customers pay for the cloud resources attached to the cluster. Vultr's April 2026 pricing documentation names worker nodes, Vultr Load Balancers, and Block Storage as the billable resource categories. VKE integrates with Vultr's Cloud Controller Manager and Container Storage Interface. Those integrations let Kubernetes request Vultr networking, managed Load Balancers, and persistent Block Storage without the operator building every cloud integration manually. The current VKE release line supports Kubernetes 1.36.x, and Vultr's June 2026 changelog records worker-node images on Ubuntu 24.04 LTS. VKE also supports multiple node pools and both manual and automatic node-pool scaling. For networking, a new cluster can attach to an existing same-region VPC; if none is selected, VKE provisions a new VPC in the region by default. Teams that want private-only worker placement can use VPC-focused deployment options rather than exposing every node directly to the public internet. Vultr's compute breadth is a genuine advantage. Current VKE documentation supports virtual worker instances across Cloud Compute classes and Cloud GPU, and Vultr provides preconfigured VKE applications for AMD and NVIDIA GPU tooling. VKE does **not** currently support Vultr Bare Metal servers as worker nodes, so GPU and specialized-compute advantages should be understood as virtual-compute options rather than unrestricted access to every Vultr infrastructure product. Vultr's broader platform also includes Load Balancers, Block Storage, DNS, registries and automation through the Vultr API, CLI, and Terraform provider. For teams already operating on Vultr, that existing provider surface can matter as much as the Kubernetes control plane itself. ## Raff overview [Raff Kubernetes](/products/kubernetes) is a managed Kubernetes service with a free standard control plane, optional three-master HA, node-pool autoscaling, multiple worker pools, built-in monitoring and logs, private-by-default networking, and a managed public endpoint. Current Raff Kubernetes worker tiers are: | Worker | vCPU | RAM | Monthly price | |---|---:|---:|---:| | K8s Starter | 1 | 2 GB | $9.99 | | K8s Standard | 2 | 4 GB | $17.99 | | K8s Performance | 4 | 8 GB | $33.99 | | K8s High Memory | 8 | 16 GB | $71.99 | | K8s Large | 8 | 32 GB | $119.99 | | K8s Scale | 16 | 64 GB | $229.99 | The standard control plane remains **$0 at every listed size**. Optional high availability promotes the control plane to three masters with etcd quorum for **$30/month**. Kubernetes storage is **$0.10/GB-month**, and public cluster bandwidth is truly unmetered at up to **3 Gbps with $0 egress fees**. Every Raff cluster gets its own VPC and a managed public endpoint. Nodes stay on the private network while intended public traffic enters through the managed edge. This is conceptually similar to VKE's ability to use or automatically provision a same-region VPC, although the products package and expose the workflow differently. Raff deliberately has a smaller public-region and worker-class catalog than Vultr. That is a limitation when geography, GPU capacity, or a particular Vultr compute family is required. The trade-off is a narrower decision surface with exact published Kubernetes worker prices, one public region to reason about, and transfer costs that do not change with public egress volume. Raff currently reports **15,000+ VMs** on its platform and publishes a **99.9% uptime SLA** for managed Kubernetes. Those signals do not replace architecture review: application availability still depends on replica count, worker capacity, disruption behavior, ingress, storage, and external dependencies. ## Vultr Kubernetes Engine pricing vs Raff pricing Both Raff and VKE currently publish a **$0 standard control plane**, so the most useful comparison starts with the surrounding resources. Vultr's VKE cost documentation says workers are billed according to the selected Vultr compute plan's current hourly or monthly rate. Current provisioning examples use the `vc2-2c-4gb` Cloud Compute plan for **2 vCPUs and 4 GB RAM**, but Vultr directs customers to its live regional pricing page for the exact current price. Because that price was not reliably retrievable in this review, this article does not turn an older cached rate into a 2026 claim. Raff's K8s Standard plan is explicitly published at **$17.99/month for 2 vCPU / 4 GB**. | Cost component | Raff Kubernetes | Vultr Kubernetes Engine | |---|---:|---:| | Standard managed control plane | $0 | $0 | | 2 vCPU / 4 GB worker | $17.99/month | Live regional rate for `vc2-2c-4gb` | | HA control plane | $30/month | Optional; no separate current surcharge published in VKE pricing docs | | Managed public traffic entry | Included managed endpoint | Vultr Load Balancer starts at $10/month if used | | 100 GB persistent storage — lower-cost tier | $8/month | $2.50/month HDD Block | | 100 GB persistent storage — performance tier | $8/month | $10/month NVMe Block | | Public egress overage | $0 | $0.01/GB after plan allowance | This table exposes an important point that a single “storage price” would hide. Vultr's **HDD Block Storage at $25/TB-month ($0.025/GB-month)** is cheaper per GB than Raff's Kubernetes storage, while Vultr's **NVMe Block Storage at $100/TB-month ($0.10/GB-month)** matches Raff's $0.10/GB-month storage. The correct choice depends on the workload's latency, IOPS, throughput, and durability requirements rather than the lowest unit price alone. ### High-availability pricing is documented differently Raff publishes a clear **$30/month** price for its three-master HA control plane. Vultr documents VKE high availability as an optional cluster setting available through the console, API, CLI, and Terraform. Its current VKE pricing page continues to state that the fully managed control plane is available at no additional cost and lists worker nodes, Load Balancers, and Block Storage as chargeable resources. Because the pricing documentation does not expose a separate VKE HA line item, this article does not invent one. If a Vultr quote or console estimate shows an HA-specific charge for your region or account, use that live value instead of this article's generic pricing model. ### Load-balancer pricing can change the ingress model Vultr Load Balancers currently start at **$10/month per instance**. They are bandwidth-neutral themselves: traffic is accounted against attached backend instances, and outbound usage above the applicable compute-plan allowance is billed at the standard overage rate. Raff includes a managed public endpoint and automatic TLS with the cluster. That does not make every application ingress design identical to a Vultr Load Balancer, but it means teams should include ingress/LB resources when comparing actual deployment architectures rather than comparing only node counts. :::cta cluster Compare your production Kubernetes floor on Raff with a $0 standard control plane, published worker pricing, and $0 public egress. ::: ## Bandwidth and transfer policy Raff Kubernetes prices public egress at **$0** and includes truly unmetered bandwidth at up to **3 Gbps**. Same-platform traffic between a Raff cluster and Raff storage is also not metered. Vultr uses a quota model for compute-instance bandwidth. Each instance plan includes a monthly allowance, and outbound traffic above the account's applicable allocation is billed at **$0.01/GB**. Vultr Load Balancers do not add a second bandwidth charge; backend-instance egress remains the relevant meter. Vultr also documents a free account-level bandwidth allocation, but the amount available to a particular production estate depends on current plan and account rules. For that reason, a VKE cost model should use the actual node plan and account allocation shown in the Vultr console rather than assuming a generic transfer allowance from an older price table. This distinction matters differently by workload. A private internal API with little outbound traffic may never approach Vultr's allowance, making the bandwidth difference financially irrelevant. A public API, package distribution service, media workload, software update system, or customer-export pipeline can make predictable egress economics more valuable. The comparison should therefore be phrased precisely: **Raff removes the public-egress variable; Vultr includes bandwidth and charges $0.01/GB when applicable allowance is exceeded.** That is not the same as saying every VKE workload pays egress fees. ## Feature comparison: Vultr Kubernetes Engine vs Raff | Feature | Raff Kubernetes | Vultr Kubernetes Engine | |---|---|---| | Standard control plane | $0 | $0 | | Optional control-plane HA | Three masters, $30/month | Yes | | Multiple node pools | Yes | Yes | | Node-pool autoscaling | Yes | Yes | | Standard private networking | Per-cluster VPC | Existing or auto-created same-region VPC | | VPC-only/private worker options | Private-by-default Raff model | Supported VPC-focused deployment options | | Public endpoint / LB | Managed endpoint included | Vultr Load Balancer integration | | Managed LB entry price | Included endpoint | Starts at $10/month | | Persistent storage | $0.10/GB-month | HDD $0.025/GB-month; NVMe $0.10/GB-month | | Public egress | $0 | Included allowance, then $0.01/GB overage | | Public region model | `us-east` | Broader Vultr global cloud footprint | | GPU Kubernetes workers | No published GPU worker tier | Cloud GPU supported | | Bare Metal workers | No published Kubernetes Bare Metal tier | Not supported by current VKE | | Kubernetes version management | Managed control plane and cluster workflow | VKE upgrade workflow; worker upgrades require operator action in current docs | | Cloud integrations | Raff storage, VPC, apps, managed data services | Vultr LB, Block Storage, DNS, CCM/CSI integrations | | API / CLI / Terraform | Raff platform automation | Vultr API, CLI, Terraform | | Ingress controller included | One-click networking apps available | No preconfigured ingress controller | | Built-in monitoring/logs | Included in Raff dashboard | Vultr platform monitoring plus Kubernetes ecosystem tooling | Vultr wins on geographic breadth, virtual compute variety, GPU-capable Kubernetes infrastructure, a mature provider automation surface, and its lower-cost HDD storage tier. Raff wins on exact published Kubernetes worker pricing, $0 public egress, the $30 published HA option, included managed public endpoint, and a single-region operating model that can be simpler when `us-east` already satisfies the application. VKE's automatic VPC creation is also a meaningful operational strength. A team moving to VKE does not need to start with publicly exposed worker nodes simply because it has not pre-created a network. Raff similarly makes private networking the default, so this is closer to feature parity than a decisive difference. ## Features and reliability: Raff vs Vultr Kubernetes Engine This comparison includes **0 controlled Raff-versus-VKE workload benchmarks**, so it does not declare either platform faster. A defensible Kubernetes benchmark would need matched worker CPU classes, Kubernetes versions, node counts, Pod requests, storage class, CNI behavior, region, container image, traffic profile, and repeated test runs. ### VKE manages platform state but operators still own workload state Vultr's current documentation describes VKE as managing the control plane and worker-node lifecycle. If a worker is deleted outside the VKE dashboard, the platform detects the missing node and provisions a replacement to restore the desired node-pool size. That is useful infrastructure reconciliation, but replacement does not preserve application state that lived only on an ephemeral node disk. Raff follows the same managed-Kubernetes boundary. Control-plane operations and worker reconciliation reduce platform toil; they do not replace PersistentVolumes, database backups, object-storage durability, application replication, or tested restores. ### Upgrade workflows still require planning Vultr documents managed control-plane upgrades and states that worker nodes must be upgraded by the customer, individually or in batches, to align with the selected Kubernetes version. Its current VKE release line supports Kubernetes 1.36.x and uses Ubuntu 24.04 LTS worker images. That is not necessarily a disadvantage: explicit worker upgrade control can be valuable when teams want to choose disruption windows. It does mean that “managed Kubernetes” should not be interpreted as “no upgrade planning.” PodDisruptionBudgets, replica headroom, maintenance windows, and version-dependent operators remain customer concerns on either provider. ### Storage choices trade cost for performance Vultr gives VKE users two Block Storage performance tiers. HDD Block is the lower-cost capacity option; NVMe Block targets much higher IOPS and throughput. That choice is a real Vultr advantage for teams that want a cheaper bulk-capacity tier beside performance storage. Raff publishes one Kubernetes storage rate at $0.10/GB-month, reducing the number of storage billing choices. A simpler catalog can make cost review easier, but it does not beat Vultr HDD on raw dollars per GB. ## When you should choose Vultr Kubernetes Engine over Raff Choose Vultr Kubernetes Engine when: - **You need broader geographic placement.** Vultr operates a much larger global cloud footprint than Raff's current single public `us-east` region, although specific VKE/plan availability should still be checked before deployment. - **GPU workers are required.** Current VKE documentation supports Cloud GPU virtual instances and GPU-oriented applications; Raff does not publish a Kubernetes GPU worker tier. - **You need more virtual compute classes.** VKE can use several Vultr virtual compute families rather than a single small Kubernetes-specific catalog. - **Low-cost capacity storage matters.** Vultr HDD Block Storage is $25/TB-month, or about $0.025/GB-month, below Raff's $0.10/GB-month Kubernetes storage rate. - **Vultr-native networking and storage already exist in your estate.** VPC, Load Balancers, Block Storage, DNS, CCM, and CSI integrations can reduce migration work for teams already standardized on Vultr. - **API, CLI, and Terraform maturity are important.** Vultr exposes VKE provisioning and HA controls through all three automation paths. - **You want explicit VPC attachment or automatic same-region VPC creation.** VKE can attach an existing same-region VPC or provision one automatically when you do not select one. These are genuine reasons to stay on or select VKE. A lower Raff worker price or zero-egress model does not compensate for a missing region or GPU requirement when those are architectural constraints. ## When you should choose Raff over Vultr Kubernetes Engine Choose Raff Kubernetes when: - **You want an exact published Kubernetes worker price.** Raff lists 2 vCPU / 4 GB at $17.99/month directly on the Kubernetes page instead of requiring a separate regional compute-price lookup. - **Public egress should remain $0.** Raff removes outbound transfer overage from the cluster bill; Vultr charges $0.01/GB when applicable allowance is exceeded. - **You want a published HA add-on price.** Raff's three-master HA option is $30/month. Vultr supports HA, but its current VKE pricing documentation does not expose a separate HA surcharge. - **An included public endpoint fits the ingress model.** Raff includes a managed public endpoint and TLS; Vultr Load Balancers start at $10/month when used. - **The workload belongs in `us-east`.** Vultr's global footprint adds little value if one eastern-U.S. region already satisfies latency, residency, and resilience requirements. - **You prefer fewer infrastructure choices.** Raff's smaller worker and region catalog can make routine cluster sizing and cost review easier for small teams that do not need GPU or specialized compute. - **The storage workload fits Raff's single $0.10/GB-month tier.** That rate matches Vultr NVMe Block's $0.10/GB-month, although Vultr HDD remains cheaper for capacity-first storage. For the broader operating-model decision, read [Managed Kubernetes vs Self-Managed Kubernetes](/learn/guides/managed-vs-self-managed-kubernetes) before comparing provider line items in isolation. ## Migrating from Vultr Kubernetes Engine to Raff Moving from VKE to Raff is mainly a Kubernetes workload migration plus a provider-integration migration. Standard manifests and Helm charts are portable; Vultr-specific networking, storage, load-balancer behavior, registry credentials, and persistent data need deliberate replacement. 1. **Inventory the VKE cluster.** Record Kubernetes version, node pools, autoscaling ranges, Cloud Compute classes, GPU pools, namespaces, Helm releases, CRDs, NetworkPolicies, ingress controllers, Vultr Load Balancers, Block Storage claims, storage classes, VPC configuration, DNS, secrets, and backup jobs. 2. **Create the Raff target cluster.** Choose standard or HA control plane, worker plans, node counts, autoscaling bounds, private VPC, storage capacity, public endpoint, and monitoring requirements. 3. **Replace Vultr-specific integrations.** Review Vultr CCM behavior, Vultr CSI storage classes, Load Balancer annotations, VPC assumptions, GPU operators, and DNS automation. **Gotcha:** provider-specific annotations often remain in exported YAML even when the new provider ignores them. 4. **Move persistent data separately.** Kubernetes object definitions do not contain the data inside Vultr Block Storage or external databases. Use database-native replication/export, application-aware backup tools, or a verified data-copy process. 5. **Recreate ingress intentionally.** VKE does not ship with a preconfigured ingress controller, so document whether the source cluster uses NGINX, Traefik, Gateway API, direct LoadBalancer Services, or another controller before mapping public traffic to the Raff endpoint and in-cluster networking. 6. **Verify workload behavior.** Test readiness and liveness probes, autoscaling, PVC binding, DNS, NetworkPolicies, jobs, logs, external integrations, and restore procedures before any production traffic moves. 7. **Cut over with rollback.** Lower DNS TTL to **300 seconds** before the migration window, synchronize final state, update DNS and allowlists, monitor production, and keep VKE recoverable until the rollback window closes. If the application is also moving from Docker Compose into Kubernetes, separate those two changes where practical. The [Docker Compose to Managed Kubernetes Migration Checklist](/learn/guides/docker-compose-to-managed-kubernetes-migration) defines the state, health-check, configuration, cutover, and rollback gates before a provider move adds another variable. ## About Vultr Kubernetes Engine [Vultr Kubernetes Engine](https://docs.vultr.com/products/compute/kubernetes) is Vultr's managed Kubernetes product. It combines a managed control plane with worker-node pools on supported Vultr virtual compute, Vultr Cloud Controller Manager, Vultr CSI, VPC networking, autoscaling, Load Balancer integration, Block Storage, and provider automation. Vultr currently operates **33 global cloud data center regions** across its broader infrastructure footprint. VKE availability and the exact compute families available to a cluster can vary by region, so teams should verify the target location and plan before treating the full Vultr region map as guaranteed VKE coverage. The standard VKE control plane is published at **$0**. Workers use the selected Vultr compute plan and bill at its current regional hourly or monthly rate. Vultr Load Balancers start at **$10/month**, outbound bandwidth overage is **$0.01/GB** after applicable allowance, and Block Storage is available in HDD and NVMe tiers. VKE also supports optional high availability, multiple node pools, autoscaling, API/CLI/Terraform provisioning, and Cloud GPU workers. It does not currently support Vultr Bare Metal servers as VKE worker nodes. ## Conclusion: Vultr Kubernetes Engine or Raff? The Vultr-Kubernetes-versus-Raff decision is strongest when it is reduced to four concrete axes: geography and compute choice, known recurring cluster costs, transfer economics, and storage/ingress design. - **Geography and compute:** Vultr wins with a much broader global footprint and more virtual compute choices, including Cloud GPU. Raff currently operates managed Kubernetes in `us-east` with a smaller worker catalog. - **Published cluster costs:** both standard control planes are $0. Raff publishes 2 vCPU / 4 GB workers at $17.99/month and HA at $30/month; Vultr bills workers at current regional compute rates and does not expose a separate HA surcharge in its current VKE pricing documentation. - **Transfer:** Raff public Kubernetes egress is $0 with unmetered bandwidth up to 3 Gbps. Vultr includes plan bandwidth and charges $0.01/GB when applicable allowance is exceeded. - **Storage and ingress:** Vultr HDD Block is cheaper per GB than Raff storage, while Vultr NVMe Block is more expensive per GB; Vultr Load Balancers start at $10/month, while Raff includes a managed public endpoint. Choose VKE when its regions, compute classes, GPU support, lower-cost HDD tier, or Vultr-native integrations solve a real requirement. Choose Raff when `us-east` fits and published worker/HA pricing plus $0 egress make the production Kubernetes floor easier to forecast. Continue with [Kubernetes Cluster Sizing](/learn/guides/kubernetes-cluster-sizing), [Kubernetes Node Pools](/learn/guides/kubernetes-node-pools), and [Managed Kubernetes vs Self-Managed Kubernetes](/learn/guides/managed-vs-self-managed-kubernetes). --- ### Neon Alternative 2026: Pricing, Performance & Features URL: https://rafftechnologies.com/learn/compare/neon-alternative Description: Considering Neon? Raff is a Neon alternative from $7.99/mo for 1 vCPU, 1 GB RAM and 25 GB, with fixed pricing and managed backups. Neon and Raff solve the same managed PostgreSQL problem with different operating models. Neon treats the database as elastic developer infrastructure: Launch bills active compute at $0.106 per CU-hour, can scale to zero after 5 idle minutes, and paid plans include 500 GB of public transfer each month. Raff instead offers provisioned plans, with the first paid PostgreSQL tier at $7.99/month for 1 vCPU, 1 GB RAM, and 25 GB NVMe. Neon fits branching, previews, and intermittent demand; Raff fits continuously active production databases where published capacity and predictable plan pricing matter. ## Neon vs Raff: which is right for you? Neon and Raff both provide managed PostgreSQL, but the buyer is choosing between serverless elasticity and provisioned capacity. | Decision factor | Choose Raff | Choose Neon | |---|---|---| | Production cost model | You want a published monthly plan with listed vCPU, RAM, and storage | You want compute and storage billed by actual usage | | Development workflow | Conventional dev, staging, and production databases are enough | You need copy-on-write branches for pull requests, previews, or tests | | Idle databases | The database is expected to stay available continuously | Scale-to-zero after 5 idle minutes can materially reduce compute usage | | PostgreSQL versions | PostgreSQL 14–16 covers the application | You need PostgreSQL 17 or 18 | | Availability model | You want an optional HA add-on priced at +70% | You want Neon's Scale/Business compute-endpoint SLA and serverless architecture | | Geography | `us-east` fits the application and data-placement requirement | You need a choice across multiple AWS and Azure regions | | Billing detail | Fewer usage meters are preferable | CU-hours, database storage, history, branches, and transfer are acceptable | Choose Neon when database environments are frequently created, cloned, suspended, and discarded. Choose Raff when the database is a steady production dependency and the team wants capacity, recovery, and cost decisions to be explicit before deployment. For the broader operating-model decision, read [PostgreSQL for SaaS Apps](/learn/guides/postgresql-for-saas-apps) and [Managed vs Self-Hosted Databases](/learn/guides/managed-vs-self-hosted-databases). ## Neon overview Neon is a serverless PostgreSQL service built around separated compute and storage. Projects can contain branches, compute endpoints, databases, roles, and read replicas while remaining compatible with PostgreSQL clients and drivers. Its defining workflow is database branching. A child branch can be created without immediately copying the full parent database, which makes branches useful for pull-request previews, migration tests, CI jobs, developer sandboxes, and other short-lived environments. Neon also supports autoscaling and scale-to-zero. Free and Launch computes suspend after 5 minutes of inactivity by default; paid plans can keep a compute always active. Current public pricing positions include: - **Free — $0:** 100 projects, 100 CU-hours per project each month, 0.5 GB storage per project, compute up to 2 CU, and up to 6 hours of restore history. - **Launch — usage-based:** $0.106 per CU-hour, $0.35 per GB-month of database storage, up to 16 CU, and up to 7 days of restore history. - **Scale — usage-based:** $0.222 per CU-hour, $0.35 per GB-month, up to 56 CU, up to 30 days of restore history, private networking, IP allow rules, and an SLA for covered compute endpoints. Paid plans include 500 GB of public transfer each month from June 1, 2026. Neon also charges $0.002 per branch-hour above included allowances and $0.20 per GB-month for restore-history data on paid plans. Neon supports PostgreSQL 14, 15, 16, 17, and 18. Its February 2026 version update listed 14.21, 15.16, 16.12, 17.8, and 18.2. Neon became a Databricks company in May 2025. ## Raff overview [Raff Managed PostgreSQL](/products/managed-databases/postgresql) uses provisioned database plans with published vCPU, RAM, and NVMe allocations. Raff currently supports PostgreSQL 14, 15, and 16 with managed backups, point-in-time recovery for supported production workflows, monitoring, built-in connection pooling, private connectivity, storage expansion, and optional high availability. Raff has both a permanent free tier and paid plans: - **Free — $0/month:** 1 vCPU, 1 GB RAM, 2 GB storage, up to 60 direct connections and 200 pooled connections. - **Paid entry — $7.99/month:** 1 vCPU, 1 GB RAM, and 25 GB NVMe. - **Production — $45.99/month:** 2 vCPU, 4 GB RAM, and 80 GB NVMe. - **Scale — $146.99/month:** 8 vCPU, 16 GB RAM, and 180 GB NVMe. Additional managed-database storage is $0.15/GB-month. PostgreSQL high availability adds 70% to the selected plan price, and a PostgreSQL read replica is $29.99/month. A recurring Raff operations rule is to size PostgreSQL in this order: **workload → recovery target → connection model → ownership model → capacity**. That keeps a larger plan from becoming the default answer to connection storms, poor queries, or an undefined recovery target. Raff supports 3,000+ customers and 15,000+ production VMs and publishes a 99.9% uptime SLA. On August 16, 2026, Raff's Trustpilot profile showed 4.5/5; G2 is 4.6/5. ## Neon pricing vs Raff pricing The pricing models are different enough that a forced "same-size plan" would be misleading. Raff sells provisioned tiers; Neon bills active compute in CU-hours plus database storage and other usage dimensions. The table therefore compares buying positions rather than claiming equal performance. | Buying position | Raff Managed PostgreSQL | Neon | What it means | |---|---|---|---| | Free development | $0 — 1 vCPU / 1 GB / 2 GB; 60 direct / 200 pooled connections | $0 — 100 CU-hours/project, 0.5 GB/project, up to 2 CU | Both have permanent free tiers with different ceilings | | Entry paid | $7.99/month — 1 vCPU / 1 GB / 25 GB | Launch — $0.106/CU-hour + $0.35/GB-month | Raff fixes the base monthly plan; Neon follows active usage | | Always-active example | $7.99/month within the paid entry allocation | 0.25 CU for 730 h + 5 GB storage ≈ $21.10/month | Neon example is usage math, not a matched resource tier | | Production position | $45.99/month — 2 vCPU / 4 GB / 80 GB | Launch formula; 1 CU for 730 h + 25 GB storage ≈ $86.13/month | The architectures are not equivalent; test the real workload | | HA / SLA position | Production +70% HA = $78.18/month | Scale — $0.222/CU-hour + $0.35/GB-month; 99.95% compute-endpoint SLA threshold | Different availability models; compare RTO/RPO, not labels | The Neon arithmetic uses 730 hours only to show how continuous runtime changes usage-based cost. A database that sleeps for long periods can cost much less on Neon because suspended compute stops consuming CU-hours. A fair production estimate should include active compute time, database size, restore-history retention, branches, read replicas, public or private transfer, and availability requirements. Raff's paid plan price already includes the listed compute and storage allocation; extra storage, HA, and replicas are explicit modifiers. :::cta Deploy a Database Now Deploy managed PostgreSQL with published plans, backups, pooling, private connectivity, and optional high availability. ::: ## Bandwidth and transfer policy Neon changed its paid-plan public transfer allowance on June 1, 2026. Launch and Scale now include **500 GB of public transfer per month**, up from 100 GB. Transfer above the included amount remains $0.10/GB. The Free plan includes 5 GB of public transfer. Scale private-network transfer is priced separately at $0.01/GB in both directions. That makes Neon's external-data-transfer model straightforward to calculate: | Public transfer in a paid month | Neon transfer charge above allowance | |---:|---:| | 100 GB | $0 | | 500 GB | $0 | | 1 TB | About $52.40 | | 5 TB | About $471.60 | The examples use 1 TB = 1,024 GB and apply $0.10/GB only above the 500 GB included allowance. Raff private networking is free and private traffic inside Raff's VPC is unmetered. For managed-database traffic that leaves the Raff network over a public path, teams should verify the current product billing for that route instead of assuming the VM-specific 3 Gbps unmetered policy applies to databases. The architectural preference is the same on both platforms: keep application and database traffic private and geographically close where practical. Neon offers broader AWS/Azure placement; Raff is simpler when the application and database both fit `us-east`. ## Feature comparison: Neon vs Raff | Feature | Raff Managed PostgreSQL | Neon | |---|---|---| | Database model | Provisioned managed PostgreSQL | Serverless PostgreSQL with separated compute and storage | | Supported PostgreSQL majors | 14–16 | 14–18 | | Free tier | $0, 1 vCPU / 1 GB / 2 GB | $0, 100 CU-hours/project and 0.5 GB/project | | Paid entry | $7.99/month | Launch at $0.106/CU-hour + $0.35/GB-month | | Scale to zero | No | Yes; 5 minutes by default on Free and Launch | | Autoscaling | Plan resize | Automatic compute scaling within configured bounds | | Database branching | Conventional separate environments | Copy-on-write branches | | Connection pooling | Built in | Pooled and direct endpoints | | High availability | Optional +70% | SLA-backed compute endpoints on Scale/Business; different architecture | | Restore model | Managed backups and PITR on supported production workflows | 6 hours, 7 days, or 30 days by plan | | Private networking | Raff private connectivity | Private networking on Scale | | Read replicas | $29.99/month PostgreSQL read replica | Read replicas supported | | Public region model | `us-east` | Multiple AWS and Azure regions | | Support model | Direct Raff support | Community, billing, and plan-based support | Neon wins on branching, scale-to-zero, newer PostgreSQL major versions, and geographic choice. Raff wins on published provisioned tiers, a simple HA price formula, and fewer compute/storage usage meters for always-on production databases. ## Features and reliability: Raff vs Neon ### Engine and version coverage Raff Managed PostgreSQL currently supports PostgreSQL 14, 15, and 16. Neon supports PostgreSQL 14 through 18 and published current minor versions 14.21, 15.16, 16.12, 17.8, and 18.2 in February 2026. Neon therefore has the version-coverage advantage for applications that already require PostgreSQL 17 or 18. A Neon database on PostgreSQL 17 or 18 must resolve version compatibility before migration to Raff rather than assuming an in-place downgrade is possible. ### High availability topology Raff offers an optional PostgreSQL high-availability configuration priced at **+70% of the base plan**, using a synchronous standby and automatic failover model. The Production tier therefore moves from $45.99 to $78.18/month with HA. Neon does not expose a directly equivalent "+70% standby" toggle in its public pricing. Instead, the Scale/Business SLA applies to covered compute endpoints and uses a **99.95% monthly uptime threshold** for service-credit eligibility. These models should be compared through recovery time, recovery point, failover behavior, and application requirements rather than by feature name alone. ### Backup model Raff includes managed backups and supports point-in-time recovery for supported production workflows. The team still owns recovery-point selection and application validation after a restore. Neon provides time-travel and restore history by plan: up to 6 hours on Free, 7 days on Launch, and 30 days on Scale. Paid restore-history data is billed at $0.20/GB-month based on the volume of data changes during the selected window. ### Connection and networking Raff provides built-in pooling, TLS, allowlist controls, and private connectivity for Raff-hosted workloads. Private VPC traffic is unmetered. Neon provides pooled and direct connection endpoints, supports PgBouncer-based pooling, and offers private networking and IP allow rules on Scale. Paid plans include 500 GB/month of public transfer; Scale private transfer is metered separately. ### Upgrade and maintenance behavior Raff handles host-level and database-service maintenance for supported managed PostgreSQL versions, while the application team remains responsible for schema migrations, query compatibility, extensions, and release validation. Neon validates PostgreSQL minor releases and applies a new minor version the next time a compute restarts. Neon also uses scheduled update notices for PostgreSQL updates, security patches, and service changes. Teams should test extensions and application behavior before major-version changes on either platform. ### Reliability track record Raff publishes a 99.9% uptime SLA and supports 3,000+ customers and 15,000+ production VMs. Its Trustpilot profile was 4.5/5 on August 16, 2026. Neon's current SLA applies to Business/Scale compute endpoints and uses a 99.95% monthly uptime threshold; it explicitly does not cover every Neon API or platform component. Neon is a Databricks company, and its current site reports millions of Postgres databases started daily. Trustpilot shows an unclaimed `neon.com` profile at 3.2/5, which is too small a sample to treat as a broad product-satisfaction measure. ## When you should choose Neon over Raff - **Database branching** — Neon creates copy-on-write branches for pull requests, previews, CI jobs, and developer sandboxes. - **Intermittent databases** — Free and Launch computes can suspend after 5 idle minutes, reducing billed CU-hours when the database is inactive. - **Newer PostgreSQL majors** — Neon supports PostgreSQL 14–18, while Raff currently supports 14–16. - **Broader placement** — Neon publishes regional status endpoints for at least 11 AWS and Azure regions; Raff exposes 1 public region, `us-east`. - **Scale-plan SLA** — Neon Scale/Business compute endpoints use a 99.95% monthly uptime threshold for service credits. - **Elastic resource use** — Launch and Scale meter compute by CU-hour instead of requiring a continuously provisioned fixed tier. ## When you should choose Raff over Neon - **Fixed paid entry** — Raff's first paid PostgreSQL plan is $7.99/month for 1 vCPU, 1 GB RAM, and 25 GB NVMe. - **Explicit HA pricing** — PostgreSQL HA adds 70% to the selected Raff plan; the $45.99 Production tier becomes $78.18/month. - **Provisioned capacity** — Raff keeps the selected plan available rather than relying on a scale-to-zero wake-up path. - **Simple database budgeting** — published vCPU, RAM, and storage tiers reduce the number of compute and storage usage meters to forecast. - **Raff-hosted application paths** — private VPC traffic is unmetered when the application and database communicate inside Raff. - **Verified platform signals** — Raff supports 3,000+ customers and 15,000+ production VMs and was 4.5/5 on August 16, 2026. ## Migrating from Neon to Raff 1. **Inventory the Neon project.** Record PostgreSQL major version, extensions, branch hierarchy, roles, databases, pooled/direct endpoints, read replicas, restore window, IP rules, and private-network dependencies. 2. **Confirm Raff compatibility.** Select the Raff PostgreSQL tier, confirm every required extension, and resolve any PostgreSQL 17/18 source before migration because Raff currently supports 14–16. 3. **Transfer the database.** Use `pg_dump`/`pg_restore` for smaller databases or logical replication for an active production database where the source configuration permits it. 4. **Recreate access and networking.** Rotate credentials, replace Neon endpoint URLs, rebuild allowlists/private connections, and update application secrets, monitoring, and scheduled jobs. 5. **Verify before cutover.** Compare row counts, sequences, indexes, extensions, query plans, pooled connections, application writes, backups, restore expectations, and latency from the target application path. 6. **Cut over with rollback retained.** Bring replication lag to zero where used, coordinate final writes, switch the application connection string, verify production traffic, and keep Neon available until the rollback window closes. Operational gotchas: - Neon branches do not map one-for-one to Raff environments; choose which branch is the production source of truth before copying data. - A PostgreSQL 17 or 18 Neon source cannot be treated as a routine downgrade to Raff PostgreSQL 14–16; resolve version compatibility first. - Neon autoscaling and scale-to-zero assumptions must be replaced with a Raff plan sized for normal and peak demand. - Extension names can match while supported versions or configuration differ; test each required extension before cutover. For a stateful production database, plan a short write-coordination window even when logical replication is used. Short-lived preview branches are usually better recreated as development/test environments than migrated individually. ## About Neon [Neon](https://neon.com/) is operated by Neon, LLC, a Databricks affiliate headquartered in San Francisco and founded in 2021. Neon provides serverless PostgreSQL with separated compute and storage, branching, autoscaling, scale-to-zero, read replicas, and developer automation. Neon joined Databricks in May 2025 while continuing to operate the Neon PostgreSQL service. ## Conclusion: Neon or Raff? The comparison resolves across four decision axes: - **Pricing model** — Raff publishes a $7.99/month paid entry tier; Neon Launch meters compute at $0.106/CU-hour plus $0.35/GB-month. - **Developer workflow** — Neon leads on copy-on-write branches, autoscaling, and 5-minute scale-to-zero; Raff uses conventional provisioned database environments. - **Availability and placement** — Raff offers a +70% HA option in `us-east`; Neon offers a 99.95% Scale/Business compute-endpoint SLA threshold across multiple AWS/Azure regions. - **Operational fit** — Raff favors explicit capacity and predictable modifiers; Neon favors elastic usage and programmable database environments. Choose Neon when branching, scale-to-zero, PostgreSQL 17/18, or multi-region developer workflows are required. Choose Raff when an always-on managed PostgreSQL service needs published capacity, a fixed HA formula, private Raff connectivity, and direct support. Raff supports 3,000+ customers and 15,000+ production VMs and was verified at 4.5/5 on August 16, 2026. --- ### Supabase Alternative 2026: Pricing, Performance & Features URL: https://rafftechnologies.com/learn/compare/supabase-alternative Description: Considering Supabase? Raff offers $0 PostgreSQL with 1 vCPU, 1 GB RAM and 2 GB storage; paid plans add fixed resources and optional HA. Raff wins on published PostgreSQL resources, explicit high-availability pricing, private Raff connectivity, and a database-first operating model. Supabase wins on integrated Auth, Storage, Realtime, generated APIs, Edge Functions, branching, and a much broader region footprint. Choose Supabase if those backend-as-a-service features replace application engineering; choose Raff if PostgreSQL operations, portability, and predictable capacity are the primary decision. Both offer permanent $0 tiers: Raff includes 1 vCPU, 1 GB RAM, and 2 GB database storage, while Supabase Free includes a 500 MB database and up to 2 active projects. After free, Raff Managed PostgreSQL starts at $7.99/month for 1 vCPU, 1 GB RAM, and 25 GB NVMe. Supabase Pro starts at $25/month and includes $10 in compute credits, enough for one Micro instance with 1 GB RAM and a 2-core ARM CPU. Supabase can also bill for database disk, egress, file storage, monthly active users, Realtime, Edge Functions, branches, and point-in-time recovery. Raff uses provisioned database tiers plus explicit storage, HA, and replica modifiers. ## Supabase vs Raff: which is right for you? Supabase and Raff overlap at managed PostgreSQL, but they solve different scopes. Supabase is a PostgreSQL-centered backend platform. Raff Managed PostgreSQL is a focused database service that sits alongside Raff application, compute, storage, and networking products. At Raff, our decision rule comes before the price table: **are you replacing a database service, or are you replacing an application backend?** If Auth, Storage, Realtime, generated APIs, and functions are requirements, Supabase is the broader product. If those concerns already have an owner, compare PostgreSQL operations directly. | Decision factor | Choose Raff | Choose Supabase | |---|---|---| | Primary need | Managed PostgreSQL with explicit capacity | Integrated backend platform around PostgreSQL | | Free database | 1 vCPU / 1 GB / 2 GB | 500 MB database, shared CPU, 500 MB RAM | | Paid entry | $7.99/month for 1 vCPU / 1 GB / 25 GB | Pro from $25/month with $10 compute credits | | Authentication | Use application or selected provider | Integrated Supabase Auth | | Realtime | Application-defined | Integrated Realtime service | | File storage | Separate Raff Object Storage product | Integrated Supabase Storage | | Functions | Raff Apps / Raff Functions as separate products | Integrated Edge Functions | | PostgreSQL version | 14–16 | Hosted platform currently defaults to PostgreSQL 17 | | Region choice | `us-east` | 17 specific AWS regions plus general-region selection | | HA model | Optional synchronous standby at +70% | Platform/read-replica model; no equivalent fixed +70% standby toggle | Supabase is the stronger choice when its integrated services remove meaningful application work. Raff is the stronger choice when the team wants PostgreSQL to remain a portable, separately operated infrastructure component. For the broader ownership model, read [Managed vs Self-Hosted Databases](/learn/guides/managed-vs-self-hosted-databases) and [PostgreSQL for SaaS Apps](/learn/guides/postgresql-for-saas-apps). ## Supabase overview [Supabase](https://supabase.com/) combines a dedicated PostgreSQL database with application-facing backend services. Every project includes database APIs, Auth, Storage, Realtime, Edge Functions, client tooling, and observability capabilities, with limits and feature access determined by plan. Its current public pricing starts with: - **Free — $0/month:** up to 2 active projects, 500 MB database size per project, shared CPU, 500 MB RAM, 50,000 monthly active users, 1 GB file storage, 5 GB egress, 5 GB cached egress, and community support. Free projects can pause after one week of inactivity. - **Pro — from $25/month:** 100,000 MAU, 8 GB database disk per project, 250 GB uncached egress, 250 GB cached egress, 100 GB file storage, email support, and daily backups retained for 7 days. - **Team — from $599/month:** adds collaboration, access-control, compliance, support, and 14-day backup-retention features. - **Enterprise — custom:** adds negotiated infrastructure, support, security, and uptime commitments. Paid plans include $10/month in compute credits. Supabase's current pricing page lists Micro compute at $10/month with 1 GB RAM, a 2-core ARM CPU, 60 recommended direct connections, and 200 pooler connections, so the credit covers one Micro project for a full billing month. Supabase's product advantage is integration. Auth can connect application identity to database Row Level Security; Storage and Realtime share the platform; generated APIs reduce boilerplate; Edge Functions provide a server-side runtime; and Pro branching can create isolated preview environments. A preview branch has no separate flat fee but incurs its own usage, with default Micro branch compute starting at $0.01344/hour. Supabase's hosted platform currently defaults to PostgreSQL 17. That is a version-coverage advantage over Raff for applications that specifically require PostgreSQL 17 today. ## Raff overview [Raff Managed PostgreSQL](/products/managed-databases/postgresql) provides managed PostgreSQL with published vCPU, RAM, and NVMe allocations, managed backups, point-in-time recovery for supported production workflows, monitoring, built-in connection pooling, private connectivity, storage expansion, and optional high availability. Raff's permanent PostgreSQL free tier includes 1 vCPU, 1 GB RAM, 2 GB storage, 60 direct connections, and 200 pooled connections. Current paid reference tiers include: | Raff PostgreSQL tier | Monthly price | Resources | |---|---:|---| | Entry | $7.99 | 1 vCPU / 1 GB / 25 GB | | Small production | $45.99 | 2 vCPU / 4 GB / 80 GB | | Scale | $146.99 | 8 vCPU / 16 GB / 180 GB | Raff Managed PostgreSQL starts at $7.99/month for 1 vCPU, 1 GB RAM, and 25 GB NVMe. Additional managed-database storage is $0.15/GB-month. PostgreSQL high availability adds 70% to the selected plan, and a PostgreSQL read replica is $29.99/month. Raff currently supports PostgreSQL 14, 15, and 16. The database service does not bundle Supabase-equivalent Auth, Realtime, generated client APIs, or file storage into the PostgreSQL product. Teams can combine Managed PostgreSQL with Raff Apps, Raff Functions, Object Storage, VPC networking, or their own application services without making those layers part of the database contract. Raff supports 3,000+ customers and 15,000+ production VMs under a published 99.9% platform SLA. On August 16, 2026, Raff's Trustpilot profile displayed 4.5/5; G2 is 4.6/5. ## Supabase pricing vs Raff pricing The two pricing models should not be treated as matched performance tiers. Supabase Pro is an organization-level backend plan with project compute and usage meters, while Raff prices provisioned managed PostgreSQL capacity directly. | Buying position | Raff Managed PostgreSQL | Supabase | Practical difference | |---|---|---|---| | Free development | $0 — 1 vCPU / 1 GB / 2 GB | $0 — 500 MB DB/project, shared CPU, 500 MB RAM, up to 2 active projects | Both have permanent free tiers; Supabase bundles more backend services | | Entry paid | $7.99 — 1 vCPU / 1 GB / 25 GB | Pro $25 — includes $10 compute credit covering one Micro | Raff is database-first; Supabase includes BaaS allowances | | Small production | $45.99 — 2 vCPU / 4 GB / 80 GB | Pro + Small compute totals $30 for one project after the $10 credit | Not a performance match; model workload and BaaS usage separately | | HA / recovery position | $78.18 — $45.99 tier with +70% HA | PITR starts about $100/month for 7 days and requires at least Small compute | Raff HA and Supabase PITR solve different risks | | Higher capacity | $146.99 — 8 vCPU / 16 GB / 180 GB | Compute scales separately up to larger paid instances | Compare actual workload, connections, disk, and service usage | **Comparison class:** these are buying positions, not matched benchmark tiers. Supabase Pro bundles backend services; Raff prices managed PostgreSQL capacity and explicit operational modifiers. A single Supabase Pro project on Small compute is illustrated in Supabase's billing documentation as $25 plan + $15 compute - $10 credit = **$30/month** before additional usage. A Micro project remains covered by the $10 compute credit, leaving the base Pro subscription at $25 when usage stays within included allowances. ### Automated backups and recovery cost Supabase automatically backs up Pro, Team, and Enterprise projects daily. Pro retains 7 days, Team 14 days, and Enterprise up to 30 days. Point-in-time recovery is a separate add-on: about $100/month for 7 days, $200 for 14 days, or $400 for 28 days, and the project must use at least Small compute. Raff includes managed backups and supports PITR for supported production PostgreSQL workflows. Optional HA is priced separately at +70% because failover availability and historical recovery are different controls. ### Usage and add-on costs Supabase Pro includes 8 GB of database disk per project and then charges $0.125/GB for general-purpose disk capacity. It also meters categories such as egress, file storage, MAU, Realtime messages and connections, Edge Function invocations, branching, and selected add-ons. Raff paid plans include their listed database storage allocation. Extra managed-database storage is $0.15/GB-month, PostgreSQL HA is +70%, and a PostgreSQL read replica is $29.99/month. :::cta Deploy a Database Now Deploy managed PostgreSQL with published resources, backups, pooling, private connectivity, and optional high availability. ::: ## Bandwidth and transfer policy Supabase Pro currently includes **250 GB of uncached egress** and **250 GB of cached egress**. Usage above those separate allowances is $0.09/GB uncached and $0.03/GB cached. Cached egress applies to Storage CDN traffic; database, Auth, Realtime, Functions, Supavisor, and other traffic can contribute to uncached egress. Using 1 TB = 1,024 GB and applying overage only after the 250 GB allowance, the transfer math is: | Monthly traffic in one egress category | Supabase uncached overage | Supabase cached overage | |---:|---:|---:| | 1 TB | $69.66 | $23.22 | | 5 TB | $438.30 | $146.10 | | 10 TB | $899.10 | $299.70 | | 50 TB | $4,585.50 | $1,528.50 | These figures model each quota independently; a real Supabase bill depends on how traffic is split between cached and uncached categories. Raff private VPC traffic is unmetered. For managed-database traffic that leaves Raff over a public path, verify the current billing for that route rather than assuming the VM-specific public bandwidth policy applies to databases. Supabase has an advantage when Storage CDN delivery and application services are deliberately integrated into the same billing model. Raff has an advantage when application-to-database traffic stays private inside Raff and the team wants database networking separated from public content delivery. ## Feature comparison: Supabase vs Raff | Feature | Raff Managed PostgreSQL | Supabase | |---|---|---| | Core product | Managed relational database service | PostgreSQL backend-as-a-service | | Permanent free tier | 1 vCPU / 1 GB / 2 GB | 500 MB DB/project, shared CPU, 500 MB RAM, 2 active projects | | Paid entry | $7.99/month | Pro from $25/month | | Current PostgreSQL versions | 14–16 | Hosted platform defaults to PostgreSQL 17 | | Connection pooling | Built in | Direct and pooled connection endpoints | | Authentication | Application / selected provider | Integrated Supabase Auth | | Generated APIs | Application-defined | Integrated database APIs | | Realtime | Application-defined | Integrated Realtime | | File storage | Separate Raff Object Storage | Integrated Supabase Storage | | Functions | Separate Raff Functions / Apps | Integrated Edge Functions | | Branching | Separate database environments | Preview branches on paid plans | | Backups | Managed | Daily on Pro/Team/Enterprise | | PITR | Supported production workflows | Paid add-on from about $100/month | | Traditional HA | Optional synchronous standby +70% | No directly equivalent fixed-price synchronous-standby toggle | | Region model | 1 public region: `us-east` | 17 specific AWS regions plus general regions | Supabase wins on application-backend integration, PostgreSQL 17, preview environments, and geographic choice. Raff wins on provisioned resource visibility, explicit HA pricing, a focused database operating model, and portability across separately selected application services. ## Features and reliability: Raff vs Supabase This is a non-VM comparison, so the useful evidence is feature and operating-model reliability rather than synthetic performance claims. Raff and Supabase have **0 controlled head-to-head database benchmarks** in this comparison, and neither is declared faster. ### Engine and version coverage Raff Managed PostgreSQL currently supports PostgreSQL 14–16. Supabase states that PostgreSQL 17 is now the default on its hosted platform and has also moved its current self-hosted default to PostgreSQL 17. Supabase therefore wins when PostgreSQL 17 is a hard requirement. A migration from Supabase PostgreSQL 17 to Raff must resolve version compatibility before data movement; it is not a routine downgrade. ### High availability and replicas Raff offers an optional synchronous standby and automatic failover model priced at +70% of the selected PostgreSQL plan. This exposes availability cost before deployment. Supabase offers read replicas and platform-managed project infrastructure, but its public pricing does not expose a directly equivalent fixed-price synchronous-standby toggle. Supabase's pricing page places formal uptime SLAs at Enterprise, while Team includes support SLAs. Read replicas should not be treated as backups or as an exact equivalent to Raff's synchronous HA topology. ### Backups and point-in-time recovery Raff includes managed backups and supports point-in-time recovery for supported production workflows. The application team still owns recovery-point selection and validation after restore. Supabase Pro includes 7 days of daily backups, Team 14 days, and Enterprise up to 30 days. PITR is available to paid projects as an add-on starting around $100/month for 7 days and requires at least Small compute. ### Networking and connections Raff provides built-in pooling, TLS, allowlist controls, and private connectivity for Raff-hosted workloads. Private VPC traffic is unmetered. Supabase gives each project direct and pooled PostgreSQL connection options. Its Pro pricing includes 250 GB uncached and 250 GB cached egress, while AWS PrivateLink is listed for Team and Enterprise rather than Free or Pro. ### Maintenance and upgrades Raff handles service-level maintenance for supported managed PostgreSQL versions while the application team owns schema migrations, query compatibility, extensions, credentials, and release validation. Supabase manages hosted project infrastructure and provides PostgreSQL upgrade workflows. Its 2026 platform direction uses PostgreSQL 17 as the default, so teams with older projects should treat major-version compatibility and extension support as explicit upgrade work. ### Reliability and trust signals Raff publishes a 99.9% platform SLA and supports 3,000+ customers and 15,000+ production VMs. Its Trustpilot profile displayed **4.5/5** on August 16, 2026. Supabase reports 8 million developers and 100,000 GitHub stars as of April 2026, which demonstrates a much larger developer ecosystem. Its Trustpilot page displayed **2.7/5** when checked on August 16, 2026. Review-site ratings are user sentiment signals, not uptime measurements. ## When you should choose Supabase over Raff - **Integrated backend services** — Supabase combines PostgreSQL with Auth, Storage, Realtime, APIs, and Edge Functions in one project. - **PostgreSQL 17** — Supabase's hosted platform currently defaults to PostgreSQL 17; Raff currently supports 14–16. - **Broader region choice** — Supabase lists 17 specific AWS regions plus general-region selection; Raff has 1 public region, `us-east`. - **Preview environments** — Supabase branching creates isolated environments on paid plans, with Micro branch compute starting at $0.01344/hour. - **Free BaaS experimentation** — Supabase Free provides 2 active projects plus Auth, Storage, Realtime, and Function allowances at $0. - **Large ecosystem** — Supabase reported 8 million developers and 100,000 GitHub stars in April 2026. ## When you should choose Raff over Supabase - **Focused managed PostgreSQL** — Raff provides a $0 database tier and paid PostgreSQL from $7.99/month without requiring adoption of a BaaS layer. - **Published capacity** — paid Raff tiers state vCPU, RAM, NVMe allocation, and monthly price directly. - **Explicit high availability** — PostgreSQL HA adds 70% to the selected Raff plan; the $45.99 tier becomes $78.18/month. - **Private Raff application paths** — private VPC traffic is unmetered when application and database services communicate inside Raff. - **Multiple database engines** — Raff also provides managed MySQL, Valkey, ClickHouse, and Kafka under the same cloud account. - **Portability by separation** — authentication, API, function, and storage choices can remain independent of the PostgreSQL service. ## Migrating from Supabase to Raff A Supabase-to-Raff migration is not only a PostgreSQL copy when the application uses Supabase-specific backend services. 1. **Inventory the Supabase project.** Record PostgreSQL major version, schemas, extensions, roles, Row Level Security policies, Auth providers, users, Storage buckets, Realtime subscriptions, Edge Functions, branches, webhooks, secrets, and client SDK dependencies. 2. **Confirm Raff compatibility and provision the target.** Select a Raff PostgreSQL tier, verify every required extension and PostgreSQL version, configure pooling, TLS, access rules, private networking, backups, and optional HA. 3. **Move PostgreSQL data.** Use `pg_dump`/`pg_restore` for suitable databases or logical replication for an active low-downtime migration where source and target configuration permit it. 4. **Replace application-backend dependencies.** Move file objects to the selected storage path, replace Supabase Auth where used, recreate API behavior, relocate Edge Functions, and redesign Realtime integrations that are not plain PostgreSQL features. 5. **Update application configuration.** Replace Supabase project URLs, keys, database endpoints, auth callbacks, storage URLs, secrets, webhooks, generated-client assumptions, and branch-specific environment configuration. 6. **Validate and cut over.** Verify row counts, sequences, extensions, RLS behavior, authentication, uploads, subscriptions, background jobs, connection pooling, backups, restore expectations, and rollback before switching production traffic. Operational gotchas: - A Supabase project already on PostgreSQL 17 cannot be treated as a routine downgrade to Raff PostgreSQL 14–16. - Row Level Security policies may remain PostgreSQL objects, but application identity claims supplied by Supabase Auth must be recreated correctly. - Supabase Storage signed URLs, Auth sessions, Realtime subscriptions, Edge Functions, and preview branches do not migrate automatically with the database. - Client libraries can combine database, Auth, Storage, and Realtime calls behind one SDK, so each dependency must be mapped explicitly. For a stateful production migration, keep Supabase available through a defined rollback window until database consistency and every application-facing replacement have been verified. ## About Supabase [Supabase](https://supabase.com/) is operated by Supabase Inc., a remote-first company whose work began in January 2020. The platform combines managed PostgreSQL with Auth, Storage, Realtime, generated APIs, Edge Functions, branching, SDKs, and observability. Supabase operates as a distributed global company rather than around a single conventional office headquarters. ## Conclusion: Supabase or Raff? The comparison resolves across four measured decision axes: - **Product scope** — Supabase bundles Auth, Storage, Realtime, APIs, Edge Functions, and branching; Raff keeps PostgreSQL focused and separately composable. - **Pricing model** — both have $0 tiers; Raff paid PostgreSQL starts at $7.99/month while Supabase Pro starts at $25/month plus applicable usage. - **Operations** — Raff publishes resource tiers and +70% PostgreSQL HA; Supabase combines project compute with platform services and add-ons. - **Reach and ecosystem** — Supabase offers 17 specific AWS regions and a much larger developer ecosystem; Raff exposes `us-east` and a narrower infrastructure model. Choose Supabase when integrated backend services, PostgreSQL 17, preview environments, or broad regional placement are requirements. Choose Raff when PostgreSQL should remain a focused managed service with explicit resources, recovery choices, private connectivity, and predictable operational modifiers. Raff supports 15,000+ production VMs and was verified at 4.5/5 on August 16, 2026. --- ### PlanetScale Alternatives 2026: MySQL & Postgres Options URL: https://rafftechnologies.com/learn/compare/planetscale-alternatives-mysql-postgres Description: Moving off PlanetScale? Compare Raff, Neon and Supabase for MySQL/Postgres pricing, branching, scaling, migration and production trade-offs in 2026. PlanetScale has changed substantially from the product many developers still remember. In 2026 its product surface spans **PlanetScale Postgres**, **Vitess for MySQL-compatible workloads**, and **Neki**, PlanetScale's sharded Postgres architecture. The platform also includes high-availability and performance-focused deployment options, database branching, deploy workflows, and production query tooling. That makes “PlanetScale alternative” a broader decision than it was a few years ago. Some teams want to keep **MySQL compatibility**. Others are comfortable moving to **Postgres**. Some are primarily searching for a cheaper database. Others actually need PlanetScale's branching, non-blocking schema changes, or Vitess-style horizontal scaling. For small and mid-sized teams, the most useful alternatives break into four models: **Raff Managed MySQL/PostgreSQL** for straightforward managed databases with fixed plan pricing, **Neon** for serverless Postgres with scale-to-zero and database branching, **Supabase** for Postgres bundled into a broader backend platform, and staying with **PlanetScale** when Vitess, its schema workflow, or its high-scale architecture is the requirement. ## PlanetScale alternatives at a glance | Option | Database model | Pricing model | Typical fit | Main trade-off | |---|---|---|---|---| | PlanetScale | Postgres + Vitess/MySQL-compatible + Neki for sharded Postgres | Resource-based / pay-as-you-go | Teams that value sharding, database branching and PlanetScale's schema workflow | More specialized platform than a conventional managed MySQL/Postgres service | | Raff | Managed MySQL 8 + PostgreSQL | Free tier + fixed monthly plans | Small teams wanting familiar engines, predictable plans and managed operations | Smaller regional footprint and fewer database-development workflow features than PlanetScale | | Neon | Serverless Postgres | Free tier + usage-based paid plans | Postgres teams that value scale-to-zero, branching and variable workloads | Postgres only; cost follows metered compute/storage usage | | Supabase | Managed Postgres + backend services | Free tier + subscription + usage | Teams wanting database, auth, storage, realtime and APIs together | Broader backend platform can be unnecessary when the requirement is only a database | **Short answer:** stay with PlanetScale when Vitess, sharded Postgres through Neki, its branch/deploy workflow, or PlanetScale-specific operational tooling is part of the requirement. Raff fits teams that mainly need managed MySQL or PostgreSQL with familiar engines and a simpler fixed-plan bill. Neon targets serverless Postgres and scale-to-zero. Supabase combines Postgres with a broader backend platform. :::cluster ## Why teams look for PlanetScale alternatives The reasons have changed over time. Earlier PlanetScale-alternative searches were often driven by the removal of its old Hobby plan. In 2026 the product itself has expanded: PlanetScale now sells Postgres as well as Vitess, publishes resource-based pricing, and continues to invest in database branches, safe migrations, schema recommendations, CLI tooling, and production insights. Today, teams usually evaluate alternatives for one of six reasons: - they want a **free database tier** for a small project or staging environment; - they want conventional MySQL/Postgres without the additional Vitess layer; - they prefer a fixed monthly plan instead of resource-based billing; - they need a broader backend platform such as auth, object storage, realtime, and APIs; - they want serverless Postgres that scales compute down when idle; - they no longer need PlanetScale-specific branching, schema-deployment, or horizontal-sharding capabilities. The correct alternative depends on which of those problems you are actually solving. ## PlanetScale in 2026: Postgres, Vitess, and Neki PlanetScale's current product surface spans three database architectures: - **PlanetScale Postgres** for managed PostgreSQL workloads; - **Vitess** for MySQL-compatible horizontal scaling; - **Neki**, PlanetScale's sharded Postgres architecture for workloads that need Postgres scale beyond a single cluster. PlanetScale currently lists Postgres single-node deployments starting at **$5/month**, high-performance Metal deployments starting at **$50/month**, and high-availability configurations with a primary plus two replicas across three availability zones. Vitess pricing is based on cluster size, VTGate configuration, storage, and the selected infrastructure profile. A primary PlanetScale differentiator is not simply “we host a database.” Its Vitess product continues to combine vanilla MySQL with routing, control-plane components, and horizontal-sharding architecture. PlanetScale also continues to invest heavily in schema workflow: branches, deploy requests, safe migrations, non-blocking schema changes, query insights, and automation through its CLI/API/Terraform tooling. Choose PlanetScale when several of these are true: - horizontal MySQL scaling through Vitess is part of the architecture; - database branching is integrated into the development workflow; - non-blocking production schema changes are a recurring requirement; - the team values PlanetScale's deploy-request and schema-analysis workflow; - PlanetScale's performance-oriented infrastructure profiles fit the workload; - the organization is comfortable with resource-based pricing. If those are not requirements, a simpler managed database may be easier to operate and budget. ## Raff: familiar MySQL or Postgres with a smaller operational surface [Raff Managed Databases](/products/managed-databases) is the most direct alternative in this comparison for a team that mainly wants the database engine itself managed. Raff currently offers managed PostgreSQL, MySQL, Valkey, Kafka, and ClickHouse. MongoDB is still rolling out and should not be treated as a generally available managed engine yet. PostgreSQL, MySQL and Valkey also have a **free tier**: one free database per account, no fixed trial expiry, with inactive free databases pausing after seven days without a connection while retaining their data. Paid MySQL and PostgreSQL plans currently start at **$7.99/month**. The entry MySQL plan includes **1 vCPU, 1 GB RAM and 25 GB NVMe storage**, with daily backups included. Raff's MySQL service runs MySQL 8 with InnoDB; high-availability MySQL plans use a three-node Galera design behind HAProxy. Raff fits when: - standard MySQL 8 or PostgreSQL compatibility is preferable to a specialized distributed database layer; - the team wants a clear fixed monthly plan; - backups, monitoring, private networking and migration support should be part of the managed service boundary; - a free database is useful for development or a small workload; - the application already runs on a conventional ORM or framework and should not need a database-architecture rewrite; - direct migration assistance matters more than sophisticated database branching. Raff is **not** a drop-in replacement for every PlanetScale architecture. A workload that depends on Vitess horizontal sharding, PlanetScale-specific branching, or deploy-request workflows should treat those as migration requirements, not optional features. For the broader operating-model decision, read [MySQL Hosting: Managed vs Self-Hosted for Production Apps](/learn/guides/mysql-hosting-managed-vs-self-hosted). ## Neon: serverless Postgres and scale-to-zero Neon is a better PlanetScale alternative when the application can use Postgres and the priority is serverless behavior rather than MySQL compatibility. Neon's current platform uses a usage-based pricing model and can scale idle compute to zero. Its Free plan remains available, while paid Launch and Scale plans meter compute usage rather than requiring a fixed monthly minimum. Neon also puts database branching at the center of its developer workflow. Current Neon pricing guidance lists: - a Free plan with multiple projects and per-project compute allowances; - Launch compute currently priced at **$0.106 per CU-hour**; - Scale compute currently priced at **$0.222 per CU-hour**; - **500 GB of public data transfer included each month on paid plans** as of June 2026. Neon fits when: - Postgres is acceptable or already used; - workloads are bursty or spend long periods idle; - scale-to-zero can materially reduce compute consumption; - branch-per-preview or branch-per-development workflows are important; - the team prefers metered serverless economics over fixed capacity plans. Neon is not the right direct substitute when retaining MySQL compatibility is mandatory. Moving from PlanetScale Vitess/MySQL to Neon is a **database-engine migration**, not just a provider migration. Raff already has a dedicated [Neon Alternative 2026 comparison](/learn/compare/neon-alternative) for that narrower provider decision. ## Supabase: when PlanetScale is only one part of the backend you need Supabase is not primarily a PlanetScale-style database platform. It is a broader backend platform built around Postgres. Its value becomes clear when the application needs several services together: - managed Postgres; - authentication; - object/file storage; - realtime updates; - generated APIs; - edge functions; - backend administration tooling. Supabase currently offers a **Free plan at $0/month** and a **Pro plan from $25/month**. The current Free plan includes a 500 MB database per project. Pro includes an 8 GB disk allocation per project before additional storage charges and includes daily backups with seven-day retention. Choose Supabase when: - the app needs a backend platform rather than only a database; - Postgres is already the preferred engine; - built-in auth, storage, realtime and APIs reduce application engineering; - the team's architecture benefits from consolidating those backend services. Choose another option when the application only needs MySQL/Postgres and the broader platform would add concepts, billing dimensions or migration dependencies that the team does not need. Raff already publishes a dedicated [Supabase Alternative 2026 comparison](/learn/compare/supabase-alternative) for teams evaluating that specific switch. ## PlanetScale vs Raff: the most direct small-team decision For a small team that is not choosing a full backend platform, the most relevant comparison is often PlanetScale vs Raff. | Decision | PlanetScale | Raff | |---|---|---| | Engines | Postgres + Vitess/MySQL-compatible | PostgreSQL + MySQL 8 plus other managed data engines | | MySQL architecture | Vitess-based distributed platform | Conventional managed MySQL 8 / InnoDB | | Postgres available | Yes | Yes | | Free database tier | No general free tier shown on current PlanetScale pricing page | Yes for PostgreSQL/MySQL/Valkey, one per account | | Paid entry reference | Postgres single node from $5/month | Managed MySQL/Postgres paid plans from $7.99/month | | Database branching | Core PlanetScale workflow | Not the primary workflow | | Safe/non-blocking schema tooling | Strong PlanetScale feature | Standard database/application migration workflow | | Horizontal Vitess sharding | Core strength | No equivalent Vitess layer | | Pricing style | Resource-based / pay as you go | Fixed plan baseline | | Migration assistance | Provider tooling/support dependent on case | Raff advertises free migration assistance | | Best fit | Teams needing PlanetScale's scale and schema-development model | Teams wanting straightforward managed database operations | The question is therefore not simply “which starts cheaper?” PlanetScale's Postgres entry price can be lower than Raff's paid entry plan, while Raff also has a free database tier. Those numbers describe different capacity models and platform behavior. Choose from architecture first, then compare equivalent production configurations. ## What about TiDB, Railway and other PlanetScale alternatives? Several other products can make sense depending on the workload. ### TiDB TiDB is worth evaluating when retaining MySQL-style application compatibility and distributed horizontal scaling are more important than using conventional MySQL. It competes more directly with the distributed-database problem PlanetScale Vitess solves than Postgres-first alternatives do. ### Railway Railway is useful when the database should live beside application deployments in a developer platform. It can be convenient for small teams that value one deployment workflow for apps and databases, but the purchasing decision is closer to choosing an application platform than choosing a specialized DBaaS. ### Self-managed MySQL or Postgres Self-hosting can reduce provider abstraction and increase control, but it also moves backups, upgrades, monitoring, failover, security, disk growth and incidents back to your team. For small teams, compare that operating cost against the managed option rather than comparing only VM price. Use [VPS for Databases: What Small Teams Should Know](/learn/guides/vps-for-databases) when self-hosting is a serious candidate. ## Pricing comparison: use the same workload The providers in this comparison do not bill the same thing, so headline starting prices should not be treated as equivalent production costs. | Provider | Public pricing approach | Entry/reference point | Important variables | |---|---|---|---| | PlanetScale | Resource-based pay as you go | Postgres single node from $5/month; Metal from $50/month | engine, cluster size, replicas, storage, VTGate, egress | | Raff | Free tier + fixed plans | Free tier; paid MySQL/Postgres from $7.99/month | selected plan, storage growth, HA configuration | | Neon | Free + metered serverless usage | Free; Launch compute $0.106/CU-hour | active compute time, storage, transfer, branch usage | | Supabase | Subscription + compute/usage | Free; Pro from $25/month | compute, database storage, egress, auth/storage/realtime usage, add-ons | Before comparing cost, define: ```text engine + required memory / CPU + average and peak load + database size + monthly growth + read/write pattern + HA requirement + backup / PITR requirement + public egress + region + development branches + extra backend services ``` Then price each provider against the same workload. A free tier can be ideal for development but irrelevant to a production HA cluster. A $5 single-node plan is not equivalent to a three-node HA cluster. A usage-based database can be extremely inexpensive when idle and more expensive when continuously active. **Compare equivalent outcomes, not marketing entry prices.** ## Migration from PlanetScale: identify whether you are moving providers or database engines The first migration question is whether the target uses the same database family. ### PlanetScale Vitess to Raff Managed MySQL This keeps the application in the MySQL ecosystem, but it is still not a simple server copy. Vitess adds its own topology, routing and operational behavior. Validate: - SQL and feature compatibility used by the application; - schema and index definitions; - foreign key behavior used by the current PlanetScale configuration; - connection limits and pooling; - transaction patterns; - table size and growth; - data export/replication method; - cutover and rollback approach. ### PlanetScale Postgres to Raff or Neon Postgres This is a same-engine provider migration, which generally reduces application rewrite risk, but you still need to validate: - extensions; - roles and privileges; - connection strings and TLS; - logical replication or migration tooling; - sequence and identity state; - backups and PITR expectations; - connection pooling; - cutover lag and rollback. ### PlanetScale MySQL/Vitess to Neon or Supabase This is a MySQL-to-Postgres migration. Treat it as an application and schema migration, not merely infrastructure replacement. Data types, indexes, SQL behavior, extensions, migrations and ORM behavior all need validation. ## PlanetScale alternative migration checklist - [ ] Confirm whether the source is PlanetScale Vitess or PlanetScale Postgres. - [ ] Decide whether the target keeps the same database engine. - [ ] Inventory schema, indexes, extensions and database-specific features. - [ ] Measure production database size and write rate. - [ ] Document connection and transaction patterns. - [ ] Define HA and recovery requirements on the target. - [ ] Map backups and PITR expectations. - [ ] Identify PlanetScale branch/deploy workflows that must be replaced. - [ ] Test application queries against the target before moving production data. - [ ] Choose replication, logical migration or export/import based on the engine pair. - [ ] Define a cutover window and rollback condition. - [ ] Verify consumer/background jobs do not continue writing to the old database after cutover. - [ ] Validate application behavior and business data before deleting the source. ## Which PlanetScale alternative should you choose? ### Stay with PlanetScale when - Vitess horizontal scaling is a real requirement; - PlanetScale's branching and deploy-request workflow saves your team meaningful engineering time; - non-blocking schema changes are part of frequent production releases; - the current resource-based pricing matches workload economics; - moving away would require rebuilding database workflows that are already working well. ### Choose Raff when - standard managed MySQL 8 or PostgreSQL fits the application; - predictable fixed monthly plans matter; - the team wants a free development/small-workload database option; - conventional ORM and framework compatibility is more important than Vitess-specific scale; - migration assistance and direct human support are valuable; - the team wants multiple managed data engines under one provider. ### Choose Neon when - Postgres is the target engine; - scale-to-zero is valuable; - database branching is central to development and preview workflows; - usage-based serverless pricing fits an intermittent workload. ### Choose Supabase when - the application needs Postgres plus auth, storage, realtime and APIs; - consolidating backend services is more important than buying a database independently. ## Conclusion PlanetScale is no longer a product that can be summarized as “serverless MySQL.” In 2026 it is a broader cloud database platform spanning PlanetScale Postgres and Vitess, with sophisticated branching, schema-deployment and performance workflows. That means the best alternative depends on what part of PlanetScale you actually value. Choose **Raff** when the goal is a familiar managed MySQL or Postgres database with a free tier, fixed paid plans from $7.99/month, backups and managed operations without adopting a specialized distributed-database workflow. Choose **Neon** when serverless Postgres and scale-to-zero are central. Choose **Supabase** when the database should arrive with a full backend platform. Stay with **PlanetScale** when Vitess, database branching, safe migrations, or its high-scale workflow materially reduce engineering work. The right migration is the one that removes complexity your team does not need without throwing away capabilities it actually depends on. :::cta database Compare managed MySQL and PostgreSQL options. ::: ## Sources - [PlanetScale Pricing](https://planetscale.com/pricing) - [PlanetScale Features](https://planetscale.com/features) - [PlanetScale Vitess](https://planetscale.com/vitess) - [PlanetScale Changelog](https://planetscale.com/changelog) - [Neon Usage-Based Pricing](https://neon.com/blog/new-usage-based-pricing) - [Neon Compute Price Update](https://neon.com/blog/major-compute-price-reduction-on-neon) - [Neon Data Transfer Update](https://neon.com/blog/more-data-transfer-on-paid-plans) - [Supabase Pricing](https://supabase.com/pricing) - [Raff Managed Databases](/products/managed-databases) - [Raff Managed MySQL](/products/managed-databases/mysql) - Product and pricing details reviewed: 2026-09-18 --- ### Confluent Alternatives 2026: Managed Kafka Options for Small Teams URL: https://rafftechnologies.com/learn/compare/confluent-alternatives-managed-kafka Description: Compare Confluent alternatives including Raff Managed Kafka, Amazon MSK and Aiven across pricing, regions, operations, migration and platform scope. Confluent is one of the most complete managed data-streaming platforms around Apache Kafka, but it is not the right operating model for every team. Some buyers need Confluent's connectors, governance, Flink, ksqlDB, Tableflow, Cluster Linking, and global cloud footprint. Others mainly need **reliable managed Apache Kafka without adopting a broader enterprise streaming platform or a highly granular consumption bill**. For small and mid-sized teams, practical Confluent alternatives fall into four different categories: **Raff Managed Kafka** for a simpler fixed-plan Apache Kafka service in `us-east`, **Amazon MSK** for AWS-native Kafka, **Aiven for Apache Kafka** for multi-cloud managed open-source infrastructure, and **self-managed Apache Kafka** when broker-level control is a hard requirement. The right alternative depends less on a generic feature count and more on five questions: **Do you need Confluent-specific services? Which cloud or region must the cluster run in? Do you want fixed or usage-based billing? Who should own broker operations? How difficult will migration be from the parts of Confluent you actually use?** ## Confluent alternatives at a glance | Option | Kafka model | Billing model | Typical fit | Main trade-off | |---|---|---|---|---| | Confluent Cloud | Managed Kafka plus broader streaming platform | Consumption-based across capacity, ingress, egress, storage and optional services | Teams that want a broad enterprise streaming ecosystem | More platform surface and more billing dimensions than a Kafka-only service | | Raff Managed Kafka | Managed Apache Kafka | Fixed plan pricing from $79.99/month | Small and mid-sized teams that want straightforward managed Kafka in `us-east` | One public region and a much smaller streaming ecosystem than Confluent | | Amazon MSK | AWS-managed Apache Kafka | Provisioned or serverless usage-based pricing | Teams deeply standardized on AWS | AWS pricing and architecture can involve several usage dimensions | | Aiven for Apache Kafka | Managed Apache Kafka across multiple clouds | Free/Developer entry tiers plus production plans with plan- and usage-dependent pricing | Teams wanting multi-cloud Kafka and a broad managed open-source data platform | Production pricing and service choices are broader than a simple fixed Kafka plan | | Self-managed Kafka | Apache Kafka operated by your team | Infrastructure + engineering + operations | Teams with hard broker-level requirements and mature Kafka operations | Your team owns upgrades, balancing, monitoring, incidents and recovery | **Short answer:** Confluent fits teams that use its broader streaming platform. Raff fits teams that mainly need managed Apache Kafka in `us-east` with a smaller operating surface and fixed entry pricing. Amazon MSK fits AWS-native environments. Aiven fits multi-cloud teams that want a broader managed open-source catalog. Self-hosting is most relevant when broker-level control is a documented requirement. :::cluster For the operating-model decision before vendor selection, read [Managed Kafka vs Self-Hosted Kafka](/learn/guides/managed-kafka-vs-self-hosted-kafka). ## Why teams look for Confluent alternatives Confluent's breadth is a strength, not a flaw. The reason to evaluate alternatives is that not every Kafka workload needs that breadth. Common switching or evaluation triggers include: - the application mainly needs Apache Kafka brokers rather than a complete streaming-data platform; - the team wants a simpler monthly cost model; - an AWS-native architecture makes Amazon MSK operationally easier; - a multi-cloud requirement favors a provider such as Aiven; - a small team wants fewer platform-specific services to learn and operate; - procurement wants a lower-cost entry point for an early production workload; - a workload needs broker-level control that a managed service does not expose; - the team wants to reduce dependence on Confluent-specific services before future migration becomes harder. A lower entry price is not enough reason to migrate. If your application relies heavily on Confluent connectors, Stream Governance, Flink SQL, ksqlDB, Tableflow, Cluster Linking, or other platform-specific workflows, replacing the Kafka cluster can be the easy part while replacing the surrounding platform becomes the real project. That distinction matters because **Kafka protocol portability and platform portability are not the same thing**. ## Confluent Cloud when Kafka is only one part of the streaming platform Confluent Cloud goes far beyond managed brokers. Its current cloud platform combines Kafka with managed streaming and data-integration capabilities such as connectors, governance, stream processing, cross-cluster tooling, and analytical/table integrations. Its billing model reflects that broader platform. Confluent documentation currently lists billable dimensions including: - Kafka cluster capacity through eCKUs or CKUs depending on cluster type; - data ingress; - data egress; - storage; - Cluster Linking; - connectors; - ksqlDB; - Flink SQL; - Tableflow; - audit logs; - support. For Basic, Standard, Enterprise, and Freight clusters, current Confluent documentation uses elastic capacity units, or **eCKUs**. Dedicated clusters use **CKUs**. Storage and transfer are separate billing dimensions. That model is useful when a company wants elastic capacity and many managed streaming services in one platform. It can be less attractive when a small team wants to answer a simpler question: “What will one Kafka environment cost us each month?” Choose Confluent when several of these are true: - your team actively uses or expects to use its broader streaming ecosystem; - global cloud placement is required; - enterprise governance and integration workflows are important; - usage-based elastic capacity fits your financial model; - migrating away from Confluent-specific services would create more work than the platform cost justifies. The goal of an alternatives page should not be to make Confluent look oversized for everyone. For many data-platform teams, that breadth is exactly why they buy it. ## Raff Managed Kafka: a smaller managed Kafka surface [Raff Managed Kafka](/products/managed-databases/kafka) is the most direct alternative in this list for a team that wants managed **Apache Kafka itself** without building an enterprise-wide streaming platform around the purchase. Raff's managed Kafka product provides managed Apache Kafka with fixed plans. As of September 2026, the published entry plan starts at **$79.99/month for 2 vCPU, 4 GB RAM, and 80 GB storage**. Verify the current Kafka version and HA topology on the live product page before planning a production migration around version-specific behavior. Raff uses fixed plan pricing rather than metering Kafka capacity, ingress, egress, and storage as separate Confluent-style billing dimensions. That makes it easier for a small team to establish a monthly baseline before traffic grows. Raff is a stronger fit when: - the currently supported Kafka version meets the application requirement; - one public `us-east` region fits the workload; - the team wants broker operations managed without adopting a much larger streaming platform; - a fixed plan price is easier to budget than several usage dimensions; - direct support and migration assistance are useful to a smaller engineering team; - Kafka supports the product but is not itself the product team's core specialty. Raff is **not** the right substitute when the requirement is effectively “give us Confluent's entire platform at a lower price.” Raff does not match Confluent's global footprint or the breadth of its streaming ecosystem. A useful Raff decision rule is: **if your application needs Kafka semantics but your team does not gain product value from operating or extending a large Kafka platform, keep the service boundary small.** For topic, partition, consumer and retention decisions that remain your responsibility on any provider, use [Kafka Architecture for Small Teams](/learn/guides/kafka-architecture-small-teams). ## Amazon MSK: when Kafka already belongs inside AWS Amazon Managed Streaming for Apache Kafka, or Amazon MSK, is the natural Confluent alternative for teams whose infrastructure, networking, security, observability, and procurement are already centered on AWS. AWS currently offers both **MSK Provisioned** and **MSK Serverless**. The serverless model charges across several usage dimensions, including: - cluster-hours; - partition-hours; - data written by producers; - data read by consumers; - storage; - additional standard AWS transfer charges in some network paths. AWS's own current pricing example for an MSK Serverless cluster in US East (Ohio) uses five topics with 20 partitions each, 100 GB/day written, 200 GB/day read, and 100 GB average storage. AWS calculates that specific 31-day example at **$1,299.60**. That is a workload example, **not a starting price**, but it illustrates why MSK buyers should model partitions, throughput and data movement before assuming the final bill from the word “serverless.” Amazon MSK fits when: - VPC, IAM, CloudWatch and other AWS integrations are already part of the architecture; - the team wants Apache Kafka without leaving AWS operational boundaries; - AWS regions satisfy placement and compliance requirements; - infrastructure teams already understand AWS billing and networking; - procurement prefers consolidating cloud spend into AWS. It is less compelling when the main goal is escaping hyperscaler complexity or when the team wants a small fixed monthly Kafka plan. ## Aiven for Apache Kafka: multi-cloud and managed open-source breadth Aiven is another strong managed Apache Kafka alternative, especially for teams that want to keep a broader set of open-source data services under one managed provider while retaining cloud and region choice. Aiven's current public Kafka pricing includes: - **Free: $0/month**, with limited throughput, topics and retention; - **Developer: starting at $35/month** for the current entry configuration; - production-oriented Professional options whose exact cost depends on plan, cloud, region, capacity and the current service model. The current Developer tier is designed for development, testing, and smaller workloads. Aiven documentation lists **1 MB/s ingress, 2 MB/s egress, up to 20 topics**, configurable one-to-three-day retention, and KRaft for that tier. Aiven also offers broader production capabilities and deployment across major cloud providers. Aiven fits when: - the team wants Kafka plus managed PostgreSQL, MySQL, Valkey, OpenSearch, ClickHouse or other open-source data services; - AWS, Azure or Google Cloud placement flexibility matters; - the organization wants a managed open-source platform rather than one cloud vendor's native stack; - region selection is more important than minimizing the provider surface; - the team's Kafka needs are likely to outgrow a small single-region service. Compared with Raff, Aiven offers much broader geographic and platform choice. Raff offers a smaller `us-east` footprint and simpler fixed entry plan. Those are different product strategies rather than a universal winner and loser. ## Self-managed Kafka: when control is the requirement Running Apache Kafka yourself remains a valid Confluent alternative when managed-service constraints block a real requirement. Self-management can make sense when you need: - exact broker configuration; - custom networking or security architecture; - precise upgrade timing; - host-level debugging or observability; - unusual storage or topology design; - Kubernetes-native operation through tooling such as an operator; - direct control over the full Kafka lifecycle; - an existing platform team that already operates Kafka reliably. The cost model is broader than VM price: ```text broker compute + storage + network + monitoring + spare capacity + replication overhead + upgrades + engineering time + on-call coverage + incident response + recovery testing ``` If no named team owns those responsibilities, self-hosting has not eliminated the managed-service cost; it has moved the cost into engineering and operational risk. This is exactly the boundary covered in [Managed Kafka vs Self-Hosted Kafka](/learn/guides/managed-kafka-vs-self-hosted-kafka). ## Confluent pricing vs alternatives: compare billing models, not one headline number There is no responsible one-line statement that “Provider X is Y% cheaper than Confluent” for every Kafka workload. The services bill different things and include different platform capabilities. | Provider | Public pricing model | Useful entry/reference point | Cost variables to model | |---|---|---|---| | Confluent Cloud | Consumption-based | No single fixed comparable monthly cluster price | eCKU/CKU capacity, ingress, egress, storage, connectors and other platform services | | Raff Managed Kafka | Fixed plans | From $79.99/month for 2 vCPU / 4 GB / 80 GB | selected plan, storage/capacity growth, HA configuration | | Amazon MSK | Provisioned or serverless usage pricing | AWS publishes workload examples rather than one universal starting total | brokers or cluster-hours, partitions, data in/out, storage, network transfer | | Aiven for Kafka | Tier/plan dependent | Free $0; Developer from $35/month | tier, retention, cloud/region, capacity, network and production configuration | | Self-managed Kafka | Infrastructure + labor | No managed-service fee | brokers, disks, traffic, monitoring, replicas, labor, on-call and recovery | A useful cost exercise is to define the same workload first: ```text average and peak ingress + average and peak egress + partition count + retention + stored data + replication / HA requirement + region + connectors / schema / stream processing needs + support requirement ``` Then price each provider against that workload. A small cluster with modest traffic may strongly favor one pricing model. A high-throughput platform using managed connectors, governance and stream processing can favor another because buying those capabilities separately creates its own cost. **Price equivalent outcomes, not just Kafka brokers.** ## Migration from Confluent depends on how much Confluent-specific surface you use For an application using standard Kafka producers and consumers, the Kafka broker layer is often the most portable part of the architecture. Client configuration, authentication, networking, topics, offsets, retention, and data movement still need a migration plan, but the application protocol is based on Kafka. Migration becomes more involved when the application also depends on Confluent-specific or Confluent-managed services. Inventory these before choosing an alternative: - Schema Registry and schema compatibility workflows; - managed connectors; - ksqlDB; - Flink SQL; - Tableflow; - Cluster Linking; - governance and audit workflows; - cloud-specific private networking; - identity and access configuration; - metrics and alerting integrations. A practical migration sequence is: 1. **Inventory Kafka and platform dependencies.** Record topics, partitions, retention, ACLs, schemas, connectors, consumer groups, throughput and Confluent-specific services. 2. **Create the target Kafka environment.** Match Kafka/client compatibility, networking, authentication, capacity, retention and HA requirements. 3. **Test client compatibility.** Point non-production producers and consumers at the target and validate serialization, authentication, throughput and failure behavior. 4. **Plan data movement.** Select a supported replication, mirroring, export/import or dual-run method appropriate to the source and target. 5. **Rebuild non-Kafka dependencies.** Replace or migrate schema, connector, processing and governance features that do not move with broker data. 6. **Cut over consumers and producers deliberately.** Define authoritative clusters, offset handling, rollback and the point where new writes stop on the source. 7. **Validate business outcomes.** Confirm event freshness, consumer lag, downstream state and critical workflows before retiring Confluent resources. Do not assume that “Kafka-compatible” means every surrounding feature migrates automatically. For consumer recovery planning during a move, use [Kafka Consumer Groups: Lag, Rebalances & Recovery Planning](/learn/guides/kafka-consumer-groups-lag-rebalances). ## Which Confluent alternative should you choose? ### Choose Confluent Cloud when - you need a broad enterprise data-streaming platform rather than only Kafka; - managed connectors, governance, Flink/ksqlDB, Tableflow or cross-cluster tooling reduce engineering work; - global cloud and region choice is important; - usage-based elastic billing fits the organization's cost model; - replacing Confluent-specific services would create unnecessary migration risk. ### Choose Raff Managed Kafka when - the current managed Kafka version fits the workload; - `us-east` satisfies placement needs; - a published fixed entry plan from $79.99/month is easier to forecast; - the team primarily needs brokers, monitoring and managed operations rather than a broad streaming suite; - direct support and a smaller platform surface are preferable for a small engineering team. ### Choose Amazon MSK when - the organization is already deeply AWS-native; - VPC/IAM/CloudWatch and AWS procurement integration reduce operational work; - AWS region breadth matters; - the team is comfortable modeling serverless or provisioned AWS costs. ### Choose Aiven when - multi-cloud or broad region placement is a priority; - Kafka is part of a larger managed open-source data stack; - Aiven's free/developer path is useful for evaluation; - the team wants a provider-independent open-source platform with broader geographic coverage than Raff. ### Choose self-managed Kafka when - a documented broker-level requirement blocks managed services; - the team already has Kafka automation, monitoring and on-call maturity; - the operational control is worth the lifecycle burden. ## Confluent alternative evaluation checklist Before switching providers, confirm: - [ ] Required Kafka version and client compatibility are supported. - [ ] Required region and network architecture are available. - [ ] Peak ingress and egress fit the target service. - [ ] Partition count and connection requirements fit service limits. - [ ] Retention and storage growth are modeled. - [ ] HA and failure behavior are understood. - [ ] Schema Registry requirements are mapped. - [ ] Every connector is mapped to a target equivalent or replacement. - [ ] ksqlDB/Flink/Tableflow dependencies are identified. - [ ] Consumer groups and offsets have a migration plan. - [ ] Authentication and ACLs can be recreated. - [ ] Monitoring and alert ownership are defined. - [ ] Full monthly production cost is modeled from the same workload. - [ ] Rollback remains possible through the cutover window. ## Conclusion The best Confluent alternative depends on what you are actually replacing. If Confluent is your enterprise streaming platform, its broad ecosystem can justify both the platform surface and its consumption model. If Confluent is mainly acting as a managed Kafka cluster for a smaller product team, a narrower service may be easier to operate and budget. Raff fits teams that want **managed Apache Kafka, fixed plan pricing from $79.99/month, managed broker operations, and a focused `us-east` deployment model**. Amazon MSK fits AWS-native architecture. Aiven fits multi-cloud and managed open-source breadth. Self-managed Kafka is most relevant when direct operational control is itself a requirement. Choose based on the platform capabilities you use today and the responsibilities you want to own tomorrow—not simply the lowest number on a pricing page. :::cta kafka Compare managed Kafka options. ::: ## Sources - [Confluent Cloud Pricing](https://www.confluent.io/pricing/) - [Confluent Cloud Billing Dimensions](https://docs.confluent.io/cloud/current/billing/billing-dimensions.html) - [Confluent Cloud Cluster Types](https://docs.confluent.io/cloud/current/clusters/cluster-types.html) - [Amazon MSK Pricing](https://aws.amazon.com/msk/pricing/) - [Aiven for Apache Kafka Pricing](https://aiven.io/pricing/kafka) - [Aiven Kafka Developer Tier](https://aiven.io/docs/products/kafka/dev-tier/kafka-dev-tier) - [Raff Managed Kafka](/products/managed-databases/kafka) - [Apache Kafka Documentation](https://kafka.apache.org/documentation/) - Pricing and product details reviewed: 2026-09-18 --- ### Bluehost Alternative 2026: Pricing, Performance & Features URL: https://rafftechnologies.com/learn/compare/raff-vs-bluehost-vps Description: Considering Bluehost? Raff is $17.99/mo for 2 vCPU, 4 GB and 80 GB NVMe with no 24-month prepay and no renewal price jump. Bluehost is a long-established web hosting company, best known for shared and WordPress hosting, that also sells a four-plan VPS line. Raff Technologies is a US cloud provider where the virtual machine is one product among several, alongside managed databases, object storage, Functions and Kubernetes on the same account. The two are not really the same kind of purchase: a Bluehost account bundles a domain, email and a hosting panel, while a Raff account is infrastructure an application runs on. At the matched entry shape, Bluehost NVMe 2 renews at $5.69/month for 1 vCPU and 2 GB, and the identical Raff shape is $8.99/month. ## Bluehost VPS and Raff at a glance **Bluehost** sells four self-managed VPS plans, from NVMe 2 at 1 vCPU core, 2 GB DDR5 RAM and 50 GB NVMe, up to NVMe 16 at 8 vCPU cores, 16 GB DDR5 and 450 GB NVMe. Every tier lists unmetered bandwidth and multiple data centers, and Bluehost states that all VPS tiers include root SSH and API access. Two things are excluded from VPS plans by Bluehost's own note: **cPanel and 24/7 priority support**. Bluehost's VPS positioning has moved toward developers — it describes the recommended NVMe 4 plan as suited to Docker, AI agents and growing applications. Pricing is promotional: each advertised rate applies to a 24-month term paid upfront, and each plan then renews higher. **Raff Technologies** runs 15,000+ VMs for 3,000+ customers from its us-east region, with a 99.9% uptime SLA backed by service credits, rated 4.5/5 on Trustpilot and 4.6/5 on G2. VMs run AMD EPYC with DDR5 ECC memory and NVMe storage in two lines: General Purpose with shared vCPU from $4.99/month, and CPU-Optimized with dedicated vCPU from $15.99/month, scaling to 16 vCPU and 32 GB. Every plan includes a 3 Gbps port with unmetered transfer, automated Daily or Weekly backup schedules, uncapped snapshots, firewall controls, private networking and full root access. Past the VM, Raff sells S3-compatible object storage at $7/month for 100 GB and 1 TB of egress, managed PostgreSQL, MySQL, Valkey, ClickHouse and Kafka from $7.99/month, managed Kubernetes with a free control plane and workers from $9.99/month, Functions with a free monthly tier, block volumes at $0.08/GiB-month, and Raff Apps from $3/month. ## Bluehost VPS pricing vs Raff pricing Bluehost VPS plans use shared vCPU cores, so the like-for-like Raff line is General Purpose. | Shape | Bluehost promo (24-mo term) | Bluehost renewal | Bluehost upfront for 24 months | Raff General Purpose | |---|---|---|---|---| | 1 vCPU / 2 GB | $4.69 — NVMe 2, 50 GB NVMe | **$5.69** | $112.56 | **$8.99** — 1 vCPU / 2 GB / 50 GB NVMe | | 2 vCPU / 4 GB | $9.49 — NVMe 4, 100 GB NVMe | **$11.99** | $227.76 | **$17.99** — 2 vCPU / 4 GB / 80 GB NVMe | | 4 vCPU / 8 GB | $12.99 — NVMe 8, 200 GB NVMe | **$28.99** | $311.76 | **$33.99** — 4 vCPU / 8 GB / 160 GB NVMe | | 8 vCPU / 16 GB | $25.99 — NVMe 16, 450 GB NVMe | **$49.99** | $623.76 | **$71.99** — 8 vCPU / 16 GB / 240 GB NVMe | *Raff General Purpose against Bluehost's self-managed VPS — both shared vCPU. Bluehost publishes no dedicated-vCPU VPS line, so every row above is shared against shared. Bluehost pricing read from Bluehost's live VPS pricing page on 2026-08-18; all figures monthly USD.* Which Bluehost number you compare against changes the answer completely. Against the **promotional** rate, Raff is 90% to 177% more expensive. Against the **renewal** rate — the price you actually pay from month 25 onward, and the fair comparison since Raff runs no promotion — the gap collapses: | Shape | Raff | Bluehost renewal | Difference | |---|---|---|---| | 1 vCPU / 2 GB | $8.99 | $5.69 | Raff +58% | | 2 vCPU / 4 GB | $17.99 | $11.99 | Raff +50% | | 4 vCPU / 8 GB | $33.99 | $28.99 | Raff +17% | | 8 vCPU / 16 GB | $71.99 | $49.99 | Raff +44% | NVMe 8 is the clearest example: $12.99/month promotional, $28.99/month at renewal — a **123% increase on the same hardware**. Budgeting from the advertised number will understate the two-year cost of that plan by more than half. The commitment differs too. Bluehost's advertised rate needs a 24-month term paid upfront, up to $623.76 at the top tier. Raff offers monthly, 1-year, and 2-year subscriptions plus pay-as-you-go billing from a prepaid balance, and carries a 14-day money-back guarantee, so evaluating it does not require a two-year decision. ### Automated backups Bluehost's VPS plan cards do not list backup or snapshot pricing, so treat data protection as a separate line item to confirm before committing to a 24-month term. Raff includes a free backup and snapshot storage pool — 50 GB per account plus 10–15% of each VM's disk — with Daily and Weekly schedules you configure and uncapped snapshots. Storage above the pool is billed at $0.06/GB-month. ### Bandwidth Neither provider meters standard outbound transfer, so there is no overage table to build. Bluehost lists unmetered bandwidth on all four VPS tiers; Raff includes unmetered transfer on a 3 Gbps standard port. Bluehost does not publish a port speed for its VPS plans. ## Bluehost VPS performance vs Raff **Raff has not run a head-to-head benchmark against Bluehost VPS, and this page will not estimate one.** Where numbers are not measured, they are not claimed. What follows is what can be stated from published specifications and architecture. **Plan ceiling.** Bluehost's VPS line stops at NVMe 16 — 8 vCPU and 16 GB RAM. Raff General Purpose scales to 16 vCPU and 32 GB, and CPU-Optimized offers dedicated vCPU from $15.99/month. Outgrowing NVMe 16 means leaving the product; outgrowing a Raff plan means selecting a larger one. **Resize behaviour.** Raff plans change size on demand: stop the VM, switch plan, restart, with the price difference settled to your account balance. Disk grows the same way, and there is a `resize` API endpoint for both. Bluehost does not document an equivalent in-place resize for VPS plans. **Storage architecture.** Both use NVMe, but differently. Local NVMe attached to a host answers a small write without a network round trip, which favours small-block random I/O. Raff runs distributed block storage across an NVMe cluster, so a write crosses the network and is replicated before it is acknowledged — slower for small synchronous writes, and the reason data is replicated rather than pinned to one machine, snapshots and backups are taken at the storage layer, and a VM can change plan without being rebuilt. **Reliability commitments.** Raff commits to a 99.9% uptime SLA with service credits, documented in the service level agreement, running 15,000+ VMs from us-east on AMD EPYC with DDR5 ECC memory. ECC matters for long-running database and application workloads because it corrects single-bit errors rather than passing them into your data. If you need a measured comparison rather than a specification one, the honest advice is to run your own workload on both for a week. ## Bluehost vs Raff: features and reliability ### Compute Bluehost offers four shared-vCPU shapes with 2 GB to 16 GB DDR5 RAM and root SSH plus API access on every tier, ending at 8 vCPU and 16 GB. Raff offers General Purpose from $4.99/month and CPU-Optimized dedicated vCPU from $15.99/month, on AMD EPYC with DDR5 ECC memory, scaling to 16 vCPU and 32 GB, with on-demand resize through the API. ### Networking Raff includes a 3 Gbps port with unmetered transfer, private networking, VPC, firewall controls and site-to-site VPN gateways. Bluehost lists unmetered bandwidth and multiple data centers; private networking is not presented as part of the VPS product. ### Storage Bluehost includes more local NVMe at every tier — 100 GB against Raff's 80 GB at 2 vCPU / 4 GB, and 450 GB against 320 GB at 8 vCPU / 16 GB. Raff separates storage into VM disk, block volumes at $0.08/GiB-month that resize independently of the VM, and S3-compatible object storage at $7/month for 100 GB and 1 TB of egress. ### Support Raff provides 24/7 human support through live chat, with a first response typically under 10 minutes. No bots triaging you first, and no support tier to buy: a single $4.99 VM reaches the same engineers as a hundred production machines, through the same queue. Bluehost states that 24/7 priority support is **not** included with VPS plans, so support level is a difference to price in rather than assume. ### What Raff does not replace Bluehost is a hosting company. Raff is a cloud provider. That distinction is worth making concrete, because a Bluehost account bundles things a cloud account does not. Raff does not offer mailboxes or email hosting, domain registration, cPanel, a one-click WordPress installer, or bundled SSL certificates. Moving a site from Bluehost means leaving email and domains where they are or moving them to a specialist provider, and installing your own certificates on the VM. What replaces them is infrastructure: managed PostgreSQL, MySQL, Valkey, ClickHouse and Kafka from $7.99/month, object storage at $7/month for 100 GB and 1 TB of egress, Functions with a free tier of 100,000 GB-seconds and 10,000 vCPU-seconds per month, Raff Apps from $3/month, and managed Kubernetes with a free control plane — all on one account, connected over private networking, on one bill. If what you need is a website, a mailbox and a domain on one bill, Bluehost is the right shape. If what you need is infrastructure for an application to run on, Raff is. ## When you should choose Bluehost over Raff - **A website with email and a domain on one bill** — Bluehost bundles mailboxes, domain registration and hosting; Raff offers none of the three - **WordPress and agency sites** — a hosting-account workflow rather than infrastructure to assemble ([VPS for web hosting](/learn/guides/vps-for-web-hosting)) - **Lowest monthly cost** — $9.49 promotional and $11.99 at renewal against Raff's $17.99 at 2 vCPU / 4 GB - **Storage-heavy single servers** — 450 GB NVMe at 8 vCPU / 16 GB against Raff's 320 GB - **Users outside the United States** — multiple data centers against Raff's single us-east region ## When you should choose Raff over Bluehost - **Applications that outgrow a hosting account** — Raff scales to 16 vCPU and 32 GB; Bluehost's VPS line ends at 8 vCPU and 16 GB, so outgrowing NVMe 16 means leaving the product - **APIs, containers and background jobs** — resize on demand through a `resize` API endpoint, plus Raff Apps from $3/month and managed Kubernetes with a free control plane ([VPS for Docker containers](/learn/guides/vps-for-docker-containers)) - **Database-backed products** — managed PostgreSQL, MySQL, Valkey, ClickHouse and Kafka from $7.99/month over private networking, instead of running your own on the VPS ([VPS for databases](/learn/guides/vps-for-databases)) - **Workloads that must recover cleanly** — Daily and Weekly backup schedules on a free storage pool, uncapped snapshots, 1–365 day retention, and block volumes at $0.08/GiB-month, all API-driven - **Teams that cannot prepay two years** — monthly or pay-as-you-go billing with a 14-day money-back guarantee; the longer Raff terms are optional rather than required - **24/7 human support** — live chat to the same engineers at any account size, first response typically under 10 minutes; Bluehost excludes 24/7 priority support from VPS plans ## Migrating from Bluehost to Raff 1. **Inventory the account, not just the server** — record the OS version, runtimes, database engines, cron jobs, and separately: which domains, mailboxes and certificates live in the Bluehost account. Those need a new home. 2. **Decide where email and domains go first** — Raff does not host either. Settle that before touching the server, because it is the step people discover too late. 3. **Size the Raff VM by workload, not by matching disk** — Bluehost includes more local NVMe, so decide what belongs on VM disk and what moves to block volumes or object storage. 4. **Provision and harden** — create the Raff VM with the same distribution, apply firewall rules, attach private networking before moving data. 5. **Move data in order, then test before DNS** — files with rsync or SCP, then database dumps, then uploads to object storage. Run the application against the Raff VM by hostname, check logs, take a snapshot once verified. 6. **Cut over and watch the term** — lower DNS TTL beforehand, switch, then confirm your Bluehost billing term. A 24-month prepaid term does not stop when you migrate. ## About Bluehost Bluehost is a US web hosting provider offering shared hosting, WordPress hosting, domains, email and a four-plan self-managed VPS line, aimed largely at website owners and agencies. Its VPS tiers run from 1 to 8 vCPU cores with unmetered bandwidth and multiple data centers. See [Bluehost VPS hosting](https://www.bluehost.com/hosting/vps) for current plans and terms. ## Conclusion: Bluehost or Raff? The comparison resolves across four measured axes: - **Price** — Bluehost is cheaper at every tier: $9.49 promotional and $11.99 renewal against Raff's $17.99 at 2 vCPU / 4 GB - **Price stability** — Raff charges the same rate indefinitely with no prepayment; Bluehost's NVMe 8 goes from $12.99 to $28.99 at renewal, a 123% step-up on $311.76 paid upfront - **Headroom** — Raff scales to 16 vCPU and 32 GB with on-demand resize; Bluehost's VPS line ends at 8 vCPU and 16 GB - **What surrounds the server** — Raff adds managed databases, object storage, Functions, Apps and Kubernetes on one account; Bluehost adds a domain, mailboxes and a hosting panel If you want the cheapest server to run a website that will look the same in two years, and you want email and a domain on the same bill, choose Bluehost. If the workload has to grow — resize without rebuilding, pass 16 GB of RAM, or sit next to a managed database or Kubernetes cluster — choose Raff. Raff runs 15,000+ VMs for 3,000+ customers and is rated 4.5/5 on Trustpilot, with a 99.9% uptime SLA in writing. --- ### Hostinger Alternative 2026: Pricing, Performance & Features URL: https://rafftechnologies.com/learn/compare/raff-vs-hostinger Description: Considering Hostinger? Raff is $27.99/mo for 2 vCPU, 8 GB and 160 GB NVMe with unmetered transfer on a 3 Gbps port. Hostinger is one of the largest hosting companies in the world, selling shared hosting, WordPress hosting, domains, email and a four-plan VPS line to millions of customers. Raff Technologies is a US cloud provider where the virtual machine is one product among several, alongside managed databases, object storage, Functions and Kubernetes on the same account. Both sell shared-vCPU VMs on AMD EPYC with NVMe storage, so the comparison is a fair one: Hostinger KVM 2 lists at $24.49/month for 2 vCPU and 8 GB, and the closest Raff plan is $27.99/month. The interesting differences are not in the server — they are in the transfer policy, the disk, and what happens when one machine is no longer enough. ## Hostinger VPS and Raff at a glance **Hostinger** sells four KVM VPS plans, all on AMD EPYC with NVMe storage and a 1 Gbps network. KVM 1 is 1 vCPU, 4 GB RAM, 50 GB and 4 TB of transfer; KVM 8 is 8 vCPU, 32 GB, 400 GB and 32 TB. Every plan includes free weekly backups, firewall management, public API access, an AI-assisted web terminal, and a free domain for the first year. Pricing runs on three levels, and it matters which one you compare. The **list price** is what the plan costs without a term — $19.49, $24.49, $42.99 and $73.99. The **advertised price** is a 24-month promotional rate at 63–70% off. After that term the plan **renews** at a third price: $11.99, $14.99, $28.99 and $49.99. This page compares list prices, with promo and renewal shown alongside. **Raff Technologies** runs 15,000+ VMs for 3,000+ customers from its us-east region, with a 99.9% uptime SLA backed by service credits, rated 4.5/5 on Trustpilot and 4.6/5 on G2. VMs run AMD EPYC with DDR5 ECC memory and NVMe storage in two lines: General Purpose with shared vCPU from $4.99/month, and CPU-Optimized with dedicated vCPU from $15.99/month, scaling to 16 vCPU and 32 GB. Every plan includes a 3 Gbps port with unmetered transfer, automated Daily or Weekly backup schedules, uncapped snapshots, firewall controls, private networking and full root access. Past the VM the catalogs diverge. Raff sells S3-compatible object storage at $7/month for 100 GB and 1 TB of egress, managed PostgreSQL, MySQL, Valkey, ClickHouse and Kafka from $7.99/month, managed Kubernetes with a free control plane and workers from $9.99/month, Functions with a free monthly tier, block volumes at $0.08/GiB-month, and Raff Apps from $3/month. Hostinger bundles the things a website needs — a domain, email, a control panel. ## Hostinger VPS pricing vs Raff pricing Hostinger KVM plans use shared vCPU cores, so the like-for-like Raff line is General Purpose. | Shape | Hostinger KVM list | Hostinger 24-mo promo → renewal | Raff General Purpose | |---|---|---|---| | 1 vCPU / 4 GB | **$19.49** — KVM 1, 50 GB NVMe, 4 TB, 1 Gbps | $6.49 → $11.99 | **$17.99** — 2 vCPU / 4 GB / 80 GB NVMe, unmetered, 3 Gbps | | 2 vCPU / 8 GB | **$24.49** — KVM 2, 100 GB NVMe, 8 TB, 1 Gbps | $8.99 → $14.99 | **$27.99** — 2 vCPU / 8 GB / 160 GB NVMe, unmetered, 3 Gbps | | 4 vCPU / 16 GB | **$42.99** — KVM 4, 200 GB NVMe, 16 TB, 1 Gbps | $12.99 → $28.99 | **$55.99** — 4 vCPU / 16 GB / 240 GB NVMe, unmetered, 3 Gbps | | 8 vCPU / 32 GB | **$73.99** — KVM 8, 400 GB NVMe, 32 TB, 1 Gbps | $25.99 → $49.99 | **$119.99** — 8 vCPU / 32 GB / 320 GB NVMe, unmetered, 3 Gbps | *Raff General Purpose against Hostinger KVM — both shared AMD EPYC on NVMe. Hostinger publishes no dedicated-vCPU VPS line, so every row above is shared against shared. Hostinger list, promotional and renewal prices read from Hostinger's live pricing page on 2026-08-18; the promotional rate requires a 24-month term.* At list price the two are close, and at the smallest shape Raff is cheaper: $17.99 buys 2 vCPU, 4 GB and 80 GB against KVM 1's $19.49 for 1 vCPU, 4 GB and 50 GB — twice the cores and 60% more disk for less money. Against the 24-month promotional rate Hostinger is substantially cheaper at every tier, and against the renewal rate it stays cheaper from KVM 2 upward. Hostinger also ships more RAM per core across the range. ### Bandwidth cost math Hostinger meters transfer; Raff does not. There is no per-GB overage to calculate, because Hostinger does not bill overage — it throttles. Once a plan reaches its monthly cap the connection drops to **10 Mbps for the remainder of the month**, then resets. | Monthly transfer | Raff 2 vCPU / 8 GB | Hostinger KVM 2 (8 TB cap) | |---:|---|---| | 1 TB | $27.99 · 3 Gbps | $24.49 · full 1 Gbps | | 5 TB | $27.99 · 3 Gbps | $24.49 · full 1 Gbps | | 8 TB | $27.99 · 3 Gbps | at cap | | 10 TB | $27.99 · 3 Gbps | **throttled to 10 Mbps** for the rest of the month | | 25 TB | $27.99 · 3 Gbps | **throttled to 10 Mbps** for the rest of the month | The cost of exceeding the cap is not money, it is a 100x reduction in port speed until the calendar turns. For a media-heavy site, a backup target, or an API with a traffic spike, that is a harder failure than an overage line on an invoice. Hostinger's own guidance is to monitor usage in hPanel and upgrade the plan if the cap is reached repeatedly. The allowances are generous for most websites — 8 TB covers the large majority of small-business traffic. This matters at the tail, not the median. ### Automated backups Hostinger includes free weekly backups on VPS plans. Raff includes a free backup and snapshot storage pool — 50 GB per account plus 10–15% of each VM's disk — and you choose the schedule: Daily, Weekly, or both running together, with retention from 1 to 365 days and uncapped snapshots. Storage above the pool is $0.06/GB-month. Weekly-only backups mean a worst-case recovery point of seven days. Match the schedule to how much work you can afford to lose. ## Hostinger VPS performance vs Raff This is the only comparison on this site backed by a paid head-to-head test rather than third-party data, and it does not flatter Raff on every axis. ### Methodology Measured 13 April 2026 on Ubuntu 24.04, single-pass: Raff General Purpose 2 vCPU / 4 GB in us-east against Hostinger KVM 2 in Boston, which carried roughly twice the RAM. Paid at standard rates by Raff Technologies, with no sponsorship or rebate from Hostinger. † † Raff publishes a 3 Gbps port on 10 Gbps host uplinks; 9,574 Mbps is a peak across parallel streams. ### Results | Benchmark | Raff GP 2 vCPU | Hostinger KVM 2 | Notes | |---|---:|---:|---| | Geekbench 6 single-core | **2,266** | 1,976 | Raff 15% higher | | Geekbench 6 multi-core | **4,057** | 3,583 | Raff 13% higher | | sysbench CPU single-thread | **2,171 events/s** | 1,677 events/s | Raff 29% faster | | sysbench CPU multi-thread | **4,320 events/s** | 3,350 events/s | Raff 29% faster | | sysbench memory read | **17.79 GiB/s** | 11.15 GiB/s | Raff 59% faster | | sysbench memory write | **11.42 GiB/s** | 4.60 GiB/s | Raff 2.5x faster | | sysbench memory write 1MB block | 47.08 GiB/s | **48.42 GiB/s** | Hostinger 3% higher | | fio 4K random read | 48.67k IOPS | **60.5k IOPS** | Hostinger 24% faster | | fio 4K random write | 48.80k IOPS | **60.7k IOPS** | Hostinger 24% faster | | fio 64K random read | 22.81k IOPS | **49.59k IOPS** | Hostinger 2.2x faster | | fio 64K random write | 22.93k IOPS | **49.85k IOPS** | Hostinger 2.2x faster | | sysbench fileio random read 4K | 52.31 MiB/s | **143.42 MiB/s** | Hostinger 2.7x faster | | sysbench fileio sequential read 128K | 1,730 MiB/s | **2,616 MiB/s** | Hostinger 51% faster | | sysbench fileio sequential write 128K | 664.85 MiB/s | **990.77 MiB/s** | Hostinger 49% faster | | iperf3 to NYC download | **3,635 Mbps** | 1,024 Mbps | Raff 3.5x faster | | iperf3 to NYC upload | **9,574 Mbps** | 1,034 Mbps | Raff 9.3x faster | | iperf3 to London download | **2,693 Mbps** | 959 Mbps | Raff 2.8x faster | | iperf3 to Los Angeles download | **3,430 Mbps** | 962 Mbps | Raff 3.6x faster | | Rails saturation point | ≈60–70 req/s | ≈60–70 req/s | Comparable | | Rails timeouts at 70 req/s | **729 of 20,801** | 1,365 of 21,000 | Raff fewer errors at saturation | ### What this tells you The split is clean, and it runs both ways. **Raff wins CPU, memory and network.** 29% faster sysbench CPU on both single and multi-threaded runs, 2.5x faster default-block memory write, and 3.5x to 9.3x higher iperf3 throughput. The network gap tracks the published port speeds — 3 Gbps against 1 Gbps — so it is structural rather than tuning. **Hostinger wins disk, and not marginally:** 24% higher 4K random IOPS, 2.2x at 64K, 2.7x on sysbench fileio random read, and roughly 50% higher sequential read and write. That is architecture, not hardware quality. Hostinger attaches local NVMe directly to the host, so a small write lands and is done. Raff runs distributed block storage across an NVMe cluster, so the same write crosses the network and is replicated before it is acknowledged. No amount of tuning on Raff closes that particular gap. What the distributed model buys is everything around the disk: data replicated rather than pinned to one machine, snapshots and backups taken at the storage layer, and a VM that changes plan by stopping and restarting rather than being rebuilt and restored. At application level the two saturated at the same point, around 60–70 requests per second on a database-heavy Rails workload, with Raff returning about half the timeouts at saturation. Read it as a trade: Raff for CPU, memory and egress-heavy work; Hostinger for disk-bound work. ## Hostinger vs Raff: features and reliability ### Compute Hostinger offers four shared-vCPU KVM shapes from 1 to 8 cores and 4 to 32 GB RAM, shipping more RAM per core at every tier — 4 GB on a single core, 32 GB on eight. Raff offers General Purpose from $4.99/month and CPU-Optimized dedicated vCPU from $15.99/month, on AMD EPYC with DDR5 ECC memory, scaling to 16 vCPU and 32 GB, and pairs cores with memory more evenly. Raff plans resize on demand: stop the VM, switch plan, restart, with the difference settled to the account balance and a `resize` API endpoint for CPU, RAM and disk. ### Networking Raff includes a 3 Gbps port with unmetered transfer, private networking, VPC, firewall controls and site-to-site VPN gateways. Hostinger includes a 1 Gbps network with metered transfer and firewall management. ### Storage Both use NVMe, in the two different arrangements described in the benchmark section — Hostinger local, Raff distributed. Hostinger includes 50 to 400 GB by plan; Raff includes 80 to 640 GB on the matched shapes, and separates storage into VM disk, block volumes at $0.08/GiB-month that resize independently, and S3-compatible object storage at $7/month for 100 GB and 1 TB of egress. ### Support Raff provides 24/7 human support through live chat, with a first response typically under 10 minutes. No bots triaging you first, and no support tier to buy: a single $4.99 VM reaches the same engineers as a hundred production machines, through the same queue. ### Platform A VM is rarely the whole requirement. An application needs a database, somewhere to put uploads, background jobs, and eventually a way to scale past one server. On Raff those are products on the same account: managed PostgreSQL, MySQL, Valkey, ClickHouse and Kafka from $7.99/month, object storage at $7/month, Functions with a free tier of 100,000 GB-seconds and 10,000 vCPU-seconds per month, Raff Apps from $3/month, and managed Kubernetes with a free control plane. They connect over private networking, share one API, one CLI and one bill. Hostinger's VPS bundles hosting-account conveniences instead — a free domain for the first year, an AI web terminal, hPanel — which are genuinely useful if the VPS is hosting websites rather than backing an application. The honest counter-argument is that you can run Postgres on the VPS itself for free. You can, and on a 32 GB KVM 8 it will run well. What you are then operating is backups, restore testing, failover, point-in-time recovery and version upgrades. If that work sits inside your team's capability and time budget, Hostinger is cheaper. If it does not, the question is not which VM costs less this month. ## When you should choose Hostinger over Raff - **Disk-bound databases and write-heavy queues** — 24% higher 4K random IOPS and 2.2x at 64K in paid head-to-head testing - **Websites with a domain, email and panel in one place** — a free domain for the first year, hPanel and an AI web terminal, none of which Raff offers ([VPS for web hosting](/learn/guides/vps-for-web-hosting)) - **Memory-heavy single servers on a budget** — 32 GB at 8 cores for $73.99 list, or $25.99 on a 24-month term - **Teams willing to commit two years** — promotional pricing at 63–70% off is genuinely cheaper than Raff at every tier ## When you should choose Raff over Hostinger - **Egress-heavy applications** — 9.3x higher measured iperf3 upload, unmetered on a 3 Gbps port, against a cap that throttles to 10 Mbps ([VPS for application hosting](/learn/guides/vps-for-application-hosting)) - **CPU and memory-bound services** — 29% faster sysbench CPU and 2.5x faster memory write, which is what caches, queues and API workers are bound by - **Stacks that outgrow one server** — managed PostgreSQL, MySQL, Valkey, ClickHouse and Kafka from $7.99/month, object storage at $7/month, Functions and Kubernetes on the same account over private networking ([VPS for databases](/learn/guides/vps-for-databases)) - **Workloads needing a tighter recovery point** — Daily and Weekly schedules together with 1–365 day retention, against weekly-only backups - **Buyers who will not prepay two years** — monthly or pay-as-you-go billing with a 14-day money-back guarantee; longer Raff subscriptions are optional - **24/7 human support** — live chat to the same engineers at every account size, first response typically under 10 minutes ## Migrating from Hostinger to Raff 1. **Check your transfer profile first** — if you are near a Hostinger cap, that is the strongest single reason to move; if you use 200 GB a month, it is not a factor at all. 2. **Right-size on utilisation, not RAM** — Hostinger ships more memory per core. Measure what the workload actually uses before matching 32 GB with 32 GB. 3. **Provision and harden** — create the Raff VM on the same distribution, apply firewall rules, attach private networking before moving data. 4. **Move data in order** — files with rsync or SCP, then database dumps, then uploads and static assets to object storage. 5. **Test disk-bound paths explicitly** — Hostinger measured faster on small-block random I/O, and that is architectural rather than tunable. If your application is disk-bound, benchmark it on Raff before committing. 6. **Cut over and check the term** — lower DNS TTL beforehand, switch, then confirm your Hostinger billing term. A 24-month promotional term continues after migration, and the free domain is tied to that account. ## About Hostinger Hostinger is a hosting provider founded in 2004 and headquartered in Kaunas, Lithuania, offering shared hosting, WordPress hosting, domains, email and a four-plan KVM VPS line from data centers across several regions. See [Hostinger VPS hosting](https://www.hostinger.com/vps-hosting) for current plans and terms. ## Conclusion: Hostinger or Raff? The comparison resolves across four measured axes: - **Disk** — Hostinger wins, 24% higher 4K random IOPS and 2.2x at 64K - **CPU, memory and network** — Raff wins, 29% faster sysbench CPU, 2.5x memory write, 9.3x iperf3 upload - **Transfer** — Raff unmetered at 3 Gbps; Hostinger capped at 4–32 TB then throttled to 10 Mbps until the month resets - **Price** — Hostinger is cheaper on promotional and renewal pricing; at list price the two are close, and Raff is cheaper at the smallest shape, $17.99 for 2 vCPU / 4 GB / 80 GB against $19.49 for 1 vCPU / 4 GB / 50 GB If your workload is disk-bound, or you want a website, domain and panel on one bill and will commit to two years, choose Hostinger. If your workload is CPU, memory or egress-bound, or it will need a managed database, object storage or Functions next to the VM, choose Raff. Raff runs 15,000+ VMs for 3,000+ customers and is rated 4.5/5 on Trustpilot, with a 99.9% uptime SLA in writing. --- ### Netcup Alternative 2026: Pricing, Performance & Features URL: https://rafftechnologies.com/learn/compare/raff-vs-netcup Description: Considering Netcup? Raff is $17.99/mo for 2 vCPU, 4 GB and 80 GB NVMe from us-east, with no setup fee and 24/7 support. Netcup is a German hosting provider with a reputation for selling more hardware per euro than almost anyone in Europe. Raff Technologies is a US cloud provider where [cloud servers](/products/raff-vm) are one product among several, alongside managed databases, object storage, Functions and Kubernetes on the same account. On raw specifications this is not a close comparison: Netcup VPS 500 G12 lists 2 vCores, 4 GB DDR5 ECC and 128 GB NVMe for €5.91/month including VAT, while the closest Raff plan is $17.99/month with 80 GB. Both offer US hosting, both use DDR5 ECC and NVMe. What differs is what runs beside the server, and who operates it. ## Netcup VPS and Raff at a glance **Netcup** sells two server lines. **VPS** uses shared vCores and is the volume product; **Root Server** provides dedicated cores. Alongside them it sells web hosting, domains and related services. The current VPS generation is the G12 series, running from VPS 500 G12 at 2 vCores, 4 GB DDR5 and 128 GB NVMe up to VPS 8000 G12 at 16 vCores, 64 GB and 2 TB. Every plan includes traffic, copy-on-write snapshots and a remote console, on DDR5 ECC memory and NVMe storage. Netcup operates data centers in **Vienna, Nuremberg, Amsterdam, Manassas (USA) and Singapore** — a wider footprint than Raff's single us-east region, including a US East presence. The location is chosen on the product page before ordering, and Netcup does not list a location surcharge: the same plan costs the same in Manassas as in Nuremberg. Billing is either a 12-month term or hourly with no minimum commitment, and listed prices **include 19% German VAT**; the rate varies by the country you select. **Raff Technologies** runs 15,000+ VMs for 3,000+ customers from its us-east region, with a 99.9% uptime SLA backed by service credits, rated 4.5/5 on Trustpilot and 4.6/5 on G2. VMs run AMD EPYC with DDR5 ECC memory and NVMe storage in two lines: General Purpose with shared vCPU from $4.99/month, and CPU-Optimized with dedicated vCPU from $15.99/month, scaling to 16 vCPU and 32 GB. Every plan includes a 3 Gbps port with unmetered transfer, automated Daily or Weekly backup schedules, uncapped snapshots, firewall controls, private networking and full root access, with no setup fee and no term. Past the VM, Raff sells S3-compatible object storage at $7/month for 100 GB and 1 TB of egress, managed PostgreSQL, MySQL, Valkey, ClickHouse and Kafka from $7.99/month, managed Kubernetes with a free control plane and workers from $9.99/month, Functions with a free monthly tier, block volumes at $0.08/GiB-month, and Raff Apps from $3/month. ## Netcup VPS pricing vs Raff pricing Netcup VPS uses shared vCores, so the like-for-like Raff line is General Purpose. | Shape | Netcup VPS G12 | Netcup ex-VAT | Raff General Purpose | |---|---|---|---| | 2 cores / 4 GB | **€5.91** — VPS 500, 128 GB NVMe | €4.97 ≈ **$5.76** | **$17.99** — 2 vCPU / 4 GB / 80 GB NVMe | | 4 cores / 8 GB | **€10.37** — VPS 1000, 256 GB NVMe | €8.71 ≈ **$10.10** | **$33.99** — 4 vCPU / 8 GB / 160 GB NVMe | | 8 cores / 16 GB | **€19.25** — VPS 2000, 512 GB NVMe | €16.18 ≈ **$18.75** | **$71.99** — 8 vCPU / 16 GB / 240 GB NVMe | | 12 cores / 32 GB | **€32.41** — VPS 4000, 1 TB NVMe | €27.24 ≈ **$31.57** | **$109.99** — 12 vCPU / 24 GB / 320 GB NVMe | | 16 cores / 64 GB | **€47.95** — VPS 8000, 2 TB NVMe | €40.29 ≈ **$46.71** | **$139.99** — 16 vCPU / 32 GB / 320 GB NVMe | *Raff General Purpose against Netcup VPS — both shared vCores. Raff CPU-Optimized from $15.99/mo is the match for Netcup Root Server. Netcup list prices read 2026-08-18 and include 19% German VAT; the ex-VAT column is the figure a customer outside the EU is more likely to pay, converted at €1 = $1.1593 (ECB, 2026-08-17). Confirm your own VAT position with Netcup.* **Netcup wins on price and on specifications, decisively.** Comparing ex-VAT, Raff is 200% to 284% more expensive — and Netcup ships more of everything: 128 GB against 80 GB at the entry shape, 2 TB against 640 GB at the top, and 64 GB of RAM at 16 cores where Raff sells 32 GB at any price. There is no reading of this table where Raff is the value option, and this page will not pretend otherwise. The rest of the comparison is about what the extra money buys, and for a large share of readers the honest answer will be "nothing you need." ### Netcup's Root Server line for reference Netcup also sells **Root Server**, with dedicated cores rather than shared vCores. The like-for-like Raff line there is CPU-Optimized, and the gap is wider than on the shared comparison: | Shape | Netcup Root Server | Netcup ex-VAT | Raff CPU-Optimized | |---|---|---|---| | 4 dedicated / 8 GB | **€12.79** — RS 1000, 256 GB NVMe | ≈ **$12.46** | **$60.99** at 4 vCPU / 4 GB / 80 GB | | 8 dedicated / 16 GB | **€21.43** — RS 2000, 512 GB NVMe | ≈ **$20.88** | **$144.99** at 8 vCPU / 16 GB / 180 GB | | 12 dedicated / 32 GB | **€39.92** — RS 4000, 1 TB NVMe | ≈ **$38.89** | no Raff plan at 32 GB | | 16 dedicated / 64 GB | **€71.36** — RS 8000, 2 TB NVMe | ≈ **$69.52** | **$288.99** at 16 vCPU / 32 GB / 360 GB | Dedicated cores on Netcup cost less than shared vCPU on Raff. If guaranteed CPU allocation is what you are buying, Netcup Root Server is the cheaper way to buy it, and by a wide margin. ### Term and billing Netcup offers a 12-month term or hourly billing with no minimum commitment, and lists prices including 19% German VAT — the applicable rate depends on the country you select at checkout. Raff offers monthly, 1-year, and 2-year subscriptions in USD, plus pay-as-you-go billing from a prepaid balance, and a 14-day money-back guarantee. Confirm any setup or one-off fees with Netcup at checkout for the term you choose. ### Bandwidth Neither provider meters standard outbound transfer. Netcup includes traffic on its VPS plans; Raff includes unmetered transfer on a 3 Gbps port. Netcup does not publish a per-plan port speed on its VPS page, so this is not a comparison worth resting anything on. ### Automated backups Netcup includes snapshots on VPS plans. Raff includes a free backup and snapshot storage pool — 50 GB per account plus 10–15% of each VM's disk — with Daily and Weekly schedules you configure, retention from 1 to 365 days, and uncapped snapshots. Storage above the pool is $0.06/GB-month. Confirm Netcup's current backup scheduling and retention options directly, as they differ from snapshot-only workflows. ## Netcup VPS performance vs Raff ### Methodology Raff figures are internal, measured March–May 2026 on a 2 vCPU / 4 GB shared instance. Netcup figures are third-party, from VPSBenchmarks, on an RS 1000 G12 with four **dedicated** cores in Manassas, Virginia — same region as Raff's us-east. Netcup states its VPS line carries no CPU guarantee, so a VPS would be expected to score at or below these numbers. ### Results | Metric | Raff GP (2 shared vCPU) | Netcup RS 1000 G12 (4 dedicated) | Notes | |---|---:|---:|---| | Geekbench 6 single-core | **2,266** | 1,630 | Raff 39% higher | | Geekbench 6 multi-core | 4,057 (2 vCPU) | **5,130** (4 cores) | Netcup higher with twice the cores | | fio 4K read, 50/50 mix | **48,670 IOPS** | 37,250 IOPS | Raff 31% higher | | fio 1M sequential read | **2,491 MB/s** | 1,441 MB/s | Raff 73% higher | | fio 1M sequential write | 1,257 MB/s | **1,538 MB/s** | Netcup 22% higher | | iperf3 to NYC download | **3,635 Mbps** | 2,417 Mbps | Raff 50% higher | | iperf3 to NYC upload † | **9,574 Mbps** | 2,796 Mbps | Raff 3.4x higher | | iperf3 to Los Angeles download | **3,430 Mbps** | 2,099 Mbps | Raff 63% higher | † Raff publishes a 3 Gbps port on 10 Gbps host uplinks; 9,574 Mbps is a peak across parallel streams. ### What this tells you **Raff's shared vCPU scores 39% higher single-core than Netcup's guaranteed dedicated cores.** That is the most useful line in the table, because Netcup's VPS line — the one priced against Raff above — carries no CPU guarantee at all. If a Root Server measures 1,630, a VPS on the same platform is unlikely to exceed it. Raff also leads on random IOPS by 31% on the same 50/50 job, on sequential read by 73%, and on network by 50% to 3.4x within the same region. **Netcup leads on sequential write by 22%**, and on multi-core aggregate because it ships twice the cores at a third of the price. None of which changes the arithmetic. Netcup RS 1000 G12 is €12.79 including VAT — about $12.46 ex-VAT — for four dedicated cores, 8 GB and 256 GB. The closest Raff CPU-Optimized plan is $72.99. Raff is faster per core and faster on the network; Netcup is roughly four times cheaper and gives you twice the cores and twice the disk. **Location matters more than any of it.** Netcup offers Manassas at the same price as its German locations, so a US buyer should choose Manassas. Measured from a *German* Netcup host, throughput to US cities falls to 93 Mbps to New York and 35 Mbps to Los Angeles against 898 Mbps to Paris — picking the default European location will cost more performance than every CPU difference on this page combined. ## Netcup vs Raff: features and reliability ### Compute Netcup VPS offers five shared-vCore shapes from 2 to 16 cores and 4 to 64 GB DDR5, with more memory per core than Raff sells at any tier. Netcup Root Server offers dedicated cores for workloads that need them. Raff offers General Purpose from $4.99/month and CPU-Optimized dedicated vCPU from $15.99/month, on AMD EPYC with DDR5 ECC memory, scaling to 16 vCPU and 32 GB, with on-demand resize: stop the VM, switch plan, restart, with the difference settled to your account balance and a `resize` API endpoint for CPU, RAM and disk. ### Networking Raff includes a 3 Gbps port, private networking, VPC, firewall controls and site-to-site VPN gateways. Netcup includes traffic on its VPS plans; port speed is not published per plan. ### Storage Netcup includes substantially more local NVMe at every tier — 128 GB against Raff's 80 GB at the entry shape, 2 TB against 640 GB at the top. Raff separates storage into VM disk, block volumes at $0.08/GiB-month that resize independently of the VM, and S3-compatible object storage at $7/month for 100 GB and 1 TB of egress. ### Support and billing Raff provides 24/7 human support through live chat, with a first response typically under 10 minutes. No bots triaging you first, and no support tier to buy: a single $4.99 VM reaches the same engineers as a hundred production machines, through the same queue. Billing is in USD with no VAT calculation and no setup fee. Netcup's prices include 19% German VAT and its standard term is 12 months, so the number you compare depends on your VAT position and how long you commit. Confirm Netcup's current support channels and response targets directly. ### Platform A VM is rarely the whole requirement. An application needs a database, somewhere to put uploads, background jobs, and eventually a way to scale past one server. On Raff those are products on the same account: managed PostgreSQL, MySQL, Valkey, ClickHouse and Kafka from $7.99/month, object storage at $7/month, Functions with a free tier of 100,000 GB-seconds and 10,000 vCPU-seconds per month, Raff Apps from $3/month, and managed Kubernetes with a free control plane. They connect over private networking, share one API, one CLI and one bill. Netcup sells servers, hosting and domains — a database, a queue and an object store are yours to assemble and operate. The honest counter-argument is strong here: a 32 GB Netcup VPS at €32.41 will run Postgres, Redis and your application together with room to spare, for a third of what the equivalent Raff stack costs. What you are then operating is backups, restore testing, failover, point-in-time recovery and version upgrades. If that work sits inside your team's capability and time budget, Netcup is the better buy and it is not close. ## When you should choose Netcup over Raff - **Wider choice of regions** — Vienna, Nuremberg, Amsterdam, Manassas in the US and Singapore, against Raff's single us-east - **Maximum specifications per euro** — 128 GB NVMe at the entry shape, 2 TB at the top, and 64 GB RAM at 16 cores that Raff does not sell at any price - **Memory-heavy and storage-heavy workloads** — self-hosted media, backup targets, analytics, large dev and CI fleets - **Teams comfortable operating their own data services** — a single large VPS running database, cache and application is genuinely cheaper - **Committed 12-month budgets** — the 12-month term carries no setup fee and the lowest monthly rate ## When you should choose Raff over Netcup - **Managed data services beside the VM** — PostgreSQL, MySQL, Valkey, ClickHouse and Kafka from $7.99/month with backups, point-in-time recovery and failover operated for you - **Stacks that outgrow one server** — managed PostgreSQL, MySQL, Valkey, ClickHouse and Kafka from $7.99/month, object storage at $7/month, Functions and Kubernetes on the same account over private networking ([VPS for databases](/learn/guides/vps-for-databases)) - **Teams without database operations capacity** — managed engines with backups, PITR and failover handled, instead of self-hosting on a large VPS - **Buyers who want flexible USD billing** — monthly, 1-year, 2-year, or pay-as-you-go options, plus a 14-day money-back guarantee - **Simple USD billing** — no VAT position to work out, no exchange-rate variance on the invoice - **24/7 human support** — live chat to the same engineers at any account size, first response typically under 10 minutes ## Migrating from Netcup to Raff 1. **Ask what you are actually buying** — if you want a cheap capable server, Netcup already sells one in the US. This migration only makes sense if you want the managed services beside it. 2. **Right-size on utilisation, not specifications** — Netcup ships far more RAM and disk than most workloads use. Measure actual consumption before matching 64 GB with 64 GB, because you cannot: Raff's ceiling is 32 GB. 3. **Plan the storage gap** — Netcup includes 128 GB to 2 TB locally. Decide what belongs on VM disk, what moves to block volumes at $0.08/GiB-month, and what belongs in object storage. 4. **Provision and harden** — create the Raff VM on the same distribution, apply firewall rules, attach private networking before moving data. 5. **Move data in order** — files with rsync or SCP, then database dumps, then static assets to object storage. Keep the Netcup VPS running throughout. 6. **Cut over and check the term** — lower DNS TTL beforehand, switch, then confirm your Netcup contract. A 12-month term continues after you migrate. ## About Netcup Netcup is a German hosting provider offering VPS, Root Server, web hosting, domains and related infrastructure services, serving customers from data centers in Vienna, Nuremberg, Amsterdam, Manassas in the United States and Singapore. It is known for high memory and storage allocations at low monthly prices. See [Netcup VPS](https://www.netcup.com/en/server/vps) for current plans and terms. ## Conclusion: Netcup or Raff? The comparison resolves across four axes: - **Price and specifications** — Netcup wins decisively: €5.91 (about $5.76 ex-VAT) against $17.99 at the entry shape, with more RAM and more disk at every tier - **Regions** — Netcup wins: Vienna, Nuremberg, Amsterdam, Manassas in the US and Singapore, against Raff's single us-east - **Platform** — Raff adds managed databases, object storage, Functions, Apps and Kubernetes on one account; Netcup sells servers, hosting and domains - **Billing** — Raff offers USD subscriptions or prepaid pay-as-you-go; Netcup lists VAT-inclusive 12-month or hourly billing If you want the most hardware per euro, a choice of regions, and you are comfortable running your own data services, choose Netcup — it is the better buy on price, specifications and geography, and the gap is large. Choose Raff only if you want managed databases, object storage and Functions operated for you beside the VM, with 24/7 support and flexible USD billing options. Raff runs 15,000+ VMs for 3,000+ customers and is rated 4.5/5 on Trustpilot, with a 99.9% uptime SLA in writing. --- ### DigitalOcean Alternative 2026: Droplet Pricing vs Raff URL: https://rafftechnologies.com/learn/compare/raff-vs-digitalocean Description: DigitalOcean's 2 vCPU / 4 GB / 80 GB Basic Droplet is $24/mo; Raff's matched VM is $17.99. Compare pricing, bandwidth, regions, databases, and support. DigitalOcean is one of the best-known developer clouds, with Droplets, managed databases, Kubernetes, App Platform, Spaces object storage, Functions and GPU instances, backed by a documentation library most providers cannot match. Raff Technologies runs the same shape of platform — VMs, managed databases, Kubernetes, object storage, Functions and Apps on one account — from a single us-east region. The two are close enough in scope that the comparison comes down to price per unit and which parts of the catalog you actually need. At the matched shape, a DigitalOcean Basic Droplet with 2 vCPU, 4 GB and 80 GB is $24/month; the identical Raff plan is $17.99. ## DigitalOcean VPS and Raff at a glance **DigitalOcean** sells four Droplet families. **Basic** uses shared vCPU from $4/month; **CPU-Optimized**, **General Purpose** and **Memory-Optimized** all use dedicated vCPU at different memory ratios. Every Droplet includes a metered transfer allowance — 500 GB at the entry plan rising to 11 TB — with overage at **$0.01 per GiB**. Around the Droplet sits a deep catalog: Spaces object storage from $5/month with a built-in CDN, App Platform from $0/month, Managed Databases from $15/month covering PostgreSQL, MySQL, Valkey, MongoDB, Kafka and OpenSearch, Kubernetes from $12/month with a free control plane, Functions with 90,000 GiB-seconds free per month, block storage volumes, load balancers, and GPU Droplets. DigitalOcean also operates data centers across North America, Europe and Asia, and its tutorial library is a genuine asset that no comparison should pretend away. **Raff Technologies** runs 15,000+ VMs for 3,000+ customers from us-east, with a 99.90% monthly uptime SLA backed by service credits, rated 4.5/5 on Trustpilot and 4.6/5 on G2. VMs run AMD EPYC with DDR5 ECC memory and NVMe storage in two lines: General Purpose with shared vCPU from $4.99/month, and CPU-Optimized with dedicated vCPU from $15.99/month, scaling to 16 vCPU and 32 GB. Every plan includes a 3 Gbps port with **unmetered** transfer, automated Daily or Weekly backup schedules, uncapped snapshots, firewall controls, private networking and full root access. Raff's catalog covers managed PostgreSQL, MySQL, Valkey, ClickHouse and Kafka from $7.99/month, S3-compatible object storage at $7/month for 100 GB and 1 TB of egress, managed Kubernetes with a free control plane and workers from $9.99/month, Functions with a free monthly tier, block volumes at $0.08/GiB-month, and Raff Apps from $3/month. ## DigitalOcean VPS pricing vs Raff pricing DigitalOcean Basic Droplets use shared vCPU, which matches Raff General Purpose. The dedicated families match Raff CPU-Optimized. Both tables below compare like with like. ### Shared vCPU: Raff General Purpose against DigitalOcean Basic | Shape | Raff General Purpose | DigitalOcean Basic | |---|---|---| | 1 vCPU / 1 GB | **$4.99** — 25 GB, unmetered | $6.00 — 25 GB, 1 TB transfer | | 1 vCPU / 2 GB | **$8.99** — 50 GB, unmetered | $12.00 — 50 GB, 2 TB transfer | | 2 vCPU / 2 GB | **$12.99** — 40 GB, unmetered | $18.00 — 60 GB, 3 TB transfer | | 2 vCPU / 4 GB | **$17.99** — 80 GB, unmetered | $24.00 — 80 GB, 4 TB transfer | | 4 vCPU / 8 GB | **$33.99** — 160 GB, unmetered | $48.00 — 160 GB, 5 TB transfer | | 8 vCPU / 16 GB | **$71.99** — 240 GB, unmetered | $96.00 — 320 GB, 6 TB transfer | Three of those rows are **identical on disk as well as cores and memory** — 80 GB, 160 GB and 320 GB — which makes them unusually clean comparisons. Raff is **25% to 29% cheaper** across the range. ### Dedicated vCPU: Raff CPU-Optimized against DigitalOcean CPU-Optimized | Shape | Raff CPU-Optimized | DigitalOcean CPU-Optimized | |---|---|---| | 2 vCPU / 4 GB | **$36.99** — 80 GB | $42.00 — 25 GB | | 4 vCPU / 8 GB | **$72.99** — 120 GB | $84.00 — 50 GB | | 8 vCPU / 16 GB | **$144.99** — 180 GB | $168.00 — 100 GB | Raff is **12% to 14% cheaper** on dedicated vCPU, with two to three times the included disk at every shape. *DigitalOcean prices read from digitalocean.com on 2026-08-20. DigitalOcean also sells General Purpose and Memory-Optimized Droplets at higher memory ratios — from $63/month at 2 vCPU / 8 GB and $84/month at 2 vCPU / 16 GB — where Raff's closest plans are $27.99 and, above 32 GB, nothing at all.* ### Bandwidth cost math This is where the two models diverge most. DigitalOcean meters transfer per Droplet and bills **$0.01 per GiB** beyond the allowance. Raff includes unmetered transfer on a 3 Gbps port. | Monthly egress on a 2 vCPU / 4 GB VM | Raff | DigitalOcean Basic (4 TB included) | |---:|---|---| | 2 TB | $17.99 | $24.00 | | 4 TB | $17.99 | $24.00 | | 8 TB | **$17.99** | $24.00 + $40.96 = **$64.96** | | 20 TB | **$17.99** | $24.00 + $163.84 = **$187.84** | At 20 TB the DigitalOcean bill is more than thirteen times Raff's. Below the allowance the gap is just the plan price; above it, the gap compounds. DigitalOcean does pool allowances across Droplets in an account, which softens this for fleets — but the per-GiB rate still applies once the pool is exhausted. ### Automated backups DigitalOcean sells Droplet backups as an add-on priced as a percentage of the Droplet cost, and snapshots per GB. Raff includes a free backup and snapshot storage pool — 50 GB per account plus 10–15% of each VM's disk — with Daily and Weekly schedules you configure, retention from 1 to 365 days, and uncapped snapshots. Storage above the pool is $0.06/GB-month. ## DigitalOcean VPS performance vs Raff ### Methodology The only head-to-head data Raff holds against DigitalOcean is from **May 2026**, and it compared a **dedicated-vCPU** Raff benchmark VM against a **shared-vCPU** DigitalOcean Basic Droplet in a different region, single-pass. That class mismatch is disqualifying for a provider-level claim, so the numbers below are published as a record of that test window rather than as evidence that Raff General Purpose outperforms DigitalOcean Basic today. A matched re-run is outstanding. ### Historical results — May 2026 | Benchmark | Raff (dedicated vCPU) | DigitalOcean Basic (shared vCPU) | |---|---:|---:| | sysbench CPU 1-thread | 1,663 events/s | 364 events/s | | sysbench CPU 2-thread | 3,338 events/s | 744 events/s | | Memory sequential read | 131,925 MiB/s | 36,709 MiB/s | | Memory sequential write | 37,231 MiB/s | 16,449 MiB/s | | Disk 4K random read QD32 | 74,562 IOPS | 40,679 IOPS | | Disk 4K random write QD32 | 52,450 IOPS | 11,241 IOPS | | Disk 1M sequential read | 2,376 MiB/s | 2,224 MiB/s | | Redis SET | 157,356 req/s | 61,538 req/s | | SQLite inserts | 331,110/s | 172,398/s | ### What the results tell us Read the gaps as what they are: a dedicated core will beat a shared core, and most of the CPU and Redis spread above is that difference rather than a platform difference. The one row worth attention is **1M sequential read at 2,376 against 2,224 MiB/s** — nearly level, which suggests the two platforms' sequential disk throughput is comparable even when the CPU classes are not. If you are choosing on measured performance, benchmark your own workload on both. Raff's General Purpose line is the honest comparison against a Basic Droplet, and that pairing has not been tested. ## DigitalOcean vs Raff: features and reliability ### Droplets and compute DigitalOcean scales far past Raff: up to 48 vCPU and 96 GB on CPU-Optimized, 40 vCPU and 160 GB on General Purpose, and 32 vCPU with 256 GB on Memory-Optimized, plus GPU Droplets. Raff stops at 16 vCPU and 32 GB. Below that ceiling Raff resizes on demand — stop the VM, switch plan, restart, with the difference settled to the account balance and a `resize` API endpoint for CPU, RAM and disk. ### Networking and bandwidth Raff includes a 3 Gbps port with unmetered transfer, private networking, VPC, firewall controls and site-to-site VPN gateways. DigitalOcean includes metered transfer pooled across the account at $0.01/GiB overage, VPC, cloud firewalls, and load balancers from $12/month. Raff does not charge separately for load balancing. ### Storage and object storage Raff separates storage into VM disk, block volumes at **$0.08/GiB-month**, and S3-compatible object storage at **$7/month for 100 GB with 1 TB of egress**. DigitalOcean Spaces is **$5/month for 250 GiB with 1 TiB of transfer**, with additional storage at $0.02/GiB and transfer at $0.01/GiB — and a **built-in CDN at no extra charge**. On object storage DigitalOcean is straightforwardly the better deal: more storage, lower price, and a CDN Raff does not offer. ### Managed databases Raff runs PostgreSQL, MySQL, Valkey, ClickHouse and Kafka **from $7.99/month**. DigitalOcean runs PostgreSQL, MySQL, Valkey, MongoDB, Kafka and OpenSearch **from $15/month**, with free daily backups and automated failover. Raff is roughly 47% cheaper at entry and adds ClickHouse. DigitalOcean adds MongoDB and OpenSearch, which Raff does not offer at all. ### Kubernetes and App Platform Both offer managed Kubernetes with a **free control plane** — DigitalOcean from $12/month for worker capacity, Raff from $9.99/month. App Platform is a real DigitalOcean advantage: it starts at **$0/month** with a free tier for static sites, against Raff Apps from $3/month. If you deploy small apps and static sites, DigitalOcean's free tier is not something Raff matches. ### Functions DigitalOcean Functions includes **90,000 GiB-seconds per month free**, then $0.0000185 per GiB-second, with invocations not billed separately and a **100 ms minimum billed runtime** per invocation. Raff Functions meters memory and active CPU separately, with a free tier of **100,000 GB-seconds and 10,000 vCPU-seconds per month**, and bills warm invocations at 30% of the standard rate. The free tiers are close, and the metering differs — DigitalOcean charges a flat GiB-second rate with a 100 ms floor, while Raff separates memory from CPU time and discounts warm starts. **The real difference is how long a function may run.** DigitalOcean caps execution at **15 minutes**, including initialization, with memory from 128 MB to 1 GB. Raff Functions permit runs of up to **24 hours**. That is not a pricing difference, it is a capability one: batch imports, ETL jobs, media transcoding, large report generation and long-running scrapes cannot be written as DigitalOcean Functions at all, and have to become a Droplet or a Kubernetes job instead. On Raff they stay serverless. ### Support and documentation Raff provides 24/7 human support through live chat, with a first response typically under 10 minutes. No bots triaging you first, and no support tier to buy: a single $4.99 VM reaches the same engineers as a hundred production machines. DigitalOcean's advantage here is not the ticket queue — it is the **documentation and tutorial library**, which is among the best in the industry and frequently the reason developers pick it. Raff has nothing comparable in breadth, and that is worth weighing if your team leans on published guides. ## When you should choose DigitalOcean over Raff - **Object storage and CDN workloads** — Spaces is $5/month for 250 GiB with 1 TiB transfer and a built-in CDN, against Raff's $7 for 100 GB and no CDN - **Free-tier app hosting** — App Platform starts at $0/month; Raff Apps start at $3 - **MongoDB or OpenSearch** — both managed on DigitalOcean, neither offered by Raff - **Large or GPU workloads** — up to 48 vCPU, 256 GB RAM and GPU Droplets, against Raff's 16 vCPU / 32 GB ceiling - **Multi-region deployment** — data centers across North America, Europe and Asia against Raff's single us-east region - **Teams that learn from documentation** — DigitalOcean's tutorial library is a genuine and hard-to-replicate asset ## When you should choose Raff over DigitalOcean - **Lower cost on equivalent VMs** — 25% to 29% below Basic Droplets on shared vCPU and 12% to 14% below CPU-Optimized, at identical disk on four of the six shared shapes ([VPS for application hosting](/learn/guides/vps-for-application-hosting)) - **Egress-heavy applications** — unmetered transfer on a 3 Gbps port against $0.01/GiB overage; at 20 TB a month the DigitalOcean bill is over thirteen times higher - **Database-backed products** — managed PostgreSQL, MySQL, Valkey, ClickHouse and Kafka from $7.99/month against $15 ([VPS for databases](/learn/guides/vps-for-databases)) - **Block-storage-heavy workloads** — $0.08/GiB-month, below DigitalOcean's volume pricing - **Backups without an add-on** — Daily and Weekly schedules on a free storage pool with 1 to 365 day retention, against backups priced as a percentage of Droplet cost - **Long-running serverless jobs** — Raff Functions run up to 24 hours against DigitalOcean's 15-minute cap, so batch imports, ETL and transcoding stay serverless instead of needing a Droplet - **Kubernetes at lower cost** — free control plane on both, with Raff workers from $9.99/month against $12 ## Migrating from DigitalOcean to Raff 1. **Check your egress profile first** — this is usually the largest single saving. If you are paying overage on Droplet transfer, that line disappears entirely on Raff. 2. **Match the Droplet family to the right Raff line** — Basic maps to General Purpose, CPU-Optimized and General Purpose Droplets map to Raff CPU-Optimized. Matching by price rather than class will mislead you. 3. **Check the ceiling** — Raff stops at 16 vCPU and 32 GB. Anything above that has no Raff equivalent. 4. **Plan Spaces and MongoDB separately** — Spaces is cheaper than Raff object storage and includes a CDN, and Raff has no managed MongoDB or OpenSearch. Decide whether those stay on DigitalOcean. 5. **Move data in order** — files with rsync or SCP, then database dumps into managed Postgres or MySQL, then assets to object storage. Keep the Droplet running throughout. 6. **Cut over and destroy, don't power off** — lower DNS TTL beforehand, switch, then destroy the Droplet. A powered-off Droplet still bills. ## About DigitalOcean DigitalOcean Holdings, Inc. is a US cloud infrastructure provider headquartered in New York, founded in 2012 and listed on the NYSE, serving developers and small-to-medium businesses with Droplets, managed databases, Kubernetes, App Platform, Spaces object storage, Functions and GPU instances from data centers across North America, Europe and Asia. See [DigitalOcean pricing](https://www.digitalocean.com/pricing) for current rates. ## Conclusion: DigitalOcean or Raff? For a provider-neutral checklist covering support, recovery, and total cost, see [how to choose a VPS provider](/learn/guides/how-to-choose-a-vps-provider). The comparison resolves across four axes: - **VM price** — Raff wins, 25% to 29% below Basic Droplets and 12% to 14% below CPU-Optimized, at identical disk on four of the six shared shapes - **Bandwidth** — Raff wins, unmetered on a 3 Gbps port against $0.01/GiB overage past the allowance - **Catalog breadth** — DigitalOcean wins, with MongoDB, OpenSearch, GPU Droplets, a free App Platform tier, cheaper object storage with a CDN, and multiple regions - **Managed databases** — Raff wins on price, from $7.99/month against $15, and adds ClickHouse If you need MongoDB, OpenSearch, GPU capacity, a free app tier, cheap object storage with a CDN, or a region outside the United States, choose DigitalOcean — and it is a genuinely strong platform, not a straw man. If your users are in North America and your bill is dominated by VMs, egress and managed databases, choose Raff: the same workload costs materially less. Raff runs 15,000+ VMs for 3,000+ customers and is rated 4.5/5 on Trustpilot, with a 99.90% monthly uptime SLA in writing. --- ### Hetzner Alternative 2026: Pricing, Performance & Features URL: https://rafftechnologies.com/learn/compare/raff-vs-hetzner Description: Considering Hetzner? Raff is $17.99/mo for 2 vCPU, 4 GB and 80 GB NVMe against CPX22 at €19.99, about $23.17. Hetzner built its reputation on being the cheapest credible cloud in Europe, and for years it was. That has changed. After the current pricing round, Raff Technologies is cheaper than Hetzner Cloud at every matched shared-vCPU shape — including five where the cores, memory and disk are identical. Hetzner Regular Performance CPX22 is €19.99/month for 2 vCPU, 4 GB and 80 GB; the identical Raff plan is $17.99. ## Hetzner VPS and Raff at a glance **Hetzner Cloud** sells three tiers, and the names are misleading if you read them quickly: - **Cost-Optimized** (CX) — shared, and currently marked **"Currently not available"** on Hetzner's own site - **Regular Performance** (CPX) — shared vCPU on AMD, from €11.99/month - **General Purpose** (CCX) — **dedicated** vCPU, from €43.49/month That third name is the trap. **Hetzner's "General Purpose" is its dedicated line**, while Raff's General Purpose is shared. Matching the two by name would compare Raff's shared vCPU against Hetzner's dedicated vCPU and get the answer badly wrong. The like-for-like pairing is Raff General Purpose against **Hetzner Regular Performance**, and Raff CPU-Optimized against **Hetzner General Purpose**. Hetzner runs from eu-central (Falkenstein, Nuremberg, Helsinki), us-east (Ashburn), us-west (Hillsboro) and ap-southeast (Singapore). Prices are quoted excluding VAT, so a US buyer pays the listed figure. Hetzner Cloud Backups cost **20% of the server's monthly price** and provide seven backup slots. **Raff Technologies** runs 15,000+ VMs for 3,000+ customers from us-east, with a 99.90% monthly uptime SLA backed by service credits, rated 4.5/5 on Trustpilot and 4.6/5 on G2. VMs run AMD EPYC with DDR5 ECC memory and NVMe storage in two lines: General Purpose with shared vCPU from $4.99/month, and CPU-Optimized with dedicated vCPU from $15.99/month, scaling to 16 vCPU and 32 GB. Every plan includes a 3 Gbps port with unmetered transfer, automated Daily or Weekly backup schedules, uncapped snapshots, firewall controls, private networking and full root access. Raff's catalog covers managed PostgreSQL, MySQL, Valkey, ClickHouse and Kafka from $7.99/month, S3-compatible object storage at $7/month for 100 GB with 1 TB of egress, managed Kubernetes with a free control plane and workers from $9.99/month, Functions with a free monthly tier, block volumes at $0.08/GiB-month, and Raff Apps from $3/month. ## Hetzner VPS pricing vs Raff pricing Raff General Purpose against Hetzner Regular Performance — both shared vCPU on AMD. | Shape | Raff General Purpose | Hetzner Regular Performance | |---|---|---| | 1 vCPU / 2 GB | **$8.99** — 50 GB NVMe | CPX12 — €11.99 ≈ $13.90, 40 GB | | 2 vCPU / 4 GB / 80 GB | **$17.99** | CPX22 — €19.99 ≈ **$23.17** | | 4 vCPU / 8 GB / 160 GB | **$33.99** | CPX32 — €35.99 ≈ **$41.72** | | 8 vCPU / 16 GB / 240 GB | **$71.99** | CPX42 — €69.99 ≈ **$81.14** | | 12 vCPU / 24 GB / 320 GB | **$109.99** | CPX52 — €100.99 ≈ **$117.08** | | 16 vCPU / 32 GB / 320 GB | **$139.99** | CPX62 — €130.49 ≈ **$151.28** | *Hetzner prices read 2026-08-20 from the Regular Performance page, excluding VAT, converted at €1 = $1.1593 (ECB, 2026-08-17). Hetzner lists us-east (Ashburn) and us-west (Hillsboro) among available locations; confirm regional pricing at checkout.* **Five of those rows are identical on cores, memory and disk** — 80 GB, 160 GB, 320 GB, 480 GB and 640 GB. Raff is **6% to 22% cheaper** across them, and at the entry shape gives 50 GB against 40 GB for about a third less. This is the finding that matters on this page. Hetzner's reputation is built on being the cheapest option that still works properly, and against Raff that is no longer the case at any shape in the shared line. ### If you are on the old CPX line, change plans before changing providers Hetzner still lists a previous CPX generation, and it is now priced well above the current one for the same or worse hardware: | Legacy plan | Spec | Price | Current equivalent | |---|---|---|---| | CPX21 | 3 vCPU / 4 GB / 80 GB | €32.49 | CPX22 — €19.99 | | CPX31 | 4 vCPU / 8 GB / 160 GB | €62.99 | CPX32 — €35.99 | | CPX41 | 8 vCPU / 16 GB / **240 GB** | €120.99 | CPX42 — €69.99 with **320 GB** | | CPX51 | 16 vCPU / 32 GB / **360 GB** | €238.49 | CPX62 — €130.49 with **640 GB** | CPX51 costs €238.49 for 16 vCPU, 32 GB and 360 GB. CPX62 gives the same cores and memory with **640 GB for €130.49** — 45% less money for 78% more disk. If you are running on the older line, the first thing to do is not switch providers, it is switch plans. That advice costs Raff a sale and is still the right advice. ### Dedicated vCPU Hetzner's dedicated line, confusingly named General Purpose, starts at **€43.49/month** (about $50.42). Raff CPU-Optimized starts at **$15.99/month** for 1 vCPU, 1 GB and 25 GB, and runs $36.99 at 2 vCPU / 4 GB / 80 GB. The full Hetzner CCX ladder is not reproduced here because the per-plan figures were not verified in this session — compare the specific shape you need directly rather than relying on entry prices. ### Automated backups Hetzner Cloud Backups cost **20% of the server's monthly price** and provide seven backup slots. On a CPX42 at €69.99, that is roughly €14/month for backups alone. Raff includes a free backup and snapshot storage pool — 50 GB per account plus 10–15% of each VM's disk — with Daily and Weekly schedules you configure, retention from 1 to 365 days, and uncapped snapshots. Storage above the pool is $0.06/GB-month. ## Hetzner VPS performance vs Raff ### Methodology The available head-to-head data is from **May 2026** — older than 90 days and no longer a current performance claim. It compared a Raff 2 vCPU / 4 GB benchmark VM against a Hetzner CPX test VM. The iperf3 rows measured different endpoints (NYC against Amsterdam) and are not comparable at all. ### Historical results — May 2026 | Metric | Raff | Hetzner CPX | Result in that test | |---|---:|---:|---| | Geekbench 6 single-core | **2,266** | 1,847 | Raff higher | | Geekbench 6 multi-core | **4,057** | 2,321 | Raff higher | | fio 4K random-read IOPS | **97,468** | 80,153 | Raff higher | | fio 64K mixed aggregate | 2,927 MB/s | **3,249 MB/s** | Hetzner higher | | fio 1M sequential aggregate | 3,606 MB/s | **4,013 MB/s** | Hetzner higher | ### What the results tell us In that window Raff led CPU by roughly 1.23x single-core and 1.75x multi-core, and 4K random read by 1.22x. **Hetzner led both sequential disk measurements**, by 11% at 64K and 11% at 1M. Two reasons to treat this as context rather than a claim: the data is past the 90-day freshness window, and Hetzner has since revised its plan lineup, so the tested configuration may no longer exist under the same name. If performance is your deciding factor, benchmark the specific CPX\*2 plan you are considering against the matching Raff plan. ## Hetzner vs Raff: features and reliability ### Compute Hetzner Regular Performance runs from 1 to 16 shared vCPU and 2 to 32 GB on AMD, with the dedicated General Purpose line above it. Raff covers the same shared range and stops at 16 vCPU and 32 GB, with CPU-Optimized alongside. Raff resizes on demand: stop the VM, switch plan, restart, with the difference settled to the account balance and a `resize` API endpoint for CPU, RAM and disk. ### Networking Raff includes a 3 Gbps port with unmetered transfer, private networking, VPC, firewall controls and site-to-site VPN gateways. Hetzner includes private networks, stateful firewalls at no extra cost, load balancers and a generous traffic allowance per server, with charges beyond it — confirm the current allowance and overage rate for your region, as these have changed alongside the plan revision. ### Storage Hetzner attaches local NVMe to the host and sells Volumes separately. Raff separates storage into VM disk, block volumes at $0.08/GiB-month that resize independently, and S3-compatible object storage at $7/month for 100 GB with 1 TB of egress. On the matched shapes above, Raff includes the same disk as Hetzner at every tier except the entry plan, where it includes more. ### Support Raff provides 24/7 human support through live chat, with a first response typically under 10 minutes. No bots triaging you first, and no support tier to buy: a single $4.99 VM reaches the same engineers as a hundred production machines. Hetzner's support runs on tickets and is well regarded for competence rather than speed. ### Platform Hetzner sells infrastructure: servers, storage boxes, load balancers, networks, and dedicated hardware — with a strong reputation for reliability and an active community. It does not sell managed databases, serverless functions or a PaaS layer. Raff adds those on the same account: managed PostgreSQL, MySQL, Valkey, ClickHouse and Kafka from $7.99/month, object storage at $7/month, Functions with a free tier of 100,000 GB-seconds and 10,000 vCPU-seconds and runs up to 24 hours, Raff Apps from $3/month, and managed Kubernetes with a free control plane — connected over private networking, on one API and one bill. The honest counter-argument is that a 32 GB Hetzner box will run Postgres, Redis and your application together perfectly well. It will. What you are then operating is backups, restore testing, failover, point-in-time recovery and version upgrades — and Hetzner's backup add-on costs 20% of the server price on top. ## When you should choose Hetzner over Raff - **Users in Europe or Asia** — Falkenstein, Nuremberg, Helsinki and Singapore against Raff's single us-east region - **Sequential-disk-heavy workloads** — Hetzner measured 11% higher on both 64K mixed and 1M sequential aggregate in May 2026 testing - **Dedicated hardware and storage boxes** — Hetzner's dedicated server range and Storage Box products have no Raff equivalent - **Established community and tooling** — a large, active user base with extensive third-party guides and automation recipes - **Hourly billing with a monthly cap** — pay only for hours used if a server is deleted mid-month ## When you should choose Raff over Hetzner - **Lower cost on identical hardware** — 6% to 22% cheaper at five shapes with identical cores and memory ([VPS for application hosting](/learn/guides/vps-for-application-hosting)) - **Backups without a 20% surcharge** — Daily and Weekly schedules on a free storage pool against 20% of the server's monthly price - **Users in North America** — us-east against a European-first footprint, with unmetered transfer on a 3 Gbps port - **Database-backed products** — managed PostgreSQL, MySQL, Valkey, ClickHouse and Kafka from $7.99/month, which Hetzner does not offer ([VPS for databases](/learn/guides/vps-for-databases)) - **Long-running serverless jobs** — Raff Functions run up to 24 hours; Hetzner has no serverless product - **24/7 human support** — live chat to the same engineers at any account size, first response typically under 10 minutes ## Migrating from Hetzner to Raff 1. **Check which CPX generation you are on first** — if you are on CPX21, CPX31, CPX41 or CPX51, moving to the current CPX\*2 line may save more than switching providers. Do that comparison before this one. 2. **Match the tier, not the name** — Hetzner "General Purpose" is dedicated vCPU and maps to Raff CPU-Optimized. Hetzner "Regular Performance" is shared and maps to Raff General Purpose. 3. **Check your region requirement** — Raff serves us-east only. If your users are in Europe, this migration adds latency that the price saving will not offset. 4. **Account for the backup line** — Hetzner backups cost 20% of the server price; on Raff that line goes away, which widens the real saving beyond the plan-price difference. 5. **Move data in order** — files with rsync or SCP, then database dumps into managed Postgres or MySQL, then assets to object storage. Keep the Hetzner server running throughout. 6. **Cut over and delete, don't power off** — lower DNS TTL beforehand, switch, then delete the server. Hetzner bills until a server is deleted, not until it is stopped. ## About Hetzner Hetzner Online GmbH is a German hosting provider founded in 1997 and headquartered in Gunzenhausen, offering cloud servers, dedicated servers, storage boxes, load balancers and colocation from data centers in Germany, Finland, the United States and Singapore. It is known for low prices and a strong engineering reputation in the European developer community. See [Hetzner Cloud](https://www.hetzner.com/cloud/) for current plans and terms. ## Conclusion: Hetzner or Raff? Before comparing plans across currencies and regions, use the [VPS provider decision framework](/learn/guides/how-to-choose-a-vps-provider) to define the evaluation criteria. The comparison resolves across four axes: - **Price** — Raff wins, 6% to 22% cheaper at five shapes with identical cores and memory, plus no 20% backup surcharge - **Reach** — Hetzner wins, with European and Asian regions against Raff's single us-east - **Sequential disk** — Hetzner led by about 11% in May 2026 testing, though that data is now stale - **Managed services** — Raff wins, with managed databases, Functions and Kubernetes that Hetzner does not sell If your users are in Europe, you want dedicated hardware or storage boxes, or your workload is dominated by large sequential disk operations, choose Hetzner. If your users are in North America and you want the same hardware for less with managed databases beside it, choose Raff. And if you are on an older CPX plan, check the current line first — that saving is available without moving anywhere. Raff runs 15,000+ VMs for 3,000+ customers and is rated 4.5/5 on Trustpilot, with a 99.90% monthly uptime SLA in writing. --- ### Contabo Alternative 2026: Pricing, Performance & Features URL: https://rafftechnologies.com/learn/compare/raff-vs-contabo Description: Considering Contabo? Raff is $33.99/mo for 4 vCPU, 8 GB and 160 GB NVMe on a 3 Gbps port against Contabo's 500 Mbit/s. Contabo is a German hosting company that has sold servers since 2003 — VPS, dedicated machines and object storage — at some of the lowest prices on the market. Raff Technologies is a US cloud provider where the virtual machine is one product among several, alongside managed databases, object storage, Functions and Kubernetes on the same account. Both sell shared-vCPU VMs, so the comparison is a fair one: Contabo Cloud VPS Plus 4 is €13.50/month (about $15.65) for 4 vCPU and 8 GB, and the closest Raff plan is $33.99/month. What differs is not really the server. It is what sits around it, and what you do when one server is no longer enough. ## Contabo VPS and Raff at a glance **Contabo** is a German hosting provider with data centers across Europe, the US, Asia and Australia, rated 4.6/5 on Trustpilot. Its VPS catalog splits three ways. **Core VPS** is the budget line from €5.50/month on SSD with 200 Mbit/s to 1 Gbit/s ports and 1–3 snapshots. **Performance VPS**, branded Cloud VPS Plus, is the NVMe line from €13.50/month with 500 Mbit/s to 1 Gbit/s ports and 5 snapshots. **Max Performance VPS** sits above it, and Cloud VDS offers dedicated cores. Both VPS lines run AMD EPYC — the Core-class VMs benchmarked below reported EPYC 7282 — so storage and port speed, not CPU family, separate them. Contabo advertises 99.9% uptime, unlimited traffic and a free firewall with DDoS protection across the range. **Raff Technologies** runs 15,000+ VMs for 3,000+ customers from its us-east region, with a 99.9% uptime SLA backed by service credits, rated 4.5/5 on Trustpilot and 4.6/5 on G2. VMs run AMD EPYC with DDR5 ECC memory and NVMe storage in two lines: General Purpose with shared vCPU from $4.99/month, and CPU-Optimized with dedicated vCPU from $15.99/month, scaling to 16 vCPU and 32 GB. Every plan includes a 3 Gbps port with unmetered transfer, automated Daily or Weekly backup schedules, uncapped snapshots, firewall controls, private networking and full root access. The catalogs differ past the VM. Raff sells S3-compatible object storage at $7/month for 100 GB and 1 TB of egress, managed PostgreSQL, MySQL, Valkey, ClickHouse and Kafka from $7.99/month, managed Kubernetes with a free control plane and workers from $9.99/month, Functions with a free monthly tier, block volumes at $0.08/GiB-month, and Raff Apps from $3/month. ## Contabo VPS pricing vs Raff pricing Contabo Performance VPS uses shared AMD EPYC cores, so the like-for-like Raff line is General Purpose. | Contabo shape | Contabo Performance VPS | Raff General Purpose | |---|---|---| | 4 vCPU / 8 GB | **€13.50** (about $15.65) · Plus 4 · 150 GB NVMe · 500 Mbit/s | **$33.99** · 4 vCPU / 8 GB · 160 GB NVMe · **3 Gbps** | | 6 vCPU / 12 GB | **€19.00** (about $22.03) · Plus 6 · 300 GB NVMe · 500 Mbit/s | no 6-core plan · closest is **$48.99** at 8 vCPU / 8 GB · 160 GB NVMe · **3 Gbps** | | 8 vCPU / 24 GB | **€35.00** (about $40.58) · Plus 8 · 450 GB NVMe · 1 Gbit/s | **$119.99** · 8 vCPU / 32 GB · 320 GB NVMe · **3 Gbps** | | 12 vCPU / 48 GB | **€59.00** (about $68.40) · Plus 12 · 600 GB NVMe · 1 Gbit/s | **$109.99** · 12 vCPU / 24 GB · 320 GB NVMe · **3 Gbps** | | 16 vCPU / 64 GB | **€79.00** (about $91.58) · Plus 16 · 750 GB NVMe · 1 Gbit/s | **$139.99** · 16 vCPU / 32 GB · 320 GB NVMe · **3 Gbps** | *Raff General Purpose against Contabo Performance VPS — both shared AMD EPYC on NVMe. Raff CPU-Optimized from $15.99/mo is the match for Contabo Cloud VDS. Contabo standard monthly rates, read 2026-08-18, excluding the discounted first-24-month rate; €1 = $1.1593 (ECB, 2026-08-17).* At the matched 4 vCPU / 8 GB shape Raff is about 117% more expensive. Higher up the range Contabo also sells memory shapes Raff does not offer at any price: 48 GB at 12 cores and 64 GB at 16 cores. Contabo is the cheaper product, and at the memory-heavy end it is the only product. ### Contabo's Core VPS line for reference Core VPS is the budget line, also AMD EPYC but on SSD with lower port speeds. It is not the like-for-like match, and it is the line benchmarked below — worth seeing beside the others: | Shape | Core VPS (SSD) | Performance VPS (NVMe) | Raff General Purpose (NVMe) | |---|---|---|---| | 4 vCPU / 8 GB | €5.50 (about $6.38) · 100 GB · 200 Mbit/s | €13.50 (about $15.65) · 150 GB · 500 Mbit/s | $33.99 · 160 GB · **3 Gbps** | | 8 vCPU / 24 GB | €14.00 (about $16.23) · 300 GB · 600 Mbit/s | €35.00 (about $40.58) · 450 GB · 1 Gbit/s | $119.99 at 8 vCPU / 32 GB · 320 GB · **3 Gbps** | | 16 vCPU / 64 GB | €37.00 (about $42.89) · 500 GB · 1 Gbit/s | €79.00 (about $91.58) · 750 GB · 1 Gbit/s | $139.99 at 16 vCPU / 32 GB · 320 GB · **3 Gbps** | If your priority is the lowest price per gigabyte of RAM and SSD is acceptable, Core VPS is the cheapest option on this page by a wide margin. ### Bandwidth and transfer Neither provider meters standard outbound transfer. Contabo lists unlimited traffic under a fair-use policy; Raff includes unmetered transfer. The difference is the pipe: Contabo Performance VPS runs 500 Mbit/s on Plus 4 and Plus 6 and 1 Gbit/s from Plus 8 up — its own headline is "Unlimited Traffic up to 1 Gbit/s" — while every Raff plan runs a 3 Gbps port regardless of tier. At the matched shape that is a six-fold difference in ceiling. Unlimited transfer on a 500 Mbit/s port and unmetered transfer on a 3 Gbps port are not the same product. ### Automated backups Raff includes a free backup and snapshot storage pool — 50 GB per account plus 10–15% of each VM's disk — with Daily and Weekly schedules you configure yourself, retention from 1 to 365 days, and uncapped snapshots. Storage above the pool is $0.06/GB-month. Contabo Performance VPS includes 5 snapshots and sells automated backups as a paid add-on at checkout. Compare the configured price, not the headline price, if scheduled backups are a requirement. ### Location and term Contabo's advertised rates are European base prices, and some US, Asian and Australian locations carry a surcharge — confirm the price for the region you need. The rates above are standard monthly prices; the advertised lower rate is a 24-month commitment, not the ongoing price. Raff prices are not region-surcharged and can be billed monthly, on optional 1-year or 2-year subscriptions, or pay as you go from a prepaid balance; Raff also carries a 14-day money-back guarantee. ## Contabo VPS performance vs Raff ### Methodology Raff figures are internal, measured March–May 2026 on a 2 vCPU / 4 GB instance rather than the 4 vCPU / 8 GB shape priced above. Contabo figures are third-party, from VPSBenchmarks. Sequential throughput is shown in MB/s on both sides. Two Core VPS figures are withheld because they exceed Contabo's own newer NVMe tier by roughly four times — most likely page-cache effects rather than a real result. ### Results | Metric | Raff General Purpose | Contabo Performance VPS (Plus 4) | Contabo Core VPS | |---|---:|---:|---:| | Geekbench 6 single-core | 2,266 | **2,476** | 1,163 | | Geekbench 6 multi-core | 4,057 (2 vCPU) | **8,157** (4 vCPU) | 4,700 (4 vCPU) | | fio 4K read, 50/50 mix | **48,670 IOPS** | 15,948 IOPS | 15,768 IOPS | | fio 4K read, read-only | **74,562 IOPS** | not published | not published | | fio 1M sequential read | **2,491 MB/s** | 534.8 MB/s | withheld | | fio 1M sequential write | **1,257 MB/s** | 570.4 MB/s | withheld | | iperf3 peak † | **9,574 Mbps** | 496 Mbps | 485–496 Mbps | | CPU steal, sustained load | 0.13–0.32% over 26h | **0.00%** avg and max | 3.08–4.26% | | Request timeouts @ 120 req/s | not run | not run | **4,058** | † Raff VMs publish a 3 Gbps port speed and are provisioned on 10 Gbps host uplinks in us-east. The 9,574 Mbps figure is a measured peak across parallel iperf3 streams, above the published per-VM rate — treat 3 Gbps as the committed speed, not 9.5. ### What this tells you **On CPU the two are close.** 2,476 against 2,266 single-core is about 9% apart, across separate tests on different days — inside the range where the honest answer is *comparable* rather than *faster*. CPU steal is effectively zero on both: 0.00% on Contabo Performance, 0.13–0.32% on Raff across a 26-hour run. Neither shows the shared-core variance that makes a server feel slow under load. If per-core CPU is all your workload cares about, this comparison does not separate them, and Contabo is cheaper. **Raff separates on throughput.** Sequential 1M reads ran 2,491 MB/s against 534.8 MB/s, writes 1,257 MB/s against 570.4 MB/s, and the 4K mixed job 48,670 IOPS against 15,948. The network gap is structural rather than tuning: Plus 4 lists a 500 Mbps maximum and measured 496 Mbps. **The Core column shows what the cheap line gives up:** roughly half the single-core score, 3.08–4.26% CPU steal under load, and 4,058 request timeouts at 120 req/s. CPU steal is time your VM was ready to run but waiting for a core held by a neighbour — at 3–4%, a server stays online and answers monitoring checks while individual requests queue. That is how a platform records high availability and slow page loads at the same time. It belongs to Core VPS, not to Performance VPS. ## Contabo vs Raff: features and reliability ### Compute Contabo Performance VPS offers five shared AMD EPYC shapes from 4 to 16 cores and 8 to 64 GB RAM, with more memory per core than Raff sells at any tier. Raff offers General Purpose from $4.99/month and CPU-Optimized dedicated vCPU from $15.99/month, on AMD EPYC with DDR5 ECC memory, scaling to 16 vCPU and 32 GB. Raff plans resize on demand: stop the VM, switch plan, restart, with the difference settled to your account balance and a `resize` API endpoint for CPU, RAM and disk. ### Networking Raff includes a 3 Gbps port on every plan, private networking, VPC, firewall controls and site-to-site VPN gateways. Contabo includes a free firewall and DDoS protection, with port speeds of 500 Mbit/s to 1 Gbit/s on the Performance line. ### Storage Both lines use NVMe, but not in the same way. Contabo attaches local NVMe to the host. Raff runs distributed block storage across an NVMe cluster, so a write crosses the network and is replicated before it is acknowledged. What that model buys is everything around the disk: data replicated rather than pinned to one machine, snapshots and backups taken at the storage layer, and a VM that changes plan by stopping and restarting rather than being rebuilt. Block volumes at $0.08/GiB-month attach and resize independently for the same reason. Contabo ships more capacity per plan — 150 GB at 4 cores rising to 750 GB at 16 — against Raff's 160 GB and 640 GB at the same core counts. ### Support Raff provides 24/7 human support through live chat, with a first response typically under 10 minutes. No bots triaging you first, and no support tier to buy: a single $4.99 VM reaches the same engineers as a hundred production machines, through the same queue. Contabo's help centre describes a different model. Live chat requires an active Contabo account and a login to the customer panel, and the conversation starts with ContaBro, a virtual assistant, before a human agent is reached. Phone support runs 08:00 to 23:00 European time. Ticket support accepts requests at any hour, but Contabo does not publish a response target. The practical difference shows up twice: before you buy, when you cannot reach Contabo chat without an account, and at 3 AM, when a bot answers first. ### Platform This is the widest gap, and for most buyers the one that decides the question. A VM is rarely the whole requirement. An application needs a database, somewhere to put uploads, background jobs, and eventually a way to scale beyond one server. On Raff those are products on the same account: managed PostgreSQL, MySQL, Valkey, ClickHouse and Kafka from $7.99/month, object storage at $7/month for 100 GB and 1 TB of egress, Functions with a free tier of 100,000 GB-seconds and 10,000 vCPU-seconds per month, Raff Apps from $3/month, and managed Kubernetes with a free control plane and workers from $9.99/month. They connect over private networking rather than the public internet, share one API, one CLI and one bill, and the database you attach today is the one you scale next quarter. Contabo offers object storage and managed services alongside its servers, but the catalog is oriented around servers — a database, a queue and an object store assembled from separate places, each with its own credentials, billing and failure modes. The honest counter-argument is that you can run Postgres on the same Contabo box for free. You can, and on a 48 GB plan it will run well. What you are then operating is backups, restore testing, failover, point-in-time recovery and version upgrades. If that work is inside your team's capability and time budget, Contabo is genuinely cheaper. If it is not, the question is not which VM costs less this month — it is what the second and third piece of your stack cost in time when you need them. ## When you should choose Contabo over Raff - **Memory-heavy batch and analytics** — 48 GB at 12 cores for €59.00 (about $68.40) and 64 GB at 16 cores for €79.00 (about $91.58); Raff sells no equivalent at any price - **Self-hosted storage, media and backup targets** — 750 GB NVMe at the top tier against Raff's 640 GB, with unlimited traffic - **Large dev, test and CI fleets** — comparable per-core CPU at roughly half the cost, where latency variation costs nothing - **Single CPU-bound servers** — 2,476 Geekbench 6 single-core with 0.00% CPU steal, cheaper than Raff at every matched tier - **Users outside the United States** — data centers across Europe, Asia and Australia against Raff's single us-east region ## When you should choose Raff over Contabo - **User-facing APIs and web applications** — 9,574 Mbps measured against 496 Mbps, on a 3 Gbps port at every tier ([VPS for application hosting](/learn/guides/vps-for-application-hosting)) - **Database-backed products** — 48,670 4K read IOPS on a 50/50 mix against 15,948, and 2,491 MB/s sequential read, with managed PostgreSQL, MySQL, Valkey, ClickHouse and Kafka from $7.99/month on the same account ([VPS for databases](/learn/guides/vps-for-databases)) - **Stacks that will outgrow one server** — object storage at $7/month, Functions with a free monthly tier, Raff Apps from $3/month and managed Kubernetes with a free control plane, connected over private networking - **Production workloads that must recover** — Daily and Weekly schedules on a free storage pool, retention from 1 to 365 days, and uncapped snapshots, against 5 snapshots with backups sold as an add-on - **Latency-sensitive services** — CPU-Optimized dedicated vCPU from $15.99/month where shared-core variance is unacceptable - **Teams evaluating without commitment** — monthly billing, a 14-day money-back guarantee, and no KYC verification step before first provisioning ## Migrating from Contabo to Raff 1. **Right-size on measured utilisation** — do not match core and RAM counts by default. Contabo's memory-heavy shapes are often larger than the workload needs. 2. **Plan the memory gap honestly** — if you genuinely use 48 or 64 GB, Raff has no equivalent plan, and that is a reason to stay. 3. **Provision and harden** — create the Raff VM on the same distribution, apply firewall rules, attach private networking before moving data. 4. **Move data in order** — files with rsync or SCP, then database dumps, then static assets to object storage. Keep the Contabo VPS running throughout. 5. **Test under load, not at idle** — the differences here appear under sustained traffic. Replay real traffic before switching DNS. 6. **Cut over and check the term** — lower DNS TTL beforehand, switch, then confirm your Contabo billing term. A discounted 24-month rate continues after you migrate. ## About Contabo Contabo is a German hosting provider founded in Munich, offering Core, Performance and Max Performance VPS lines, Cloud VDS, dedicated servers and object storage from data centers in Europe, the US, Asia and Australia. It is known for high RAM and core counts at low monthly prices. See [Contabo VPS](https://contabo.com/en/vps/) for current plans and terms. ## Conclusion: Contabo or Raff? If you need to weigh initial server cost against reliability and ongoing operations, follow the [VPS provider selection checklist](/learn/guides/how-to-choose-a-vps-provider). The comparison resolves across four measured axes: - **Price** — Contabo wins: €13.50 (about $15.65) against $33.99 at 4 vCPU and 8 GB, under half, and cheaper at every tier above - **Per-core CPU** — comparable, 2,476 against 2,266 Geekbench 6 single-core, with CPU steal effectively zero on both - **Throughput** — Raff wins, 9,574 Mbps against 496 Mbps and 2,491 MB/s sequential read against 534.8 MB/s - **Platform** — Raff adds managed databases from $7.99/month, Functions, object storage, Apps and Kubernetes to the same account, over private networking If you are buying one server, CPU is what you care about, and price decides it, choose Contabo — per-core performance is comparable and it costs roughly half. If you are building an application that will also need a managed database, object storage, Functions or Kubernetes, choose Raff: those run on the same account, over private networking, on one bill. Raff runs 15,000+ VMs for 3,000+ customers and is rated 4.5/5 on Trustpilot, with a 99.9% uptime SLA in writing. --- ### OVHcloud Alternative 2026: Pricing, Performance & Features URL: https://rafftechnologies.com/learn/compare/raff-vs-ovhcloud Description: Considering OVHcloud? Raff is $17.99/mo for 2 vCPU and 4 GB against d2-4 at $18.69, with a 3 Gbps port on every plan. OVHcloud is Europe's largest cloud provider, with its own data centers, its own network, and a VPS line priced lower than almost anything comparable. Raff Technologies is a US cloud provider selling VMs, managed databases, object storage, Functions and Apps on one account. On price this is not a close comparison: OVHcloud VPS-1 gives 2 vCores, 4 GB and 40 GB NVMe for $4.54/month, where the nearest Raff plan is $17.99. What differs is disk, port speed, how long a backup is kept, and what runs beside the server. ## OVHcloud VPS and Raff at a glance OVHcloud is Europe's largest cloud provider, running its own data centers and network since 1999. Raff Technologies is a US cloud provider selling VMs, managed databases, object storage, Functions and Apps from a single us-east region. One thing has to be settled before any price is compared: **OVHcloud sells two different compute products.** | | What it is | Starts at | |---|---|---| | **VPS 2027** | Budget self-managed servers. Monthly billing, four fixed sizes, one rolling 24-hour backup. | **$4.54/mo** | | **Public Cloud** | The cloud platform. Hourly billing, API and CLI, private networking, snapshots, managed databases and Kubernetes alongside. | **$9.41/mo** | **A Raff VM is the second kind of product.** It bills hourly, exposes an API and CLI, resizes on demand, sits on private networking, and has managed databases on the same account. So this page compares **Raff against Public Cloud**, and shows the VPS line separately — because it is genuinely cheaper, and some readers should buy it. **Raff Technologies** runs 15,000+ VMs for 3,000+ customers from us-east, with a 99.90% monthly uptime SLA backed by service credits, rated 4.5/5 on Trustpilot and 4.6/5 on G2. VMs run AMD EPYC with DDR5 ECC memory and NVMe storage, in two lines: General Purpose with shared vCPU from $4.99/month, and CPU-Optimized with dedicated vCPU from $15.99/month. Every plan includes a **3 Gbps port** with unmetered transfer regardless of size, Daily or Weekly backup schedules, uncapped snapshots, firewall controls, private networking and full root access. Beyond the VM, Raff sells managed PostgreSQL, MySQL, Valkey, ClickHouse and Kafka from $7.99/month, object storage at $7/month for 100 GB, managed Kubernetes with a free control plane, Functions that run up to 24 hours, IAM, and Raff Apps from $3/month. ## OVHcloud VPS pricing vs Raff pricing Both providers sell shared and dedicated vCPU, so there are two comparisons. OVHcloud's shared range is **D2 Discovery**; its dedicated ranges are **B3**, **C3** and **R3**. ### Shared vCPU | Shape | Raff General Purpose | OVHcloud D2 | |---|---|---| | 1 vCPU / 2 GB | **$8.99** — 50 GB | d2-2 — $9.41, 25 GB | | 2 vCPU / 4 GB | **$17.99** — 80 GB | d2-4 — $18.69, 50 GB | | 4 vCPU / 8 GB | **$33.99** — 160 GB | d2-8 — $33.65, 50 GB | Raff is **within a few percent of Public Cloud on shared vCPU** — about 4% cheaper at the two smaller shapes and about 1% more at 4 vCPU / 8 GB — **with more disk on every row**. ### Dedicated vCPU | Shape | Raff CPU-Optimized | OVHcloud C3 | |---|---|---| | 2 vCPU / 4 GB | **$36.99** — 80 GB | c3-4 — $39.42, 50 GB | | 4 vCPU / 8 GB | **$72.99** — 120 GB | c3-8 — $78.69, 100 GB | | 8 vCPU / 16 GB | **$144.99** — 180 GB | c3-16 — $157.22, 200 GB | Raff is **6% to 8% cheaper**. *OVHcloud Public Cloud US prices read from us.ovhcloud.com on 2026-08-20. Monthly figures are the published hourly rate at 730 hours.* ### Port speed Raff runs a **3 Gbps port on every plan**, including the $4.99 entry. OVHcloud scales bandwidth with instance size: | OVHcloud instance | Its port | Raff advantage | |---|---|---| | d2-2 | 100 Mbps | **30x** | | d2-4, c3-4 | 250 Mbps | **12x** | | d2-8, c3-8 | 500 Mbps | **6x** | | c3-16 | 1 Gbps | **3x** | On the small instances most projects start with, that is a thirty-fold difference in ceiling. ### If you only care about price, buy the VPS **OVHcloud VPS-1 is $4.54/month** — cheaper than any Raff plan, and cheaper than OVHcloud's own Public Cloud. If the monthly figure decides your purchase, buy it. This page will not argue otherwise. **Why is it so much cheaper than the same company's Public Cloud?** Not because the hardware is worse — OVHcloud does not say what the hardware is. It is cheaper because it is a smaller product: - **No hourly billing.** Monthly commitment only, where Public Cloud and Raff bill by the hour. - **One rolling 24-hour backup**, not a retention window. - **It sits outside the platform.** Managed databases, object storage and Kubernetes are Public Cloud products. A VPS does not get them beside it on the same private network. - **No published CPU specification.** OVHcloud states the vCore count but not the processor, the generation, or whether cores are shared or dedicated. Every other provider in this comparison publishes at least the CPU family. That last one is worth pausing on. It is not evidence of bad hardware — it is an absence of evidence, and you can verify the absence yourself on their pricing page. If knowing what you are running on matters, that is a reason to check before buying rather than a reason not to buy. At $4.54 the VPS is a fair trade for a small self-managed server. It is simply not the same purchase as a cloud instance. ### Backups OVHcloud VPS includes a **daily backup of the previous 24 hours** — one day of history. A problem introduced on Monday and found on Wednesday is already past it. Premium backup starts at $1.40/month. Raff includes a free backup and snapshot pool — 50 GB per account plus 10–15% of each VM's disk — with Daily and Weekly schedules, **1 to 365 day retention**, and uncapped snapshots. Above the pool it is $0.06/GB-month. ## OVHcloud VPS performance vs Raff **Raff has no current, matched benchmark against the VPS 2027 range, and this page will not estimate one.** The available data is from May 2026 and compared a Raff 2 vCPU / 4 GB instance against an OVHcloud `b3-16` Public Cloud instance with 4 vCores and 16 GB — a different product line, a different shape, and a single pass. That is not a basis for a claim about VPS 2027. What can be said from published specifications: **Bandwidth ceiling is the measurable difference.** Raff publishes 3 Gbps on every plan; OVHcloud publishes 100 Mbps to 4 Gbps depending on instance size, and only its largest instances exceed Raff's port. On the shapes most projects actually buy, the gap runs from 3x to 30x, and it does not depend on a benchmark to verify. **Storage architecture.** OVHcloud attaches NVMe to the host. Raff runs distributed block storage across an NVMe cluster, so a write crosses the network and is replicated before it is acknowledged — slower for small synchronous writes, and the reason data is replicated rather than pinned to one machine, snapshots are taken at the storage layer, and a VM can change plan without being rebuilt. **Reliability commitment.** Raff commits to 99.90% monthly uptime with service credits, documented in the service level agreement, running 15,000+ VMs from us-east. If performance is your deciding factor, run your workload on both. OVHcloud bills monthly with no term, so the test is inexpensive. ## OVHcloud vs Raff: features and reliability ### Compute OVHcloud VPS spans 2 to 8 vCores and 4 to 24 GB. Raff spans 1 to 16 vCPU and 1 to 32 GB across two lines, with CPU-Optimized offering dedicated vCPU from $15.99/month — OVHcloud's VPS line has no dedicated-vCPU equivalent, though its Public Cloud does. Raff resizes on demand: stop the VM, switch plan, restart, with the difference settled to the account balance and a `resize` API endpoint. ### Networking Raff includes a 3 Gbps port at every tier with unmetered transfer, private networking, VPC, firewall controls and site-to-site VPN gateways. OVHcloud includes unlimited traffic with a tier-dependent ceiling, anti-DDoS protection on every plan, and a global network that is genuinely one of the company's strongest assets. ### Storage Raff includes about twice the disk at each matched tier, and separates storage into VM disk, block volumes at $0.08/GiB-month, and S3-compatible object storage at $7/month for 100 GB with 1 TB of egress. OVHcloud sells object storage and block storage through its Public Cloud rather than the VPS product. ### Support Raff provides 24/7 human support through live chat, with a first response typically under 10 minutes. No bots triaging you first, and no support tier to buy: a single $4.99 VM reaches the same engineers as a hundred production machines. OVHcloud's VPS support is documented as email-based assistance alongside a substantial guide library. For a self-managed VPS at $4.54/month that is a reasonable trade, and it is worth pricing the difference honestly rather than assuming one model suits everyone. ### Platform This is where the comparison turns, if it turns at all. Raff sells the layers around the VM on the same account: managed PostgreSQL, MySQL, Valkey, ClickHouse and Kafka from $7.99/month reachable over private networking, S3-compatible object storage, Functions with a free tier that run **up to 24 hours**, managed Kubernetes with a free control plane, IAM with roles and audit logs, and Raff Apps from $3/month. Private traffic between them is unmetered and free. OVHcloud has equivalents — managed databases, object storage, managed Kubernetes — but they live in Public Cloud, a separate product with its own pricing model, rather than beside the VPS you just bought. Assembling a VPS plus Public Cloud services is a different exercise from adding a database to an existing account. The honest counter-argument remains strong here: a VPS-4 with 24 GB of RAM at $23.37 will run Postgres, Redis and your application together comfortably. It will. What you are then operating is backups with more than 24 hours of history, restore testing, failover and version upgrades — and at that price, many teams will decide that is a fair trade. ## When you should choose OVHcloud over Raff - **The VPS line on price above all else** — VPS-1 at $4.54/month undercuts every Raff plan and OVHcloud's own Public Cloud, if a simpler product suits you - **Users outside North America** — European and global regions plus Local Zones in more than 15 cities, against Raff's single us-east - **Memory-heavy single servers** — 24 GB at $23.37 has no Raff equivalent near that price - **Dedicated servers and bare metal** — a deep dedicated range that Raff does not offer at all - **Anti-DDoS at every tier** — included on all VPS plans as standard ## When you should choose Raff over OVHcloud - **Backups with real retention** — Daily and Weekly schedules with 1 to 365 day retention, against a single rolling 24-hour backup ([VPS backup strategy](/learn/guides/cloud-server-backup-strategies)) - **Egress-heavy applications** — a 3 Gbps port on every plan against 100 Mbps on d2-2 and 250 Mbps on d2-4, a twelve to thirty-fold difference in ceiling - **More included disk** — roughly twice the storage at each matched tier - **Database-backed products** — managed PostgreSQL, MySQL, Valkey, ClickHouse and Kafka from $7.99/month on the same account over private networking ([VPS for databases](/learn/guides/vps-for-databases)) - **Long-running serverless jobs** — Raff Functions run up to 24 hours; nothing in the OVHcloud VPS product is equivalent - **24/7 live support** — chat to the same engineers at any account size, first response typically under 10 minutes, against email-based VPS support ## Migrating from OVHcloud to Raff 1. **Be clear which OVHcloud product you are on** — if you run a VPS 2027 plan, Raff costs more and this migration is about backup retention, port ceiling and managed services, not price. If you run Public Cloud instances, Raff is cheaper at every class. 2. **Check which VPS generation you are on** — OVHcloud notes that VPS 2027 configurations have shifted, so an older plan may not map to the model with the same name. 3. **Check your region requirement** — Raff serves us-east only. European or Asian users will see added latency. 4. **Right-size on utilisation** — OVHcloud ships more cores at the upper tiers; Raff ships more disk. Measure what the workload uses rather than matching specifications. 5. **Move data in order** — files with rsync or SCP, then database dumps into managed Postgres or MySQL, then assets to object storage. Keep the OVHcloud VPS running throughout. 6. **Cut over and cancel properly** — lower DNS TTL beforehand, switch, then cancel the VPS in the OVHcloud control panel rather than leaving it idle. ## About OVHcloud OVHcloud is a French cloud provider founded in 1999 and headquartered in Roubaix, operating its own data centers and network across Europe, North America and Asia-Pacific. It offers VPS, dedicated servers, Public Cloud instances, managed Kubernetes, object storage and Local Zones, and is one of the largest cloud providers in Europe. See [OVHcloud VPS](https://us.ovhcloud.com/vps/) for current plans and terms. ## Conclusion: OVHcloud or Raff? The honest split is not price against price — it is **what stage the workload is at.** **For a trial, a prototype, a staging box or a small static site, the OVHcloud VPS is enough.** $4.54/month, unlimited traffic, a daily backup, and a server that works. Nothing on this page beats that for something you are still deciding about, and you should not pay production prices for a machine you might delete next week. **For production, the deciding factors stop being the monthly figure.** They become: how far back your backups go, whether the port holds up when traffic arrives, whether you can attach a managed database without assembling a second product, and how fast someone answers at 3 AM. That is the comparison Raff is priced for: - **Price at production class** — against OVHcloud Public Cloud, the equivalent product, Raff is **level with Public Cloud on shared vCPU and 6% to 8% cheaper on dedicated**, with more disk on most rows - **Backup history** — 1 to 365 days of retention with Daily and Weekly schedules, against a single rolling 24-hour backup - **Port ceiling** — a 3 Gbps port on every Raff plan, against 100 Mbps to 1 Gbps on the Public Cloud instances most projects buy - **Room to grow** — managed databases from $7.99, object storage, Functions and Kubernetes on the same account and private network, rather than in a separate product OVHcloud keeps the advantages that come with its scale: regions across three continents, Local Zones in more than 15 cities, a deep dedicated server range, and the cheapest entry price here. ### The part that decides it: what happens when it works Start on the OVHcloud VPS if the project might not survive the month. At $4.54 it costs almost nothing to find out, and that is a genuinely good reason. But be clear what you are choosing, because **the VPS line does not grow into Public Cloud — it is a separate product.** When the project does work, and backups need to reach further back than yesterday, or traffic outgrows the port, or you need a managed database on a private network, you are not upgrading. You are migrating: a different product or a different provider, a data move, a DNS cutover, and a maintenance window you have to explain to someone. On Raff the same account runs from $4.99 to 16 vCPU and 32 GB, and the managed database, object storage, Functions and Kubernetes are already there on the same private network. Growing means selecting a larger plan and restarting, not planning a migration. So the question is not which server is cheaper this month. It is whether you want to spend a weekend migrating in six months — and if the answer is no, starting where you intend to end up is worth more than the difference between $4.54 and $17.99. Raff runs 15,000+ VMs for 3,000+ customers and is rated 4.5/5 on Trustpilot, with a 99.90% monthly uptime SLA in writing. --- ### Linode Alternative 2026: Pricing, Performance & Features URL: https://rafftechnologies.com/learn/compare/raff-vs-linode Description: Considering Linode? Raff is $17.99/mo for 2 vCPU, 4 GB and 80 GB NVMe against an identical $24 Linode Shared CPU plan. Linode is now Akamai Cloud, having been acquired in 2022 and folded into Akamai's edge network. It sells Shared CPU and Dedicated CPU compute, managed databases, Kubernetes, object storage and a large regional footprint, with the developer documentation and community that made Linode's name. Raff Technologies runs the same shape of platform — VMs, managed databases, Kubernetes, object storage, Functions and Apps on one account — from a single us-east region. At the matched shape, a Linode Shared CPU plan with 2 vCPU, 4 GB and 80 GB is $24/month; the identical Raff plan is $17.99. ## Linode VPS and Raff at a glance **Akamai Cloud** sells two compute lines. **Shared CPU** runs from $5/month for 1 vCPU, 1 GB and 25 GB, up to $576/month at 20 vCPU and 96 GB — and Akamai's own pricing page labels this line **"Legacy Hardware."** **Dedicated CPU** is the current G8 generation, from $50.40/month for 2 vCPU, 4 GB and 40 GB. Every plan includes a generous transfer allowance — 1 TB at the entry plan rising to 20 TB — with overage at **$0.005 per GB**, half what most competitors charge. Around the compute sit managed MySQL and PostgreSQL from $16/month, Kubernetes with an optional HA control plane at $60 per cluster per month, and object storage at **$0.02/GB** with the first 1 TB of egress free each month. Behind all of it is Akamai's global edge network, which no independent provider can match. **Raff Technologies** runs 15,000+ VMs for 3,000+ customers from us-east, with a 99.90% monthly uptime SLA backed by service credits, rated 4.5/5 on Trustpilot and 4.6/5 on G2. VMs run AMD EPYC with DDR5 ECC memory and NVMe storage in two lines: General Purpose with shared vCPU from $4.99/month, and CPU-Optimized with dedicated vCPU from $15.99/month, scaling to 16 vCPU and 32 GB. Every plan includes a 3 Gbps port with unmetered transfer, automated Daily or Weekly backup schedules, uncapped snapshots, firewall controls, private networking and full root access. Raff's catalog covers managed PostgreSQL, MySQL, Valkey, ClickHouse and Kafka from $7.99/month, S3-compatible object storage at $7/month for 100 GB with 1 TB of egress, managed Kubernetes with a free control plane and workers from $9.99/month, Functions with a free monthly tier, block volumes at $0.08/GiB-month, and Raff Apps from $3/month. ## Linode VPS pricing vs Raff pricing Linode Shared CPU matches Raff General Purpose; Linode Dedicated CPU matches Raff CPU-Optimized. ### Shared vCPU: Raff General Purpose against Linode Shared CPU | Shape | Raff General Purpose | Linode Shared CPU | |---|---|---| | 1 vCPU / 1 GB | **$4.99** — 25 GB, unmetered | $5.00 — Nanode 1 GB, 25 GB, 1 TB | | 1 vCPU / 2 GB | **$8.99** — 50 GB, unmetered | $12.00 — Linode 2 GB, 50 GB, 2 TB | | 2 vCPU / 4 GB | **$17.99** — 80 GB, unmetered | $24.00 — Linode 4 GB, 80 GB, 4 TB | | 4 vCPU / 8 GB | **$33.99** — 160 GB, unmetered | $48.00 — Linode 8 GB, 160 GB, 5 TB | | 8 vCPU / 16 GB | **$71.99** — 240 GB, unmetered | $96.00 — Linode 16 GB, **6 vCPU**, 320 GB, 8 TB | | 8 vCPU / 32 GB | **$119.99** — 320 GB, unmetered | $192.00 — Linode 32 GB, 640 GB, 16 TB | Four of those rows are **identical on cores, memory and disk** — 25 GB, 80 GB, 160 GB and 640 GB. Raff runs **25% to 38% cheaper** across them, and at the 16 GB shape Raff gives 8 vCPU against Linode's 6 for 25% less. ### Dedicated vCPU: Raff CPU-Optimized against Linode Dedicated CPU (G8) | Shape | Raff CPU-Optimized | Linode Dedicated G8 | |---|---|---| | 2 vCPU / 4 GB | **$36.99** — 80 GB | $50.40 — 40 GB | | 4 vCPU / 8 GB | **$72.99** — 120 GB | $100.80 — 80 GB | | 8 vCPU / 16 GB | **$144.99** — 180 GB | $194.40 — 160 GB | Raff is **25% to 28% cheaper** on dedicated vCPU, with more included disk at every shape. *Akamai Cloud prices read from the North America pricing page on 2026-08-20. Akamai labels the Shared CPU line "Legacy Hardware"; the Dedicated CPU line is the current G8 generation.* ### The hardware-generation caveat That "Legacy Hardware" label matters, and it cuts both ways. The Shared CPU line is the one priced against Raff General Purpose above, and Akamai is signalling it runs on older hosts. If you are buying shared vCPU from Akamai today, you are buying a line the vendor itself marks as legacy — but it is also the line where the transfer allowances are largest, and none of that tells you how a given workload performs. ### Bandwidth cost math Linode's transfer allowances are the most generous in this comparison set — 1 TB to 20 TB by plan, pooled across the account — and overage is **$0.005/GB**, half DigitalOcean's rate. Raff includes unmetered transfer on a 3 Gbps port. | Monthly egress on a 2 vCPU / 4 GB VM | Raff | Linode (4 TB included) | |---:|---|---| | 4 TB | $17.99 | $24.00 | | 8 TB | **$17.99** | $24.00 + $20.48 = $44.48 | | 20 TB | **$17.99** | $24.00 + $81.92 = $105.92 | At 20 TB Linode costs about seven and a half times Raff. But at typical volumes the allowance covers it, and $0.005/GB is a fair overage rate — this axis matters less against Linode than against providers charging twice that. ### Automated backups Linode sells Backups as a per-plan add-on. Raff includes a free backup and snapshot storage pool — 50 GB per account plus 10–15% of each VM's disk — with Daily and Weekly schedules you configure, retention from 1 to 365 days, and uncapped snapshots. Storage above the pool is $0.06/GB-month. ## Linode VPS performance vs Raff This is a clean pairing: both machines are shared-CPU with no dedicated or burstable allocation, both are 2 cores with 4 GB and 80 GB, and both sit in US East — Linode in Cedar Knolls, New Jersey, Raff in us-east. ### Methodology Raff figures are internal, measured March–May 2026 on a General Purpose 2 vCPU / 4 GB instance in us-east. Linode figures are third-party, from VPSBenchmarks, on a **Shared 4GB** plan ($24.00/month, 2 cores / 4 GB / 80 GB, KVM) in New Jersey running Ubuntu 24.04, trial started **17 October 2025** — older than Raff's run, and worth weighing accordingly. ### Results | Metric | Raff General Purpose | Linode Shared 4GB | Notes | |---|---:|---:|---| | Geekbench 6 single-core | **2,266** | 1,245 | Raff 1.82x higher | | Geekbench 6 multi-core | **4,057** | 2,222 | Raff 1.83x higher | | fio 4K read, 50/50 mix | **48,670 IOPS** | 32,269 IOPS | Raff 1.51x higher | | fio 1M sequential read | **2,491 MB/s** | 2,206 MB/s | Raff 1.13x higher | | fio 1M sequential write | 1,257 MB/s | **2,353 MB/s** | Linode 1.87x higher | | iperf3 to NYC, upload | **9,574 Mbps** | 4,506 Mbps | Raff 2.12x higher | | iperf3 to NYC, download | 3,635 Mbps | **8,049 Mbps** | Linode 2.21x higher | | Processor | AMD EPYC, DDR5 ECC | **AMD EPYC 7542** (Zen 2, 2019) | | | Monthly price | **$17.99** | $24.00 | | ### What the results tell us **Raff is roughly 1.8x faster per core**, on the same shared-CPU basis, at the same shape, in the same region — and for 25% less money. **The processor line explains why, and it corroborates Akamai's own label.** The benchmarked Linode host runs an **AMD EPYC 7542**, a Zen 2 part launched in 2019. That is consistent with Akamai marking the Shared CPU line "Legacy Hardware": the plans are priced against current-generation shared vCPU elsewhere but run on older silicon. It is also a reason to treat the CPU gap as a hardware-generation gap rather than a permanent platform difference — Akamai could refresh the line. **Linode wins two axes, and both are real.** Sequential 1M write measured 2,353 MB/s against Raff's 1,257, and download to New York 8,049 Mbps against 3,635. The download figure reflects capability rather than measurement noise: Linode publishes a 4,000 Mbps maximum network speed on this plan against Raff's 3 Gbps port. If your workload pulls large volumes inbound or writes large sequential files, Linode's configuration is the stronger one. **Random I/O and sequential read favour Raff** — 1.51x on the 4K mixed job, which is the pattern most databases actually run. Read it as a trade: Raff for CPU-bound work and small-block I/O at lower cost, Linode for sequential writes and inbound bandwidth. ## Linode vs Raff: features and reliability ### Compute Linode scales to 20 vCPU and 96 GB on Shared CPU and well beyond on Dedicated, against Raff's ceiling of 16 vCPU and 32 GB. Below that ceiling Raff resizes on demand: stop the VM, switch plan, restart, with the difference settled to the account balance and a `resize` API endpoint for CPU, RAM and disk. ### Networking and bandwidth Raff includes a 3 Gbps port with unmetered transfer, private networking, VPC, firewall controls and site-to-site VPN gateways. Linode includes 1–20 TB of pooled transfer with $0.005/GB overage, private networking, cloud firewalls and NodeBalancers — and sits on Akamai's edge network, which is a genuine advantage for globally distributed delivery. ### Storage and object storage Raff separates storage into VM disk, block volumes at $0.08/GiB-month, and S3-compatible object storage at $7/month for 100 GB with 1 TB of egress. Linode object storage is **$0.02/GB-month with the first 1 TB of egress free** and $0.005/GB after. On object storage Linode is substantially cheaper — roughly $0.02/GB against Raff's effective $0.07/GB at the entry tier. If your workload is storage-heavy rather than compute-heavy, that difference can outweigh the VM saving. ### Managed databases Raff runs PostgreSQL, MySQL, Valkey, ClickHouse and Kafka **from $7.99/month**. Linode runs managed MySQL and PostgreSQL **from $16/month** for a single shared 1 GB node. Raff is roughly 50% cheaper at entry and covers five engines against two. ### Kubernetes Both offer managed Kubernetes. Raff provides a free control plane with workers from $9.99/month and an HA add-on at $30. Linode's LKE HA control plane is **$60 per cluster per month**. For a production cluster needing high availability, Raff's HA option is half the price. ### Support and ecosystem Raff provides 24/7 human support through live chat, with a first response typically under 10 minutes. No bots triaging you first, and no support tier to buy: a single $4.99 VM reaches the same engineers as a hundred production machines. Linode's advantage is the ecosystem around it: a documentation and tutorial library built over two decades, an active community, and since the Akamai acquisition, integration with one of the largest edge and security networks in the world. Raff has none of that reach, and no comparison should pretend otherwise. ## When you should choose Linode over Raff - **Object-storage-heavy workloads** — $0.02/GB-month with 1 TB of free egress, against Raff's $7 for 100 GB - **Global delivery** — Akamai's edge network and a regional footprint spanning North America, Europe and Asia-Pacific against Raff's single us-east region - **Very large instances** — up to 20 vCPU and 96 GB on Shared CPU and further on Dedicated, against Raff's 16 vCPU / 32 GB ceiling - **Inbound-heavy and sequential-write workloads** — measured 2.21x higher download to New York and 1.87x higher 1M sequential write, on a 4,000 Mbps port - **Large monthly transfer within allowance** — 4 TB to 20 TB included by plan, with a low $0.005/GB overage - **Teams that rely on documentation and community** — two decades of Linode guides and an active forum ## When you should choose Raff over Linode - **Lower cost on equivalent VMs** — 25% to 38% below Shared CPU and 25% to 28% below Dedicated G8, at identical disk on four matched shapes ([VPS for application hosting](/learn/guides/vps-for-application-hosting)) - **Current hardware on the shared line** — Akamai labels its Shared CPU plans "Legacy Hardware", and the benchmarked host runs a 2019-era EPYC 7542; Raff measured 1.82x faster single-core at the same shape - **Database-backed products** — managed PostgreSQL, MySQL, Valkey, ClickHouse and Kafka from $7.99/month against $16 for two engines ([VPS for databases](/learn/guides/vps-for-databases)) - **Highly available Kubernetes** — $30 for the HA add-on against $60 per cluster per month - **Egress-heavy applications** — unmetered transfer on a 3 Gbps port, with no allowance to track - **Backups without an add-on** — Daily and Weekly schedules on a free storage pool with 1 to 365 day retention ## Migrating from Linode to Raff 1. **Match the line, not the price** — Linode Shared CPU maps to Raff General Purpose, Dedicated G8 to Raff CPU-Optimized. Mapping by monthly cost will land you in the wrong class. 2. **Check the ceiling** — Raff stops at 16 vCPU and 32 GB. Larger Linode instances have no equivalent. 3. **Price object storage separately** — Linode is cheaper per GB. If you hold significant object data, consider leaving it where it is rather than assuming the whole account should move. 4. **Check what the edge network is doing for you** — if Akamai's CDN or security services are in your delivery path, moving compute does not move those, and you may still need them. 5. **Move data in order** — files with rsync or SCP, then database dumps into managed Postgres or MySQL, then assets to object storage. Keep the Linode instance running throughout. 6. **Cut over and delete, don't power off** — lower DNS TTL beforehand, switch, then delete the Linode. A powered-off instance still bills. ## About Linode Linode is a cloud computing provider founded in 2003 and headquartered in Philadelphia, acquired by Akamai Technologies in 2022 and now operating as Akamai Cloud. It offers Shared CPU and Dedicated CPU compute, managed databases, Kubernetes, object storage and NodeBalancers from regions across North America, Europe and Asia-Pacific, integrated with Akamai's global edge platform. See [Akamai Cloud pricing](https://www.akamai.com/cloud/pricing) for current rates. ## Conclusion: Linode or Raff? For broader buying criteria beyond this two-provider comparison, see the [VPS provider selection guide](/learn/guides/how-to-choose-a-vps-provider). The comparison resolves across four axes: - **VM price** — Raff wins, 25% to 38% below Shared CPU and 25% to 28% below Dedicated G8, at identical disk on four matched shapes - **Object storage** — Linode wins, $0.02/GB-month with 1 TB free egress against Raff's $7 for 100 GB - **Reach** — Linode wins, with Akamai's edge network and regions across three continents against Raff's single us-east - **Managed services** — Raff wins, five database engines from $7.99/month against two from $16, and HA Kubernetes at $30 against $60 If you need global reach, cheap object storage at scale, instances above 16 vCPU, or Akamai's edge and security services, choose Linode. If your users are in North America and your bill is dominated by VMs and managed databases, choose Raff — the same workload costs 25% to 38% less. Raff runs 15,000+ VMs for 3,000+ customers and is rated 4.5/5 on Trustpilot, with a 99.90% monthly uptime SLA in writing. --- ### UpCloud Alternative 2026: Pricing, Performance & Features URL: https://rafftechnologies.com/learn/compare/raff-vs-upcloud Description: Considering UpCloud? Raff is $17.99/mo for 2 vCPU, 4 GB and 80 GB NVMe against UpCloud Premium at about $30.14 with 50 GB. UpCloud is a Finnish cloud provider that has sold infrastructure since 2011, with 15 data centers across four continents and a 99.999% uptime SLA on its production tiers. Raff Technologies is a US cloud provider running 15,000+ VMs for 3,000+ customers from a single us-east region. Both sell shared-vCPU cloud servers, managed databases, managed Kubernetes and object storage, so this is a platform comparison rather than a server comparison. At the matched production shape, Raff General Purpose is $17.99/month for 2 vCPU, 4 GB and 80 GB NVMe; the equivalent UpCloud Premium plan is about $30.14 with 50 GB. ## UpCloud VPS and Raff at a glance **UpCloud** sells three cloud-server lines. **Starter** is the budget tier on previous-generation AMD CPUs and Standard SSD, from €3/month with a 99.99% SLA. **Premium** is the production tier on newer AMD CPUs with MaxIOPS storage included, from €5/month at 99.999%. **Cloud Native** decouples compute from storage, from €12/month, and stops charging compute while a server is stopped. UpCloud publishes no CPU-dedication guarantee on any of the three — its only dedicated-hardware product is Private Cloud, from €3,190/month. Around the servers sits a substantial catalog: Managed Databases for PostgreSQL and MySQL from €9/month, Valkey from €8/month and OpenSearch from €100/month; Managed Kubernetes with a free development control plane and €60/month for production; block storage in MaxIOPS, Standard and Archive tiers; managed NFS file storage; object storage; load balancers; NAT and VPN gateways; GPU servers with NVIDIA L4 through B200; and Private Cloud on dedicated hardware. **Raff Technologies** runs 15,000+ VMs for 3,000+ customers from us-east, with a 99.9% uptime SLA backed by service credits, rated 4.5/5 on Trustpilot and 4.6/5 on G2. VMs run AMD EPYC with DDR5 ECC memory and NVMe storage in two lines: General Purpose with shared vCPU from $4.99/month, and CPU-Optimized with dedicated vCPU from $15.99/month, scaling to 16 vCPU and 32 GB. Every plan includes a 3 Gbps port with unmetered transfer, automated Daily or Weekly backup schedules, uncapped snapshots, firewall controls, private networking and full root access. Raff's platform covers managed PostgreSQL, MySQL, Valkey, ClickHouse and Kafka from $7.99/month, S3-compatible object storage at $7/month for 100 GB and 1 TB of egress, managed Kubernetes with a free control plane and workers from $9.99/month, Functions with a free monthly tier, block volumes at $0.08/GiB-month, and Raff Apps from $3/month. One structural difference is worth stating up front: **UpCloud has 15 regions to Raff's one.** If your users sit outside North America, that matters more than anything else on this page. ## UpCloud VPS pricing vs Raff pricing UpCloud publishes no CPU-dedication guarantee on Starter, Premium or Cloud Native, which makes **Raff General Purpose the like-for-like match** and means Raff CPU-Optimized has no UpCloud counterpart short of Private Cloud. **Premium is the fair comparison**: both include storage in the plan price, both are the production tier, both carry the vendor's top SLA. | Shape | Raff General Purpose | UpCloud Premium | |---|---|---| | 1 vCPU / 1 GB | **$4.99** — 25 GB NVMe | €5 ≈ $5.80 — 25 GB MaxIOPS | | 2 vCPU / 2 GB | **$12.99** — 40 GB NVMe | €16 ≈ $18.55 — 50 GB MaxIOPS | | 2 vCPU / 4 GB | **$17.99** — 80 GB NVMe | €26 ≈ $30.14 — 50 GB MaxIOPS | | 2 vCPU / 8 GB | **$27.99** — 160 GB NVMe | €38 ≈ $44.05 — 100 GB MaxIOPS | | 4 vCPU / 8 GB | **$33.99** — 160 GB NVMe | €52 ≈ $60.28 — 100 GB MaxIOPS | | 4 vCPU / 16 GB | **$55.99** — 240 GB NVMe | €92 ≈ $106.66 — 150 GB MaxIOPS | | 8 vCPU / 16 GB | **$71.99** — 240 GB NVMe | €148 ≈ $171.58 — 200 GB MaxIOPS | | 8 vCPU / 32 GB | **$119.99** — 320 GB NVMe | €192 ≈ $222.59 — 200 GB MaxIOPS | *Raff General Purpose against UpCloud Premium — both shared vCPU with storage included. UpCloud prices read 2026-08-18, exclude local taxes, converted at €1 = $1.1593 (ECB, 2026-08-17).* Raff is **30% to 58% cheaper at every matched tier above the entry shape, and includes more storage at every one of them** — 240 GB against 200 GB at 8 vCPU / 16 GB, 640 GB against 200 GB at 8 vCPU / 32 GB. Only the 1 vCPU / 1 GB entry is close, and Raff is still 14% lower there. ### UpCloud's Starter line for reference Starter is UpCloud's budget tier, and it is genuinely cheaper than Raff: | Shape | Raff General Purpose | UpCloud Starter | |---|---|---| | 1 vCPU / 1 GB | $4.99 — 25 GB | **€3 ≈ $3.48** — 10 GB | | 2 vCPU / 4 GB | $17.99 — 80 GB | **€12 ≈ $13.91** — 30 GB | | 2 vCPU / 8 GB | $27.99 — 160 GB | **€18 ≈ $20.87** — 40 GB | | 4 vCPU / 16 GB | $55.99 — 240 GB | **€28 ≈ $32.46** — 50 GB | What Starter gives up is stated by UpCloud itself: **previous-generation AMD CPUs**, Standard SSD rather than MaxIOPS, a **99.99% SLA instead of 99.999%**, and 250–500 Mbit/s rather than 1000 Mbps. Storage is three to six times smaller at every tier. If your workload fits that envelope, Starter is the cheaper buy and this page will not argue otherwise. ### Cloud Native — compute and storage billed separately Cloud Native decouples the two: compute from €12/month for 4 GB / 1 core, with storage added at €0.220/GB-month for MaxIOPS, €0.085 for Standard, or €0.056 for Archive. A 2-core, 4 GB Cloud Native server with 80 GB Standard storage works out at about €21.80 ≈ $25.27/month against Raff's $17.99 with 80 GB included. The model is useful when storage and compute scale independently, or when a stopped server should stop billing — UpCloud does not charge for compute while a Cloud Native server is stopped, which Raff does not offer. ### Bandwidth Neither provider bills standard outbound transfer per gigabyte. Raff includes unmetered transfer on a 3 Gbps port. UpCloud includes transfer under a Fair Transfer Policy with zero-cost egress, at 250–500 Mbit/s on Starter and 1000 Mbps on Premium and Cloud Native. Raff's port is three times faster than UpCloud's fastest tier; UpCloud's policy is a fair-share model rather than a hard cap. ### Automated backups Raff includes a free backup and snapshot storage pool — 50 GB per account plus 10–15% of each VM's disk — with Daily and Weekly schedules you configure, retention from 1 to 365 days, and uncapped snapshots. Storage above the pool is $0.06/GB-month. UpCloud Simple Backups are priced by server plan or by storage size and retention schedule, so backup cost scales with what you keep rather than being bundled. ## UpCloud VPS performance vs Raff ### Methodology Measured 30 March 2026 on Ubuntu 24.04, single-pass: Raff CPU-Optimized 2 vCPU / 4 GB in us-east against UpCloud Cloud Native 2 cores / 4 GB in Helsinki. Paid at standard rates by Raff Technologies, with no sponsorship or rebate from UpCloud. UpCloud publishes no dedicated-vCPU line, so no same-class pairing exists. ### Results | Benchmark | Raff | UpCloud | Notes | |---|---:|---:|---| | Geekbench 6 single-core | **2,266** | 1,627 | Raff 1.39x higher | | Geekbench 6 multi-core | **4,057** | 2,944 | Raff 1.38x higher | | sysbench CPU single-thread | **2,171 ops/s** | 1,591 ops/s | Raff 1.36x higher | | sysbench CPU multi-thread | **4,320 ops/s** | 3,167 ops/s | Raff 1.36x higher | | sysbench memory read | **17.79 GiB/s** | 10.41 GiB/s | Raff 1.71x higher | | sysbench memory write | **11.42 GiB/s** | 4.70 GiB/s | Raff 2.43x higher | | fio 64K read | **1,459.6 MB/s** | 401.5 MB/s | Raff 3.64x higher | | fio 64K write | **1,467.3 MB/s** | 403.6 MB/s | Raff 3.64x higher | | sysbench random read 4K | 52.31 MiB/s | **151.07 MiB/s** | UpCloud 2.89x higher | | sysbench random write 4K | 25.15 MiB/s | **42.55 MiB/s** | UpCloud 1.69x higher | | sysbench sequential read 128K | **1,730 MiB/s** | 401.38 MiB/s | Raff 4.31x higher | | sysbench sequential write 128K | **664.85 MiB/s** | 398.93 MiB/s | Raff 1.67x higher | | Best IPv4 download | **3,635 Mbps** | 1,075 Mbps | Raff 3.38x higher | | Best IPv4 upload | **9,574 Mbps** | 6,154 Mbps | Raff 1.56x higher | ### What the results tell us Raff led CPU by roughly 1.36x to 1.39x on both Geekbench and sysbench, memory write by 2.43x, sequential and 64K disk throughput by 1.67x to 3.64x, and network by 1.56x to 3.38x. **UpCloud won small-block random I/O** — 2.89x on 4K random read and 1.69x on 4K random write. That is the pattern databases and write-heavy queues care about most, and it comes from UpCloud's MaxIOPS storage, which is built for exactly that. If your bottleneck is small synchronous writes, UpCloud's storage is the stronger platform in this test. Read it as a trade: Raff for CPU, memory, sequential throughput and egress; UpCloud for small-block random I/O. ## UpCloud vs Raff: features and reliability ### Compute UpCloud offers three shared-vCPU lines from 1 to 80 cores and 1 GB to 512 GB RAM — a far wider ceiling than Raff's 16 vCPU and 32 GB. Raff offers General Purpose from $4.99/month and CPU-Optimized dedicated vCPU from $15.99/month, on AMD EPYC with DDR5 ECC memory, and resizes on demand: stop the VM, switch plan, restart, with the difference settled to the account balance and a `resize` API endpoint. ### Networking Raff includes a 3 Gbps port with unmetered transfer, private networking, VPC, firewall controls and site-to-site VPN gateways. UpCloud includes 1000 Mbps on production tiers with zero-cost egress, software-defined private networks, load balancers, and managed NAT and VPN gateways. ### Storage Raff separates storage into VM disk, block volumes at $0.08/GiB-month and object storage at $7/month for 100 GB with 1 TB of egress. UpCloud offers three block tiers — MaxIOPS at €0.220/GB-month with up to 100k IOPS, Standard at €0.085, Archive at €0.056 — plus managed NFS file storage, which Raff does not offer. UpCloud's storage catalog is the more configurable of the two; Raff's is the simpler. ### Support and reliability Raff provides 24/7 human support through live chat, with a first response typically under 10 minutes. No bots triaging you first, and no support tier to buy: a single $4.99 VM reaches the same engineers as a hundred production machines. On published commitments, UpCloud advertises 99.999% monthly uptime on Premium and Cloud Native; Raff commits to **99.90% monthly, contractual with service credits**, measured from a public status page. Both figures are credit thresholds rather than measured availability, and neither vendor's number is evidence of what your workload will actually see. What is clearly in UpCloud's favour is footprint: 15 data centers against Raff's single us-east region. ### Platform Both sell the layers around the VM, which makes this a rare like-for-like platform comparison. | Product | Raff | UpCloud | |---|---|---| | Managed PostgreSQL / MySQL | **from $7.99/mo** | from €9/mo ≈ $10.43 | | Managed Valkey / Redis-compatible | **from $7.99/mo** | from €8/mo ≈ $9.27 | | Managed Kubernetes control plane | **free** | free (dev) · €60/mo production | | Object storage | **$7/mo — 100 GB + 1 TB egress** | available | | Block storage | **$0.08/GiB-mo** | €0.085 Standard ≈ $0.099 · €0.220 MaxIOPS | | Functions / serverless | **free tier, 100,000 GB-s** | not offered | | PaaS / app deployment | **Raff Apps from $3/mo** | not offered | | ClickHouse | **from $59.99/mo** | not offered | | Kafka | **from $79.99/mo** | not offered | | OpenSearch | not offered | **from €100/mo** | | Managed NFS file storage | not offered | **available** | | GPU servers | not offered | **NVIDIA L4 – B200** | | Private cloud | not offered | **from €3,190/mo** | Raff is cheaper on the products both sell and adds Functions, Apps, ClickHouse and Kafka. UpCloud adds OpenSearch, NFS, GPU and Private Cloud, and its Kubernetes production tier costs €60/month where Raff's control plane is free at every size. ## When you should choose UpCloud over Raff - **Users outside North America** — 15 data centers across four continents against Raff's single us-east region - **Small-block random I/O workloads** — MaxIOPS measured 2.89x higher on 4K random read in paid head-to-head testing - **GPU, search or shared-filesystem workloads** — NVIDIA L4 through B200, managed OpenSearch and managed NFS, none of which Raff sells - **Budget servers where specs can slip** — the Starter line undercuts Raff at every tier if previous-generation CPUs and smaller disks are acceptable - **Very large single servers** — up to 80 cores and 512 GB RAM against Raff's 16 vCPU and 32 GB ## When you should choose Raff over UpCloud - **Production VMs at lower cost** — 30% to 58% cheaper than UpCloud Premium at every matched tier, with more storage included at each ([VPS for application hosting](/learn/guides/vps-for-application-hosting)) - **CPU and memory-bound services** — 1.36x to 1.39x faster CPU and 2.43x faster memory write in paid head-to-head testing - **Egress-heavy applications** — a 3 Gbps unmetered port against 1000 Mbps, and 3.38x measured download throughput - **Database-backed products** — managed PostgreSQL, MySQL, Valkey, ClickHouse and Kafka from $7.99/month against €9/month, on the same account over private networking ([VPS for databases](/learn/guides/vps-for-databases)) - **Kubernetes at production scale** — a free control plane at every cluster size, against €60/month for UpCloud's production tier - **Serverless and app deployment** — Functions with a free monthly tier and Raff Apps from $3/month, neither of which UpCloud offers ## Migrating from UpCloud to Raff 1. **Check your region requirement first** — Raff serves us-east only. If your users are in Europe or Asia, this migration adds latency that no other difference offsets. 2. **Right-size on utilisation** — UpCloud shapes run wider than Raff's ceiling of 16 vCPU and 32 GB. Measure what the workload actually uses before assuming a match exists. 3. **Test disk-bound paths explicitly** — UpCloud MaxIOPS measured faster on small-block random I/O. If your application is bound by small synchronous writes, benchmark it on Raff before committing. 4. **Move data in order** — files with rsync or SCP, then database dumps into managed Postgres or MySQL, then static assets to object storage. Keep the UpCloud server running throughout. 5. **Cut over and verify billing** — lower DNS TTL beforehand, switch, then confirm your UpCloud resources are deleted rather than stopped, since block storage bills whether or not a server runs. ## About UpCloud UpCloud is a Finnish cloud infrastructure provider founded in 2011 and headquartered in Helsinki, offering cloud servers, managed databases, managed Kubernetes, object and file storage, GPU servers and private cloud from 15 data centers across Europe, North America, Asia and Australia. See [UpCloud pricing](https://upcloud.com/pricing) for current plans and terms. ## Conclusion: UpCloud or Raff? If benchmarks influence your choice, use the [VPS benchmarking guide](/learn/guides/vps-benchmarking-guide) to compare repeatable workload-specific results instead of one headline score. The comparison resolves across four axes: - **Price** — Raff wins on the production tier, 30% to 58% below UpCloud Premium with more storage included; UpCloud's Starter line is cheaper than both - **Performance** — split: Raff leads CPU, memory, sequential disk and network; UpCloud leads small-block random I/O by 2.89x - **Reach** — UpCloud wins, 15 data centers across four continents against Raff's single us-east region - **Platform** — Raff is cheaper on the products both sell and adds Functions, Apps, ClickHouse and Kafka; UpCloud adds OpenSearch, NFS, GPU and Private Cloud If you need multiple regions, GPU or shared filesystems, choose UpCloud. If your users are in North America and you want production VMs and managed databases at materially lower cost, choose Raff. Raff runs 15,000+ VMs for 3,000+ customers and is rated 4.5/5 on Trustpilot, with a 99.9% uptime SLA in writing. --- ### AWS Lightsail Pricing 2026: Plans, Costs & Raff Comparison URL: https://rafftechnologies.com/learn/compare/raff-vs-aws-lightsail Description: AWS Lightsail pricing starts at $3.50 IPv6-only or $5 with IPv4; the 2 vCPU / 4 GB / 80 GB plan is $24. Compare bundles, transfer, add-ons, and Raff. AWS Lightsail pricing in 2026 starts at **$3.50/month for an IPv6-only Linux/Unix virtual server** or **$5/month for a Linux/Unix bundle with a public IPv4 address**. The popular public-IPv4 General Purpose tier with **2 vCPU, 4 GB RAM, 80 GB SSD, and 4 TB transfer is $24/month**. Lightsail bundles compute, SSD storage, and a transfer allowance into one monthly cap, but snapshots, block storage, load balancers, databases, object storage, and transfer overages are separate charges. Raff uses a different VM pricing model. Its current General Purpose **2 vCPU / 4 GB / 80 GB NVMe** plan is **$17.99/month with unmetered VM bandwidth**. At the four Lightsail General Purpose shapes that match Raff on vCPU and RAM, Raff is about **25% to 36% lower on monthly VM price** before any Lightsail transfer overage. This page focuses on the actual cost question: what Amazon Lightsail costs, what the monthly bundle includes, where extra charges appear, and when the simpler Raff price model can be cheaper. ## AWS Lightsail pricing in 2026 Amazon Lightsail offers General Purpose, Memory Optimized, and Compute Optimized virtual-server bundles. It also prices Linux/Unix and Windows separately and offers a lower-priced IPv6-only option for virtual servers that do not need a public IPv4 address. The current **Linux/Unix General Purpose bundles with public IPv4** include: | Monthly price | Memory | vCPU | SSD disk | Transfer allowance | |---:|---:|---:|---:|---:| | $5 | 0.5 GB | 2 vCPU | 20 GB | 1 TB | | $7 | 1 GB | 2 vCPU | 40 GB | 2 TB | | $12 | 2 GB | 2 vCPU | 60 GB | 3 TB | | $24 | 4 GB | 2 vCPU | 80 GB | 4 TB | | $44 | 8 GB | 2 vCPU | 160 GB | 5 TB | | $84 | 16 GB | 4 vCPU | 320 GB | 6 TB | | $164 | 32 GB | 8 vCPU | 640 GB | 7 TB | | $384 | 64 GB | 16 vCPU | 1,280 GB | 8 TB | Lightsail also scales much higher than Raff, including larger General Purpose, Memory Optimized, and Compute Optimized bundles. That matters when a workload needs more than Raff's current 16 vCPU / 32 GB ceiling. ### AWS Lightsail IPv6-only pricing Lightsail discounts virtual servers that use only IPv6. Current Linux/Unix General Purpose examples are: | Monthly price | Memory | vCPU | SSD disk | Transfer allowance | |---:|---:|---:|---:|---:| | $3.50 | 512 MB | 2 vCPU | 20 GB | 1 TB | | $5 | 1 GB | 2 vCPU | 40 GB | 2 TB | | $10 | 2 GB | 2 vCPU | 60 GB | 3 TB | | $20 | 4 GB | 2 vCPU | 80 GB | 4 TB | | $40 | 8 GB | 2 vCPU | 160 GB | 5 TB | | $80 | 16 GB | 4 vCPU | 320 GB | 6 TB | | $160 | 32 GB | 8 vCPU | 640 GB | 7 TB | If the application can operate without public IPv4, the IPv6-only bundle is the correct Lightsail price to compare. If you need a public IPv4 address, use the public-IPv4 table instead of quoting the $3.50 entry price. ## What is included in AWS Lightsail pricing? Lightsail's core appeal is that a virtual-server plan bundles several resources under one monthly price. AWS currently lists a static IP address, management console, DNS management, one-click SSH or RDP access, API access, SSD storage, and server monitoring among the capabilities included with Lightsail plans. The VM price also includes a transfer allowance. For the public-IPv4 General Purpose Linux bundles above, that allowance ranges from 1 TB on the smallest plan to 10 TB on the largest tiers. However, the VM bundle is not the entire Lightsail bill. Common separate charges include: | Lightsail add-on | Current pricing signal | |---|---:| | Manual or automatic snapshots | $0.05/GB-month | | Block storage | $0.10/GB-month | | Load balancer | $18/month | | Object storage | $1/mo for 5 GB, $3/mo for 100 GB, $5/mo for 250 GB | | Managed database | Starts at $15/mo Standard or $30/mo HA | | CDN distribution | Starts at $2.50/month | The practical lesson is that **Lightsail virtual-server pricing is predictable at the bundle level, but the full application price can grow as you add storage, backups, databases, load balancing, CDN, and transfer overages.** ## AWS Lightsail vs Raff pricing Raff's current General Purpose VM lineup is designed around several CPU-to-memory ratios rather than one fixed ladder. Four Lightsail General Purpose shapes match a Raff plan on **vCPU and RAM**. On the two largest, Lightsail bundles more disk, so those rows are a CPU-and-memory match rather than a like-for-like disk match: | Shape | Raff General Purpose | AWS Lightsail public IPv4 | Raff price difference | |---|---:|---:|---:| | 2 vCPU / 4 GB | **$17.99/mo** — 80 GB NVMe | $24/mo — 80 GB SSD | about 25% lower | | 2 vCPU / 8 GB | **$27.99/mo** — 160 GB NVMe | $44/mo — 160 GB SSD | about 36% lower | | 4 vCPU / 16 GB | **$55.99/mo** — 240 GB NVMe | $84/mo — 320 GB SSD | about 33% lower | | 8 vCPU / 32 GB | **$119.99/mo** — 320 GB NVMe | $164/mo — 640 GB SSD | about 27% lower | The comparison above is deliberately narrow. It compares monthly VM price at matching resource shapes. It does **not** imply identical CPU behavior, storage architecture, region coverage, ecosystem depth, or service feature parity. Raff also offers smaller and alternative ratios, including 2 vCPU / 2 GB at $12.99, 4 vCPU / 4 GB at $24.99, and 4 vCPU / 8 GB at $33.99. All current Raff General Purpose VM plans include unmetered bandwidth on a 3 Gbps public port. For current Raff sizes, see [Raff cloud pricing](/pricing) and [Raff General Purpose VM Plans](/learn/guides/raff-general-purpose-vm-plans-explained). ## AWS Lightsail bandwidth pricing and transfer overages The transfer allowance is the most important variable after VM size. AWS states that **both inbound and outbound transfer count toward the Lightsail allowance**, but only **outbound transfer above the allowance** is billed as overage. Transfer allowances are also smaller in several Asia-Pacific and South America regions than the headline bundle values. Overage pricing varies by AWS Region. In **US East**, Lightsail transfer overage is currently **$0.09/GB**. For the $24 public-IPv4 General Purpose plan with a 4 TB transfer allowance, a simple all-outbound example looks like this: | Monthly outbound transfer | Raff 2 vCPU / 4 GB | Lightsail 2 vCPU / 4 GB | |---:|---:|---:| | 2 TB | $17.99 | $24 | | 4 TB | $17.99 | $24 | | 6 TB | $17.99 | about $204 | | 8 TB | $17.99 | about $384 | | 20 TB | $17.99 | about $1,464 | The Lightsail examples use $0.09/GB and 1 TB = 1,000 GB for the overage calculation. Real bills depend on region, ingress/outbound mix, pooled allowances, and other Lightsail resources. For low-traffic applications, the included allowance may be plenty and no overage appears. For public downloads, media delivery, large restores, software distribution, or unexpectedly viral traffic, the transfer line can become the dominant cost. Raff VM bandwidth is currently unmetered, so those examples remain at the VM's monthly price rather than adding a GB-based transfer charge. ## Is AWS Lightsail free? AWS currently includes Lightsail in the AWS Free Tier and advertises free-start offers for selected Lightsail bundles. The exact eligible plans and duration can depend on the current AWS Free Tier offer and account eligibility, so treat the free tier as an onboarding offer rather than the long-term production price. For production planning, use the normal bundle prices above and verify any free-tier credit separately on AWS before deployment. ## AWS Lightsail snapshot and backup costs Lightsail prices **manual and automatic instance/disk snapshots at $0.05/GB-month**. That means backup cost scales with snapshot storage rather than being permanently included in the VM bundle. Raff uses a different backup model. Current Raff VM accounts receive a backup and snapshot storage pool, with additional storage priced separately. The important architecture point is that neither provider's backup cost should be inferred from the VM headline price alone: check retention, snapshot growth, and restore requirements. For recovery planning, see [VPS backup strategy](/learn/guides/cloud-server-backup-strategies) and [Raff Data Protection](/products/data-protection). ## Lightsail block storage, load balancer, database, and object-storage pricing A multi-service Lightsail architecture can add several fixed or usage-based components: - **Block storage:** $0.10 per allocated GB-month, starting at 8 GB. - **Load balancer:** $18/month. - **Object storage:** bundles currently start at $1/month for 5 GB and 25 GB transfer; the 100 GB bundle is $3/month with 250 GB transfer. - **Managed databases:** Standard plans start at $15/month; HA starts at $30/month. - **CDN distributions:** start at $2.50/month. This is why a fair Lightsail cost calculation should model the application architecture, not only the VM. A WordPress site using a VM, CDN distribution, and object storage has a different monthly bill from a single Lightsail instance. A SaaS application using a VM, managed database, snapshots, and load balancer has a different cost again. ## AWS Lightsail pricing calculator: what to include Before comparing Lightsail with another VPS or cloud provider, estimate at least these variables: 1. Linux/Unix or Windows; 2. public IPv4 or IPv6-only; 3. General Purpose, Memory Optimized, or Compute Optimized; 4. required vCPU, RAM, and SSD capacity; 5. monthly inbound and outbound transfer; 6. transfer-overage region; 7. snapshot storage and retention; 8. attached block storage; 9. load balancers; 10. managed databases; 11. object storage and CDN usage; 12. whether the workload will stay inside Lightsail or expand into the wider AWS catalog. That final point matters. Lightsail can be economical as a simple VPS, but an application that gradually adds RDS, S3, CloudFront, Lambda, Route 53, or other AWS services is no longer a Lightsail-only pricing problem. ## AWS Lightsail vs Raff: features and operating model ### Compute Lightsail offers a much wider upper range than Raff and now exposes General Purpose, Memory Optimized, and Compute Optimized bundles. The smallest Lightsail plans are attractive for tiny workloads, especially when IPv6-only is acceptable. Raff General Purpose starts at 2 vCPU / 2 GB / 40 GB NVMe for $12.99/month and offers multiple CPU-to-memory ratios through 16 vCPU / 32 GB. Raff also has a separate CPU-Optimized line for workloads that need a different compute model. ### Networking Raff current VM plans include a 3 Gbps public port and unmetered bandwidth, plus private networking, VPC, firewall controls, and IPv4 with optional IPv6. Lightsail bundles a transfer allowance with each virtual server. Only outbound transfer above the allowance is billed, and regional overage prices apply. Lightsail also includes DNS tooling and supports load balancers and CDN distributions as separate products. ### Storage Both platforms separate VM disk from other storage products. Raff offers NVMe-backed VM disk, block volumes, and S3-compatible Object Storage. Lightsail offers SSD bundle storage, block storage, snapshots, and Lightsail Object Storage, with Amazon S3 available elsewhere in the AWS account. ### Managed databases and application services Lightsail offers managed databases and a container service, while the wider AWS account provides products such as RDS, Lambda, EKS, S3, CloudFront, and many more. Raff provides managed databases, Kubernetes, Apps, Functions, object storage, VPC, and data protection under the same platform. AWS wins on catalog breadth; Raff focuses on a smaller infrastructure surface with simpler pricing. ## What about AWS Lightsail performance? There is **no current controlled Raff-vs-Lightsail benchmark with the same VM shape, region, image, test window, and methodology** that is strong enough to support a responsible performance winner. The earlier comparison used third-party Lightsail data and Raff internal data from different regions and different memory sizes. Those results are not suitable for a direct speed claim, so this update does not present them as a benchmark. If performance is the deciding factor, test the exact Lightsail and Raff shapes you would buy using the same OS image, CPU workload, disk test, network path, and sustained-load duration. Pricing can be compared from published rate cards; performance needs matched measurement. ## When AWS Lightsail is the better choice Choose Lightsail when: - you want a very small VM starting below Raff's entry price; - an IPv6-only server fits the workload and you want the lowest Lightsail bundle price; - your application already lives inside an AWS account; - you expect to use RDS, S3, CloudFront, Lambda, Route 53, or other AWS services; - you need a much larger VM than Raff's current maximum; - you need broader AWS region coverage; - AWS-specific contracts, compliance controls, IAM practices, or operational tooling are already part of the organization. Lightsail's strongest advantage is the path into the broader AWS ecosystem, not merely the VPS bundle price. ## When Raff is the better choice Choose Raff when: - a current Raff shape matches the workload and you want a lower monthly VM price; - bandwidth usage is high or difficult to predict; - you want unmetered VM transfer rather than a transfer allowance and regional overage model; - the application needs the common infrastructure layers rather than the full AWS service catalog; - you want VM, database, storage, networking, Kubernetes, Apps, Functions, and support under a smaller platform surface; - predictable monthly infrastructure cost matters more than access to hundreds of AWS services. At the exact 2 vCPU / 4 GB / 80 GB match, Raff is currently $17.99/month versus Lightsail public-IPv4 General Purpose at $24/month. :::cta Deploy a Cloud Server Deploy a Raff VM with unmetered bandwidth and current General Purpose plans from $12.99/month. ::: ## Migrating from AWS Lightsail to Raff 1. **Export the real monthly cost first.** Review the last several Lightsail bills for VM bundles, transfer overage, snapshots, block storage, databases, CDN, and load balancers. 2. **Inventory AWS dependencies.** Identify S3, RDS, CloudFront, Route 53, IAM, Lambda, or other services that will stay in AWS if only the VM moves. 3. **Choose the Raff shape from measured usage.** Match CPU, RAM, and storage based on actual workload metrics instead of copying the Lightsail bundle blindly. 4. **Provision networking and security.** Recreate firewall rules, private networking, credentials, and monitoring before moving production traffic. 5. **Move state deliberately.** Copy files, database data, and application assets using a tested migration plan. Keep the source available until checks pass. 6. **Lower DNS TTL and cut over.** Switch traffic only after application, database, storage, and backup verification. 7. **Delete unneeded AWS resources after rollback.** Removing the instance alone may not remove snapshots, disks, databases, static IPs, load balancers, or other billable resources. If the application depends heavily on AWS-native services, moving only the VM can increase cross-cloud complexity. In that case, the lower VM price may not justify the architectural split. ## Frequently asked questions ### How much does AWS Lightsail cost? Linux/Unix General Purpose virtual servers currently start at $3.50/month for IPv6-only or $5/month with a public IPv4 address. Larger public-IPv4 bundles include $24/month for 2 vCPU / 4 GB / 80 GB with 4 TB transfer and $44/month for 2 vCPU / 8 GB / 160 GB with 5 TB transfer. ### Is AWS Lightsail cheaper than EC2? There is no universal answer. Lightsail bundles compute, SSD storage, and transfer into a fixed monthly plan, while EC2 exposes more instance families and pricing dimensions. Lightsail is usually easier to estimate for a simple VPS; EC2 is more flexible for broader AWS architectures. ### Is AWS Lightsail free? AWS includes Lightsail in its Free Tier offers for eligible accounts and selected plans. Treat the free offer as temporary onboarding and use normal bundle pricing for long-term production budgeting. ### Does AWS Lightsail charge for bandwidth? Each Lightsail VM includes a transfer allowance. Both inbound and outbound traffic count toward that allowance, but only outbound transfer above the allowance is charged. Regional overage pricing applies; US East is currently $0.09/GB. ### How much do Lightsail snapshots cost? Manual and automatic instance/disk snapshots are currently $0.05/GB-month. ### What is the cheapest AWS Lightsail plan? The cheapest current Linux/Unix General Purpose virtual-server bundle is $3.50/month with IPv6 only. The cheapest bundle with a public IPv4 address is $5/month. ### Is Raff cheaper than AWS Lightsail? At four matching public-IPv4 General Purpose shapes, Raff is currently about 25% to 36% lower on the monthly VM price. The exact 2 vCPU / 4 GB / 80 GB comparison is $17.99/month on Raff versus $24/month on Lightsail. Lightsail can still be the better choice when AWS ecosystem access, global regions, or larger instances matter more than VM price. ### Does Lightsail have a pricing calculator? AWS provides pricing pages and the broader AWS Pricing Calculator. For Lightsail, estimate the VM bundle plus transfer overage, snapshots, block storage, load balancers, databases, object storage, CDN, and any wider AWS services the application uses. ## Sources - [Amazon Lightsail pricing](https://aws.amazon.com/lightsail/pricing/) - [AWS Free Tier for Lightsail](https://aws.amazon.com/free/compute/lightsail/) - [Raff pricing](/pricing) - [Raff General Purpose VM Plans](/learn/guides/raff-general-purpose-vm-plans-explained) - Pricing verified: 2026-08-28 ## Conclusion: AWS Lightsail pricing vs Raff AWS Lightsail remains one of AWS's simplest compute products because the VM price bundles memory, vCPU, SSD storage, and a transfer allowance. Linux plans start at $3.50/month for IPv6-only and $5/month with public IPv4, while larger General Purpose bundles scale far beyond Raff's current maximum. For directly matched public-IPv4 VM shapes, Raff is currently about 25% to 36% lower on monthly VM price and includes unmetered VM bandwidth. Lightsail's trade-off is access to a larger AWS operating model: broader regions, much larger servers, and a path into hundreds of AWS services. Choose **AWS Lightsail** when AWS integration, region choice, very small entry plans, or large instance sizes matter most. Choose **Raff** when the workload fits Raff's current VM range and predictable pricing with unmetered VM bandwidth is the stronger requirement. --- ### Amazon RDS Alternative 2026: Pricing, Performance & Features URL: https://rafftechnologies.com/learn/compare/amazon-rds-alternative Description: Considering Amazon RDS? Compare Raff Managed PostgreSQL with RDS pricing, HA, backups, regions, transfer costs and migration trade-offs for 2026. Raff Managed PostgreSQL and Amazon RDS solve different versions of the managed-database problem. Raff publishes fixed PostgreSQL resource tiers with explicit HA and replica modifiers, while Amazon RDS exposes a broader set of engines, regions, instance classes, storage options, availability topologies, and AWS integrations. For teams searching for **Amazon RDS alternatives**, the useful comparison is not the smallest card price. It is the complete monthly database architecture: compute, storage, HA, replicas, transfer, backups, recovery, monitoring, and the operational model around them. For the PostgreSQL-specific workload requirements behind those costs, see [PostgreSQL for SaaS Apps](/learn/guides/postgresql-for-saas-apps). Raff Managed PostgreSQL uses published monthly resource tiers, explicit +70% HA pricing, built-in pooling, and one public `us-east` region. Amazon RDS offers six relational engines, 39 AWS Regions, Multi-AZ deployment models, read replicas, and deep AWS networking and governance integrations. RDS fits architectures that depend on AWS-native services, multi-engine support, or global placement. Raff fits PostgreSQL workloads where a smaller pricing and operational surface is more important than AWS ecosystem breadth. :::cluster ## Amazon RDS vs Raff: which is right for you? The decision is mostly about scope. Amazon RDS is a broad AWS-managed relational database platform. [Raff Managed PostgreSQL](/products/managed-databases/postgresql) is a narrower managed PostgreSQL product with published resource tiers. | Decision factor | Raff Managed PostgreSQL | Amazon RDS | |---|---|---| | Primary database need | Managed PostgreSQL with published capacity | Broad managed relational database platform | | Paid entry | $7.99/month for 1 vCPU / 1 GB / 25 GB | Configuration-dependent pay-as-you-go pricing | | High availability | Optional HA at +70% of the selected PostgreSQL plan | Multi-AZ DB instance and Multi-AZ DB cluster models | | Database engines | PostgreSQL; Raff also sells MySQL, Valkey, ClickHouse, and Kafka as separate managed products | Db2, MariaDB, Microsoft SQL Server, MySQL, Oracle, PostgreSQL | | Public region model | `us-east` | 39 AWS geographic Regions | | Private networking | Raff private connectivity | Amazon VPC and security groups | | Billing model | Published tiers plus explicit modifiers | DB class, storage, topology, Region, transfer, and other usage | From Raff pricing and customer conversations, the most useful buying rule is to compare the monthly architecture rather than one instance price. HA, replicas, storage growth, recovery, transfer paths, and operating ownership can change the real cost more than the entry plan. For the broader ownership decision, read [Managed vs Self-Hosted Databases](/learn/guides/managed-vs-self-hosted-databases). ## Amazon RDS overview [Amazon Relational Database Service](https://aws.amazon.com/rds/) is AWS's managed relational database service. AWS currently documents six core RDS engines: IBM Db2, MariaDB, Microsoft SQL Server, MySQL, Oracle Database, and PostgreSQL. RDS manages infrastructure tasks such as automated backups, patching, failure detection, recovery, and supported availability configurations. Application teams still own schema design, query behavior, indexing, connection patterns, compatibility testing, recovery objectives, and restore validation. The service supports multiple DB instance families and deployment models. RDS can also integrate with Amazon VPC, security groups, IAM-related workflows, CloudWatch, EventBridge, AWS APIs, CLI tooling, and other AWS services. The pricing consequence is that RDS does not have one universal monthly PostgreSQL price. Total cost depends on engine, Region, DB class, storage, deployment topology, backup usage, replicas, data transfer, and optional AWS services. ## Raff overview [Raff Managed PostgreSQL](/products/managed-databases/postgresql) provides managed PostgreSQL with published vCPU, RAM, and storage allocations, built-in pooling, monitoring, private connectivity, managed backup workflows, storage expansion, and optional high availability. Raff offers a permanent PostgreSQL free tier with **1 vCPU, 1 GB RAM, and 2 GB storage**. Current paid reference tiers include: | Raff PostgreSQL tier | Monthly price | Resources | |---|---:|---| | Entry | $7.99 | 1 vCPU / 1 GB RAM / 25 GB | | Production | $45.99 | 2 vCPU / 4 GB RAM / 80 GB | | Scale | $146.99 | 8 vCPU / 16 GB RAM / 180 GB | Additional managed-database storage is **$0.15/GB-month**. PostgreSQL HA adds **70%** to the selected plan, and a PostgreSQL read replica is **$29.99/month**. The $45.99 tier therefore becomes **$78.18/month** with HA. Raff also operates separate managed MySQL, Valkey, ClickHouse, and Kafka products. That is different from RDS's one service spanning six relational engine families. Raff supports **3,000+ customers**, has run **15,000+ VMs**, and publishes a **99.9% uptime SLA**. ## Amazon RDS pricing vs Raff pricing Raff publishes PostgreSQL plan prices. Amazon RDS uses usage-based pricing that varies by Region, engine, DB class, storage, topology, and other selected resources. AWS's own RDS for PostgreSQL pricing page states that partial instance hours are billed in one-second increments with a 10-minute minimum charge after a billable status change. For new AWS customers, the current AWS Free Tier model offers up to **$100 in credits at sign-up** and up to **another $100 in credits**. The RDS Free plan supports eligible `db.t3.micro` and `db.t4g.micro` instances for MySQL, PostgreSQL, MariaDB, and SQL Server Express. AWS describes the Free plan as an exploration path available for up to six months, not a permanent production database tier. | Buying position | Raff Managed PostgreSQL | Amazon RDS | What changes the comparison | |---|---:|---|---| | Free development | $0 permanent: 1 vCPU / 1 GB / 2 GB | AWS credits and Free-plan eligibility | Permanent tier vs time/credit-based evaluation | | Entry paid | $7.99/month: 1 vCPU / 1 GB / 25 GB | DB class + storage + applicable usage | RDS total varies by configuration | | Small production | $45.99/month: 2 vCPU / 4 GB / 80 GB | Instance + storage + topology + usage | Not matched performance tiers | | HA position | $78.18/month on the $45.99 Raff tier | Multi-AZ bills the selected availability topology | Compare failover design, not only price | | Read scaling | $29.99/month PostgreSQL replica | Replica uses the selected RDS DB instance configuration | RDS offers broader topology and Region choices | **Comparison class:** these are buying positions, not matched benchmarks. Raff and RDS use different CPU, storage, network, and operational models. GSC shows this page receiving searches for exact RDS PostgreSQL pricing configurations such as `db.t4g.micro` and `db.t4g.medium` in `us-east-1`, including Multi-AZ. Those figures are deliberately not frozen into this article because the current dollar total depends on live AWS Region, instance, storage, topology, and usage settings. For an exact AWS number, use the official RDS pricing page or AWS Pricing Calculator at the time of purchase, then compare it with the complete Raff tier and any HA or replica modifier. ### Automated backups and recovery cost AWS documents automated-backup retention of **0 to 35 days** for RDS DB instances. Setting retention to 0 disables automated backups. Multi-AZ DB clusters use a **1 to 35 day** retention range. Backup storage beyond included allowances and retained backups can create additional charges depending on the configuration. Raff provides managed backup workflows for its managed databases. HA, replicas, and recovery are separate design decisions and should not be treated as interchangeable controls. ### Multi-AZ and replica cost RDS Multi-AZ models add standby or cluster resources in additional Availability Zones. The actual total depends on the selected RDS topology and resources rather than a universal multiplier. Raff exposes its PostgreSQL HA modifier directly as +70% of the selected plan. Raff's PostgreSQL read replica is $29.99/month. :::cta database Compare plans, then deploy. ::: ## Bandwidth and transfer policy Amazon RDS transfer charges depend on the traffic path. AWS currently states that data transfer between RDS and EC2 in the **same Availability Zone is free**, and replication traffic for RDS Multi-AZ deployments is also free of data-transfer charges. When EC2 and RDS communicate across Availability Zones in the same Region, AWS applies standard EC2 regional transfer charges of **$0.01/GB in and $0.01/GB out** on the EC2 side, with no additional RDS-side transfer charge for that specific path. Cross-Region replicas, snapshot copies, and cross-Region automated backups can add transfer charges. Raff private VPC traffic is unmetered. Public traffic rules should be checked against the current managed-database product and billing path rather than assuming the VM egress model applies to every database route. The practical question is application placement. Same-AZ AWS application/database paths have different transfer economics from cross-AZ or cross-Region designs, while Raff's simpler model is easiest to reason about when application and database workloads stay inside Raff private networking in `us-east`. ## Feature comparison: Amazon RDS vs Raff | Feature | Raff Managed PostgreSQL | Amazon RDS | |---|---|---| | Core database focus | Managed PostgreSQL | Broad managed relational database service | | Core engine breadth | PostgreSQL; other Raff engines are separate products | Db2, MariaDB, SQL Server, MySQL, Oracle, PostgreSQL | | Permanent free database tier | 1 vCPU / 1 GB / 2 GB | Current AWS Free plan uses credits and eligible micro classes | | Paid entry | $7.99/month | Configuration-dependent pay-as-you-go | | PostgreSQL versions | Verify current supported versions in the live product flow | Version catalog varies by Region and DB class | | Connection pooling | Built in | Application or proxy architecture selected separately | | Managed backups | Yes | Automated backups and snapshots | | Backup retention | Verify current Raff workflow for the selected service | 0-35 days DB instances; 1-35 days Multi-AZ DB clusters | | High availability | Optional +70% | Multi-AZ DB instance and Multi-AZ DB cluster models | | Read replicas | $29.99/month PostgreSQL replica | Standard selected DB-instance configuration; same- and cross-Region options vary by engine/version | | Private networking | Raff private connectivity | Amazon VPC | | Monitoring | Included database monitoring | CloudWatch and RDS monitoring tooling | | Public region model | 1 region: `us-east` | 39 AWS geographic Regions | RDS exposes substantially more choices around engines, regions, instance families, governance, and topology. Raff exposes a smaller PostgreSQL-specific buying surface with published capacity and explicit add-ons. ## Features and reliability: Raff vs Amazon RDS This comparison does not contain a controlled PostgreSQL benchmark between Raff and Amazon RDS. There are **0 matched head-to-head performance tests** here, so no performance winner is claimed. For a real performance decision, test the same PostgreSQL version, schema, dataset, query mix, connection model, and application-to-database network path on both services. ### Database-engine breadth Amazon RDS supports six core relational engines: Db2, MariaDB, Microsoft SQL Server, MySQL, Oracle, and PostgreSQL. Raff's managed catalog currently includes PostgreSQL, MySQL, Valkey, ClickHouse, and Kafka as separate products. Teams that require Oracle, SQL Server, Db2, or RDS-native MariaDB should account for that engine difference before comparing price. ### High availability Amazon RDS offers multiple availability models, including Multi-AZ DB instances and Multi-AZ DB clusters for supported engines and configurations. A Multi-AZ DB cluster uses a writer plus readable instances across Availability Zones. Raff PostgreSQL offers optional HA priced at +70% of the selected plan. That makes the monthly modifier explicit but provides fewer topology choices than AWS. ### Backups and recovery Amazon RDS supports automated backups, snapshots, and configurable retention. Cross-Region backup and snapshot workflows can support disaster-recovery designs while adding storage and transfer considerations. Raff provides managed backup workflows. On either platform, teams should define recovery objectives and test restores rather than treating the existence of backups as proof of recoverability. ### Networking and monitoring Amazon RDS integrates with VPC, security groups, IAM-related workflows, CloudWatch, EventBridge, APIs, and other AWS services. Raff provides private connectivity, pooling, access controls, and database monitoring inside a smaller cloud operating model. ### Geographic reach and operating signals AWS currently lists **39 geographic Regions and 124 Availability Zones**. Raff exposes one public region, `us-east`. Raff publishes a **99.9% uptime SLA**, supports **3,000+ customers**, and has run **15,000+ VMs**. Review-site ratings are intentionally omitted here because low review counts and changing ratings make them a weaker durable comparison signal than product scope, SLA, and current pricing. ## When you should choose Amazon RDS over Raff Amazon RDS fits better when: - you need Db2, MariaDB, SQL Server, MySQL, Oracle, or PostgreSQL inside one AWS service; - database placement across several AWS Regions is a requirement; - IAM, VPC, CloudWatch, EventBridge, AWS APIs, and other AWS-native controls are part of the operating model; - you need more Multi-AZ and replica topology choices; - cross-Region database architectures are required; - your organization already uses AWS Reserved DB Instance commitments or AWS procurement controls; - the database is tightly coupled to a broader AWS architecture. ## When you should choose Raff over Amazon RDS Raff fits better when: - PostgreSQL is the database requirement; - a published paid entry of **$7.99/month** is useful for planning; - HA pricing should be known before deployment as a **+70%** modifier; - built-in connection pooling reduces application-side setup; - private Raff application-to-database connectivity is the intended architecture; - the team prefers fewer billing and topology dimensions; - `us-east` satisfies the placement requirement. The trade-off is explicit: Raff simplifies the product surface by offering fewer engine, region, and topology choices than RDS. ## Migrating from Amazon RDS to Raff A direct RDS-to-Raff PostgreSQL migration starts by confirming that the source is PostgreSQL and that the current Raff product supports the source version and required extensions. Do not assume compatibility from an old version list. 1. **Inventory RDS.** Record PostgreSQL version, extensions, DB class, storage, parameter groups, users, databases, Multi-AZ state, replicas, backup retention, networking, IAM dependencies, RDS Proxy usage, and monitoring. 2. **Confirm the Raff target.** Verify current supported PostgreSQL versions and extensions in the live product flow, select the target tier, and configure networking, pooling, backups, storage, and optional HA. 3. **Move the data.** Use `pg_dump`/`pg_restore` for suitable migrations or PostgreSQL logical replication when low downtime is required and both ends support the design. 4. **Replace AWS-specific dependencies.** Update IAM database-auth assumptions, RDS Proxy dependencies, Secrets Manager automation, CloudWatch alarms, VPC-specific endpoints, and related AWS workflows where used. 5. **Validate the target.** Compare row counts, sequences, extensions, indexes, representative query plans, pooled/direct connections, application writes, backup behavior, and latency from the real application path. 6. **Cut over with rollback retained.** Coordinate the final write window or replication lag, switch connection strings and access rules, verify production traffic, and retain the RDS source for a defined rollback window. For production moves, verify current compatibility and migration scope before scheduling cutover. Do not base a migration on historical product-version claims. ## About Amazon RDS [Amazon Relational Database Service](https://aws.amazon.com/rds/) is operated by Amazon Web Services. It supports Db2, MariaDB, Microsoft SQL Server, MySQL, Oracle Database, and PostgreSQL, with managed infrastructure functions such as automated backups, patching, monitoring integrations, availability options, replicas for supported engines, VPC networking, APIs, and Region-specific deployment choices. The product is designed to integrate deeply with the wider AWS cloud. That ecosystem breadth is one of the main reasons to select RDS, but it also creates more architecture and billing dimensions than a PostgreSQL-specific managed service. ## Conclusion: Amazon RDS or Raff? The decision comes down to four practical axes: - **Scope:** RDS spans six relational engines and deep AWS integration; Raff keeps this comparison centered on managed PostgreSQL. - **Pricing model:** Raff starts at $7.99/month with published resources; RDS pricing depends on class, storage, topology, Region, and usage. - **Geography and availability:** AWS spans 39 Regions and 124 Availability Zones; Raff operates one public `us-east` region with an explicit +70% PostgreSQL HA option. - **Operational surface:** AWS provides more infrastructure, governance, topology, and procurement choices; Raff provides fewer decisions and explicit plan modifiers. Use Amazon RDS when AWS-native integration, engine breadth, global placement, or advanced topology is a requirement. Use Raff when the workload is PostgreSQL, `us-east` is sufficient, and published capacity with a smaller pricing and operational surface better matches the team. Raff supports **3,000+ customers**, has run **15,000+ VMs**, and publishes a **99.9% uptime SLA**. ## Sources - [Amazon RDS](https://aws.amazon.com/rds/) - [Amazon RDS pricing](https://aws.amazon.com/rds/pricing/) - [Amazon RDS for PostgreSQL pricing](https://aws.amazon.com/rds/postgresql/pricing/) - [Amazon RDS Free Tier](https://aws.amazon.com/rds/free/) - [RDS backup retention](https://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/USER_WorkingWithAutomatedBackups.BackupRetention.html) - [AWS Regions and Availability Zones](https://aws.amazon.com/about-aws/global-infrastructure/regions_az/) - AWS facts re-verified: 2026-09-17 --- ### Cloudflare R2 Pricing 2026: Free Tier, Costs & Raff Comparison URL: https://rafftechnologies.com/learn/compare/raff-object-storage-vs-cloudflare-r2 Description: Cloudflare R2 pricing explained for 2026: Standard and Infrequent Access rates, 10 GB free tier, request costs, free egress, calculator examples, and Raff comparison. Cloudflare R2 pricing in 2026 is built around four meters: stored data, Class A operations, Class B operations, and—only for Infrequent Access—data retrieval. **Standard storage costs $0.015/GB-month, Infrequent Access costs $0.01/GB-month, and direct internet egress from R2 is free.** The Standard free tier includes 10 GB-month of storage, 1 million Class A operations, and 10 million Class B operations every month. For most buyers, the important detail is that R2 is not simply “$0.015 per GB.” Request volume can become the larger part of the bill. Raff Object Storage uses a different model: **$7/month includes 100 GB storage, 1 TB egress, and no separate API request charges.** Raff is materially more expensive for storage-heavy, low-request workloads, while it can be cheaper for request-heavy workloads. ## Cloudflare R2 pricing at a glance | R2 meter | Standard | Infrequent Access | |---|---:|---:| | Storage | $0.015/GB-month | $0.01/GB-month | | Class A operations | $4.50/million | $9.00/million | | Class B operations | $0.36/million | $0.90/million | | Retrieval processing | None | $0.01/GB | | Internet egress | Free | Free | | Minimum storage duration | None | 30 days | | Free tier | Yes | No | Cloudflare's free tier applies only to **Standard storage**. It does not apply to Infrequent Access. Cloudflare also rounds each billable meter up to the next billing unit. For example, 1.1 GB-month is billed as 2 GB-months, and 1,000,001 operations are billed as 2 million operations. That rounding matters most for small workloads close to a billing boundary. ## Cloudflare R2 free tier in 2026 The current R2 Standard free tier includes, every month: - **10 GB-month of Standard storage** - **1 million Class A operations** - **10 million Class B operations** - **Free direct internet egress** The free tier resets monthly and applies only to Standard storage. Infrequent Access does not receive the 10 GB storage allowance or the operation allowances. This makes R2 attractive for small sites, prototypes, static assets, and applications whose reads stay below the included Class B allowance. The common mistake is assuming that “free egress” means serving any amount of traffic is completely free. R2 itself does not charge egress bandwidth, but reads still count as Class B operations. Other Cloudflare products connected to R2 can also have their own pricing. ## How much does Cloudflare R2 cost? For Standard storage, a useful simplified formula is: ```text Monthly R2 cost = billable storage + billable Class A operations + billable Class B operations ``` Where, after the Standard free tier: ```text Storage: $0.015 per GB-month Class A: $4.50 per million operations Class B: $0.36 per million operations Egress: $0 ``` Cloudflare rounds usage up to the next billing unit, so use the official R2 calculator for exact production estimates. ### 100 GB stored with light request volume If you store 100 GB for the month in Standard storage and stay inside the free operation allowances: ```text 100 GB - 10 GB free = 90 GB billable 90 × $0.015 = $1.35/month ``` **Estimated R2 cost: $1.35/month.** Raff Object Storage is **$7/month** for the same 100 GB capacity, but that $7 also includes 1 TB egress and no separate request meter. For a storage-led workload with light requests, R2 wins clearly on price. ### 1,000 GB stored with light request volume For 1,000 GB of R2 Standard storage: ```text 1,000 GB - 10 GB free = 990 GB billable 990 × $0.015 = $14.85/month ``` **Estimated R2 cost: $14.85/month.** Raff would cost **$70/month** for 1,000 GB of storage before any egress overage. Again, R2 is much cheaper when stored capacity is the main cost driver. ### 100 GB with 300 million reads per month This is where the model changes. At 100 GB, storage is still about $1.35. If the bucket receives 300 million Class B reads: ```text 300M reads - 10M free = 290M billable reads 290 × $0.36 = $104.40 Storage = $1.35 Total ≈ $105.75/month ``` Raff remains **$7/month** at 100 GB because API requests are not metered separately. This is the key crossover: **R2 is cheaper for storage-heavy workloads; Raff can be cheaper for request-heavy workloads.** ### 100 GB with 50 million Class A operations Class A operations are much more expensive than Class B operations. ```text 50M Class A - 1M free = 49M billable 49 × $4.50 = $220.50 Storage = $1.35 Total ≈ $221.85/month ``` Raff remains $7 at 100 GB because there is no separate Class A/Class B billing model. Applications that frequently list objects, write many small files, perform multipart workflows, or generate large volumes of metadata operations should model these request costs before choosing a provider. ## Cloudflare R2 pricing calculator: what to include When estimating R2, use more than stored GB. A useful calculator input set is: 1. average GB-month stored; 2. Standard vs Infrequent Access storage; 3. monthly Class A operations; 4. monthly Class B operations; 5. GB retrieved from Infrequent Access; 6. whether objects may be deleted before the 30-day IA minimum; 7. costs from any other Cloudflare service connected to the bucket. Cloudflare provides an official R2 pricing calculator. It is particularly useful because R2 rounds billable usage to whole units and because operation count can dominate low-storage workloads. For application planning, also separate **object count** from **stored capacity**. One 100 GB file and one million 100 KB objects can have similar storage footprints but very different request patterns. ## Cloudflare R2 vs Raff Object Storage: quick cost comparison | Scenario | Raff Object Storage | Cloudflare R2 Standard | Better fit | |---|---:|---:|---| | 100 GB, light operations | $7.00/mo | About $1.35/mo | R2 | | 500 GB, light operations | $35.00/mo | About $7.35/mo | R2 | | 1,000 GB, light operations | $70.00/mo | About $14.85/mo | R2 | | 100 GB, 300M Class B reads | $7.00/mo | About $105.75/mo | Raff | | 100 GB, 50M Class A operations | $7.00/mo | About $221.85/mo | Raff | These examples use R2 Standard, apply the monthly Standard free tier, and assume no other billable operation classes unless shown. The table is not meant to claim that Raff is cheaper overall. It shows that the two products optimize for different billing patterns. ## Raff Object Storage pricing Raff Object Storage uses a simpler bundle: - **$7/month base price** - **100 GB storage included** - **1 TB egress included each month** - **API requests are not separately metered** - **$0.07/GB-month for storage above 100 GB** - **$0.01/GB for egress above 1 TB** - **Free inbound traffic** There are no Class A or Class B request meters. That makes Raff easier to forecast for backup tooling, application uploads, object browsers, sync jobs, or workloads that generate many small API calls. The trade-off is important: Raff's raw per-GB storage price is higher than R2. If your workload is mostly stored capacity with modest request volume or very high public egress, R2 is usually the cheaper choice. :::cta Create a Bucket Now Create S3-compatible storage with 100 GB and 1 TB egress included for $7/month. ::: ## Is Cloudflare R2 egress really free? For R2 itself, direct egress to the internet is free for both Standard and Infrequent Access storage. Cloudflare specifically documents free R2 egress through the Workers API, S3 API, and `r2.dev` domains. The important caveat is that **other metered Cloudflare services connected to R2 can still generate their own charges**. R2 therefore has a major advantage for: - public asset delivery; - software downloads; - media files; - large datasets downloaded frequently; - migration architectures where outbound bandwidth would otherwise dominate the bill. Raff includes 1 TB egress in the $7 bundle and then charges $0.01/GB. | Monthly internet egress | Raff incremental egress charge | R2 egress charge | |---:|---:|---:| | 1 TB | $0 | $0 | | 5 TB | $40.96 | $0 | | 10 TB | $92.16 | $0 | | 50 TB | $501.76 | $0 | For bandwidth-heavy public delivery, R2 is the stronger economic choice. ## Standard vs Infrequent Access pricing R2 Infrequent Access lowers the storage rate from $0.015 to $0.01 per GB-month, but it is not simply a cheaper version of Standard. Infrequent Access adds: - Class A operations at $9.00/million; - Class B operations at $0.90/million; - $0.01/GB retrieval processing; - a 30-day minimum storage duration; - no Standard free-tier allowances. Use Infrequent Access for objects that are genuinely cold and remain stored long enough for the lower capacity price to offset retrieval and request costs. Do not use it simply because $0.01/GB looks lower on the pricing table. ## What are Class A and Class B operations? Cloudflare groups R2 requests into operation classes. **Class A operations** generally mutate state or perform management work. Examples include `PutObject`, `ListObjects`, multipart upload operations, copies, and lifecycle configuration changes. **Class B operations** generally read existing data or metadata. Examples include `GetObject`, `HeadObject`, and several bucket metadata reads. Deletes and some abort operations are free. For asset-heavy sites, Class B reads are usually the meter to watch. For upload-heavy systems, backup tools, data ingest, or object-management workflows, Class A volume can become significant. ## Feature comparison: Cloudflare R2 vs Raff Pricing is only part of the decision. | Feature | Raff Object Storage | Cloudflare R2 | |---|---|---| | S3-compatible API | Yes | Yes | | Standard storage class | Yes | Yes | | Infrequent Access class | No | Yes | | Direct internet egress | 1 TB included, then $0.01/GB | Free | | Request charges | None | Class A / Class B after free tier | | Free storage tier | No separate free tier | 10 GB-month Standard | | Lifecycle rules | Not currently exposed | Yes | | Bucket locks | Not currently exposed | Yes, Cloudflare bucket locks | | Native S3 bucket versioning | No | Not implemented in the R2 S3 compatibility matrix | | Presigned URLs | Yes | Yes | | Multipart uploads | Yes | Yes | | Workers integration | Separate Raff compute products | Native R2 Workers binding | | Public placement options | `us-east` | Automatic placement, location hints, jurisdiction controls | R2 also publishes an eleven-nines annual durability design target and documents redundancy across multiple storage facilities within a geographic region. Raff publishes a 99.9% platform SLA but does not publish an equivalent object-durability target. If a procurement or recovery policy requires a published durability target, R2 has the stronger documented position. ## Is R2 really S3-compatible? R2 implements a broad S3-compatible API and works with many AWS S3 SDKs and tools by changing the endpoint and credentials. It is not full Amazon S3 parity. Cloudflare publishes a compatibility matrix showing implemented and unsupported operations. For example, native S3 bucket versioning operations such as `PutBucketVersioning` remain unsupported, and S3 Object Lock APIs are not equivalent to Cloudflare's separate Bucket Locks feature. Raff is also S3-compatible for common object-storage workflows, including AWS CLI, SDKs, rclone, s3cmd, multipart uploads, and presigned URLs. Before migrating stateful storage, test the exact API operations your application depends on rather than treating “S3-compatible” as “identical to S3.” ## When Cloudflare R2 is the better choice Choose R2 when: - raw storage price is the primary cost driver; - public internet egress is high; - you need a free tier for a small workload; - you use Cloudflare Workers or Cloudflare-native delivery; - lifecycle rules or Cloudflare Bucket Locks matter; - you need broader placement and jurisdiction controls; - you want a published eleven-nines durability design target. For large, low-request buckets, R2's pricing advantage is substantial. ## When Raff is the better choice Choose Raff when: - request volume is high or difficult to predict; - you want one fixed base bundle instead of separate operation classes; - 100 GB storage and 1 TB egress fit the workload; - your application infrastructure is already on Raff; - you want storage, compute, networking, databases, and support under one account; - you do not need R2-specific lifecycle, placement, or Cloudflare Workers integrations. The strongest Raff case is not “cheaper storage.” It is **simpler request economics and fewer billing dimensions**. ## Migrating between R2 and Raff Both products use S3-compatible workflows, so the data path is familiar, but feature parity still needs review. For a workload-level overview before planning the migration, see [S3-Compatible Object Storage: Use Cases for Developers](/learn/guides/s3-compatible-object-storage-use-cases-for-developers). A safe migration plan is: 1. inventory buckets, object counts, total bytes, storage classes, lifecycle rules, bucket locks, CORS, access keys, and application dependencies; 2. create the target bucket and credentials; 3. verify required S3 operations on the target provider; 4. copy objects with rclone, an S3 SDK, or another S3-compatible migration tool; 5. preserve content types, cache headers, object keys, and metadata; 6. validate object counts and checksums; 7. test presigned URLs, uploads, downloads, CORS, and permissions; 8. cut over the application endpoint with a rollback window; 9. remove the old bucket only after new writes and reads are verified. If the application continues writing during migration, plan a final synchronization or controlled write freeze before cutover. R2 Infrequent Access objects can also incur retrieval and minimum-duration charges during migration, so include those costs in the plan. ## Frequently asked questions ### How much is Cloudflare R2? R2 Standard storage is $0.015/GB-month after the 10 GB Standard free tier. Standard Class A operations are $4.50/million after 1 million free monthly operations, and Class B operations are $0.36/million after 10 million free monthly operations. Direct R2 internet egress is free. ### Is Cloudflare R2 free? R2 has a monthly Standard free tier, not an unlimited free plan. It includes 10 GB-month storage, 1 million Class A operations, 10 million Class B operations, and free direct egress. The free tier does not apply to Infrequent Access storage. ### Why is Cloudflare R2 so cheap? R2 prices storage aggressively and does not charge direct internet egress. It still charges for Class A and Class B operations, so request-heavy workloads can cost much more than the storage price alone suggests. ### Is R2 egress really free? Direct egress from R2 is free. Cloudflare notes that other metered services connected to R2 may still have their own charges. ### What is the Cloudflare R2 free storage limit? The Standard free tier includes 10 GB-month of storage per month. Usage above that is billed at $0.015/GB-month. Infrequent Access does not receive the free storage allowance. ### Is R2 cheaper than Raff Object Storage? For storage-heavy, low-request workloads, usually yes. At 100 GB with light operations, R2 is about $1.35/month versus Raff at $7. For request-heavy workloads, Raff can be cheaper because it does not charge per API request. ### Does Cloudflare R2 charge for reads? Yes, after the free allowance. Standard Class B operations, which include common reads such as `GetObject`, cost $0.36 per million requests after 10 million free operations each month. ### Does Cloudflare R2 have a pricing calculator? Yes. Cloudflare provides an official R2 pricing calculator. Use it for exact estimates because storage, requests, storage class, retrieval, and billable-unit rounding all affect the total. ## Sources - [Cloudflare R2 pricing](https://developers.cloudflare.com/r2/pricing/) - [Cloudflare R2 S3 API compatibility](https://developers.cloudflare.com/r2/api/s3/api/) - [Cloudflare R2 durability](https://developers.cloudflare.com/r2/reference/durability/) - [Raff Object Storage](/products/object-storage) - Date verified: 2026-08-28 ## Conclusion: Cloudflare R2 pricing vs Raff Cloudflare R2 is one of the lowest-cost mainstream S3-compatible options when stored capacity and public egress dominate the workload. Standard storage is $0.015/GB-month, direct egress is free, and the monthly free tier covers 10 GB-month plus substantial request allowances. The trade-off is request-based billing. Class A and Class B operations can become the largest part of the bill for asset-heavy, backup, synchronization, or metadata-intensive workloads. Raff takes the opposite approach: $7/month includes 100 GB storage, 1 TB egress, and no separate API request charges. Choose **Cloudflare R2** when low per-GB storage cost, free egress, Cloudflare integrations, or lifecycle controls matter most. Choose **Raff** when request volume is hard to forecast and a simpler bundled bill is more valuable than the lowest raw storage price. --- ### DigitalOcean App Platform Alternative 2026: Pricing, Performance & Features URL: https://rafftechnologies.com/learn/compare/digitalocean-app-platform-alternative Description: DigitalOcean App Platform starts at $5/mo for 1 shared vCPU / 512 MiB; Raff Apps starts at $3/mo. Compare pricing, transfer, regions, scaling, and storage. Raff Apps wins on lower comparable service prices, $0 public application egress, persistent application volumes, full Docker Compose imports, and first-party managed data services. DigitalOcean App Platform wins on 12 deployment regions, a free static-site tier, GitLab and Bitbucket sources, dedicated CPU plans, mature autoscaling, and a 99.95% per-component SLA. Choose DigitalOcean App Platform when regional placement and autoscaling are requirements; choose Raff when `us-east`, durable app volumes, Compose portability, and a tighter monthly cost boundary fit the workload. Raff Pro is $27.99/month for 2 vCPU and 4 GB, while DigitalOcean's 2 shared vCPU / 4 GiB plan is $50/month with 250 GiB of outbound transfer included. DigitalOcean App Platform and Raff Apps are both managed deployment platforms, but their strongest buying cases are different. DigitalOcean spreads dynamic apps across 12 regions and can autoscale request-driven services to 100 containers, while Raff exposes one public `us-east` region and emphasizes predictable service tiers, $0 public app egress, and persistent volumes. DigitalOcean starts dynamic compute at $5/month; Raff Apps starts at $3/month. For small SaaS teams, the useful comparison is therefore not only deployment convenience but the full cost and operating model once transfer, durable state, source integrations, and scaling requirements are included. ## DigitalOcean App Platform vs Raff: which is right for you? DigitalOcean App Platform is the stronger fit when location choice, autoscaling, dedicated CPU, or multiple Git providers are requirements. Raff is the stronger fit when the workload can stay in `us-east` and the team values lower listed service prices, persistent application volumes, Docker Compose portability, and $0 public egress. | Decision factor | Choose Raff Apps | Choose DigitalOcean App Platform | |---|---|---| | Dynamic entry price | You want a managed runtime from $3/month | You want 1 shared vCPU / 512 MiB from $5/month | | Geography | One public `us-east` region fits the workload | You need one of 12 App Platform regions | | Persistent files | Application-attached persistent volumes matter | Durable state can live in Spaces or Managed Databases | | Bandwidth | Public application egress should cost $0 | Included pooled transfer plus $0.02/GiB overage fits | | Source providers | GitHub is sufficient | GitHub, GitLab, or Bitbucket is required | | Scaling | Published service tiers and scale-to-zero fit | Request-based or CPU-based autoscaling is required | | Deployment model | Full Docker Compose import matters | App Spec, API, `doctl`, or Terraform is preferred | From the Raff pricing side, the practical lesson is to compare the complete application bill rather than the smallest plan card. DigitalOcean's $5 entry tier includes more listed shared CPU than Raff Micro, but the decision changes materially at matched 1 vCPU / 2 GB and 2 vCPU / 4 GB sizes, and changes again when outbound transfer or persistent state enters the architecture. ## DigitalOcean App Platform overview DigitalOcean App Platform is a fully managed PaaS that builds and deploys applications from Git repositories or container images while DigitalOcean manages the underlying infrastructure. It supports web services, static sites, workers, cron jobs, deployment jobs, functions, and database integrations. Current source options include GitHub, GitLab, and Bitbucket repositories plus images from DigitalOcean Container Registry, Docker Hub, and GitHub Container Registry. Apps can be managed through the control panel, API, `doctl`, Terraform, and a YAML App Spec. DigitalOcean offers shared and dedicated CPU plans. Shared dynamic plans start at **$5/month for 1 shared vCPU / 512 MiB**, while dedicated plans start at **$29/month for 1 dedicated vCPU / 512 MiB**. Request-based autoscaling works with shared and dedicated CPU plans and supports up to **100 containers**; CPU-based autoscaling requires dedicated CPU and, like fixed scaling, can reach **250 containers**. DigitalOcean also provides a free static-site tier for up to **3 apps** containing only static-site components, with **1 GiB outbound transfer per app**. Its strongest advantages in this comparison are 12 deployment regions, a 99.95% App Platform component SLA, multiple source providers, dedicated CPU options, autoscaling, and integration with the wider DigitalOcean cloud. Its clearest constraint is durable local state. App Platform does not support volumes, and the local filesystem is limited to **4 GiB** and is ephemeral across deployments and other container replacements. Persistent data therefore belongs in services such as Spaces or DigitalOcean Managed Databases. ## Raff overview [Raff Apps](/products/app-platform) is Raff's managed application platform for deploying source code and containers without administering the operating system beneath them. It supports GitHub push-to-deploy, buildpacks, Dockerfiles, existing container images, and full Docker Compose imports. Raff Apps supports public web services, private services, long-running workers, timezone-aware cron jobs, one-off jobs, pull-request previews, persistent application volumes, immutable revisions, one-click rollback, and scale-to-zero behavior. Applications can connect to Raff Managed Databases for PostgreSQL, MySQL, Valkey, ClickHouse, and Kafka, plus object storage, VMs, private networking, Kubernetes, and Functions. Current service tiers are: | Tier | vCPU | RAM | Ephemeral disk | Monthly ceiling | |---|---:|---:|---:|---:| | Micro | 0.25 | 512 MB | 2 GB | $3.00 | | Starter | 0.5 | 1 GB | 5 GB | $6.99 | | Standard | 1 | 2 GB | 10 GB | $16.99 | | Pro | 2 | 4 GB | 20 GB | $27.99 | | Pro Max | 4 | 8 GB | 40 GB | $61.99 | | Scale | 8 | 16 GB | 80 GB | $119.99 | Runtime is billed per second against each published monthly ceiling. Public application egress and Apps team seats cost $0, and the spend cap is enabled by default. Raff currently exposes one public region, `us-east`, which is a real limitation for teams that require placement closer to users elsewhere. Raff publishes a **99.9% platform SLA**. On August 16, 2026, Raff was rated **4.5/5**, with G2 at 4.6/5. ## DigitalOcean App Platform pricing vs Raff pricing DigitalOcean bills each App Platform component according to its container size and replica count. Apps are billed by the second with a one-minute minimum. Raff also prorates Apps runtime by the second but caps each service at its published monthly price. DigitalOcean also offers a **$10/month fixed-size 1 shared vCPU / 1 GiB plan** with **100 GiB included outbound transfer** and no manual replica scaling. The **$12/month 1 GiB plan** in the scalable row below allows manual scaling and includes 150 GiB. These are different plan options, not two prices for identical scaling behavior. | Buying position | Raff Apps | DigitalOcean App Platform | Decision signal | |---|---:|---:|---| | Entry dynamic app | Micro — 0.25 vCPU / 512 MB / $3 | 1 shared vCPU / 512 MiB / $5 | DigitalOcean includes more listed shared CPU; Raff is $2 lower | | 1 GiB fixed-size | Starter — 0.5 vCPU / 1 GB / $6.99 | 1 shared vCPU / 1 GiB / $10 fixed | Fixed DO plan has more listed shared CPU but no manual replica scaling | | 1 GB dynamic | Starter — 0.5 vCPU / 1 GB / $6.99 | 1 shared vCPU / 1 GiB / $12 scalable | DigitalOcean adds manual horizontal scaling | | 1 vCPU / 2 GB | Standard — $16.99 | 1 shared vCPU / 2 GiB — $25 | Closely matched published CPU/RAM totals | | 2 vCPU / 4 GB | Pro — $27.99 | 2 shared vCPU / 4 GiB — $50 | Raff is $22.01 lower before DO overage | | Static sites | No equivalent published free Apps tier | Up to 3 static-only apps free | DigitalOcean wins for qualifying static-only projects | **Comparison class:** these rows compare published CPU, memory, and price positions, not measured application performance. DigitalOcean distinguishes shared and dedicated CPU scheduling; Raff Apps does not publish the same shared-versus-dedicated labels, so resource counts alone should not be treated as benchmark equivalence. ### Bandwidth cost math DigitalOcean's 2 shared vCPU / 4 GiB plan includes **250 GiB** outbound transfer. Additional outbound transfer costs **$0.02/GiB**, and App Platform allowance and usage are pooled across apps at the team level. Raff Apps public egress is $0. | Monthly outbound traffic | Raff Pro | DigitalOcean 2 shared vCPU / 4 GiB | |---:|---:|---:| | 250 GiB | $27.99 | $50.00 | | 500 GiB | $27.99 | $55.00 | | 1 TiB | $27.99 | $65.48 | | 2 TiB | $27.99 | $85.96 | | 5 TiB | $27.99 | $147.40 | The DigitalOcean examples assume no unused transfer allowance from other App Platform components in the same team pool. Pooling can reduce overage for teams whose other apps use less than their accumulated allowance. ### Automated backups DigitalOcean App Platform rollback and data backup are separate systems. App Platform can roll an app's **code, configuration, and App Spec** back to one of the **10 most recent successful deployments**, but DigitalOcean explicitly states that this rollback does not restore database data. DigitalOcean Managed Databases include **daily backups with point-in-time recovery**; PostgreSQL and MySQL documentation currently describes PITR within the previous **7 days**. App Platform's 4 GiB local filesystem is ephemeral and should not be treated as a backup target. Raff likewise separates application revision rollback from durable-data recovery. Persistent volumes, managed databases, and object storage need recovery policies appropriate to the state they hold; one-click application rollback does not substitute for a database or file backup. ### Hidden platform costs DigitalOcean dedicated egress IPs are billed per second up to **$25/month**. Development databases cost **$7/month per 512 MB**, while production managed databases are separate resources. DigitalOcean can still be the better buy when its 12-region footprint, autoscaling, dedicated CPU, or source-provider integrations eliminate other operational work. :::cta Deploy an App Now Deploy web services, workers, cron jobs, and Docker Compose stacks with managed runtime infrastructure. ::: ## Bandwidth and transfer policy Every current DigitalOcean App Platform compute plan includes an outbound-transfer allowance, from **50 GiB** on the $5 shared plan to **900 GiB** on the largest listed dedicated plan. Additional outbound transfer is $0.02/GiB and inbound transfer is free. Transfer allowance and usage are pooled across App Platform apps at the team level and do not roll over. DigitalOcean currently notes that users can view ingress bandwidth for individual apps but cannot directly view accrued App Platform transfer allowance or cumulative App Platform usage. That makes the final monthly charge more dependent on team-wide traffic patterns than a single component's plan card suggests. Raff Apps prices public application egress at $0. For bandwidth-heavy APIs, downloads, or traffic with large seasonal swings, that removes a variable from the application bill. DigitalOcean remains stronger when global regional placement is more valuable than the transfer difference or when pooled allowances cover the team's normal traffic. ## Feature comparison: DigitalOcean App Platform vs Raff | Feature | Raff Apps | DigitalOcean App Platform | |---|---|---| | Dynamic entry price | $3/month | $5/month | | Source providers | GitHub | GitHub, GitLab, Bitbucket | | Dockerfile / existing image | Yes | Yes | | Docker Compose | Full stack import | App components are modeled through App Platform configuration/App Spec | | Public regions | 1: `us-east` | 12 | | Free static tier | No equivalent published Apps tier | Up to 3 static-only apps | | Persistent app volumes | Yes | No | | App local filesystem | 2–80 GB ephemeral disk by Raff tier | 4 GiB ephemeral limit | | Public application egress | $0 | Included allowance, then $0.02/GiB | | Request-based autoscaling | Not published as a Raff Apps control | Shared and dedicated services, up to 100 containers | | CPU autoscaling | Not published as a Raff Apps control | Dedicated plans, up to 250 containers | | Dedicated CPU app plans | Not separately labeled | Yes, from $29/month | | Deployment rollback | Immutable revisions, one-click rollback | 10 most recent successful deployments | | Managed data options | PostgreSQL, MySQL, Valkey, ClickHouse, Kafka | PostgreSQL, MySQL, Valkey, MongoDB, Kafka, OpenSearch | | SLA | 99.9% platform SLA | 99.95% per App Platform component instance | DigitalOcean wins clearly on region count, Git-provider breadth, dedicated CPU choices, free static hosting, autoscaling controls, and the higher numerical App Platform SLA. Raff wins on lower listed prices at the matched 1 vCPU / 2 GB and 2 vCPU / 4 GB positions, persistent application volumes, full Compose imports, and $0 public egress. ## Features and reliability: Raff vs DigitalOcean App Platform This comparison includes **0 controlled Raff-versus-DigitalOcean App Platform application benchmarks**, so it does not declare either platform faster. DigitalOcean publishes both shared and dedicated CPU app plans, while Raff Apps does not expose the same CPU-class labels; a responsible benchmark would need matched CPU scheduling, region, memory, application image, database placement, caching, concurrency, and repeated test windows. ### Reliability commitment DigitalOcean commits to **99.95% monthly uptime for each App Platform component instance**. Raff publishes a **99.9% platform SLA**. On the numerical commitment alone, DigitalOcean has the stronger SLA. DigitalOcean also documents high availability for apps running **two or more containers**. That is an important strength for teams prepared to pay for multiple replicas. A one-container deployment still leaves the application at one runtime instance, even though the platform's component SLA applies. ### Persistent state DigitalOcean App Platform does not support volumes. Its local filesystem is **4 GiB and ephemeral**, so production files must be externalized to Spaces, Managed Databases, or another durable service. That architecture is often desirable for horizontally scaled apps, but it can require application changes for software that expects local persistent files. Raff Apps supports persistent application volumes. This makes lift-and-shift deployment easier for some stateful applications, though horizontally scaled services still need a deliberate shared-data design rather than assuming one attached filesystem solves multi-instance state. ### Autoscaling and capacity DigitalOcean has the more mature documented autoscaling surface. Request-based autoscaling can use requests per second or P95 request duration on shared or dedicated services, with a maximum of **100 containers**. CPU-based autoscaling requires dedicated CPU and can scale to **250 containers**. Request-based autoscaling and Scale to Zero cannot be enabled on the same service. Raff's public Apps model is simpler: teams choose a service tier, can use scale-to-zero behavior, and work within the platform's managed service abstraction. Teams that specifically need request-target or CPU-target autoscaling should treat DigitalOcean as the stronger option. ### Release and data recovery DigitalOcean can roll back to one of the **10 most recent successful deployments**, restoring code, configuration, and App Spec while leaving database data untouched. Raff uses immutable revisions and one-click application rollback. Both models require separate database and file recovery planning when a release includes state changes. ### Platform breadth DigitalOcean's wider cloud catalog is a genuine operational advantage for teams already using Droplets, DOKS, Spaces, Container Registry, Functions, or its Managed Databases. Raff offers a smaller integrated surface across Apps, VMs, managed databases, object storage, Kubernetes, Functions, and private networking. ## When you should choose DigitalOcean App Platform over Raff Choose DigitalOcean App Platform when: - **Regional placement is mandatory.** DigitalOcean App Platform exposes **12 regions** versus Raff Apps' single public `us-east` region. - **Autoscaling is a core requirement.** Request-based rules can scale to **100 containers**, while fixed and CPU-based scaling can reach **250**. - **GitLab or Bitbucket is required.** DigitalOcean supports both directly in addition to GitHub. - **Dedicated CPU app containers matter.** Current dedicated plans start at **$29/month** for 1 dedicated vCPU / 512 MiB. - **Static-only projects should be free.** DigitalOcean allows up to **3 qualifying static-only apps** at $0. - **A higher numerical SLA is required.** DigitalOcean commits to **99.95%** per App Platform component instance. - **The team already uses DigitalOcean.** App Platform integrates with its databases, Spaces, registry, Functions, DOKS, API, `doctl`, and Terraform workflows. ## When you should choose Raff over DigitalOcean App Platform Choose Raff Apps when: - **Comparable service prices matter.** Raff Standard is **$16.99** at 1 vCPU / 2 GB versus DigitalOcean's **$25** shared plan; Raff Pro is **$27.99** at 2 vCPU / 4 GB versus **$50**. - **Public egress is material.** Raff Apps charges **$0** for public application egress instead of $0.02/GiB after DigitalOcean's pooled allowance. - **Persistent app volumes are required.** DigitalOcean App Platform provides **0 persistent volumes** and a 4 GiB ephemeral filesystem. - **Docker Compose is the deployment artifact.** Raff can import a **full Compose stack** instead of translating services into platform-specific components. - **A default cost guardrail matters.** Raff Apps uses published monthly ceilings and enables the spend cap by default. - **Managed data should stay in the same compact workflow.** Raff provides **5 managed data engines**: PostgreSQL, MySQL, Valkey, ClickHouse, and Kafka. - **The workload fits `us-east`.** DigitalOcean's 12-region advantage has little value if one eastern-US deployment location already meets latency and architecture requirements. [Raff Apps](/products/app-platform) is a live managed application platform. For adjacent app-platform choices, compare [Render and Raff](/learn/compare/render-alternative), [Coolify and Raff](/learn/compare/coolify-alternative), and [Netlify and Raff](/learn/compare/netlify-alternative). ## Migrating from DigitalOcean App Platform to Raff 1. **Inventory the App Platform app.** Export the App Spec and record services, static sites, workers, jobs, functions, databases, repositories, branches, build/run commands, environment-variable scopes, domains, routes, health checks, replica counts, autoscaling, region, egress IPs, logs, and alerts. **Gotcha:** App Spec fields are platform configuration, not a portable Compose file. 2. **Map components to Raff services.** Move public HTTP components to web services, internal APIs to private services, consumers to workers, schedules to cron jobs, and administrative commands to one-off jobs. 3. **Choose a portable build source.** Use GitHub, a Dockerfile, a prebuilt image, buildpacks, or Docker Compose. **Gotcha:** GitLab and Bitbucket source workflows need a GitHub mirror or an external image-building pipeline before direct Raff deployment. 4. **Move durable state.** Export managed databases with native tools and copy Spaces objects to Raff Object Storage or another S3-compatible destination. Do not plan around App Platform's local filesystem because it is ephemeral. 5. **Recreate configuration and verify.** Add secrets, routes, domains, health checks, private bindings, persistent volumes, managed data services, callbacks, and external allowlists. Test on a temporary hostname and perform a restore rehearsal. 6. **Cut over with rollback.** Lower DNS TTL to **300 seconds**, freeze writes where necessary, complete the final data sync, update DNS and callback URLs, monitor production, and retain the DigitalOcean app until the rollback window closes. Stateless source/image components are usually the easiest part of this migration. Stateful databases, object storage, App Spec assumptions, source-provider integrations, autoscaling rules, egress IP allowlists, and region-specific dependencies create most of the migration risk. Before switching production traffic, use the [App Platform Migration Checklist](/learn/guides/app-platform-migration-checklist) to validate secrets, durable data, domains, workers, and rollback. ## About DigitalOcean App Platform [DigitalOcean App Platform](https://www.digitalocean.com/products/app-platform) is a managed PaaS from **DigitalOcean Holdings, Inc.**, whose principal executive offices are in New York. DigitalOcean was founded in **2012**. App Platform deploys source code and container images across 12 regions with managed builds, routing, scaling, monitoring, and integrations into DigitalOcean's broader cloud portfolio. ## Conclusion: DigitalOcean App Platform or Raff? The DigitalOcean-App-Platform-versus-Raff decision resolves across four measured axes: cost boundary, regional/scaling reach, durable state, and platform operations. - **Cost boundary:** Raff starts at **$3/month**, is $27.99 at 2 vCPU / 4 GB, and charges $0 public app egress; DigitalOcean starts dynamic compute at **$5/month**, is $50 at 2 shared vCPU / 4 GiB, and meters transfer above plan allowances. - **Regional and scaling reach:** DigitalOcean provides **12 regions**, request-based autoscaling to **100 containers**, CPU/fixed scaling to **250**, and dedicated CPU plans; Raff exposes one public `us-east` Apps region and a simpler service model. - **Durable state:** Raff supports persistent application volumes; DigitalOcean App Platform supports **0 volumes** and limits local storage to a 4 GiB ephemeral filesystem, encouraging state to live in databases or object storage. - **Platform operations:** DigitalOcean offers GitHub, GitLab, Bitbucket, App Spec, `doctl`, Terraform, and a 99.95% component SLA; Raff emphasizes full Compose import, service ceilings, a default spend cap, and a 99.9% platform SLA. Choose DigitalOcean App Platform when multi-region placement, autoscaling, dedicated CPU, GitLab/Bitbucket, or DigitalOcean-native operations are requirements. Choose Raff when a `us-east` deployment can trade geographic breadth for lower comparable service prices, persistent volumes, Docker Compose portability, $0 public egress, and a tighter billing model. Raff publishes a **99.9% platform SLA**. --- ### Coolify Alternative 2026: Pricing, Performance & Features URL: https://rafftechnologies.com/learn/compare/coolify-alternative Description: Considering Coolify? Raff Apps starts at $3/mo with $0 public egress; Coolify is free self-hosted but requires your own server. Raff Apps wins on managed runtime infrastructure, fixed service ceilings, $0 public application egress, first-party managed data services, and reduced server maintenance. Coolify wins on open-source ownership, host-level control, infrastructure-provider choice, broader Git-provider support, and the ability to deploy unlimited workloads across user-selected servers. Choose Coolify when owning the server and control plane is part of the requirement; choose Raff when the goal is to deploy services without operating the platform beneath them. Raff Apps starts at $3/month including runtime, while Coolify self-hosted software is $0 and Coolify Cloud starts at $5/month for two connected servers before workload-server costs. Coolify and Raff Apps can both deploy Git projects, Dockerfiles, images, and Docker Compose stacks, but the operational boundary is fundamentally different. Coolify runs as an open-source control plane over infrastructure the customer supplies, and Coolify Cloud manages that control plane for $5/month while customers still bring their own servers. Raff Technologies includes the application runtime inside published service tiers, starting at $3/month with $0 public app egress. The comparison therefore turns on infrastructure ownership, operating responsibility, and whether server density or service-by-service cost boundaries matter more. ## Coolify vs Raff: which is right for you? Coolify is the better fit when server ownership is intentional. Raff is the better fit when infrastructure maintenance is work the application team wants the platform to absorb. | Decision factor | Choose Raff Apps | Choose Coolify | |---|---|---| | Operating model | Managed application runtime and platform | Open-source control plane on servers you own or rent | | Entry price | Micro from $3/month including runtime | Self-hosted software $0; server required | | Managed control plane | Included | Cloud $5/month for 2 connected servers | | Cost boundary | Published per-service ceiling and default spend cap | Server bill + storage + networking + backup + optional Cloud fee | | Server maintenance | Raff manages platform hosts | Customer manages workload servers | | Location choice | One public `us-east` region | Any supported user-selected server location | | Portability | Dockerfile, image, buildpacks, and full Compose import | Open-source control plane, Docker, Compose, and host access | For a small team, the most important question is not whether Coolify or Raff has more deployment features. It is whether Linux patching, Docker capacity, SSH security, disk pressure, network policy, workload backups, and provider billing should remain part of the team's operating model. ## Coolify overview [Coolify](https://coolify.io/) is an open-source, self-hostable platform for deploying applications, databases, and Docker-compatible services on infrastructure selected by the user. Its documentation explicitly says Coolify is not a cloud service that supplies application compute: users provide a VPS, EC2 instance, Raspberry Pi, laptop, or other supported server and connect it over SSH. The self-hosted edition is **free forever** with the full feature set. Coolify supports GitHub, GitLab, Bitbucket, Gitea, and other Git sources; Dockerfiles; Docker Compose; container images; pull-request deployments; automatic Let's Encrypt certificates; APIs; webhooks; monitoring; database deployments; S3-compatible backups; and Docker Swarm. Its current documentation says Kubernetes support is coming later. Coolify Cloud manages the Coolify control plane rather than the workload servers. It costs **$5/month for up to 2 connected servers** and **$3/month for each additional server**, with a 20% discount displayed for annual billing. Customers still bring and pay for the servers where applications, databases, and services run. Coolify Cloud reports **2,100+ active users**, while the broader Coolify documentation reports **204,000+ servers** running Coolify and a community above 16,000 members. Coolify's strongest advantages are ownership and infrastructure freedom. Teams can choose server providers and locations, keep data and configuration on their own infrastructure, use host-level Docker capabilities, and move the control plane without translating every application into a proprietary runtime model. ## Raff overview [Raff Apps](/products/app-platform) is a managed application platform for deploying source code and containers without administering the underlying operating system. It supports GitHub push-to-deploy, buildpacks, Dockerfiles, existing container images, and full Docker Compose imports. Raff Apps supports public web services, private services, background workers, timezone-aware cron jobs, one-off jobs, pull-request previews, immutable revisions, one-click rollback, persistent volumes, and scale-to-zero behavior. Applications can connect to managed PostgreSQL, MySQL, Valkey, ClickHouse, and Kafka, as well as object storage, VMs, private networking, Kubernetes, and Functions. Current Raff Apps tiers are: | Tier | vCPU | RAM | Ephemeral disk | Monthly ceiling | |---|---:|---:|---:|---:| | Micro | 0.25 | 512 MB | 2 GB | $3.00 | | Starter | 0.5 | 1 GB | 5 GB | $6.99 | | Standard | 1 | 2 GB | 10 GB | $16.99 | | Pro | 2 | 4 GB | 20 GB | $27.99 | | Pro Max | 4 | 8 GB | 40 GB | $61.99 | | Scale | 8 | 16 GB | 80 GB | $119.99 | Compute is billed per second against the published monthly ceiling. Public application egress and team seats are priced at $0, and the spend cap is enabled by default. Raff publishes a **99.9% platform SLA**. Raff was verified at **4.5/5** on August 16, 2026, and G2 is 4.6/5. Raff gives up Coolify's host-level freedom in exchange for a smaller operational surface and explicit service-by-service resource boundaries. ## Coolify pricing vs Raff pricing Coolify and Raff price different layers. Raff's Apps price includes the application runtime. Coolify self-hosted is software that runs on infrastructure the customer supplies, while Coolify Cloud charges for a hosted control plane and still requires external workload servers. | Buying position | Raff Apps | Coolify | Decision signal | |---|---:|---:|---| | Entry deployment | Micro $3 including runtime | Self-hosted $0 software + server | Coolify wins if suitable infrastructure already exists | | Hosted control plane | Included in Apps service | Cloud $5/month for up to 2 servers | Coolify Cloud fee does not include workload compute | | 3 connected servers | Workloads priced by selected Apps services | $8/month control-plane fee + 3 server bills | Coolify rewards teams intentionally operating a server fleet | | 10 connected servers | Workloads priced by selected Apps services | $29/month control-plane fee + 10 server bills | Server, storage, transfer, and operations dominate total cost | | 2 vCPU / 4 GB application | Raff Pro $27.99 including managed runtime | No fixed Coolify compute price; depends on chosen server | Not a performance-equivalent price comparison | **Comparison class:** Coolify is a control plane, not a fixed compute service. Its software fee cannot be compared directly with a Raff Apps instance unless the Coolify workload server, storage, bandwidth, backup destination, and operating effort are included. ### Automated backups Coolify Cloud automatically backs up the **Coolify Cloud database every 24 hours**. That protects the managed control plane; it should not be treated as an automatic backup of every application, database, or persistent volume on connected servers. For workload data, Coolify supports scheduled database backups using cron-style frequencies and can store backups locally or in S3-compatible storage with configurable retention. The operator chooses the schedule, storage target, and retention policy and remains responsible for verifying restores. Raff also separates application deployment rollback from durable-data recovery. App revisions are not database backups. Production state should live in managed databases, object storage, or persistent volumes with a documented recovery path appropriate to the selected service. ### Hidden infrastructure costs Coolify's self-hosted $0 software price is real, but total application cost can include the server, block or local storage, snapshots, public transfer, backup storage, monitoring, spare capacity for builds, and engineering time for updates and incidents. Coolify Cloud removes maintenance of the Coolify instance itself, not the connected workload servers. Coolify can be cheaper when several low-traffic applications share one well-managed server. Raff can cost more than dense server packing because services have explicit resource boundaries, but that model also limits the number of operational variables a small application team must own. :::cta Deploy an App Now Deploy containers, workers, cron jobs, and Docker Compose stacks with managed runtime infrastructure. ::: ## Bandwidth and transfer policy Raff Apps charges **$0 for public application egress**. Coolify does not publish one universal workload-bandwidth price because the user's connected server provider controls transfer allowances, overage rates, port characteristics, and regional network charges. That distinction makes Coolify's network economics highly provider-dependent. A server with generous or unmetered transfer can make a Coolify deployment attractive for bandwidth-heavy applications, while a server with metered cloud egress can create a materially different bill even though Coolify itself adds no per-GB application fee. For budgeting, a Coolify team must evaluate at least two separate network boundaries: traffic associated with the workload server and any storage or cross-region transfer used by the application. Raff collapses normal public Apps egress to $0, making transfer easier to forecast but offering less location choice than Coolify's bring-your-own-server model. ## Feature comparison: Coolify vs Raff | Feature | Raff Apps | Coolify | |---|---|---| | Primary model | Managed app runtime | Open-source deployment control plane | | Git providers | GitHub | GitHub, GitLab, Bitbucket, Gitea, other Git sources | | Dockerfile / existing image | Yes | Yes | | Docker Compose | Full stack import | Primary deployment path, including raw Compose | | Pull-request deployments | Yes | Yes | | Host-level access | No | Yes, on user-controlled servers | | Location choice | Public `us-east` region | Any supported server location/provider | | Public app egress | $0 | Provider-dependent | | Long-running workers | First-class service type | Containers/services configured by operator | | Private services | First-class service type | Docker/provider networking controlled by operator | | Persistent volumes | Managed application volumes | Host/provider storage controlled by operator | | Managed PostgreSQL | First-party Raff service | Customer-operated PostgreSQL deployment | | Managed MySQL | First-party Raff service | Customer-operated MySQL/MariaDB deployment | | S3-compatible backups | Available through Raff data products | Configurable scheduled DB/instance backups | | Multi-server | Managed platform abstraction | Unlimited connected servers; Docker Swarm supported | | Kubernetes | Raff Managed Kubernetes is live separately | Documented as coming later | | Team members | $0 Apps seat fee | Unlimited; Cloud teams can require separate subscriptions | | Open-source control plane | No | Yes | Coolify wins on infrastructure-provider choice, host access, open-source ownership, Git-provider breadth, and server-level Docker control. Raff wins on managed workload infrastructure, explicit service resources, first-party managed data services, $0 public application egress, and removing Linux/Docker host maintenance from the application team's responsibilities. ## Features and reliability: Raff vs Coolify This comparison includes **0 controlled Raff-versus-Coolify application benchmarks**, so it does not declare either platform faster. Coolify does not have one standardized compute substrate: the user can deploy it against VPS instances, dedicated servers, local machines, cloud instances, or Docker Swarm clusters, so performance follows the chosen infrastructure and topology. ### Reliability ownership Raff operates the Apps platform host, deployment system, and runtime infrastructure. The customer still owns application code, configuration, data design, secrets, and external dependencies. Coolify self-hosting shifts more of the reliability surface to the operator: Linux security updates, SSH access, Docker updates, disk capacity, reverse proxy availability, server monitoring, provider incidents, workload backups, and recovery. Coolify Cloud removes maintenance of the Coolify control plane, but connected servers remain customer-operated infrastructure. ### Application isolation and density Coolify lets teams pack several workloads onto one server and configure Docker resource limits themselves. That can improve infrastructure utilization, but it also creates a shared capacity and failure domain unless the operator deliberately isolates workloads and reserves headroom. Raff assigns applications to published service tiers. The team gives up some server-packing flexibility but gets explicit vCPU/RAM boundaries and monthly ceilings per service. ### Backups and recovery Coolify supports scheduled database backups and S3-compatible destinations with configurable retention. Coolify Cloud separately backs up its own control-plane database every 24 hours. Application volumes, uploaded files, provider snapshots, and external services still need an explicit recovery design. Raff also requires state-aware recovery planning. Application revision rollback, managed-database recovery, object storage, and persistent-volume protection are separate concerns and should be tested independently. ### Release safety Coolify supports health checks and can roll back using Docker images that remain available locally. Raff uses immutable application revisions and one-click rollback. In both cases, rolling application code backward does not automatically undo incompatible database migrations or restore lost data. ### Availability design Coolify can connect unlimited servers and supports single-server, multi-server, and Docker Swarm setups, giving experienced teams wide freedom to design availability. The platform does not turn a single connected server into a highly available application automatically. Raff publishes a **99.9% platform SLA** and abstracts host placement from the Apps user. Application architecture still matters: a single app instance, database, or external dependency can remain a failure point on either model. ## When you should choose Coolify over Raff Choose Coolify when: - **Open-source ownership is mandatory.** The full Coolify feature set is available in its $0 self-hosted edition. - **You already operate servers well.** The team has Linux, Docker, monitoring, backup, and incident-response practices in place. - **Infrastructure-provider choice matters.** Coolify can connect unlimited compatible servers from locations and providers you select. - **Multi-app server density is valuable.** Several low-traffic services can share one server instead of each having a separate managed service tier. - **Git-provider breadth matters.** Coolify supports GitHub, GitLab, Bitbucket, Gitea, and other Git workflows. - **Deep Docker control is required.** Raw Compose, custom networks, storage, and host-level configuration remain available to the operator. - **A large self-hosted service catalog is useful.** Coolify documents 200+ one-click services alongside arbitrary Docker-compatible workloads. Coolify can also run on a Raff Linux VM when a team wants Coolify's control plane while keeping the underlying server on Raff infrastructure. The [Coolify installation tutorial](/learn/tutorials/install-coolify-ubuntu-24-04) covers that path. ## When you should choose Raff over Coolify Choose Raff Apps when: - **Server maintenance should disappear from the workflow.** Raff manages the runtime host instead of asking the application team to patch Linux and Docker. - **Service cost boundaries matter.** Raff Standard is $16.99 for 1 vCPU / 2 GB and Raff Pro is $27.99 for 2 vCPU / 4 GB, each with a published ceiling. - **Public transfer is substantial.** Raff Apps prices public egress at $0 rather than inheriting a connected server provider's transfer schedule. - **Managed databases are preferred.** Raff provides PostgreSQL, MySQL, Valkey, ClickHouse, and Kafka without operating database containers inside the app stack. - **A default spend guardrail matters.** The Apps spend cap is enabled by default. - **Persistent application services are the main abstraction.** Web, private, worker, cron, and one-off services are first-class platform types. - **One cloud account should span the stack.** Apps can connect to Raff databases, object storage, VMs, private networks, Kubernetes, and Functions. For a managed application runtime without maintaining workload servers, compare the [Raff Apps product and plans](/products/app-platform) against your complete Coolify server and operations costs. ## Migrating from Coolify to Raff 1. **Inventory every Coolify resource.** Record applications, Compose stacks, Git sources, domains, environment variables, secrets, ports, health checks, volumes, databases, schedules, webhooks, and host-specific dependencies. **Gotcha:** Coolify labels and proxy rules are not portable application configuration. 2. **Map workloads to Raff services.** Move public HTTP workloads to web services, internal components to private services, consumers to workers, schedules to cron jobs, and administrative commands to one-off jobs. 3. **Choose a portable deployment source.** Use GitHub, an existing image, a Dockerfile, buildpacks, or a Docker Compose import. **Gotcha:** bind mounts, host networking, privileged containers, devices, and host paths may need redesign on a managed platform. 4. **Export persistent state.** Create database-native dumps, archive application volumes, copy uploaded files, verify checksums, and move shared object data to an appropriate durable service before final synchronization. 5. **Recreate configuration and verify.** Add secrets, domains, health checks, private bindings, storage, database credentials, OAuth callbacks, webhooks, and allowlists. Test a temporary hostname and perform a restore rehearsal. 6. **Cut over with rollback.** Lower DNS TTL to **300 seconds**, freeze writes where necessary, complete the final data sync, change DNS and callbacks, monitor production, and retain the Coolify deployment until the rollback window closes. Stateless containers are usually the simplest part of a Coolify-to-Raff migration. Stateful volumes, databases, host networking, server cron, proxy labels, and provider-specific infrastructure create most of the migration risk. Use the [App Platform Migration Checklist](/learn/guides/app-platform-migration-checklist) to check secrets, volumes, worker schedules, domain cutover, and rollback before moving production traffic. ## About Coolify [Coolify](https://coolify.io/) is an open-source self-hosting platform operated by **coolLabs Solutions Kft.**, a Hungary-based software company. It deploys applications, databases, and Docker-compatible services to customer-controlled infrastructure and offers both a free self-hosted control plane and a managed Coolify Cloud option. Official documentation currently reports 204,000+ servers running Coolify. ## Conclusion: Coolify or Raff? The Coolify-versus-Raff decision resolves across four measured axes: operating responsibility, cost boundary, infrastructure control, and data/availability ownership. - **Operating responsibility:** Raff manages the Apps runtime host; Coolify users manage workload servers even when the Coolify Cloud control plane is managed. - **Cost boundary:** Raff Apps starts at $3 with published service ceilings; Coolify self-hosted is $0 software and Cloud starts at $5 for 2 servers, but workload infrastructure is separate. - **Infrastructure control:** Coolify provides open-source host access and user-selected locations; Raff deliberately abstracts the host and exposes one public `us-east` Apps region. - **Data and availability ownership:** Coolify gives operators direct control over Docker, storage, backup schedules, and multi-server topology; Raff provides managed service boundaries and first-party data products. Choose Coolify when open-source ownership, server density, provider choice, and host-level control justify owning the infrastructure lifecycle. Choose Raff when the objective is to ship connected application services with explicit resource ceilings, $0 public egress, managed data services, and less server administration. Raff publishes a **99.9% platform SLA**. For adjacent decisions, review [Render Alternative 2026](/learn/compare/render-alternative), [Self-Hosting Apps on Raff](/learn/guides/self-hosting-apps-on-raff), and [Install Coolify on Ubuntu 24.04](/learn/tutorials/install-coolify-ubuntu-24-04). --- ### Railway Alternative 2026: Pricing, Performance & Features URL: https://rafftechnologies.com/learn/compare/raff-vs-railway Description: Railway Hobby has a $5 minimum with $5 usage included; Pro has a $20 minimum with $20 included. Compare usage billing, egress, regions, scaling, and Raff Apps. Raff wins on fixed service ceilings, $0 public egress, full Docker Compose import, and first-party managed data services. Railway wins on four deployment regions, usage-based compute, PR environments, native volume backups, and broader per-service scaling. Choose Railway when global placement and pay-for-actual-use economics matter; choose Raff when `us-east`, predictable monthly ceilings and Compose portability fit the workload. Raff Apps starts at $3/month, while Railway Hobby is $5/month with $5 of included resource usage before metered CPU, memory, storage, and egress. Railway and Raff are now a direct app-platform comparison rather than a PaaS-versus-VM mismatch. Railway charges $20 per vCPU-month, $10 per GB-month of RAM, $0.15 per GB-month of volume storage, and $0.05 per GB of egress, with subscription fees credited toward usage. Raff Apps publishes fixed service ceilings from $3 to $119.99 per month and charges $0 for public app egress and team seats. The practical decision is whether variable usage pricing and four deployment regions are more valuable than fixed resource tiers, direct Compose imports, and a single `us-east` operating model. ## Railway vs Raff: which is right for you? Choose Railway when you want a usage-metered PaaS with four deployment regions, automatic GitHub deployment workflows, PR environments, native scheduled volume backups, replicas, and service sleeping. Choose Raff when you want fixed monthly service ceilings, $0 public egress, full Docker Compose import, persistent app volumes, and first-party managed databases alongside the application platform. | Decision factor | Choose Raff Apps | Choose Railway | |---|---|---| | Entry app price | You want a fixed $3/month Micro ceiling | You want a $0 Free plan or $5 Hobby subscription credited toward usage | | Billing model | Fixed service tiers with per-second billing to a monthly ceiling | Metered CPU, RAM, volume, and egress usage | | Geography | One public `us-east` region fits the workload | You need California, Virginia, Amsterdam, or Singapore | | Egress | You want $0 public app egress | $0.05/GB is acceptable or traffic is modest | | Deployment artifact | Full Docker Compose import matters | GitHub, local source, or Docker image service mapping fits | | Preview workflow | Raff pull-request previews fit the team | Railway PR Environments and focused previews are preferred | | Durable state | Raff persistent volumes plus managed data services fit | Native Railway volume backups and database templates are preferred | For Raff's app-platform decisions, the useful comparison is the steady operating bill rather than the smallest plan card. We separate runtime, outbound traffic, and durable state because those three costs behave differently as a SaaS workload grows. A platform can look inexpensive at idle and become expensive at sustained CPU, memory, or egress; the reverse is also true when a fixed tier sits mostly unused. ## Railway overview [Railway](https://railway.com) is a deployment platform from Railway Corporation. It runs long-lived services, cron jobs, and single-file TypeScript functions, with deployments from GitHub repositories, local source, or Docker images. Railway also provides environments, variables, private networking, replicas, persistent volumes, database templates, logs, metrics, deployment rollback, and a template marketplace. Railway's current subscription structure is Free at **$0/month**, Hobby at **$5/month**, Pro at **$20/month**, and Enterprise at custom pricing. The Free plan includes **$1 of monthly resource credit**, Hobby includes **$5**, and Pro includes **$20**. On paid plans, the subscription amount is credited against resource usage rather than added on top of the same amount of usage. Current metered rates are **$20/vCPU-month**, **$10/GB-month of RAM**, **$0.15/GB-month for volumes**, and **$0.05/GB of network egress**. Compute is billed by the minute. Railway's [pricing documentation](https://docs.railway.com/pricing) is explicit that the final bill depends on actual resource consumption. Railway currently exposes four standard deployment regions: California, Virginia, Amsterdam, and Singapore. Services can use horizontal replicas, and Railway's Serverless mode can put an inactive service to sleep after more than 10 minutes without outbound traffic, then wake it on the next incoming request. Railway is particularly strong for teams that want service-level automation rather than fixed instance sizing. GitHub autodeploys, PR Environments, focused PR previews, deployment rollback, native volume backup schedules, and cross-region deployment controls are integrated into the platform workflow. ## Raff overview [Raff Apps](/products/app-platform) is Raff's managed application platform for deploying source code and containers without administering the operating system underneath them. It supports GitHub push-to-deploy, buildpacks, Dockerfiles, existing container images, and full Docker Compose imports. Raff Apps supports public web services, private services, long-running workers, timezone-aware cron jobs, one-off jobs, pull-request previews, persistent application volumes, immutable revisions, one-click rollback, and scale-to-zero behavior. Applications can connect to Raff Managed Databases for PostgreSQL, MySQL, Valkey, ClickHouse, and Kafka as well as object storage, VMs, Kubernetes, Functions, and private networking. | Raff Apps tier | vCPU | RAM | Ephemeral disk | Monthly ceiling | |---|---:|---:|---:|---:| | Micro | 0.25 | 512 MB | 2 GB | $3.00 | | Starter | 0.5 | 1 GB | 5 GB | $6.99 | | Standard | 1 | 2 GB | 10 GB | $16.99 | | Pro | 2 | 4 GB | 20 GB | $27.99 | | Pro Max | 4 | 8 GB | 40 GB | $61.99 | | Scale | 8 | 16 GB | 80 GB | $119.99 | Runtime is billed per second against the published monthly ceiling. Public application egress and Apps team seats cost **$0**, and the spend cap is enabled by default. Raff currently exposes one public Apps region, `us-east`, which is a real limitation for teams that need geographic placement elsewhere. Raff publishes a **99.9% platform SLA**. On August 17, 2026, Raff's Trustpilot profile was **4.5/5**, with G2 at 4.6/5. ## Railway pricing vs Raff pricing Railway and Raff price application compute differently. Railway meters CPU and memory actually consumed, while Raff publishes resource tiers with a monthly ceiling. The right comparison therefore needs both the plan entry points and a few clearly labeled full-utilization examples. | Buying position | Raff Apps | Railway | Decision signal | |---|---:|---:|---| | Entry platform | Micro — 0.25 vCPU / 512 MB — $3 ceiling | Free — $0 with $1 monthly resource credit | Railway wins for experimentation at $0 | | Personal paid baseline | Starter — 0.5 vCPU / 1 GB — $6.99 ceiling | Hobby — $5 with $5 usage included | Different models; Railway meters actual use | | Production/team baseline | Standard — 1 vCPU / 2 GB — $16.99 ceiling | Pro — $20 with $20 usage included | Raff has lower fixed tier; Railway includes platform usage credit | | Full-month 1 vCPU + 2 GB use | $16.99 Standard ceiling | $40 if 1 vCPU and 2 GB were continuously consumed | Railway can be lower when actual CPU use is far below the full-month assumption | | Full-month 2 vCPU + 4 GB use | $27.99 Pro ceiling | $80 if 2 vCPU and 4 GB were continuously consumed | Raff has the lower ceiling under sustained full utilization | **Comparison class:** Railway does not sell fixed 1 vCPU / 2 GB or 2 vCPU / 4 GB instances at those monthly totals. The $40 and $80 Railway rows are arithmetic examples using its published $20/vCPU-month and $10/GB-month rates under continuous full-month consumption. Real Railway CPU usage may be substantially lower, especially for idle or bursty services. Railway's subscription is credited against usage. A Pro workspace with $40 of resource usage pays $40 total for the usage/subscription portion, not $60. Pro seats are currently $0, so neither Railway nor Raff adds a per-seat charge for the standard team workflow. ### Bandwidth cost math Railway charges **$0.05/GB** for network egress. Raff Apps public application egress is **$0**. | Monthly public egress | Raff Apps | Railway egress charge | |---:|---:|---:| | 100 GB | $0 | $5.00 | | 500 GB | $0 | $25.00 | | 1 TiB (1,024 GB) | $0 | $51.20 | | 2 TiB (2,048 GB) | $0 | $102.40 | | 5 TiB (5,120 GB) | $0 | $256.00 | These figures isolate public egress only. Railway recommends private networking for service-to-service communication inside a project to avoid unnecessary public-network charges. ### Automated backups Railway has a meaningful native advantage for volume-backed services. Railway volumes support manual backups and automated **daily, weekly, and monthly** schedules. Daily backups are retained for **6 days**, weekly backups for **1 month**, and monthly backups for **3 months**. Backup storage is incremental and billed at the same **$0.15/GB-month** rate as volumes for data unique to the backup. Raff Apps application revisions and one-click rollback are release controls, not a substitute for data backup. Raff's current canonical Apps specification does not claim an equivalent native volume-backup schedule, so this comparison does not invent one. Stateful Raff Apps workloads should place recoverable data in an appropriate managed database, object storage, or another verified backup path and test restoration separately from application rollback. ### Variable-cost boundaries Railway lets workspace admins set compute usage alerts and hard limits. Hitting a hard limit takes workloads offline to stop additional compute charges. Raff Apps instead publishes a monthly ceiling for each service tier and enables a spend cap by default. Railway provides finer pay-for-use economics; Raff gives a more visible upper bound for the selected app tier. :::cta Deploy an App Now Deploy web services, workers, cron jobs, and Docker Compose stacks on Raff Apps. ::: ## Bandwidth and transfer policy Railway meters public network egress at **$0.05/GB**. Private networking connects services inside a project environment over Railway's internal network, which can avoid public egress for internal service communication. The cost model therefore rewards architectures that keep app-to-database and service-to-service traffic private. Raff Apps charges **$0 for public application egress**. That removes outbound transfer as a variable line item for APIs, media delivery, downloads, package distribution, and workloads with seasonal or unpredictable traffic. The trade-off is geography. Railway currently has **four standard deployment regions** across the United States, Europe, and Southeast Asia; Raff Apps exposes **one public region, `us-east`**. Railway can reduce user-to-app distance for geographically distributed audiences, while Raff is easier to forecast when one eastern-U.S. placement is sufficient and transfer volume is material. ## Feature comparison: Railway vs Raff | Feature | Raff Apps | Railway | |---|---|---| | Entry price | $3/month ceiling | $0 Free; $5 Hobby | | Billing model | Per second to fixed tier ceiling | Metered CPU, RAM, storage, egress | | Public regions | 1 — `us-east` | 4 — California, Virginia, Amsterdam, Singapore | | Public egress | $0 | $0.05/GB | | Source deployment | GitHub, buildpacks, Dockerfile, existing image | GitHub, local source, Docker image | | Docker Compose | Full stack import | Compose services must be translated into Railway services | | Public web services | Yes | Yes | | Private services/networking | Yes | Yes | | Long-running workers | Yes | Yes | | Cron jobs | Yes | Yes | | Scale-to-zero / sleeping | Yes | Serverless sleep after >10 minutes without outbound traffic | | PR preview environments | Yes | Yes, including focused PR environments | | Persistent volumes | Yes | Yes, $0.15/GB-month | | Native volume backup schedule | Not claimed in current Apps specification | Daily / weekly / monthly | | Deployment rollback | Immutable revisions, one-click rollback | Previous deployment rollback within plan retention | | Horizontal replicas | Platform-managed service model | Up to 6 Hobby / 42 Pro by current plan limits | | Team seats | $0 | $0 on Pro/Enterprise | | Managed data model | First-party PostgreSQL, MySQL, Valkey, ClickHouse, Kafka | Database services/templates including PostgreSQL, MySQL, Redis, MongoDB | | Published standard SLA | 99.9% platform SLA | Pro explicitly excludes SLOs; Enterprise can negotiate an SLA | Railway wins on region choice, native scheduled volume backups, explicit replica controls, its $0 Free plan, and usage-based economics for low-duty-cycle services. Raff wins on fixed tier ceilings, $0 public egress, direct Compose import, and a first-party managed-data portfolio that is separate from app containers. ## Features and reliability: Raff vs Railway This comparison includes **0 controlled Raff-versus-Railway application benchmarks**, so it does not declare either platform faster. A valid test would need matched CPU scheduling, memory, region, application image, database placement, storage path, concurrency, caching, and repeated test windows. ### Usage-based compute versus fixed ceilings Railway's billing can be efficient for bursty workloads because CPU and memory are metered rather than sold as fixed instance sizes. Railway Serverless can also stop an inactive service after more than 10 minutes without outbound traffic, reducing compute usage while it sleeps. The first request wakes the service and can experience a cold-start delay. Raff Apps also supports scale-to-zero, but its commercial model is easier to cap: each tier has a published monthly ceiling. The trade-off is that a fixed ceiling does not automatically mean it is cheaper for a lightly used service. Railway's metered model can win when the application spends most of the month idle. ### Regions and replicas Railway exposes four standard deployment regions and lets services run horizontal replicas. Current plan limits allow up to **6 replicas on Hobby** and **42 on Pro**. Railway also supports changing regions, although a service with an attached volume needs a volume migration and can experience downtime during that move. Raff Apps exposes only `us-east`. Teams with users concentrated in eastern North America may not benefit from extra placement choices, but teams with latency or data-location requirements in Europe, Asia-Pacific, or the U.S. West should treat Railway's region map as a substantive advantage. ### Release safety and previews Both platforms provide pull-request preview workflows and deployment rollback. Railway PR Environments can clone an environment for a GitHub pull request and remove it when the PR closes; focused PR environments can deploy only services whose watched paths changed. Raff Apps provides pull-request previews, immutable revisions, and one-click rollback. Railway's current rollback retention is **24 hours on Free/Trial, 72 hours on Hobby, 120 hours on Pro, and 360 hours on Enterprise**. Raff's immutable revision model is not a database restore mechanism either, so both platforms still require a separate data-recovery plan. ### Data recovery Railway's scheduled volume backups are one of its clearest operational strengths. The platform can retain daily, weekly, and monthly volume backups and restore them into the same project and environment. Railway also documents PostgreSQL point-in-time recovery for eligible Postgres deployments. Raff Apps supports persistent volumes, but this comparison does not claim a native Apps-volume backup schedule that is absent from the current canonical specification. For teams that want database operations separated from application runtime, Raff provides first-party Managed Databases for **five engines: PostgreSQL, MySQL, Valkey, ClickHouse, and Kafka**. ### Trust and support Railway's current Trustpilot profile shows **2.9/5**; the profile is marked as merged, so that signal should be interpreted cautiously rather than treated as a clean product benchmark. Railway's own support documentation says its Central Station community has **1.8 million+ users and developers**, a much larger public community signal than Raff's current customer count. Raff publishes a **99.9% platform SLA**. Railway Pro support usually targets responses within 72 hours but explicitly excludes SLOs; Railway can provide Business Class SLOs and negotiate a contractual SLA for Enterprise customers. ## When you should choose Railway over Raff Choose Railway when: - **You need more regions.** Railway exposes **4 standard deployment regions** versus Raff Apps' single public `us-east` region. - **Usage-based billing matches the workload.** Railway meters CPU at **$20/vCPU-month** and RAM at **$10/GB-month**, which can suit low-duty-cycle services better than a fixed tier. - **Native volume backups are important.** Railway supports daily, weekly, and monthly schedules with retention up to **3 months** on the monthly schedule. - **PR infrastructure is central to development.** Railway can provision full or focused PR Environments automatically from GitHub pull requests. - **You want explicit replica controls.** Current plan limits allow up to **6 replicas on Hobby** and **42 on Pro**. - **A $0 experimentation tier matters.** Railway Free includes **$1 of resource usage per month**. - **Railway's deployment canvas and templates fit the team.** GitHub, Docker images, databases, volumes, variables, and services are modeled in one project workflow. ## When you should choose Raff over Railway Choose Raff Apps when: - **A fixed cost ceiling matters.** Raff Apps starts at **$3/month** and publishes ceilings through **$119.99/month** rather than leaving CPU and RAM fully variable. - **Public egress is material.** Raff Apps charges **$0** for public app egress versus Railway's **$0.05/GB**. - **Docker Compose is the deployment artifact.** Raff imports a **full Compose stack**; Railway maps Compose services into separate Railway services instead of running the Compose file directly. - **First-party managed data should be separate from app containers.** Raff provides **5 managed data engines**: PostgreSQL, MySQL, Valkey, ClickHouse, and Kafka. - **One public eastern-U.S. region is sufficient.** Railway's four-region advantage has less value when `us-east` already satisfies latency and architecture needs. - **A published standard SLA matters.** Raff publishes a **99.9% platform SLA**, while Railway's Pro support documentation explicitly excludes SLOs. - **Predictable team pricing matters.** Raff Apps seats cost **$0**, and the spend cap is enabled by default. [Raff Apps](/products/app-platform) is a live managed application platform. For adjacent app-platform decisions, compare [Render and Raff](/learn/compare/render-alternative), [DigitalOcean App Platform and Raff](/learn/compare/digitalocean-app-platform-alternative), and [Fly.io and Raff](/learn/compare/flyio-alternative). ## Migrating from Railway to Raff 1. **Inventory the Railway project.** Record services, GitHub repositories, Docker images, build and start commands, variables, private-network dependencies, public domains, replicas, regions, cron jobs, functions, volumes, database services, backup schedules, and PR Environment behavior. 2. **Map Railway services to Raff Apps.** Move public HTTP workloads to web services, internal APIs to private services, queue consumers to workers, schedules to cron jobs, and administrative tasks to one-off jobs. **Gotcha:** a Railway project can contain service relationships that are implicit in reference variables and internal DNS, so document them before migration. 3. **Choose the deployment source.** Use GitHub, a Dockerfile, an existing image, buildpacks, or Docker Compose on Raff. If the original architecture started from Compose, this is the point to restore the Compose file as the source of truth rather than maintaining a Railway-specific service translation. 4. **Move durable state.** Export Railway PostgreSQL, MySQL, Redis, MongoDB, or other database data with native tools and copy volume data through an application-safe workflow. **Gotcha:** Railway deployment rollback restores code/image and variables, not a database; volume backups must be restored or exported separately. 5. **Recreate configuration and verify.** Add secrets, private service bindings, domains, health checks, persistent volumes, managed data services, callbacks, and external allowlists. Test startup ordering, background workers, cron behavior, cold-start expectations, restore procedures, and a temporary hostname before cutover. 6. **Cut over with rollback.** Lower DNS TTL to **300 seconds**, freeze writes where required, run the final data sync, update DNS and callback URLs, monitor production, and retain the Railway environment until the rollback window closes. Stateless GitHub or container services are generally the easiest part of a Railway-to-Raff migration. Stateful volumes, database recovery, Railway reference variables, PR-environment assumptions, multi-region placement, internal DNS, and provider-specific deployment settings create most of the migration risk. Use the [App Platform Migration Checklist](/learn/guides/app-platform-migration-checklist) to validate environment variables, data recovery, private service dependencies, DNS cutover, and rollback. ## About Railway [Railway](https://railway.com) is a deployment platform operated by **Railway Corporation**, with its legal contact address in San Francisco, California. It provides application services, cron jobs, functions, databases, volumes, private networking, deployment regions, GitHub automation, PR environments, observability, and usage-based billing for developers and production teams. Railway pricing, region, backup, deployment, and support claims in this comparison were verified against Railway's official documentation on August 17, 2026. ## Conclusion: Railway or Raff? The Railway-versus-Raff decision resolves across four measured axes: cost model, geographic/scaling reach, deployment portability, and data/reliability operations. - **Cost model:** Raff Apps starts at **$3/month** with fixed service ceilings and $0 public egress; Railway starts at $0, then meters CPU at **$20/vCPU-month**, RAM at **$10/GB-month**, and egress at **$0.05/GB**. - **Geographic and scaling reach:** Railway exposes **4 regions** and up to **42 Pro replicas**; Raff Apps exposes one public `us-east` region and a simpler fixed-tier operating model. - **Deployment portability:** Raff supports full Docker Compose import, while Railway translates Compose services into Railway services; both support GitHub and container workflows. - **Data and reliability operations:** Railway has native scheduled volume backups and Enterprise SLA options; Raff publishes a **99.9% platform SLA** and separates application runtime from five first-party managed data engines. Choose Railway when global placement, explicit replicas, native volume backup schedules, PR environments, or pay-for-actual-use economics are the deciding requirements. Choose Raff when `us-east` is sufficient and fixed service ceilings, $0 public egress, Compose portability, and first-party managed data make the app bill and architecture easier to reason about. Raff publishes a **99.9% platform SLA**. Railway's public Trustpilot profile currently shows **2.9/5**, while Railway reports a Central Station community of **1.8 million+ users and developers**; the different sample sizes and profile structures make review scores context rather than a substitute for technical due diligence. --- ### Heroku Alternative 2026: Pricing, Performance & Features URL: https://rafftechnologies.com/learn/compare/raff-vs-heroku Description: Considering Heroku? Raff Apps starts at $3/mo with $0 public egress; Heroku starts at $5 Eco with a mature PaaS ecosystem. Raff wins on fixed application tiers, $0 public egress, full Docker Compose import, first-party managed data services, and a spend cap enabled by default. Heroku wins on its mature add-on ecosystem, Pipelines and Review Apps, 12 published runtime-region choices across Common Runtime and Private Spaces, dedicated Performance dynos, and Salesforce enterprise integration. Choose Heroku when its established delivery workflow, Private Spaces, ecosystem, or Salesforce alignment are requirements; choose Raff when `us-east`, predictable service ceilings, Compose portability, and transfer simplicity fit the workload. Raff Apps starts at $3/month, while Heroku starts at $5/month for the Eco plan or $7/month for an always-on Basic dyno. Heroku and Raff Apps are both managed application platforms, so this is a direct PaaS comparison rather than a PaaS-versus-VM comparison. Heroku packages applications around dynos, process types, buildpacks, Pipelines, Review Apps, add-ons, and its Common Runtime or Private Spaces. Raff Apps packages web services, private services, workers, cron jobs, previews, managed data, persistent volumes, and container workflows around published service ceilings and $0 public application egress. ## Heroku vs Raff: which is right for you? Choose Heroku when the application already depends on Heroku conventions or when its ecosystem reduces more engineering work than a lower infrastructure bill would save. Choose Raff when the team wants a smaller operating surface, clear service ceilings, Docker Compose portability, and fewer variable transfer costs. | Decision factor | Choose Raff Apps | Choose Heroku | |---|---|---| | Entry app price | $3/month Micro ceiling | $5/month Eco or $7/month Basic | | Billing preference | Per-second runtime to a published monthly ceiling | Wall-clock dyno usage; Eco uses a pooled 1,000-hour plan | | Geography | One public `us-east` region fits | US/EU Common Runtime or one of 10 Private Spaces regions is required | | Deployment artifact | Docker Compose, Dockerfile, image, GitHub, or buildpack portability matters | Procfile/buildpack conventions and Heroku-native workflows matter | | Delivery workflow | Raff previews and immutable revisions are enough | Pipelines and mature Review Apps are central | | Ecosystem | First-party Raff cloud products fit | Heroku add-ons reduce integration work | | Public transfer | $0 public app egress matters | Heroku's 2 TB soft per-app bandwidth limit fits the workload | A practical decision rule from Raff's product and customer work is to price the whole application stack, not one web process. Web services, workers, previews, databases, durable storage, outbound traffic, and platform-specific integrations usually explain more of the long-term cost than the smallest runtime card. For the broader deployment decision, read [Cloud VM vs App Platform for Startups](/learn/guides/cloud-vm-vs-app-platform-startups). ## Heroku overview [Heroku](https://www.heroku.com/) is a managed cloud application platform operated by Salesforce. Applications run in dynos, Heroku's managed application containers, and teams deploy through source-based build workflows or container-based paths depending on the runtime generation and application configuration. Current Common Runtime pricing starts with **Eco at $5/month** for a shared pool of **1,000 dyno hours**. Eco dynos have 512 MB RAM and sleep after 30 minutes of inactivity. **Basic costs $7/month** for an always-on 512 MB dyno. Production Common Runtime tiers include **Standard-1X at $25/month**, **Standard-2X at $50/month**, and **Performance-M at $250/month** with dedicated compute. Heroku bills non-Eco dynos by wall-clock runtime and prorates usage to the second. A dyno accrues usage while scaled above zero whether or not the application is actively handling requests. Review Apps and one-off dynos also accrue usage while running. Heroku's delivery workflow is one of its clearest strengths. Pipelines model development, review, staging, and production stages, while Review Apps can create disposable applications for pull requests. The platform also provides release history, rollback, logs, metrics on eligible tiers, add-ons, managed data products, and mature developer documentation. Geography is another substantive advantage. Heroku currently lists **2 Common Runtime regions** — United States and Europe — plus **10 Private Spaces regions**: Dublin, Frankfurt, London, Montreal, Mumbai, Oregon, Singapore, Sydney, Tokyo, and Virginia. Private Spaces provide isolated network environments for enterprise workloads. Heroku is also moving from its Cedar generation toward Fir. Fir Private Spaces are generally available, but generation-specific feature differences still matter during deployment and migration, so teams should verify whether an application depends on Cedar-only behavior before moving runtimes. ## Raff overview [Raff Apps](/products/app-platform) is Raff's managed application platform for deploying source code and containers without administering the operating system underneath the service. It supports GitHub push-to-deploy, buildpacks, Dockerfiles, existing container images, and full Docker Compose imports. Raff Apps supports public web services, private services, long-running workers, timezone-aware cron jobs, one-off jobs, pull-request previews, persistent application volumes, immutable revisions, one-click rollback, and scale-to-zero behavior. Applications can connect to Raff Managed Databases for PostgreSQL, MySQL, Valkey, ClickHouse, and Kafka, along with object storage, VMs, Kubernetes, Functions, and private networking. | Raff Apps tier | vCPU | RAM | Ephemeral disk | Monthly ceiling | |---|---:|---:|---:|---:| | Micro | 0.25 | 512 MB | 2 GB | $3.00 | | Starter | 0.5 | 1 GB | 5 GB | $6.99 | | Standard | 1 | 2 GB | 10 GB | $16.99 | | Pro | 2 | 4 GB | 20 GB | $27.99 | | Pro Max | 4 | 8 GB | 40 GB | $61.99 | | Scale | 8 | 16 GB | 80 GB | $119.99 | Runtime is billed per second against the published monthly ceiling. Public application egress costs **$0**, Apps team seats cost **$0**, and the spend cap is enabled by default. Raff Apps currently exposes one public region, `us-east`. That is a real limitation versus Heroku for teams that require Europe, Asia-Pacific, Canada, or U.S. West placement. Raff publishes a **99.9% platform SLA**. On August 17, 2026, Raff's Trustpilot profile showed **4.5/5**, while G2 showed **4.6/5**. ## Heroku pricing vs Raff pricing Heroku and Raff price managed application runtime differently enough that the comparison should use buying positions rather than pretend the resource classes are identical. | Buying position | Raff Apps | Heroku | Decision signal | |---|---:|---:|---| | Personal / intermittent app | Micro — $3 ceiling, 0.25 vCPU / 512 MB | Eco — $5 for 1,000 shared dyno hours / 512 MB | Raff has the lower paid ceiling; Heroku's pooled Eco hours can cover several sleeping personal apps | | Small always-on app | Starter — $6.99 ceiling, 0.5 vCPU / 1 GB | Basic — $7 maximum / 512 MB | Similar monthly price; Raff publishes more memory and a vCPU allocation | | Production baseline | Standard — $16.99 ceiling, 1 vCPU / 2 GB | Standard-1X — $25 maximum / 512 MB | Raff has the lower published ceiling; Heroku brings mature production workflow features | | Larger service | Pro — $27.99 ceiling, 2 vCPU / 4 GB | Standard-2X — $50 maximum / 1 GB | Raff publishes more resources at a lower ceiling; compute classes are not performance-equivalent | | Higher performance position | Pro Max — $61.99 ceiling, 4 vCPU / 8 GB | Performance-M — $250 maximum / 2.5 GB dedicated compute | Heroku wins on a documented dedicated-compute class; Raff has the lower general Apps ceiling | **Comparison class:** these rows compare published buying positions, not matched performance. Heroku does not publish directly comparable vCPU allocations for its shared Common Runtime dynos, and Performance-M uses dedicated compute. Heroku's non-Eco dynos are prorated based on wall-clock usage, with the listed monthly amount acting as the maximum for a dyno that runs continuously through the billing period. Eco is different: the $5 subscription provides 1,000 dyno hours shared across Eco apps in the account. Raff Apps also prorates running services per second, but each tier exposes a monthly ceiling. That makes the upper bound visible for the selected app service before traffic arrives. ### Preview and worker cost Heroku Review Apps and one-off dynos consume billable runtime while active. A production architecture with web dynos, workers, review environments, scheduled jobs, and add-ons can therefore have several independently active resources. Raff previews, web services, workers, cron jobs, and one-off workloads also need to be included in architecture cost. The key difference is the pricing presentation: Raff uses published service ceilings, while Heroku uses dyno runtime and separate attached services. ### Data-service cost Neither app-runtime price includes every production dependency. Heroku Postgres, Key-Value Store, and third-party add-ons have their own plans. Raff Managed Databases and object storage are also separate products. Compare the application plus database, durable storage, backups, preview environments, and traffic rather than treating a single dyno or app service as the production bill. :::cta Deploy an App Now Deploy web services, workers, cron jobs, and Docker Compose stacks on Raff Apps with published service ceilings. ::: ## Bandwidth and transfer policy Raff Apps prices public application egress at **$0**. This removes a per-GB public application-transfer line item from the Apps runtime bill. Heroku does not publish a standard per-GB egress price for ordinary dyno application traffic. Instead, Heroku currently documents a **2 TB soft network-bandwidth limit per app per month**. Teams approaching or exceeding platform limits should review their architecture and Heroku requirements rather than treating the soft limit as an unlimited-transfer promise. The connected data path still matters on both platforms. Add-ons, external databases, object storage, cross-region services, logging providers, backups, and third-party APIs can have their own transfer policies. For Raff, $0 Apps public egress applies to the application platform. It should not be generalized to every connected product without checking that product's current pricing model. Heroku's model is workable when application traffic stays within its operating limits and connected-service transfer is modest. Raff is simpler to forecast for applications where public response traffic is large or uneven and `us-east` already satisfies placement requirements. ## Feature comparison: Heroku vs Raff | Feature | Raff Apps | Heroku | |---|---|---| | Entry app price | $3/month ceiling | $5 Eco / $7 Basic | | Billing model | Per second to fixed tier ceiling | Wall-clock dyno usage; pooled Eco hours | | Public regions | 1 — `us-east` | 2 Common Runtime + 10 Private Spaces regions | | Public app egress | $0 | No standard per-GB dyno rate; 2 TB soft bandwidth limit per app | | Git deployment | Yes | Yes | | Buildpacks | Yes | Yes | | Dockerfile / image workflow | Yes | Yes, subject to runtime-generation workflow | | Docker Compose | Full stack import | No direct whole-stack Compose execution model | | Web and worker processes | Yes | Yes | | Cron / scheduled work | Yes | Scheduler and related workflows | | Pull-request previews | Yes | Review Apps | | Release rollback | Immutable revisions / one-click rollback | Release history / rollback | | Persistent application volumes | Yes | Dyno filesystem is ephemeral; durable state uses data/add-on services | | Managed data | PostgreSQL, MySQL, Valkey, ClickHouse, Kafka | Heroku Postgres, Key-Value Store, add-on ecosystem | | Dedicated app compute tier | No separate Apps class in this comparison | Performance dynos | | Enterprise isolated runtime | Raff platform/private-networking model | Private Spaces and Shield options | | Default spend cap | Yes | No equivalent default app-spend-cap positioning | Heroku wins on geography, dedicated Performance dynos, Pipelines, Review Apps, Private Spaces, and add-on depth. Raff wins on fixed service ceilings, $0 public app egress, Docker Compose import, first-party managed data breadth, and default spend protection. ## Features and reliability: Raff vs Heroku This comparison contains **0 controlled Raff-versus-Heroku application benchmarks**, so it does not declare either platform faster. A valid application benchmark would need matched runtime class, region, application image, database location, cache behavior, concurrency, persistent storage path, and repeated test windows. ### Deployment and delivery workflow Heroku Pipelines remain a mature continuous-delivery model. A pipeline can group development, review, staging, and production apps, and Review Apps can automatically create disposable environments for pull requests. This workflow is a genuine Heroku advantage for teams already standardized on it. Raff provides pull-request previews, immutable revisions, and one-click rollback. Its differentiator is broader deployment-artifact portability: GitHub source, buildpacks, Dockerfiles, container images, and full Docker Compose imports can feed the same Apps workflow. ### Runtime and scaling choices Heroku provides several Common Runtime dyno classes and dedicated Performance dynos. Performance-M starts at $250/month and uses dedicated compute, which Raff Apps does not claim to match with a separately published dedicated application-runtime class. Raff publishes explicit vCPU, memory, and ephemeral-disk ceilings from the $3 Micro tier through the $119.99 Scale tier. Scale-to-zero can reduce runtime cost for suitable services, but service cold-start behavior should be tested against the application's latency requirements. ### Platform generations Heroku is actively operating both Cedar and Fir platform generations. Fir Private Spaces are generally available, but some workflows and compatibility details differ from Cedar. Teams should evaluate generation-specific support for build, container, networking, compliance, and migration requirements rather than treating every Heroku runtime as identical. Raff presents a smaller runtime surface. That reduces platform-generation choice but also removes one category of migration decision for teams that do not need Heroku's enterprise runtime options. ### Persistent state and recovery Heroku dyno filesystems are ephemeral. Durable state normally belongs in Heroku Postgres, Key-Value Store, an add-on, or an external service. Application release rollback does not restore database state. Raff Apps supports persistent volumes plus first-party managed databases and object storage. Raff application revisions are also release controls rather than a substitute for database backups, object protection, or tested recovery procedures. ### Geography and operating evidence Heroku lists **12 runtime-region choices** across Common Runtime and Private Spaces, versus Raff Apps' **1 public region**. Heroku is the stronger choice when regional placement or enterprise network isolation is mandatory. Raff publishes a **99.9% platform SLA**. Its current Trustpilot profile is **4.5/5**, with G2 at **4.6/5**. Heroku has a much longer specialized PaaS operating history, which remains a genuine maturity advantage. ## When you should choose Heroku over Raff Choose Heroku when: - **Your application is already Heroku-native.** Procfiles, buildpacks, add-ons, Pipelines, Review Apps, and release workflows can make migration cost more important than runtime price. - **The add-on ecosystem matters.** Heroku's mature marketplace can reduce integration and procurement work. - **More regions are required.** Heroku publishes 2 Common Runtime and 10 Private Spaces regions versus Raff Apps' single public `us-east` region. - **Private Spaces are required.** Heroku provides isolated enterprise runtime environments with network controls and multiple regional choices. - **Dedicated app compute matters.** Performance dynos provide a documented dedicated-compute class. - **Salesforce alignment matters.** Heroku operates inside Salesforce's enterprise product and procurement environment. - **Pipelines and Review Apps are established team standards.** Replacing a mature delivery workflow can outweigh infrastructure savings. ## When you should choose Raff over Heroku Choose Raff Apps when: - **A lower published app ceiling matters.** Raff starts at $3/month and Standard is $16.99/month for 1 vCPU and 2 GB RAM. - **Docker Compose is the source of truth.** Raff can import a connected Compose stack rather than requiring each service to be remodeled around a Heroku application workflow. - **Public application transfer is material.** Raff Apps prices public egress at $0. - **Cost protection should be on by default.** Raff enables the Apps spend cap before a team has to react to an unexpected usage increase. - **First-party data services fit the architecture.** Raff offers managed PostgreSQL, MySQL, Valkey, ClickHouse, and Kafka alongside Apps. - **`us-east` is sufficient.** Heroku's regional advantage has less value when one eastern-U.S. region already meets latency and placement needs. - **Published resource allocations matter.** Raff exposes vCPU and RAM directly across its Apps tiers. [Raff Apps](/products/app-platform) is a live managed application platform. For adjacent app-platform decisions, compare [Railway and Raff](/learn/compare/raff-vs-railway), [Render and Raff](/learn/compare/render-alternative), and [DigitalOcean App Platform and Raff](/learn/compare/digitalocean-app-platform-alternative). ## Migrating from Heroku to Raff 1. **Inventory the Heroku application.** Record dyno types, Procfile processes, buildpacks, container settings, config vars, add-ons, databases, domains, Scheduler jobs, Pipelines, Review Apps, release-phase commands, regions, and external allowlists. 2. **Choose the Raff deployment path.** Use GitHub/buildpacks for conventional source deployments, a Dockerfile or existing image for packaged services, or Docker Compose when the application already has a multi-service definition. 3. **Map process types and environments.** Convert Heroku web processes to Raff web services, internal services to private services, workers to workers, scheduled tasks to cron jobs, and administrative commands to one-off jobs. Recreate development, preview, staging, and production behavior intentionally rather than assuming Pipeline semantics transfer automatically. 4. **Move configuration and integrations.** Recreate secrets and environment variables, then replace Heroku-specific add-ons, callback URLs, log drains, trusted IP assumptions, and platform APIs where required. **Gotcha:** an add-on can look like a simple environment variable while hiding provider-specific networking or lifecycle behavior. 5. **Move persistent state.** Export databases with engine-native tools and move uploaded files or other durable data to persistent volumes, managed databases, or object storage. **Gotcha:** the Heroku dyno filesystem is ephemeral and should never be treated as migration source-of-truth storage. 6. **Verify and cut over.** Test builds, health checks, workers, cron jobs, previews, database connectivity, restore procedures, and external integrations on a temporary hostname. Lower DNS TTL to **300 seconds**, perform the final data sync, switch DNS and callbacks, monitor production, and retain Heroku until the rollback window closes. The most difficult part of a Heroku migration is usually not application source code. Add-ons, buildpack assumptions, Pipeline behavior, Review Apps, scheduled work, networking, and durable data require the most deliberate mapping. Use the [App Platform Migration Checklist](/learn/guides/app-platform-migration-checklist) to verify service mapping, add-on replacements, data restoration, cutover, and rollback. ## About Heroku [Heroku](https://www.heroku.com/) is a Salesforce cloud application platform that runs applications in managed dynos and supports buildpacks, container workflows, Pipelines, Review Apps, managed data products, add-ons, Common Runtime regions, and enterprise Private Spaces. Heroku currently operates both Cedar and Fir platform generations, with Fir Private Spaces generally available. Heroku pricing, runtime, region, Pipeline, and bandwidth claims in this comparison were rechecked against Heroku's official pricing and Dev Center documentation on August 17, 2026. ## Conclusion: Heroku or Raff? The Heroku-versus-Raff decision resolves across four measured axes: cost model, delivery ecosystem, geography/runtime choice, and deployment portability. - **Cost model:** Raff Apps starts at **$3/month** with fixed service ceilings and $0 public egress; Heroku starts at **$5 Eco** or **$7 Basic** and bills active dynos by wall-clock runtime outside the Eco pool. - **Delivery ecosystem:** Heroku has mature Pipelines, Review Apps, add-ons, and Salesforce enterprise integration; Raff provides a smaller first-party cloud surface with previews and immutable revisions. - **Geography and runtime choice:** Heroku publishes **12 runtime-region choices** across Common Runtime and Private Spaces and operates Cedar plus Fir; Raff Apps currently exposes one public `us-east` region. - **Deployment portability:** Raff supports full Docker Compose import along with source and container paths; Heroku is strongest when the application already follows Heroku process, buildpack, and add-on conventions. Choose Heroku when regional choice, Private Spaces, dedicated Performance dynos, add-on depth, Pipelines, or Salesforce alignment are hard requirements. Choose Raff when `us-east` is sufficient and fixed service ceilings, $0 public egress, Compose portability, first-party managed data, and default spend protection make the application easier to budget and operate. Raff publishes a **99.9% platform SLA**. --- ### Render Alternative 2026: Pricing, Performance & Features URL: https://rafftechnologies.com/learn/compare/render-alternative Description: Render pricing includes a $7 0.5 CPU / 512 MB web-service tier and $25 1 CPU / 2 GB tier. Compare compute, workspace costs, bandwidth, regions, and Raff Apps. Raff Apps is a Render alternative for teams that prioritize lower published production tiers, $0 public egress, Docker Compose import, and a spend cap enabled by default. Render is stronger for five-region deployment, a $0 evaluation tier, Blueprints, Pro autoscaling, full-stack preview environments, and its broader managed PaaS workflow. Render can be cheaper for a prototype that stays on its free tier, while Raff becomes easier to forecast for always-on services and bandwidth-heavy applications. Choose Render when region choice and its mature PaaS workflow are decisive; choose Raff when predictable application cost and portability matter more. Raff Apps, the managed application platform from Raff Technologies, and Render both remove routine VM administration from web services, workers, scheduled jobs, and containerized applications. Raff starts at $3/month for 0.25 vCPU and 512 MB and charges $0 for public app egress. Render offers a free 0.1 CPU / 512 MB web-service tier, a $7 Starter service, and a $25 Standard service, while current workspace plans are Hobby $0, Pro $25 flat, Scale $499 flat, and Enterprise custom. The right choice depends on region, traffic, deployment workflow, and how much platform-specific behavior the application uses. ## Render vs Raff: which is right for you? Render is the safer default when an application needs geographic choice, established Blueprint workflows, or Pro-level collaboration and scaling features. Raff is the clearer alternative when one `us-east` region fits and the team values published monthly ceilings, $0 public egress, and a direct path between Apps, managed databases, object storage, VMs, and Kubernetes. | Decision factor | Choose Raff Apps | Choose Render | |---|---|---| | Entry path | You want a paid service from $3/month with explicit resources | You want a $0 web-service evaluation tier | | Always-on compute | You want 0.5 vCPU / 1 GB at $6.99 or 1 vCPU / 2 GB at $16.99 | You want Starter at $7 or Standard at $25 | | Public transfer | You want app egress priced at $0 | Your included workspace bandwidth covers usage or $0.15/GB overage is acceptable | | Deployment portability | Dockerfile, buildpacks, images, and full Docker Compose import matter | Git workflows, Docker, Blueprints, and Terraform fit the team | | Managed data | You want first-party PostgreSQL, MySQL, Valkey, ClickHouse, or Kafka alongside the app | You want Render Postgres and Render Key Value or will self-manage another datastore | | Geography | One public `us-east` region fits | You need Oregon, Ohio, Virginia, Frankfurt, or Singapore | | Team workflow | No workspace fee and a default spend cap matter | Pro autoscaling, audit logs, environment isolation, and full-stack previews matter | Our product decision at Raff was to put cost boundaries in place before an application scales: per-second compute has a published monthly ceiling, public egress is $0, and the spend cap starts enabled. That is useful for small teams because cost control does not depend on noticing a traffic spike after the invoice is already growing. For the broader architecture decision, read [Cloud VM vs App Platform: What Startups Should Know](/learn/guides/cloud-vm-vs-app-platform-startups). ## Render overview [Render](https://render.com/) is a managed application platform for deploying code as web services, static sites, private services, background workers, cron jobs, and Workflows, with managed Postgres and Key Value datastores alongside application services. Render supports Git-based deploys, Docker images, native runtimes, custom domains with managed TLS, health checks, zero-downtime deploys for eligible stateless services, persistent disks, Blueprints, Terraform, service previews, logs, metrics, and horizontal scaling. Manual scaling is available across workspaces, while autoscaling requires Pro or higher and supports up to 100 instances. Current web-service compute shapes include Free at 0.1 CPU / 512 MB, Starter at 0.5 CPU / 512 MB, Standard at 1 CPU / 2 GB, and Pro at 2 CPU / 4 GB, with larger service shapes available. Render's current public material verifies Starter at $7/month and Standard at $25/month for always-on services. Render introduced its current workspace plans on April 23, 2026. Hobby is $0, Pro is $25/month flat with unlimited team members, Scale is $499/month flat, and Enterprise is custom. Pro adds features such as autoscaling, audit logs, environment isolation, compliance-report access, and full-stack preview environments; Scale adds broader organization and compliance controls. Render's strongest advantages are geographic choice, a free evaluation path, mature declarative deployment workflows, managed previews, horizontal autoscaling, and an established application-platform operating model. Its company page reports $258 million raised. ## Raff overview [Raff Apps](/products/app-platform) deploys source code and containers without requiring teams to administer the underlying operating system. It supports GitHub push-to-deploy, Dockerfiles, existing container images, automatic buildpacks, full Docker Compose import, immutable revisions, one-click rollback, persistent volumes, and pull-request preview environments. Raff Apps currently provides five application service patterns: public web services, private services, background workers, timezone-aware cron jobs, and one-off jobs. Services can bind directly to Raff managed databases and object storage over private connectivity. Current Raff Apps compute tiers are: | Tier | vCPU | RAM | Ephemeral disk | Monthly ceiling | |---|---:|---:|---:|---:| | Micro | 0.25 | 512 MB | 2 GB | $3.00 | | Starter | 0.5 | 1 GB | 5 GB | $6.99 | | Standard | 1 | 2 GB | 10 GB | $16.99 | | Pro | 2 | 4 GB | 20 GB | $27.99 | | Pro Max | 4 | 8 GB | 40 GB | $61.99 | | Scale | 8 | 16 GB | 80 GB | $119.99 | Compute is billed per second against the published monthly ceiling. Raff Apps charges $0 for public egress and $0 per team seat, and the spend cap is enabled by default. Services can scale to zero, so an intermittently used service can finish below its monthly ceiling. Raff publishes a **99.9% platform SLA**. Raff Technologies was verified at **4.5/5** on August 16, 2026, and G2 is 4.6/5. Raff is newer and geographically narrower than Render; its value is a compact application-and-infrastructure stack with explicit cost boundaries. ## Render pricing vs Raff pricing Render and Raff both separate application compute from attached data services, but the cost structure differs. Raff publishes per-instance monthly ceilings and charges $0 for app egress and team seats. Render combines workspace-plan fees, service compute, and usage-based items such as outbound bandwidth, persistent disks, extra build minutes, and extra custom domains. Current Render workspace pricing is: - **Hobby:** $0/month, one team member - **Pro:** $25/month flat, unlimited team members - **Scale:** $499/month flat, unlimited team members - **Enterprise:** custom Current Render service pricing verified in official Render material includes **Starter at $7/month for 0.5 CPU / 512 MB** and **Standard at $25/month for 1 CPU / 2 GB**. Free web services use 0.1 CPU / 512 MB, spin down after 15 minutes of inactivity, and are designed for evaluation rather than production. The closest verified buying positions are: | Buying position | Raff Apps | Render | Decision signal | |---|---:|---:|---| | Evaluation / hobby | Micro $3 — 0.25 vCPU / 512 MB | Free $0 — 0.1 CPU / 512 MB | Render wins when $0 evaluation is the priority | | Small always-on service | Starter $6.99 — 0.5 vCPU / 1 GB | Starter $7 — 0.5 CPU / 512 MB | Similar price; Raff publishes twice the RAM | | Standard service | Standard $16.99 — 1 vCPU / 2 GB | Standard $25 — 1 CPU / 2 GB | Raff is $8.01 lower for the published shape | | Pro workspace + Standard service | $16.99 service; $0 workspace fee | $25 Pro workspace + $25 Standard service = $50 | Features differ; Render Pro adds team and platform capabilities | | 5 TB public outbound on a Pro workspace | $0 app-egress line; compute separate | About $764.25 bandwidth overage + $25 workspace; compute separate | Transfer becomes a material Render line item | **Comparison class:** these are price-and-resource planning positions, not performance-equivalent benchmarks. CPU labels, host hardware, scheduling, build systems, networking, and storage paths differ, so the table does not prove equal throughput or latency. ### Additional Render billing lines Render bills persistent disks at $0.25/GB-month and Postgres storage at $0.30/GB-month. New workspace plans include 5 GB of outbound bandwidth on Hobby, 25 GB on Pro, and 1 TB on Scale, then charge $0.15/GB. Extra custom domains are $0.25/month each beyond the plan allowance, and additional standard build-pipeline usage is $5 per 1,000 minutes. These charges are not inherently disadvantages; Render exposes more workspace and platform controls than a simple compute-only comparison captures. The correct comparison is the full production stack, including database, storage, bandwidth, preview environments, and team plan. ### Automated backups and recovery Render persistent disks receive an automatic snapshot once every 24 hours, and snapshots remain available for at least seven days. Render explicitly warns against using disk-snapshot restore as the recovery method for a custom database such as MySQL or MongoDB; database-native backups should be maintained instead. Raff Apps persistent state should likewise be treated separately from disposable application compute. Managed databases provide database-specific backup workflows, and durable files can be placed in Raff Object Storage or persistent volumes according to the workload. Recovery should be tested independently of a successful application deploy. :::cta Deploy an App Now Deploy from GitHub, Docker, buildpacks, or Docker Compose with a spend cap enabled by default. ::: ## Bandwidth and transfer policy Raff Apps charges **$0 for public application egress**. Render measures outbound traffic sent from workspace services to destinations outside Render, applies a monthly allowance based on the workspace plan, and charges **$0.15/GB** above that allowance. Current included Render outbound bandwidth is **5 GB on Hobby, 25 GB on Pro, 1 TB on Scale, and custom on Enterprise**. Unused allowance does not roll over. For a production-oriented Render Pro workspace, using 1 TB = 1,024 GB and the 25 GB monthly allowance: | Monthly public outbound | Raff Apps egress | Render Pro bandwidth overage | |---:|---:|---:| | 1 TB | $0 | About $149.85 | | 5 TB | $0 | About $764.25 | | 10 TB | $0 | About $1,532.25 | | 50 TB | $0 | About $7,676.25 | These figures isolate the public-transfer line. Render's $25 Pro workspace fee and service compute are additional, while a Scale workspace includes 1 TB before overage but starts at $499/month. Private traffic inside a Render region follows different rules and should not be treated as public internet egress. For both platforms, keep internal service-to-database traffic private and move large durable files to object storage when that architecture fits. The bandwidth difference matters most for public APIs, downloads, media delivery, generated files, and other internet-heavy workloads. ## Feature comparison: Render vs Raff | Feature | Raff Apps | Render | |---|---|---| | Free web-service tier | No; Micro starts at $3 | Yes; 0.1 CPU / 512 MB with free-tier limits | | Paid Starter | $6.99 — 0.5 vCPU / 1 GB | $7 — 0.5 CPU / 512 MB | | Standard | $16.99 — 1 vCPU / 2 GB | $25 — 1 CPU / 2 GB | | Git deployment | GitHub | GitHub, GitLab, Bitbucket, public Git URLs | | Dockerfile / image deployment | Yes | Yes | | Full Docker Compose import | Yes | No native whole-stack Compose import documented; Blueprints are Render's declarative model | | Preview environments | Isolated pull-request stack previews | Full-stack preview environments require Pro+ | | Manual scaling | Yes | All workspaces, up to 100 instances | | Autoscaling | Platform capability | Pro+, up to 100 instances | | Managed PostgreSQL | Yes | Yes | | Managed MySQL | Yes | No first-party managed MySQL; custom MySQL can run on a persistent disk | | Redis-compatible managed service | Valkey | Render Key Value | | Managed object storage | Raff Object Storage | Use an external or self-managed object store | | Persistent disk / volume | Yes | Paid services; one service instance per disk | | Workflow orchestration | One-off jobs, cron, workers, Functions | Render Workflows beta for chained long-running tasks | | Public service regions | 1: `us-east` | 5: Oregon, Ohio, Virginia, Frankfurt, Singapore | | Workspace fee | $0 | Hobby $0, Pro $25, Scale $499 | | Seat fee | $0 | No per-seat fee on current Pro and Scale plans | | Public egress | $0 | Allowance by plan, then $0.15/GB | Render wins on region choice, Git-provider breadth, Blueprints/Terraform workflows, Pro autoscaling, Workflows, and mature workspace controls. Raff wins on lower verified Starter/Standard production pricing, $0 public egress, full Docker Compose import, first-party managed MySQL, and a default spend cap. ## Features and reliability: Raff vs Render This comparison includes **0 controlled Raff-vs-Render application benchmarks**, so it does not declare either platform faster. A credible test would require the same container, dependency versions, region assumptions, instance class, database path, request generator, concurrency, and repeated warm and cold runs. ### Deployment reliability Render performs zero-downtime deploys for eligible services without persistent disks. Health checks protect new releases: if a new version fails to become healthy, Render keeps the existing deployment serving traffic. Running instances that repeatedly fail health checks can be removed from routing and restarted automatically. Raff Apps uses immutable revisions, health-aware deployment workflows, one-click rollback, and a broader Raff platform covered by a 99.9% SLA. On either provider, application-level retries, external monitoring, database recovery, and tested rollback procedures still matter. ### Stateful-service trade-offs A Render persistent disk is attached to one service instance. A disk-backed service cannot scale horizontally to multiple instances, and attaching a disk disables the normal zero-downtime deployment path. Render's automatic daily disk snapshots provide a recovery option for files, but custom databases require database-native backup procedures. Raff persistent volumes also make an application stateful. For relational production data, managed databases are generally a cleaner boundary than placing the database inside the application service, because database backup and recovery can be managed independently from application revisions. ### Regional footprint Render offers **5 public service regions**: Oregon, Ohio, Virginia, Frankfurt, and Singapore. Existing Render services and databases cannot change region in place; a new resource must be created and configuration/data migrated. Raff Apps currently exposes **1 public region, `us-east`**. Render therefore has the clear advantage when geography, regional placement, or a European/Asian application location is mandatory. Raff is appropriate when the `us-east` location fits the user base and the cost model matters more than region choice. ### Operating trust Render's company page reports **$258 million raised**, and its documentation provides detailed operational guidance for health checks, maintenance, multi-instance availability, and backup testing. Raff publishes a **99.9% platform SLA**. These signals are different rather than directly equivalent. Render has the longer specialized PaaS track record; Raff provides a smaller platform with public SLA and review signals that can be checked independently. ## When you should choose Render over Raff Choose Render when: - **You need more region choice.** Render offers five service regions; Raff Apps currently exposes one public `us-east` region. - **You need a $0 evaluation path.** Render's free web service is useful for prototypes and testing, although it spins down after 15 minutes of inactivity. - **Blueprint and Git-provider workflows matter.** Keeping a mature `render.yaml` definition and direct GitLab or Bitbucket integration can be lower-risk than translating the deployment. - **Pro autoscaling is a requirement.** Render can scale eligible services automatically by CPU and/or memory, with up to 100 instances. - **Full-stack preview environments matter.** Render can create disposable copies of Blueprint-defined services and datastores for pull requests on Pro and higher. - **You need Render Workflows.** Its beta workflow product chains long-running distributed tasks within the Render platform. - **You need Scale-level organization controls.** Render's Scale plan adds SSO, SCIM, advanced RBAC, HIPAA-enabled workspaces, and multi-workspace management. Render is also the cheaper option when a prototype genuinely fits the free web-service limits and does not need always-on production behavior. ## When you should choose Raff over Render Choose Raff Apps when: - **Lower verified always-on tiers matter.** Raff Starter is $6.99 for 0.5 vCPU / 1 GB versus Render Starter at $7 for 0.5 CPU / 512 MB, and Raff Standard is $16.99 versus Render Standard at $25 for 1 CPU / 2 GB. - **Public egress is substantial.** Raff app egress is $0, while Render Pro includes 25 GB then charges $0.15/GB. - **Docker Compose is already the source of truth.** Raff can import a full Compose stack instead of translating each service into a provider-specific definition. - **First-party managed MySQL is required.** Raff provides managed MySQL alongside PostgreSQL, Valkey, ClickHouse, and Kafka. - **Cost protection should be automatic.** Raff enables a spend cap by default and does not add a workspace or seat fee. - **Scale-to-zero is useful.** Raff Apps can reduce idle-service runtime below the monthly ceiling. - **One provider should cover both PaaS and infrastructure.** Raff connects Apps with managed databases, object storage, VMs, private networking, Kubernetes, and Functions. For these deployment needs, review the [Raff Apps product and plans](/products/app-platform) before choosing between managed platform workflows. ## Migrating from Render to Raff 1. **Inventory the Render workspace.** Record every web service, private service, worker, cron job, Workflow, Postgres database, Key Value instance, persistent disk, environment group, custom domain, region, Blueprint, preview environment, and external allowlist. 2. **Map each service to Raff.** Move public web services to Raff web services, internal services to private services, background workers to workers, scheduled tasks to cron jobs, and suitable administrative commands to one-off jobs. **Gotcha:** Render Workflows do not map one-to-one to Raff Apps; preserve task dependencies, retries, and failure semantics explicitly. 3. **Choose the build path.** Connect the GitHub repository, deploy an existing container image, use a Dockerfile, let buildpacks detect the runtime, or import Docker Compose when several services already run together. **Gotcha:** Render Blueprints and Raff stack definitions are different configuration models. 4. **Move persistent state.** Export Postgres or Key Value data with engine-appropriate tools, move durable files from Render disks, and recreate storage or managed database targets on Raff. Do not use a disk snapshot as a substitute for a database-consistent export. 5. **Recreate configuration and test.** Add environment variables, secrets, private bindings, health checks, domains, scheduled-job timezones, storage mounts, webhook callbacks, and allowlists. Test on a temporary hostname and verify backup and restore procedures before cutover. 6. **Cut over with rollback.** Lower DNS TTL to **300 seconds** before the change, run the final state sync, update DNS and external callbacks, monitor production, and keep Render services available until the rollback window closes. Network identities, custom domains, OAuth callbacks, payment webhooks, SMTP allowlists, database allowlists, and preview-environment configuration can all change during migration. Treat the migration as a platform-behavior translation, not only a code copy. Use the [App Platform Migration Checklist](/learn/guides/app-platform-migration-checklist) to validate persistent state, secrets, domains, worker schedules, and rollback before cutover. ## About Render [Render](https://render.com/) is a managed application platform headquartered in San Francisco. It provides web and private services, workers, cron jobs, static sites, Workflows, Postgres, Key Value, persistent disks, Blueprints, Terraform support, preview environments, and scaling features. Render's current public company page reports $258 million raised, and its current workspace pricing uses Hobby, Pro, Scale, and Enterprise plans. ## Conclusion: Render or Raff? The Render-versus-Raff decision resolves across four measured axes: entry and compute cost, public bandwidth, platform workflow, and regional reach. - **Entry and compute:** Render offers a $0 evaluation tier; Raff Starter is $6.99 versus Render Starter at $7, and Raff Standard is $16.99 versus Render Standard at $25. - **Bandwidth:** Raff Apps charges $0 for public egress; Render Pro includes 25 GB and then charges $0.15/GB. - **Workflow:** Render wins on Blueprints, broader Git-provider support, Pro autoscaling, full-stack previews, and Workflows; Raff wins on full Docker Compose import and default spend controls. - **Regions:** Render offers five public service regions; Raff Apps currently exposes one public region, `us-east`. Choose Render when the free evaluation path, five-region placement, or its PaaS-native workflow is a requirement. Choose Raff when the application fits `us-east` and lower published production tiers, $0 public egress, Docker Compose portability, and automatic cost boundaries are the stronger decision factors. Raff publishes a **99.9% platform SLA**. For adjacent comparisons, review [Vercel alternatives](/learn/compare/vercel-alternative), [Netlify alternatives](/learn/compare/netlify-alternative), and [Railway comparison](/learn/compare/raff-vs-railway). --- ### Vercel Alternative 2026: Pricing, Performance & Features URL: https://rafftechnologies.com/learn/compare/vercel-alternative Description: Comparing Raff Apps with Vercel? Raff Apps starts at $3/mo with $0 public app egress. Vercel Pro starts at $20/mo and includes $20 usage credit plus Flat Rate CDN capacity. Raff Apps wins on fixed service resources, full Docker Compose import, long-running workers, private services, and $0 public application egress. Vercel wins on its global CDN, 20 compute-capable regions, Next.js-first workflow, preview deployments, and $0 Hobby plan for qualifying personal use. Choose Vercel when framework-native global frontend delivery is the requirement; choose Raff when the application is a portable container stack with always-on processes and explicit cost ceilings. Raff Apps starts at $3/month, while Vercel Pro is $20/month and currently includes one deploying seat, $20 of usage credit, and the baseline Flat Rate CDN tier (1 million CDN requests and 1 TB transfer capacity), with optional higher tiers. Vercel and Raff Apps solve different deployment problems even though both can ship web applications from source. Vercel combines a global delivery network with framework-aware builds and request-driven compute across 20 compute-capable regions. Raff Technologies positions Raff Apps around explicit service resources in one public `us-east` region, with a $3 entry tier, $0 public app egress, workers, cron jobs, private services, persistent volumes, and Docker Compose portability. The practical choice is therefore less about a single feature checklist and more about whether the production workload behaves like a globally delivered frontend or a connected set of application services. ## Vercel vs Raff: which is right for you? Use Vercel when the frontend platform itself is part of the application architecture. Use Raff when the application is better represented as services that should remain portable across source, containers, databases, storage, and private networking. | Decision factor | Choose Raff Apps | Choose Vercel | |---|---|---| | Primary workload | APIs, containers, workers, cron jobs, private services, and multi-service stacks | Next.js, framework frontends, static delivery, previews, and request-driven functions | | Entry path | Micro from $3/month with explicit resources | Hobby at $0 for qualifying personal/non-commercial use | | Commercial plan | Fixed service tier; no workspace or seat fee | Pro at $20/month with one deploying seat and usage allowances | | Public transfer | $0 application egress | Flat Rate CDN included on Pro: 1M CDN requests and 1 TB nominal capacity; extra tiers available | | Deployment portability | Dockerfile, image, buildpacks, and full Docker Compose import | Git/framework builds, CLI, hooks, API, and Vercel platform conventions | | Global delivery | Add an external CDN when required | 126 PoPs across 94 cities and 51 countries, with 20 compute-capable regions | | Data architecture | First-party managed databases, object storage, persistent volumes | Vercel Blob, Edge Config, and Marketplace data providers | At Raff, we made a deliberate product decision to make cost boundaries visible before a service receives production traffic: each app tier has a published monthly ceiling, public app egress is $0, and the spend cap starts enabled. That model is useful for small teams running several persistent processes because cost protection does not depend on reverse-engineering request, seat, transfer, and function meters after launch. For the broader platform decision, review [Cloud VM vs App Platform: What Startups Should Know](/learn/guides/cloud-vm-vs-app-platform-startups). ## Vercel overview Vercel is a managed developer and AI cloud platform with deep Next.js roots. It connects to Git providers, builds framework projects, creates preview and production deployments, serves content through a global CDN, and runs server-side code through Vercel Functions and Fluid Compute. Its current public plans are: - **Hobby — $0/month:** intended for personal and non-commercial use. - **Pro — $20/month:** includes one deploying seat, $20 monthly infrastructure usage credit, and the baseline Flat Rate CDN tier with 1 million CDN requests and 1 TB of monthly capacity. Higher CDN tiers are optional; other infrastructure meters can still incur charges. - **Enterprise — custom:** adds enterprise controls, multi-region compute and failover options, and a 99.99% SLA. Vercel's global network currently documents **126 points of presence across 94 cities and 51 countries**, with **20 compute-capable regions**. That footprint is a genuine advantage for globally distributed frontends because caching, routing, preview deployments, and framework-specific delivery are part of the platform rather than a separately assembled CDN layer. Vercel Functions use Fluid Compute rather than fixed application-server tiers. Current published usage rates start at **$0.128 per active CPU-hour**, **$0.0106 per provisioned GB-hour**, and **$0.60 per million invocations** after the applicable included usage. Functions automatically scale down when no requests are active. Vercel also provides Blob storage, Edge Config, image optimization, Web Analytics, Speed Insights, Observability, WAF and DDoS controls, Cron Jobs, and Marketplace integrations for third-party databases and data services. In September 2025, Vercel announced a $300 million Series F at a $9.3 billion valuation, which is a meaningful public scale and funding signal. ## Raff overview [Raff Apps](/products/app-platform) deploys source code and containers without requiring a team to administer the operating system. It supports GitHub push-to-deploy, Dockerfiles, existing container images, automatic buildpacks, full Docker Compose imports, immutable revisions, one-click rollback, persistent volumes, pull-request previews, and scale-to-zero behavior. Raff Apps supports public web services, private services, background workers, timezone-aware cron jobs, and one-off jobs. Applications can connect to managed PostgreSQL, MySQL, Valkey, ClickHouse, and Kafka, as well as object storage, VMs, private networking, Kubernetes, and Functions. Current Raff Apps tiers are: | Tier | vCPU | RAM | Ephemeral disk | Monthly ceiling | |---|---:|---:|---:|---:| | Micro | 0.25 | 512 MB | 2 GB | $3.00 | | Starter | 0.5 | 1 GB | 5 GB | $6.99 | | Standard | 1 | 2 GB | 10 GB | $16.99 | | Pro | 2 | 4 GB | 20 GB | $27.99 | | Pro Max | 4 | 8 GB | 40 GB | $61.99 | | Scale | 8 | 16 GB | 80 GB | $119.99 | Compute is billed per second against the published monthly ceiling. Public application egress and team seats are priced at $0, and the spend cap is enabled by default. Raff publishes a **99.9% platform SLA**. Raff Technologies was verified at **4.5/5** on August 16, 2026, and G2 is 4.6/5. Raff is geographically narrower than Vercel; its strength is the explicit service model and the ability to keep app, database, storage, VM, and Kubernetes workloads under one cloud account. ## Vercel pricing vs Raff pricing Vercel and Raff expose different units of cost. Raff prices long-running application services by fixed vCPU/RAM tiers with per-second proration. Vercel Pro combines a $20 platform fee with a $20 infrastructure usage credit, one included deploying seat, and the baseline Flat Rate CDN tier (1 million CDN requests and 1 TB data transfer capacity). Additional deploying seats, non-CDN infrastructure meters, or upgraded CDN tiers can increase the bill. The closest useful buying positions are: | Buying position | Raff Apps | Vercel | Decision signal | |---|---:|---:|---| | Personal / hobby | Micro $3 — 0.25 vCPU / 512 MB | Hobby $0 for qualifying personal/non-commercial use | Vercel wins when a qualifying $0 frontend plan is enough | | Small commercial app | Starter $6.99 — 0.5 vCPU / 1 GB | Pro $20 platform fee with one deploying seat and usage allowances | Raff publishes fixed service resources; Vercel bundles frontend-platform allowances | | Standard backend | Standard $16.99 — 1 vCPU / 2 GB | No direct fixed-instance equivalent; Functions use CPU, memory, invocation, and transfer meters | Compare workload behavior rather than CPU labels | | Five deploying developers | $0 additional seat fee | $100/month in Pro platform/paid-seat fees before additional infrastructure usage | Vercel collaboration cost becomes material as deploying members increase | | Sustained high CDN demand | $0 app-egress line; compute separate | Optional $20/mo Flat Rate CDN 10M tier supports 10M requests and 50 TB capacity; Pro fee and non-CDN usage separate | Compare workload and CDN tier, not old per-GB overage arithmetic | **Comparison class:** these are buying positions, not performance-equivalent instances. Vercel Functions and Raff application services have different execution, scaling, caching, host, and networking models, so matching a price or CPU label does not establish equal throughput or latency. ### Flat Rate CDN capacity and budgeting Vercel's Flat Rate CDN became generally available for Pro teams in September 2026. For new Pro teams it is enabled by default; existing teams can opt in. The included capacity is measured per team, not per project. Temporary spikes beyond the chosen capacity do not automatically cause CDN overage charges under the documented spike-protection and fair-use rules; persistent high usage may require a higher tier. | Flat Rate CDN tier | Monthly CDN requests | Monthly data-transfer capacity | Extra CDN fee | |---|---:|---:|---:| | Included with Pro | 1 million | 1 TB | $0 beyond Pro subscription | | Flat Rate CDN 10M | 10 million | 50 TB | $20/month | | Flat Rate CDN 50M | 50 million | 50 TB | $100/month | | Flat Rate CDN 150M | 150 million | 50 TB | $300/month | The **$20/month Pro platform subscription** includes **$20 in infrastructure usage credit**, which is separate from the CDN capacity tier. Pro still has billable compute, storage, build, collaboration and other eligible meters according to the selected configuration. Teams using alternative on-demand CDN billing should check the corresponding current rates rather than assume the flat-rate model applies. Official source: [Vercel Flat Rate CDN availability and tiers](https://vercel.com/changelog/flat-rate-cdn-is-now-ga-for-pro-teams). ### Automated backups Vercel's security documentation says Vercel platform customer data is backed up every **2 hours** and each backup is retained for **30 days**. That platform-resiliency statement should not be interpreted as a backup promise for every application datastore. Vercel Blob currently has **no native backup system**, and database backup, point-in-time recovery, and retention depend on the Marketplace database provider selected by the customer. Raff Apps likewise separates disposable application compute from durable application data. Ephemeral app disk is not a backup. Production state should live in managed databases, object storage, or persistent volumes, and backup/restore behavior should be verified for the selected Raff data service before launch. ### Other billable resources Vercel Pro includes one deploying seat; additional paid Owner or Member seats are **$20/month each**, while Viewer seats are free. Blob storage currently includes 1 GB then starts at $0.023/GB-month, with separate operation and data-transfer meters. Vercel's default on-demand budget for new teams is $200 per billing cycle and can be customized, with alerts and an optional hard pause at 100%. Raff does not add an Apps workspace or seat fee. Its main variable costs come from the selected app tiers and any separately attached managed database, storage, or infrastructure products. :::cta Deploy an App Now Deploy containers, workers, cron jobs, and Docker Compose stacks with explicit monthly ceilings. ::: ## Bandwidth and transfer policy Raff Apps charges **$0 for public application egress**. Vercel's default Pro Flat Rate CDN includes **1 million CDN Requests** (the metric previously called Edge Requests) and **1 TB of transfer capacity** per team per month. This is a **CDN capacity tier**, not a promise of 10 million free requests. Additional CDN capacity tiers are available for a fixed monthly fee, and temporary traffic spikes are covered by spike protection subject to fair-use terms. Vercel's global network combines CDN delivery and framework-aware routing, while origin compute, Blob storage, team roles, and certain other products have their own cost models. Moving a globally cached web frontend to a single-region app service is not a direct bandwidth-equivalent replacement. For high-transfer web services or APIs, compare the complete monthly bill: Raff's app compute and $0 public egress versus Vercel's Pro subscription, CDN tier choice, non-CDN usage and regional requirements. ## Feature comparison: Vercel vs Raff | Feature | Raff Apps | Vercel | |---|---|---| | Primary deployment model | Long-running services and containers | Framework deployments and request-driven Functions | | Git deployment | GitHub | GitHub, GitLab, Bitbucket, Azure DevOps, CLI, hooks, API | | Dockerfile / existing image | Yes | Not the primary general-service model | | Full Docker Compose import | Yes | No native whole-stack Compose import | | Preview environments | Pull-request previews | Automatic deployment previews with framework-aware workflow | | Always-on worker | Yes | Not the primary Functions execution model | | Private service | Yes | Private backend design depends on platform/networking architecture | | Cron jobs | Timezone-aware app jobs | Cron Jobs invoke Vercel Functions | | Global CDN | External CDN can be added | Built in across 126 PoPs | | Compute regions | 1 public region: `us-east` | 20 compute-capable regions | | Persistent mounted volume | Yes | No general mounted persistent filesystem for Functions | | Managed PostgreSQL | First-party Raff managed database | Marketplace provider | | Managed MySQL | First-party Raff managed database | Marketplace/external provider | | Object storage | Raff Object Storage | Vercel Blob | | Team seat fee | $0 | One deploying seat included on Pro; additional paid members $20/month | | Public app transfer | $0 | Flat Rate CDN on Pro: 1M requests and 1 TB nominal capacity; optional higher tiers | | Rollback | Immutable revisions and one-click rollback | Instant rollback to eligible prior production deployments | Vercel wins on global frontend delivery, framework integration, Git-provider breadth, preview collaboration, distributed function regions, and frontend observability. Raff wins on portable containers, Docker Compose, long-running workers, private services, fixed app resources, first-party managed MySQL, persistent volumes, and $0 public app egress. ## Features and reliability: Raff vs Vercel This comparison includes **0 controlled Raff-versus-Vercel application benchmarks**, so it does not declare either platform faster. Vercel's request-driven Functions and global CDN are not performance-equivalent to a continuously available Raff container, and a credible test must hold application code, cache policy, data location, request mix, and concurrency constant. ### Global delivery Vercel's **126 PoPs across 94 cities and 51 countries** and **20 compute-capable regions** give it the stronger default architecture for globally distributed frontends. Every request passes through Vercel's global CDN, and teams can place Functions in selected regions according to application needs. Raff Apps currently exposes one public `us-east` region. Teams can place a separate CDN in front of an application where necessary, but that is an additional architectural component. For a cache-heavy international frontend, Vercel therefore has a genuine out-of-the-box advantage. ### Compute model Raff exposes explicit vCPU and RAM tiers for processes that may remain available continuously. This maps naturally to APIs, WebSocket-oriented services, workers, private services, and multi-container applications. Vercel Functions scale around requests and can scale down to zero. Fluid Compute bills active CPU, provisioned memory, and invocations, which can be efficient for bursty or I/O-heavy workloads. It is less directly comparable to an always-on process because cost and concurrency depend on request behavior rather than a fixed instance shape. ### Rollback and data recovery Both platforms provide deployment rollback. Vercel Pro and Enterprise can roll back to eligible prior production deployments retained by the platform, while Raff uses immutable revisions and one-click rollback for application releases. Deployment rollback is not the same as data recovery. Vercel Blob has no native backup feature, and Marketplace database recovery depends on the chosen provider. Raff also separates application revision rollback from database, object-storage, and persistent-volume recovery. Production teams should test both code rollback and state restoration independently. ### Operating trust Vercel announced a **$300 million Series F at a $9.3 billion valuation** in September 2025 and publishes a **99.99% Enterprise SLA**. Raff publishes a **99.9% platform SLA**. Those signals measure different things. Vercel has the larger global frontend-platform footprint and funding scale; Raff provides a smaller cloud with public customer, VM, SLA, and review signals that can be checked independently. ## When you should choose Vercel over Raff Choose Vercel when: - **Next.js and framework-native delivery are central.** Vercel integrates builds, routing, caching, previews, image optimization, and deployment behavior around frontend frameworks. - **Global delivery is mandatory.** Vercel documents 126 PoPs and 20 compute-capable regions; Raff Apps currently exposes one `us-east` region. - **A qualifying $0 personal plan matters.** Vercel Hobby costs $0 for personal/non-commercial use, while Raff Apps starts at $3/month. - **Preview collaboration is part of development.** Vercel generates deployment URLs around branches and commits and integrates them deeply into frontend workflows. - **Request-driven compute fits the workload.** Fluid Compute scales down to zero and bills CPU, memory, and invocations rather than a continuously running service tier. - **Enterprise multi-region failover is required.** Vercel Enterprise adds multi-region compute/failover options and a 99.99% SLA. Vercel is also the safer choice when replacing its framework-specific caching, Incremental Static Regeneration, image delivery, or preview behavior would create more engineering work than the migration saves. ## When you should choose Raff over Vercel Choose Raff Apps when: - **The application is container-first.** Raff supports Dockerfiles, existing images, buildpacks, and full Docker Compose imports. - **Long-running processes are required.** Web services, workers, private services, cron jobs, and one-off jobs map directly to persistent service types. - **Compute cost should be explicit.** Raff Standard is $16.99 for 1 vCPU / 2 GB and Raff Pro is $27.99 for 2 vCPU / 4 GB, each with a published monthly ceiling. - **Public egress is substantial.** Raff app egress is $0; Vercel Pro includes 1 TB of Flat Rate CDN capacity and may require a higher fixed-rate CDN tier for sustained higher traffic. - **First-party managed MySQL is required.** Raff provides managed MySQL alongside PostgreSQL, Valkey, ClickHouse, and Kafka. - **Seat growth should not change the bill.** Raff Apps charges $0 per team seat; Vercel charges $20/month for each additional paid Pro Owner or Member. - **Docker Compose portability matters.** A multi-service development stack can be imported without translating every component into frontend-platform-specific products. For containerized web services and workers with explicit resource ceilings, review [Raff Apps](/products/app-platform) and compare the complete workload instead of equating a CDN plan with a VM. ## Migrating from Vercel to Raff 1. **Inventory the Vercel project.** Record frameworks, build commands, environment variables, domains, rewrites, redirects, Functions, Cron Jobs, Blob stores, Edge Config, Marketplace databases, preview behavior, image optimization, and cache rules. 2. **Choose the Raff package.** Use buildpacks for a conventional source deployment, a Dockerfile for reproducible packaging, an existing container image for a prebuilt artifact, or Docker Compose for a multi-service stack. **Gotcha:** Vercel project configuration does not map one-to-one to a container or Compose definition. 3. **Map execution units.** Convert HTTP Functions into application routes, asynchronous consumers into workers, schedules into Raff cron jobs, and internal APIs into private services where appropriate. **Gotcha:** Function code that assumes ephemeral request execution may need explicit connection pooling, graceful shutdown, and concurrency handling. 4. **Move persistent state.** Copy Vercel Blob objects to Raff Object Storage, migrate Marketplace databases with provider-native export/import tools, and move Edge Config values into application configuration or a suitable datastore. Verify backup and restore before the final sync. 5. **Rebuild delivery behavior.** Recreate redirects, headers, image delivery, cache rules, and an external CDN where global edge delivery remains necessary. Test a temporary hostname from the regions that matter to users. 6. **Cut over with rollback.** Lower DNS TTL to **300 seconds**, perform the final state sync, update DNS, OAuth callbacks, webhooks, and allowlists, monitor production, and keep the Vercel deployment available until the rollback window closes. Stateless application code is usually the easiest part to move. Stateful data, framework-specific caching, preview environments, edge behavior, and public URLs create most migration risk, so each should have a tested rollback path before DNS changes. Use the [App Platform Migration Checklist](/learn/guides/app-platform-migration-checklist) to plan service configuration, data export, CDN changes, health checks, DNS, and rollback. ## About Vercel [Vercel](https://vercel.com/) is operated by Vercel Inc., a developer and AI cloud company founded in 2015 and headquartered in San Francisco. It develops Next.js and provides Git-based deployments, preview environments, a global CDN, Vercel Functions, Fluid Compute, Blob storage, Edge Config, observability, image optimization, and Marketplace integrations for application data services. ## Conclusion: Vercel or Raff? The Vercel-versus-Raff decision resolves across four measured axes: cost model, application process model, global delivery, and data portability. - **Cost model:** Vercel Hobby can be $0 and Pro is $20 with allowances; Raff Apps starts at $3 and publishes fixed monthly service ceilings with $0 team seats. - **Application model:** Vercel centers framework deployments and request-driven Functions; Raff centers containers, workers, private services, cron jobs, and Docker Compose stacks. - **Global delivery:** Vercel provides 126 PoPs and 20 compute-capable regions; Raff Apps currently exposes one public `us-east` region and can use an external CDN when required. - **Data portability:** Vercel combines Blob, Edge Config, and Marketplace data providers; Raff connects Apps to first-party managed databases, object storage, persistent volumes, VMs, and Kubernetes. Choose Vercel when globally distributed frontend delivery and framework-native platform behavior are requirements. Choose Raff when the application is a portable service stack and explicit compute, seat, transfer, and data-service boundaries are more important than a built-in global frontend network. Raff publishes a **99.9% platform SLA**. For adjacent comparisons, review [Render Alternative 2026](/learn/compare/render-alternative), [Netlify Alternative 2026](/learn/compare/netlify-alternative), and [Railway comparison](/learn/compare/raff-vs-railway). --- ### Fly.io Alternative 2026: Pricing, Performance & Features URL: https://rafftechnologies.com/learn/compare/flyio-alternative Description: Considering Fly.io? Raff Apps starts at $3/mo with $0 public egress; Fly.io spans 18 regions with pay-as-you-go Machines. Raff Apps wins on fixed monthly ceilings, $0 public egress, full Docker Compose import, first-party managed data services, and a default spend cap. Fly.io wins on 18 global regions, Anycast routing, Machine-level control, flexible autoscaling, and region-specific pay-as-you-go compute that can be cheaper at some resource sizes. Choose Fly.io when multi-region placement and infrastructure control are requirements; choose Raff when `us-east`, predictable app costs, Compose portability, and a more managed workflow fit the workload. Raff Pro is $27.99/month for 2 vCPU and 4 GB; Fly.io's total price for a two-shared-CPU/4 GB Machine varies with region and the current CPU/RAM schedule before separately billed storage, egress, IP addresses, or support. Among Fly.io alternatives, Raff takes a deliberately different approach to application operations. Fly.io exposes 18 regions, Fly Machines, regional volumes, Anycast networking, and separate metered resources; Raff packages managed services into tiers from $3/month with $0 public app egress and visible monthly ceilings. Fly.io's short trial includes 2 total Machine hours or 7 days, while Raff's paid Micro tier is designed to remain deployed. The decision is less about which platform has more knobs and more about whether the team needs global infrastructure control or a tighter managed-service boundary. ## Fly.io vs Raff: which is right for you? The practical choice is global infrastructure control versus a managed application platform with tighter cost boundaries. | Decision factor | Choose Raff Apps | Choose Fly.io | |---|---|---| | Cost model | You want a published monthly ceiling per service | You want regional pay-as-you-go Machine pricing | | Entry service | You want 0.25 vCPU / 512 MB for $3/month | You want a 1 shared CPU / 512 MB Machine billed at the current region-specific rate | | Geography | One public `us-east` region fits | You need placement across 18 regions | | Bandwidth | Public application egress should cost $0 | $0.02–$0.12/GB internet egress is acceptable | | Deployment | GitHub, buildpacks, Dockerfile, image, or full Compose import fits | `flyctl`, `fly.toml`, Machines, and APIs fit | | Persistent state | App volumes plus 5 managed data engines fit | Regional Fly Volumes and Managed Postgres fit | | Scaling | Managed service tiers and scale-to-zero fit | Autostop/autostart and programmable metrics scaling are required | Fly.io is stronger when region placement, Anycast routing, and Machine-level behavior are part of the application architecture. Raff is stronger when the workload fits `us-east` and the team wants fewer infrastructure decisions, predictable service ceilings, and $0 public app egress. ## Fly.io overview Fly.io is a developer-focused public cloud built around Fly Machines. It turns application containers into hardware-isolated virtual machines and exposes them through `flyctl`, `fly.toml`, the Machines API, private networking, volumes, and a global Anycast network. Fly.io currently lists **18 application regions** across North America, Europe, Asia-Pacific, South America, and Africa. Machines and Fly Volumes are tied to the region where they are created, while Fly Proxy and Anycast networking can route traffic across globally distributed application instances. Fly.io supports two documented autoscaling models. **Autostop/autostart** starts or stops an existing pool of Machines based on traffic; it does not create new Machines. **Metrics-based autoscaling** can create, delete, start, or stop Machines based on a metric the team defines, with the reconciliation loop running every **15 seconds by default**. Stopped or suspended Machines do not incur CPU and RAM charges, but stopped Machine root filesystems and provisioned volumes can remain billable. This can reduce compute cost for sporadic workloads while increasing the importance of understanding Machine state, regional capacity, storage, and minimum-running settings. Fly.io's current free trial includes **2 total Machine hours or 7 days**, whichever comes first, with up to 10 Machines, 20 GB of volume storage, 2 vCPUs per Machine, and 4 GB of memory per Machine. It is an evaluation period, not a permanent free production tier. ## Raff overview [Raff Apps](/products/app-platform) is Raff's managed application platform for deploying source code and containers without administering the underlying operating system. It supports GitHub push-to-deploy, Dockerfiles, existing images, buildpacks, and full Docker Compose imports. Raff Apps supports public web services, private services, long-running workers, timezone-aware cron jobs, one-off jobs, pull-request preview environments, persistent application volumes, immutable revisions, one-click rollback, and scale-to-zero behavior. Applications can connect to Raff Managed Databases for PostgreSQL, MySQL, Valkey, ClickHouse, and Kafka, plus object storage, VMs, private networking, Kubernetes, and Functions. Current service tiers are: | Tier | vCPU | RAM | Ephemeral disk | Monthly ceiling | |---|---:|---:|---:|---:| | Micro | 0.25 | 512 MB | 2 GB | $3.00 | | Starter | 0.5 | 1 GB | 5 GB | $6.99 | | Standard | 1 | 2 GB | 10 GB | $16.99 | | Pro | 2 | 4 GB | 20 GB | $27.99 | | Pro Max | 4 | 8 GB | 40 GB | $61.99 | | Scale | 8 | 16 GB | 80 GB | $119.99 | Runtime is billed per second against each published monthly ceiling. Public application egress and Apps team seats cost $0, and the spend cap is enabled by default. From Raff's side, the pricing rule we use is simple: cost protection should exist before the first production traffic spike. That is why the service ceiling and default spend cap are part of the product model rather than optional cost controls a small team has to configure after deployment. Raff currently exposes one public Apps region, `us-east`. Raff publishes a **99.9% platform SLA**. On August 16, 2026, Raff was rated **4.5/5**, with G2 at 4.6/5. ## Fly.io pricing vs Raff pricing Fly.io and Raff both meter runtime at a fine-grained level, but the pricing structures answer different questions. Raff asks the team to choose a service tier with a published monthly ceiling. Fly.io prices a running Machine from a regional CPU preset plus additional RAM, then bills storage, snapshots, networking, databases, IP addresses, certificates, and support separately when applicable. Its October 1, 2026 pricing update lists additional RAM at **$6/GB-month**, while CPU preset prices remain region-dependent; use the [current official price matrix](https://fly.io/pricing-update/) for a specific region and Machine shape. | Buying position | Raff Apps | Fly.io | Decision signal | |---|---:|---:|---| | 512 MB service | Micro — 0.25 vCPU / 512 MB / $3 | shared-cpu-1x / 512 MB — check current regional CPU/RAM rate | Fly includes more listed shared CPU; Raff has one ceiling | | 1 GB service | Starter — 0.5 vCPU / 1 GB / $6.99 | shared-cpu-1x / 1 GB — CPU preset plus RAM priced by region | Fly may be lower or higher by region | | 2 GB service | Standard — 1 vCPU / 2 GB / $16.99 | shared-cpu-1x / 2 GB — CPU preset plus RAM priced by region | Published CPU labels are not benchmark equivalence | | 2 CPU / 4 GB service | Pro — 2 vCPU / 4 GB / $27.99 | shared-cpu-2x / 4 GB — CPU preset plus RAM priced by region | Fly may be lower or higher before add-ons | | Technical support | Included direct cloud support | Community included; Standard $29/month | Paid Fly support can exceed small compute spend | **Comparison class:** these rows compare published resource shapes and pricing methods, not a current all-region price quote or measured application throughput. Fly.io distinguishes shared and performance CPU classes and varies compute prices by region; Raff Apps does not publish an equivalent Fly CPU-class taxonomy. ### Bandwidth cost math Fly.io meters public internet egress by region group at **$0.02/GB** from North America and Europe, **$0.04/GB** from Asia-Pacific, Oceania, and South America, and **$0.12/GB** from Africa and India. Raff Apps public application egress is $0. | Monthly public egress | Raff Apps | Fly.io NA / Europe | Fly.io APAC / Oceania / South America | Fly.io Africa / India | |---:|---:|---:|---:|---:| | 1 TiB | $0 | $20.48 | $40.96 | $122.88 | | 5 TiB | $0 | $102.40 | $204.80 | $614.40 | | 10 TiB | $0 | $204.80 | $409.60 | $1,228.80 | The calculations use 1 TiB = 1,024 GB and include only public egress. They exclude compute, volumes, snapshots, cross-region private transfer, IP addresses, databases, support, certificates, and taxes. ### Automated backups Fly Volumes cost **$0.15/GB-month** and new volumes receive automatic daily block-level snapshots with **5 days of retention by default**. Snapshot storage costs **$0.08/GB-month**, with the first 10 GB free each month, and retention can be configured from 1 to 60 days. Fly.io explicitly warns that daily snapshots may not contain the latest data and recommends a separate backup plan for important state. Fly.io Managed Postgres includes high availability, backups, and connection pooling on every current plan; Basic starts at **$38/month** for Shared-2x and 1 GB RAM plus **$0.28 per provisioned GB-month** of database storage. Raff also separates application revision rollback from durable-data backup. Immutable app revisions help recover a deployment, but persistent volumes, managed databases, and object storage still need recovery policies appropriate to the data they hold. ### Hidden platform costs Fly.io's current pay-as-you-go model can add several resource lines beyond a running Machine: Volumes at $0.15/GB-month, snapshot storage at $0.08/GB-month after the first 10 GB, dedicated IPv4 at $2/month, paid support from $29/month, and public egress at $0.02–$0.12/GB by region group. Managed SSL is free for the first 10 single-hostname certificates, then $0.10/month each; wildcard certificates are $1/month. Fly.io offers a **40% compute discount** through eligible prepaid Machine reservations. Those reservations are specific to a region and CPU class, and unused monthly reservation credit does not roll over. That can improve Fly.io economics for stable workloads but is a different commitment model from on-demand comparison pricing. :::cta Deploy an App Now Deploy managed app services with fixed ceilings and $0 public egress. ::: ## Bandwidth and transfer policy Fly.io charges for traffic leaving an application to the public internet and for private traffic crossing regions. Under its granular rates, private cross-region transfer is currently **$0.006/GB** in North America and Europe, **$0.015/GB** in Asia-Pacific, Oceania, and South America, and **$0.05/GB** in Africa and India. Inbound traffic is free, and same-region transfer between apps or Machines is free within the documented granular-rate model. Raff Apps prices public application egress at $0. For public APIs, downloads, or products with unpredictable outbound traffic, that removes a variable charge from the app bill. Fly.io is stronger when its global region placement and Anycast design are worth the transfer complexity, particularly when most application and data traffic stays local to each region. A distributed Fly.io design should model both internet egress and cross-region private traffic. A centralized Raff Apps design should instead model the latency implications of keeping the application in one public `us-east` region. ## Feature comparison: Fly.io vs Raff | Feature | Raff Apps | Fly.io | |---|---|---| | Entry managed service | $3/month | 512 MB shared Machine: see regional CPU/RAM quote | | Public regions | 1 — `us-east` | 18 | | Primary deployment workflow | Visual platform + GitHub | CLI-first with `flyctl` and `fly.toml` | | Dockerfile / image | Yes | Yes | | Full Docker Compose import | Yes | No whole-stack Compose import | | Persistent app storage | Yes | Fly Volumes at $0.15/GB-month | | Public app egress | $0 | $0.02–$0.12/GB by region group | | Scale-to-zero behavior | Available | Autostop/autostart existing Machines | | Metrics-based autoscaling | Not published as an equivalent Apps control | Creates/deletes or starts/stops Machines | | Managed PostgreSQL | Yes | Yes, from $38/month + storage | | Managed MySQL | Yes | No first-party Fly Managed MySQL product documented | | Managed Redis-compatible engine | Valkey | Upstash is a partnered extension | | Object storage | Raff S3-compatible Object Storage | Tigris is a partnered extension | | Included direct technical support | Yes | Community; paid email support from $29/month | Fly.io wins on global placement, Anycast networking, Machine-level control, performance CPU options, and programmable scaling. Raff wins on simpler fixed service ceilings, full Docker Compose import, $0 public app egress, first-party MySQL/Valkey choices, and included direct support. ## Features and reliability: Raff vs Fly.io This comparison includes **0 controlled Raff-versus-Fly.io application benchmarks**, so it does not declare either platform faster. A valid application test would need the same image, CPU scheduling class, memory, region, storage path, datastore placement, concurrency profile, network route, and repeated measurement window. ### Region placement and routing Fly.io's clearest reliability and latency advantage is geographic control. Teams can place Machines in **18 regions**, and the global Anycast network can route incoming connections toward deployed instances. This is materially stronger than Raff Apps' current single public `us-east` region for products serving users across several continents. That flexibility moves more architecture responsibility to the team. Machines and volumes are regional, so application state, database topology, request routing, and failover behavior need to match the chosen placement model. ### Autoscaling and stopped Machines Fly Proxy autostop/autostart starts and stops an existing Machine pool according to traffic and concurrency. Stopped or suspended Machines do not accrue CPU or RAM charges, though their root filesystems and attached volumes can remain billable. Fly.io's metrics-based autoscaler goes further by creating/deleting or starting/stopping Machines using user-defined metrics, with a **15-second default reconciliation loop**. This is more programmable than Raff's public Apps scaling surface and is a genuine advantage for infrastructure-aware teams. ### Persistent state and snapshots Fly Volumes are hardware-local, regional persistent NVMe storage. Fly.io takes daily block-level snapshots with **5-day default retention**, but explicitly recommends an independent backup plan for important data. A snapshot can restore into a new equal-or-larger volume; it does not turn a local volume into globally shared storage. Raff Apps supports persistent application volumes and also provides managed databases and object storage. On both platforms, stateful reliability requires matching the storage layer to the workload rather than treating application rollback as data protection. ### Managed database reliability Fly.io Managed Postgres includes high availability, backups, connection pooling, and replicated storage. It is available in **12 regions** and currently starts at **$38/month + $0.28/GB-month** of provisioned storage. Raff exposes five managed data engines—PostgreSQL, MySQL, Valkey, ClickHouse, and Kafka—inside the same cloud workflow. Fly.io has the stronger distributed Postgres geography; Raff has the broader first-party engine set for this comparison. ### SLA and support Fly.io's current **99.9% uptime SLA is part of its Enterprise support plan**, which starts at **$2,500+/month**. Standard support is $29/month and Premium is $199/month; community support remains free. Raff publishes a **99.9% platform SLA** and includes direct cloud support without a separate entry support subscription. Public review evidence is also different: on August 16, 2026, Fly.io's unclaimed Trustpilot profile showed **2.8/5**, while Raff's claimed profile showed **4.5/5**. Review counts are small enough that neither score should substitute for architecture or support evaluation. ## When you should choose Fly.io over Raff Choose Fly.io when: - **Global placement is required.** Fly.io lists **18 regions** versus Raff Apps' single public `us-east` region. - **Anycast routing is part of the design.** Fly Proxy supports globally routed applications across regional Machine deployments. - **Machine-level control matters.** Fly exposes shared/performance CPU classes, memory, regional placement, `fly.toml`, `flyctl`, and the Machines API. - **Programmable autoscaling is required.** Metrics-based scaling can create, delete, start, or stop Machines with a **15-second default loop**. - **Sporadic workloads benefit from stopped compute.** Stopped/suspended Machines incur **$0 CPU and RAM charges**, though storage remains billable. - **Regional Managed Postgres matters.** Fly Managed Postgres is available in **12 regions** and includes HA and backups. - **Prepaying for stable compute is acceptable.** Eligible Machine reservations provide a **40% discount** for a specific region and CPU class. ## When you should choose Raff over Fly.io Choose Raff Apps when: - **A visible monthly ceiling matters.** Raff tiers run from **$3 to $119.99/month** with per-second prorating against the ceiling. - **Public egress is material.** Raff Apps charges **$0** for public egress versus Fly.io's $0.02–$0.12/GB regional rates. - **Docker Compose describes the stack.** Raff can import a **full Compose stack** instead of translating it into Fly-specific configuration. - **A broader first-party managed data set is useful.** Raff exposes **5 managed engines**: PostgreSQL, MySQL, Valkey, ClickHouse, and Kafka. - **Support should not be a separate subscription.** Fly.io technical support starts at **$29/month**; Raff includes direct cloud support. - **A default spend guardrail matters.** Raff enables the Apps spend cap by default in addition to service ceilings. - **The workload fits `us-east`.** Fly.io's 18-region advantage adds little when one eastern-U.S. application region already meets the latency requirement. [Raff Apps](/products/app-platform) is a live managed application platform. For adjacent app-platform decisions, compare [Render and Raff](/learn/compare/render-alternative), [Coolify and Raff](/learn/compare/coolify-alternative), and [DigitalOcean App Platform and Raff](/learn/compare/digitalocean-app-platform-alternative). ## Migrating from Fly.io to Raff 1. **Inventory the Fly.io organization.** Record apps, process groups, Machines, CPU/memory sizes, regions, volumes, secrets, certificates, IPs, private-network dependencies, Managed Postgres, extensions, and every `fly.toml` file. **Gotcha:** `fly.toml` is provider-specific and cannot be imported as a Raff service definition. 2. **Map Fly processes to Raff services.** Move HTTP processes to web services, internal processes to private services, consumers to workers, scheduled tasks to cron jobs, and administrative commands to one-off jobs. 3. **Choose a portable deployment source.** Connect GitHub, deploy an image, use a Dockerfile or buildpack, or convert a multi-service stack into Docker Compose. **Gotcha:** Fly autostop, concurrency, regional placement, and Machine-count rules need to be redesigned rather than copied verbatim. 4. **Export persistent state.** Use database-native export/restore tools for PostgreSQL and synchronize files from every Fly Volume. Move durable shared uploads to object storage where multiple app instances need access. 5. **Recreate configuration and verify.** Add secrets, domains, private bindings, health checks, volumes, managed data services, callbacks, and outbound allowlists. Validate on a temporary hostname and rehearse a restore before production cutover. 6. **Cut over with rollback.** Lower DNS TTL to **300 seconds**, complete the final data synchronization, update DNS, callbacks, and allowlists, monitor the Raff deployment, and retain Fly.io until the rollback window closes. Stateless containerized services are usually the simplest part of the move. Stateful volumes, Managed Postgres, Anycast assumptions, cross-region traffic, fixed outbound IPs, and Fly-specific scaling rules create most of the migration risk. Use the [App Platform Migration Checklist](/learn/guides/app-platform-migration-checklist) to validate service mapping, regional dependencies, backups, hostname cutover, and rollback. ## About Fly.io [Fly.io](https://fly.io/) is operated by **Fly.io, Inc.**, a developer-focused public cloud founded in **2017** and based in Chicago. It runs containerized applications as hardware-isolated Fly Machines across 18 regions, with Anycast networking, regional volumes, Managed Postgres, APIs, and Fly Kubernetes. Current Fly.io terms identify Fly.io, Inc. as the contracting entity. ## Conclusion: Fly.io or Raff? The Fly.io-versus-Raff decision resolves across four measured axes: cost boundary, global placement, state and recovery, and operational control. - **Cost boundary:** Raff Pro is **$27.99/month** at 2 vCPU / 4 GB with $0 public app egress; Fly.io's two-shared-CPU/4 GB cost varies by region and current CPU/RAM rates, with separate storage, egress, IP, or support charges. - **Global placement:** Fly.io offers **18 application regions** and Anycast routing; Raff Apps currently exposes one public `us-east` region. - **State and recovery:** Fly Volumes cost **$0.15/GB-month** with daily snapshots and 5-day default retention; Raff combines persistent app volumes with five first-party managed data engines and object storage. - **Operational control:** Fly.io exposes Machines, `fly.toml`, APIs, regional networking, and programmable autoscaling; Raff emphasizes GitHub deployment, full Compose import, service ceilings, a default spend cap, and included support. Choose Fly.io when multi-region placement, Anycast routing, Machine control, or programmable scaling are required. Choose Raff when `us-east` is sufficient and the team values predictable service ceilings, $0 public egress, Docker Compose portability, first-party managed data options, and a more managed operating model. Raff publishes a **99.9% platform SLA**. --- ### Netlify Alternative 2026: Pricing, Performance & Features URL: https://rafftechnologies.com/learn/compare/netlify-alternative Description: Considering Netlify? Raff Apps starts at $3/mo with $0 public egress; Netlify starts free and Pro begins at $20/mo. Raff Apps wins on fixed service resources, full Docker Compose import, long-running workers, private services, and $0 public application egress. Netlify wins on its $0 plan, global CDN, unlimited deploy previews, Edge Functions, framework-aware delivery, and mature frontend collaboration workflow. Choose Netlify when global frontend delivery and edge-native workflows are requirements; choose Raff when the application is a portable service stack with explicit compute and transfer boundaries. Raff Apps starts at $3/month, while Netlify starts at $0 and Pro now ranges from $20 for 3,000 credits to $126 for 20,000 credits. Raff Apps is a Netlify alternative for teams whose production workload looks more like connected application services than a frontend delivery project. Netlify packages deploys, compute, bandwidth, requests, database usage, and AI activity into credits, while Raff Technologies prices application services through published vCPU/RAM tiers with per-second billing and monthly ceilings. Netlify has the stronger built-in global delivery layer; Raff has the more explicit model for workers, private services, persistent volumes and Docker Compose stacks. ## Netlify vs Raff: which is right for you? Choose based on workload shape first, then pricing. Netlify is strongest when the deployment workflow, CDN, edge execution, previews, and frontend tooling are part of the product architecture. Raff is strongest when the application is a set of portable services that should remain understandable as compute, data, storage, and networking components. | Decision factor | Choose Raff Apps | Choose Netlify | |---|---|---| | Primary workload | APIs, containers, workers, cron jobs, private services, and multi-service stacks | Static sites, framework frontends, Functions, Edge Functions, and globally cached web applications | | Entry path | Micro from $3/month with explicit resources | Free at $0 with 300 credits | | Team plan | No workspace or seat fee | Pro starts at $20/month with 3,000 credits and unlimited members | | Public transfer | $0 application egress | 20 credits per GB of bandwidth | | Deployment package | GitHub, buildpacks, Dockerfile, container image, Docker Compose | Git, CLI, API, framework builds, Functions, Edge Functions | | Data layer | Managed PostgreSQL, MySQL, Valkey, ClickHouse, Kafka, object storage, persistent volumes | Netlify Database, Netlify Blobs, and integrations | | Global delivery | Add an external CDN when required | Global CDN and worldwide Edge Function execution are built in | Our product decision at Raff was to put cost boundaries in place before traffic arrives: each service has a published monthly ceiling, public app egress is $0, and the spend cap starts enabled. That matters for small teams running several persistent processes because the bill does not depend on combining deploy, request, bandwidth, function, and team-seat meters after launch. For the broader architecture decision, review [Cloud VM vs App Platform: What Startups Should Know](/learn/guides/cloud-vm-vs-app-platform-startups). ## Netlify overview [Netlify](https://www.netlify.com/) is a managed web development platform for deploying and serving modern web applications. It connects to source repositories, creates production and preview deployments, serves content through a global CDN, runs Functions and Edge Functions, manages domains and TLS, and provides observability and collaboration features around the deployment lifecycle. Current [Netlify pricing](https://www.netlify.com/pricing/) uses credits for new standard-plan accounts: - **Free — $0/month:** 300 credits and a hard monthly credit limit. - **Personal — $9/month:** 1,000 credits with optional additional credit packs or auto recharge. - **Pro — $20 to $126/month:** five monthly credit tiers from 3,000 to 20,000 credits, all with unlimited members. - **Enterprise — custom:** adds a 99.99% SLA, enterprise network tier, SSO, SCIM, log drains, organization management, and dedicated support. The current Pro tiers are **3,000 credits for $20**, **5,000 for $33**, **10,000 for $63**, **15,000 for $95**, and **20,000 for $126**. Pro tiers with 5,000 credits or more can roll unused monthly credits into the next billing cycle; the base 3,000-credit tier does not roll over. Netlify converts platform usage into a shared credit balance. Production deploys cost **15 credits each**, compute costs **10 credits per GB-hour**, bandwidth costs **20 credits per GB**, and web requests cost **2 credits per 10,000 requests**. Deploy previews and branch deploys do not consume production-deploy credits, although their traffic and compute can still consume the relevant meters. Netlify's genuine strengths are global frontend delivery, unlimited deploy previews, framework-aware builds, Edge Functions, instant cache behavior, integrated web observability, and a permanent $0 entry plan. Its trade-off is that the same credit balance is consumed by several workload dimensions, so production cost depends on how the application deploys, computes, transfers data, and receives requests. ## Raff overview [Raff Apps](/products/app-platform) deploys source code and containers without requiring teams to administer the operating system. It supports GitHub push-to-deploy, Dockerfiles, existing container images, automatic buildpacks, full Docker Compose imports, immutable revisions, one-click rollback, pull-request preview environments, persistent volumes, and scale-to-zero behavior. Raff Apps supports public web services, private services, background workers, timezone-aware cron jobs, and one-off jobs. Applications can connect to managed PostgreSQL, MySQL, Valkey, ClickHouse, and Kafka, plus object storage, VMs, private networking, Kubernetes, and Functions. Current Raff Apps tiers are: | Tier | vCPU | RAM | Ephemeral disk | Monthly ceiling | |---|---:|---:|---:|---:| | Micro | 0.25 | 512 MB | 2 GB | $3.00 | | Starter | 0.5 | 1 GB | 5 GB | $6.99 | | Standard | 1 | 2 GB | 10 GB | $16.99 | | Pro | 2 | 4 GB | 20 GB | $27.99 | | Pro Max | 4 | 8 GB | 40 GB | $61.99 | | Scale | 8 | 16 GB | 80 GB | $119.99 | Compute is billed per second against the published monthly ceiling. Public application egress and team seats are priced at $0, and the spend cap is enabled by default. Raff publishes a **99.9% platform SLA**. Raff is geographically narrower than Netlify; its advantage is the explicit service model and a single cloud account for app, database, object storage, VM, private network, Kubernetes, and Functions workloads. ## Netlify pricing vs Raff pricing Netlify and Raff charge for different units. Raff prices continuously running application services by fixed vCPU/RAM tiers. Netlify charges a plan price that includes a shared credit allowance, then consumes those credits across production deploys, compute, bandwidth, web requests, database activity, and AI usage. The closest useful buying positions are: | Buying position | Raff Apps | Netlify | Decision signal | |---|---:|---:|---| | Free evaluation | Micro $3 — 0.25 vCPU / 512 MB | Free $0 — 300 credits | Netlify wins when a hard-limited $0 frontend plan is enough | | Personal production | Starter $6.99 — 0.5 vCPU / 1 GB | Personal $9 — 1,000 credits | Raff publishes resources; Netlify publishes a shared usage allowance | | Small team | Standard $16.99 — 1 vCPU / 2 GB | Pro $20 — 3,000 credits and unlimited members | Netlify includes team frontend tooling; Raff includes fixed application compute | | Higher-credit team | Pro $27.99 — 2 vCPU / 4 GB | Pro $126 — 20,000 credits with one-cycle rollover | Different buying models; compare actual deploy, compute, transfer, and request usage | | 5 TB public bandwidth | $0 app-egress line; compute separate | About $670 in extra Pro credit packs on the base plan, plus the $20 plan, if all monthly credits otherwise go to bandwidth | Bandwidth-heavy workloads can diverge sharply | **Comparison class:** these are planning positions, not performance-equivalent instances. Netlify Functions and Raff application services use different execution, scaling, caching, host, and network models, so matching price points does not prove equal throughput or latency. ### Bandwidth cost math Netlify consumes **20 credits per GB** of bandwidth. On the base Pro plan, 3,000 monthly credits are included and additional credits can be purchased in **1,500-credit packs for $10**. The following examples assume all 3,000 monthly credits are available for bandwidth and ignore deploy, compute, request, database, form, and AI usage: | Monthly public bandwidth | Raff Apps public egress | Netlify base Pro credit cost | |---:|---:|---:| | 1 TB | $0 | About $120 extra credits + $20 Pro | | 5 TB | $0 | About $670 extra credits + $20 Pro | | 10 TB | $0 | About $1,350 extra credits + $20 Pro | | 50 TB | $0 | About $6,810 extra credits + $20 Pro | Higher Pro credit tiers can reduce the effective per-credit price and unused monthly credits can roll for one billing cycle on tiers of 5,000 or more. The table therefore illustrates the base-plan transfer economics, not the lowest possible Netlify price for every traffic pattern. ### Automated backups [Netlify Database backup and recovery](https://docs.netlify.com/build/data-and-storage/netlify-database/backup-and-recovery/) is more specific than the old comparison implied. Netlify automatically backs up the production database **daily at midnight UTC** and also takes a backup whenever a production deploy is published for a project with a database. Retention depends on plan: Free retains scheduled backups for **3 days** and the most recently published deploy backup; Personal retains scheduled backups for **7 days** and the last **3** deploy backups; Pro and Enterprise retain scheduled backups for **30 days** and the last **10** deploy backups. Restoring replaces the production branch with the selected backup, so application teams should account for data created after that backup. Raff Apps likewise separates application deployment rollback from durable-data recovery. Ephemeral app storage is not a backup; production state should live in managed databases, object storage, or persistent volumes with recovery procedures tested independently from application deploy rollback. ### Credit controls and hidden cost drivers Netlify auto recharge is disabled by default. When enabled, Personal purchases **500 credits for $5** as needed and Pro purchases **1,500 credits for $10** as needed. Purchased credits do not expire. If auto recharge stays disabled, a paid account can instead purchase credit packs manually; Free has a hard limit and no recharge option. The main cost drivers to model are production deploy frequency, function/database compute GB-hours, web and database bandwidth, web requests, and AI inference. A low-traffic static site can remain inexpensive, while an application with high traffic, frequent server-side execution, or database activity can consume the same shared credit balance quickly. :::cta Deploy an App Now Deploy web services, workers, cron jobs, and Docker Compose stacks with explicit monthly ceilings. ::: ## Bandwidth and transfer policy Raff Apps charges **$0 for public application egress**. Netlify consumes **20 credits per GB** for bandwidth sent to the internet, including web content, assets, image delivery, downloads, function responses, and database bandwidth where applicable. Netlify's global CDN can reduce origin work and improve delivery latency, so its bandwidth meter should not be evaluated separately from the value of built-in caching and edge delivery. A static or heavily cached international site can benefit from Netlify's architecture even when the billing model is more complex than a flat transfer policy. For dynamic APIs, downloads, media delivery, package distribution, or other workloads where public transfer is large and difficult to predict, Raff's $0 app-egress line is easier to budget. The key difference is not that one platform has bandwidth and the other does not; it is that Netlify converts bandwidth into shared credits while Raff does not meter public Apps egress separately. ## Feature comparison: Netlify vs Raff | Feature | Raff Apps | Netlify | |---|---|---| | Primary deployment model | Long-running services and containers | Frontend deployments, Functions, and Edge Functions | | Git deployment | GitHub | Git providers, CLI, API, and agent workflows | | Dockerfile / existing image | Yes | Not the primary general-service model | | Full Docker Compose import | Yes | No native whole-stack Compose import | | Deploy previews | Pull-request previews | Unlimited deploy previews and branch deploys | | Global CDN | External CDN can be added | Built in | | Edge execution | Application/external edge layer | Edge Functions run on worldwide edge locations | | Always-on worker | Yes | Not a general worker-container product | | Private service | Yes | Not a general private-service product | | Cron jobs | Timezone-aware jobs | Scheduled Functions | | Persistent mounted volume | Yes | Data products rather than a general mounted filesystem | | Managed PostgreSQL | First-party Raff managed database | Netlify Database | | Managed MySQL | First-party Raff managed database | No first-party managed MySQL product listed | | Redis-compatible managed service | Valkey | External integration | | Object storage | Raff Object Storage | Netlify Blobs | | Team seats | $0 | Unlimited on Pro | | Public app bandwidth | $0 | 20 credits per GB | | Rollback | Immutable revisions and one-click rollback | Production deploy rollback | Netlify wins on global CDN delivery, Edge Functions, deploy previews, framework-aware frontend workflow, web observability, and a permanent free tier. Raff wins on containers, Docker Compose, long-running workers, private services, explicit vCPU/RAM tiers, mounted persistent volumes, managed MySQL, and $0 public app egress. ## Features and reliability: Raff vs Netlify This comparison includes **0 controlled Raff-versus-Netlify application benchmarks**, so it does not declare either platform faster. A credible test would need the same application code, cache behavior, function or service resources, datastore location, request mix, concurrency, and client regions. ### Global frontend delivery Netlify's CDN is distributed across regions worldwide, and Edge Functions run from the worldwide edge location closest to the user. That gives Netlify the stronger default architecture for globally distributed static content, cached frontends, request rewriting, and edge personalization. Raff Apps currently exposes one public `us-east` region. A team can place a CDN in front of a Raff service, but that is an additional architectural component. For international frontend delivery with minimal infrastructure assembly, Netlify has a genuine advantage. ### Application process model Raff exposes explicit service resources and persistent process types. A Standard service provides 1 vCPU and 2 GB RAM; workers, private services, cron jobs, and web services can run as distinct components. Netlify Functions and Edge Functions fit request-driven and frontend-adjacent logic. They remove server-process management but do not represent the same operating model as a continuously available container or background worker. ### Deployment and data recovery Netlify production deploys can be rolled back, and Netlify Database provides scheduled and publish-triggered backups with plan-specific retention. Those are separate recovery layers: rolling back code does not automatically restore application data. Raff also separates application revisions from durable-data recovery. Production teams should test both code rollback and state restoration, including database exports/restores, object recovery, secrets, DNS, and external callbacks. ### Operating trust Netlify's official company page reports **$212 million raised**, and Enterprise includes a **99.99% SLA**. Raff publishes a **99.9% platform SLA**. These are different trust signals. Netlify has the longer specialized frontend-platform history and larger funding base; Raff provides a smaller cloud with public customer, VM, SLA, and review metrics. ## When you should choose Netlify over Raff Choose Netlify when: - **A permanent $0 plan matters.** Netlify Free includes 300 monthly credits; Raff Apps starts at $3/month. - **The project is frontend-first.** Framework builds, CDN delivery, previews, cache behavior, and web observability are integrated. - **Worldwide edge execution is required.** Edge Functions run from Netlify's worldwide edge locations close to users. - **Every branch needs a review environment.** Deploy previews and branch deploys do not consume production-deploy credits. - **The team wants unlimited Pro members.** Netlify Pro starts at $20/month and no longer uses per-seat pricing for team members. - **Built-in Postgres branching and deploy-linked backups fit the workflow.** Netlify Database backs up daily and on production publish, with Pro retention up to 30 days. - **Enterprise frontend controls are required.** Netlify Enterprise adds a 99.99% SLA, enterprise network tier, SSO, SCIM, log drains, and dedicated support. ## When you should choose Raff over Netlify Choose Raff Apps when: - **The application is container-first.** Raff accepts Dockerfiles, existing images, buildpacks, and full Docker Compose stacks. - **Long-running processes are required.** Web services, private services, workers, cron jobs, and one-off jobs map directly to persistent service types. - **Compute should be explicit.** Raff Standard is $16.99 for 1 vCPU / 2 GB and Raff Pro is $27.99 for 2 vCPU / 4 GB. - **Public egress is substantial.** Raff app egress is $0, while Netlify consumes 20 credits for every GB of metered bandwidth. - **Managed MySQL is required.** Raff provides managed MySQL alongside PostgreSQL, Valkey, ClickHouse, and Kafka. - **Mounted persistent storage is required.** Raff Apps supports persistent volumes for state that must survive deployments and restarts. - **Docker Compose portability matters.** A multi-service development stack can be imported instead of translated into several frontend-platform primitives. For applications that need long-running services or workers, compare [Raff Apps](/products/app-platform) with the full Netlify frontend and edge delivery workflow. ## Migrating from Netlify to Raff 1. **Inventory the Netlify project.** Record the framework, build command, publish directory, Functions, Edge Functions, Scheduled Functions, redirects, headers, forms, Blobs, Database, environment contexts, domains, analytics, and deploy-preview behavior. 2. **Choose the Raff deployment package.** Use a buildpack for a conventional app, a Dockerfile for reproducible builds, an existing image for a prebuilt artifact, or Docker Compose for a multi-service stack. **Gotcha:** Netlify project configuration does not map one-to-one to a container definition. 3. **Map execution units.** Convert HTTP Functions into web-service routes, background work into workers, schedules into cron jobs, and internal APIs into private services where appropriate. **Gotcha:** Edge Functions can rely on edge-specific runtime behavior that must be recreated in application middleware or another edge layer. 4. **Move persistent state.** Export Netlify Database through PostgreSQL-compatible tooling, copy Netlify Blobs data to Raff Object Storage where appropriate, recreate secrets, and replace any platform-specific form or identity dependencies before cutover. 5. **Rebuild delivery behavior and test.** Recreate redirects, headers, caching, image delivery, custom domains, preview rules, and an external CDN when global edge delivery remains necessary. Test database restore, object access, webhooks, OAuth callbacks, and client latency. 6. **Cut over with rollback.** Lower DNS TTL to **300 seconds**, perform the final data sync, switch DNS and external callbacks, monitor production, and keep the Netlify project available until the rollback window closes. Stateless frontend assets and portable application code are usually the easiest parts to move. Edge behavior, platform-specific Functions, redirects, Blobs, database branches, forms, identity dependencies, and global cache behavior create most migration risk. Use the [App Platform Migration Checklist](/learn/guides/app-platform-migration-checklist) to prepare application configuration, data migration, external CDN behavior, DNS, and rollback. ## About Netlify [Netlify](https://www.netlify.com/about/) is operated by Netlify, Inc., a web development platform company founded in 2014 and headquartered in San Francisco. It provides Git and API deployments, a global CDN, deploy previews, Functions, Edge Functions, Netlify Database, Netlify Blobs, observability, security controls, and enterprise web-delivery capabilities. Netlify reports $212 million raised. ## Conclusion: Netlify or Raff? The Netlify-versus-Raff decision resolves across four measured axes: delivery model, application process model, pricing model, and data portability. - **Delivery model:** Netlify includes global CDN and edge execution; Raff Apps exposes `us-east` application compute and can use an external CDN when required. - **Application model:** Netlify centers frontend deploys, Functions, and Edge Functions; Raff centers containers, workers, private services, cron jobs, and Docker Compose stacks. - **Pricing model:** Netlify starts at $0 and Pro ranges from $20/3,000 credits to $126/20,000 credits; Raff Apps starts at $3 with explicit service-resource ceilings. - **Data portability:** Netlify provides Database and Blobs within its frontend workflow; Raff connects Apps to managed databases, object storage, persistent volumes, VMs, Kubernetes, and Functions. Choose Netlify when global frontend delivery, previews, edge execution, and its credit-based web workflow remove more operating work than the usage model adds. Choose Raff when the production system is a portable service stack and explicit compute, process, storage, and transfer boundaries are more important than a built-in global edge network. Raff publishes a **99.9% platform SLA**. For adjacent decisions, review [Render Alternative 2026](/learn/compare/render-alternative), [Vercel Alternative 2026](/learn/compare/vercel-alternative), and [Railway comparison](/learn/compare/raff-vs-railway). --- ## Windows Server articles ### Windows Server Initial Setup Checklist: First 30 Minutes After Deploying a VPS URL: https://rafftechnologies.com/windows-server/windows-server-initial-setup-checklist Description: Use this 30-minute Windows Server setup checklist after deploying a VPS to establish updates, administrator access, firewall and Defender checks, storage visibility, and a recovery point before installing workloads. ## In short The first 30 minutes after deploying a Windows Server VPS should establish a safe operating baseline before you install IIS, SQL Server, Remote Desktop Services, business software, or other workloads. Confirm the server identity and network state, choose a clear hostname and time zone, start Windows Update, create a named administrator, verify Windows Firewall and Microsoft Defender, check disk capacity, and create a recovery point. This Raff Technologies checklist is for the first administrative session after you have connected successfully; it does not replace full production hardening. If you have not connected yet, start with [How to Connect to a Windows VPS via RDP](/windows-server/connect-to-windows-vps-via-rdp). Return here after the first successful login. ## The 30-minute checklist | Time | Action | Expected result | |---|---|---| | 0–5 minutes | Record the server purpose, OS, hostname, IP configuration, and recovery path | You know exactly which VM you are changing | | 5–10 minutes | Choose the final hostname and confirm the time zone | Logs, certificates, scheduled tasks, and monitoring use the correct identity and time | | 10–18 minutes | Start Windows Update and plan one controlled restart | The server begins from a current patch level | | 18–23 minutes | Create and test a named administrator account | Daily administration does not depend on one shared built-in account | | 23–27 minutes | Verify Windows Firewall, RDP rules, and Microsoft Defender | Core host protections are active before the workload is exposed | | 27–30 minutes | Check disk capacity, create a recovery point, and save a baseline record | You have a rollback path and a known starting state | Windows Update can take longer than 30 minutes. The goal is to complete the first-pass decisions and start the update cycle, not to guarantee every cumulative update finishes within the time window. ## Before you change anything Open PowerShell as Administrator and capture the current server state: ```powershell Get-ComputerInfo | Select-Object CsName, WindowsProductName, WindowsVersion, OsBuildNumber, OsArchitecture Get-NetIPConfiguration Get-TimeZone Get-Volume | Where-Object DriveLetter | Select-Object DriveLetter, FileSystemLabel, SizeRemaining, Size ``` Record these items outside the VPS: - Raff VM name - public IP address - selected Windows Server version - administrator username - server owner - intended workload - expected users - recovery or password-reset path - whether a snapshot or backup already exists A short record prevents confusion later when several Windows VMs have similar names or roles. > **Do not change the Windows network adapter to a static address unless the hosting platform specifically requires it.** Cloud VPS images commonly receive network configuration through the provider environment. An incorrect guest-level IP, gateway, or DNS change can immediately break RDP access. ## Minutes 0–5: Confirm the server identity and purpose Before installing software, decide what this server is for. A server that will become a domain controller needs different planning from an IIS server, SQL Server VM, RDS Session Host, or single-user administrative VPS. Use a simple role statement: ```text Purpose: Internal accounting application Owner: Operations team Users: 5 Data: Application files and SQL database Access: RDP through approved admin addresses Recovery target: Same business day ``` Then verify the operating system: ```powershell Get-ComputerInfo | Select-Object CsName, WindowsProductName, WindowsVersion, OsBuildNumber ``` Do not assume the deployed image matches the version requested. Confirm it before installing drivers, agents, or application dependencies. For new deployments, [Windows Server 2019 vs 2022 vs 2025](/windows-server/windows-server-version-comparison) explains when compatibility may matter more than choosing the newest version. ## Minutes 5–10: Set a clear hostname and correct time zone A random generated hostname is difficult to recognize in logs, monitoring, certificates, backup consoles, and Active Directory. Choose a short name that describes the server role without embedding secrets or customer data. Examples: ```text APP01 WEB01 SQL01 RDS01 DC01 ``` Check the current name: ```powershell $env:COMPUTERNAME ``` Rename a new workgroup server before joining it to a domain: ```powershell Rename-Computer -NewName "APP01" ``` The new name becomes active after restart. If the server is already domain-joined, use the correct domain credentials and change process instead of treating it as a fresh standalone VM. Next, check the current time zone: ```powershell Get-TimeZone ``` List available Windows time-zone IDs when needed: ```powershell Get-TimeZone -ListAvailable | Select-Object Id, DisplayName ``` Set the intended zone by its Windows ID: ```powershell Set-TimeZone -Id "UTC" ``` Use the zone required by the workload and organization. UTC is often easier for infrastructure logs, while business applications may require the organization’s local time zone. Verify Windows Time status: ```powershell w32tm /query /status ``` Correct time matters for event logs, authentication, scheduled tasks, certificate validation, database jobs, and incident review. ## Minutes 10–18: Start Windows Update before installing workloads Patch the base operating system before adding production software. This reduces the chance that application troubleshooting becomes mixed with pending operating-system changes. On Windows Server with Desktop Experience: 1. Open **Settings**. 2. Select **Windows Update**. 3. Check for updates. 4. Install available cumulative and security updates. 5. Note whether a restart is required. On Server Core, run: ```powershell SConfig ``` SConfig supports common first-run tasks, including computer name, local administrators, update settings, Remote Desktop, networking, date and time, activation, and restart controls. Do not install every optional driver or preview update automatically. Prioritize normal security and cumulative updates, then review optional items against the workload. After the update cycle and controlled restart, verify recently installed updates: ```powershell Get-CimInstance Win32_QuickFixEngineering | Sort-Object InstalledOn -Descending | Select-Object -First 10 HotFixID, Description, InstalledOn ``` For an established production server, use a maintenance window and recovery point rather than patching without rollback planning. See [Windows Update Strategy on Production Servers](/windows-server/windows-update-strategy) for the ongoing process. ## Minutes 18–23: Create a named administrator account Do not let every administrative action depend on a shared built-in `Administrator` account. Create a named local administrator for the person or operational function responsible for the server. Run PowerShell as Administrator: ```powershell $Password = Read-Host "Enter a strong password for opsadmin" -AsSecureString New-LocalUser ` -Name "opsadmin" ` -Password $Password ` -FullName "Operations Administrator" ` -Description "Named administrator for server operations" Add-LocalGroupMember -Group "Administrators" -Member "opsadmin" ``` Verify the local Administrators group: ```powershell Get-LocalGroupMember -Group "Administrators" ``` Then test a new RDP session with the named account before changing the built-in Administrator account. Use these rules: - Create one named account per administrator where practical. - Store credentials in an approved password manager. - Do not send passwords through ordinary chat or email. - Keep the number of local administrators small. - Do not disable the only known working administrator account during the first session. - If the server will become a domain controller, complete local-account planning before promotion because domain controllers do not use local accounts in the same way as member servers. Full account lockout, auditing, LAPS, and least-privilege configuration belong in the production hardening phase, not a rushed first-login change set. ## Minutes 23–27: Verify the firewall and RDP rules Windows Firewall should remain enabled on all profiles. Check its state: ```powershell Get-NetFirewallProfile | Select-Object Name, Enabled, DefaultInboundAction, DefaultOutboundAction ``` Review the Remote Desktop rule group: ```powershell Get-NetFirewallRule -DisplayGroup "Remote Desktop" | Select-Object DisplayName, Enabled, Direction, Action, Profile | Format-Table -AutoSize ``` At this stage, verify rather than aggressively rewrite the rules. A remote firewall mistake can lock you out. Do not: - disable Windows Firewall to solve a connection problem - open SQL Server, SMB, WinRM, IIS, or custom application ports before the service needs them - expose TCP 445 or database ports broadly to the public internet - restrict RDP to an IP address until you have confirmed the correct source address and recovery path - change several RDP and firewall controls at the same time For the detailed workflow, use [Configure Windows Firewall on a Windows VPS](/windows-server/configure-windows-firewall). ## Verify Microsoft Defender status Check whether Microsoft Defender Antivirus and real-time protection are active: ```powershell Get-MpComputerStatus | Select-Object AntivirusEnabled, RealTimeProtectionEnabled, AntivirusSignatureLastUpdated ``` Update signatures: ```powershell Update-MpSignature ``` If `Get-MpComputerStatus` is unavailable, confirm whether another endpoint-protection product or server image configuration is responsible for antimalware protection. Do not install multiple real-time antivirus products without checking compatibility. This first-pass check does not replace security hardening. Windows Server 2025 supports role-aware Microsoft security baselines through OSConfig, but those settings can change authentication, RDP redirection, SMB, TLS, audit, and application behavior. OSConfig security baselines apply to Windows Server 2025; use a different supported baseline workflow for earlier releases. Test any baseline against the real workload before enforcing it. Use [Windows Server Hardening Checklist](/windows-server/windows-server-hardening-checklist) before production. ## Minutes 27–30: Check storage and create a recovery point Review mounted volumes and free capacity: ```powershell Get-Volume | Where-Object DriveLetter | Select-Object DriveLetter, FileSystemLabel, @{Name="FreeGB";Expression={[math]::Round($_.SizeRemaining / 1GB, 2)}}, @{Name="SizeGB";Expression={[math]::Round($_.Size / 1GB, 2)}} ``` Confirm that: - the system volume has enough free space for updates and temporary files - expected data volumes are present - application data will not be placed randomly across user profiles - future database, log, upload, and backup growth has been considered Before installing server roles or business applications, create a snapshot or backup through the available Raff protection workflow. A snapshot is useful for fast rollback before a major change, but it is not a complete long-term backup strategy or an application-aware database backup. Read [Windows VPS Backup Strategy for Small Businesses](/windows-server/windows-vps-backup-strategy-small-business) before the server stores production data. ## Save a baseline record Create a small administration folder and export the starting state: ```powershell $Path = "C:\Admin\Baseline" New-Item -ItemType Directory -Path $Path -Force | Out-Null Get-ComputerInfo | Out-File "$Path\computer-info.txt" Get-NetIPConfiguration | Format-List * | Out-File "$Path\network.txt" Get-NetFirewallProfile | Format-Table Name, Enabled, DefaultInboundAction, DefaultOutboundAction -AutoSize | Out-File "$Path\firewall-profiles.txt" Get-LocalGroupMember -Group "Administrators" | Out-File "$Path\administrators.txt" Get-Volume | Where-Object DriveLetter | Format-Table DriveLetter, FileSystemLabel, SizeRemaining, Size -AutoSize | Out-File "$Path\volumes.txt" ``` This is not a monitoring system. It is a simple before-state that helps with later troubleshooting and change review. Keep critical recovery documentation outside the VPS as well. ## Final verification after the restart Use this checklist after Windows Update or hostname changes restart the server: | Check | Verification | |---|---| | RDP access | Reconnect successfully with the named administrator | | Hostname | `$env:COMPUTERNAME` shows the intended name | | OS version | `Get-ComputerInfo` shows the expected Windows Server edition and build | | Time | `Get-TimeZone` and `w32tm /query /status` are correct | | Updates | No required cumulative update remains waiting without a plan | | Firewall | All intended profiles remain enabled | | Defender | Antivirus and real-time protection report the expected state | | Administrators | Only known accounts have local administrator rights | | Storage | Expected volumes are mounted with adequate free space | | Recovery | A snapshot or backup path exists before major workload changes | | Documentation | Purpose, owner, access method, and change date are recorded | Do not install the production workload until the server can restart and pass this basic verification. ## What not to do in the first 30 minutes Avoid these common first-login mistakes: ### Do not disable Windows Firewall Fix the exact rule or service instead. Disabling the entire firewall removes a core protection layer. ### Do not change the guest network configuration casually An incorrect static IP, gateway, or DNS setting can break remote access. Follow the provider’s networking model. ### Do not expose application ports before installation A port should have a documented service, source, protocol, owner, and reason before it is opened. ### Do not browse and download software as the shared Administrator account Use trusted vendor sources and move toward named administrative and standard-user accounts. ### Do not promote the server to a domain controller without DNS and recovery planning Active Directory changes identity, DNS, local account behavior, and recovery requirements. Treat it as a dedicated project. ### Do not apply a full security baseline blindly Security baselines are valuable, but they can alter application and RDP behavior. Snapshot, test, and apply the baseline for the correct server role. ### Do not treat a snapshot as the only backup Snapshots support rollback. Production recovery also needs retention, off-server copies, application-aware backups, and restore testing where appropriate. ## The first-day work after this checklist The first 30 minutes establish a known starting point. The rest of the first day should be based on the server’s role. | Server role | Next work | |---|---| | Administrative Windows VPS | Restrict RDP, configure logging, and complete hardening | | RDS Session Host | Plan RDS roles, licensing mode, CALs, user profiles, and app publishing | | IIS server | Install IIS, configure HTTPS, deploy the app, and open only TCP 80/443 as required | | SQL Server | Confirm edition and licensing, storage layout, service accounts, backups, and private connectivity | | Domain controller | Confirm domain design, DNS, time hierarchy, backups, and a second-domain-controller plan | | File server | Plan volumes, NTFS and share permissions, SMB exposure, quotas, and backup recovery | | Business application server | Verify vendor support, prerequisites, database requirements, printing, licensing, and restore steps | Complete the production hardening checklist before the server becomes an internet-facing or business-critical system. ## Verification scope This checklist was reviewed against current Microsoft Learn documentation on July 31, 2026. The commands use built-in Windows Server administration tools and are written for a fresh Windows Server 2025 VPS; Microsoft also documents SConfig for Windows Server 2022 and 2019. Provider-specific networking, recovery, and image defaults can vary, so confirm those settings in the Raff dashboard before changing guest networking or access controls. The checklist deliberately avoids workload-specific configuration until the server role is known. :::cta Deploy Windows Now Deploy a Windows VM, complete the first-run checklist, and build from a known baseline. ::: ## What's next - [How to Connect to a Windows VPS via RDP](/windows-server/connect-to-windows-vps-via-rdp) — complete the first connection before this checklist - [Windows Server Hardening Checklist](/windows-server/windows-server-hardening-checklist) — prepare the server for production - [Configure Windows Firewall on a Windows VPS](/windows-server/configure-windows-firewall) — review and narrow inbound access safely - [Windows VPS Backup Strategy for Small Businesses](/windows-server/windows-vps-backup-strategy-small-business) — build a real recovery plan - [Windows Server 2019 vs 2022 vs 2025](/windows-server/windows-server-version-comparison) — select the operating system for the workload - [Raff Windows Server Hub](/windows-server) — browse Windows Server deployment, licensing, security, and troubleshooting resources ## Sources - Microsoft Learn — [Configure Server Core with SConfig](https://learn.microsoft.com/en-us/windows-server/administration/server-core/server-core-sconfig) - Microsoft Learn — [Rename-Computer](https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.management/rename-computer) - Microsoft Learn — [Set-TimeZone](https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.management/set-timezone) - Microsoft Learn — [New-LocalUser](https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.localaccounts/new-localuser) - Microsoft Learn — [Add-LocalGroupMember](https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.localaccounts/add-localgroupmember) - Microsoft Learn — [Get-NetFirewallProfile](https://learn.microsoft.com/en-us/powershell/module/netsecurity/get-netfirewallprofile) - Microsoft Learn — [Get-MpComputerStatus](https://learn.microsoft.com/en-us/powershell/module/defender/get-mpcomputerstatus) - Microsoft Learn — [Windows Server 2025 security baselines with OSConfig](https://learn.microsoft.com/en-us/windows-server/security/osconfig/osconfig-how-to-configure-security-baselines) - Date last verified: 2026-07-31 --- ### Windows VPS Hosting for Small Businesses URL: https://rafftechnologies.com/windows-server/windows-vps-small-business Description: Learn when a Windows VPS makes sense for small businesses that need Remote Desktop access, Windows apps, shared files, backups, migration, and predictable cloud infrastructure. A Windows VPS can help small businesses run Windows workloads in the cloud when they need Remote Desktop access, hosted business apps, shared files, SQL Server tools, backups, migration from old office hardware, or a central Windows Server environment for remote users. It works best when the business plans user count, access model, application support, storage, backups, security, and licensing before production. Raff Technologies provides Windows VMs for small teams that want a practical cloud Windows Server without building a complex hyperscaler setup. Small businesses usually do not wake up thinking, “We need a virtual private server.” They feel a business problem first. The office server is getting old. Remote employees need access. Accounting software only works on one machine. Files are spread across offices. Backups are unclear. A legacy app still needs Windows. A tax team needs seasonal access. An MSP needs a repeatable client environment. A Windows VPS is valuable when it turns those problems into one controlled Windows environment: users connect remotely, business apps run centrally, files are protected, backups are planned, and the server is no longer tied to one physical office. ## Quick verdict: when a Windows VPS fits a small business Use this table before choosing a Windows VPS. | Small business situation | Windows VPS fit | Why | |---|---|---| | Team needs Remote Desktop access | Strong fit | Users can reach a centralized Windows environment from outside the office. | | Business app runs on Windows Server | Strong fit after testing | Apps can run in a cloud-hosted Windows Server environment. | | Office server is aging | Strong fit | A Windows VPS can replace the physical server role. | | Multiple offices need the same apps or files | Strong fit | Centralized access reduces branch-by-branch complexity. | | Files need shared access and backups | Good fit | A cloud file server can centralize shared folders with backup planning. | | ERP, inventory, tax, or accounting software needs remote access | Good fit after vendor checks | App support, licensing, and database behavior must be reviewed. | | Users only need simple document collaboration | Depends | SaaS file tools may be simpler. | | Large local files move all day | Depends | Local storage may still be better for heavy LAN file workflows. | | High availability is mandatory | Not a single VPS decision | Plan redundancy, failover, and recovery architecture. | | App vendor does not support hosted/RDS use | Risky | Check vendor support before migration. | The best fit is a business that needs a central Windows Server environment for remote access, apps, files, or migration from local infrastructure. :::cta Explore Windows VM Use Raff Windows VM when your small business needs a cloud-hosted Windows Server for remote access, apps, files, and Windows workloads. ::: ## Why small businesses choose Windows VPS hosting ![Use case map showing Windows VPS for remote access, business software, server replacement, shared files, databases, and backups](https://raff-images.s3.raffusercloud.com/windows_vps_small_business_use_case_map_webp_619238fc20.png) A small business usually chooses Windows VPS hosting for one of six reasons. | Reason | Example | |---|---| | Remote access | Employees need to reach a Windows desktop or app from home, branches, or client sites. | | Business software | Accounting, ERP, inventory, tax, Access, or legacy apps need a central Windows environment. | | Server replacement | The old office server is aging, unreliable, or difficult to maintain. | | Shared files | Users need central folders, mapped drives, or app file paths. | | Databases | SQL Server or app databases need a Windows Server environment. | | Better recovery planning | Backups, snapshots, restore testing, and off-server copies need to be clearer. | The goal is not “move everything to cloud” by default. The goal is to put the right Windows workloads in an environment that is easier to access, manage, back up, and support. ## Windows VPS vs local office server A local office server can still work when users are on-site, workloads depend on local hardware, and the business has reliable power, cooling, backup, and IT support. ![Comparison visual showing local office server versus Windows VPS for small business users, apps, files, and backups](https://raff-images.s3.raffusercloud.com/small_business_local_server_vs_windows_vps_webp_e4b61e25e7.png) A Windows VPS becomes attractive when the business needs remote access, multi-location access, or a cleaner replacement for old hardware. | Area | Local office server | Windows VPS | |---|---|---| | Server location | One physical office | Cloud-hosted Windows Server VM | | Hardware | Business owns and replaces it | Cloud VM replaces physical server role | | Remote users | VPN, firewall, or local workaround | Remote access can be planned from the start | | Multi-location access | Often complex | Centralized environment for branch users | | Backups | Often inconsistent or local | VM backup, snapshot, and restore planning can be centralized | | Scaling | Buy or replace hardware | Resize VM or split roles | | Support | May require on-site work | MSP/team can manage a known cloud environment | | Risk | Office power/hardware can block access | Not tied to one office server | The decision is not “cloud always wins.” The decision is whether the workload benefits from being centralized in a hosted Windows environment. ## Windows VPS vs SaaS tools A Windows VPS is not always the best answer. Some business problems are better solved with SaaS. | Need | Windows VPS | SaaS | |---|---|---| | Run a Windows-only desktop app | Strong fit | Usually poor fit unless vendor has SaaS version | | Host legacy business software | Strong fit after testing | Depends on replacement availability | | Use mapped drives or NTFS permissions | Strong fit | Different model | | Real-time document co-authoring | Not ideal | Strong fit | | Vendor-managed updates | Business/MSP manages app | Vendor usually manages | | Custom Windows server control | Strong fit | Limited | | Simple file sharing | Can work | Often simpler | | SQL Server-backed app | Strong fit | Depends on app | If a SaaS version of the application fully replaces the workflow, it may be simpler. If the business still depends on Windows Server, Remote Desktop, mapped drives, SQL Server, or legacy apps, a Windows VPS may be the practical path. ## Common Windows VPS use cases for small businesses ### Remote Desktop for employees Many small businesses use a Windows VPS so employees can connect to a central Windows environment instead of relying on one office PC or server. Remote Desktop fits when: | Situation | Why it fits | |---|---| | Users need access from home | The Windows environment is reachable remotely. | | Multiple users need the same app | The app can run centrally where supported. | | Branch users need shared access | Offices connect to one environment. | | MSP manages users | Access can be documented and standardized. | Microsoft describes Remote Desktop Services as a Windows Server platform for securely delivering managed desktops and applications to users in offices, homes, branches, and partner locations. That is the right mental model for many small business Remote Desktop scenarios. For staff desktop sessions, licensing matters. Microsoft states that each user or device connecting to an RD Session Host running Windows Server needs an RDS Client Access License. ### Business software hosting A Windows VPS can host Windows-based business software when the vendor supports the environment. Examples include: | Software type | Planning focus | |---|---| | Accounting software | Data location, printers, RDS support, backups | | Tax software | Seasonal users, client files, vendor support | | ERP/inventory | Database, reports, branches, device workflows | | Microsoft Access | Front-end/back-end split, file paths, RDP access | | Legacy apps | Runtime dependencies, licensing, support | | SQL-backed apps | SQL Server backups, logins, jobs, connection strings | The application should be tested before production. A Windows VPS can provide the server environment, but the vendor support model still matters. ### Cloud file server A Windows VPS can work as a cloud file server when the business needs shared folders, NTFS permissions, mapped drives, and backup planning. It is strongest when: | File pattern | Fit | |---|---| | Users access files through RDP/RDS | Strong fit | | Business apps need shared folders | Good fit after testing | | Multi-location users need one file location | Good fit | | Folder permissions matter | Good fit | | Users want direct SMB from anywhere | Risky without secure access design | Microsoft describes SMB as the protocol Windows uses for file sharing. SMB should be used through a controlled access model, not casually exposed to the public internet. ### SQL Server and database-backed apps A Windows VPS can support SQL Server-backed business apps when the database workload is sized and backed up correctly. Plan: | SQL area | What to check | |---|---| | SQL version and edition | Supported by the application | | Recovery model | Affects backup and restore strategy | | Logins and users | Must migrate correctly | | SQL Agent jobs | Backups, imports, exports, reports | | Connection strings | Apps must point to the new SQL Server | | Firewall rules | Restrict access to required paths | | Restore test | Proves backup recovery | SQL Server migration is not only restoring a database. Logins, jobs, permissions, and app connections matter. ### Office server replacement Many small businesses reach Windows VPS hosting because the old office server becomes a risk. Warning signs: | Sign | Meaning | |---|---| | Hardware is old | Replacement risk is growing | | Backups are unclear | Recovery is not proven | | Remote access is messy | Users depend on workarounds | | Multiple offices copy files manually | Centralization may help | | One person knows the setup | Documentation risk | | Server runs many hidden tasks | Migration checklist is needed | A side-by-side migration is usually safer: build the new Windows VPS, test apps and users, run final sync, cut over, and keep rollback ready. ## How to choose the right Windows VPS size Do not size a Windows VPS only by employee count. Size it by active users, application workload, database load, storage growth, and remote access pattern. ![Workload planning visual for small business Windows VPS sizing with users, apps, SQL, storage, backups, and growth](https://raff-images.s3.raffusercloud.com/windows_vps_small_business_workload_planning_webp_0d86615079.png) Use this starting model: | Workload | Starting size | When to move up | |---|---:|---| | 1 admin or light user | 2 vCPU / 4 GB RAM | If apps or reports run on the server | | 3 light remote users | 4 vCPU / 8 GB RAM | If users keep browsers, PDFs, or Office apps open | | 3 business app users | 4 vCPU / 16 GB RAM | If accounting, Access, tax, or legacy apps run daily | | 5 active users | 4 vCPU / 16 GB RAM | If users stay logged in most of the day | | 10 active users | 8 vCPU / 32 GB RAM | If the VPS becomes a shared workplace | | SQL/ERP/heavy app | 8-16 vCPU / 32-64 GB RAM | If database, reports, and sessions compete | Storage should include production files, app data, database files, user profiles, logs, backups, reports, exports, and 12 to 24 months of expected growth. :::cta View Pricing Compare Raff Windows VM plans when sizing CPU, memory, storage, and monthly cost for your small business workload. ::: ## Remote access: direct RDP, RDS, RD Gateway, or VPN? Remote access should be designed before users start working. | Access model | Best fit | |---|---| | Direct admin RDP | One or two administrators | | RDS Session Host | Multiple staff users need desktop/app sessions | | RD Gateway | Controlled access for remote RDS users | | VPN/private access | Mapped drives or internal tools need private network access | | Web app access | Users only need browser access to an app | Direct RDP may be acceptable for restricted admin access. It should not become the default plan for every business user without a security review. RD Gateway can be useful when multiple users connect from changing locations. Microsoft describes RD Gateway as enabling secure, encrypted connections to RDS resources over the internet without requiring VPN access. ## Backups are part of the Windows VPS decision A Windows VPS should not become production until backup and restore planning are clear. Plan: | Backup layer | Purpose | |---|---| | VM backup | Recover the whole Windows VPS | | Snapshot before changes | Roll back before risky updates or migrations | | File-level backup | Restore individual files or folders | | Database backup | Protect SQL Server or app databases | | Off-server copy | Reduce risk from VM/account/ransomware scenarios | | Restore test | Prove recovery works | Backups should be tied to business expectations: | Term | Meaning | |---|---| | RPO | How much data loss is acceptable | | RTO | How long the business can be down | A 3-user office may accept different recovery targets than a tax firm during filing season or a warehouse during daily shipping. :::cta Explore Data Protection Protect your Windows VPS workload with backup, snapshot, and restore planning before storing production business data. ::: ## Security planning for small business Windows VPS A Windows VPS can hold business-critical data, so security must be planned before users connect. Minimum planning: | Area | Recommendation | |---|---| | Admin access | Use named admin accounts | | User access | Least privilege and role-based groups | | RDP exposure | Avoid broad direct RDP exposure | | Firewall rules | Allow only required ports and sources | | Updates | Patch Windows and business apps deliberately | | Backups | Restrict who can delete or modify backups | | Passwords | Use strong credentials and offboarding process | | Logs | Review failed logins and access events | | App support | Keep vendor-supported versions where possible | | Documentation | Record access, roles, backups, and support owners | Microsoft provides Windows Server security baseline guidance and Security Compliance Toolkit resources for recommended configuration baselines. For small businesses, baselines are a starting point, not a complete compliance program. ## Licensing and support questions to ask Before production, answer these questions: | Question | Why it matters | |---|---| | Does the app vendor support Windows Server? | Unsupported apps create migration risk. | | Does the app support RDS or multi-user sessions? | Staff Remote Desktop use may need a supported model. | | Are RDS CALs required? | Staff desktop sessions differ from admin access. | | Does SQL Server licensing apply? | SQL Server edition and licensing are separate decisions. | | Are Windows users named and documented? | Shared accounts create security and support problems. | | Who patches the server? | Updates need ownership. | | Who supports the app? | Infrastructure and app support are different. | | Who tests restores? | Backups are only useful if recoverable. | A Windows VPS is infrastructure. The business or MSP still owns the software, licensing, access, backups, and support process unless a specific managed service says otherwise. ## Migration path from local server to Windows VPS For many SMBs, the Windows VPS journey starts with migration from local hardware. Use this safe pattern: 1. Inventory the old server. 2. Decide what moves, rebuilds, retires, or stays local. 3. Build the new Windows VPS. 4. Configure access, users, firewall, and backups. 5. Run test migration. 6. Test real workflows. 7. Schedule cutover. 8. Run final sync or final backup/restore. 9. Move users. 10. Keep rollback ready. 11. Monitor after cutover. Do not break the old server first. Keep it available until the Windows VPS is proven. ## Windows VPS for MSP-managed clients MSPs can use Windows VPS environments to standardize client workloads. Good MSP use cases: | MSP client need | Why Windows VPS helps | |---|---| | Replace aging office servers | Removes hardware dependency | | Host client business apps | Centralizes Windows app access | | Support remote users | Gives a known access model | | Standardize backups | Easier to document and monitor | | Separate client environments | Cleaner security and billing | | Build test environments | Safer migrations and upgrades | Each client should usually have its own Windows VPS, access policy, backup plan, documentation set, and offboarding process. ## Windows VPS pricing: what affects cost? Small businesses should compare more than the base monthly VM price. Cost drivers include: | Cost area | What affects it | |---|---| | CPU and RAM | Active users, apps, reports, SQL workload | | Storage | Files, databases, profiles, logs, growth | | Backups | Retention, frequency, restore needs | | Windows licensing | Depends on provider and deployment model | | RDS CALs | Required for staff RDS usage scenarios | | SQL Server | Edition and licensing model | | Migration labor | Apps, files, SQL, AD, cutover | | Support | Infrastructure support vs app support | | Security | Access controls, monitoring, hardening | | Downtime risk | Recovery expectations and redundancy | The cheapest server is not always the cheapest operating model. The right Windows VPS plan should match the workload and recovery expectations. ## How Raff fits Windows VPS hosting for small businesses Raff fits small businesses that need a cloud-hosted Windows Server environment for Remote Desktop access, business apps, shared files, SQL Server tools, office server replacement, migration, multi-location users, MSP client environments, tax software, accounting workflows, ERP/inventory systems, or Microsoft Access and legacy apps. Raff Windows VMs can serve as the infrastructure layer. From there, the business or MSP should configure users, applications, RDS access, backups, security rules, monitoring, and documentation. Raff is not a replacement for application vendor support, SQL Server licensing, RDS CAL planning, or internal business process ownership. The clean model is: use Raff for the Windows VM foundation, then plan the workload correctly. :::cta Deploy Windows Now Create a Raff Windows VM when your team is ready to run Windows workloads, remote users, apps, and shared files in the cloud. ::: ## Recommended path by small business situation ![Decision path visual showing small business Windows VPS use cases including sizing, migration, files, SQL, remote access, and backups](https://raff-images.s3.raffusercloud.com/windows_vps_small_business_decision_path_webp_a022ef6abc.png) | Business situation | Recommended next guide | |---|---| | You are sizing for users | Windows VPS sizing for remote users | | You are replacing office hardware | Cloud Windows Server vs Local Office Server | | You need migration planning | Windows Server Migration Checklist | | You are moving a local server | Local Office Server to Cloud Windows VPS Migration | | You are moving file shares | File Server Migration to Windows VPS | | You are moving SQL Server | SQL Server Migration to Windows VPS | | You need shared folders | Windows VPS as a Cloud File Server | | You need remote access security | RD Gateway vs Direct RDP | | You run ERP or inventory software | Windows VPS for ERP and Inventory Software | | You run tax software | Windows VPS for Tax Software | | You use Access or legacy apps | Windows VPS for Microsoft Access and Legacy Apps | | You manage clients as an MSP | Windows VPS for MSP Client Environments | This page is the starting point. The supporting guides help you make the detailed decision. ## What's next - Explore [Raff Windows VM](https://rafftechnologies.com/products/windows-vm) when you are ready to compare Windows VM plans. - Review [Raff pricing](https://rafftechnologies.com/pricing) when sizing CPU, RAM, storage, and monthly cost. - Read [Windows VPS sizing for remote users](https://rafftechnologies.com/windows-server/windows-vps-sizing-remote-users) before choosing a plan. - Read [Cloud Windows Server vs Local Office Server](https://rafftechnologies.com/windows-server/cloud-windows-server-vs-local-office-server) if you are replacing office hardware. - Read [Windows Server Migration Checklist for Small Businesses](https://rafftechnologies.com/windows-server/windows-server-migration-checklist-small-business) before moving production workloads. - Read [Local Office Server to Cloud Windows VPS Migration](https://rafftechnologies.com/windows-server/local-server-to-cloud-windows-vps-migration) if you are moving from local hardware. - Read [File Server Migration to Windows VPS](https://rafftechnologies.com/windows-server/file-server-migration-to-windows-vps) if shared folders are part of the move. - Read [SQL Server Migration to Windows VPS](https://rafftechnologies.com/windows-server/sql-server-migration-to-windows-vps) if the workload depends on SQL Server. ## Sources - Microsoft Learn — [Remote Desktop Services overview in Windows Server](https://learn.microsoft.com/en-us/windows-server/remote/remote-desktop-services/overview) - Microsoft Learn — [Remote Desktop Services roles](https://learn.microsoft.com/en-us/windows-server/remote/remote-desktop-services/rds-roles) - Microsoft Learn — [License Remote Desktop Services with Client Access Licenses](https://learn.microsoft.com/en-us/windows-server/remote/remote-desktop-services/rds-client-access-license) - Microsoft Learn — [Deploy Remote Desktop Gateway role for Remote Desktop Services](https://learn.microsoft.com/en-us/windows-server/remote/remote-desktop-services/remote-desktop-gateway-role) - Microsoft Learn — [What is SMB File Sharing for Windows and Windows Server?](https://learn.microsoft.com/en-us/windows-server/storage/file-server/file-server-smb-overview) - Microsoft Learn — [SMB security hardening in Windows Server and Windows Client](https://learn.microsoft.com/en-us/windows-server/storage/file-server/smb-security-hardening) - Microsoft Learn — [Back up and restore of SQL Server databases](https://learn.microsoft.com/en-us/sql/relational-databases/backup-restore/back-up-and-restore-of-sql-server-databases) - Microsoft Learn — [Recovery models in SQL Server](https://learn.microsoft.com/en-us/sql/relational-databases/backup-restore/recovery-models-sql-server) - Microsoft Learn — [Security baselines guide](https://learn.microsoft.com/en-us/windows/security/operating-system-security/device-management/windows-security-configuration-framework/windows-security-baselines) - Microsoft Learn — [Microsoft Security Compliance Toolkit](https://learn.microsoft.com/en-us/windows/security/operating-system-security/device-management/windows-security-configuration-framework/security-compliance-toolkit-10) - Raff — [Windows VM product page](https://rafftechnologies.com/products/windows-vm) - Raff — [Windows Server Hub](https://rafftechnologies.com/windows-server) - Raff — [Pricing](https://rafftechnologies.com/pricing) --- ### 25 PowerShell Commands Every Windows VPS Admin Needs URL: https://rafftechnologies.com/windows-server/powershell Description: 25 copy-paste PowerShell commands for daily Windows VPS admin: services, processes, files, networking, users, disk, remote management, and Windows Updates. ## In short A focused reference of the **25 PowerShell commands** that handle 90% of daily Windows VPS admin work — service management, process control, file ops, networking, user accounts, disk, remote management, and Windows Updates. All commands tested on Windows Server 2022 and 2025 with built-in PowerShell 5.1; nothing requires PowerShell 7.x. Copy-paste ready. Bookmark this page. ## How to follow along Open PowerShell **as Administrator** on your Raff Windows VPS: 1. RDP into the VPS (see [Connect to a Raff Windows VPS via RDP](/windows-server/connect-to-windows-vps-via-rdp)) 2. Right-click Start → **Windows PowerShell (Admin)** — or press `Win + X` → `A` Most commands below need admin rights. The ones that don't are noted explicitly. --- ## Service management ### 1. List all services + status ```powershell Get-Service | Select-Object Name, DisplayName, Status, StartType | Format-Table -AutoSize ``` Filter to a name pattern (e.g. all SQL services): ```powershell Get-Service -Name 'MSSQL*' ``` Microsoft Learn: [`Get-Service`](https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.management/get-service) ### 2. Restart a service ```powershell Restart-Service -Name 'W3SVC' -Force ``` `-Force` skips the dependent-service prompt. For IIS specifically, `iisreset` is also a valid one-liner. ### 3. Change service startup type ```powershell # Set to Automatic (starts on boot) Set-Service -Name 'MSSQLSERVER' -StartupType Automatic # Disable a service Set-Service -Name 'Spooler' -StartupType Disabled ``` Microsoft Learn: [`Set-Service`](https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.management/set-service) --- ## Process management ### 4. List running processes ```powershell # All processes, sorted by RAM use Get-Process | Sort-Object WorkingSet64 -Descending | Select-Object -First 20 Name, Id, CPU, @{N='MB';E={[math]::Round($_.WorkingSet64/1MB,1)}} ``` Filter by name: ```powershell Get-Process -Name 'sqlservr*' ``` ### 5. Kill a process ```powershell # By name Stop-Process -Name 'notepad' -Force # By PID (safer when multiple processes share a name) Stop-Process -Id 4452 -Force ``` `-Force` skips the user confirmation prompt. Use sparingly — kills don't run cleanup code. --- ## File and folder operations ### 6. List directory contents recursively ```powershell # Files only, recursive, with size in MB Get-ChildItem -Path 'C:\inetpub' -File -Recurse | Select-Object FullName, @{N='MB';E={[math]::Round($_.Length/1MB,2)}}, LastWriteTime | Sort-Object MB -Descending | Select-Object -First 20 ``` Find files larger than 100 MB (great for "what's eating my disk?"): ```powershell Get-ChildItem -Path 'C:\' -File -Recurse -ErrorAction SilentlyContinue | Where-Object Length -gt 100MB | Select-Object FullName, @{N='MB';E={[math]::Round($_.Length/1MB,1)}} ``` ### 7. Copy with retry + logging (Robocopy wrapper) `Copy-Item` is fine for one-off; for backups, use Robocopy via PowerShell: ```powershell # Mirror a folder, retry 3x on errors, log to file robocopy 'C:\Source' 'D:\Backup' /MIR /R:3 /W:5 /LOG:'C:\Logs\backup.log' /NP ``` Robocopy isn't a PowerShell cmdlet but it's the standard tool for serious file ops on Windows. PowerShell scripts wrap it for backup automation. ### 8. Calculate folder size ```powershell (Get-ChildItem -Path 'C:\inetpub' -Recurse -ErrorAction SilentlyContinue | Measure-Object -Property Length -Sum).Sum / 1GB ``` Returns size in GB. Wrap in `[math]::Round(..., 2)` for clean output. --- ## System information ### 9. Get OS + hardware overview ```powershell Get-ComputerInfo | Select-Object CsName, OsName, OsVersion, OsBuildNumber, OsHardwareAbstractionLayer, CsTotalPhysicalMemory, CsNumberOfLogicalProcessors ``` Microsoft Learn: [`Get-ComputerInfo`](https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.management/get-computerinfo) ### 10. List installed Windows updates ```powershell Get-HotFix | Sort-Object InstalledOn -Descending | Select-Object -First 20 HotFixID, Description, InstalledOn, InstalledBy ``` ### 11. Read the Event Log ```powershell # Last 50 errors from the System log Get-EventLog -LogName System -EntryType Error -Newest 50 | Format-Table TimeGenerated, Source, EventID, Message -AutoSize -Wrap ``` For Windows Server 2022/2025, prefer the newer cmdlet: ```powershell # Last 50 errors using the new event log API Get-WinEvent -FilterHashtable @{LogName='System'; Level=2} -MaxEvents 50 | Format-Table TimeCreated, Id, ProviderName, Message -AutoSize -Wrap ``` --- ## Networking ### 12. List IP addresses ```powershell Get-NetIPAddress | Where-Object AddressFamily -eq 'IPv4' | Select-Object InterfaceAlias, IPAddress, PrefixLength, AddressState ``` ### 13. Test if a remote port is open ```powershell Test-NetConnection -ComputerName 'google.com' -Port 443 ``` The PowerShell equivalent of `nc -zv` — confirms TCP reachability + DNS resolution. Microsoft Learn: [`Test-NetConnection`](https://learn.microsoft.com/en-us/powershell/module/nettcpip/test-netconnection) ### 14. List Windows Firewall rules ```powershell # All inbound allow rules Get-NetFirewallRule -Direction Inbound -Action Allow -Enabled True | Sort-Object DisplayName | Select-Object DisplayName, Profile, @{N='Port';E={(Get-NetFirewallPortFilter -AssociatedNetFirewallRule $_).LocalPort}} ``` ### 15. Add a firewall rule ```powershell # Allow inbound TCP 8080 New-NetFirewallRule -DisplayName 'Custom App TCP 8080' ` -Direction Inbound -Protocol TCP -LocalPort 8080 ` -Action Allow -Profile Any ``` Restrict by source IP for tighter security: ```powershell New-NetFirewallRule -DisplayName 'SQL from Office' ` -Direction Inbound -Protocol TCP -LocalPort 1433 ` -RemoteAddress '203.0.113.10/32' ` -Action Allow ``` Microsoft Learn: [`New-NetFirewallRule`](https://learn.microsoft.com/en-us/powershell/module/netsecurity/new-netfirewallrule) --- ## User and group management ### 16. List local users ```powershell Get-LocalUser | Format-Table Name, Enabled, LastLogon, Description -AutoSize ``` ### 17. Create a local user ```powershell $password = Read-Host 'Password' -AsSecureString New-LocalUser -Name 'jane.doe' -Password $password -FullName 'Jane Doe' -Description 'Accountant' ``` ### 18. Add a user to a group ```powershell # Grant RDP access Add-LocalGroupMember -Group 'Remote Desktop Users' -Member 'jane.doe' # Grant local admin (use sparingly!) Add-LocalGroupMember -Group 'Administrators' -Member 'jane.doe' ``` Microsoft Learn: [`Add-LocalGroupMember`](https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.localaccounts/add-localgroupmember) --- ## Disk and storage ### 19. Show disk and volume usage ```powershell # Volumes with free space Get-Volume | Where-Object DriveLetter | Select-Object DriveLetter, FileSystemLabel, @{N='SizeGB';E={[math]::Round($_.Size/1GB,1)}}, @{N='FreeGB';E={[math]::Round($_.SizeRemaining/1GB,1)}}, @{N='UsedPct';E={[math]::Round((1-$_.SizeRemaining/$_.Size)*100,1)}} ``` ### 20. Show physical disks ```powershell Get-PhysicalDisk | Format-Table FriendlyName, MediaType, Size, HealthStatus ``` Useful to confirm your VPS is on NVMe SSD as expected. --- ## Remote management ### 21. Enable PowerShell remoting (server side) ```powershell # On the server you want to manage remotely Enable-PSRemoting -Force ``` Microsoft Learn: [`Enable-PSRemoting`](https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/enable-psremoting) ### 22. Run a command on a remote server ```powershell # Run on a single remote machine Invoke-Command -ComputerName 'SERVER02' -ScriptBlock { Get-Service W3SVC } # Run on a fleet Invoke-Command -ComputerName 'SRV01','SRV02','SRV03' -ScriptBlock { Get-WmiObject Win32_OperatingSystem | Select-Object PSComputerName, Caption, BuildNumber } ``` ### 23. Open an interactive remote PowerShell session ```powershell Enter-PSSession -ComputerName 'SERVER02' -Credential (Get-Credential) # Now you're 'inside' SERVER02 — every command runs there. Type 'exit' to leave. ``` --- ## Performance ### 24. Live performance counters ```powershell # CPU + memory snapshot every 2 seconds, 10 samples Get-Counter -Counter '\Processor(_Total)\% Processor Time', '\Memory\Available MBytes' ` -SampleInterval 2 -MaxSamples 10 ``` Useful counters for Windows Server admin: | Counter | What it shows | |---------|--------------| | `\Processor(_Total)\% Processor Time` | Overall CPU % | | `\Memory\Available MBytes` | Free RAM | | `\PhysicalDisk(_Total)\Avg. Disk Queue Length` | Disk congestion (>2 = bottleneck) | | `\Network Interface(*)\Bytes Total/sec` | Network throughput per NIC | | `\Process(*)\Working Set` | RAM per process | ### 25. Install + run Windows Updates from PowerShell The built-in Windows Update UI works, but for headless / Server Core / scripted patching: ```powershell # One-time: install the PSWindowsUpdate module from PowerShell Gallery Install-Module -Name PSWindowsUpdate -Force -Scope AllUsers # Check what's available Get-WindowsUpdate # Install everything (will reboot if needed) Get-WindowsUpdate -Install -AcceptAll -AutoReboot # Install only security updates Get-WindowsUpdate -Install -AcceptAll -Category 'Security Updates' -AutoReboot ``` PSWindowsUpdate is community-maintained but widely used. Source: [PowerShell Gallery — PSWindowsUpdate](https://www.powershellgallery.com/packages/PSWindowsUpdate). --- ## Bonus: discoverability When you forget a command name, PowerShell's discovery tools help: ```powershell # Find cmdlets by keyword (no need to know exact name) Get-Command *firewall* # See full help for any cmdlet (requires Update-Help once) Get-Help Get-Service -Full # See examples only Get-Help Get-Service -Examples # Update help files (do once after install) Update-Help -Force -ErrorAction SilentlyContinue ``` ## What's next - [Connect to a Raff Windows VPS via RDP](/windows-server/connect-to-windows-vps-via-rdp) — get to the PowerShell prompt - [Install MSSQL Server 2022 / 2025 on a Windows VPS](/windows-server/install-sql-server-2025-windows-server-vps) — uses several of these PowerShell commands - [Deploy ASP.NET Core to IIS on Windows Server](/windows-server/iis-aspnet-core-windows-server-vps) — IIS + app pool management with PowerShell ## Sources - Microsoft Learn — [PowerShell documentation](https://learn.microsoft.com/en-us/powershell/) - Microsoft Learn — [Get-Service](https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.management/get-service) - Microsoft Learn — [New-NetFirewallRule](https://learn.microsoft.com/en-us/powershell/module/netsecurity/new-netfirewallrule) - Microsoft Learn — [Test-NetConnection](https://learn.microsoft.com/en-us/powershell/module/nettcpip/test-netconnection) - Microsoft Learn — [Enable-PSRemoting](https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/enable-psremoting) - PowerShell Gallery — [PSWindowsUpdate module](https://www.powershellgallery.com/packages/PSWindowsUpdate) - Date last verified: 2026-04-20 --- ### Windows VPS for Law Firms: Remote Access, Case Files, Legal Apps, and Backups URL: https://rafftechnologies.com/windows-server/windows-vps-law-firms Description: Learn when a Windows VPS makes sense for law firms that need remote access, case files, legal software, shared folders, backups, security, permissions, and cloud Windows Server hosting. A Windows VPS can help law firms centralize remote access, legal software, case files, shared folders, document workflows, and backups in a cloud-hosted Windows Server environment. It works best when the firm plans user access, legal software support, file permissions, backup retention, security controls, remote desktop licensing, and migration before production. Raff Technologies provides Windows VMs for law firms, legal teams, and MSPs that need a practical Windows Server foundation without relying on one aging office server or scattered workstation setup. Law firms do not just need “a server.” They need controlled access to client files, case documents, legal applications, PDFs, scanned records, billing tools, calendars, templates, and shared workspaces. That is why a Windows VPS for a law firm should be planned around the full operational workflow: - attorneys, paralegals, admins, and remote staff; - case files, pleadings, discovery folders, PDFs, and templates; - legal practice management or billing software; - Microsoft Office, Outlook workflows, and document exports; - Remote Desktop or RDS access; - permissions and least privilege; - backups and restore testing; - migration from old office hardware; - secure access and offboarding. A Windows VPS gives the law firm the infrastructure layer. The firm or MSP still needs to plan the software, users, licensing, file permissions, backups, and security process correctly. :::cta Explore Windows VM Use Raff Windows VM when your law firm needs a cloud-hosted Windows Server for remote access, case files, legal apps, and shared workloads. ::: ## Quick verdict: when law firms should use a Windows VPS Use this table before moving legal workflows to a Windows VPS. | Law firm situation | Windows VPS fit | Why | |---|---|---| | Attorneys and staff need remote access | Strong fit | Users can connect to a centralized Windows environment. | | Case files are spread across PCs or office shares | Strong fit | Files can be centralized with permissions and backups. | | Legal software needs a Windows environment | Strong fit after vendor check | Apps can run where supported. | | Firm is replacing an old office server | Strong fit | A cloud Windows VPS can replace the server role. | | Multiple offices need the same files or apps | Strong fit with access planning | Branch users can work in one environment. | | Paralegals or admins need shared document workflows | Good fit | Shared folders and templates can be organized centrally. | | Firm only uses browser-based legal SaaS | Depends | SaaS may already solve the need. | | Heavy scanning or local printer workflows are critical | Depends | Test device redirection and workflow first. | | Legal app vendor does not support RDS/hosted use | Risky | Verify support before production. | | Firm has strict compliance/audit requirements | Needs planning | Access, logging, backup, encryption, and policies matter. | The best fit is a firm that still depends on Windows-based legal workflows but wants remote access, better server reliability, clearer backups, and a more supportable environment. ## Why law firms move Windows workloads to the cloud Small and midsize law firms often move to a Windows VPS after the current office setup becomes difficult to support. | Problem | What it looks like | How a Windows VPS helps | |---|---|---| | Remote access is inconsistent | Staff remote into office PCs or use risky workarounds | Users connect to one hosted Windows environment | | Case files are scattered | Documents live on laptops, desktops, shared drives, or local folders | Case folders can be centralized | | Old server risk is growing | Office server is aging, slow, or hard to back up | Cloud Windows VPS reduces local hardware dependency | | Legal apps need Windows | Software still runs best in a Windows Server/RDS model | App environment can be centralized where supported | | Permissions are unclear | Everyone has too much access or shared accounts are used | Users and groups can be documented | | Backups are not proven | Nobody knows whether deleted case files can be restored | Backup and restore planning becomes part of production | | Multiple locations need access | Branch offices and remote users need the same system | Centralized access can simplify support | | MSP support is inconsistent | Every workstation has a different setup | One server is easier to document and manage | For a law firm, infrastructure problems quickly become business problems: missed deadlines, inaccessible case files, lost documents, broken templates, unplanned downtime, and security risk. ## Windows VPS vs office PC vs local office server Many firms begin with one “main” office PC, a shared drive, or a small local server. That setup can work for a very small office, but it becomes fragile as users, files, remote work, and legal software grow. | Area | Office PC | Local office server | Windows VPS | |---|---|---|---| | Best fit | Very small office | Mostly on-site users | Remote or hybrid legal team | | Remote access | Usually awkward | VPN/RDP/firewall planning needed | Designed around remote access | | Case files | Often scattered | Central on LAN | Central in hosted environment | | Legal apps | Local installs | Server-based where supported | Central Windows environment | | Backups | Often inconsistent | Depends on local process | VM/file/app backups can be planned | | Hardware risk | High | Medium/high over time | Not tied to one office machine | | Multi-location access | Weak | Complex | Better fit | | MSP support | Harder | Manageable | Easier to standardize | | Growth | Limited | Hardware upgrade required | Resize or split roles | The right question is not “cloud or local?” The right question is: where should case files, legal apps, and staff sessions live so the firm can work securely and recover quickly? ## Common law firm workloads on a Windows VPS ### Legal practice management and billing tools Some firms use browser-based practice management software. Others still depend on Windows desktop apps, local databases, billing tools, document assembly software, or older legal applications. A Windows VPS can help when: | Need | Planning point | |---|---| | Multiple users need the same legal app | Confirm vendor support for Windows Server/RDS use | | App needs shared folders | Keep files and app paths consistent | | App uses a database | Plan SQL/app backups and performance | | Reports and billing exports matter | Test real reporting workflows | | Users work remotely | Plan RDS access and security | | Vendor support is required | Confirm supported deployment before migration | Do not assume every legal app supports hosted or RDS use. Confirm the support model first. ### Case files and shared folders Case files are usually the center of the law firm workflow. A Windows VPS can centralize: | File type | Example | |---|---| | Case folders | Matter folders, client files, pleadings | | Discovery | PDFs, documents, exports, scans | | Templates | Letters, motions, forms, engagement letters | | Billing exports | Reports, invoices, time entries | | Administrative files | HR, finance, office operations | | Archived cases | Closed matters and historical files | The file structure should be cleaned up before migration. Moving a messy file system into the cloud does not fix permissions, naming, duplication, or retention problems. ### Remote Desktop for attorneys, paralegals, and staff Remote Desktop is often the access layer for a law firm Windows VPS. Users may include: | User type | Common need | |---|---| | Attorneys | Case files, legal apps, templates, PDFs | | Paralegals | Shared folders, forms, discovery, filing workflows | | Legal assistants | Calendars, documents, billing tools | | Admin staff | Reports, file access, office documents | | Remote workers | Same environment from home or branch offices | | MSP/IT | Server administration and support | Microsoft describes Remote Desktop Services as a Windows Server platform for securely delivering managed desktops and applications to users in the office, at home, branch locations, or partner locations. That is the right model for many law firm remote-access projects. For staff desktop sessions, licensing matters. Microsoft states that each user or device connecting to an RD Session Host running Windows Server needs a Remote Desktop Services Client Access License. Use these related guides: - [Remote Desktop Server for Business](https://rafftechnologies.com/windows-server/remote-desktop-server-for-business) - [Remote Desktop Gateway vs Direct RDP](https://rafftechnologies.com/windows-server/remote-desktop-gateway-vs-direct-rdp) - [RDS CAL Licensing on Windows Server](https://rafftechnologies.com/windows-server/rds-cal-licensing-guide) - [Windows VPS sizing for remote users](https://rafftechnologies.com/windows-server/windows-vps-sizing-remote-users) :::cta Talk to Windows Engineer Review law firm users, Remote Desktop access, RDS licensing, case files, legal software, backups, and migration scope before choosing your Windows VPS plan. ::: ## Case files, permissions, and least privilege A law firm Windows VPS should not be built with one shared login and one open file share. Plan access carefully. | Area | Recommendation | |---|---| | User accounts | Use named users, not shared accounts | | Admin accounts | Keep admin accounts separate from daily user accounts | | Groups | Use role-based Windows groups | | Case folders | Assign access by matter, department, or role where needed | | Confidential matters | Restrict access to approved users only | | Templates | Keep shared templates read-only where appropriate | | Archived matters | Separate active and closed files | | Offboarding | Remove users immediately when they leave | | Access review | Periodically review who can access sensitive folders | | Documentation | Record permissions, owners, and exceptions | ABA Model Rule 1.6 addresses confidentiality of information relating to the representation of a client. This article is not legal advice, but the operational takeaway is simple: a law firm should treat file permissions, access controls, backups, and provider selection as serious business decisions. ## Secure remote access: direct RDP, RD Gateway, or VPN? The remote access model should be chosen before production users connect. | Access model | Best fit | |---|---| | Direct admin RDP | One or two trusted administrators | | RDS Session Host | Staff users need desktop/app sessions | | RD Gateway | Controlled remote access to RDS resources | | VPN/private access | Users connect privately before accessing internal services | | RemoteApp | Users need specific apps, not full desktops | Broadly exposing direct RDP is rarely the best business model. RD Gateway or VPN/private access can provide a more controlled path, depending on the firm’s setup. Microsoft describes RD Gateway as enabling secure, encrypted connections to Remote Desktop Services resources over the internet without requiring VPN access. That can be useful for law firms with remote users and branch offices. ## Backups and restore testing for law firms Law firms should not move case files, client documents, or legal app data to any server without a recovery plan. A Windows VPS backup plan should include: | Backup layer | Purpose | |---|---| | VM backup | Recover the whole Windows VPS | | Snapshot before changes | Roll back before updates, migrations, or app changes | | File-level backup | Restore deleted or changed case files | | App/database backup | Protect legal app databases correctly | | Off-server copy | Reduce risk from account, server, or ransomware issues | | Restore test | Prove recovery works before an emergency | | Retention policy | Align with firm policy and jurisdictional requirements | Do not confuse “the server is in the cloud” with “we have backups.” Cloud hosting and backups are different. Use: [Windows VPS Backup Strategy for Small Businesses](https://rafftechnologies.com/windows-server/windows-vps-backup-strategy-small-business). :::cta Explore Data Protection Protect law firm workloads with backup, snapshot, and restore planning before case files and legal apps move to a Windows VPS. ::: ## Security planning for law firm data Legal workloads involve sensitive client information, case strategy, settlement documents, contracts, evidence, billing records, and internal firm files. Minimum planning: | Security area | Recommendation | |---|---| | Named users | Avoid shared staff accounts | | Least privilege | Give users only the access they need | | Admin separation | Use separate admin accounts | | RDP exposure | Avoid broad direct RDP exposure | | RD Gateway/VPN | Use controlled remote access where appropriate | | Firewall | Restrict allowed sources and ports | | Updates | Patch Windows and legal apps deliberately | | Backups | Restrict who can delete backups | | Logs | Review failed sign-ins and suspicious access | | Endpoint behavior | Control local drive, clipboard, printer, and file redirection where needed | | Offboarding | Remove access immediately | | Documentation | Record users, apps, shares, backups, and owners | Microsoft provides Windows Server security baseline guidance and Security Compliance Toolkit resources for recommended configuration baselines. Those baselines are a starting point. Law firms also need operational policies, user training, access reviews, and vendor due diligence. Use: [Windows Server Hardening Checklist](https://rafftechnologies.com/windows-server/windows-server-hardening-checklist). ## Sizing a Windows VPS for a law firm Do not size the server only by total staff count. Size it by active users, apps, documents, storage growth, and Remote Desktop workload. Use this as a starting point: | Law firm workload | Starting size | When to move up | |---|---:|---| | Solo attorney/admin use | 2 vCPU / 4 GB RAM | If apps, PDFs, or reports run on the server | | 2-3 light users | 4 vCPU / 8 GB RAM | If users open PDFs, Office apps, browser tabs, and file shares | | 3-5 active users | 4 vCPU / 16 GB RAM | Better for legal apps, shared folders, PDFs, and RDS sessions | | 5-10 active users | 8 vCPU / 32 GB RAM | Useful when the server becomes a daily shared workspace | | Document-heavy workflow | Size storage first | PDFs, scans, discovery, and archives grow quickly | | Database-backed legal app | 8-16 vCPU / 32-64 GB RAM | Consider database load, reports, and app requirements | Plan storage for: - active case files; - closed matter archives; - PDFs and scans; - document templates; - legal app data; - billing exports; - user profiles; - downloads; - logs; - backups; - migration staging; - 12 to 24 months of growth. For deeper sizing, use: [Windows VPS sizing for remote users](https://rafftechnologies.com/windows-server/windows-vps-sizing-remote-users). ## Pricing factors for law firms The monthly VM price is only the foundation. | Cost factor | Why it matters | |---|---| | CPU and RAM | Active users, legal apps, PDFs, reports, RDS sessions | | Storage | Case files, scans, archives, backups, growth | | Backups | Frequency, retention, restore tests | | Windows licensing | Depends on provider and deployment model | | RDS CALs | Staff Remote Desktop sessions may require licensing | | Legal software licenses | Vendor licensing and support terms | | SQL/database licensing | Applies if legal app uses SQL Server | | Migration | Case files, permissions, users, apps, cutover | | Support | Windows, RDS, legal app, printer/scanner troubleshooting | | Security | Access controls, hardening, logging, offboarding | | Recovery expectations | Higher uptime/recovery needs may require stronger architecture | A cheap server can become expensive if case files are slow, backups fail, access is insecure, or staff cannot work during court deadlines. Use: [Windows VPS Pricing Explained](https://rafftechnologies.com/windows-server/windows-vps-pricing-explained). :::cta View Pricing Compare Raff Windows VM plans when sizing CPU, memory, storage, backups, and monthly cost for your law firm. ::: ## Migration path for law firms If the firm is moving from an office server, shared workstation, or local file share, migrate carefully. Use this path: 1. Inventory users, legal apps, case files, shares, printers, scanners, and databases. 2. Confirm legal software vendor support for Windows Server/RDS or hosted use. 3. Clean up file structure and old permissions before migration. 4. Choose the Windows VPS size. 5. Build the Windows VPS. 6. Configure access, firewall, users, groups, and backups. 7. Install legal apps and dependencies. 8. Copy test data first. 9. Test real workflows with attorneys, paralegals, and admin staff. 10. Test printing, scanning, PDFs, templates, and reports. 11. Run a restore test. 12. Schedule cutover outside critical deadlines. 13. Move final data. 14. Keep the old environment available for rollback. 15. Monitor performance and support tickets after cutover. Do not migrate during an active deadline period unless there is an urgent risk and a clear rollback plan. Use: - [Windows Server Migration Checklist for Small Businesses](https://rafftechnologies.com/windows-server/windows-server-migration-checklist-small-business) - [Local Office Server to Cloud Windows VPS Migration](https://rafftechnologies.com/windows-server/local-server-to-cloud-windows-vps-migration) - [File Server Migration to Windows VPS](https://rafftechnologies.com/windows-server/file-server-migration-to-windows-vps) ## Windows VPS as a cloud file server for law firms Many law firms first think they need “remote desktop,” but the real issue is often case-file centralization. A Windows VPS can work as a cloud file server when: | Need | Fit | |---|---| | Shared case folders | Strong fit | | NTFS permissions | Strong fit | | Mapped drives for legal apps | Good fit after testing | | Remote users access files through RDS | Strong fit | | Multi-office file access | Good fit with access planning | | Direct public SMB access | Avoid | | Large discovery uploads/downloads | Depends on workflow and storage size | SMB is the Windows file-sharing protocol. Do not expose SMB directly to the public internet. Use a controlled access model such as RDS, RD Gateway, VPN/private networking, or another secure access pattern. Use: [Windows VPS as a Cloud File Server](https://rafftechnologies.com/windows-server/windows-vps-cloud-file-server). ## When a Windows VPS is not the right fit A Windows VPS is useful, but it is not always the answer. Pause when: | Situation | Better next step | |---|---| | Firm only uses browser-based SaaS | SaaS may already solve the need | | Legal software vendor forbids hosted/RDS use | Do not proceed without support path | | Internet is unreliable | Fix connectivity or design fallback | | Scanning/printing workflow is untested | Test devices before production | | Compliance requirements are strict | Design access, logging, retention, and policy first | | High availability is required | Plan redundancy and failover | | Users need local offline access all day | Cloud desktop may frustrate users | | File organization is chaotic | Clean up before migration | | Licensing is unclear | Resolve before production | The right answer may be SaaS, a local server, Windows VPS, or a hybrid model. Choose based on workflow, risk, and supportability. ## How Raff fits law firms Raff fits law firms that need a cloud-hosted Windows Server environment for remote attorneys, paralegals, legal assistants, case files, legal software, shared folders, billing tools, document workflows, backups, and office server replacement. Raff can provide the Windows VM foundation. Your firm or MSP should still plan: - legal software licensing; - RDS CAL requirements; - user access and offboarding; - file permissions; - backup retention; - restore testing; - vendor support; - secure remote access; - document workflows; - migration and rollback. That is the clean way to use Raff: use the platform for the Windows Server foundation, then design the legal workload properly. Raff is especially relevant when your firm wants a practical alternative to maintaining local office hardware, but still needs Windows apps, shared folders, Remote Desktop access, and clear recovery planning. :::cta Deploy Windows Now Create a Raff Windows VM when your law firm is ready to run remote users, case files, legal apps, and Windows workloads in the cloud. ::: ## Recommended path by law firm situation | Situation | Read next | |---|---| | You need the broad SMB decision guide | [Windows VPS Hosting for Small Businesses](https://rafftechnologies.com/windows-server/windows-vps-small-business) | | You need remote access planning | [Remote Desktop Server for Business](https://rafftechnologies.com/windows-server/remote-desktop-server-for-business) | | You need pricing clarity | [Windows VPS Pricing Explained](https://rafftechnologies.com/windows-server/windows-vps-pricing-explained) | | You need file server planning | [Windows VPS as a Cloud File Server](https://rafftechnologies.com/windows-server/windows-vps-cloud-file-server) | | You are replacing office hardware | [Cloud Windows Server vs Local Office Server](https://rafftechnologies.com/windows-server/cloud-windows-server-vs-local-office-server) | | You are moving files | [File Server Migration to Windows VPS](https://rafftechnologies.com/windows-server/file-server-migration-to-windows-vps) | | You need backups | [Windows VPS Backup Strategy for Small Businesses](https://rafftechnologies.com/windows-server/windows-vps-backup-strategy-small-business) | | You need secure remote access | [Remote Desktop Gateway vs Direct RDP](https://rafftechnologies.com/windows-server/remote-desktop-gateway-vs-direct-rdp) | | You need hardening | [Windows Server Hardening Checklist](https://rafftechnologies.com/windows-server/windows-server-hardening-checklist) | | You manage client firms as an MSP | [Windows VPS for MSP Client Environments](https://rafftechnologies.com/windows-server/windows-vps-for-msp-client-environments) | ## Final law firm checklist Before moving law firm workloads to a Windows VPS, confirm: | Check | Done | |---|---| | Legal apps listed | ☐ | | Vendor support checked | ☐ | | App licenses reviewed | ☐ | | RDS CAL requirements reviewed | ☐ | | Attorneys, paralegals, admins, and remote users estimated | ☐ | | CPU/RAM/storage starting point chosen | ☐ | | Case folder structure documented | ☐ | | File permissions planned | ☐ | | Confidential matter access reviewed | ☐ | | Backup layers defined | ☐ | | Restore test planned | ☐ | | Remote access model chosen | ☐ | | Printers/scanners tested | ☐ | | Security hardening reviewed | ☐ | | Migration window selected | ☐ | | Rollback plan documented | ☐ | | Support owner assigned | ☐ | If the checklist feels unclear, do not treat the environment as production yet. ## What's next - Explore [Raff Windows VM](https://rafftechnologies.com/products/windows-vm) when you are ready to compare Windows VM options. - Review [Raff pricing](https://rafftechnologies.com/pricing) before choosing CPU, RAM, storage, and monthly cost. - Read [Windows VPS Hosting for Small Businesses](https://rafftechnologies.com/windows-server/windows-vps-small-business) for the broader SMB guide. - Read [Remote Desktop Server for Business](https://rafftechnologies.com/windows-server/remote-desktop-server-for-business) before rolling out remote staff access. - Read [Windows VPS Pricing Explained](https://rafftechnologies.com/windows-server/windows-vps-pricing-explained) before budgeting the full environment. - Read [Windows VPS as a Cloud File Server](https://rafftechnologies.com/windows-server/windows-vps-cloud-file-server) if case files are the main workload. - Read [Windows VPS Backup Strategy for Small Businesses](https://rafftechnologies.com/windows-server/windows-vps-backup-strategy-small-business) before moving production legal data. - Read [Windows Server Hardening Checklist](https://rafftechnologies.com/windows-server/windows-server-hardening-checklist) before opening access to users. ## Sources - Raff — [Windows VM product page](https://rafftechnologies.com/products/windows-vm) - Raff — [Pricing](https://rafftechnologies.com/pricing) - Raff — [Windows Server Hub](https://rafftechnologies.com/windows-server) - Raff — [Remote Desktop Server for Business](https://rafftechnologies.com/windows-server/remote-desktop-server-for-business) - Raff — [Windows VPS as a Cloud File Server](https://rafftechnologies.com/windows-server/windows-vps-cloud-file-server) - Microsoft Learn — [Remote Desktop Services overview in Windows Server](https://learn.microsoft.com/en-us/windows-server/remote/remote-desktop-services/overview) - Microsoft Learn — [License Remote Desktop Services with Client Access Licenses](https://learn.microsoft.com/en-us/windows-server/remote/remote-desktop-services/rds-client-access-license) - Microsoft Learn — [Deploy Remote Desktop Gateway role for Remote Desktop Services](https://learn.microsoft.com/en-us/windows-server/remote/remote-desktop-services/remote-desktop-gateway-role) - Microsoft Learn — [What is SMB File Sharing for Windows and Windows Server?](https://learn.microsoft.com/en-us/windows-server/storage/file-server/file-server-smb-overview) - Microsoft Learn — [SMB security hardening in Windows Server and Windows Client](https://learn.microsoft.com/en-us/windows-server/storage/file-server/smb-security-hardening) - Microsoft Learn — [Security baselines guide](https://learn.microsoft.com/en-us/windows/security/operating-system-security/device-management/windows-security-configuration-framework/windows-security-baselines) - ABA — [Model Rule 1.6: Confidentiality of Information](https://www.americanbar.org/groups/professional_responsibility/publications/model_rules_of_professional_conduct/rule_1_6_confidentiality_of_information/) - ABA — [Comment on Rule 1.6](https://www.americanbar.org/content/aba-cms-dotorg/en/groups/professional_responsibility/publications/model_rules_of_professional_conduct/rule_1_6_confidentiality_of_information/comment_on_rule_1_6/) --- ### Windows VPS for Insurance Agencies: Remote Access, Client Files, Apps, and Backups URL: https://rafftechnologies.com/windows-server/windows-vps-insurance-agencies Description: Learn when a Windows VPS makes sense for insurance agencies that need remote access, client files, agency apps, shared folders, backups, security, permissions, and office server migration. A Windows VPS can help insurance agencies centralize remote access, client files, agency applications, shared folders, reports, downloads, scanned documents, and backups in a cloud-hosted Windows Server environment. It works best when the agency plans user access, agency software support, file permissions, retention needs, backup strategy, Remote Desktop licensing, security, and migration before production. Raff Technologies provides Windows VMs for insurance agencies, small offices, and MSPs that need a practical Windows Server foundation without depending on one old office server or scattered workstation setup. Insurance agencies do not only need “a server.” They need a controlled place where producers, CSRs, owners, admins, and remote staff can reach the same files, tools, reports, and workflows. A Windows VPS can support that model when the agency still depends on Windows apps, mapped drives, shared folders, PDFs, policy documents, downloads, scanned files, quote exports, or office server workflows. The goal is not to move everything to the cloud blindly. The goal is to make agency work easier to access, easier to protect, easier to support, and less dependent on one physical office machine. :::cta Explore Windows VM Run insurance apps, files, and remote users on Raff Windows VM. ::: ## Quick verdict: when insurance agencies should use a Windows VPS Use this table before moving agency workloads to a Windows VPS. | Insurance agency situation | Windows VPS fit | Why | |---|---|---| | Producers or CSRs need remote access | Strong fit | Users can connect to one hosted Windows environment. | | Client files are spread across PCs, shares, or branches | Strong fit | Files can be centralized with permissions and backups. | | Agency apps need Windows or shared file paths | Strong fit after vendor check | Apps can run in a supported Windows Server environment. | | Old office server is slow or risky | Strong fit | A cloud Windows VPS can replace the office server role. | | Branch offices need the same files or apps | Strong fit with access planning | Teams can work from one environment. | | MSP manages the agency environment | Strong fit | Centralized server is easier to document and support. | | Agency only uses browser-based SaaS tools | Depends | SaaS access may already be enough. | | Heavy scanning or local device workflows are critical | Depends | Test printers, scanners, and local devices first. | | Vendor does not support hosted/RDS use | Risky | Verify support before production. | | Agency has strict regulatory or contractual requirements | Needs planning | Access, logging, backups, retention, and policy ownership matter. | The best fit is an insurance agency that still depends on Windows-based office workflows but wants safer remote access, clearer backups, and a more supportable server model. ## Why insurance agencies move Windows workloads to the cloud Insurance agencies often move to a Windows VPS after the current office setup becomes hard to manage. ![Architecture diagram showing producers, CSRs, admins, and remote staff accessing agency apps, client files, reports, and backups through a centralized Windows VPS](https://raff-images.s3.raffusercloud.com/centralized_insurance_agency_environment_webp_1d1979dce6.png) | Problem | What it looks like | How a Windows VPS helps | |---|---|---| | Remote access is messy | Staff remote into office PCs or use VPN workarounds | Users connect to one hosted Windows environment | | Client files are scattered | Documents live on local PCs, shared drives, downloads, or email | Central folders and permissions can be planned | | Old server risk is growing | Office server is aging, slow, or hard to back up | Cloud Windows VPS reduces local hardware dependency | | Apps need Windows | Some tools still depend on Windows, file paths, or local installs | Supported apps can run in a central Windows environment | | Branch offices duplicate files | Offices use separate folders or app installs | Shared environment reduces duplication | | Backups are unclear | Deleted files or ransomware recovery is not proven | Backup and restore planning becomes part of production | | MSP support is inconsistent | Every workstation is different | One server is easier to document and manage | | User offboarding is weak | Access remains on shared accounts or old devices | Named users and access review are easier to enforce | For insurance agencies, downtime is not the only risk. The bigger operational risk is losing access to client records, policy documents, billing exports, certificates, reports, scans, or the tools staff need during business hours. ## Windows VPS vs office PC vs local office server Many agencies begin with a shared drive on one office PC, then move to a small local server, then eventually need better remote access and backup planning. | Area | Office PC | Local office server | Windows VPS | |---|---|---|---| | Best fit | Very small office | Mostly on-site agency staff | Remote or hybrid agency team | | Remote access | Awkward and inconsistent | VPN/RDP/firewall planning needed | Designed around remote access | | Client files | Often scattered | Central on LAN | Central in hosted environment | | Agency apps | Local installs | Server-based where supported | Central Windows environment | | Backups | Often inconsistent | Depends on local process | VM/file/app backups can be planned | | Hardware risk | High | Medium/high over time | Not tied to one office machine | | Branch access | Weak | More complex | Better fit | | MSP support | Harder | Manageable | Easier to standardize | | Growth | Limited | Hardware upgrade required | Resize or split roles | A Windows VPS is not automatically right for every agency. But it is often the cleanest next step when the agency has outgrown one office PC or local server. ## Common insurance agency workloads on a Windows VPS ### Agency management workflows Insurance agencies may use a mix of agency management systems, rating tools, document templates, file exports, carrier portals, PDFs, and local folders. A Windows VPS can help when: | Need | Planning point | |---|---| | Multiple users need the same Windows app | Confirm vendor support for Windows Server/RDS use | | App depends on shared folders | Keep paths, permissions, and drive mappings consistent | | Reports and exports matter | Test real workflows before production | | App uses a database | Plan database backups and performance | | Remote staff need access | Plan RDP/RDS/RD Gateway or VPN access | | Vendor support is required | Confirm supported hosting model before migration | Do not assume every agency application supports hosted or RDS use. Confirm the vendor’s supported deployment model first. ### Client files and policy documents Client files are often the center of agency work. A Windows VPS can centralize: | File type | Example | |---|---| | Client folders | Account records, policy documents, notes | | Certificates | COIs, forms, renewal documents | | Scans | IDs, signed forms, supporting documents | | Quotes and proposals | PDF exports, spreadsheets, submissions | | Billing files | Statements, invoices, payment documents | | Claims documents | Supporting files and correspondence | | Templates | Letters, forms, agency documents | | Archived clients | Historical account folders | Moving a messy file system to the cloud does not fix it. Clean up folder structure, permissions, naming, and archives before migration. ### Remote Desktop for producers, CSRs, and admins Remote Desktop is often the access layer for insurance agency Windows VPS workloads. Users may include: | User type | Common need | |---|---| | Agency owners | Full overview, reports, admin workflows | | Producers | Client files, quotes, proposals, carrier docs | | CSRs/account managers | Client files, certificates, renewals, document workflows | | Admin staff | Shared folders, reports, billing exports | | Remote employees | Same environment from home or branch offices | | MSP/IT | Server administration and support | Microsoft describes Remote Desktop Services as a Windows Server platform for securely delivering managed desktops and applications to users in the office, at home, branch locations, or partner locations. For staff desktop sessions, Microsoft states that each user or device connecting to an RD Session Host running Windows Server needs a Remote Desktop Services Client Access License. Use these related guides: - [Remote Desktop Server for Business](https://rafftechnologies.com/windows-server/remote-desktop-server-for-business) - [Windows VPS for Remote Employees](https://rafftechnologies.com/windows-server/windows-vps-remote-employees) - [Remote Desktop Gateway vs Direct RDP](https://rafftechnologies.com/windows-server/remote-desktop-gateway-vs-direct-rdp) - [RDS CAL Licensing on Windows Server](https://rafftechnologies.com/windows-server/rds-cal-licensing-guide) :::cta Talk to Windows Engineer Plan users, apps, files, backups, and migration before production. ::: ## Client files, permissions, and retention planning Insurance agencies handle client records, policy data, payment documents, identification documents, claims information, and correspondence. File access should be deliberate. Plan: | Area | Recommendation | |---|---| | User accounts | Use named users, not shared logins | | Role groups | Create groups for owners, producers, CSRs, admins, and MSPs | | Client folders | Standardize folder names before migration | | Permissions | Use least privilege for sensitive folders | | Archives | Separate active and inactive client files | | Downloads | Control where carrier downloads and exports are stored | | Templates | Keep shared templates read-only where appropriate | | Offboarding | Remove access quickly when staff leave | | Retention | Align with agency policy, carrier agreements, and legal/regulatory obligations | | Documentation | Record folder owners, permissions, exceptions, and backup scope | This article is not legal or compliance advice. Insurance agencies should validate retention, privacy, cybersecurity, and access-control obligations with qualified advisors. The NAIC Insurance Data Security Model Law is one important reference point for the insurance sector. The NAIC says the model requires licensees in adopting states to develop, implement, and maintain an information security program, investigate cybersecurity events, and notify the state insurance commissioner of such events. ## Security planning for insurance agency data A Windows VPS can hold sensitive client and business data. Security should be planned before production use. Minimum planning: | Security area | Recommendation | |---|---| | Named users | Avoid shared producer/CSR/admin accounts | | Admin separation | Keep admin accounts separate from daily user accounts | | Strong passwords | Use strong password rules and offboarding process | | RDP exposure | Avoid broad direct RDP exposure | | RD Gateway/VPN | Use controlled access where appropriate | | Firewall rules | Restrict allowed sources and ports | | Permissions | Use groups and least privilege | | Local redirection | Control clipboard, drive, and printer redirection where needed | | Backups | Restrict who can delete backups | | Updates | Patch Windows and apps deliberately | | Logs | Review failed sign-ins and suspicious access | | Documentation | Record users, apps, shares, backups, and owners | Microsoft provides Windows Server security baseline guidance and Security Compliance Toolkit resources for recommended configuration baselines. Those baselines are only a starting point. Agencies also need operational process, user training, access reviews, vendor checks, and retention policy. Use: [Windows Server Hardening Checklist](https://rafftechnologies.com/windows-server/windows-server-hardening-checklist). ## Backups and restore testing for insurance agencies Backups are not optional for insurance agency workloads. ![Layered protection stack showing permissions, backups, snapshots, off-server copies, and restore testing for insurance agency client files on a Windows VPS](https://raff-images.s3.raffusercloud.com/insurance_agency_protection_stack_webp_0ce613effa.png) A Windows VPS backup plan should cover: | Backup layer | Purpose | |---|---| | VM backup | Recover the whole Windows VPS | | Snapshot before changes | Roll back before updates, migrations, or app changes | | File-level backup | Restore deleted or changed client files | | App/database backup | Protect agency app data correctly | | Off-server copy | Reduce risk from account, server, or ransomware issues | | Restore test | Prove recovery works before an emergency | | Retention policy | Align with agency requirements and business risk | Do not confuse “server is in the cloud” with “we have backups.” Cloud hosting and backup planning are different. Use: [Windows VPS Backup Strategy for Small Businesses](https://rafftechnologies.com/windows-server/windows-vps-backup-strategy-small-business). :::cta Explore Data Protection Protect client files, app data, and restore points. ::: ## Sizing a Windows VPS for an insurance agency Do not size only by employee count. Size by active users, apps, file volume, scanning/export workflows, and Remote Desktop workload. ![Workload planning infographic for insurance agency Windows VPS sizing with active users, agency apps, client files, scans, backups, and storage growth](https://raff-images.s3.raffusercloud.com/insurance_agency_workload_planning_webp_2c8700c364.png) Use this as a starting point: | Insurance agency workload | Starting size | When to move up | |---|---:|---| | Solo owner/admin use | 2 vCPU / 4 GB RAM | If apps, PDFs, or reports run on the server | | 2-3 light users | 4 vCPU / 8 GB RAM | If users open PDFs, Office apps, portals, and shared folders | | 3-5 active users | 4 vCPU / 16 GB RAM | Better for agency apps, shared files, and RDS sessions | | 5-10 active users | 8 vCPU / 32 GB RAM | Useful when the server becomes a daily shared workspace | | Document-heavy agency | Size storage first | PDFs, scans, policy docs, and archived files grow quickly | | Database-backed agency app | 8-16 vCPU / 32-64 GB RAM | Consider database load, reports, and app requirements | Plan storage for: - active client files; - archived accounts; - policy documents; - certificates; - scans; - PDFs; - billing exports; - claims documents; - templates; - user profiles; - downloads; - logs; - backups; - migration staging; - 12 to 24 months of growth. For deeper sizing, use: [Windows VPS sizing for remote users](https://rafftechnologies.com/windows-server/windows-vps-sizing-remote-users). ## Pricing factors for insurance agencies The monthly VM price is only the foundation. | Cost factor | Why it matters | |---|---| | CPU and RAM | Active users, apps, PDFs, reports, and RDS sessions | | Storage | Client files, scans, archived accounts, backups, growth | | Backups | Frequency, retention, restore tests | | Windows licensing | Depends on provider and deployment model | | RDS CALs | Staff Remote Desktop sessions may require licensing | | Agency software licenses | Vendor licensing and support terms | | SQL/database licensing | Applies if the app uses SQL Server | | Migration | Files, permissions, users, apps, cutover | | Support | Windows, RDS, app, printer/scanner troubleshooting | | Security | Access controls, hardening, logging, offboarding | | Recovery expectations | Better recovery targets may require stronger planning | A cheap server can become expensive if files are slow, backups fail, access is insecure, or staff cannot work during renewal deadlines. Use: [Windows VPS Pricing Explained](https://rafftechnologies.com/windows-server/windows-vps-pricing-explained). :::cta View Pricing Compare plans for users, files, apps, and backups. ::: ## Migration path for insurance agencies If the agency is moving from an office server, shared workstation, or local file share, migrate carefully. Use this path: 1. Inventory users, apps, client folders, shares, printers, scanners, databases, and integrations. 2. Confirm agency software vendor support for Windows Server/RDS or hosted use. 3. Clean up file structure and old permissions before migration. 4. Choose the Windows VPS size. 5. Build the Windows VPS. 6. Configure access, firewall, users, groups, and backups. 7. Install agency apps and dependencies. 8. Copy test data first. 9. Test workflows with owners, producers, CSRs, admins, and remote staff. 10. Test printing, scanning, PDFs, downloads, templates, and reports. 11. Run a restore test. 12. Schedule cutover outside critical deadlines. 13. Move final data. 14. Keep the old environment available for rollback. 15. Monitor performance and support tickets after cutover. Do not migrate during a critical renewal, enrollment, audit, or reporting period unless there is an urgent risk and a clear rollback plan. Use: - [Windows Server Migration Checklist for Small Businesses](https://rafftechnologies.com/windows-server/windows-server-migration-checklist-small-business) - [Local Office Server to Cloud Windows VPS Migration](https://rafftechnologies.com/windows-server/local-server-to-cloud-windows-vps-migration) - [File Server Migration to Windows VPS](https://rafftechnologies.com/windows-server/file-server-migration-to-windows-vps) ## Windows VPS as a cloud file server for insurance agencies Some agencies think they need a full cloud desktop platform, but the main problem is file centralization. A Windows VPS can work as a cloud file server when: | Need | Fit | |---|---| | Shared client folders | Strong fit | | NTFS permissions | Strong fit | | Mapped drives for apps | Good fit after testing | | Remote users access files through RDS | Strong fit | | Branch office file access | Good fit with access planning | | Direct public SMB access | Avoid | | Large file uploads/downloads | Depends on workflow and storage size | SMB is the Windows file-sharing protocol. Do not expose SMB directly to the public internet. Use a controlled access model such as RDS, RD Gateway, VPN/private networking, or another secure access pattern. Use: [Windows VPS as a Cloud File Server](https://rafftechnologies.com/windows-server/windows-vps-cloud-file-server). ## When a Windows VPS is not the right fit A Windows VPS is useful, but it is not always the answer. Pause when: | Situation | Better next step | |---|---| | Agency only uses browser-based SaaS | SaaS may already solve the need | | Agency software vendor forbids hosted/RDS use | Do not proceed without support path | | Internet is unreliable | Fix connectivity or design fallback | | Scanning/printing workflow is untested | Test devices before production | | Compliance requirements are strict | Design access, logging, retention, and policy first | | High availability is required | Plan redundancy and failover | | Users need local offline access all day | Cloud desktop may frustrate users | | File organization is chaotic | Clean up before migration | | Licensing is unclear | Resolve before production | The right answer may be SaaS, a local server, Windows VPS, or a hybrid model. Choose based on workflow, risk, supportability, and compliance requirements. ## How Raff fits insurance agencies Raff fits insurance agencies that need a cloud-hosted Windows Server environment for remote producers, CSRs, admins, client files, agency apps, shared folders, reports, backups, and office server replacement. Raff can provide the Windows VM foundation. Your agency or MSP should still plan: - agency software licensing; - RDS CAL requirements; - user access and offboarding; - file permissions; - backup retention; - restore testing; - vendor support; - secure remote access; - document workflows; - migration and rollback. That is the clean way to use Raff: use the platform for the Windows Server foundation, then design the insurance agency workload properly. Raff is especially relevant when your agency wants a practical alternative to maintaining local office hardware, but still needs Windows apps, shared folders, Remote Desktop access, and recovery planning. :::cta Deploy Windows Now Launch a Raff Windows VM for your agency workload. ::: ## Recommended path by insurance agency situation | Situation | Read next | |---|---| | You need the broad SMB decision guide | [Windows VPS Hosting for Small Businesses](https://rafftechnologies.com/windows-server/windows-vps-small-business) | | You need remote access planning | [Remote Desktop Server for Business](https://rafftechnologies.com/windows-server/remote-desktop-server-for-business) | | You support remote employees | [Windows VPS for Remote Employees](https://rafftechnologies.com/windows-server/windows-vps-remote-employees) | | You need pricing clarity | [Windows VPS Pricing Explained](https://rafftechnologies.com/windows-server/windows-vps-pricing-explained) | | You need file server planning | [Windows VPS as a Cloud File Server](https://rafftechnologies.com/windows-server/windows-vps-cloud-file-server) | | You are replacing office hardware | [Cloud Windows Server vs Local Office Server](https://rafftechnologies.com/windows-server/cloud-windows-server-vs-local-office-server) | | You are moving files | [File Server Migration to Windows VPS](https://rafftechnologies.com/windows-server/file-server-migration-to-windows-vps) | | You need backups | [Windows VPS Backup Strategy for Small Businesses](https://rafftechnologies.com/windows-server/windows-vps-backup-strategy-small-business) | | You need secure remote access | [Remote Desktop Gateway vs Direct RDP](https://rafftechnologies.com/windows-server/remote-desktop-gateway-vs-direct-rdp) | | You need hardening | [Windows Server Hardening Checklist](https://rafftechnologies.com/windows-server/windows-server-hardening-checklist) | | You manage agencies as an MSP | [Windows VPS for MSP Client Environments](https://rafftechnologies.com/windows-server/windows-vps-for-msp-client-environments) | ## Final insurance agency checklist Before moving insurance agency workloads to a Windows VPS, confirm: | Check | Done | |---|---| | Agency apps listed | ☐ | | Vendor support checked | ☐ | | App licenses reviewed | ☐ | | RDS CAL requirements reviewed | ☐ | | Owners, producers, CSRs, admins, and remote users estimated | ☐ | | CPU/RAM/storage starting point chosen | ☐ | | Client folder structure documented | ☐ | | File permissions planned | ☐ | | Sensitive folder access reviewed | ☐ | | Retention requirements reviewed | ☐ | | Backup layers defined | ☐ | | Restore test planned | ☐ | | Remote access model chosen | ☐ | | Printers/scanners tested | ☐ | | Security hardening reviewed | ☐ | | Migration window selected | ☐ | | Rollback plan documented | ☐ | | Support owner assigned | ☐ | If the checklist feels unclear, do not treat the environment as production yet. ## What's next - Explore [Raff Windows VM](https://rafftechnologies.com/products/windows-vm) when you are ready to compare Windows VM options. - Review [Raff pricing](https://rafftechnologies.com/pricing) before choosing CPU, RAM, storage, and monthly cost. - Read [Windows VPS Hosting for Small Businesses](https://rafftechnologies.com/windows-server/windows-vps-small-business) for the broader SMB guide. - Read [Remote Desktop Server for Business](https://rafftechnologies.com/windows-server/remote-desktop-server-for-business) before rolling out remote staff access. - Read [Windows VPS for Remote Employees](https://rafftechnologies.com/windows-server/windows-vps-remote-employees) if remote work is the main driver. - Read [Windows VPS Pricing Explained](https://rafftechnologies.com/windows-server/windows-vps-pricing-explained) before budgeting the full environment. - Read [Windows VPS as a Cloud File Server](https://rafftechnologies.com/windows-server/windows-vps-cloud-file-server) if client files are the main workload. - Read [Windows VPS Backup Strategy for Small Businesses](https://rafftechnologies.com/windows-server/windows-vps-backup-strategy-small-business) before moving production agency data. - Read [Windows Server Hardening Checklist](https://rafftechnologies.com/windows-server/windows-server-hardening-checklist) before opening access to users. ## Sources - Raff — [Windows VM product page](https://rafftechnologies.com/products/windows-vm) - Raff — [Pricing](https://rafftechnologies.com/pricing) - Raff — [Windows Server Hub](https://rafftechnologies.com/windows-server) - Microsoft Learn — [Remote Desktop Services overview in Windows Server](https://learn.microsoft.com/en-us/windows-server/remote/remote-desktop-services/overview) - Microsoft Learn — [License Remote Desktop Services with Client Access Licenses](https://learn.microsoft.com/en-us/windows-server/remote/remote-desktop-services/rds-client-access-license) - Microsoft Learn — [Deploy Remote Desktop Gateway role for Remote Desktop Services](https://learn.microsoft.com/en-us/windows-server/remote/remote-desktop-services/remote-desktop-gateway-role) - Microsoft Learn — [What is SMB File Sharing for Windows and Windows Server?](https://learn.microsoft.com/en-us/windows-server/storage/file-server/file-server-smb-overview) - Microsoft Learn — [SMB security hardening in Windows Server and Windows Client](https://learn.microsoft.com/en-us/windows-server/storage/file-server/smb-security-hardening) - Microsoft Learn — [Security baselines guide](https://learn.microsoft.com/en-us/windows/security/operating-system-security/device-management/windows-security-configuration-framework/windows-security-baselines) - NAIC — [Cybersecurity](https://content.naic.org/insurance-topics/cybersecurity) - NAIC — [Insurance Data Security Model Law](https://content.naic.org/sites/default/files/government-affairs-brief-data-security-model-law.pdf) --- ### Windows VPS for Real Estate Offices: Remote Access, Documents, Apps, and Shared Files URL: https://rafftechnologies.com/windows-server/windows-vps-real-estate-offices Description: Learn when a Windows VPS makes sense for real estate offices that need remote access, transaction documents, shared folders, office apps, backups, security, permissions, and branch access. A Windows VPS can help real estate offices centralize remote access, transaction documents, shared folders, office applications, reports, listing files, property management tools, backups, and branch-office access in a cloud-hosted Windows Server environment. It works best when the office plans users, applications, file permissions, document retention, Remote Desktop access, backup strategy, security, and migration before production. Raff Technologies provides Windows VMs for real estate offices, brokerages, property teams, and MSPs that need a practical Windows Server foundation without relying on one aging office server or scattered workstation setup. Real estate teams do not only need “a server.” They need a controlled place where agents, brokers, transaction coordinators, admins, assistants, and remote staff can access the same documents, applications, reports, templates, and shared files. That is the business problem Raff Windows VPS can help solve. Instead of spreading files across office PCs, laptops, USB drives, email threads, and old shared folders, the team can work from one cloud Windows environment with planned access, permissions, backups, and recovery. :::cta Explore Windows VM Run real estate apps, documents, and users on Raff Windows VM. ::: ## Quick verdict: when real estate offices should use a Windows VPS Use this table before moving real estate office workloads to a Windows VPS. | Real estate office situation | Windows VPS fit | Why | |---|---|---| | Agents or admins need remote access | Strong fit | Users can connect to one hosted Windows environment. | | Transaction files are spread across PCs or folders | Strong fit | Documents can be centralized with permissions and backups. | | Office apps need Windows or mapped drives | Strong fit after vendor check | Apps can run in a supported Windows Server environment. | | Office server is old or unreliable | Strong fit | A cloud Windows VPS can replace the local server role. | | Multiple offices need shared files | Strong fit with access planning | Branch users can work from one environment. | | Property management or brokerage team needs shared workflows | Good fit | Apps, reports, and folders can be organized centrally. | | Office only uses browser-based SaaS tools | Depends | SaaS access may already be enough. | | Heavy image/video/media files are the main workload | Depends | Storage and transfer workflow need testing. | | Vendor does not support hosted/RDS use | Risky | Verify support before production. | | Office has strict records or privacy requirements | Needs planning | Access, retention, logging, backups, and policy ownership matter. | The best fit is a real estate office that still depends on Windows-based workflows, shared documents, mapped folders, or local server patterns but wants better remote access and recovery planning. ## Why real estate offices move Windows workloads to the cloud Real estate offices often grow into cloud infrastructure because the old setup becomes hard to support. ![Architecture diagram showing agents, brokers, coordinators, and admins accessing real estate apps, transaction documents, shared folders, and backups through a Windows VPS](https://raff-images.s3.raffusercloud.com/real_estate_office_windows_vps_architecture_webp_f57d47adb1.png) | Problem | What it looks like | How a Windows VPS helps | |---|---|---| | Remote access is messy | Agents remote into office PCs or ask admins to send files | Users access one hosted Windows environment | | Documents are scattered | Contracts, PDFs, forms, listing files, and reports live everywhere | Shared folders can be centralized | | Old server risk is growing | Local office server is slow, full, or poorly backed up | Cloud Windows VPS reduces hardware dependency | | Branch offices duplicate files | Multiple offices keep separate folders and versions | Central environment reduces duplication | | Office apps need Windows | Some apps still expect local Windows paths or installs | Supported apps can run centrally | | Backups are unclear | Deleted or changed documents are hard to recover | Backup and restore planning becomes part of production | | MSP support is inconsistent | Every workstation has a different setup | One server is easier to document and manage | | Offboarding is weak | Former staff may still have file copies or shared credentials | Named users and access review are easier to enforce | The business risk is not only downtime. It is losing access to contracts, client files, closing documents, property reports, commission records, templates, or shared folders when the team needs them. ## Windows VPS vs office PC vs local office server Many real estate offices begin with shared folders on one office PC or a small local server. That can work for a very small team, but it becomes fragile as agents, admins, locations, and documents grow. | Area | Office PC | Local office server | Windows VPS | |---|---|---|---| | Best fit | Very small office | Mostly on-site users | Remote or hybrid real estate team | | Remote access | Awkward and inconsistent | VPN/RDP/firewall planning needed | Designed around remote access | | Documents | Often scattered | Central on LAN | Central in hosted environment | | Office apps | Local installs | Server-based where supported | Central Windows environment | | Backups | Often inconsistent | Depends on local process | VM/file/app backups can be planned | | Hardware risk | High | Medium/high over time | Not tied to one office machine | | Branch access | Weak | More complex | Better fit | | MSP support | Harder | Manageable | Easier to standardize | | Growth | Limited | Hardware upgrade required | Resize or split roles | A Windows VPS is not automatically right for every office. But it is often the cleanest next step when the business has outgrown one office PC, one NAS, or one aging local server. ## Common real estate workloads on a Windows VPS ![Workflow visual showing real estate transaction documents, listing files, templates, reports, and archived deals centralized on a Windows VPS](https://raff-images.s3.raffusercloud.com/real_estate_document_workflow_windows_vps_webp_d6d1bfaf47.png) ### Transaction documents and shared folders Real estate teams handle a large number of documents. A Windows VPS can centralize: | File type | Example | |---|---| | Transaction folders | Buyer/seller files, contracts, disclosures | | Listing files | Listing agreements, property documents, photos, PDFs | | Templates | Forms, letters, checklists, office documents | | Reports | Commission reports, sales reports, property reports | | Closing files | Signed documents, settlement files, supporting PDFs | | Client files | Contact-related documents, notes, attachments | | Property files | Lease files, inspection files, maintenance records | | Archived deals | Closed transactions and historical files | Moving a messy file system to the cloud does not fix it. Clean up folder structure, names, old versions, permissions, and archives before migration. ### Real estate office applications Some real estate teams use mostly browser-based SaaS. Others still depend on Windows apps, local reporting tools, templates, accounting software, property management tools, document utilities, or older internal systems. A Windows VPS can help when: | Need | Planning point | |---|---| | Multiple users need the same Windows app | Confirm vendor support for Windows Server/RDS use | | App depends on shared folders | Keep paths, permissions, and mapped drives consistent | | Reports and exports matter | Test real workflows before production | | App uses a database | Plan database backups and performance | | Remote staff need access | Plan RDP/RDS/RD Gateway or VPN access | | Vendor support is required | Confirm supported hosting model before migration | Do not assume every real estate or property management application supports hosted or RDS use. Confirm the vendor’s supported deployment model first. ### Remote Desktop for agents, brokers, and admins Remote Desktop is often the access layer for real estate office Windows VPS workloads. Users may include: | User type | Common need | |---|---| | Brokers/owners | Reports, admin workflows, shared files | | Agents | Transaction documents, templates, listing files | | Transaction coordinators | Checklists, closing files, PDFs, shared folders | | Admin staff | Office documents, commission files, reports | | Property managers | Property files, leases, maintenance documents | | Remote staff | Same environment from home or branch offices | | MSP/IT | Server administration and support | Microsoft describes Remote Desktop Services as a Windows Server platform for securely delivering managed desktops and applications to users in the office, at home, branch locations, or partner locations. For staff desktop sessions, Microsoft states that each user or device connecting to an RD Session Host running Windows Server needs a Remote Desktop Services Client Access License. Use these related guides: - [Remote Desktop Server for Business](https://rafftechnologies.com/windows-server/remote-desktop-server-for-business) - [Windows VPS for Remote Employees](https://rafftechnologies.com/windows-server/windows-vps-remote-employees) - [Remote Desktop Gateway vs Direct RDP](https://rafftechnologies.com/windows-server/remote-desktop-gateway-vs-direct-rdp) - [RDS CAL Licensing on Windows Server](https://rafftechnologies.com/windows-server/rds-cal-licensing-guide) :::cta Talk to Windows Engineer Plan users, apps, documents, backups, and migration before launch. ::: ## Shared documents, permissions, and retention planning A real estate office should not run on one shared account and one open folder. Plan access carefully. | Area | Recommendation | |---|---| | User accounts | Use named users, not shared logins | | Role groups | Create groups for brokers, agents, admins, coordinators, property managers, and MSPs | | Transaction folders | Standardize folder structure by client, deal, property, or year | | Permissions | Use least privilege for sensitive folders | | Archives | Separate active and closed transaction files | | Downloads | Control where forms, signed PDFs, and exports are stored | | Templates | Keep shared templates read-only where appropriate | | Offboarding | Remove access quickly when staff leave | | Retention | Align with office policy and legal/regulatory requirements | | Documentation | Record folder owners, permissions, exceptions, and backup scope | This article is not legal or compliance advice. Real estate offices should validate document retention, privacy, cybersecurity, and broker/agency obligations with qualified advisors. ## Security planning for real estate office data A Windows VPS can hold contracts, client information, payment-related documents, signed forms, property files, and business records. Security should be planned before production use. Minimum planning: | Security area | Recommendation | |---|---| | Named users | Avoid shared agent/admin accounts | | Admin separation | Keep admin accounts separate from daily user accounts | | Strong passwords | Use strong password rules and offboarding process | | RDP exposure | Avoid broad direct RDP exposure | | RD Gateway/VPN | Use controlled access where appropriate | | Firewall rules | Restrict allowed sources and ports | | Permissions | Use groups and least privilege | | Local redirection | Control clipboard, drive, and printer redirection where needed | | Backups | Restrict who can delete backups | | Updates | Patch Windows and apps deliberately | | Logs | Review failed sign-ins and suspicious access | | Documentation | Record users, apps, shares, backups, and owners | Microsoft provides Windows Server security baseline guidance and Security Compliance Toolkit resources for recommended configuration baselines. Those baselines are only a starting point. Offices also need operational process, user training, access reviews, vendor checks, and retention policy. Use: [Windows Server Hardening Checklist](https://rafftechnologies.com/windows-server/windows-server-hardening-checklist). ## Backups and restore testing for real estate offices Backups are not optional for real estate office workloads. ![Layered protection stack showing permissions, backups, snapshots, off-server copies, and restore testing for real estate transaction documents on a Windows VPS](https://raff-images.s3.raffusercloud.com/real_estate_office_protection_stack_webp_15269e881b.png) A Windows VPS backup plan should cover: | Backup layer | Purpose | |---|---| | VM backup | Recover the whole Windows VPS | | Snapshot before changes | Roll back before updates, migrations, or app changes | | File-level backup | Restore deleted or changed transaction documents | | App/database backup | Protect app data correctly | | Off-server copy | Reduce risk from account, server, or ransomware issues | | Restore test | Prove recovery works before an emergency | | Retention policy | Align with office requirements and business risk | Do not confuse “server is in the cloud” with “we have backups.” Cloud hosting and backup planning are different. Use: [Windows VPS Backup Strategy for Small Businesses](https://rafftechnologies.com/windows-server/windows-vps-backup-strategy-small-business). :::cta Explore Data Protection Protect transaction files, app data, and restore points. ::: ## Sizing a Windows VPS for a real estate office Do not size only by employee count. Size by active users, apps, document volume, scanning/export workflows, listing media, and Remote Desktop workload. Use this as a starting point: | Real estate workload | Starting size | When to move up | |---|---:|---| | Solo broker/admin use | 2 vCPU / 4 GB RAM | If apps, PDFs, or reports run on the server | | 2-3 light users | 4 vCPU / 8 GB RAM | If users open PDFs, Office apps, browser portals, and shared folders | | 3-5 active users | 4 vCPU / 16 GB RAM | Better for office apps, shared documents, and RDS sessions | | 5-10 active users | 8 vCPU / 32 GB RAM | Useful when the server becomes a daily shared workspace | | Document-heavy office | Size storage first | PDFs, scans, transaction files, and archives grow quickly | | Property management/app database workload | 8-16 vCPU / 32-64 GB RAM | Consider database load, reports, and app requirements | Plan storage for: - active transaction files; - closed deal archives; - listing documents; - property files; - signed PDFs; - scans; - reports; - templates; - user profiles; - downloads; - listing media and photos; - logs; - backups; - migration staging; - 12 to 24 months of growth. For deeper sizing, use: [Windows VPS sizing for remote users](https://rafftechnologies.com/windows-server/windows-vps-sizing-remote-users). ## Pricing factors for real estate offices The monthly VM price is only the foundation. | Cost factor | Why it matters | |---|---| | CPU and RAM | Active users, apps, PDFs, reports, and RDS sessions | | Storage | Transaction files, scans, listing media, archives, backups, growth | | Backups | Frequency, retention, restore tests | | Windows licensing | Depends on provider and deployment model | | RDS CALs | Staff Remote Desktop sessions may require licensing | | Real estate software licenses | Vendor licensing and support terms | | SQL/database licensing | Applies if the app uses SQL Server | | Migration | Files, permissions, users, apps, cutover | | Support | Windows, RDS, app, printer/scanner troubleshooting | | Security | Access controls, hardening, logging, offboarding | | Recovery expectations | Better recovery targets may require stronger planning | A cheap server can become expensive if documents are slow, backups fail, access is insecure, or staff cannot work during active transactions. Use: [Windows VPS Pricing Explained](https://rafftechnologies.com/windows-server/windows-vps-pricing-explained). :::cta View Pricing Compare plans for users, documents, apps, and backups. ::: ## Migration path for real estate offices If the office is moving from an office server, shared workstation, NAS, or local file share, migrate carefully. Use this path: 1. Inventory users, apps, transaction folders, shares, printers, scanners, databases, and integrations. 2. Confirm real estate software vendor support for Windows Server/RDS or hosted use. 3. Clean up file structure and old permissions before migration. 4. Choose the Windows VPS size. 5. Build the Windows VPS. 6. Configure access, firewall, users, groups, and backups. 7. Install office apps and dependencies. 8. Copy test data first. 9. Test workflows with brokers, agents, coordinators, admins, and remote staff. 10. Test printing, scanning, PDFs, downloads, templates, reports, and file paths. 11. Run a restore test. 12. Schedule cutover outside active deadline periods. 13. Move final data. 14. Keep the old environment available for rollback. 15. Monitor performance and support tickets after cutover. Do not migrate during a closing deadline, audit, or major transaction period unless there is an urgent risk and a clear rollback plan. Use: - [Windows Server Migration Checklist for Small Businesses](https://rafftechnologies.com/windows-server/windows-server-migration-checklist-small-business) - [Local Office Server to Cloud Windows VPS Migration](https://rafftechnologies.com/windows-server/local-server-to-cloud-windows-vps-migration) - [File Server Migration to Windows VPS](https://rafftechnologies.com/windows-server/file-server-migration-to-windows-vps) ## Windows VPS as a cloud file server for real estate offices Some real estate offices think they need a full cloud desktop platform, but the main problem is document centralization. A Windows VPS can work as a cloud file server when: | Need | Fit | |---|---| | Shared transaction folders | Strong fit | | NTFS permissions | Strong fit | | Mapped drives for apps | Good fit after testing | | Remote users access files through RDS | Strong fit | | Branch office file access | Good fit with access planning | | Direct public SMB access | Avoid | | Large listing media transfers | Depends on workflow and storage size | SMB is the Windows file-sharing protocol. Do not expose SMB directly to the public internet. Use a controlled access model such as RDS, RD Gateway, VPN/private networking, or another secure access pattern. Use: [Windows VPS as a Cloud File Server](https://rafftechnologies.com/windows-server/windows-vps-cloud-file-server). ## When a Windows VPS is not the right fit A Windows VPS is useful, but it is not always the answer. Pause when: | Situation | Better next step | |---|---| | Office only uses browser-based real estate SaaS | SaaS may already solve the need | | Vendor forbids hosted/RDS use | Do not proceed without support path | | Internet is unreliable | Fix connectivity or design fallback | | Scanning/printing workflow is untested | Test devices before production | | Media files are very large | Test storage and transfer workflow | | Compliance requirements are strict | Design access, logging, retention, and policy first | | High availability is required | Plan redundancy and failover | | Users need local offline access all day | Cloud desktop may frustrate users | | File organization is chaotic | Clean up before migration | | Licensing is unclear | Resolve before production | The right answer may be SaaS, a local server, Windows VPS, or a hybrid model. Choose based on workflow, risk, supportability, and compliance requirements. ## How Raff fits real estate offices Raff fits real estate offices that need a cloud-hosted Windows Server environment for remote agents, brokers, admins, transaction documents, office apps, shared folders, reports, backups, and office server replacement. Raff can provide the Windows VM foundation. Your office or MSP should still plan: - real estate software licensing; - RDS CAL requirements; - user access and offboarding; - file permissions; - backup retention; - restore testing; - vendor support; - secure remote access; - document workflows; - migration and rollback. That is the clean way to use Raff: use the platform for the Windows Server foundation, then design the real estate office workload properly. Raff is especially relevant when your office wants a practical alternative to maintaining local server hardware, but still needs Windows apps, shared folders, Remote Desktop access, and recovery planning. :::cta Deploy Windows Now Launch a Raff Windows VM for your real estate workload. ::: ## Recommended path by real estate office situation | Situation | Read next | |---|---| | You need the broad SMB decision guide | [Windows VPS Hosting for Small Businesses](https://rafftechnologies.com/windows-server/windows-vps-small-business) | | You need remote access planning | [Remote Desktop Server for Business](https://rafftechnologies.com/windows-server/remote-desktop-server-for-business) | | You support remote employees | [Windows VPS for Remote Employees](https://rafftechnologies.com/windows-server/windows-vps-remote-employees) | | You need pricing clarity | [Windows VPS Pricing Explained](https://rafftechnologies.com/windows-server/windows-vps-pricing-explained) | | You need file server planning | [Windows VPS as a Cloud File Server](https://rafftechnologies.com/windows-server/windows-vps-cloud-file-server) | | You are replacing office hardware | [Cloud Windows Server vs Local Office Server](https://rafftechnologies.com/windows-server/cloud-windows-server-vs-local-office-server) | | You are moving files | [File Server Migration to Windows VPS](https://rafftechnologies.com/windows-server/file-server-migration-to-windows-vps) | | You need backups | [Windows VPS Backup Strategy for Small Businesses](https://rafftechnologies.com/windows-server/windows-vps-backup-strategy-small-business) | | You need secure remote access | [Remote Desktop Gateway vs Direct RDP](https://rafftechnologies.com/windows-server/remote-desktop-gateway-vs-direct-rdp) | | You need hardening | [Windows Server Hardening Checklist](https://rafftechnologies.com/windows-server/windows-server-hardening-checklist) | | You manage real estate offices as an MSP | [Windows VPS for MSP Client Environments](https://rafftechnologies.com/windows-server/windows-vps-for-msp-client-environments) | ## Final real estate office checklist Before moving real estate office workloads to a Windows VPS, confirm: | Check | Done | |---|---| | Office apps listed | ☐ | | Vendor support checked | ☐ | | App licenses reviewed | ☐ | | RDS CAL requirements reviewed | ☐ | | Brokers, agents, coordinators, admins, and remote users estimated | ☐ | | CPU/RAM/storage starting point chosen | ☐ | | Transaction folder structure documented | ☐ | | File permissions planned | ☐ | | Sensitive folder access reviewed | ☐ | | Retention requirements reviewed | ☐ | | Backup layers defined | ☐ | | Restore test planned | ☐ | | Remote access model chosen | ☐ | | Printers/scanners tested | ☐ | | Security hardening reviewed | ☐ | | Migration window selected | ☐ | | Rollback plan documented | ☐ | | Support owner assigned | ☐ | If the checklist feels unclear, do not treat the environment as production yet. ## What's next - Explore [Raff Windows VM](https://rafftechnologies.com/products/windows-vm) when you are ready to compare Windows VM options. - Review [Raff pricing](https://rafftechnologies.com/pricing) before choosing CPU, RAM, storage, and monthly cost. - Read [Windows VPS Hosting for Small Businesses](https://rafftechnologies.com/windows-server/windows-vps-small-business) for the broader SMB guide. - Read [Remote Desktop Server for Business](https://rafftechnologies.com/windows-server/remote-desktop-server-for-business) before rolling out remote staff access. - Read [Windows VPS for Remote Employees](https://rafftechnologies.com/windows-server/windows-vps-remote-employees) if remote work is the main driver. - Read [Windows VPS Pricing Explained](https://rafftechnologies.com/windows-server/windows-vps-pricing-explained) before budgeting the full environment. - Read [Windows VPS as a Cloud File Server](https://rafftechnologies.com/windows-server/windows-vps-cloud-file-server) if transaction files are the main workload. - Read [Windows VPS Backup Strategy for Small Businesses](https://rafftechnologies.com/windows-server/windows-vps-backup-strategy-small-business) before moving production real estate data. - Read [Windows Server Hardening Checklist](https://rafftechnologies.com/windows-server/windows-server-hardening-checklist) before opening access to users. ## Sources - Raff — [Windows VM product page](https://rafftechnologies.com/products/windows-vm) - Raff — [Pricing](https://rafftechnologies.com/pricing) - Raff — [Windows Server Hub](https://rafftechnologies.com/windows-server) - Microsoft Learn — [Remote Desktop Services overview in Windows Server](https://learn.microsoft.com/en-us/windows-server/remote/remote-desktop-services/overview) - Microsoft Learn — [License Remote Desktop Services with Client Access Licenses](https://learn.microsoft.com/en-us/windows-server/remote/remote-desktop-services/rds-client-access-license) - Microsoft Learn — [Deploy Remote Desktop Gateway role for Remote Desktop Services](https://learn.microsoft.com/en-us/windows-server/remote/remote-desktop-services/remote-desktop-gateway-role) - Microsoft Learn — [What is SMB File Sharing for Windows and Windows Server?](https://learn.microsoft.com/en-us/windows-server/storage/file-server/file-server-smb-overview) - Microsoft Learn — [SMB security hardening in Windows Server and Windows Client](https://learn.microsoft.com/en-us/windows-server/storage/file-server/smb-security-hardening) - Microsoft Learn — [Security baselines guide](https://learn.microsoft.com/en-us/windows/security/operating-system-security/device-management/windows-security-configuration-framework/windows-security-baselines) --- ### Windows VPS for Construction Companies: Business Apps URL: https://rafftechnologies.com/windows-server/windows-vps-construction-companies Description: Windows VPS for construction companies: centralize estimating, accounting, project files, and remote access while planning backups and workload limits. A Windows VPS can help construction companies centralize estimating and bidding software, accounting and payroll tools, ERP or inventory systems, project documents, shared folders, reports, and remote access in one cloud-hosted Windows Server environment. It works best when the company still depends on Windows-based business software but needs office staff, project managers, estimators, administrators, and remote teams to reach the same applications and files from different locations. The strongest use cases are business operations rather than graphics-heavy design work. Estimating, job costing, accounting, document management, light ERP, reporting, and shared Windows applications are often good candidates. Heavy CAD, BIM, Revit, 3D modeling, rendering, or other GPU-intensive workloads may require specialized infrastructure and should be tested separately. Raff Technologies provides the Windows VM foundation. The construction company or its MSP should still plan software compatibility, user access, RDS licensing, project-file storage, backups, security, migration, and recovery before production. :::cta Explore Windows VM Run construction apps, files, and remote users on Raff Windows VM. ::: ## Quick verdict: when construction companies should use a Windows VPS Use this table before moving construction workloads to a Windows VPS. | Construction company situation | Windows VPS fit | Why | |---|---|---| | Estimators need access from home or another office | Strong fit | Users can connect to the same hosted Windows environment. | | Accounting, payroll, or job-costing software requires Windows | Strong fit after vendor check | Supported applications can run centrally. | | Project documents are spread across office PCs | Strong fit | Shared folders and permissions can be centralized. | | Multiple offices or job sites need the same files | Strong fit with access planning | Users can reach one environment instead of maintaining separate copies. | | An aging office server hosts business software | Strong fit | A Windows VPS can reduce dependency on local hardware. | | ERP or inventory software supports Windows Server | Good fit | The app, database, and users can stay in one environment. | | Staff need Remote Desktop access to shared applications | Strong fit with RDS planning | The server can deliver a consistent workspace. | | Large CAD or BIM models are the primary workload | Test carefully | Performance, GPU, storage, and latency requirements may exceed a standard VPS. | | Plotters, scanners, USB devices, or dongles are critical | Needs testing | Device redirection and hardware dependencies may not work as expected. | | The company only uses browser-based SaaS tools | Depends | A Windows VPS may add complexity without solving a real problem. | The best fit is a small or midsize construction company that has outgrown a single office PC or local server but still relies on Windows applications, shared files, and centralized business workflows. ## Why construction companies outgrow local office infrastructure Construction companies often begin with a practical setup: one office, several workstations, a shared drive, and a few locally installed applications. ![Architecture diagram showing office staff, project managers, remote users, and branch offices accessing estimating software, ERP applications, project files, and backups through a centralized Windows VPS](https://raff-images.s3.raffusercloud.com/construction_company_windows_vps_workflow_webp_6d038f0f8b.png) That setup becomes harder to manage as the company adds employees, job sites, branches, subcontractor coordination, project documents, and remote work. | Common problem | What it looks like in practice | How a Windows VPS helps | |---|---|---| | Estimating software is tied to one office PC | Estimators remote into a workstation or exchange files manually | The application can run in a centralized environment where supported. | | Project files are scattered | Contracts, drawings, change orders, reports, and spreadsheets live in different folders | Shared folders can be organized in one Windows environment. | | Remote access is inconsistent | VPN issues, office-PC sleep problems, and changing public IPs interrupt work | Users connect to a cloud-hosted Windows Server. | | The local server is aging | Hardware failure, limited storage, and warranty concerns create risk | The workload moves away from one physical machine. | | Multiple offices keep separate copies | Staff work from different versions of the same spreadsheet or document | One central environment reduces duplication. | | Backups are unclear | Files are copied occasionally but restores are never tested | Backup, snapshot, retention, and restore ownership can be planned. | | Every PC has a different setup | Software versions, mapped drives, and permissions vary by employee | A central server is easier to standardize and support. | | Growth requires hardware purchases | More users mean new server hardware, storage, UPS, and installation work | A cloud VM can be resized or extended with additional storage. | The main benefit is not simply “putting a server in the cloud.” It is creating one controlled environment for the Windows tools and project information the business already depends on. ## Common construction workloads on a Windows VPS ### Estimating, bidding, and job-costing software Estimating and bidding are often the first workflows construction companies want to centralize. A Windows VPS can be useful when the application: - supports Windows Server; - supports Remote Desktop Services or hosted use; - stores data in a shared database or company file; - needs several estimators to work from different locations; - depends on mapped drives, Windows services, or scheduled tasks; - must remain available outside normal office hours. Before migration, confirm the software vendor supports the intended deployment model. Some applications are licensed per user, device, server, company file, or concurrent session. Others may require a specific SQL Server edition, Windows version, or local component. Do not assume that software working on a Windows 10 or Windows 11 desktop means it is supported on Windows Server. ### Accounting, payroll, and financial workflows Construction companies often combine general accounting with job costing, payroll, subcontractor records, purchasing, and project-level reporting. A Windows VPS can centralize: | Workload | Example need | |---|---| | Accounting | Shared company file or accounting application | | Payroll | Controlled access for finance and admin staff | | Job costing | Costs organized by project, phase, or cost code | | Accounts payable | Vendor invoices, purchase orders, and approvals | | Accounts receivable | Progress billing, invoices, and payment tracking | | Reporting | Project profitability, labor, material, and cash-flow reports | | Document exports | PDFs, spreadsheets, and archived reports | The server should be sized for active users, report generation, database activity, and document storage rather than employee count alone. ### ERP, inventory, and operations software A contractor may use ERP or operations software for: - materials and inventory; - purchasing; - equipment records; - warehouse or yard operations; - project costing; - work orders; - scheduling; - vendor management; - reporting; - SQL Server-backed applications. A Windows VPS is a practical fit when the software vendor supports Windows Server and the workload does not require specialized hardware or extremely low-latency local integration. Read [Windows VPS for ERP and Inventory Software](https://rafftechnologies.com/windows-server/windows-vps-erp-inventory-software) when the operations system is the main workload. ### Project documents and shared folders Construction businesses produce a large amount of structured and unstructured data. A Windows VPS can centralize: | File category | Examples | |---|---| | Contracts | Owner, subcontractor, supplier, and vendor agreements | | Estimates | Bid worksheets, cost models, takeoff exports, and pricing files | | Project administration | RFIs, submittals, change orders, meeting notes, and schedules | | Financial records | Invoices, purchase orders, payroll exports, and job-cost reports | | Safety and compliance files | Training records, checklists, permits, and inspection documents | | Site documentation | Daily logs, progress photos, reports, and issue lists | | Templates | Standard forms, spreadsheets, letters, and project folder structures | | Archives | Completed projects and historical records | A cloud file server does not fix poor document organization. Clean up naming, folder structure, duplicate files, permissions, and archives before migration. Read [Windows VPS as a Cloud File Server](https://rafftechnologies.com/windows-server/windows-vps-cloud-file-server) if shared project files are the main use case. ### Remote office and job-site access Construction work rarely happens from one desk. Potential users include: | User type | Common access need | |---|---| | Owners and directors | Reports, approvals, and financial visibility | | Estimators | Estimating software, bid files, and supplier pricing | | Project managers | Project folders, reports, schedules, and change orders | | Accounting staff | Accounting, payroll, job costing, and invoices | | Operations staff | ERP, purchasing, inventory, and equipment records | | Site supervisors | Documents, reports, and administrative workflows | | Remote employees | The same applications and files available from home | | MSP or IT provider | Administration, monitoring, backups, and support | A Windows VPS can give these users one consistent environment, but access should be designed around actual roles. Not every employee needs full desktop access, local drive redirection, administrator rights, or access to every project folder. ## A practical construction-company Windows VPS architecture A simple environment may look like this: ```text Office staff ───────┐ Remote estimators ──┤ Project managers ───┼── Secure Remote Access ── Windows VPS Branch office ──────┤ ├─ Business applications MSP / IT ───────────┘ ├─ Database ├─ Shared project files ├─ User profiles └─ Backups and snapshots ``` The design can stay on one server for a small team when the workload is modest and the risks are understood. As the environment grows, separate the database, file storage, Remote Desktop roles, or application tiers when performance, security, or recovery requirements justify it. Do not add complexity only because larger companies use it. Start with the simplest architecture that meets the business requirement and can be backed up and restored reliably. ## Remote Desktop planning for construction teams Remote Desktop is often the access layer for hosted Windows business software. Microsoft describes Remote Desktop Services as a Windows Server platform for delivering managed desktops and applications to users in offices, homes, branches, and partner locations. For a small construction company, the important distinction is between administrative Remote Desktop access and staff using the server as their daily workspace. When employees use an RD Session Host for desktops or applications, Microsoft states that each connecting user or device needs a Remote Desktop Services Client Access License. Plan: - expected active users; - per-user or per-device RDS licensing; - named accounts rather than shared logins; - RD Gateway, VPN, or another controlled access model; - firewall restrictions; - session timeouts; - clipboard, drive, printer, and device redirection; - user-profile storage; - application compatibility in multi-user sessions; - support ownership. Use these related guides: - [Remote Desktop Server for Business](https://rafftechnologies.com/windows-server/remote-desktop-server-for-business) - [Windows VPS for Remote Employees](https://rafftechnologies.com/windows-server/windows-vps-remote-employees) - [Remote Desktop Gateway vs Direct RDP](https://rafftechnologies.com/windows-server/remote-desktop-gateway-vs-direct-rdp) - [RDS CAL Licensing on Windows Server](https://rafftechnologies.com/windows-server/rds-cal-licensing-guide) :::cta Talk to Windows Engineer Plan users, software, storage, backups, and migration before launch. ::: ## Multiple offices, warehouses, and job sites A construction company may have a head office, branch office, warehouse, yard, temporary project office, and employees working from home. Maintaining a separate file copy or application install at every location creates support problems. A centralized Windows VPS can help by giving authorized users access to the same: - business applications; - company database; - project folders; - templates; - reports; - mapped drives; - archived records; - administrative tools. The user experience still depends on internet quality and latency. A job site with unstable connectivity may need a fallback plan for critical documents or workflows. Read [Windows VPS for Multi-Location Small Businesses](https://rafftechnologies.com/windows-server/windows-vps-multi-location-business) for the broader branch-office model. ## Printers, scanners, plotters, USB devices, and licensing dongles Peripheral dependencies are one of the most common migration surprises. Construction workflows may involve: - office printers; - large-format plotters; - scanners; - label printers; - local USB storage; - signature devices; - serial devices; - hardware licensing dongles; - specialized measurement or takeoff hardware. Test each critical device before production. | Dependency | Planning question | |---|---| | Printer | Does it work through Remote Desktop redirection or a network print server? | | Plotter | Are the driver, page size, spool size, and application workflow supported? | | Scanner | Does the application need direct TWAIN/WIA access or can files be uploaded separately? | | USB device | Does the device support redirection or network access? | | License dongle | Does the vendor permit hosted use or offer a network-license option? | | Local folder | Can the workflow use a server folder instead? | | Email integration | Does the application support the installed Outlook or mail configuration? | A Windows VPS migration should not be approved because the application opens successfully. The actual end-to-end workflow must work. ## CAD, BIM, Revit, and graphics-heavy workloads A standard Windows VPS is not automatically a replacement for a high-end engineering workstation. Treat the following as specialized workloads: - large AutoCAD files; - Revit and BIM models; - 3D coordination; - rendering; - point-cloud processing; - GPU acceleration; - very large image or plan sets; - latency-sensitive interactive graphics. These workloads may require dedicated GPU resources, specialized remote-display technology, high storage throughput, or a different workstation model. A construction company can still use a Windows VPS for the surrounding business workflows—estimating, accounting, ERP, reports, shared folders, and administration—while keeping GPU-heavy design work on specialized infrastructure. That hybrid model is often more practical than forcing every workload onto one server. ## Security planning for construction company data Construction servers may contain contracts, financial records, payroll data, project pricing, subcontractor information, drawings, credentials, and internal documents. Minimum planning should include: | Security area | Recommendation | |---|---| | User accounts | Use named users and remove shared credentials | | Administrative access | Separate administrator accounts from daily accounts | | Remote access | Avoid unrestricted public RDP exposure | | Firewall rules | Restrict ports and source addresses where practical | | Permissions | Use role-based access and least privilege | | Project folders | Limit access by project, department, or responsibility | | Offboarding | Remove accounts and review access immediately | | Updates | Patch Windows and supported applications deliberately | | Endpoint security | Use appropriate anti-malware and monitoring controls | | Logs | Review failed sign-ins and unusual access patterns | | Backups | Restrict deletion and protect recovery credentials | | Documentation | Record server owners, users, apps, shares, and recovery steps | Security is not complete when the server is deployed. It depends on daily administration, access review, patching, user behavior, backup protection, and incident response. ## Backup and recovery planning Project documents and business applications should not depend on one server state. A practical protection model includes: | Protection layer | Purpose | |---|---| | Application-aware backup | Protect databases and application data correctly | | File-level backup | Restore deleted or changed documents | | VM backup | Recover the broader server environment | | Snapshot before changes | Create a rollback point before updates or migrations | | Off-server copy | Reduce risk from account, VM, or ransomware incidents | | Retention policy | Keep recovery points for the required period | | Restore test | Prove that files, apps, and databases can be recovered | | Recovery documentation | Define owners, credentials, steps, and priorities | A snapshot is useful before a risky change, but it is not the entire backup strategy. Backups need retention, separation, monitoring, and restore testing. Use [Windows VPS Backup Strategy for Small Businesses](https://rafftechnologies.com/windows-server/windows-vps-backup-strategy-small-business) before moving production construction data. :::cta Explore Data Protection Protect project files, app data, and recovery points. ::: ## Sizing a Windows VPS for a construction company Do not size only by total employee count. Size by active concurrent users, software requirements, database activity, reports, file volume, and growth. Use this as an initial planning range, not a guarantee: | Construction workload | Starting size | When to increase resources | |---|---:|---| | Solo estimator or admin workload | 2 vCPU / 4 GB RAM | If the app, PDFs, browser, or reports compete for memory | | 2-3 light users | 4 vCPU / 8 GB RAM | If several apps and documents stay open simultaneously | | 3-5 active users | 4 vCPU / 16 GB RAM | Better for shared business apps and RDS sessions | | 5-10 active users | 8 vCPU / 32 GB RAM | Useful when the server becomes a daily shared workspace | | ERP or SQL-backed app | 8-16 vCPU / 32-64 GB RAM | Depends on database size, reports, transactions, and vendor guidance | | Document-heavy environment | Size storage separately | Project archives, scans, photos, plans, and exports grow quickly | | Heavy CAD/BIM/rendering | Specialized assessment | Standard VPS sizing may not be appropriate | Plan storage for: - application installation; - databases; - project folders; - estimates and bid archives; - contracts and change orders; - drawings and PDFs; - photos and reports; - user profiles; - exports and temporary files; - logs; - backups; - migration staging; - 12 to 24 months of growth. Raff Volumes can add block storage independently from the VM lifecycle, but storage architecture, backup scope, and application paths should be planned before attaching production data. Read [Windows VPS Sizing for Remote Users](https://rafftechnologies.com/windows-server/windows-vps-sizing-remote-users) for more detailed user-based planning. ## Pricing factors construction companies should include The monthly VM price is only one part of the decision. | Cost factor | Why it matters | |---|---| | CPU and RAM | Active users, reports, apps, and database activity | | Storage | Project files, archives, photos, drawings, and growth | | Backups | Frequency, retention, storage, monitoring, and restore tests | | Windows licensing | Depends on the provider and deployment model | | RDS licensing | Staff desktop or RemoteApp sessions may require CALs | | Application licensing | Vendor rules may change in hosted or multi-user environments | | SQL Server licensing | Applies when the software uses SQL Server | | Migration work | Inventory, testing, data transfer, cutover, and rollback | | Support | Windows, RDS, app, printing, and device troubleshooting | | Security | Hardening, monitoring, access review, and incident response | | Recovery target | Faster recovery may require stronger architecture and process | A low-cost server is not a good deal if estimators cannot access the application, project files are slow, backups are untested, or the vendor will not support the deployment. Use [Windows VPS Pricing Explained](https://rafftechnologies.com/windows-server/windows-vps-pricing-explained) before budgeting the full environment. :::cta View Pricing Compare plans for users, apps, storage, and backups. ::: ## Migration path for a construction company A safe migration should be side by side rather than a rushed lift-and-shift. ### 1. Inventory the current environment Document: - applications and versions; - databases; - users and groups; - file shares and permissions; - mapped drives; - printers, scanners, and plotters; - USB devices and licensing dongles; - scheduled tasks and Windows services; - integrations; - storage usage; - backup jobs; - recovery requirements; - support contacts and vendor terms. ### 2. Confirm software and license support Ask each vendor: - Is Windows Server supported? - Is Remote Desktop Services supported? - Is cloud-hosted deployment permitted? - Are multiple concurrent users supported? - Which database version is required? - Are printers, scanners, plotters, or dongles supported? - Does the vendor support the application after migration? ### 3. Build a test environment Create the Windows VPS, install the application, restore a copy of the data, and test representative workflows. Do not test with only an administrator account. Test with the real roles that will use the system. ### 4. Configure access and protection Before production: - create named users; - configure groups and permissions; - restrict remote access; - configure the firewall; - plan RDS licensing; - configure backups; - create a snapshot before major changes; - document recovery steps. ### 5. Test full workflows Test: - login; - application launch; - estimate creation; - report generation; - database access; - file open/save; - mapped drives; - printing and plotting; - scanning or uploads; - email or export functions; - multi-user behavior; - remote performance; - backup and restore. ### 6. Schedule cutover Choose a low-risk window. Avoid a major bid deadline, payroll run, billing cycle, audit, or critical project milestone. Run the final backup and data sync, validate the new environment, release users gradually, and keep the old system available until final approval. ### 7. Monitor after migration Track: - CPU and RAM usage; - disk capacity; - database performance; - login delays; - application errors; - printing issues; - backup success; - support tickets; - user feedback. Use: - [Windows Server Migration Checklist for Small Businesses](https://rafftechnologies.com/windows-server/windows-server-migration-checklist-small-business) - [Local Server to Cloud Windows VPS Migration](https://rafftechnologies.com/windows-server/local-server-to-cloud-windows-vps-migration) - [File Server Migration to Windows VPS](https://rafftechnologies.com/windows-server/file-server-migration-to-windows-vps) ## When a Windows VPS is not the right fit A Windows VPS is useful, but it should not be forced into every construction workflow. ![Decision infographic comparing construction workloads suited to a Windows VPS with CAD, BIM, Revit, rendering, and GPU workloads that may require specialized infrastructure](https://raff-images.s3.raffusercloud.com/windows_vps_construction_companies_webp_3ba9c6bbb6.png) Pause when: | Situation | Better next step | |---|---| | Heavy CAD, BIM, Revit, or rendering is the main workload | Evaluate GPU-enabled or specialized workstation infrastructure | | Software vendor does not support Windows Server or RDS | Use a supported platform or replace the application | | Critical workflow depends on unsupported USB hardware | Keep the workload local or use a hybrid design | | Job-site internet is unreliable | Improve connectivity and plan offline access | | The company already uses browser-based SaaS successfully | Avoid adding a server without a clear need | | Large files require constant local transfer | Test latency and storage workflow before migration | | High availability is mandatory | Design redundancy and failover rather than relying on one VM | | Security ownership is unclear | Assign operational responsibility before launch | | Backups cannot be tested | Do not move production data yet | | Licensing remains unresolved | Resolve vendor and Microsoft requirements first | The correct answer may be a Windows VPS, local server, SaaS platform, specialized GPU environment, or hybrid architecture. ## How Raff fits construction companies Raff fits construction companies that need a cloud-hosted Windows Server foundation for estimating, accounting, job costing, ERP, project documents, shared folders, reports, remote employees, and office-server replacement. Raff provides Windows VMs with administrator and RDP access, flexible compute sizing, NVMe storage, optional attached Volumes, snapshots, scheduled backups, networking controls, and human support. The company or MSP should still plan: - application compatibility; - vendor licensing; - RDS CAL requirements; - user roles and offboarding; - project-folder permissions; - printer and plotter testing; - backup retention; - restore testing; - security hardening; - migration and rollback; - specialized CAD or GPU requirements. That is the right way to use Raff: as the Windows infrastructure foundation, not as a substitute for application ownership, licensing review, or business-process planning. :::cta Deploy Windows Now Launch a Raff Windows VM for your construction workload. ::: ## Recommended path by construction-company situation | Situation | Read next | |---|---| | You need the broad SMB decision guide | [Windows VPS Hosting for Small Businesses](https://rafftechnologies.com/windows-server/windows-vps-small-business) | | Remote staff need a shared Windows workspace | [Remote Desktop Server for Business](https://rafftechnologies.com/windows-server/remote-desktop-server-for-business) | | Employees work from home or project sites | [Windows VPS for Remote Employees](https://rafftechnologies.com/windows-server/windows-vps-remote-employees) | | Several offices need the same environment | [Windows VPS for Multi-Location Small Businesses](https://rafftechnologies.com/windows-server/windows-vps-multi-location-business) | | ERP or inventory is the main workload | [Windows VPS for ERP and Inventory Software](https://rafftechnologies.com/windows-server/windows-vps-erp-inventory-software) | | Project files are the main problem | [Windows VPS as a Cloud File Server](https://rafftechnologies.com/windows-server/windows-vps-cloud-file-server) | | You need backup planning | [Windows VPS Backup Strategy for Small Businesses](https://rafftechnologies.com/windows-server/windows-vps-backup-strategy-small-business) | | You are replacing local hardware | [7 Signs You Have Outgrown Your Office Server](https://rafftechnologies.com/windows-server/replace-office-server-small-business) | | You are planning migration | [Windows Server Migration Checklist for Small Businesses](https://rafftechnologies.com/windows-server/windows-server-migration-checklist-small-business) | | You need pricing clarity | [Windows VPS Pricing Explained](https://rafftechnologies.com/windows-server/windows-vps-pricing-explained) | | You need sizing guidance | [Windows VPS Sizing for Remote Users](https://rafftechnologies.com/windows-server/windows-vps-sizing-remote-users) | ## Final construction-company checklist Before moving construction workloads to a Windows VPS, confirm: | Check | Done | |---|---| | Applications and versions inventoried | ☐ | | Vendor support for Windows Server checked | ☐ | | Hosted and RDS licensing reviewed | ☐ | | Active users and roles estimated | ☐ | | CPU, RAM, and storage starting point chosen | ☐ | | Database requirements documented | ☐ | | Project folders and mapped drives documented | ☐ | | File permissions reviewed | ☐ | | Printers, scanners, and plotters tested | ☐ | | USB devices and dongles reviewed | ☐ | | CAD/BIM/GPU workloads separated where needed | ☐ | | Remote-access model chosen | ☐ | | Firewall and security controls planned | ☐ | | Backup layers defined | ☐ | | Restore test completed | ☐ | | Migration window selected | ☐ | | Rollback path documented | ☐ | | Support owner assigned | ☐ | If the checklist is incomplete, treat the environment as a test system rather than production. ## What's next - Explore [Raff Windows VM](https://rafftechnologies.com/products/windows-vm) when you are ready to compare Windows VM options. - Review [Raff pricing](https://rafftechnologies.com/pricing) before choosing CPU, RAM, storage, and monthly cost. - Read [Windows VPS Hosting for Small Businesses](https://rafftechnologies.com/windows-server/windows-vps-small-business) for the broader decision guide. - Read [Windows VPS for ERP and Inventory Software](https://rafftechnologies.com/windows-server/windows-vps-erp-inventory-software) when operations software is the main workload. - Read [Windows VPS for Multi-Location Small Businesses](https://rafftechnologies.com/windows-server/windows-vps-multi-location-business) when branches or project offices need centralized access. - Read [Windows VPS Backup Strategy for Small Businesses](https://rafftechnologies.com/windows-server/windows-vps-backup-strategy-small-business) before moving production project data. - Read [Local Server to Cloud Windows VPS Migration](https://rafftechnologies.com/windows-server/local-server-to-cloud-windows-vps-migration) before replacing an office server. - Read [Windows VPS Sizing for Remote Users](https://rafftechnologies.com/windows-server/windows-vps-sizing-remote-users) before selecting the production plan. ## Sources - Raff — [Windows VM product page](https://rafftechnologies.com/products/windows-vm) - Raff Docs — [Virtual Machines](https://docs.rafftechnologies.com/products/build/virtual-machines) - Raff Docs — [Plans and sizing](https://docs.rafftechnologies.com/products/build/virtual-machines/concepts/plans-and-sizing) - Raff Docs — [Attach a Volume to a VM](https://docs.rafftechnologies.com/products/store/volumes/quickstart-guides/attach-to-vm) - Microsoft Learn — [Remote Desktop Services overview in Windows Server](https://learn.microsoft.com/en-us/windows-server/remote/remote-desktop-services/overview) - Microsoft Learn — [License Remote Desktop Services with Client Access Licenses](https://learn.microsoft.com/en-us/windows-server/remote/remote-desktop-services/rds-client-access-license) - Microsoft Learn — [Remote Desktop Services: choose how you pay](https://learn.microsoft.com/en-us/windows-server/remote/remote-desktop-services/rds-plan-choose-how-you-pay) - Microsoft Learn — [Windows Server Backup command reference](https://learn.microsoft.com/en-us/windows-server/administration/windows-commands/windows-server-backup-command-reference) --- ### Windows VPS for Manufacturing Businesses: ERP and Files URL: https://rafftechnologies.com/windows-server/windows-vps-manufacturing-businesses Description: Learn when a Windows VPS fits manufacturing businesses that need ERP, inventory, shared files, remote access, backups, and a hybrid plant-cloud design. A Windows VPS for manufacturing businesses is a cloud-hosted Windows Server that centralizes office-facing manufacturing software, databases, files, and remote user sessions. It fits ERP, MRP, inventory, purchasing, accounting, reporting, and administrative workflows when the software vendor supports Windows Server. Raff Technologies recommends keeping PLC, CNC, SCADA, and other hardware-bound plant control local unless every dependency has been tested. For the broader small-business decision, read [Windows VPS Hosting for Small Businesses](https://rafftechnologies.com/windows-server/windows-vps-small-business). ## Windows VPS for manufacturing businesses: quick verdict A Windows VPS is strongest on the office and management side of manufacturing. It is weaker when the workload directly controls physical equipment. | Manufacturing situation | Windows VPS fit | Reason | |---|---|---| | ERP or MRP software runs on Windows Server | Strong fit after vendor confirmation | The application, database, reports, and users can share one hosted environment. | | Office staff need the same inventory and purchasing data | Strong fit | Central access reduces separate installs and duplicated files. | | Managers need access from another plant, warehouse, or home | Strong fit with remote-access planning | Users can reach the same Windows applications and reports. | | An aging factory-office server hosts business software | Strong fit after dependency review | The business can move away from one physical server without replacing the application. | | Production reports and quality documents are scattered | Good fit | Shared folders, permissions, and backups can be centralized. | | The application depends on SQL Server | Good fit with database sizing | Database memory, storage, maintenance, and backups must be planned. | | Label printers and barcode scanners are essential | Test before production | Redirection, drivers, network paths, and application behavior vary. | | PLC, CNC, SCADA, or machine control is the main workload | Keep local or use a designed hybrid architecture | Physical-process systems have different safety, reliability, and latency requirements. | | Production must continue through an internet outage | Hybrid or local design required | A cloud-only workflow creates a connectivity dependency. | | Heavy CAD, simulation, or rendering is the main workload | Specialized assessment | GPU, display protocol, storage throughput, and file size may exceed a standard VPS. | The best candidate is a small or midsize manufacturer with Windows-based business software tied to an office or plant server. The company wants remote access, central data, simpler server management, and tested recovery without redesigning every application as SaaS. A manufacturing company should not move its entire plant into one cloud VM. The practical goal is to separate workloads by function: centralize the business systems that benefit from shared access, while protecting the operational technology that depends on local equipment, deterministic response, or continued operation during an internet outage. ## Manufacturing workloads should be separated into IT and OT The first decision is not server size. It is workload classification. Information technology (IT) supports business operations such as accounting, ERP, purchasing, reporting, email, shared files, and employee access. Operational technology (OT) monitors or controls physical processes and equipment. OT can include programmable logic controllers (PLCs), supervisory control and data acquisition (SCADA), distributed control systems, industrial PCs, sensors, and machine interfaces. [NIST SP 800-82 Revision 3](https://csrc.nist.gov/pubs/sp/800/82/r3/final) treats OT as a distinct security and reliability domain because it interacts with the physical environment. That distinction matters when planning a Windows VPS. Raff Technologies' default recommendation is simple: - move office-facing applications first; - keep machine control local; - document every integration between the two; - add connectivity only where the business case is clear; - test failure behavior before production. A safe first phase may move ERP clients, purchasing, accounting, document storage, reports, and remote administration. It should not automatically move PLC programming stations, machine-control databases, serial-device gateways, or production systems that must remain available when the WAN is down. This separation gives the business a useful cloud environment without turning a server migration into an unplanned OT redesign. ## Office-facing manufacturing workloads are the strongest fit Manufacturing businesses often rely on Windows software that sits between general office tools and plant operations. These workloads can fit a Windows VPS when the vendor supports the deployment model. ### ERP, MRP, and production-planning applications Enterprise resource planning (ERP) connects finance, purchasing, inventory, sales, and operations. Material requirements planning (MRP) focuses more directly on materials, bills of materials, production demand, scheduling, and purchasing requirements. A Windows VPS can host these applications when: - the vendor supports Windows Server; - hosted or virtualized use is permitted; - Remote Desktop Services is supported where needed; - the application database is supported in the chosen layout; - integrations can reach the required endpoints; - backups can protect both the application and its data; - plant devices are not assumed to work without testing. The existing [Windows VPS for ERP and Inventory Software](https://rafftechnologies.com/windows-server/windows-vps-erp-inventory-software) guide covers the deeper ERP hosting decision. The manufacturing-specific question is broader: which production-office workflows belong in the hosted environment, and which dependencies must stay near the plant floor? ### Inventory, purchasing, and warehouse administration A hosted Windows environment can centralize: - item masters and stock records; - purchase orders; - supplier records; - reorder reports; - receiving administration; - warehouse transfers; - batch or lot documentation; - finished-goods records; - inventory valuation reports; - exported labels and packing documents. This does not guarantee that every scanner or label printer will work remotely. The application may run correctly while the physical workflow fails. Receiving, picking, printing, and correction procedures must be tested from the actual warehouse location. ### Accounting, payroll, and job costing Manufacturers frequently combine an ERP or MRP system with separate accounting, payroll, costing, or reporting software. A Windows VPS can provide one controlled environment for: | Financial workload | Typical need | |---|---| | General ledger | Central access for finance staff | | Accounts payable | Supplier invoices, approvals, and payment files | | Accounts receivable | Customer invoices, credits, and statements | | Payroll | Restricted access for authorized staff | | Standard costing | Material, labor, overhead, and variance analysis | | Job costing | Costs by work order, batch, project, or production run | | Month-end reporting | CPU, RAM, database, and export capacity during peak periods | The server should be sized for active sessions and reporting peaks, not only the number of licensed employees. ### Quality, compliance, and production documents A Windows VPS can also centralize documents that support production without controlling the machinery itself: - standard operating procedures; - work instructions; - inspection forms; - certificates of analysis; - calibration records; - nonconformance records; - corrective-action documents; - training records; - supplier documents; - maintenance reports; - production schedules; - completed batch or work-order files. Shared folders need a deliberate structure. Moving disorganized files to a cloud server only relocates the problem. Clean up duplicate folders, naming rules, permissions, archives, and ownership before migration. ### Reporting and management access Owners, plant managers, finance leads, purchasing teams, and operations managers may need reports without direct access to plant-control systems. A hosted Windows environment can provide access to: - production summaries; - inventory reports; - purchasing dashboards; - financial reports; - order status; - capacity-planning exports; - maintenance documents; - approved quality records. This is a strong reason to separate reporting from control. A manager can reach business information remotely without opening a path directly into the OT network. ## Hardware-bound plant workloads should remain local until proven A cloud Windows Server should not become the default home for systems that directly interact with physical equipment. Keep or test locally when the workload depends on: - PLC communication; - CNC controllers; - SCADA servers; - human-machine interfaces; - machine vision; - serial or fieldbus devices; - real-time data acquisition; - USB licensing dongles; - proprietary PCI hardware; - local sensor gateways; - low-latency machine commands; - safety-related processes; - operation during a WAN outage. The issue is not that cloud infrastructure is inherently unsuitable. The issue is that these systems have different failure consequences. A delayed report is inconvenient. A delayed or unavailable machine-control command can stop production or create a safety risk. CISA's [Secure Connectivity Principles for Operational Technology](https://www.cisa.gov/resources-tools/resources/secure-connectivity-principles-operational-technology-ot) recommends treating connectivity into OT as a deliberate design decision. Manufacturing teams should document why a connection exists, who owns it, how it is secured, and what happens when it fails. A Windows VPS may still support the surrounding workflow. It can host the business application, reporting database, document repository, or remote office desktop while the control system remains local. ## A hybrid plant-cloud design reduces unnecessary risk For many manufacturers, hybrid is not a temporary compromise. It is the correct architecture. A practical pattern looks like this: ![Hybrid manufacturing architecture diagram showing remote managers, finance, purchasing, and other locations accessing a cloud Windows VPS for ERP, database, reports, documents, and backups, while PLC, CNC, SCADA, scanners, printers, and plant-floor workflows remain in the local plant environment](https://raff-images.s3.raffusercloud.com/manufacturing_hybrid_plant_cloud_architecture_webp_6cce6d9b2a.png) The connection between the cloud environment and the plant should carry only the data and services required by the business. Do not create broad network access because it is convenient. A good hybrid design answers five questions: 1. Which system is the source of truth? 2. Which direction does data move? 3. Which ports and identities are required? 4. What happens when the link is unavailable? 5. How is the connection monitored and revoked? Raff recommends proving 5 workflows before cutover: login, transaction entry, printing, backup, and restore. ## Multi-site manufacturing benefits from one business environment A manufacturer may operate a head office, plant, warehouse, service location, or second production site. Separate office servers can create different versions of applications, reports, and files at each location. One Windows VPS can give authorized users access to the same business environment when: - each location has reliable connectivity; - latency is acceptable for the application; - user roles are defined; - printing and scanning have been tested; - database and file access stay inside the hosted environment where practical; - the business has a fallback for connectivity loss. Centralization can reduce version drift and duplicated data. It does not remove the need for site-level procedures. A warehouse may still require local label printing. A plant may need offline work instructions. A second facility may need a separate recovery path. The architecture should follow the workflow, not the organization chart. ## Remote access should match manufacturing user roles Remote Desktop Services (RDS) can deliver managed Windows desktops and applications to users in offices, homes, branches, and partner locations. Microsoft describes this model in its [Remote Desktop Services overview](https://learn.microsoft.com/en-us/windows-server/remote/remote-desktop-services/overview). Manufacturing users do not all need the same access. | User role | Likely access need | |---|---| | Owner or director | Reports, approvals, and dashboards | | Plant manager | Production reports, schedules, and documents | | Finance team | Accounting, costing, payroll, and exports | | Purchasing team | Suppliers, purchase orders, and material planning | | Inventory administrator | Stock records, transfers, and adjustments | | Sales or customer service | Order status, availability, and customer records | | IT or MSP | Administration, patching, monitoring, and recovery | | Machine operator | Often local application or kiosk access rather than full remote desktop | Use named accounts. Separate administrator credentials from daily user accounts. Restrict clipboard, drive, printer, and device redirection based on the workflow rather than enabling everything by default. If employees use an RD Session Host for daily desktop or application sessions, Microsoft states that each connecting user or device needs an [RDS Client Access License](https://learn.microsoft.com/en-us/windows-server/remote/remote-desktop-services/rds-client-access-license). Administrative RDP sessions are not a substitute for a licensed multi-user deployment. ## Printers, scanners, and shop-floor devices require full workflow tests Device behavior is one of the most common reasons a technically successful migration fails operationally. Manufacturing workflows may depend on: - label printers; - barcode scanners; - document scanners; - scales; - signature pads; - USB dongles; - serial devices; - network printers; - local folders used by import tools; - email or PDF export components. Test the entire process, not only whether Windows recognizes the device. | Device or dependency | Test before approval | |---|---| | Label printer | Correct driver, label size, template, queue, and print speed | | Barcode scanner | Input mode, focus behavior, session mapping, and application validation | | Document scanner | TWAIN/WIA requirement, upload method, resolution, and file path | | Network printer | Reachability, permissions, driver compatibility, and spool behavior | | USB license dongle | Vendor permission, redirection support, and network-license alternatives | | Serial device | Gateway method, latency, reconnection, and failure behavior | | Scale or measurement device | Data interface, local service, and application integration | | Export folder | Path, permissions, file naming, and downstream pickup process | Microsoft documents printer and drive redirection as configurable Remote Desktop features, and its troubleshooting guidance shows that policy and client settings can prevent redirection even when the session itself works. Treat every device as a separate acceptance test. ## Database and integration planning determine real performance The visible Windows application may not be the main resource consumer. The database, reports, imports, and integrations can create more load than the desktop sessions. Document: - database engine and version; - database size and growth rate; - peak transaction periods; - month-end and year-end reporting; - scheduled imports and exports; - EDI jobs; - label-generation services; - API integrations; - mapped-drive dependencies; - service accounts; - scheduled tasks; - antivirus exclusions approved by the vendor; - backup windows; - maintenance jobs; - log growth; - recovery model and restore process. A small application can still have a demanding database. Ten light users may create less load than one report that scans years of production and inventory data. Keep the application and database close enough to avoid unnecessary network latency. Do not place a file-based database across a slow WAN path. When the database grows or becomes business-critical, consider separating application, Remote Desktop, and database roles. ## Sizing depends on concurrent work, not employee count Do not size a manufacturing Windows VPS by the number of people employed. Size it by the people active at the same time and the work they perform. Use these ranges only as test starting points: | Workload | Initial test size | Increase resources when | |---|---:|---| | One administrator or light reporting user | 2 vCPU / 4 GB RAM | Browser, application, and PDF workloads compete for memory | | 2–3 light office users | 4 vCPU / 8 GB RAM | Several sessions, spreadsheets, and reports run together | | 4–5 active business users | 4 vCPU / 16 GB RAM | ERP client, database, printing, and reports share one VM | | 6–10 active users | 8 vCPU / 32 GB RAM | The server becomes a daily shared workspace | | SQL-backed ERP or MRP | 8–16 vCPU / 32–64 GB RAM | Database working set, reports, and batch jobs need more capacity | | Document-heavy environment | Size storage separately | Drawings, scans, quality records, and archives grow quickly | | GPU-heavy CAD or simulation | Specialized assessment | A standard VPS lacks the required graphics profile | For a 5-user office team, Raff recommends testing 4 vCPU and 16 GB RAM before production. That is a planning point, not a performance guarantee. The application vendor's requirements, database behavior, active sessions, antivirus, integrations, and file growth can change the result. Measure during real workflows: - user logon time; - application launch time; - report duration; - CPU peaks; - available memory; - disk latency; - database waits; - print completion time; - backup duration; - session disconnects; - storage growth. Start with the [Windows VPS sizing guide for remote users](https://rafftechnologies.com/windows-server/windows-vps-sizing-remote-users) when estimating session load. ## Security should separate business access from plant control A manufacturing Windows environment can contain supplier pricing, payroll, customer records, product data, bills of materials, production reports, quality documents, credentials, and remote-access pathways. Minimum controls include: | Security area | Planning requirement | |---|---| | Identities | Named users, strong authentication, and prompt offboarding | | Administration | Separate admin accounts and restricted privileged access | | Remote access | Controlled RDS, RD Gateway, VPN, or private-access design | | Firewall | Permit only required ports and sources | | IT/OT boundary | Separate business systems from machine-control networks | | Permissions | Access by role, department, site, or responsibility | | Service accounts | Document ownership, purpose, and password rotation | | Updates | Planned Windows and application maintenance windows | | Logging | Review failed logons, changes, and unusual access | | Backups | Protect deletion rights and recovery credentials | | Vendor access | Time-bound, approved, and monitored where possible | | Documentation | Record owners, dependencies, recovery steps, and contacts | CISA notes that connections between business systems and OT can create paths for attackers when they are not inventoried and secured. Use segmentation and explicit access rules instead of assuming the plant network is trusted. Do not expose Server Message Block (SMB), database ports, or unrestricted RDP directly to the public internet. Keep remote access narrow and documented. ## Backups must protect applications, data, and recovery knowledge A manufacturing backup plan should protect more than the VM disk. Use layered protection: | Protection layer | Purpose | |---|---| | Application-aware backup | Protect ERP, MRP, SQL Server, and transactional data correctly | | File backup | Recover deleted or changed documents and exports | | VM backup | Recover the wider Windows environment | | Snapshot before change | Create a short-term rollback point before updates or migration | | Off-server copy | Reduce risk from server, account, or ransomware incidents | | Retention policy | Keep recovery points for the required business period | | Restore test | Prove that the application and data are usable | | Recovery documentation | Preserve owners, credentials, order of operations, and dependencies | A green backup job does not prove the factory office can resume work. Restore a database to a test environment. Open the application. Run a report. Confirm permissions. Print a sample label or document. Verify that integrations can reconnect safely. Read the [Windows VPS Backup Strategy for Small Businesses](https://rafftechnologies.com/windows-server/windows-vps-backup-strategy-small-business) before moving production data. ## Internet outages need an operational fallback A cloud-hosted business application depends on connectivity. Manufacturing companies should decide what users do when the plant cannot reach the server. Possible fallback measures include: - local copies of critical work instructions; - offline emergency contact lists; - approved manual receiving or production forms; - locally available safety and quality documents; - queued transactions for later entry; - a secondary internet connection; - cellular failover for office users; - documented recovery priorities; - local operation for machine-control systems; - a defined point at which production pauses. Do not describe the fallback as “we will use mobile data” unless it has been tested from the actual site. Signal strength, carrier congestion, firewall rules, VPN behavior, and data limits can change the result. The business should know whether a one-hour outage delays reporting, stops shipping, prevents material issue, or halts production. That impact determines the architecture and recovery budget. ## Migration should begin with one bounded workflow A manufacturing migration is safer when the first phase has a clear boundary. ### 1. Inventory the current environment Document: - applications and versions; - databases; - Windows services; - users and groups; - file shares and permissions; - printers, scanners, and label devices; - PLC, CNC, SCADA, and machine integrations; - USB and serial dependencies; - scheduled tasks; - EDI, API, and export jobs; - storage usage and growth; - backup jobs; - recovery requirements; - vendor and MSP contacts; - internet and site dependencies. ### 2. Classify each dependency Mark every item as: - cloud candidate; - local plant dependency; - integration between cloud and plant; - unsupported or unknown; - replacement candidate. Unknown dependencies should block production cutover until tested. ### 3. Confirm vendor and license support Ask the application vendor: - Is Windows Server supported? - Is virtual or hosted deployment supported? - Is RDS supported? - Which SQL Server edition and version are required? - Are multiple concurrent users supported? - Are warehouse devices supported through remote sessions? - Is a hardware dongle required? - Does the vendor support the application after migration? ### 4. Build a parallel test environment Install the software on a test Windows VPS. Restore a copy of the data. Create non-admin user accounts. Reproduce representative roles from finance, purchasing, inventory, management, and IT. Do not test only with a fast connection from the head office. Test from the plant, warehouse, second location, and remote user networks. ### 5. Test complete business workflows Validate: - login and authentication; - application launch; - order entry; - purchase order creation; - inventory lookup and adjustment; - production-report access; - report generation; - database performance; - file open and save; - label and document printing; - scanner or upload workflow; - scheduled jobs; - integrations; - backup; - restore; - loss of connectivity; - rollback. ### 6. Schedule a low-risk cutover Avoid month-end, payroll, stock count, major shipment dates, planned maintenance, or peak production runs. Run the final backup and data synchronization. Validate the destination. Release users in a controlled order. Keep the old environment available until the business owner, application owner, and IT owner approve the new workflow. ### 7. Monitor the first production cycle Track performance and support issues through at least one complete operating cycle. That may include a normal production day, a purchasing run, a shipping window, and month-end reporting. Use the [Windows Server Migration Checklist for Small Businesses](https://rafftechnologies.com/windows-server/windows-server-migration-checklist-small-business) to document cutover and rollback. ## A Windows VPS is not the right fit for every manufacturer Pause or choose another architecture when: | Situation | Better next step | |---|---| | Machine control depends on the server | Keep the control workload local and design OT connectivity separately | | Production cannot tolerate WAN loss | Preserve local operation or build tested connectivity redundancy | | The vendor prohibits hosted or RDS deployment | Use a supported model or replace the application | | USB, serial, or proprietary hardware is mandatory | Test a gateway or keep the dependent workload local | | Heavy CAD, simulation, or rendering dominates | Evaluate GPU-enabled or specialized workstation infrastructure | | The database requires high availability | Design database redundancy and failover instead of relying on one VM | | The business already uses a suitable SaaS platform | Avoid adding a Windows server without a clear need | | Security ownership is undefined | Assign system, access, patching, backup, and incident owners first | | Restore testing cannot be completed | Keep the environment in test status | | The IT/OT boundary is undocumented | Complete the dependency and network review before migration | The correct answer may be cloud, local, hybrid, SaaS, specialized GPU infrastructure, or a larger multi-server design. The goal is not to make every workload fit a Windows VPS. The goal is to place each workload where it can be supported and recovered. ## Raff provides the Windows infrastructure foundation Raff fits manufacturing businesses that need a cloud-hosted Windows Server for ERP or MRP clients, inventory administration, purchasing, accounting, reports, shared files, remote office users, and replacement of an aging business server. Raff Windows VMs provide full administrator and Remote Desktop access, selectable Windows Server versions, NVMe storage, optional attached Volumes, backups and snapshots, firewall controls, private networking options, and human support. The manufacturer or its MSP remains responsible for: - application compatibility; - vendor licensing; - RDS licensing; - user roles and offboarding; - database administration; - IT/OT segmentation; - device and printer testing; - backup retention; - restore testing; - Windows and application updates; - migration and rollback; - business continuity; - compliance decisions. Raff should be the infrastructure layer under a documented manufacturing workflow, not a shortcut around vendor support or plant-safety requirements. ## Recommended path by manufacturing situation | Situation | Recommended path | |---|---| | One plant with an aging ERP server | Test the ERP, database, users, printing, backups, and restore on one Windows VPS | | Office staff need remote access | Use a controlled RDS or remote-access design with named users and licensing | | Several plants need the same business system | Centralize the business application, then test site connectivity and local device workflows | | Warehouse devices are critical | Keep device services local or prove redirection and gateway behavior before cutover | | PLC or CNC integration is required | Keep control local and define a narrow, monitored data exchange | | Reports are needed remotely | Publish access to the reporting or business environment without opening the OT network | | SQL Server drives performance | Size around the database working set, reports, jobs, and recovery requirements | | Production must operate offline | Preserve local operational workflows and treat cloud access as a business-system layer | | Heavy CAD or rendering is required | Use specialized graphics infrastructure rather than a standard Windows VPS | ## Final manufacturing Windows VPS checklist Before putting the environment into production, confirm: | Check | Done | |---|---| | Applications and versions inventoried | ☐ | | IT and OT workloads classified | ☐ | | Vendor support for Windows Server confirmed | ☐ | | Hosted and RDS licensing reviewed | ☐ | | Active users and roles documented | ☐ | | Database requirements documented | ☐ | | PLC, CNC, SCADA, and machine links documented | ☐ | | Label printers, scanners, and shop-floor devices tested | ☐ | | USB, serial, and dongle dependencies reviewed | ☐ | | Network flows and firewall rules documented | ☐ | | Internet-outage fallback tested | ☐ | | CPU, RAM, and storage starting point selected | ☐ | | Storage growth estimated | ☐ | | Application-aware backups configured | ☐ | | Off-server recovery copy planned | ☐ | | File and database restores tested | ☐ | | Migration window approved | ☐ | | Rollback path documented | ☐ | | System, security, and recovery owners named | ☐ | | Old environment retained until final approval | ☐ | An incomplete checklist means the system is still a test environment. ## What's next A Windows VPS for manufacturing businesses works best when the company separates business applications from physical-process control, tests real plant workflows, and keeps a rollback path. Read [Windows VPS Hosting for Small Businesses](https://rafftechnologies.com/windows-server/windows-vps-small-business) when you need the broader decision framework. Explore [Raff Windows VM](https://rafftechnologies.com/products/windows-vm) when the ERP, files, users, devices, backups, and hybrid architecture are documented well enough to build a test environment. ## Sources - Microsoft Learn — [Remote Desktop Services overview in Windows Server](https://learn.microsoft.com/en-us/windows-server/remote/remote-desktop-services/overview) - Microsoft Learn — [License Remote Desktop Services with Client Access Licenses](https://learn.microsoft.com/en-us/windows-server/remote/remote-desktop-services/rds-client-access-license) - Microsoft Learn — [Printer redirection and drive redirection troubleshooting](https://learn.microsoft.com/en-us/troubleshoot/windows-server/printing/printer-hard-drive-not-redirect-to-remote-desktop-session) - NIST — [SP 800-82 Revision 3: Guide to Operational Technology Security](https://csrc.nist.gov/pubs/sp/800/82/r3/final) - CISA — [Secure Connectivity Principles for Operational Technology](https://www.cisa.gov/resources-tools/resources/secure-connectivity-principles-operational-technology-ot) - CISA — [Primary Mitigations to Reduce Cyber Threats to Operational Technology](https://www.cisa.gov/resources-tools/resources/primary-mitigations-reduce-cyber-threats-operational-technology) - Raff — [Windows VPS for ERP and Inventory Software](https://rafftechnologies.com/windows-server/windows-vps-erp-inventory-software) - Raff — [Windows VPS Backup Strategy for Small Businesses](https://rafftechnologies.com/windows-server/windows-vps-backup-strategy-small-business) - Raff — [Windows Server Migration Checklist for Small Businesses](https://rafftechnologies.com/windows-server/windows-server-migration-checklist-small-business) - Raff — [Windows VM product page](https://rafftechnologies.com/products/windows-vm) --- ### Windows VPS for Logistics & Distribution: Inventory, Warehouse Access, and Apps URL: https://rafftechnologies.com/windows-server/windows-vps-logistics-distribution-companies Description: Learn when a Windows VPS fits logistics and distribution companies that need inventory systems, warehouse access, remote teams, shared files, and backup planning. A Windows VPS for logistics and distribution companies can centralize inventory software, order processing, customer records, billing, reports, shared documents, and remote user sessions in one cloud-hosted Windows Server environment. It is strongest for the business systems used by management, finance, dispatch, purchasing, customer service, and warehouse administration. It can also support warehouse users when the application vendor allows hosted Windows Server or Remote Desktop Services deployments and every scanner, label printer, scale, carrier integration, and packing workflow has been tested. A Windows VPS should not automatically replace every local warehouse system. Device-heavy packing stations, conveyor controls, serial equipment, proprietary shipping hardware, or workflows that must continue during an internet outage may need a local component or hybrid design. Raff Technologies provides the Windows VM infrastructure. The logistics company or its MSP remains responsible for application support, licensing, RDS CALs, user access, device testing, database administration, backups, security, migration, and recovery. :::cta Explore Windows VM Centralize logistics apps, files, users, and reporting on Windows. ::: ## Windows VPS for logistics companies: quick verdict Use the table below before moving logistics or distribution workloads to a Windows VPS. | Logistics situation | Windows VPS fit | Why | |---|---|---| | Inventory or order-processing software supports Windows Server | Strong fit after vendor confirmation | Applications, databases, reports, and users can share one hosted environment. | | Management needs access from home, another office, or while traveling | Strong fit | Authorized users can reach the same Windows applications and reports remotely. | | Finance, billing, and customer service use the same operational data | Strong fit | Centralization reduces separate installs, exports, and conflicting records. | | Several warehouses or branches use different copies of files | Strong fit with connectivity planning | Users can work from one controlled environment rather than maintaining separate versions. | | An aging office server hosts inventory or shipping software | Strong fit after dependency review | The business can move away from one physical server without immediately replacing the application. | | Barcode scanners and label printers are essential | Test before production | Drivers, redirection, local services, label templates, and application behavior vary. | | Carrier tools require local USB or proprietary hardware | Hybrid or local component may be required | The application may work remotely while the shipping workflow fails. | | Warehouse work must continue through an internet outage | Hybrid or offline-capable design required | A cloud-only system creates a connectivity dependency. | | Conveyor, sortation, or automation control is the main workload | Keep control local | Physical equipment control has different latency, safety, and availability requirements. | | The company already uses a supported browser-based SaaS platform | Depends | A Windows VPS may add complexity without solving a real problem. | The strongest candidate is a small or midsize logistics, wholesale, fulfillment, or distribution company that still relies on Windows business software but needs consistent access across offices, warehouses, branches, and remote staff. The goal is not to move every warehouse device into the cloud. The goal is to centralize the business environment while preserving local workflows that depend on physical equipment or uninterrupted site access. ## Why logistics companies outgrow local Windows servers Many logistics businesses begin with a practical setup: one office server, a shared drive, locally installed inventory software, and several warehouse PCs. That setup becomes harder to manage as the company adds customers, stock locations, users, carriers, branches, delivery routes, and higher order volume. | Common problem | What it looks like in practice | How a Windows VPS can help | |---|---|---| | Inventory software is tied to one office | Remote staff connect through an unreliable VPN or office PC | The supported application can run in one cloud-hosted Windows environment. | | Warehouses use separate spreadsheets or exports | Stock data and order status differ by location | Central users can work from the same application and database. | | Shipping documents are scattered | Labels, manifests, invoices, POD files, and reports live on different PCs | Shared folders and permissions can be centralized. | | The server is aging | Disk, power supply, warranty, and replacement concerns increase | The workload moves away from one physical machine. | | Remote access is inconsistent | Home users, dispatchers, and managers depend on changing VPN or PC conditions | Users connect to a controlled hosted environment. | | Every workstation has a different setup | Application versions, printers, mapped drives, and settings vary | A central environment is easier to standardize and support. | | Backups are unclear | Files are copied occasionally, but database and restore procedures are unproven | Backup layers, retention, and restore testing can be documented. | | Growth requires another hardware purchase | More users and records demand CPU, RAM, and storage | A VM can be resized and extended with attached storage. | The business benefit is not simply replacing a server rack with a cloud server. It is giving authorized teams one controlled place to reach the applications, data, and documents that move orders through the business. ## Logistics workloads that fit a Windows VPS ### Inventory and warehouse-management administration A Windows VPS can host inventory or warehouse-management software when the vendor supports the operating system, hosted deployment, database, and multi-user access model. Potential workloads include: - item and SKU records; - stock balances; - warehouse locations and bins; - receiving administration; - picking and packing records; - transfers between locations; - batch, lot, or serial-number records; - reorder and replenishment reports; - cycle-count administration; - damaged-stock records; - stock valuation reports; - exported labels and packing documents. The server can centralize the application and its data, but it does not guarantee that the physical warehouse workflow will function correctly. Receiving, picking, scanning, label printing, corrections, and returns must be tested from the actual site. Read [Windows VPS for ERP and Inventory Software](https://rafftechnologies.com/windows-server/windows-vps-erp-inventory-software) when the ERP or inventory platform is the primary workload. ### Order processing and customer service Distribution businesses often use Windows applications for the steps between customer demand and warehouse execution. A hosted environment may centralize: - sales orders; - purchase orders; - order status; - allocations and backorders; - customer records; - pricing and discount rules; - credit status; - returns and authorizations; - shipment history; - invoice preparation; - proof-of-delivery documents; - customer-service notes; - reports and exports. Central access can reduce the need to email spreadsheets or export data between departments. It also makes role-based permissions easier to manage than separate application installs on many PCs. ### Dispatch, routing, and delivery administration A Windows VPS can support dispatch and delivery administration when the software is a normal Windows business application rather than a latency-sensitive vehicle-control or automation system. Potential uses include: - dispatch boards; - route planning applications; - delivery schedules; - driver documents; - shipment status reports; - customer delivery windows; - freight documents; - proof-of-delivery archives; - exported route files; - billing and exception reports. Mobile driver applications, telematics platforms, and live tracking systems may remain separate SaaS or vendor-managed systems. The Windows VPS can host the back-office application, integration service, reports, or exported records when the vendor supports that design. ### Finance, billing, and purchasing Logistics companies often combine operational software with separate accounting, billing, purchasing, or payroll applications. | Business workload | Typical use in the hosted environment | |---|---| | Accounts receivable | Customer invoices, credits, statements, and aging reports | | Accounts payable | Supplier and carrier invoices, approvals, and payment files | | Billing | Freight, handling, storage, fulfillment, and accessorial charges | | Purchasing | Purchase orders, supplier records, and replenishment activity | | Payroll | Restricted access for authorized finance staff | | Costing | Margin, freight cost, warehouse cost, and customer profitability reports | | Month-end reporting | Database, CPU, memory, and export capacity during peak periods | The environment should be sized for reporting peaks and database activity, not only the number of employees with licenses. ### Shared documents and operational records Logistics businesses generate large volumes of documents that support the application workflow. A Windows VPS can centralize: - bills of lading; - packing lists; - manifests; - invoices; - delivery notes; - proof-of-delivery files; - customs and import-export records; - customer instructions; - carrier documents; - rate sheets; - warehouse procedures; - safety documents; - claims and damage reports; - exported spreadsheets; - archived reports; - scanned receiving documents. Moving files to a cloud server does not fix poor organization. Clean up duplicate folders, naming rules, access permissions, retention requirements, and archive ownership before migration. Read [Windows VPS as a Cloud File Server](https://rafftechnologies.com/windows-server/windows-vps-cloud-file-server) when shared files are the main problem. ## A practical logistics and warehouse architecture A small or midsize logistics environment may use a hybrid pattern: ![Hybrid logistics architecture showing management, finance, customer service, dispatch, and branch offices accessing a cloud Windows VPS for inventory, order processing, documents, permissions, and backups while barcode scanners, label printers, packing stations, scales, and carrier services remain in the local warehouse environment](https://raff-images.s3.raffusercloud.com/logistics_hybrid_cloud_warehouse_architecture_webp_bb6f80601f.png) The cloud environment becomes the shared business system. The local warehouse keeps the devices and procedures that need to remain close to physical operations. A good design answers six questions: 1. Which system is the source of truth for inventory and orders? 2. Which warehouse devices connect directly to the application? 3. Which services must remain local? 4. What data moves between the warehouse and cloud environment? 5. What happens when the site loses internet access? 6. Who owns recovery when an application, device, or integration fails? Do not create broad network access only because it is convenient. Permit the identities, ports, systems, and data flows that the documented workflow requires. ## Connecting offices, warehouses, and branches A logistics company may operate a head office, one or more warehouses, retail or service branches, remote dispatchers, and staff working from home. A centralized Windows VPS can give authorized users access to the same: - inventory application; - order database; - customer records; - billing tools; - reports; - shared documents; - mapped drives; - templates; - archived records; - administrative utilities. This can reduce application-version drift and separate file copies, but the user experience still depends on connectivity and latency at each site. Test from every important location. A server that feels fast from headquarters may perform differently from a warehouse using congested broadband, fixed wireless, or cellular failover. For every location, document: - primary internet connection; - backup connection; - expected latency; - firewall or VPN requirements; - active user count; - printers and scanners; - local carrier tools; - outage procedure; - support contact; - recovery priority. Read [Windows VPS for Multi-Location Small Businesses](https://rafftechnologies.com/windows-server/windows-vps-multi-location-business) for the broader branch-office model. ## Remote Desktop access should follow user roles Microsoft describes Remote Desktop Services as a Windows Server platform for delivering managed desktops and applications to users in offices, homes, branches, and partner locations. A logistics company should not give every employee the same desktop, permissions, or redirection rights. | User role | Likely access need | |---|---| | Owner or director | Reports, dashboards, approvals, and financial visibility | | Operations manager | Inventory, order status, exceptions, and warehouse reporting | | Dispatcher | Dispatch board, routes, shipment status, and driver documents | | Customer service | Orders, availability, delivery status, returns, and customer records | | Finance team | Billing, accounting, payroll, and reports | | Purchasing team | Suppliers, purchase orders, replenishment, and stock reports | | Warehouse supervisor | Inventory, receiving, picking, packing, and exception workflows | | Warehouse operator | A limited application or task-specific session rather than full desktop access | | MSP or IT provider | Administration, patching, monitoring, backups, and recovery | Use named accounts instead of shared warehouse logins where practical. Separate administrator credentials from daily user accounts. Restrict clipboard, drive, printer, and device redirection based on the workflow. If employees use an RD Session Host for daily desktop or RemoteApp sessions, Microsoft requires an appropriate RDS Client Access License for each connecting user or device. Administrative sessions are not a substitute for a licensed multi-user environment. Use these related guides: - [Remote Desktop Server for Business](https://rafftechnologies.com/windows-server/remote-desktop-server-for-business) - [Windows VPS for Remote Employees](https://rafftechnologies.com/windows-server/windows-vps-remote-employees) - [Remote Desktop Gateway vs Direct RDP](https://rafftechnologies.com/windows-server/remote-desktop-gateway-vs-direct-rdp) - [RDS CAL Licensing on Windows Server](https://rafftechnologies.com/windows-server/rds-cal-licensing-guide) :::cta Talk to Windows Engineer Plan users, devices, storage, backups, and migration before launch. ::: ## Barcode scanners, label printers, scales, and carrier tools need workflow testing Hardware dependencies are one of the biggest reasons a technically successful migration fails in daily operations. A warehouse workflow may involve: - handheld barcode scanners; - USB scanners in keyboard-wedge mode; - network-connected scanners; - thermal label printers; - office and laser printers; - document scanners; - scales; - signature pads; - USB licensing dongles; - serial devices; - carrier desktop clients; - local browser extensions; - watched folders; - local services that generate labels or manifests. Remote Desktop can redirect some local resources and peripherals, but policy, client settings, drivers, application behavior, and the device communication method all affect the result. Test the complete process, not only whether Windows detects the hardware. | Device or dependency | Acceptance test | |---|---| | Barcode scanner | Scan mode, correct characters, focus behavior, prefixes or suffixes, and application validation | | Label printer | Driver, label size, template, queue, print speed, darkness, and barcode readability | | Document scanner | TWAIN or WIA requirement, upload path, resolution, naming, and multi-page workflow | | Network printer | Reachability, permissions, driver compatibility, spool behavior, and failover | | Shipping scale | Local service, serial or USB interface, unit handling, and application integration | | Signature pad | Vendor support, redirection method, session behavior, and data capture | | USB dongle | Vendor permission, network-license option, and redirection support | | Carrier application | Supported Windows Server version, user context, updates, browser component, and printer integration | | Watched folder | Path, permissions, naming, pickup timing, and recovery after disconnection | | Export or import job | File format, schedule, service account, error handling, and duplicate prevention | Microsoft documents printer, drive, USB, clipboard, and other peripheral redirection as configurable RDP capabilities. A policy or client configuration can block a resource even when the session itself works. Zebra also documents scanner behavior and remote-management options for supported hardware. That does not make every model or workflow automatically compatible. Use the device vendor's documentation for the exact scanner or printer model. ## Inventory databases and integrations determine real performance The visible Windows application may not be the main resource consumer. Inventory databases, order imports, reports, carrier integrations, and scheduled jobs can create more load than user sessions. Document: - database engine and version; - database size and monthly growth; - peak order periods; - receiving and shipping peaks; - concurrent users; - report schedules; - import and export jobs; - EDI processes; - carrier integrations; - API services; - label-generation services; - mapped-drive dependencies; - service accounts; - scheduled tasks; - backup windows; - database maintenance; - transaction-log growth; - recovery model; - restore process. A ten-user application can still need significant resources when a report scans years of order history or a batch job imports thousands of transactions. Keep the application and database close to each other. Avoid placing a file-based database across a wide-area network path. If the database becomes large or business-critical, consider separating Remote Desktop, application, and database roles. SQL Server backups should be planned around the chosen recovery model and verified through actual restore tests. A VM-level backup alone does not replace application-aware database protection. ## Size for concurrent workflows, not total employees Do not size a logistics Windows VPS by total staff count. Size it by concurrent sessions, application requirements, database activity, reports, integrations, and file growth. Use the following only as initial test ranges: | Workload | Initial test size | Increase resources when | |---|---:|---| | One administrator or reporting user | 2 vCPU / 4 GB RAM | The app, browser, PDF tools, and reports compete for memory | | 2-3 light office users | 4 vCPU / 8 GB RAM | Several sessions and documents stay open together | | 4-5 active business users | 4 vCPU / 16 GB RAM | Inventory app, database, printing, and reports share one VM | | 6-10 active users | 8 vCPU / 32 GB RAM | The server becomes a daily shared workspace | | SQL-backed inventory or ERP system | 8-16 vCPU / 32-64 GB RAM | Database working set, reports, imports, and integrations need more capacity | | Document-heavy operation | Size storage separately | POD files, scans, manifests, labels, reports, and archives grow quickly | | High-availability requirement | Multi-server assessment | One VM does not provide application-level failover | For a five-user office or dispatch team, 4 vCPU and 16 GB RAM can be a reasonable test starting point. It is not a performance guarantee. Measure during representative workflows: - user logon time; - application launch time; - order lookup and save time; - inventory query time; - report duration; - CPU peaks; - available memory; - disk latency; - database waits; - label generation time; - print completion time; - import and export duration; - backup duration; - session disconnects; - storage growth. Read [Windows VPS Sizing for Remote Users](https://rafftechnologies.com/windows-server/windows-vps-sizing-remote-users) before choosing a production plan. ## Plan storage around database and document growth Logistics environments can grow faster than expected because application data and operational documents expand at different rates. Plan capacity for: - Windows and application installation; - inventory or ERP database; - transaction logs; - customer and supplier documents; - scanned receiving files; - labels and manifests; - proof-of-delivery archives; - exports and imports; - user profiles; - temporary report files; - integration logs; - backup staging; - migration copies; - 12 to 24 months of growth. Keep system, database, documents, and backups logically separated where the application supports it. Attached Raff Volumes can add block storage without using VM resize only to gain disk space, but volume layout and backup scope should be designed before moving production data. ## Security must protect customer, inventory, and shipping data A logistics Windows environment may contain customer records, addresses, pricing, invoices, supplier data, stock records, shipment history, credentials, and remote-access pathways. Minimum controls include: | Security area | Planning requirement | |---|---| | Identities | Named users, strong authentication, and prompt offboarding | | Administration | Separate privileged accounts and restrict administrator access | | Remote access | Use a controlled RDS, RD Gateway, VPN, or private-access design | | Firewall | Permit only required ports and sources | | Permissions | Limit access by role, warehouse, department, customer, or responsibility | | Warehouse stations | Use task-specific accounts and avoid unnecessary administrator rights | | Service accounts | Document purpose, ownership, permissions, and credential rotation | | Updates | Plan Windows, application, carrier-client, and device-driver maintenance | | Logging | Review failed logons, changes, and unusual access | | Backups | Protect backup deletion rights and recovery credentials | | Vendor access | Make access approved, time-bound, and monitored where possible | | Documentation | Record owners, dependencies, recovery order, and support contacts | Do not expose unrestricted RDP, SMB, or database ports directly to the public internet. Use explicit access rules instead of assuming that every office or warehouse network is trusted. ## Backups must protect the application, database, files, and recovery process A logistics backup plan needs more than a copy of the Windows disk. Use layered protection: | Protection layer | Purpose | |---|---| | Application-aware database backup | Protect inventory, orders, billing, and transactional data correctly | | File backup | Recover deleted or changed labels, manifests, scans, reports, and documents | | VM backup | Recover the broader Windows environment | | Snapshot before change | Create a short-term rollback point before updates or migration | | Off-server copy | Reduce risk from server, account, or ransomware incidents | | Retention policy | Preserve recovery points for the required business period | | Restore test | Prove that applications, data, permissions, and workflows are usable | | Recovery documentation | Preserve owners, credentials, sequence, dependencies, and contacts | A successful backup notification does not prove the operation can resume. Restore the database to a test environment. Open the application. Confirm inventory and order records. Run a report. Test user permissions. Print a sample label or packing document. Validate integrations and scheduled jobs. Raff VMs support scheduled backups and point-in-time snapshots, but application owners still need to define database protection, retention, off-server copies, and restore procedures. Read [Windows VPS Backup Strategy for Small Businesses](https://rafftechnologies.com/windows-server/windows-vps-backup-strategy-small-business) before moving production logistics data. :::cta Explore Data Protection Protect logistics applications, databases, files, and recovery points. ::: ## Internet outages require a warehouse fallback A cloud-hosted business application depends on site connectivity. Logistics companies should define what happens when a warehouse cannot reach the server. Possible fallback measures include: - a secondary internet connection; - cellular failover; - locally available emergency contacts; - approved manual receiving forms; - approved manual shipping forms; - locally cached work instructions; - printed pick lists for limited scenarios; - queued transactions for later entry; - local access to carrier emergency procedures; - a process for reconciling offline activity; - a defined point at which shipping or receiving pauses. Do not assume that mobile data is a recovery plan until it has been tested from the actual warehouse. Building construction, signal strength, carrier congestion, VPN behavior, firewall rules, and data limits can change the result. The business should know whether a one-hour outage delays management reports, stops label printing, blocks receiving, prevents shipment confirmation, or halts the whole warehouse. That impact determines the connectivity and recovery design. ## Migration should start with one bounded workflow A logistics migration is safer when the first phase has a clear scope. ### 1. Inventory the current environment Document: - applications and versions; - databases; - users and groups; - file shares and permissions; - mapped drives; - warehouse and branch locations; - scanners and printers; - scales and serial devices; - carrier software; - USB and licensing dongles; - scheduled tasks and services; - imports, exports, EDI, and APIs; - storage usage and growth; - backup jobs; - internet connections; - outage procedures; - recovery requirements; - vendor and MSP contacts. ### 2. Classify every dependency Mark each item as: - cloud candidate; - local warehouse dependency; - integration between cloud and warehouse; - unsupported or unknown; - replacement candidate. Unknown dependencies should block production cutover until they are tested. ### 3. Confirm vendor and licensing support Ask the application vendor: - Is Windows Server supported? - Is virtual or hosted deployment supported? - Is Remote Desktop Services supported? - Which database edition and version are required? - Are multiple concurrent users supported? - Are label printers, scanners, scales, and carrier tools supported remotely? - Does the product require a USB dongle or local service? - Will the vendor support the application after migration? ### 4. Build a parallel test environment Create a test Windows VPS, install the software, restore a copy of the data, and create non-administrator accounts for representative roles. Test from the office, warehouse, branch, and remote-user networks. Do not approve the environment based only on an administrator session from headquarters. ### 5. Validate complete workflows Test: - login and authentication; - application launch; - order entry and lookup; - inventory lookup and adjustment; - receiving workflow; - picking and packing workflow; - label printing; - document printing; - scanner input; - scale integration; - carrier export or client workflow; - report generation; - file open and save; - imports and exports; - scheduled jobs; - backup; - database restore; - loss of connectivity; - rollback. ### 6. Schedule a low-risk cutover Avoid month-end, stock counts, holiday peaks, major promotions, large customer launches, or critical shipping windows. Run the final backup and data synchronization. Validate the destination. Release users in a controlled order. Keep the previous environment available until the business owner, application owner, warehouse owner, and IT owner approve the new workflow. ### 7. Monitor the first operating cycle Track performance and support issues through normal receiving, picking, packing, shipping, billing, and reporting cycles. Monitor: - CPU and memory; - disk capacity and latency; - database performance; - session disconnects; - application errors; - printer and scanner issues; - integration failures; - backup success; - restore readiness; - support tickets; - user feedback. Use the [Windows Server Migration Checklist for Small Businesses](https://rafftechnologies.com/windows-server/windows-server-migration-checklist-small-business) and [Local Server to Cloud Windows VPS Migration](https://rafftechnologies.com/windows-server/local-server-to-cloud-windows-vps-migration) before production cutover. ## When a Windows VPS is not the right fit A Windows VPS should not be forced into every logistics workflow. | Situation | Better next step | |---|---| | Conveyor, sortation, or automation control depends on the server | Keep the control workload local and design integration separately | | Warehouse work cannot tolerate internet loss | Preserve offline operation or build tested connectivity redundancy | | The vendor prohibits hosted or RDS deployment | Use a supported model or replace the application | | Critical workflow depends on unsupported USB or serial hardware | Keep the dependent component local or use a tested gateway | | Carrier software requires an unsupported local environment | Keep the carrier tool local and integrate through approved files or APIs | | A suitable SaaS WMS, TMS, or ERP already solves the requirement | Avoid adding Windows infrastructure without a clear benefit | | The database requires high availability | Design database redundancy and failover rather than relying on one VM | | Security ownership is undefined | Assign access, patching, backup, and incident owners first | | Restore testing cannot be completed | Keep the environment in test status | | No one owns warehouse outage procedures | Complete operational continuity planning before migration | The right answer may be cloud, local, SaaS, hybrid, or a larger multi-server design. The purpose of planning is to place each workload where it can be supported and recovered. ## How Raff supports logistics and distribution workloads Raff fits logistics and distribution companies that need a cloud-hosted Windows Server foundation for inventory applications, order processing, billing, reporting, shared documents, remote users, and replacement of an aging business server. Raff Windows VMs provide administrator and Remote Desktop access, selectable Windows Server templates, NVMe-backed storage, optional attached Volumes, snapshots, scheduled backups, firewall controls, private networking options, VM resizing, and human support. The logistics company or its MSP remains responsible for: - application compatibility; - vendor licensing; - RDS licensing; - user roles and offboarding; - database administration; - warehouse device testing; - printer and scanner configuration; - carrier integrations; - backup retention; - restore testing; - Windows and application updates; - security hardening; - migration and rollback; - business continuity; - compliance decisions. Raff should be the infrastructure layer under a documented logistics workflow, not a shortcut around application support, device testing, or warehouse continuity planning. ## Recommended path by logistics situation | Situation | Recommended path | |---|---| | One warehouse has an aging inventory server | Test the application, database, users, devices, backups, and restore on one Windows VPS | | Management and finance need remote access | Use a controlled RDS or remote-access design with named users and licensing | | Several warehouses need the same business system | Centralize the application, then test each site's connectivity and device workflow | | Barcode scanners and printers are critical | Test exact models, drivers, templates, queues, and user sessions before cutover | | Carrier software must remain local | Keep the local carrier component and define a narrow, documented integration | | SQL Server drives performance | Size around database memory, reports, jobs, and recovery requirements | | Warehouse operations must work offline | Preserve local procedures or an offline-capable component | | Shared documents are the main problem | Use a structured file-server design with permissions and backup | | High availability is mandatory | Evaluate a multi-server application and database architecture | ## Final logistics Windows VPS checklist Before putting the environment into production, confirm: | Check | Done | |---|---| | Applications and versions inventoried | ☐ | | Vendor support for Windows Server confirmed | ☐ | | Hosted and RDS licensing reviewed | ☐ | | Active users and roles documented | ☐ | | Warehouses, branches, and remote locations documented | ☐ | | Database requirements documented | ☐ | | Barcode scanners tested | ☐ | | Label printers and templates tested | ☐ | | Scales, serial devices, and USB dependencies reviewed | ☐ | | Carrier software and integrations tested | ☐ | | Imports, exports, EDI, and APIs documented | ☐ | | Network flows and firewall rules documented | ☐ | | Internet-outage fallback tested | ☐ | | CPU, RAM, and storage starting point selected | ☐ | | Storage growth estimated | ☐ | | Application-aware database backups configured | ☐ | | Off-server recovery copy planned | ☐ | | File, database, and application restores tested | ☐ | | Migration window approved | ☐ | | Rollback path documented | ☐ | | System, warehouse, security, and recovery owners named | ☐ | | Old environment retained until final approval | ☐ | An incomplete checklist means the system is still a test environment. ## What's next A Windows VPS for logistics and distribution companies works best when the business centralizes supported Windows applications and data, tests every warehouse device, and preserves a clear fallback for connectivity loss. Read [Windows VPS Hosting for Small Businesses](https://rafftechnologies.com/windows-server/windows-vps-small-business) for the broader decision framework. Review [Windows VPS for Manufacturing Businesses](https://rafftechnologies.com/windows-server/windows-vps-manufacturing-businesses) when the same environment also supports production operations. Explore [Raff Windows VM](https://rafftechnologies.com/products/windows-vm) when the users, devices, database, storage, backups, and migration path are documented well enough to build a test environment. :::cta Deploy Windows Now Build a test environment for your logistics Windows workload. ::: ## Sources - Microsoft Learn — [Remote Desktop Services overview in Windows Server](https://learn.microsoft.com/en-us/windows-server/remote/remote-desktop-services/overview) - Microsoft Learn — [License Remote Desktop Services with Client Access Licenses](https://learn.microsoft.com/en-us/windows-server/remote/remote-desktop-services/rds-client-access-license) - Microsoft Learn — [Peripheral and resource redirection over the Remote Desktop Protocol](https://learn.microsoft.com/en-us/azure/virtual-desktop/redirection-remote-desktop-protocol) - Microsoft Learn — [Printer redirection and drive redirection troubleshooting](https://learn.microsoft.com/en-us/troubleshoot/windows-server/printing/printer-hard-drive-not-redirect-to-remote-desktop-session) - Microsoft Learn — [Back up and restore SQL Server databases](https://learn.microsoft.com/en-us/sql/relational-databases/backup-restore/back-up-and-restore-of-sql-server-databases) - Zebra — [Scanner remote management](https://www.zebra.com/us/en/software/scanner-software/remote-management.html) - Raff Docs — [Virtual Machines](https://docs.rafftechnologies.com/products/build/virtual-machines) - Raff Docs — [Plans and sizing](https://docs.rafftechnologies.com/products/build/virtual-machines/concepts/plans-and-sizing) - Raff Docs — [Virtual Machine features and limits](https://docs.rafftechnologies.com/products/build/virtual-machines/details/features-and-limits) - Raff Docs — [Enable backups](https://docs.rafftechnologies.com/products/build/virtual-machines/quickstart-guides/enable-backups) - Raff — [Windows VPS for ERP and Inventory Software](https://rafftechnologies.com/windows-server/windows-vps-erp-inventory-software) - Raff — [Windows VPS Backup Strategy for Small Businesses](https://rafftechnologies.com/windows-server/windows-vps-backup-strategy-small-business) - Raff — [Windows Server Migration Checklist for Small Businesses](https://rafftechnologies.com/windows-server/windows-server-migration-checklist-small-business) - Raff — [Windows VM product page](https://rafftechnologies.com/products/windows-vm) --- ### Windows VPS for Microsoft Access and Legacy Apps URL: https://rafftechnologies.com/windows-server/windows-vps-microsoft-access-legacy-apps Description: Learn when a Windows VPS makes sense for Microsoft Access databases and legacy Windows apps, including RDP, RDS, backups, sizing, and risks. ## In short A Windows VPS can be a practical way to run Microsoft Access databases and legacy Windows apps when users need remote access, centralized files, backups, and a consistent Windows Server environment. It works best when Access is split correctly, users connect through Remote Desktop instead of opening database files over a slow WAN, and RDS licensing is planned for staff desktop sessions. Raff Technologies provides Windows VMs for teams that need this kind of hosted Windows environment. Microsoft Access and legacy Windows apps are common in small businesses because they solve real operational problems: invoicing, inventory, quoting, reporting, customer records, tax workflows, internal forms, and custom line-of-business tools. The issue is usually not that the app stopped working. The issue is that the business has changed around it. A local office setup may have worked when everyone sat near the same server. Once people work from home, branch offices, client sites, or different states, the old pattern starts to break. A Windows VPS gives the business a cloud-hosted Windows Server that users can reach through Remote Desktop Protocol, Remote Desktop Services, or app-specific access patterns. ## Quick verdict: when a Windows VPS makes sense Use this table before moving a Microsoft Access database or legacy Windows app to a Windows VPS. | Situation | Windows VPS fit | Why | |---|---|---| | One user needs an always-on Windows app | Good fit | Simple RDP access can keep the environment online. | | 3-10 users need the same legacy app remotely | Good fit with RDS planning | A shared Windows Server can centralize the app and data. | | Access database is already split front-end/back-end | Better fit | Split design is safer for shared Access databases. | | Users open one Access file directly over VPN/WAN | Risky | WAN-style file access can create performance and reliability issues. | | App requires local USB hardware or dongles | Depends | Hardware dependency may make cloud hosting difficult. | | App vendor supports Windows Server/RDS | Stronger fit | Supportability matters before production migration. | | App vendor forbids cloud/RDS hosting | Poor fit | Licensing or support terms may block the move. | | Database is growing beyond Access limits | Consider SQL Server or migration | A VPS can host the app temporarily, but the data layer may need redesign. | The best use case is not "put any old file on a server." The best use case is a planned Windows environment where Access, files, users, backups, and security are treated as production infrastructure. :::cta Explore Windows Server VPS Use Raff Windows Server VPS when your team needs remote access to Microsoft Access databases, legacy apps, or shared Windows workloads. ::: ## Why Access and legacy apps become a cloud server problem Microsoft Access and legacy apps often start as local office tools. They become infrastructure problems when the business depends on them every day. Common triggers include: | Trigger | What changes | |---|---| | Remote work | Users need access outside the office LAN. | | Multiple locations | Branches need the same app and data. | | Aging office server | Hardware replacement becomes urgent. | | Slow VPN access | File-based apps perform poorly over remote links. | | No backup owner | The app holds business data but has no recovery plan. | | Inconsistent PCs | App versions, drivers, and local settings differ by workstation. | | Staff growth | More users increase locking, performance, and support issues. | | Vendor support risk | Old app versions may not support modern local desktops. | A Windows VPS does not fix a badly designed Access database by itself. It gives the business a controlled Windows Server environment where the app can run closer to its data, users can connect remotely, and backups can be planned centrally. That is the main buyer benefit: less dependency on one office machine and more control over how the app is accessed. ## Microsoft Access should usually be split for shared use For shared Microsoft Access databases, split design matters. Microsoft Support says to consider splitting any database that several people share over a network because splitting can improve performance and reduce the chance of database file corruption. ![Diagram showing Microsoft Access front-end and back-end database split on a Windows VPS](https://raff-images.s3.raffusercloud.com/access_database_split_windows_vps_diagram_webp_e6e7378779.png) A split Access database has two parts: | Component | What it contains | Where it should live | |---|---|---| | Back-end database | Tables and shared data | Server/shared location | | Front-end database | Queries, forms, reports, macros, code | Separate copy for each user | Microsoft's guidance on sharing an Access desktop database explains that each user should interact with the data by using a local copy of the front-end database while the back-end stores the shared tables. Microsoft performance guidance also says that splitting a database improves multi-user performance because only data is sent across the network. On a Windows VPS, this usually means users connect into the Windows environment and run their own front-end copy there, while the back-end stays on the server side. That is different from asking remote users to open one shared Access file across a VPN. ## Avoid opening Access databases directly over slow WAN links Access can work well on a local area network when designed properly. It often behaves poorly when users open file-based databases across slow or unstable wide-area links. ![Comparison visual showing Access database over WAN versus Access running inside RDP on a Windows VPS](https://raff-images.s3.raffusercloud.com/access_database_wan_vs_rdp_pattern_webp_b0c19ae6be.png) Microsoft's Access deployment guidance warns that Azure file shares can introduce issues similar to those that arise when using an Access split database in a WAN. The practical lesson applies beyond Azure: Access is sensitive to network behavior because file-based database access depends on reliable, low-latency file operations. For remote teams, the safer pattern is usually: ```text User device -> Remote Desktop session -> Access front-end runs on Windows VPS -> Access back-end stays close to the front-end ``` The riskier pattern is: ```text User device -> VPN/WAN -> Open Access database file across remote network -> Slow forms, locking issues, corruption risk ``` A Windows VPS helps when it keeps the application runtime and the database file close together. Users see the app through Remote Desktop, but the Access file operations happen inside the server environment. ## RDP, RDS, and user count decide the access model Access and legacy app hosting on a Windows VPS is usually an access-design question before it is a software question. Use this table: | User pattern | Recommended access model | |---|---| | One owner/admin uses the app | Direct RDP with restrictions can work | | Two admins maintain the app | Direct RDP or controlled admin access | | Three or more staff use the app daily | RDS Session Host planning | | Users connect from changing locations | Consider RD Gateway | | Users only need a web app or SQL app | Do not give desktop access unless needed | | MSP manages the app for a client | Standardize RDS, backups, access, and documentation | Default Windows Server RDP is for administration. If several staff members need daily desktop sessions, plan Remote Desktop Services and RDS Client Access Licenses before production. Microsoft's RDS licensing documentation says each user or device connecting to an RD Session Host running Windows Server needs an RDS CAL. That applies to the user access model; it is separate from whether Access itself is licensed correctly. :::cta Plan Your Windows VPS Plan CPU, RAM, storage, RDS access, and backups before moving Access databases or legacy apps to a Windows VPS. ::: ## Sizing depends on users, app behavior, and data size Do not size a Windows VPS for Access or legacy apps by the installer requirements alone. Size it by concurrent users, app workload, database size, profile growth, backups, and reporting activity. Use this starting guide: | Workload | Starting size | When to move up | |---|---:|---| | 1 admin or single app user | 2 vCPU / 4 GB RAM | If the app is heavy or runs reports | | 3 light Access users | 4 vCPU / 8 GB RAM | If forms/reports feel slow | | 3 business app users | 4 vCPU / 16 GB RAM | If app, profiles, and reports use memory | | 5 Access or legacy app users | 4 vCPU / 16 GB RAM | If month-end reporting creates lag | | 10 active users | 8 vCPU / 32 GB RAM | If users run several apps in RDS | | SQL Server plus legacy app | 8-16 vCPU / 32-64 GB RAM | If database and users compete for RAM | For Access specifically, watch storage and profile growth. Access front-end files, back-end databases, exports, reports, backups, temporary files, and user profiles can grow quietly. The existing Raff sizing guide for remote users should be linked from this article because Access buyers often ask the same practical question: how much CPU, RAM, and storage do we need for 3, 5, or 10 users? ## Storage planning is more than the database file A small Access database file can hide a larger storage requirement. Business app environments accumulate files over time. Plan storage for: | Data type | Examples | |---|---| | Access back-end files | `.accdb`, `.mdb`, linked table back ends | | Access front-end copies | Per-user front-end files | | Legacy app data | App folders, local databases, config files | | Shared files | PDFs, reports, invoices, exports, attachments | | User profiles | Desktop, Documents, Downloads, AppData | | Temporary files | Lock files, report output, installer cache | | Backups | App backups, file backups, VM-level backups | | Logs | Windows logs, app logs, audit logs | Do not run the production disk near full. Access and legacy apps can behave unpredictably when disks are full, temp files cannot be written, or backup jobs run out of space. A practical rule: size storage for the next 12 months of data, not today's database file. ## Backups must be app-aware enough to restore the business Microsoft's Access backup guidance says you need a backup copy to restore the entire database after a system failure or restore an object when undo is not enough. For a business Access app, that backup must be part of the server plan, not something done manually once in a while. A useful backup model: | Backup layer | Purpose | |---|---| | VM backup | Recover the whole Windows VPS | | Snapshot before changes | Roll back after updates or app upgrades | | File-level backup | Restore Access files, reports, exports, app folders | | App-specific backup | Use the legacy app's supported backup process | | Off-server copy | Protect against VM, account, or ransomware incidents | | Restore test | Prove the backup actually works | Back up the Access back-end during a low-activity window or with users out of the database where needed. Document how users exit, where the back-end lives, where front-end copies live, and how to restore the environment. A backup that restores the file but breaks links, permissions, or front-end deployment is not enough. Test the app after restore. ## Security starts with access control Access and legacy apps often hold customer records, invoices, tax data, payroll data, inventory, or operational history. Treat the Windows VPS as a business system. At minimum, plan: | Security area | Recommendation | |---|---| | RDP exposure | Restrict access; avoid broad direct RDP exposure | | User accounts | Use named users, not shared administrator accounts | | Permissions | Limit who can modify app folders and database files | | Backups | Restrict who can delete backup copies | | Windows updates | Schedule updates and test before business-critical periods | | Antivirus/Defender | Avoid exclusions unless required and documented | | Audit logs | Track logins and failed access attempts | | App credentials | Do not store passwords in shared files | | Admin access | Separate admin work from daily user sessions | For multi-user environments, read the RD Gateway vs Direct RDP article before exposing access to staff. Remote access design should happen before the app becomes daily production work. ## Legacy apps need compatibility checks before migration Legacy Windows apps vary widely. Some run fine on Windows Server. Others depend on old runtimes, hardcoded paths, mapped drives, printer drivers, old Office components, local machine names, COM objects, ODBC drivers, or licensing services. Before moving the app to a Windows VPS, check: | Compatibility item | Why it matters | |---|---| | Windows Server version | Some apps support only specific versions | | 32-bit vs 64-bit components | Older Access/ODBC/COM pieces may depend on bitness | | Office/Access runtime version | Front-end behavior may depend on the runtime | | Mapped drive paths | Hardcoded drive letters can break after migration | | UNC paths | Server path changes may require relinking | | Printer dependencies | Reports may depend on installed printers | | Licensing method | Hardware IDs, dongles, or local activation may not work | | User permissions | Apps may assume write access to install folders | | Database engine | Some apps use Jet/ACE, SQL Server, SQLite, or proprietary files | | Vendor support | Unsupported hosting can create business risk | Do not migrate the production system first. Build a test Windows VPS, copy a non-production version, run the real workflow, and let users test the forms, reports, exports, printing, and end-of-day process. ## When Access should move to SQL Server instead A Windows VPS can centralize Access, but it does not turn Access into SQL Server. Some Access systems eventually outgrow the file-based model. Consider SQL Server or another database back end when: | Signal | Meaning | |---|---| | Many users edit data at once | Locking and performance risk rises | | Database file is growing fast | File-based design may become fragile | | Reports are slow | Queries may need a stronger database engine | | App is business-critical | Recovery, auditing, and consistency matter more | | Remote users keep increasing | RDS can help, but data layer may still need redesign | | Corruption or repair is common | Architecture should be reviewed | | Integrations need APIs | Access may not be the right system of record | Access can still be a useful front end in some environments, especially with linked SQL Server tables. But that is a redesign decision, not a simple VPS migration. If your workload already needs SQL Server, use the Raff SQL Server guides instead of treating the Access file as the long-term database layer. ## Migration plan for Access and legacy apps Use a staged migration, not a rushed weekend copy. ![Checklist visual for moving Microsoft Access databases and legacy Windows apps to a Windows VPS](https://raff-images.s3.raffusercloud.com/legacy_app_migration_checklist_windows_vps_webp_2576c140e1.png) A practical sequence: 1. Inventory the current app, database files, user count, and shared folders. 2. Confirm who uses the app and when peak usage happens. 3. Check whether the Access database is split. 4. Identify front-end copies, back-end location, linked tables, and file paths. 5. Check Access runtime, Office version, ODBC drivers, printers, and app dependencies. 6. Choose an initial Windows VPS size. 7. Build a test Windows VPS. 8. Copy a non-production version of the app and data. 9. Relink tables or paths as needed. 10. Test forms, reports, printing, exports, imports, and backup. 11. Test with real users over RDP/RDS. 12. Document rollback and restore steps. 13. Schedule production cutover. 14. Keep the old environment available until the new one is verified. For many SMBs, the first migration goal is not modernization. It is stability: make the app reachable, backed up, and less dependent on one aging office server. ## When a Windows VPS is not the right fit A Windows VPS is not always the right answer for Access or legacy apps. Pause before using a Windows VPS when: | Situation | Better next step | |---|---| | Vendor does not allow server/RDS hosting | Ask vendor for supported deployment paths | | App requires local USB dongle | Check licensing hardware support first | | App needs very low-latency LAN file access | Test before migration | | Database is already unstable or corrupt | Repair/compact and architecture review first | | App has no installer or documentation | Build a test environment before production | | Many users need heavy reporting | Consider SQL Server or app modernization | | Compliance requires specific hosting controls | Review with IT/security advisor | | Business wants fully managed desktop support | Consider managed desktop or RDS provider | The worst migration is moving a fragile system into the cloud and assuming the cloud will fix the fragility. A Windows VPS gives you a better hosting environment, but the app still needs a clean operating model. ## How Raff fits Access and legacy app hosting Raff fits this use case when a small business needs a Windows Server VPS for Microsoft Access databases, legacy Windows apps, shared business tools, or remote staff access. Raff Windows VMs provide a Windows Server environment with full administrator access and RDP. The public Windows VM page lists Windows Server 2019, 2022, and 2025 support, full admin access, 24/7 support, and a 99.9% uptime SLA. For Access and legacy app buyers, that matters because the server becomes part of daily business operations. Raff is not a replacement for application support. If the Access database needs redesign, if the vendor does not support RDS, or if the app requires special licensing, those issues must be handled before production. Raff provides the Windows VM environment; the workload still needs sizing, backup, security, and compatibility planning. :::cta Deploy a Windows VM Run your Windows workload on Raff Windows VM with remote access, NVMe storage, backups, snapshots, and simple monthly pricing. ::: ## Recommended path by business type | Business type | Recommendation | |---|---| | Solo operator with one Access app | Start with a small Windows VPS and restricted admin RDP. | | 3-person office | Use split Access design and plan RDP/RDS access carefully. | | 5-user accounting or admin team | Plan RDS, backups, storage, and app-specific restore testing. | | 10-user team | Size for active users and consider whether SQL Server should replace the back end. | | MSP client | Standardize front-end deployment, backups, access, and restore documentation. | | Multi-location business | Use RDP/RDS to keep app and data close together instead of opening files over WAN. | | Legacy app with hardware dependency | Test licensing, drivers, and hardware assumptions before moving. | | Business with unstable Access file | Fix split design, compact/repair, and backup before cloud migration. | The safest path is to test the app on a Windows VPS before moving production data. Access and legacy apps can be extremely valuable, but they need careful handling because the business often depends on small details nobody has documented. ## What's next - Read [Windows VPS sizing for remote users](https://rafftechnologies.com/windows-server/windows-vps-sizing-remote-users) before choosing CPU, RAM, and storage. - Read [Cloud Windows Server vs Local Office Server](https://rafftechnologies.com/windows-server/cloud-windows-server-vs-local-office-server) if you are replacing office hardware. - Read [Windows VPS Backup Strategy for Small Businesses](https://rafftechnologies.com/windows-server/windows-vps-backup-strategy-small-business) before moving production app data. - Read [Remote Desktop Gateway vs Direct RDP](https://rafftechnologies.com/windows-server/remote-desktop-gateway-vs-direct-rdp) before giving staff remote desktop access. - Read [Windows VPS for Business Software](https://rafftechnologies.com/windows-server/windows-vps-for-business-software) if you are comparing several SMB app workloads. - Read [RDS CAL Licensing on Windows Server](https://rafftechnologies.com/windows-server/rds-cal-licensing-guide) before rolling out staff desktop sessions. - Review [Raff Windows VM](https://rafftechnologies.com/products/windows-vm) and [pricing](https://rafftechnologies.com/pricing) when planning the production server. ## Sources - Microsoft Support - [Split an Access database](https://support.microsoft.com/en-us/access/split-an-access-database) - Microsoft Support - [Ways to share an Access desktop database](https://support.microsoft.com/en-us/access/ways-to-share-an-access-desktop-database) - Microsoft Support - [Deploy an Access application](https://support.microsoft.com/en-us/access/deploy-an-access-application) - Microsoft Support - [Help Access run faster](https://support.microsoft.com/en-us/access/help-access-run-faster) - Microsoft Support - [Compact and repair a database](https://support.microsoft.com/en-us/access/compact-and-repair-a-database) - Microsoft Support - [Protect your data with backup and restore processes](https://support.microsoft.com/en-us/access/protect-your-data-with-backup-and-restore-processes) - Microsoft Learn - [License Remote Desktop Services with Client Access Licenses](https://learn.microsoft.com/en-us/windows-server/remote/remote-desktop-services/rds-client-access-license) - Raff - [Windows VPS for Business Software](https://rafftechnologies.com/windows-server/windows-vps-for-business-software) - Raff - [Windows VPS for Remote Desktop](https://rafftechnologies.com/windows-server/windows-vps-for-remote-desktop) - Raff - [Windows VM product page](https://rafftechnologies.com/products/windows-vm) - Raff - [Pricing](https://rafftechnologies.com/pricing) --- ### Windows Server Standard vs Datacenter: Which Edition Should You Choose for a VPS? URL: https://rafftechnologies.com/windows-server/windows-server-standard-vs-datacenter Description: Compare Windows Server Standard vs Datacenter for a VPS. Choose by virtualization rights, Datacenter-only features, licensing model, workload, and hosted-server requirements. Windows Server Standard vs Datacenter is primarily a licensing and feature decision, not a performance decision. For most Raff Windows VPS workloads, **Standard is the right default** because one hosted virtual machine rarely benefits from Datacenter's unlimited virtualization rights. Datacenter becomes the better choice when you license and operate a physical virtualization host, need more than two Windows Server virtual machines per fully licensed host, or require a Datacenter-only capability such as Storage Spaces Direct. The edition does not automatically give a single VPS more CPU, RAM, storage speed, or Remote Desktop capacity. ## In short Choose **Windows Server Standard** for a typical hosted VPS running RDP administration, IIS, SQL Server, Active Directory, file services, or one business application. Choose **Datacenter** for dense Hyper-V hosts, unlimited Windows Server guest rights, Storage Spaces Direct, or other Datacenter-only infrastructure features. On one provider-managed VPS, Datacenter usually adds licensing cost without improving application performance. ## Windows Server Standard vs Datacenter at a glance | Decision area | Windows Server Standard | Windows Server Datacenter | |---|---|---| | Intended environment | Physical or minimally virtualized servers | Highly virtualized datacenters and cloud environments | | Windows Server VM rights on a fully licensed physical host | Two virtual machines, plus one Hyper-V host used only to manage them | Unlimited virtual machines, plus one Hyper-V host | | Core licensing model | Yes | Yes | | Windows Server CAL requirement | Yes, under conventional server licensing | Yes, under conventional server licensing | | Maximum memory | Same published platform limits | Same published platform limits | | Storage Spaces Direct | Not included | Included | | Storage Replica | One partnership, one resource group, one 2 TB volume | Unlimited | | Hyper-V isolated containers | Up to two | Unlimited | | Automatic Virtual Machine Activation | Limited guest scenario | Included | | Typical hosted VPS choice | Usually the practical default | Needed only for specific features or licensing designs | Microsoft positions Standard for physical or lightly virtualized environments and Datacenter for highly virtualized environments. The current Windows Server 2025 reference pricing also reflects that difference: Microsoft lists a suggested 16-core MSRP of **$1,176 for Standard** and **$6,771 for Datacenter**. Those figures are reference prices for Microsoft licensing, not Raff's monthly VPS price. [Microsoft publishes the current edition and pricing details here](https://www.microsoft.com/en-us/cloud-platform/windows-server-pricing). ## The editions do not create different VPS performance tiers Standard and Datacenter can run the same general-purpose Windows Server roles, including: - Active Directory Domain Services - DNS and DHCP - IIS - file and storage services - Windows Server Backup - Group Policy - Failover Clustering - Windows Server Update Services - Windows Subsystem for Linux - common Windows business applications A Datacenter installation does not make the same virtual CPU faster. It does not increase the RAM assigned by the VPS plan. It does not improve NVMe latency, network throughput, SQL query speed, or RDP responsiveness by itself. Performance depends on the VM configuration and workload: - virtual CPU count and scheduling - allocated RAM - storage latency and throughput - database configuration - application behavior - user-session count - antivirus and backup activity - network conditions Choose the edition for licensing rights and required features. Choose the VPS plan for performance. This distinction prevents a common purchasing mistake: paying for Datacenter because the name sounds like a higher-performance operating system. ## Virtualization rights are the main licensing difference Microsoft's current Windows Server licensing comparison gives Standard rights for **two Windows Server virtual machines** when all physical cores on the server are properly licensed. Datacenter provides rights for **unlimited Windows Server virtual machines** on that licensed server. Both also allow the physical operating-system environment when it is used only to host and manage the virtual machines. [Microsoft summarizes these rights in its Windows Server overview](https://learn.microsoft.com/en-us/windows-server/get-started/overview). For self-managed physical hosts, the practical logic is: ```text One or two Windows Server VMs per host: Standard may be sufficient. More than two Windows Server VMs per host: Stack additional Standard licenses or evaluate Datacenter. High and changing VM density: Datacenter usually becomes simpler to license. ``` Raff uses Microsoft's 2-VM Standard right as the first licensing threshold for self-managed virtualization hosts. Standard licensing can be stacked. Fully licensing the host again with Standard can grant rights for two additional Windows Server virtual machines. Whether stacking Standard remains economical depends on the host's physical core count, expected VM density, agreement, and reseller pricing. Datacenter removes the need to count Windows Server guests after the physical host is fully licensed. That is its major advantage for private clouds, virtualization clusters, and service-provider infrastructure. ## A hosted VPS changes the edition decision A hosted VPS is already a guest virtual machine on infrastructure operated by the provider. That matters because the two-VM and unlimited-VM rights concern how the underlying physical server is licensed. Buying or activating Datacenter inside one VPS does **not automatically grant control of the provider's physical host**. It also does not automatically grant a right to run unlimited nested Windows Server VMs inside that VPS. Nested virtualization must be technically available, permitted by the provider, and correctly licensed. For one hosted Windows VPS, Raff recommends Standard unless a Datacenter-only feature is required. This is also why edition choice and provider licensing must be considered together: - Under a provider-managed licensing model, the provider controls how Windows Server is licensed on the infrastructure. - Under Bring Your Own License, the customer's agreement, Software Assurance or subscription rights, deployment model, and provider eligibility matter. - Under a physical-host or dedicated-server model, virtualization rights become a much larger part of the decision. Raff is a Microsoft Service Provider License Agreement provider. Production licensing, Bring Your Own License eligibility, Remote Desktop Services licensing, and activation are separate from choosing the operating-system image. Read [Windows Server licensing on Raff](/windows-server/windows-licensing) before applying an existing license. ## Datacenter-only capabilities matter for infrastructure hosts Datacenter includes capabilities designed for larger virtualization and software-defined infrastructure environments. The most relevant differences include the following. ### Storage Spaces Direct Storage Spaces Direct combines local drives across clustered servers into shared software-defined storage. Microsoft lists it as a Datacenter capability, not a Standard capability. This feature is relevant when you operate the physical servers and storage devices in a supported cluster. It is normally not a reason to select Datacenter for one hosted VPS because the guest does not control the provider's physical disks or storage cluster. ### Expanded Storage Replica rights Windows Server Standard includes limited Storage Replica rights: one partnership, one resource group, and a single volume up to 2 TB. Datacenter provides unlimited Storage Replica partnerships, resource groups, and replicated volume sizes under the product limits. Standard may cover a small, carefully defined replication scenario. Datacenter fits broader disaster-recovery and multi-volume replication designs. ### Unlimited Hyper-V isolated containers Standard supports unlimited Windows Server containers but limits Hyper-V isolated containers to two. Datacenter supports unlimited Windows Server containers and unlimited Hyper-V isolated containers. This difference matters for dense container hosts using Hyper-V isolation. It usually does not matter for an ordinary application VPS that does not host Windows containers. ### Automatic Virtual Machine Activation Automatic Virtual Machine Activation simplifies activation for supported Windows Server guests running on a properly activated Datacenter host. It is useful for administrators operating their own Hyper-V infrastructure. It is not a performance feature and is rarely a deciding factor for a single hosted VPS. ### Host Guardian Hyper-V support Microsoft's edition comparison lists Host Guardian Hyper-V support for Datacenter. This is relevant to shielded and guarded virtualization designs, not normal Windows application hosting. The complete feature matrix changes by Windows Server release. Verify the exact version in [Microsoft's Windows Server edition comparison](https://learn.microsoft.com/en-us/windows-server/get-started/editions-comparison) before designing around one feature. ## Standard fits most single-VPS workloads Windows Server Standard is normally sufficient for these hosted workloads: - one Remote Desktop administration server - an IIS web or application server - a Windows service or background worker - a small or medium SQL Server workload - an Active Directory domain controller - DNS and DHCP - a cloud file server - accounting, tax, ERP, inventory, or legacy software - a development or test environment - a management or monitoring server These workloads do not become more capable merely because the operating-system edition changes to Datacenter. For business applications, the more important checks are: 1. Does the vendor support Windows Server 2025, 2022, or 2019? 2. Does the application require Desktop Experience? 3. How many users will connect? 4. Is Remote Desktop Session Host required? 5. What CPU, memory, and storage does the workload need? 6. How will the server be backed up and restored? Use [Windows Server 2019 vs 2022 vs 2025](/windows-server/windows-server-version-comparison) to choose the release. Use [Windows Server Core vs Desktop Experience](/windows-server/windows-server-core-vs-desktop-experience) to choose the installation option. Those decisions are separate from Standard versus Datacenter. ## Datacenter fits virtualization and private-cloud workloads Datacenter becomes appropriate when one or more of these conditions apply: - you license and manage a physical Hyper-V host - the host runs many Windows Server guests - VM density changes frequently - stacking Standard licenses becomes difficult or uneconomical - you need Storage Spaces Direct - you need broad Storage Replica rights - you need unlimited Hyper-V isolated containers - you operate shielded or guarded virtualization infrastructure - you are building a private cloud or virtualization cluster These are host-level infrastructure requirements. They are different from renting one Windows VPS for an application. Datacenter can also make operational planning simpler. An administrator can add and remove Windows Server guests without recalculating Standard virtualization rights after every density change, provided the host remains correctly licensed. ## Edition recommendations by workload | Workload | Recommended edition | Reason | |---|---|---| | One Windows VPS for business software | Standard | Datacenter rights normally add no value | | One IIS or ASP.NET server | Standard | Core web roles are available in both editions | | One SQL Server VM | Standard | SQL Server licensing and VM sizing matter more | | Active Directory domain controller | Standard | AD DS is available in both editions | | Remote Desktop administration | Standard | Edition does not expand the two administrative sessions | | Multi-user RDS Session Host | Standard in most cases | RDS roles and RDS CALs are the key requirements | | Small file server | Standard | File services and backup are included | | Two Windows Server guests on one physical host | Standard may fit | Standard includes two VM rights after full host licensing | | Four or more Windows Server guests on one host | Compare stacked Standard with Datacenter | Core count and license price determine the break-even point | | Large Hyper-V cluster | Datacenter | Unlimited guest rights simplify dense virtualization | | Storage Spaces Direct cluster | Datacenter | The feature is Datacenter-only | | Extensive Storage Replica design | Datacenter | Standard replication rights are limited | | One nested-lab VPS | Verify first | Provider support and licensing must both allow the design | The recommendation can change when the deployment model changes. A workload that fits Standard inside one hosted VM may justify Datacenter when moved onto a customer-managed virtualization cluster. ## Standard and Datacenter use the same core licensing model Microsoft licenses both editions by physical core for conventional host licensing. Current reference pricing is based on a 16-core license, and Microsoft requires Windows Server Client Access Licenses for users or devices accessing the licensed server under that model. Important distinctions include: - Windows Server CALs are separate from the server edition. - Remote Desktop Services CALs are separate from Windows Server CALs. - SQL Server has its own edition and licensing rules. - Microsoft 365 Apps licensing is separate. - Service-provider licensing differs from ordinary perpetual licensing. - Bring Your Own License rights depend on the agreement and deployment environment. Standard versus Datacenter does not remove the need to plan RDS licensing. More than the permitted administrative Remote Desktop use generally requires Remote Desktop Services roles and RDS CALs. Microsoft licensing is contract-based and can change. Treat this article as a decision guide, then verify the final deployment against Microsoft's current Product Terms, licensing documents, and your agreement. Microsoft's [Windows Server licensing document center](https://www.microsoft.com/licensing/docs/view/Windows-Server) is the authoritative starting point. ## Microsoft reference pricing does not equal hosted VPS pricing Microsoft's suggested MSRP is useful for comparing the relative licensing position of Standard and Datacenter on a self-managed server. It does not tell you the final monthly price of a hosted Windows VPS. Hosted pricing can include: - compute resources - storage - network service - IP addresses - provider-managed Windows licensing - backups and snapshots - support level - billing term A provider may license Windows Server through a service-provider agreement rather than selling a perpetual 16-core license to each VPS customer. Use the [Raff pricing page](/pricing) for current VM plan pricing and confirm the applicable Windows licensing path before production deployment. ## You can convert Standard to Datacenter Microsoft supports converting an installed Windows Server Standard system to Datacenter when Datacenter is a valid target edition and a valid product key is available. Microsoft documents the process through Deployment Image Servicing and Management. Before converting: - confirm the exact Windows Server release - verify the current and target editions - obtain the correct license and product key - create a tested backup - plan a restart and maintenance window - verify application and activation status afterward An edition conversion does not replace license compliance. The installed edition and the license assigned to the deployment must match. Microsoft documents the supported path in [Convert Windows Server editions and license types](https://learn.microsoft.com/en-us/windows-server/get-started/upgrade-conversion-options). Do not assume the reverse path is equally simple. Moving from Datacenter to Standard may require a different migration or reinstallation approach depending on the version and current configuration. ## A five-question decision framework Use these questions in order. ### 1. Are you choosing an edition for one hosted VPS or a physical host? For one hosted VPS, Standard is usually sufficient. For a physical virtualization host, continue to the virtualization-rights questions. ### 2. How many Windows Server guests will run on each licensed physical host? One or two guests can fit Standard's included rights. Higher density requires stacked Standard licenses or Datacenter. ### 3. Does the design require a Datacenter-only feature? Check Storage Spaces Direct, Storage Replica scope, Hyper-V isolated containers, guarded virtualization, and activation requirements against Microsoft's current matrix. ### 4. Who provides the Windows license? Provider-managed licensing, SPLA, Bring Your Own License, perpetual licenses, and subscription licenses have different deployment conditions. ### 5. Is Datacenter solving a real requirement? Do not choose Datacenter for a faster name, a larger VPS, more RDP users, or improved SQL performance. Choose it for a documented licensing or feature need. ## Common mistakes ### Treating Datacenter as a faster operating system The edition does not increase virtual CPU, RAM, storage, or network resources. Select the VM size separately. ### Applying physical-host VM rights to one hosted guest Unlimited virtualization rights belong to a correctly licensed Datacenter host. They do not automatically transfer to a tenant's nested environment. ### Ignoring Standard license stacking Standard can be licensed again for additional two-VM sets. Compare the complete core-license cost before assuming Datacenter is required. ### Forgetting CAL and RDS requirements The Datacenter edition does not include unlimited end-user Remote Desktop access. Plan Windows Server CALs and RDS CALs separately where applicable. ### Paying for Datacenter features the workload cannot use Storage Spaces Direct and guarded virtualization are designed for infrastructure controlled at the physical-host or cluster level. One ordinary VPS cannot use every host feature. ### Choosing an edition before choosing the deployment model The correct answer may differ for a hosted VPS, dedicated server, on-premises Hyper-V host, or multi-node private cloud. ## Raff's recommendation For a normal Windows VPS, choose Standard. It supports the server roles and business workloads most customers need without paying for host-level virtualization rights that one guest cannot use. Choose Datacenter only when the requirement is explicit: - a Datacenter-only feature is required - the customer controls and licenses the physical host - dense Windows Server virtualization makes unlimited guest rights valuable - a licensing specialist confirms the design Raff supports 3,000+ customers and has deployed 15,000+ VMs from its `us-east` region. The practical goal is to match the operating-system edition, Windows Server release, and VM size to the workload instead of treating them as one decision. :::cta Deploy Windows Now Deploy a Windows VM after confirming the edition, version, licensing path, and workload size. ::: ## Sources - Microsoft Learn — [Comparison of Windows Server editions](https://learn.microsoft.com/en-us/windows-server/get-started/editions-comparison) - Microsoft Learn — [What is Windows Server?](https://learn.microsoft.com/en-us/windows-server/get-started/overview) - Microsoft — [Windows Server 2025 licensing and pricing](https://www.microsoft.com/en-us/cloud-platform/windows-server-pricing) - Microsoft — [Windows Server licensing documents](https://www.microsoft.com/licensing/docs/view/Windows-Server) - Microsoft Learn — [Convert Windows Server editions and license types](https://learn.microsoft.com/en-us/windows-server/get-started/upgrade-conversion-options) - Date last verified: 2026-08-06 --- ### Windows VPS Backup Strategy for Small Businesses URL: https://rafftechnologies.com/windows-server/windows-vps-backup-strategy-small-business Description: Plan a Windows VPS backup strategy for small business workloads with snapshots, backups, restore tests, app-aware recovery, and off-server copies. ## In short A Windows VPS backup strategy for small businesses should protect the whole server, the business data inside it, and the applications that depend on that data. Snapshots are useful before risky changes. Scheduled backups protect against server failure. App-aware backups protect SQL Server, accounting databases, and line-of-business software. Restore tests prove the plan works. Raff Technologies gives small teams Windows VMs with backup and snapshot options, but the recovery plan still needs clear ownership. A Windows VPS is often where a small business puts Remote Desktop users, accounting software, tax tools, Microsoft Access databases, SQL Server tools, IIS apps, shared files, or admin workflows. That makes backup planning a business continuity issue, not just a technical checkbox. The right backup strategy answers four questions: what must be recovered, how much data the business can lose, how long the business can be down, and who performs the restore. If those answers are missing, the business does not have a backup strategy yet. It only has backup hope. ## Quick backup strategy for a small business Windows VPS Use this as the practical starting model: | Layer | What it protects | Recommended use | |---|---|---| | VM snapshot | Server state before a risky change | Before Windows updates, app upgrades, registry changes, firewall changes, or migrations | | Scheduled VM backup | Whole-server recovery | Daily recovery point for the Windows VPS | | File-level backup | Shared folders, exports, documents, reports | Restore individual files without rolling back the whole server | | App-aware backup | SQL Server, accounting software, ERP data, Access files | Required when app data must be transaction-consistent | | Off-server copy | Backup data outside the Windows VPS | Protection if the VM, disk, account, or app is compromised | | Restore test | Proof the backup works | Required before trusting the strategy | ![Diagram showing Windows VPS backup layers including snapshots, VM backups, file backups, app-aware backups, and off-server copies](https://raff-images.s3.raffusercloud.com/windows_vps_backup_layers_diagram_webp_8a2ee3adcf.png) The safest small business pattern is not one backup type. It is layered recovery: snapshot for fast rollback, scheduled backup for server recovery, app-aware backup for databases, and off-server copies for business continuity. ## Start with RPO and RTO before choosing tools A backup tool is not the strategy. The strategy starts with two numbers: RPO and RTO. | Term | Meaning | Small business example | |---|---|---| | RPO | Recovery point objective: how much data loss is acceptable | “We can lose 24 hours of reports, but not a week of invoices.” | | RTO | Recovery time objective: how long the system can be unavailable | “We need the server usable again within 4 hours.” | A small accounting office, tax preparer, MSP client, or remote operations team needs these numbers before choosing backup frequency. A once-per-week backup may be fine for a static test server. It is usually not enough for a Windows VPS that holds daily business transactions. Use this decision shortcut: | Workload | Suggested RPO | Suggested RTO | |---|---:|---:| | Admin-only Windows VPS | 24-48 hours | Same day | | Shared files and reports | 24 hours or less | Same day | | Accounting or tax software | 4-24 hours | 2-8 hours | | SQL Server workload | 15 minutes to 24 hours, depending on recovery model | 1-8 hours | | RDP server for daily staff work | 24 hours or less | 2-8 hours | | Critical production app | Minutes to hours | Minutes to hours, with stronger architecture | Do not pick aggressive numbers casually. A 15-minute RPO usually requires transaction log backups, monitoring, storage planning, and restore practice. A 24-hour RPO is simpler but means the business accepts losing up to a day of work. ## Snapshots and backups solve different problems Snapshots and backups are related, but they are not the same recovery tool. A snapshot is a point-in-time capture that helps roll back a server quickly. A backup is a recovery copy with retention, restore policy, and operational purpose. ![Visual comparing Windows VPS snapshots and backups for rollback, recovery, retention, and disaster protection](https://raff-images.s3.raffusercloud.com/windows_vps_snapshots_vs_backups_webp_671fb3b586.png) Use snapshots for short-term safety before change. Use backups for actual recovery planning. | Scenario | Snapshot | Backup | |---|---|---| | Before Windows updates | Good fit | Also useful if update causes deeper issue | | Before app upgrade | Good fit | Needed if app data must be recovered later | | Recover one deleted file | Not ideal | Better fit with file-level backup | | Recover from corrupted SQL database | Not enough alone | App-aware SQL backup required | | Recover after ransomware | Risky if snapshots are reachable | Off-server and protected backups required | | Long-term retention | Poor fit | Backup retention policy required | | Compliance retention | Poor fit | Backup/archive process required | A snapshot can be fast, but it should not become the only plan. If the VM is compromised, encrypted, misconfigured, or deleted, relying only on local or easily reachable restore points can fail at the worst time. Microsoft’s Volume Shadow Copy Service coordinates point-in-time copies so applications can keep writing while backup components create a consistent shadow copy. That helps explain why backup consistency matters for active Windows workloads. ## Whole-server backups protect the Windows VPS A whole-server backup helps recover the Windows VPS when the operating system, configuration, or full environment must be restored. This matters when the server has many small settings: users, firewall rules, app installs, RDS configuration, scheduled tasks, certificates, IIS sites, or registry changes. Whole-server backups are useful for: | Recovery need | Why whole-server backup helps | |---|---| | Windows update breaks the server | Restore the prior server state | | App upgrade fails | Return to a known working point | | Server configuration is damaged | Recover system settings and installed roles | | RDP/RDS configuration breaks | Restore working desktop access | | IIS or service configuration is lost | Recover app server setup | | Migration rollback is needed | Restore before cutover | For small teams, the mistake is backing up only files while forgetting the server configuration. Rebuilding a Windows VPS from scratch can take hours or days if nobody documented roles, users, firewall rules, services, and app settings. Raff Windows VM buyers should enable backup planning before storing production data. The best time to design recovery is before the first business app goes live. ## File-level backups protect daily work File-level backups help restore documents, exports, PDFs, reports, scripts, configuration files, and shared folders without rolling back the entire Windows VPS. This is important because many small business incidents are not full server failures. They are smaller mistakes: | Incident | Best restore type | |---|---| | User deletes a folder | File-level restore | | Report export is overwritten | File-level restore | | Wrong file version is saved | File version restore | | User downloads bad data | File-level rollback | | App config file is changed | File-level restore | | Shared folder permissions are broken | File backup plus permission documentation | If the Windows VPS acts as a file server, do not rely only on VM-level restore. Rolling back the whole server to recover one folder can erase unrelated work that happened after the restore point. A practical small business backup plan separates: - server recovery - user file recovery - application database recovery - long-term retention - emergency rebuild documentation ## App-aware backups protect databases and business software Application data needs special care. SQL Server, accounting software, ERP systems, tax software, and some Microsoft Access deployments can write data while users work. A basic file copy may not capture a clean, consistent application state. App-aware backups matter when the workload includes: | Workload | Backup concern | |---|---| | SQL Server | Full, differential, and transaction log backups may be needed | | QuickBooks or Sage-style software | Vendor-supported backup process should be used | | Tax software | Data folders and app-specific backup/export steps must be documented | | ERP or inventory apps | Database and app files must be consistent | | Microsoft Access | File locking and split database design affect backup timing | | IIS/.NET app | App files, config, certificates, and database must be backed up together | Microsoft’s SQL Server backup documentation explains that the recovery model determines backup and restore requirements. In practice, that means SQL Server backup planning is not the same as copying a `.mdf` file from Windows Explorer. If your Windows VPS runs SQL Server, use the dedicated Raff MSSQL backup strategy guide after this article. It covers full, differential, and log backups, recovery models, off-server copies, and restore verification for SQL workloads. ## Off-server copies protect against the worst cases A backup stored only on the same Windows VPS is not enough. It may help with accidental file changes, but it does not protect against every real business incident. Use off-server backup copies for: | Risk | Why off-server matters | |---|---| | VM disk issue | Backup should not depend only on the same disk | | Ransomware | Attackers may encrypt reachable local backups | | Account compromise | Restore points should not all be exposed to the same credentials | | App corruption | Clean older copies may be needed | | Accidental deletion | Recovery copy should exist outside the affected system | | Failed migration | Rollback should not depend on the broken server | A good small business rule is: ```text One backup is not enough if it lives only where the failure happens. ``` For Windows VPS workloads, use a mix of platform backups, snapshots, app-specific backups, and off-server copies. The exact design depends on the workload, retention needs, security requirements, and recovery targets. ## Retention should match business risk Retention means how long backup copies are kept. More retention gives more recovery options, but it also increases storage cost and management responsibility. A practical small business retention model: | Backup type | Example retention | |---|---:| | Daily VM backups | 7-14 days | | Weekly backups | 4-8 weeks | | Monthly backups | 3-12 months | | App/database backups | Based on business and compliance needs | | Pre-change snapshots | Delete after the change is verified | | Legal/tax records | Based on accounting and regulatory requirements | Keep short-term restore points for fast mistakes. Keep longer-term backups for corruption, delayed discovery, audit needs, or business records. Do not keep every snapshot forever. Old snapshots and backups can increase cost, clutter recovery choices, and create confusion during an emergency. Name backup sets clearly and document what each layer is for. ## Restore testing is the real proof A backup that has never been restored is an assumption. Restore testing turns the assumption into evidence. ![Workflow visual showing Windows VPS restore testing from backup copy to verified business application recovery](https://raff-images.s3.raffusercloud.com/windows_vps_restore_test_workflow_webp_4a42d04ef0.png) Small businesses should test: | Restore test | What it proves | |---|---| | Restore one file | User mistake recovery works | | Restore a folder | Shared data recovery works | | Restore app data to a test location | App backup is usable | | Restore SQL backup with verification | Database backup is valid | | Restore whole server or clone | Disaster recovery process is realistic | | Login after restore | User access and permissions still work | | App launch after restore | Business workflow can resume | At minimum, run a restore test after the first backup setup, after major app changes, and before peak business periods such as tax season, audit season, or high-volume reporting periods. Document the restore steps in plain language. During an outage, nobody wants to reverse-engineer the backup design from memory. ## A practical backup schedule for 1, 3, 5, and 10-user teams Use this as a starting plan. Adjust based on workload and RPO/RTO. | Environment | Suggested backup approach | |---|---| | 1 admin user | Daily VM backup, snapshot before changes, monthly restore test | | 3 light users | Daily VM backup, file-level backup for shared folders, snapshot before updates | | 5 business users | Daily VM backup, app-aware backup, off-server copy, quarterly restore drill | | 10 active users | Daily VM backup, app-aware backup, off-server copy, restore test, documented runbook | | SQL Server workload | Full/differential/log backup plan based on recovery model | | Tax or accounting workload | Vendor-supported app backup plus VM backup and off-server copy | For Remote Desktop teams, connect this backup plan to your sizing plan. A server with 10 active users usually stores more profiles, more exports, more app data, and more daily changes than a one-user admin server. Read the Windows VPS sizing guide before choosing storage. Backups and snapshots add storage planning on top of the production disk. ## Security controls belong in the backup plan Backups are part of security. If the same account can delete production data and delete every backup, the recovery plan is weak. Use these controls: | Control | Why it matters | |---|---| | Separate admin accounts | Reduce the chance one login controls everything | | Restrict backup access | Users should not browse or delete backup storage | | Protect off-server copies | Backup destination should not be casually writable by users | | Monitor backup failures | Failed jobs must be visible | | Keep backup logs | You need evidence of success or failure | | Use strong passwords | RDP compromise often becomes data loss | | Patch the server | Backup does not replace hardening | | Test restore permissions | A backup is useless if nobody can restore it | Backups also need ransomware thinking. If malware can encrypt the server and connected backup destination, the backup design is incomplete. Use separation, permissions, retention, and monitoring so backup copies are harder to destroy. ## Backup strategy for common SMB Windows VPS workloads Different workloads need different backup emphasis. | Workload | Backup priority | |---|---| | RDP server for staff | VM backup, user profile backup, shared folder backup | | Accounting software | Vendor-supported app backup, VM backup, off-server copy | | SQL Server | Full/differential/log backup plan, `CHECKSUM`, restore verification | | Microsoft Access | Backup file shares during low activity; test locking behavior | | IIS/.NET app | App files, config, certificates, database, and deployment package | | File server | File-level backup, permissions documentation, off-server copy | | ERP/inventory app | App-aware database backup and restore runbook | | Tax software | Vendor data backup, retention, encrypted off-server copy | | MSP client server | Standardized backup policy and documented restore owner | Do not use the same schedule for every server without checking the workload. A Windows VPS that holds SQL Server data has different recovery needs from a Windows VPS used only for occasional admin RDP. ## How Raff fits a Windows VPS backup strategy Raff fits this use case when a small business wants a Windows Server VPS for remote access, hosted business apps, RDP users, or office server replacement, and wants backup/snapshot planning to be part of the infrastructure discussion from day one. Raff Windows VMs are useful for this pattern because buyers can deploy a Windows Server environment, enable platform-level protection options, use NVMe storage, and plan storage growth as the workload changes. Raff is not a substitute for application-specific backups. If the workload uses SQL Server, QuickBooks, Sage, Microsoft Access, ERP software, tax software, or custom business databases, use the application’s supported backup method alongside VM-level protection. Raff Technologies currently lists 15,000+ VMs deployed on its public site, and Trustpilot lists Raff Technologies at 4.5/5 across 16 reviews. For Windows VPS buyers, those trust signals matter because the server often becomes part of daily operations. :::cta Deploy a Windows VM Run your Windows workload on Raff Windows VM with remote access, NVMe storage, backups, snapshots, and simple monthly pricing. ::: ## Backup checklist before going live Before putting a small business Windows VPS into production, confirm these items: | Check | Done | |---|---| | RPO and RTO are written down | ☐ | | Daily VM backup is configured | ☐ | | Snapshot process is defined before risky changes | ☐ | | App-aware backup exists for SQL or business software | ☐ | | Off-server copy exists | ☐ | | Retention policy is documented | ☐ | | Restore owner is named | ☐ | | One file restore has been tested | ☐ | | One app/database restore has been tested | ☐ | | Backup failure alerts are monitored | ☐ | | Backup access is restricted | ☐ | | Restore notes are stored outside the server | ☐ | The restore notes should not live only on the server being restored. Keep a copy in your password manager, internal wiki, MSP documentation system, or another secure location. ## Common backup mistakes ### Treating snapshots as long-term backups Snapshots are useful before changes, but they are not a full retention and disaster recovery strategy. Use snapshots for rollback and backups for recovery planning. ### Backing up only the files Files matter, but Windows configuration, users, services, app installs, certificates, firewall rules, and scheduled tasks can also be critical. ### Ignoring application consistency SQL Server, accounting software, and ERP tools need app-aware backup planning. A file copy during active writes can create a backup that looks successful but restores poorly. ### Keeping every backup on the same server Backups stored only on the same Windows VPS may fail when the server, disk, account, or workload is compromised. ### Never testing restore A green backup job is not the same as a successful restore. Test the restore process before the business depends on it. ### Forgetting permissions If too many users can modify backup locations, accidental deletion and ransomware risk increase. ### Letting backups fill the disk Backup files, SQL dumps, logs, and snapshots can consume storage quickly. Monitor disk usage and retention. ## What's next - Read [Windows VPS sizing for remote users](https://rafftechnologies.com/windows-server/windows-vps-sizing-remote-users) before choosing CPU, RAM, storage, and backup capacity. - Read [Cloud Windows Server vs Local Office Server](https://rafftechnologies.com/windows-server/cloud-windows-server-vs-local-office-server) if you are replacing office hardware. - Read [Windows VPS for Business Software](https://rafftechnologies.com/windows-server/windows-vps-for-business-software) if the server will host accounting, admin, ERP, SQL Server, or legacy apps. - Read [MSSQL Backup Strategy on a Windows VPS](https://rafftechnologies.com/windows-server/mssql-backup-strategy) if your workload uses SQL Server. - Read [Windows Server Hardening Checklist](https://rafftechnologies.com/windows-server/windows-server-hardening-checklist) before putting a Windows VPS into production. - Review [Raff Windows VM](https://rafftechnologies.com/products/windows-vm) and [pricing](https://rafftechnologies.com/pricing) when planning the production server. ## Sources - Microsoft Learn — [Backup and Storage overview for Windows Server](https://learn.microsoft.com/en-us/troubleshoot/windows-server/backup-and-storage/backup-and-storage-overview) - Microsoft Learn — [Volume Shadow Copy Service](https://learn.microsoft.com/en-us/windows-server/storage/file-server/volume-shadow-copy-service) - Microsoft Learn — [Volume Shadow Copy Service overview](https://learn.microsoft.com/en-us/windows/win32/vss/volume-shadow-copy-service-overview) - Microsoft Learn — [Backup overview for SQL Server](https://learn.microsoft.com/en-us/sql/relational-databases/backup-restore/backup-overview-sql-server) - Microsoft Learn — [Recovery models for SQL Server](https://learn.microsoft.com/en-us/sql/relational-databases/backup-restore/recovery-models-sql-server) - Raff — [MSSQL Backup Strategy on a Windows VPS](https://rafftechnologies.com/windows-server/mssql-backup-strategy) - Raff — [Windows VPS for Business Software](https://rafftechnologies.com/windows-server/windows-vps-for-business-software) - Raff — [Windows VM product page](https://rafftechnologies.com/products/windows-vm) - Raff — [Pricing](https://rafftechnologies.com/pricing) - Trustpilot — [Raff Technologies reviews](https://www.trustpilot.com/review/rafftechnologies.com) --- ### Snapshot vs Backup on a Windows VPS: Which Protects You? URL: https://rafftechnologies.com/windows-server/snapshot-vs-backup-windows-vps Description: Snapshots roll the whole disk back in minutes; backups survive losing the server. What each protects on a Windows VPS, what each costs, and when you need both. ## In short A snapshot freezes your server's disk at one point in time so you can roll the whole machine back in minutes, and it lives on the same platform as the VM it protects. A backup is an independent copy of your data on separate storage: it survives the loss of the server itself and can restore a single file or the full system. Snapshots are the safety net before a risky change; backups are the actual data protection. Production Windows servers need both, used for different jobs. ## Quick verdict by use case | If you are... | Use | Why | |---|---|---| | About to install updates or new software | Snapshot, taken right before the change | Whole-machine rollback in minutes if the change goes wrong | | Protecting QuickBooks, Sage, or SQL Server data | Scheduled backups | Independent copies with retention, application-consistent when done properly | | Recovering a file someone deleted last week | Backup | File-level restore from a retention history a snapshot does not have | | Meeting a client or compliance retention requirement | Backups with a retention policy | Snapshots have no meaningful retention story | | Running any production workload | Both | Snapshots for changes, backups for protection | ## What a snapshot actually is A snapshot is a point-in-time image of the server's virtual disk. When you take one, the platform marks the current state of the disk and starts recording changes separately, so the original state stays recoverable. Restoring a snapshot rolls the entire machine back to that moment: operating system, applications, settings, and data together. Three properties follow from that design, and all three matter for how you should use snapshots. **Snapshots are whole-machine.** You cannot pull one file out of most platform snapshots. Rolling back means everything on the server returns to the snapshot moment, including work saved after it was taken. **Snapshots are usually crash-consistent.** A snapshot of a running server captures the disk as if the power cord had been pulled at that instant. Windows and NTFS recover from that fine, but a database engine in the middle of a write may not. Microsoft draws the same line in its own virtualization documentation: standard checkpoints capture running state without application awareness, while production checkpoints use the Volume Shadow Copy Service to quiesce applications first. On most hosting platforms, an on-demand snapshot behaves like the first kind. Microsoft is also blunt about the limits: its checkpoint documentation states that checkpoints are not a replacement for backups. **Snapshots live with the platform.** The snapshot of a VM is stored by the same infrastructure that runs the VM. That is what makes rollback fast, and it is also the weakness: a snapshot does not protect you from anything that takes out the server or the account it belongs to. ## What a backup actually is A backup is an independent copy of your data written to separate storage on a schedule, with a retention history. Where a snapshot answers "undo the last change", a backup answers "give me back what I had", at three different levels: a single file, a folder or application dataset, or the full system. The properties are the mirror image of a snapshot's. **Backups survive the server.** Because the copy is independent, deleting the VM, losing the disk, or a platform-level failure does not take the backup with it. This is the reason backups, not snapshots, are the foundation of any disaster recovery plan. **Backups have retention.** A schedule produces a history: yesterday's copy, last week's, last month's. That history is what lets you recover the spreadsheet that was corrupted nine days ago and nobody noticed, and it is the only honest answer to ransomware, where the most recent copy may already be encrypted. **Backups can be application-consistent.** Proper Windows backup tooling uses the Volume Shadow Copy Service (VSS). VSS tells registered applications such as SQL Server to flush in-flight transactions to disk before the copy is taken, so the restored database opens cleanly instead of entering recovery. This is the difference between backing up a database server and merely copying its disk. ## Side-by-side comparison | Property | Snapshot | Backup | |---|---|---| | What it captures | Entire disk at one moment | Selected data or full system, on a schedule | | Restore granularity | Whole machine only | Single file, folder, application, or full system | | Restore speed | Minutes | Minutes to hours depending on size | | Consistency | Crash-consistent as a rule | Application-consistent when VSS-aware | | Storage location | Same platform as the VM | Independent storage | | Survives loss of the server | No | Yes | | Retention history | One or a few points, short-lived | Scheduled history with a retention policy | | Cost behavior | Grows as the disk changes while it exists | Proportional to protected data and retention | | Best at | Rollback before a risky change | Data protection and recovery | ## Where snapshots win Snapshots are unbeatable immediately before a change you might regret. Windows updates on a production server, a QuickBooks year upgrade, a new line-of-business app, a registry edit you half trust: take a snapshot, make the change, verify, delete the snapshot. If the change breaks something, rollback takes minutes and restores the machine exactly as it was, with no reinstalling and no reconfiguring. They also win on simplicity. There is nothing to schedule and no agent to configure. One action, one rollback point. ## Where backups win Everything else. Backups are the only one of the two that can return a deleted file, recover data from before the most recent copy, survive the loss of the VM itself, or produce a consistent copy of a running database. If the server holds company files, client records, or a SQL Server instance, the question is not whether to run backups but how often and with what retention. Backups are also the answer to ransomware. A snapshot stored with the platform can be rolled back, which helps, but only if the snapshot predates the infection and still exists. A backup history on independent storage gives you multiple restore points to walk back through and a copy the attacker never touched. ## Where they tie Neither replaces testing. A rollback you have never rehearsed and a backup you have never restored are both assumptions, not protection. Quarterly test restores of one file and one full recovery are cheap insurance. Neither covers configuration drift by itself. Both protect a machine's state; documenting what the machine is supposed to look like is still on you. ## What each costs on a Windows VPS On Raff, snapshot storage and backup storage are priced the same, per GB per month. Current rates are on the [pricing page](https://rafftechnologies.com/pricing); the table below reflects the rate as of August 2026. | Item | Rate | Example | |---|---|---| | Snapshot storage | $0.06/GB/month | Short-lived pre-change snapshot of a lightly changing 80 GB disk: well under $4 for the days it exists | | Backup storage | $0.06/GB/month | 40 GB of protected data: $2.40/month per retained copy equivalent | Two cost behaviors are worth knowing. A snapshot's footprint grows with every change written to the disk while it exists, which is one more reason to delete snapshots after the change is verified rather than keeping them for weeks. Backup cost scales with how much you protect and how long you retain it, which makes retention policy a budgeting decision, not just a compliance one. Windows licensing is unaffected by either: the monthly Windows Server licence covers the VM regardless of how you protect its data. ## Three failures and what actually saves you The cleanest way to see the difference is to walk through the incidents that actually happen to small-business Windows servers. **The botched update.** Tuesday evening you install a Windows cumulative update and a new version of a line-of-business app. Wednesday morning printing is broken and the app will not start. If you took a snapshot before the change, this is a five-minute rollback and a calmer retry with the vendor's guidance. If you only have last night's backup, you can still get back, but you are restoring a full system instead of flipping a switch, and anything written between the backup and the failure needs care. This scenario is the one snapshots exist for. **The quietly corrupted file.** A shared workbook was damaged nine days ago and nobody noticed until month-end. A snapshot cannot help: even if one still existed from that week, rolling the whole server back would destroy nine days of everyone else's work to save one file. A backup history restores that single file from the day before the corruption and touches nothing else. Retention depth decides whether this story ends well, which is why 14 to 30 days is the practical floor for business data. **The dead server.** The VM is deleted by mistake, the disk fails, or ransomware encrypts everything including any snapshot the platform would happily roll back into. The only thing that matters now is a copy that lived somewhere else: platform backups first, and for the truly irreplaceable files, the off-platform export from the 3-2-1 rule. Recovery time is measured in hours, and the difference between a bad day and a company-ending one is entirely about whether the backups exist and have been tested. One pattern runs through all three: snapshots shine exactly when you know a risky moment is coming, and backups carry every failure you did not see coming. ## Common mistakes **Keeping a snapshot for weeks as the backup.** It grows in cost the whole time, it cannot restore individual files, and it dies with the server. Microsoft's guidance on checkpoints says the same thing: not a backup substitute. **Snapshotting a busy database server and assuming the data is safe.** A crash-consistent image of SQL Server or a QuickBooks company file mid-write can restore into an inconsistent state. Databases need VSS-aware, application-consistent backups. **No copy that leaves the platform.** The classic 3-2-1 rule wants three copies on two kinds of storage with one off-site. For critical business data, pair platform backups with a periodic export of the irreplaceable files to somewhere independent, such as object storage. **Never testing a restore.** The first restore you ever attempt should not be the one that matters. Schedule a test restore and treat a failure as a production incident. **Backing up the machine but not the data that matters.** If company files live on a second volume or a mapped path, verify the backup job actually includes them. A completed job is not the same as a complete backup. ## Our recommendation Run scheduled backups on every production Windows VPS, sized to the data and retained long enough to survive slow-burn problems: 14 to 30 days covers most small-business cases. Take a snapshot before every risky change and delete it once the change is verified. Test a restore quarterly. If you are an accounting firm hosting QuickBooks or Sage, treat application-consistent backups of the company files as non-negotiable and rehearse the restore before tax season, not during it. If you are running SQL Server, combine platform backups with native SQL backups as described in our [MSSQL backup strategy guide](https://rafftechnologies.com/windows-server/mssql-backup-strategy). If the server is a shared file store for your team, our [cloud file server guide](https://rafftechnologies.com/windows-server/windows-vps-cloud-file-server) covers the sharing side of the same coin. :::cta Deploy Windows Now Deploy a Windows VPS with snapshot and backup storage at $0.06/GB/month. ::: ## What's next - [Windows VPS backup strategy for small businesses](https://rafftechnologies.com/windows-server/windows-vps-backup-strategy-small-business): turning the backup half of this article into a concrete schedule - [Windows VPS as a cloud file server](https://rafftechnologies.com/windows-server/windows-vps-cloud-file-server): protecting shared files your team works in daily - [MSSQL backup strategy](https://rafftechnologies.com/windows-server/mssql-backup-strategy): full, differential, and log backups for SQL Server - Browse the whole [storage and backup hub](https://rafftechnologies.com/windows-server/storage-backup) ## Sources - Microsoft Learn: [Choose between standard or production checkpoints in Hyper-V](https://learn.microsoft.com/en-us/windows-server/virtualization/hyper-v/manage/choose-between-standard-or-production-checkpoints-in-hyper-v). Checkpoint consistency behavior and the statement that checkpoints are not a replacement for backups. - Microsoft Learn: [Volume Shadow Copy Service overview](https://learn.microsoft.com/en-us/windows/win32/vss/volume-shadow-copy-service-overview). How VSS coordinates application-consistent copies on Windows. - Raff [pricing page](https://rafftechnologies.com/pricing). Snapshot and backup storage rates, checked August 2026. --- ### PowerShell Remoting on Windows Server 2025: Enable WinRM Securely URL: https://rafftechnologies.com/windows-server/powershell-remoting-windows-server-2025 Description: Set up PowerShell Remoting on Windows Server 2025 with WinRM, domain authentication, firewall rules, Enter-PSSession, Invoke-Command, TrustedHosts guidance, HTTPS options, and secure troubleshooting. ## In short **PowerShell Remoting** lets you run PowerShell commands on another Windows Server without opening an interactive RDP desktop. On Windows Server 2025, the standard Windows PowerShell remoting path uses **WinRM** and the WS-Management protocol. For a domain environment, the cleanest setup is: ```text Target Windows Server → enable PowerShell Remoting → confirm WinRM listener + firewall rules → use DNS/server name → authenticate with Kerberos → test with Test-WSMan → open Enter-PSSession or run Invoke-Command → restrict admin rights and network exposure ``` The basic server-side command is: ```powershell Enable-PSRemoting -Force ``` But a secure production setup is more than running one command. You still need the right authentication model, firewall scope, DNS, administrator permissions, and a decision about whether HTTP with Kerberos is sufficient or whether your environment requires a separate HTTPS listener. This page is the canonical Raff guide for **PowerShell Remoting / WinRM setup**. For a broader command reference, see [25 PowerShell Commands Every Windows VPS Admin Needs](/windows-server/powershell). ## What PowerShell Remoting actually does PowerShell Remoting lets one Windows system execute PowerShell commands on another system. Typical uses include: - checking services across multiple servers; - restarting application services; - collecting CPU, memory, disk, and event-log data; - running configuration changes remotely; - administering Server Core systems; - automating repetitive MSP or fleet-management tasks; - running commands against several Windows VMs at once. The three commands administrators use most are: | Command | Purpose | |---|---| | `Enable-PSRemoting` | Configure the target computer to receive PowerShell remote commands | | `Enter-PSSession` | Start one interactive remote PowerShell session | | `Invoke-Command` | Run commands or script blocks remotely, including on multiple servers | Fresh US DataForSEO demand confirms this is a meaningful Windows admin topic: `powershell remoting` is roughly 590 monthly searches with KD 1, while `invoke-command powershell` is also around 590 and `enter-pssession` around 480. ## PowerShell Remoting vs RDP PowerShell Remoting and Remote Desktop solve different problems. | Need | Better tool | |---|---| | Run one admin command remotely | PowerShell Remoting | | Run the same command on several servers | PowerShell Remoting | | Automate routine administration | PowerShell Remoting | | Manage Server Core | PowerShell Remoting | | Use a graphical application | RDP | | Troubleshoot a GUI-only installer | RDP | | Give employees a desktop session | RDS, not admin remoting | PowerShell Remoting is especially useful when you want to reduce how often administrators log into each server interactively. ## How WinRM fits into PowerShell Remoting Windows PowerShell remoting uses the **Windows Remote Management (WinRM)** service. In a typical configuration: ```text PowerShell client → WS-Man request → WinRM listener on target server → authenticated remote PowerShell session ``` Microsoft documents WinRM default listener ports as: - **TCP 5985** for HTTP; - **TCP 5986** for HTTPS. Do not broadly expose either port to the public internet. For hosted Windows VMs, scope management access to trusted administrator networks, private networking, VPN, or another controlled management path. ## Prerequisites Before enabling remoting, confirm: - the target is Windows Server 2025, 2022, 2019, or another supported Windows version; - you have administrator rights on the target server; - DNS resolves the target server correctly where domain authentication is used; - Windows Firewall remains enabled; - the administrator workstation can reach the server over the intended management network; - you know whether the target is domain-joined or in a workgroup; - you have a recovery path before changing firewall or authentication settings. For a production VPS, do not solve connectivity problems by disabling Windows Firewall or opening WinRM to every source address. ## Step 1 — Check the WinRM service On the target Windows Server, open PowerShell as Administrator and run: ```powershell Get-Service WinRM ``` You can also inspect its startup configuration: ```powershell Get-Service WinRM | Select-Object Name, Status, StartType ``` If PowerShell Remoting has not been configured yet, the service state alone does not prove the server is ready to receive remote PowerShell sessions. ## Step 2 — Enable PowerShell Remoting On the server you want to manage remotely, run: ```powershell Enable-PSRemoting -Force ``` Microsoft documents `Enable-PSRemoting` as configuring the computer to receive remote commands. On supported Windows Server systems, the command performs the required remoting setup for Windows PowerShell, including WinRM-related configuration and firewall exceptions appropriate to the network profile. The `-Force` switch suppresses confirmation prompts. It does not mean “ignore security.” Afterward, check WinRM again: ```powershell Get-Service WinRM | Select-Object Name, Status, StartType ``` ## Step 3 — Inspect the WinRM listeners Run: ```powershell winrm enumerate winrm/config/listener ``` or: ```powershell Get-ChildItem WSMan:\localhost\Listener ``` A default PowerShell Remoting configuration typically includes an HTTP WinRM listener. Do not assume you need HTTPS just because the listener says HTTP. In a properly configured Active Directory environment, Kerberos provides authentication and message protection for the remoting session even when WS-Man uses the HTTP transport. HTTPS becomes more relevant when the architecture, trust boundary, or compliance requirement calls for TLS at the transport layer. ## Step 4 — Review the Windows Firewall rules PowerShell Remoting depends on inbound WinRM access. Inspect relevant firewall rules: ```powershell Get-NetFirewallRule | Where-Object DisplayName -Like '*Windows Remote Management*' | Select-Object DisplayName, Enabled, Direction, Action, Profile ``` You can inspect port filters too: ```powershell Get-NetFirewallRule | Where-Object DisplayName -Like '*Windows Remote Management*' | Get-NetFirewallPortFilter ``` For general firewall administration, use [Configure Windows Firewall on a Windows VPS](/windows-server/configure-windows-firewall). ### Do not open WinRM broadly on a public VPS A rule such as “allow TCP 5985 from anywhere” is a poor default for internet-facing infrastructure. Prefer one of these patterns: ```text Administrator workstation → VPN/private network → Windows Server ``` or: ```text Known office/admin public IP → tightly scoped firewall rule → Windows Server ``` Use the smallest practical source range. ## Step 5 — Test WinRM connectivity with Test-WSMan From the administration computer, run: ```powershell Test-WSMan SERVER01 ``` Replace `SERVER01` with the target hostname. A successful response confirms that the client can reach the target WinRM service and negotiate WS-Management communication. If the test fails, check in this order: 1. DNS/name resolution; 2. network routing; 3. Windows Firewall; 4. WinRM service state; 5. listener configuration; 6. domain/workgroup trust model; 7. administrator permissions. Do not jump immediately to TrustedHosts. ## Step 6 — Use Enter-PSSession for an interactive session For an interactive remote shell: ```powershell Enter-PSSession -ComputerName SERVER01 ``` If explicit credentials are required: ```powershell Enter-PSSession ` -ComputerName SERVER01 ` -Credential (Get-Credential) ``` Once connected, the prompt changes to indicate that commands are being executed remotely. Run a harmless verification command: ```powershell hostname ``` Then: ```powershell Get-ComputerInfo | Select-Object CsName, WindowsProductName, WindowsVersion, OsBuildNumber ``` Exit the remote session with: ```powershell Exit-PSSession ``` ## Step 7 — Use Invoke-Command for one-off remote tasks `Invoke-Command` is better when you want to run a command without entering an interactive session. Example: ```powershell Invoke-Command ` -ComputerName SERVER01 ` -ScriptBlock { Get-Service WinRM } ``` Check disk space remotely: ```powershell Invoke-Command ` -ComputerName SERVER01 ` -ScriptBlock { Get-Volume | Where-Object DriveLetter | Select-Object DriveLetter, Size, SizeRemaining } ``` Restart a service remotely: ```powershell Invoke-Command ` -ComputerName SERVER01 ` -ScriptBlock { Restart-Service -Name W3SVC } ``` Only run change commands after confirming the target computer and expected impact. ## Step 8 — Run commands on several servers One major advantage of PowerShell Remoting is fan-out administration. ```powershell Invoke-Command ` -ComputerName 'SERVER01','SERVER02','SERVER03' ` -ScriptBlock { Get-Service WinRM | Select-Object MachineName, Name, Status } ``` A more useful inventory example: ```powershell Invoke-Command ` -ComputerName 'SERVER01','SERVER02','SERVER03' ` -ScriptBlock { Get-ComputerInfo | Select-Object CsName, WindowsProductName, OsBuildNumber } ``` For MSP and fleet-management workflows, this is the point where PowerShell Remoting becomes more efficient than opening three RDP sessions. ## Domain-joined servers: prefer Kerberos In an Active Directory environment, use server names that resolve correctly in DNS and let Kerberos handle authentication. A clean domain pattern is: ```text Admin workstation joined to domain → SERVER01.contoso.local → Kerberos authentication → WinRM ``` Benefits include: - mutual authentication; - no need to create broad TrustedHosts entries; - stronger identity assurance than treating arbitrary IP addresses as trusted endpoints; - easier centralized administration. Use the server's DNS name rather than an IP address when Kerberos is part of the authentication design. ## Workgroup servers and TrustedHosts Workgroup environments do not have the same Kerberos trust relationship as an Active Directory domain. This is where administrators often encounter **TrustedHosts**. You can inspect the current list with: ```powershell Get-Item WSMan:\localhost\Client\TrustedHosts ``` The dangerous shortcut is: ```powershell Set-Item WSMan:\localhost\Client\TrustedHosts -Value '*' ``` Do **not** use a wildcard TrustedHosts value as a generic production fix. It tells the WinRM client to trust any remote computer for authentication scenarios that use TrustedHosts. If TrustedHosts is genuinely required, scope it narrowly to explicit server names or addresses and understand that TrustedHosts is an authentication trust decision, not an encryption feature. Example of a narrow entry: ```powershell Set-Item ` WSMan:\localhost\Client\TrustedHosts ` -Value 'SERVER01' ``` For multiple explicit hosts: ```powershell Set-Item ` WSMan:\localhost\Client\TrustedHosts ` -Value 'SERVER01,SERVER02' ``` Re-check afterward: ```powershell Get-Item WSMan:\localhost\Client\TrustedHosts ``` ## Should you use WinRM over HTTPS? HTTPS uses a TLS certificate and normally listens on TCP 5986. Consider a dedicated HTTPS listener when: - the server is outside a trusted domain boundary; - policy requires TLS transport; - you manage systems across networks where Kerberos is unavailable; - you need certificate-backed endpoint identity as part of the design. Do not create a self-signed certificate and expose port 5986 globally just to say “we use HTTPS.” The certificate name, trust chain, firewall scope, and client verification still matter. In a domain environment using Kerberos, HTTP does not mean the PowerShell command contents are simply sent in clear text. WS-Man authentication mechanisms protect the session. Transport HTTPS is a separate architectural choice. ## High-level WinRM HTTPS setup A proper HTTPS listener needs a server-authentication certificate whose subject or SAN matches the hostname clients use. At a high level: ```text trusted certificate → WinRM HTTPS listener → firewall rule for TCP 5986 from management sources → client connects with -UseSSL ``` Inspect existing listeners first: ```powershell winrm enumerate winrm/config/listener ``` When an HTTPS listener has been correctly configured, test it from a client with: ```powershell Test-WSMan SERVER01 -UseSSL ``` and connect with: ```powershell Enter-PSSession ` -ComputerName SERVER01 ` -UseSSL ` -Credential (Get-Credential) ``` Because certificate enrollment and listener creation vary by PKI and environment, use Microsoft's current WinRM HTTPS documentation for the exact certificate/listener procedure rather than copying an unverified certificate script into production. ## PowerShell Remoting authentication choices PowerShell remoting can support multiple authentication mechanisms depending on environment and configuration. For normal Windows Server administration, think in this order: | Environment | Preferred direction | |---|---| | Active Directory domain | Kerberos with DNS names | | Workgroup / no domain trust | Explicit credentials plus carefully scoped trust or HTTPS architecture | | Cross-boundary managed environment | Evaluate HTTPS/certificate design and organizational security requirements | Avoid enabling weaker authentication simply to make a test pass. ## Administrator permissions and least privilege By default, PowerShell Remoting endpoints are administrative management interfaces. Do not give ordinary application users local Administrator membership merely because you want them to run one remote task. For mature environments, evaluate **Just Enough Administration (JEA)** so operators can perform a defined set of administrative tasks without receiving unrestricted administrator access. JEA is especially relevant for: - help-desk teams; - MSP operators; - delegated application support; - routine service restarts; - controlled diagnostics. This article does not turn JEA into a second canonical topic; it is a hardening direction for remoting deployments. ## The second-hop problem A remote session can authenticate successfully to `SERVER01` and still fail when that remote server then tries to access another protected network resource such as `FILE01`. Example: ```text ADMIN-PC → PowerShell Remoting → SERVER01 → attempts to access → FILE01 ``` This is commonly called the **second-hop problem**. Do not solve it by casually enabling credential delegation. Depending on the environment, Microsoft documents options such as resource-based Kerberos constrained delegation, Kerberos constrained delegation, CredSSP, RunAs session configurations, and other patterns. Choose the least-risk design for the actual workflow. CredSSP, for example, delegates credentials and therefore has a different security trade-off than normal Kerberos remoting. ## Secure configuration checklist Before using PowerShell Remoting in production, confirm: - [ ] Windows Firewall remains enabled. - [ ] WinRM ports are not broadly exposed to the internet. - [ ] Domain systems use DNS names and Kerberos where possible. - [ ] TrustedHosts is empty unless the architecture specifically requires it. - [ ] TrustedHosts never uses `*` as a convenience production setting. - [ ] Administrator permissions are limited to people who need them. - [ ] Remote commands are auditable. - [ ] PowerShell logging is considered for sensitive environments. - [ ] HTTPS certificates are trusted and hostname-correct when HTTPS is used. - [ ] A recovery path exists before firewall/authentication changes. - [ ] JEA is considered for delegated administration. For the wider production baseline, use [Windows Server Hardening Checklist](/windows-server/windows-server-hardening-checklist). ## PowerShell logging for remote administration For environments where remote administrative actions need stronger visibility, PowerShell logging can help. The broader hardening guide covers script block logging and security logs. Relevant signals include: - PowerShell Operational logs; - WinRM Operational logs; - Security logon events; - process-creation auditing; - administrative group changes. Remember that verbose PowerShell logging can capture sensitive values if administrators place secrets directly inside commands or scripts. Do not type passwords or tokens into script text. ## Common errors and fixes ### `Connecting to remote server failed` Check: ```powershell Test-WSMan SERVER01 ``` Then verify DNS, routing, WinRM service, listener, firewall, and authentication. ### `WinRM cannot complete the operation` Confirm the target hostname resolves and the management port is reachable. ```powershell Test-NetConnection SERVER01 -Port 5985 ``` For HTTPS: ```powershell Test-NetConnection SERVER01 -Port 5986 ``` ### Access is denied Check whether the account has the required rights on the target server and whether you are connecting to the intended endpoint. Do not fix this by adding every operator to Domain Admins. ### The IP address works poorly with domain authentication Use the server's DNS hostname so Kerberos can work as designed. ### Workgroup authentication fails Confirm whether the design requires an HTTPS listener or a narrow TrustedHosts entry. Do not immediately set TrustedHosts to `*`. ### Port 5985 is reachable but Enter-PSSession fails Network reachability is only one layer. Check authentication, endpoint configuration, credentials, and authorization. ### HTTPS fails with a certificate error Verify: - hostname matches certificate subject/SAN; - issuing CA is trusted by the client; - certificate is not expired; - the correct certificate is bound to the WinRM HTTPS listener. ## Useful PowerShell Remoting commands ### Enable remoting ```powershell Enable-PSRemoting -Force ``` ### Test WS-Man ```powershell Test-WSMan SERVER01 ``` ### Interactive remote shell ```powershell Enter-PSSession -ComputerName SERVER01 ``` ### Interactive session with credentials ```powershell Enter-PSSession ` -ComputerName SERVER01 ` -Credential (Get-Credential) ``` ### One-off command ```powershell Invoke-Command ` -ComputerName SERVER01 ` -ScriptBlock { Get-Service } ``` ### Multiple servers ```powershell Invoke-Command ` -ComputerName SERVER01,SERVER02,SERVER03 ` -ScriptBlock { hostname } ``` ### Inspect WinRM service ```powershell Get-Service WinRM ``` ### Inspect listeners ```powershell winrm enumerate winrm/config/listener ``` ### Inspect TrustedHosts ```powershell Get-Item WSMan:\localhost\Client\TrustedHosts ``` ## Where Raff fits Raff Windows VMs provide the Windows Server infrastructure where PowerShell Remoting can be used for administration and automation. For a small Windows fleet, a practical model is: ```text Admin workstation or management VM → private/trusted management path → Raff Windows VMs → PowerShell Remoting ``` Raff provides the VM infrastructure; the administrator remains responsible for Windows identity, WinRM configuration, firewall scope, certificates, PowerShell authorization, and automation scripts unless a separate managed service explicitly covers them. :::cta Deploy Windows Now Deploy a Raff Windows VM for your Windows Server workload, then use PowerShell Remoting to manage repeatable administration without relying on an RDP session for every task. ::: ## Frequently asked questions ### Is PowerShell Remoting enabled by default on Windows Server 2025? Windows Server is designed for remote administration, but administrators should verify the effective WinRM and PowerShell remoting configuration rather than assuming every image, firewall profile, or provider template is identical. `Enable-PSRemoting -Force` is the standard command to configure Windows PowerShell remoting on a target system. ### What port does PowerShell Remoting use? WinRM normally uses TCP 5985 for HTTP and TCP 5986 for HTTPS. ### Is PowerShell Remoting over HTTP insecure? Not automatically. In an Active Directory environment, Kerberos can provide authentication and message protection while WinRM uses HTTP transport. HTTPS is a separate transport-security option and may be appropriate for cross-boundary or policy-driven deployments. ### Should I add `*` to TrustedHosts? No. A wildcard TrustedHosts value is an overly broad trust decision. Use Kerberos/domain authentication where possible or explicitly scope TrustedHosts only when the architecture genuinely requires it. ### What is the difference between Enter-PSSession and Invoke-Command? `Enter-PSSession` creates an interactive session to one target. `Invoke-Command` executes a command or script block remotely and can target one or many computers. ### Can PowerShell Remoting replace RDP? For many administration and automation tasks, yes. It does not replace RDP for GUI-only software or Remote Desktop Services for end-user desktop sessions. ### Can I manage several Windows Servers at the same time? Yes. `Invoke-Command -ComputerName` can target multiple computers, which is one of the main advantages of PowerShell Remoting for server fleets and MSP workflows. ## What's next - [25 PowerShell Commands Every Windows VPS Admin Needs](/windows-server/powershell) - [Configure Windows Firewall on a Windows VPS](/windows-server/configure-windows-firewall) - [Windows Server Hardening Checklist](/windows-server/windows-server-hardening-checklist) - [Windows Server Core vs Desktop Experience](/windows-server/windows-server-core-vs-desktop-experience) - [Raff Windows VM](/products/windows-vm) ## Sources - Microsoft Learn — Enable-PSRemoting: https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/enable-psremoting - Microsoft Learn — about_Remote: https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_remote - Microsoft Learn — about_Remote_Requirements: https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_remote_requirements - Microsoft Learn — Enter-PSSession: https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/enter-pssession - Microsoft Learn — Invoke-Command: https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/invoke-command - Microsoft Learn — WinRM installation and configuration: https://learn.microsoft.com/en-us/windows/win32/winrm/installation-and-configuration-for-windows-remote-management - Microsoft Learn — PowerShell remoting second hop: https://learn.microsoft.com/en-us/powershell/scripting/security/remoting/ps-remoting-second-hop - Microsoft Learn — Just Enough Administration: https://learn.microsoft.com/en-us/powershell/scripting/security/remoting/jea/overview - Sources verified: 2026-08-29 --- ### Active Directory DNS on Windows Server 2025: Setup, Forwarders, and Best Practices URL: https://rafftechnologies.com/windows-server/active-directory-dns-windows-server-2025 Description: Configure Active Directory DNS on Windows Server 2025 with AD-integrated zones, secure dynamic updates, forwarders, conditional forwarders, SRV validation, reverse lookup, and DNS health checks. ## In short **Active Directory DNS** is how domain members locate domain controllers, Kerberos, LDAP, Global Catalog, and other directory services. A clean Windows Server 2025 design keeps the AD namespace on internal DNS servers, uses AD-integrated zones with secure dynamic updates, verifies the domain-controller locator records, and uses deliberate forwarders for names the AD DNS servers do not host. For a typical small-business or MSP deployment: ![Active Directory DNS architecture on Windows Server 2025 showing domain members using internal AD DNS, domain controllers handling AD DS, DNS, locator records, and replication, plus conditional forwarding to authoritative DNS servers for specific internal or partner namespaces.](https://raff-images.s3.raffusercloud.com/2_0ea36c5370.jpg) This article is the canonical owner for **post-promotion Active Directory DNS configuration, validation, forwarders, conditional forwarders, and operational best practices**. Domain-controller promotion remains on [Promote a Windows VPS to an Active Directory Domain Controller](/windows-server/active-directory-domain-controller), while generic Windows DNS troubleshooting should remain a separate troubleshooting intent. ## Why Active Directory depends on DNS Microsoft documents that Active Directory Domain Services uses DNS so clients can locate domain controllers and so directory servers can find each other. Domain-controller locator information is published through DNS records such as LDAP and Kerberos SRV records. When AD DNS is unhealthy, the symptoms can look like an Active Directory, Group Policy, authentication, or replication problem: - domain joins fail; - logons are slow or inconsistent; - Group Policy applies unpredictably; - replication fails; - clients discover the wrong domain controller; - LDAP or Kerberos lookups fail; - domain-controller locator records are missing; - password or directory changes appear inconsistent between locations. For that reason, DNS should be checked before making invasive changes to AD itself. ## What this guide covers This guide assumes you already have at least one Windows Server 2025 domain controller running the DNS Server role. We will verify and configure: 1. DNS service and client settings; 2. AD-integrated zones; 3. secure dynamic updates; 4. LDAP and Kerberos SRV records; 5. server-level forwarders; 6. conditional forwarders; 7. optional reverse lookup zones; 8. `dcdiag` DNS health checks; 9. one-DC vs two-DC DNS design. ## Prerequisites Before changing DNS, confirm: - the server is already a domain controller or intended AD DNS server; - the DNS Server service is running; - the server has stable private addressing; - you know the Active Directory DNS domain; - you have administrative access; - domain traffic uses private networking, VPN, or another trusted path; - you have recorded existing forwarders before changing them; - production changes have a rollback path. Do not configure domain members to bypass AD DNS and query public recursive resolvers as their normal DNS path. Public resolvers do not know the private locator records required by your AD namespace. For production, plan at least two domain controllers. See [Active Directory Replication Topology for 2-DC Setups](/windows-server/ad-replication-topology). ## Step 1 — Record the current DNS configuration Start by documenting the current state. Run PowerShell as Administrator: ```powershell Get-Service DNS,Netlogon | Select-Object Name, Status Get-DnsServerZone | Select-Object ZoneName, ZoneType, IsDsIntegrated, IsReverseLookupZone, DynamicUpdate Get-DnsServerForwarder Get-DnsClientServerAddress -AddressFamily IPv4 | Where-Object {$_.ServerAddresses.Count -gt 0} | Select-Object InterfaceAlias, ServerAddresses ``` Record the AD domain as well: ```powershell Import-Module ActiveDirectory Get-ADDomain | Select-Object DNSRoot, NetBIOSName, PDCEmulator ``` A first domain controller commonly has the domain zone and a forest locator zone such as: ```text example.com _msdcs.example.com ``` The exact zones depend on the forest and topology. ![Windows Server 2025 Active Directory domain controller showing DNS and Netlogon services running and domain details](https://raff-images.s3.raffusercloud.com/01_ad_dns_environment_windows_server_2025_68ae3e3cfe.png) ## Step 2 — Verify the AD-integrated zones AD-integrated DNS zones store zone data in Active Directory. Microsoft documents that this removes the need for a separate classic DNS zone-transfer replication topology for those zones and enables multi-master updates through AD replication. Inspect the current zones: ```powershell Get-DnsServerZone | Format-Table ZoneName, ZoneType, IsDsIntegrated, IsReverseLookupZone, DynamicUpdate -AutoSize ``` For the AD domain zone, the expected production pattern is normally: ```text ZoneType Primary IsDsIntegrated True DynamicUpdate Secure ``` Do not convert a production zone between file-backed and AD-integrated storage merely to match a tutorial. Understand the current replication scope, dependencies, and recovery plan first. ![PowerShell showing AD-integrated DNS zones with secure dynamic updates on Windows Server 2025 Caption: AD-integrated DNS zones on the Raff lab domain controller, including secure dynamic updates. Replace this comment with the final Markdown image after the Strapi/S3 URL is available.](https://raff-images.s3.raffusercloud.com/02_ad_integrated_dns_zones_secure_updates_068ec65546.png) ## Step 3 — Verify secure dynamic updates Dynamic DNS allows domain computers and domain controllers to register and update records. Active Directory-integrated zones can use secure dynamic updates so updates are governed by authenticated identities and directory permissions. Check the domain zone: ```powershell $Domain = (Get-ADDomain).DNSRoot Get-DnsServerZone -Name $Domain | Select-Object ZoneName, IsDsIntegrated, DynamicUpdate ``` If the zone is AD-integrated and your intended policy is secure-only updates, Windows Server supports: ```powershell Set-DnsServerPrimaryZone -Name $Domain -DynamicUpdate Secure ``` Do not run that change blindly on an existing production environment. First verify the current zone type and whether any non-domain systems depend on a different registration design. Avoid using `NonsecureAndSecure` simply to make an unknown registration problem disappear. That widens who can dynamically register records in the zone. ## Step 4 — Verify the domain-controller SRV records Active Directory uses SRV records to advertise directory services. Microsoft specifically documents LDAP and Kerberos locator records used to find domain controllers. Set the domain automatically: ```powershell $Domain = (Get-ADDomain).DNSRoot ``` Verify LDAP domain-controller discovery: ```powershell Resolve-DnsName -Type SRV "_ldap._tcp.dc._msdcs.$Domain" ``` Verify Kerberos: ```powershell Resolve-DnsName -Type SRV "_kerberos._tcp.$Domain" ``` You can also use `nslookup`: ```cmd nslookup -type=SRV _ldap._tcp.dc._msdcs.example.com ``` A healthy result should return one or more domain-controller host names and the expected SRV service ports. If the records are missing, do not manually create random SRV records as the first fix. Check Netlogon, dynamic update state, zone health, DNS client configuration, and record registration. ![PowerShell showing Active Directory LDAP and Kerberos SRV records resolving to the domain controller Caption: LDAP and Kerberos SRV records resolving successfully for the Raff Active Directory test domain. Replace this comment with the final Markdown image after the Strapi/S3 URL is available.](https://raff-images.s3.raffusercloud.com/03_active_directory_srv_records_57091a94d4.png) ## Step 5 — Verify domain-controller discovery and forward resolution Confirm the DC host name resolves: ```powershell $Domain = (Get-ADDomain).DNSRoot $DC = (Get-ADDomainController -Discover).HostName Resolve-DnsName $DC Resolve-DnsName $Domain ``` Then test domain-controller discovery: ```cmd nltest /dsgetdc:example.com ``` Replace `example.com` with your actual AD DNS domain. For multi-DC environments, also verify AD site mapping and replication. A valid DNS response is only one part of correct site-aware domain-controller discovery. ## Step 6 — Configure server-level forwarders deliberately A DNS forwarder receives queries the local DNS server cannot answer. This lets domain clients continue using AD DNS while the DNS server sends public-name queries to approved recursive resolvers. Read the existing configuration first: ```powershell Get-DnsServerForwarder ``` This is important because `Set-DnsServerForwarder` replaces the existing server-level forwarder list. For a new controlled environment, example syntax is: ```powershell Set-DnsServerForwarder ` -IPAddress 1.1.1.1,8.8.8.8 ` -PassThru ``` Those IPs are examples of public recursive resolvers, not a Raff requirement. Use DNS resolvers approved for your organization, network, or customer. If you only want to append one resolver rather than replace the list: ```powershell Add-DnsServerForwarder -IPAddress 1.1.1.1 -PassThru ``` Then verify a real external lookup: ```powershell Resolve-DnsName www.microsoft.com ``` Windows DNS can use normal recursion/root hints after configured forwarders are exhausted unless the server is configured otherwise. ![PowerShell showing Windows DNS forwarders and successful external DNS resolution to microsoft.com Caption: Configured DNS forwarders with successful external name resolution from the Raff AD DNS server. Replace this comment with the final Markdown image after the Strapi/S3 URL is available.](https://raff-images.s3.raffusercloud.com/04_dns_forwarders_external_resolution_6510f8d591.png) ## Step 7 — Use conditional forwarders for specific namespaces A normal forwarder handles unresolved queries broadly. A **conditional forwarder** sends queries for one particular DNS namespace to specific DNS servers. Useful examples include: - two internal AD forests that need cross-forest name resolution; - an office namespace resolving a cloud namespace; - a partner/internal domain with dedicated authoritative DNS servers; - migration periods where two internal namespaces coexist. Architecture: ```text corp.example.com DNS | | query for partner.internal v Conditional forwarder | v Authoritative partner DNS servers ``` Do not use a conditional forwarder just to resolve normal internet names. ## Step 8 — Create an AD-integrated conditional forwarder Microsoft's `Add-DnsServerConditionalForwarderZone` cmdlet can create a conditional forwarder. With a replication scope, the forwarder can be stored in Active Directory and replicated to the selected AD DNS scope. Example: ```powershell Add-DnsServerConditionalForwarderZone ` -Name "partner.internal" ` -MasterServers 10.20.0.10,10.20.0.11 ` -ReplicationScope Forest ` -PassThru ``` Use real IP addresses for DNS servers that are authoritative for the target namespace and reachable over the intended network path. Verify the zone object: ```powershell Get-DnsServerZone -Name "partner.internal" | Format-List ZoneName, ZoneType, IsDsIntegrated ``` Then test an actual record that is known to exist: ```powershell Resolve-DnsName server01.partner.internal ``` A configured forwarder object is not proof that name resolution works. The target DNS servers must be reachable and authoritative for the namespace. We intentionally do not require a screenshot for this section unless a real reachable secondary namespace is available. Do not create a fake partner domain only for documentation evidence. ## Conditional forwarder vs delegation | Requirement | Better fit | |---|---| | Send queries for one specific external/internal namespace to known DNS servers | Conditional forwarder | | Delegate authority for a child zone inside a DNS hierarchy you control | Delegation | | Resolve ordinary internet names | Server-level forwarders or normal recursion | | Replicate one conditional forwarder across AD DNS servers | AD-integrated conditional forwarder | They are related DNS tools but they do not represent the same ownership model. ## Step 9 — Add a reverse lookup zone only when it is useful Active Directory domain-controller discovery does not depend on PTR records, but reverse DNS can improve administration, diagnostics, logging, and compatibility with software that performs reverse lookups. For a private subnet such as `10.10.0.0/24`, example syntax for an AD-integrated reverse zone is: ```powershell Add-DnsServerPrimaryZone ` -NetworkId "10.10.0.0/24" ` -ReplicationScope Forest ` -DynamicUpdate Secure ``` Verify reverse zones: ```powershell Get-DnsServerZone | Where-Object IsReverseLookupZone | Format-Table ZoneName, IsDsIntegrated, DynamicUpdate ``` Then test a PTR record that actually exists: ```powershell Resolve-DnsName 10.10.0.10 -Type PTR ``` Do not invent PTR records only to make a lab screenshot look successful. Reverse records should reflect the real network. The Raff lab check showed only the standard `0.in-addr.arpa`, `127.in-addr.arpa`, and `255.in-addr.arpa` zones rather than a real AD-integrated reverse zone for the workload network, so reverse-DNS screenshot evidence is intentionally omitted. ## Step 10 — Run the Active Directory DNS health tests `dcdiag` includes dedicated DNS tests for connectivity, forwarders, delegation, dynamic updates, and domain-controller record registration. Basic DNS: ```cmd dcdiag /test:dns /DnsBasic /v ``` ![DCDiag DNS basic test results for a Windows Server 2025 Active Directory domain controller Caption: Basic Active Directory DNS health check completed with dcdiag on the Raff Windows Server 2025 domain controller. Replace this comment with the final Markdown image after the Strapi/S3 URL is available.](https://raff-images.s3.raffusercloud.com/05_dcdiag_dns_basic_6b2456df41.png) Forwarders: ```cmd dcdiag /test:dns /DnsForwarders /v ``` Dynamic updates: ```cmd dcdiag /test:dns /DnsDynamicUpdate /v ``` Domain-controller record registration: ```cmd dcdiag /test:dns /DnsRecordRegistration /v ``` ![DCDiag DNS record registration test verifying Active Directory A, CNAME, and SRV records Caption: DCDiag record-registration test validating the domain controller's critical Active Directory DNS records. Replace this comment with the final Markdown image after the Strapi/S3 URL is available.](https://raff-images.s3.raffusercloud.com/06_dcdiag_dns_record_registration_4410d19b34.png) Broader DNS test: ```cmd dcdiag /test:dns /v ``` Microsoft documents that the record-registration test checks important A, CNAME, and SRV records used for domain-controller location. In large forests, DNS tests can take longer, especially when testing every domain controller. Scope the test intentionally. ## Step 11 — Configure domain-member DNS correctly Domain members should query DNS servers that can resolve the AD namespace. For a typical two-DC environment: ```text Preferred DNS: local/site-appropriate DC private IP Alternate DNS: another internal AD DNS/DC private IP ``` Do not configure a domain member like this: ```text Preferred DNS: public resolver Alternate DNS: DC01 ``` A public resolver does not host your private AD locator records. Verify a member server with: ```powershell Get-DnsClientServerAddress -AddressFamily IPv4 | Where-Object {$_.ServerAddresses.Count -gt 0} | Select-Object InterfaceAlias, ServerAddresses ``` ## DNS client settings on domain controllers Domain controllers must also use DNS servers that host the AD namespace. In a one-DC lab that can mean the local AD DNS service. In a two-DC or multi-site environment, choose internal DNS ordering deliberately based on topology and resilience. Do not point a domain controller only at public DNS resolvers. External lookups should be handled by the DNS server's forwarding/recursion configuration, not by bypassing AD DNS at the NIC level. ![Windows Server 2025 domain controller DNS client settings using the local AD DNS service at 127.0.0.1](https://raff-images.s3.raffusercloud.com/07_domain_controller_dns_client_settings_50759178b5.png) ## Secure dynamic updates are the normal AD baseline A practical AD DNS pattern is: ```text AD-integrated zone + Secure dynamic updates + domain clients using internal AD DNS + healthy Netlogon registration ``` If a non-domain device needs a DNS record, manage that record deliberately rather than weakening the entire AD zone to open dynamic registration. ## Be careful with aging and scavenging DNS aging and scavenging can clean stale dynamic records, but poor configuration can also remove records you still need. Before enabling scavenging in production: - inventory static records; - understand no-refresh and refresh intervals; - understand DHCP/DNS ownership behavior; - test on a controlled scope; - document recovery; - monitor resulting deletions. There is no single universal scavenging interval for every AD environment. DHCP lease duration and client behavior matter. ## Active Directory DNS best-practice checklist | Area | Baseline | |---|---| | DNS namespace | AD namespace hosted on internal authoritative DNS servers | | Zone storage | AD-integrated where appropriate for AD DNS | | Dynamic updates | Secure for AD-integrated domain zones | | Domain members | Use internal AD DNS, not public DNS directly | | Domain controllers | Use internal AD DNS paths only | | External resolution | Deliberate forwarders or normal recursion | | Conditional forwarding | Only for specific namespaces with known DNS servers | | SRV records | Verify LDAP/Kerberos/DC locator records | | Reverse DNS | Optional; keep PTR data accurate if used | | Replication | Verify AD/DNS replication in multi-DC environments | | Exposure | Keep AD DNS private; do not operate it as a public recursive resolver | | Changes | Record existing forwarder/zone config before modifying it | | Health checks | Use `dcdiag /test:dns` plus real resolution tests | | Recovery | Include AD-integrated DNS in AD backup/recovery planning | ## DNS architecture: one DC vs two DCs ### One-DC lab ```text Domain members | v DC01 / AD DNS | +--> AD-integrated zones | `--> approved external forwarders ``` This is acceptable for a lab. It is still a single point of failure for authentication and DNS. ### Two-DC production baseline ```text Trusted private network /-------------------------------\ / \ DC01 DC02 AD DS/DNS AD DS/DNS \ / \------- AD replication --------/ Clients -> internal DNS on DC01/DC02 AD DNS -> approved external forwarders for public names ``` Because AD-integrated zone data is stored in AD DS, zone data can replicate through Active Directory rather than through a separate classic zone-transfer design. For the full topology, use [Active Directory Replication Topology for 2-DC Setups](/windows-server/ad-replication-topology). ## Common Active Directory DNS mistakes ### Pointing clients directly to public DNS Public resolvers do not know your private AD locator records. Keep domain clients on AD DNS and let AD DNS resolve external names upstream. ### Replacing forwarders without recording the existing list `Set-DnsServerForwarder` replaces the forwarder list. Read the current configuration first. Use `Add-DnsServerForwarder` when you only intend to append a resolver. ### Enabling nonsecure dynamic updates as a quick fix For AD-integrated zones, secure updates should normally be preferred. Diagnose why a device cannot register instead of weakening the whole zone without a reason. ### Manually creating SRV records before fixing registration Missing `_ldap` or `_kerberos` records usually point to a Netlogon, zone, DNS client, or dynamic-registration problem. Fix the registration path rather than masking it. ### Creating conditional forwarders to unreachable servers A conditional-forwarder object can exist while every query still fails. Test a real record in the target namespace. ### Treating reverse DNS as proof that AD DNS is healthy PTR records are useful but domain-controller discovery depends on forward DNS and the correct locator records. ### Exposing AD DNS to the public internet AD DNS is internal identity infrastructure. Keep TCP/UDP 53 on trusted networks unless a separately designed public-authoritative DNS role exists for a different purpose. ### Ignoring DNS during replication troubleshooting Many apparent AD replication issues are name-resolution failures. Check DNS early. ## Troubleshooting order When Active Directory DNS appears broken: 1. Confirm DNS and Netlogon are running. 2. Confirm the server's DNS client settings use internal AD DNS. 3. Confirm the domain zone exists and is AD-integrated as expected. 4. Confirm dynamic-update mode is correct. 5. Resolve the DC host name. 6. Resolve `_ldap._tcp.dc._msdcs.`. 7. Run `dcdiag /test:dns /DnsBasic /v`. 8. Run `dcdiag /test:dns /DnsRecordRegistration /v`. 9. Check server-level forwarders if only external names fail. 10. Check target-server reachability if only one conditional-forwarder namespace fails. 11. In multi-DC environments, verify replication and AD site configuration. Do not start by deleting zones, changing the NIC to public DNS, or making multiple unrelated changes at once. Those actions can hide the real fault and make rollback difficult. ## Where Raff fits Raff Windows VMs can provide the Windows Server infrastructure for domain controllers and AD-integrated DNS where administrators need control of the operating system, private networking, firewall rules, backups, and topology. A small production deployment commonly uses two dedicated Windows VMs as domain controllers/DNS servers over a trusted private path. Raff provides the infrastructure layer; Active Directory architecture, DNS configuration, replication, security, backup, and recovery remain administrator responsibilities unless a separate managed service explicitly covers them. For a new forest, start with [Promote a Windows VPS to an Active Directory Domain Controller](/windows-server/active-directory-domain-controller). For redundancy, continue to [Active Directory Replication Topology for 2-DC Setups](/windows-server/ad-replication-topology). ## Draft validation status The screenshot positions are prepared in Strapi. The draft should remain unpublished until the uploaded media is inserted and the captured outputs are reviewed against the article claims. Required publication evidence: - Windows Server version/build and DC identity; - DNS and Netlogon services running; - real AD-integrated zones and secure dynamic-update state; - successful LDAP/Kerberos SRV lookup; - verified server-level forwarder configuration and external resolution; - `dcdiag /test:dns` basic evidence; - `dcdiag /test:dns /DnsRecordRegistration` evidence; - domain-controller DNS client configuration; - no public exposure of AD DNS introduced for testing. A conditional-forwarder screenshot is not required without a real second namespace, and reverse-DNS evidence is intentionally omitted because the lab did not have a real workload reverse zone to validate. ## Frequently asked questions ### Does Active Directory require DNS? Yes. AD DS relies on DNS for domain-controller and directory-service discovery. Domain controllers register locator records, including SRV records, that clients use to find LDAP, Kerberos, and other AD services. ### Should domain-joined computers use 8.8.8.8 or another public resolver directly? Not as their normal Active Directory DNS path. Domain members should query internal DNS servers that know the AD namespace. Those DNS servers can then forward external queries to approved upstream resolvers. ### What is an AD-integrated DNS zone? It is a DNS zone stored in Active Directory Domain Services. The DNS data can replicate through AD replication and use directory security for updates. ### What is the difference between a forwarder and a conditional forwarder? A server-level forwarder handles unresolved queries broadly. A conditional forwarder sends queries for one specific DNS namespace to specified DNS servers. ### How do I verify Active Directory SRV records? Query `_ldap._tcp.dc._msdcs.` with `Resolve-DnsName` or `nslookup`. You can also use `dcdiag /test:dns /DnsRecordRegistration /v` to validate important domain-controller DNS registrations. ### Which `dcdiag` command checks DNS forwarders? Use: ```cmd dcdiag /test:dns /DnsForwarders /v ``` Other DNS-specific tests cover basic DNS, delegation, dynamic updates, and record registration. ### Do I need a reverse lookup zone for Active Directory? Not for basic domain-controller discovery. Reverse zones are still useful for administration, diagnostics, logging, and software that expects PTR records. ## What's next - [Promote a Windows VPS to an Active Directory Domain Controller](/windows-server/active-directory-domain-controller) - [Active Directory Replication Topology for 2-DC Setups](/windows-server/ad-replication-topology) - [Active Directory Group Policy Setup from Scratch](/windows-server/ad-group-policy-setup) - [Windows LAPS on Windows Server 2025](/windows-server/windows-laps-windows-server-2025) - [Windows Server Hardening Checklist](/windows-server/windows-server-hardening-checklist) - [Raff Windows VM](/products/windows-vm) ## Sources - Microsoft Learn — DNS and AD DS: https://learn.microsoft.com/en-us/windows-server/identity/ad-ds/plan/dns-and-ad-ds - Microsoft Learn — Active Directory-Integrated DNS Zones: https://learn.microsoft.com/en-us/windows-server/identity/ad-ds/plan/active-directory-integrated-dns-zones - Microsoft Learn — DNS Forwarding in Windows Server: https://learn.microsoft.com/en-us/windows-server/networking/dns/forwarding - Microsoft Learn — Add-DnsServerConditionalForwarderZone: https://learn.microsoft.com/en-us/powershell/module/dnsserver/add-dnsserverconditionalforwarderzone?view=windowsserver2025-ps - Microsoft Learn — Set-DnsServerForwarder: https://learn.microsoft.com/en-us/powershell/module/dnsserver/set-dnsserverforwarder?view=windowsserver2025-ps - Microsoft Learn — Get-DnsServerForwarder: https://learn.microsoft.com/en-us/powershell/module/dnsserver/get-dnsserverforwarder?view=windowsserver2025-ps - Microsoft Learn — Set-DnsServerPrimaryZone: https://learn.microsoft.com/en-us/powershell/module/dnsserver/set-dnsserverprimaryzone?view=windowsserver2025-ps - Microsoft Learn — Add-DnsServerPrimaryZone: https://learn.microsoft.com/en-us/powershell/module/dnsserver/add-dnsserverprimaryzone?view=windowsserver2025-ps - Microsoft Learn — Verify that SRV DNS records have been created: https://learn.microsoft.com/en-us/troubleshoot/windows-server/networking/verify-srv-dns-records-have-been-created - Microsoft Learn — dcdiag: https://learn.microsoft.com/en-us/windows-server/administration/windows-commands/dcdiag - Microsoft Learn — Verify DNS functionality to support directory replication: https://learn.microsoft.com/en-us/windows-server/identity/ad-ds/manage/troubleshoot/verify-dns-functionality-to-support-directory-replication - Sources verified: 2026-09-01 --- ### Active Directory Backup and Authoritative Restore on Windows Server 2025 URL: https://rafftechnologies.com/windows-server/active-directory-backup-authoritative-restore-windows-server-2025 Description: Back up and recover Active Directory on Windows Server 2025 with System State, DSRM, non-authoritative recovery, authoritative object restore, Recycle Bin, and tested recovery planning. ## In short An **Active Directory backup** is not the same thing as taking a VM snapshot. For a domain controller, the recovery plan should include an Active Directory-aware backup such as **System State**, a documented Directory Services Restore Mode (DSRM) path, and a clear decision for when to use **Recycle Bin**, a **non-authoritative restore**, an **authoritative restore**, or a broader forest recovery procedure. For most administrators, the important decision is not simply "How do I restore AD?" but **what failed, what remains healthy, and which recovery scope is actually required**. ```text What failed? | |-- One deleted user / OU | -> Recycle Bin first, if enabled and eligible | |-- One failed DC, other DCs healthy | -> usually replace/rebuild the failed DC after health checks | |-- Need an older directory object/state to win replication | -> authoritative restore may be appropriate | |-- Restoring a DC from System State while healthy partners exist | -> non-authoritative restore, then replication updates it | `-- Forest-wide corruption / compromise / loss -> formal isolated forest recovery plan ``` This guide owns **Active Directory backup and recovery intent**: System State backup, backup verification, DSRM recovery concepts, non-authoritative vs authoritative restore, deleted-object recovery choices, and post-restore validation. It does **not** replace the generic [Windows VPS Backup Strategy for Small Businesses](/windows-server/windows-vps-backup-strategy-small-business), [Snapshot vs Backup](/windows-server/snapshot-vs-backup-windows-vps), or [Active Directory Replication Topology for 2-DC Setups](/windows-server/ad-replication-topology). > **Important:** Recovery commands in this guide can change or overwrite directory state. Use them only in a controlled recovery plan. For production incidents, follow Microsoft’s current recovery documentation and validate the exact scenario before making changes. ## Why Active Directory needs both replication and backup A business can have two healthy domain controllers and still need backups. Replication improves availability, but replication also copies changes. If an administrator deletes an OU, modifies a critical directory object, or an attacker makes destructive changes, those changes can replicate to other domain controllers. That creates three separate requirements: 1. **Availability** — more than one healthy domain controller when the business requires resilience. 2. **Recovery points** — trusted backups that predate the failure or unwanted change. 3. **Recovery procedure** — a documented way to restore only the required scope without creating a larger outage. This is why Active Directory design should treat a second DC and a backup as complementary controls rather than substitutes. ## Understand the recovery paths before taking action The safest AD recovery starts by classifying the incident. | Incident | First recovery path to evaluate | Why | |---|---|---| | Accidentally deleted user or OU | Active Directory Recycle Bin | Usually less disruptive than restoring a DC from backup | | One DC is lost, another healthy DC remains | Replace/rebuild the failed DC | Healthy replication partners may already hold the correct directory state | | Restore a DC and let current directory data replicate back to it | Non-authoritative restore | Restored DC is brought up to date by healthy partners | | Restore an older object and make that restored version replicate outward | Authoritative restore | The selected restored object or subtree is made authoritative | | Entire forest is compromised or unusable | Forest recovery | Requires isolated, domain-by-domain recovery planning | Do not choose an authoritative restore simply because the name sounds stronger. It is more invasive because you are deliberately making restored directory data take precedence over newer replicated copies. ## Active Directory Recycle Bin should usually be checked first for deleted objects Windows Server 2025 supports Active Directory Recycle Bin. When enabled, it can preserve deleted AD objects and their attributes so eligible objects can be restored without rolling a domain controller back to an older System State. Check whether Recycle Bin is enabled: ```powershell Get-ADOptionalFeature -Filter 'Name -like "Recycle Bin Feature"' | Select-Object Name, EnabledScopes ``` If `EnabledScopes` contains the forest configuration, Recycle Bin is enabled. Microsoft documents two important limitations: - Active Directory Recycle Bin is **not enabled by default**; - only objects deleted **after** Recycle Bin was enabled can be recovered through it. A discovery command can be used to inspect deleted test objects: ```powershell Get-ADObject -Filter 'Name -Like "*RestoreLab*"' -IncludeDeletedObjects ``` After confirming the exact identity of the intended object, a restore can be performed with `Restore-ADObject`. For production, do not pipe a broad search directly into `Restore-ADObject` until you have reviewed the returned objects. Narrow the filter and confirm identifiers such as DistinguishedName or ObjectGUID first. ## System State is the core Active Directory-aware backup Microsoft’s current Windows Server forest-recovery guidance documents **System State backup** for domain controllers. On a domain controller, System State contains the operating-system state required for Active Directory recovery, including AD DS data and related components. That makes System State different from a generic file copy. A complete production strategy can also include full-server or bare-metal recovery, platform-level backups, application backups, and copies outside the live server. These layers address different failure modes. | Protection layer | Primary job | |---|---| | AD System State | Active Directory-aware DC recovery | | Full server / BMR backup | Restore the whole server/OS when required | | VM/platform backup | Infrastructure-level recovery point | | Snapshot | Short-lived pre-change rollback | | AD Recycle Bin | Recover eligible deleted AD objects | | Second DC | Authentication/DNS availability and replication partner | A snapshot alone is not an Active Directory recovery strategy. ## Step 1 — Record the domain-controller environment Before creating the backup, record exactly what is being protected. Run PowerShell as Administrator: ```powershell Get-ComputerInfo | Select-Object WindowsProductName, WindowsVersion, OsBuildNumber hostname Get-Service NTDS,DNS,Netlogon,ADWS | Select-Object Name,Status Get-ADDomain | Select-Object DNSRoot,NetBIOSName,PDCEmulator,RIDMaster,InfrastructureMaster Get-ADForest | Select-Object ForestMode,SchemaMaster,DomainNamingMaster ``` If you have more than one DC, record them as well: ```powershell Get-ADDomainController -Filter * | Select-Object HostName,Site,IsGlobalCatalog,IPv4Address ``` This matters during recovery because you need to know whether the failed server was the only DC, a DNS server, a Global Catalog, or an FSMO role holder. ## Step 2 — Confirm Windows Server Backup is available Windows Server Backup is not installed by default on every Windows Server installation. Check the feature: ```powershell Get-WindowsFeature Windows-Server-Backup ``` If the feature is not installed and Windows Server Backup is part of your recovery design: ```powershell Install-WindowsFeature Windows-Server-Backup ``` Verify again: ```powershell Get-WindowsFeature Windows-Server-Backup ``` ## Step 3 — Choose a backup target that survives the failure you care about The only recovery copy should not disappear with the domain controller. A production backup design should consider: - failure of the OS volume; - accidental VM deletion; - administrator compromise; - ransomware; - failure of one host or storage path; - loss of an entire DC; - the need to recover from an older trusted point. A second partition on the same virtual disk is useful for limited testing, but it is **not an independent production backup target** because failure of the underlying VM or disk can remove both the source and the backup. Where possible, use a separate backup destination such as another protected storage system or supported network share that remains available if the DC is lost. The generic Raff backup strategy page owns retention, off-server copies, RPO/RTO, and layered backup design. This article focuses specifically on AD-aware backup and recovery decisions. ## Step 4 — Create a System State backup with wbadmin Microsoft documents `wbadmin start systemstatebackup` for Windows Server. Example using a deliberately prepared backup volume: ```cmd wbadmin start systemstatebackup -backupTarget:E: -quiet ``` Replace `E:` with the destination defined by your recovery design. Windows Server also supports a remote shared folder as a backup target. Example syntax: ```cmd wbadmin start systemstatebackup -backupTarget:\\backup-server\ADBackup -quiet ``` Use a real protected share and appropriate credentials. Do not expose SMB publicly just to make a backup target reachable. Without `-quiet`, `wbadmin` prompts for confirmation. You can monitor an active job with: ```cmd wbadmin get status ``` Do not treat a command starting successfully as proof that the backup completed successfully. Confirm the final result and then verify the recovery point. ## Step 5 — List the available backup versions After the backup completes, use: ```cmd wbadmin get versions ``` Microsoft documents that this returns information such as: - backup time; - backup location; - version identifier; - recovery types available from the backup. If the backup is on a specific local target: ```cmd wbadmin get versions -backupTarget:E: ``` Record the version identifier. `wbadmin` uses that value when you inspect or restore a specific recovery point. Inspect the items in a selected backup with: ```cmd wbadmin get items -version: ``` Use the actual version returned by your server. Do not copy an example timestamp into a production recovery command. ## Step 6 — Decide whether you actually need to restore this DC A failed domain controller in a healthy multi-DC domain is not automatically a restore job. If another writable DC is healthy and replication was healthy before the failure, rebuilding a clean replacement server and promoting it as a new DC may be simpler and safer than restoring an old DC image. Before restoring one failed DC, inspect the surviving environment: ```cmd repadmin /replsummary ``` ```cmd dcdiag /e /c ``` And in PowerShell: ```powershell Get-ADDomainController -Filter * | Select-Object HostName,Site,IsGlobalCatalog ``` The decision changes if: - this was the only DC; - the surviving directory contains bad replicated changes; - the forest was compromised; - a specific historical directory object/state must be recovered; - the backup is the only trusted copy. ## Non-authoritative restore: let healthy partners update the restored DC A normal domain-controller restore from System State is **non-authoritative** unless you deliberately mark restored data authoritative. Conceptually: ```text Trusted System State backup | v Restore DC | v Start AD DS normally | v Healthy replication partners send newer directory changes | v Restored DC becomes current ``` Use this when the objective is to return a failed DC to service while healthy replication partners contain the correct newer state. Microsoft documents `wbadmin start systemstaterecovery` for System State recovery. A typical command shape is: ```cmd wbadmin start systemstaterecovery -version: -backupTarget:E: ``` The exact command depends on where the backup is stored and the supported recovery scenario. Do not run System State recovery on a production DC as an experiment. Microsoft also distinguishes restoring System State to the same system from recovering onto a new or reinstalled operating-system instance. For a different server instance, follow Microsoft’s supported full-server or bare-metal recovery guidance rather than assuming a System State copy can simply be applied to a fresh installation. ## Authoritative restore: make selected restored data win replication An **authoritative restore** is different. The purpose is to restore directory data from backup and deliberately mark selected objects or a subtree so that the restored version is treated as newer and can replicate outward to other domain controllers. This may be relevant when: - an OU was deleted and Recycle Bin cannot provide the required recovery; - multiple objects need to return to a previous state; - a trusted backup contains the version that must supersede later replicated changes. It should be used at the smallest scope that solves the problem. Microsoft’s Active Directory recovery guidance documents `ntdsutil` authoritative-restore operations for selected directory objects and subtrees. Example command shape for a specific object: ```cmd ntdsutil "authoritative restore" "restore object " q q ``` For a subtree: ```cmd ntdsutil "authoritative restore" "restore subtree " q q ``` Do **not** authoritatively restore the domain root or a large production subtree merely to recover one object. A broader authoritative scope can revert unrelated attributes, memberships, and other changes that occurred after the backup was taken. ## Recycle Bin vs authoritative restore Use this decision rule: | Condition | Better first option | |---|---| | Recycle Bin enabled before deletion and object is recoverable | Recycle Bin | | Object was deleted before Recycle Bin was enabled | Backup-based recovery may be required | | Need to recover an object plus historical state not preserved elsewhere | Evaluate authoritative restore | | Entire domain/forest state is suspect | Use formal forest/domain recovery planning | Recycle Bin is generally less disruptive because it avoids restoring an entire domain controller just to recover a deleted object. ## Authoritative AD objects are not the same as authoritative SYSVOL This distinction is important. Microsoft documents authoritative synchronization of **DFSR-replicated SYSVOL** as a separate procedure from authoritative restoration of directory objects. Do not use the terms interchangeably: ```text Authoritative AD object restore -> selected directory objects or subtree Authoritative SYSVOL recovery -> SYSVOL / DFSR recovery procedure ``` A production forest recovery may require both directory and SYSVOL decisions, but they solve different problems. ## DSRM is a recovery mode, not a normal administration mode Directory Services Restore Mode allows a domain controller to start without normal AD DS operation so offline directory recovery tasks can be performed. The DSRM password is configured when the server is promoted to a domain controller. Treat it as a high-value recovery credential. For Windows Server environments using Windows LAPS, Microsoft also supports managing DSRM credentials through Windows LAPS when configured appropriately. Before an incident, verify that: - the organization knows how to retrieve the DSRM password; - the credential is stored securely; - the procedure is documented outside the failed server; - recovery staff understand the difference between the normal domain Administrator account and DSRM credentials. Never expose a real DSRM password in screenshots, tickets, scripts, or public documentation. ## Validate Active Directory after any restore A restore is not finished when the recovery command returns success. Check core services: ```powershell Get-Service NTDS,DNS,Netlogon,ADWS | Select-Object Name,Status ``` Check domain-controller health: ```cmd dcdiag ``` If multiple DCs exist, check replication: ```cmd repadmin /replsummary ``` Then validate the specific object or subtree that was recovered. For example: ```powershell Get-ADOrganizationalUnit -Filter 'Name -eq "RaffRestoreLab"' | Select-Object Name,DistinguishedName ``` For a test user: ```powershell Get-ADUser -Filter 'Name -like "*RestoreLab*"' | Select-Object Name,SamAccountName,Enabled,DistinguishedName ``` Also validate the parts of the environment that depend on Active Directory: - AD-integrated DNS records; - SYSVOL and NETLOGON shares; - authentication from an intended client or test system; - Group Policy if the recovered scope includes GPO-related data; - FSMO role ownership; - event logs for AD DS, DNS, DFS Replication, and System errors. ## Do not restore an old DC snapshot blindly Virtualized domain controllers have protections designed for supported virtualization scenarios, but a snapshot is still not a replacement for an Active Directory-aware backup and recovery plan. The practical rule is: ```text Snapshot before a risky change != Long-term AD recovery strategy ``` Use [Snapshot vs Backup on a Windows VPS](/windows-server/snapshot-vs-backup-windows-vps) for the infrastructure-level distinction. For Active Directory, keep trusted System State or supported full-server recovery points and validate the recovery process before an incident. ## One-DC lab vs two-DC production recovery planning ### One-DC environment A one-DC environment is simple but fragile: ```text DC01 -> AD DS -> DNS -> Global Catalog -> System State backup ``` If that DC is lost, there is no healthy replication partner to rebuild from. The quality and accessibility of the backup become much more important. ### Two-DC production baseline A typical small production domain might be: ```text Private / trusted network DC01 <------ AD replication ------> DC02 | | AD DS AD DS DNS DNS GC GC | | System State backups System State backups ``` Two DCs improve availability. They do not remove the need for backups because destructive directory changes can replicate. For topology, DNS client order, sites, and replication checks, use [Active Directory Replication Topology for 2-DC Setups](/windows-server/ad-replication-topology). ## Forest recovery is a separate severity level If the entire forest is compromised, corrupted, or unusable, do not treat the incident as a routine authoritative restore. Microsoft’s forest-recovery guidance describes restoring at least one domain controller in every domain from trusted backup and performing recovery in a controlled sequence. Forest-wide recovery requires decisions about: - which backup is known-good; - which DC to recover first in each domain; - isolation from compromised or unhealthy replication partners; - DNS and SYSVOL recovery; - FSMO roles; - privileged-identity recovery after compromise; - reconnecting recovered domains safely; - application and service dependencies. That deserves a dedicated recovery runbook and drill. This article stops at the point where the incident becomes a forest recovery project. ## How to choose a trusted backup The newest backup is not automatically the safest backup. If destructive or malicious changes happened at an unknown time, the latest recovery point may already contain the unwanted state. Track backup metadata alongside AD health: | Record | Why it matters | |---|---| | Backup version | Identifies the exact recovery point | | DC hostname | Shows which DC was protected | | Windows build | Helps verify the restore scenario | | Domain/forest | Prevents restoring the wrong environment | | Backup target | Shows where recovery media is stored | | Last known-good AD health | Helps identify a trusted point | | `dcdiag` result | Records directory health around backup time | | `repadmin /replsummary` | Records replication health in multi-DC environments | | Change window | Helps correlate bad changes with backup time | For business-critical AD, routine health logging makes disaster recovery easier because you can identify when the environment was last known to be healthy. ## Backup and restore testing cadence A practical small-business or MSP baseline is: | Task | Suggested cadence | |---|---| | Verify backup job completed | Every backup cycle | | Review available System State versions | Weekly or according to backup schedule | | Review `dcdiag` / replication health | Regularly and after AD changes | | Confirm DSRM recovery credentials | Quarterly / controlled policy review | | Restore a test object with Recycle Bin | Periodically in a lab | | Recovery drill from backup | Periodically based on business impact | | Review forest-recovery runbook | After topology or security changes | The exact frequency should follow the organization’s RPO, RTO, change rate, and risk. ## Common Active Directory backup mistakes ### Treating replication as backup Replication copies deletions and bad changes. Two DCs are not two historical recovery points. ### Using only a VM snapshot A snapshot is useful for short-term rollback, but it should not be the only recovery layer for a domain controller. ### Keeping the only backup on the same VM or disk That may validate a command in a lab, but it does not protect against complete VM, disk, or account loss. ### Backing up but never recording the version A backup without a documented recovery point makes incident response slower. Use `wbadmin get versions` and record the version identifier. ### Restoring a DC when rebuilding it would be simpler If healthy replication partners exist and hold the correct directory state, replacing the failed DC can be cleaner than reviving an old one. ### Using authoritative restore too broadly Restore the smallest directory scope that solves the problem. A broad subtree can revert unrelated directory changes. ### Confusing SYSVOL authoritative recovery with AD object authoritative restore They are separate procedures with different targets. ### Losing the DSRM password DSRM is part of the recovery path. Protect and verify credential retrieval before the outage. ### Testing recovery for the first time during a production incident A recovery plan is stronger when it has been rehearsed in an isolated or disposable environment before it is needed. ## Where Raff fits Raff’s role is the **Windows Server infrastructure layer**. A production Active Directory deployment can use dedicated Raff Windows VMs for domain controllers while the administrator controls AD DS, DNS, security policy, backup scheduling, and recovery procedures inside Windows Server. A production-minded architecture can look like this: ```text Raff Windows VM - DC01 + Raff Windows VM - DC02 + AD-aware System State backups + independent recovery copies + periodic recovery testing ``` The value is not simply adding more compute. It is separating identity workloads intentionally, maintaining more than one domain controller where availability requires it, and keeping recovery copies outside the failure boundary of the active DC. A second dedicated Windows VM can improve DC availability. A separate Windows VM or protected storage target can also support isolated backup or recovery workflows when the design requires it. Raff provides the VM infrastructure. Active Directory architecture, backup policy, recovery testing, and directory administration remain administrator responsibilities unless a separate managed service explicitly covers them. ## Active Directory recovery readiness checklist | Check | Ready when | |---|---| | At least one trusted AD-aware backup exists | System State or another supported recovery backup is current | | Backup version is documented | `wbadmin get versions` identifies the recovery point | | Backup survives the failure you are protecting against | One VM or disk loss does not remove every recovery copy | | DSRM password retrieval is known | Recovery staff can retrieve it securely | | Recycle Bin status is documented | Administrators know whether deleted-object recovery is available | | DC roles are documented | DNS, GC, FSMO, sites, and replication partners are known | | Restore decision tree exists | Rebuild vs non-authoritative vs authoritative vs forest recovery is clear | | Recovery has been rehearsed | The team has validated the procedure in a safe environment | | Post-restore checks are documented | AD DS, DNS, SYSVOL, objects, and replication are validated | | Recovery notes live outside the DC | Documentation survives server failure | If those items are missing, the environment may have backups but not yet a complete Active Directory recovery plan. ## Frequently asked questions ### What should I back up on an Active Directory domain controller? Use an Active Directory-aware recovery method. Microsoft documents System State backup for domain controllers, and full-server or bare-metal recovery can also be part of the disaster-recovery design. Platform snapshots and VM backups can be useful additional layers but should not be the only AD recovery plan. ### Is a second domain controller a backup? No. A second DC improves availability and provides another replica, but deletions and bad directory changes can replicate to it. Keep historical recovery points as well. ### What is a non-authoritative Active Directory restore? It restores a DC from backup and then allows healthy replication partners to bring that DC up to date with newer directory changes. ### What is an authoritative Active Directory restore? It restores directory data from backup and marks selected objects or a subtree so the restored version takes precedence and replicates outward. Use the smallest necessary scope. ### Should I use authoritative restore for a deleted user? First check Active Directory Recycle Bin. If Recycle Bin was enabled before deletion and the object is recoverable, it is usually the less disruptive path. Backup-based authoritative recovery is for cases where Recycle Bin cannot solve the requirement or where historical directory state must intentionally become authoritative. ### Can I restore a System State backup onto a fresh Windows Server installation? Do not assume so. Microsoft distinguishes same-system System State recovery from recovery onto a new or reinstalled operating-system instance. Follow the supported full-server or bare-metal recovery guidance for the actual scenario. ### Does `wbadmin get versions` prove the backup is usable? It proves that Windows can enumerate the recovery point and its metadata. It does not replace a real recovery drill. ### Can I put a System State backup on a network share? Yes. Windows Server Backup supports remote shared folders as backup targets. Use an authenticated, protected share and avoid exposing SMB publicly. ### Do snapshots replace System State backup for virtual domain controllers? No. Snapshots can help with short-term rollback, but a domain controller still needs an AD-aware backup and recovery plan. ## What’s next - [Promote a Windows VPS to an Active Directory Domain Controller](/windows-server/active-directory-domain-controller) - [Active Directory DNS on Windows Server 2025](/windows-server/active-directory-dns-windows-server-2025) - [Active Directory Replication Topology for 2-DC Setups](/windows-server/ad-replication-topology) - [Windows VPS Backup Strategy for Small Businesses](/windows-server/windows-vps-backup-strategy-small-business) - [Snapshot vs Backup on a Windows VPS](/windows-server/snapshot-vs-backup-windows-vps) - [Windows Server Hardening Checklist](/windows-server/windows-server-hardening-checklist) - [Raff Windows VM](/products/windows-vm) ## Sources - Microsoft Learn — Active Directory Forest Recovery: Back up the System State data: https://learn.microsoft.com/en-us/windows-server/identity/ad-ds/manage/ad-forest-recovery-backing-up-system-state - Microsoft Learn — Restore a virtual domain controller: https://learn.microsoft.com/en-us/windows-server/identity/ad-ds/manage/virtual-dc/restore-virtualized-domain-controller - Microsoft Learn — Active Directory Forest Recovery: Determine how to recover the forest: https://learn.microsoft.com/en-us/windows-server/identity/ad-ds/manage/forest-recovery-guide/ad-forest-recovery-determine-how-to-recover - Microsoft Learn — Active Directory Forest Recovery procedures: https://learn.microsoft.com/en-us/windows-server/identity/ad-ds/manage/forest-recovery-guide/ad-forest-recovery-procedures - Microsoft Learn — Authoritative synchronization of DFSR-replicated SYSVOL: https://learn.microsoft.com/en-us/windows-server/identity/ad-ds/manage/forest-recovery-guide/ad-forest-recovery-authoritative-recovery-sysvol - Microsoft Learn — Active Directory Recycle Bin: https://learn.microsoft.com/en-us/windows-server/identity/ad-ds/get-started/adac/active-directory-recycle-bin - Microsoft Learn — wbadmin: https://learn.microsoft.com/en-us/windows-server/administration/windows-commands/wbadmin - Microsoft Learn — wbadmin start systemstatebackup: https://learn.microsoft.com/en-us/windows-server/administration/windows-commands/wbadmin-start-systemstatebackup - Microsoft Learn — wbadmin start systemstaterecovery: https://learn.microsoft.com/en-us/windows-server/administration/windows-commands/wbadmin-start-systemstaterecovery - Microsoft Learn — wbadmin get versions: https://learn.microsoft.com/en-us/windows-server/administration/windows-commands/wbadmin-get-versions - Microsoft Learn — wbadmin get items: https://learn.microsoft.com/en-us/windows-server/administration/windows-commands/wbadmin-get-items - Microsoft Learn — Windows LAPS overview: https://learn.microsoft.com/en-us/windows-server/identity/laps/laps-overview - Sources verified: 2026-09-01 --- ### Windows VPS for Business Software & Application Hosting (2026) URL: https://rafftechnologies.com/windows-server/windows-vps-for-business-software Description: Learn which business applications fit a Windows VPS, how desktop/RDS, IIS/.NET, SQL Server, and legacy-app architectures differ, and what to check before production. ## In short A Windows VPS is a good fit for business software when the application genuinely needs Windows Server, a persistent Windows environment, Remote Desktop Services, IIS, SQL Server, Windows services, scheduled tasks, or shared application data. The important question is not simply whether the installer runs on Windows. The real question is whether the **application, user-access model, data layer, licensing, backups, and recovery process** all work correctly in a hosted Windows environment. This guide is the architecture and compatibility starting point for **Windows application hosting**. It covers desktop business apps, accounting software, SQL-backed applications, IIS/.NET workloads, legacy Windows software, and always-on Windows services. For a broader small-business infrastructure decision, use [Windows VPS Hosting for Small Businesses](/windows-server/windows-vps-small-business) instead. ## TL;DR - Use a Windows VPS when the software needs Windows Server, RDP/RDS, IIS, SQL Server, Windows services, or an always-on Windows environment. - Separate **administrative RDP** from **staff application access**. If employees use an RD Session Host, Microsoft requires the appropriate RDS CALs. - Check the exact software vendor's Windows Server and hosted/RDS support before production. - Keep latency-sensitive application data close to the application. Avoid stretching file-based business software across an unreliable WAN. - Size the server by **concurrent users + application load + database load**, not only by employee count or installer minimums. - Treat SQL Server, RDS sessions, IIS, browsers, Office apps, antivirus, backups, and reporting as competing workloads when they share one VM. - Use VM-level protection together with application- or database-aware backups where required, and test restores before go-live. - A Windows VPS is infrastructure, not a substitute for application licensing, vendor support, security hardening, or operational ownership. ![Diagram showing users connecting to a Windows VPS through Remote Desktop to access business software, company files, database services, backups, and security controls.](https://raff-images.s3.raffusercloud.com/business_software_on_windows_vps_stack_webp_bce319bcb3.png) ## What Windows application hosting means “Windows application hosting” can describe several very different architectures. Choosing the right one is more important than choosing a VM size first. | Architecture | How users reach the application | Typical workloads | Main planning issue | |---|---|---|---| | Hosted desktop / RDS | Users sign in to a Windows Server session | Accounting, ERP clients, tax software, legacy desktop apps | RDS architecture, CALs, profiles, printers, RAM per active user | | Client/server business app | User-facing app connects to a server-side data/service layer | ERP, inventory, line-of-business software | Data location, ports, vendor support, database behavior | | IIS/.NET web app | Users access the app through HTTPS | ASP.NET Core, .NET Framework, portals, internal web apps | IIS, TLS, app pools, deployment, database connections | | SQL-backed application | App connects to SQL Server on the same or separate VM | ERP, reporting, custom business apps | SQL memory, storage I/O, backups, licensing, recovery | | Windows service / scheduled workload | No daily desktop session required | Automation, integration agents, scheduled exports, admin services | Service accounts, monitoring, restart behavior, logs | | Single-user remote application | One user runs a Windows-only app remotely | Specialist admin tools, older desktop software | Vendor support, peripherals, backup and remote access | A Windows VPS can support more than one pattern, but combining them increases resource and operational complexity. A small application may run comfortably on one VM. A larger environment may need separate RDS, application, and database roles. ## Which business software fits a Windows VPS? Use the table below as a screening tool, not as a vendor compatibility guarantee. | Software type | Windows VPS fit | What to verify before production | |---|---|---| | QuickBooks Desktop | Good fit after vendor/licensing review | Multi-user model, Database Server Manager, user access, backups, printers | | Sage 50 / 100 / 300 | Good fit when the exact product architecture is supported | Windows Server version, RDS/Citrix rules, SQL requirements, integrations | | ERP / inventory software | Often a good fit | Database, reporting, branch access, devices, vendor support | | Microsoft Access / legacy apps | Often workable after testing | File paths, split database design, RDS behavior, runtime dependencies | | SQL Server-backed business apps | Strong fit when sized correctly | SQL edition, memory, storage, backups, connection strings | | IIS / ASP.NET applications | Strong fit | IIS version, .NET runtime, TLS, app pools, database connectivity | | Tax / payroll / reporting tools | Often a good fit | Hosted-use rights, seasonal load, printers, PDF/Office integration | | Trading / monitoring tools | Depends on app behavior | CPU/RAM use, session persistence, automation, vendor terms | | Hardware-dependent software | Often risky | USB devices, scanners, dongles, GPUs, local drivers | | Fully browser-based SaaS | Usually unnecessary | A VPS may add infrastructure without solving a real problem | The safest rule is simple: **test the exact application release you intend to run, not a similar version.** Windows Server support, RDS support, database requirements, Office integration, licensing, and third-party add-ons can change between releases. :::cta Hosting a Windows business application? Use Raff Windows VM as the Windows Server foundation, then size and configure the environment around the application's real user, database, storage, and licensing requirements. [Explore Raff Windows VM](/products/windows-vm). ::: ## 10 compatibility checks before moving business software Before choosing a server plan, answer these questions. 1. **Does the vendor support Windows Server?** Desktop Windows support does not automatically mean Windows Server support. 2. **Which Windows Server versions are supported?** Match the exact application release to Windows Server 2019, 2022, or 2025 only when the vendor supports it. 3. **Does the application support RDS or multi-user sessions?** Some desktop software works in one interactive session but is not supported as a multi-user server application. 4. **Where does the data live?** Identify company files, SQL databases, local databases, shared folders, configuration files, and user-profile data. 5. **Does it depend on SQL Server or another database?** Database CPU, memory, storage, backup, and licensing can dominate the design. 6. **Does it use printers, scanners, USB devices, or hardware dongles?** Remote redirection and physical-device dependencies should be tested early. 7. **Does it integrate with Office, Outlook, Excel, PDF tools, or email?** Those dependencies can affect both licensing and session memory. 8. **Does the license allow server, hosted, or remote use?** Application licensing and RDS licensing are separate from the VM itself. 9. **What must be backed up to recover the application?** VM recovery alone may not protect an actively changing database or application data set correctly. 10. **What does a real user workflow look like?** Test login, app launch, data access, reports, printing, PDF/export, email, backup, and restore before cutover. If any of these answers is unclear, treat the environment as a pilot rather than production. ## Architecture 1: desktop business apps over RDP or RDS Many Windows business applications are desktop applications. The software runs inside Windows, while users connect remotely to use it. A typical architecture looks like this: ```text Remote users ↓ Controlled RDP / RDS access ↓ Windows Server ├─ business application ├─ user sessions ├─ shared application data └─ local supporting tools ``` The important distinction is **administrative RDP vs Remote Desktop Services**. Administrative RDP is for managing the server. It should not be treated as an unlimited employee desktop platform. When multiple staff members need normal user sessions on an RD Session Host, Microsoft requires an RDS Client Access License for each user or device accessing that Session Host. | Need | Typical direction | |---|---| | One or two administrators maintain the server | Restricted administrative RDP | | Several employees run a Windows app every day | RDS Session Host planning | | Users need individual sessions and profiles | RDS Session Host + user/profile design | | Users connect from many external networks | Consider RD Gateway or another controlled access layer | | Users need only a web application | Do not provide full desktop sessions unnecessarily | Read [Multi-User RDP: 2 Admin Sessions vs RDS Session Host](/windows-server/multi-user-rdp-vs-rds) and [RDS CAL Licensing on Windows Server](/windows-server/rds-cal-licensing-guide) before using the server as a daily multi-user workspace. ## Architecture 2: accounting applications Accounting software is one of the clearest Windows application hosting use cases because the application, company data, reports, Office/PDF tools, printers, and remote users often need to work as one system. ![Diagram showing QuickBooks, Sage, company files, users, Remote Desktop sessions, database services, and backups in a Windows VPS accounting software setup.](https://raff-images.s3.raffusercloud.com/accounting_software_on_windows_vps_webp_f1989ccc3c.png) Do not duplicate one generic architecture across every accounting product. QuickBooks Desktop, Sage 50, Sage 100, and Sage 300 have different data models, support rules, and multi-user requirements. For QuickBooks Desktop, use [Self-Host QuickBooks Desktop on Windows Server VPS](/windows-server/quickbooks-multi-user-windows-server-vps). For Sage, use the refreshed [Sage 50, 100 & 300 Cloud Hosting on Windows Server](/windows-server/sage-hosting-windows-vps) guide. The shared planning principles are: - keep the application and active company data close together; - verify the exact vendor-supported Windows Server/RDS model; - size for peak concurrent users, not licensed users alone; - test reports, PDF export, Excel/Office integration, printers, and backups; - use application-aware backup methods where the vendor requires them; - separate heavier database workloads when the combined VM becomes resource-constrained. ## Architecture 3: ERP, inventory, Access, and legacy Windows apps Line-of-business software often reaches a Windows VPS because it still depends on Windows services, mapped paths, local databases, SQL Server, ODBC, scheduled jobs, or a traditional desktop client. These applications can work well in a hosted Windows environment, but they need a dependency inventory first. Check for: - hard-coded server names, IP addresses, or drive letters; - ODBC data sources and SQL connection strings; - Windows services and service accounts; - scheduled tasks and exports; - .NET Framework or runtime dependencies; - local printers and label printers; - scanners and USB devices; - DLLs, COM components, or older drivers; - Office or Access Runtime dependencies; - licensing services or hardware keys; - file-locking behavior across multiple users. A good migration test does not stop when the application opens. Create a record, edit data, save, run a report, export a PDF or spreadsheet, print, close the application, reopen it, and validate the backup/restore path. ## Architecture 4: SQL Server-backed business applications SQL Server changes the sizing and recovery model because the database can become the most resource-intensive part of the server. Microsoft's current SQL Server 2025 requirements support Windows Server 2019, Windows Server 2022, and Windows Server 2025 for supported SQL Server editions. That does **not** mean the minimum hardware requirements are a production sizing recommendation. Microsoft explicitly notes that actual requirements vary by application and installed features. When RDS users, the business application, and SQL Server share one VM, they compete for the same resources: | Resource | Competing workload | |---|---| | RAM | Windows, user sessions, SQL Server buffer pool, app processes, browsers, Office tools | | CPU | Queries, reports, user applications, antivirus, scheduled tasks | | Storage I/O | Database reads/writes, TempDB, user profiles, app files, backups | | Disk capacity | Database growth, logs, exports, profiles, backup staging | For a small workload, one VM can be reasonable. As database size, report load, concurrent users, or recovery requirements increase, separating the database role becomes easier to operate and troubleshoot. For deeper SQL planning, use: - [SQL Server Max Server Memory: How to Configure It Safely](/windows-server/mssql-memory-tuning) - [SQL Server TempDB: Files, Size & Autogrowth](/windows-server/mssql-tempdb-config) - [SQL Server Backup Strategy: Full, Differential & Log Backups](/windows-server/mssql-backup-strategy) ## Architecture 5: IIS and .NET applications A Windows VPS can also host browser-based Windows applications. In this model, end users do not need RDP. IIS runs the application and users connect over HTTPS. ```text User browser ↓ HTTPS / DNS ↓ IIS on Windows Server ↓ Application pool ↓ ASP.NET / .NET application ↓ SQL Server or external database ``` RDP is mainly an administrative path here. The production concerns are different from a desktop/RDS workload: - IIS site and binding configuration; - TLS certificates and renewal; - app pool identity and recycling; - application runtime and hosting bundle; - logs and monitoring; - deployment/rollback process; - database connectivity; - firewall and public exposure. Use [Install ASP.NET Core on IIS](/windows-server/iis-install-aspnet-core), [IIS Application Pool Settings & Tuning](/windows-server/iis-app-pool-tuning), and [win-acme on IIS: Let's Encrypt SSL Setup & Renewal](/windows-server/iis-letsencrypt-win-acme) for the web-application layer. ## Architecture 6: Windows services and always-on automation Not every business application needs a desktop session. Some workloads run as Windows services, scheduled tasks, integration agents, import/export jobs, or background processes. This can be a strong VPS use case because the workload stays online without depending on an employee's office PC. Plan for: - a dedicated service account where appropriate; - automatic service recovery after failure; - startup behavior after reboot; - scheduled task history and failure handling; - log retention; - outbound network dependencies; - monitoring/alerting; - safe credential storage; - backup of application configuration and state. Do not keep an interactive RDP session open just to make a production process run. If the application supports running as a service or scheduled workload, use the supported non-interactive model. ## Size by architecture, not by the application name There is no universal “QuickBooks VM,” “ERP VM,” or “business software VM” size. Two businesses using the same application can have very different concurrency, data size, reports, integrations, and user-session behavior. Use these as **planning directions**, not guarantees: | Workload | Initial planning direction | Main pressure to watch | |---|---:|---| | Admin tools / one light service | 2 vCPU / 4 GB RAM | Background services, Windows updates, app responsiveness | | 1–3 light business-app users | 4 vCPU / 8–16 GB RAM | Session memory, app responsiveness, storage | | 3–5 active desktop-app users | 4–8 vCPU / 16 GB+ RAM | RDS memory, reports, Office/browser use | | RDS + business app + small SQL workload | 8 vCPU / 32 GB direction | SQL memory, user sessions, disk I/O | | Reporting-heavy SQL/ERP workload | Larger VM or split roles | Database memory, TempDB, storage I/O, report concurrency | | IIS/.NET app | Size by traffic + app + database | App pool memory, CPU, logs, database load | Before choosing a production plan, read [Windows VPS sizing for remote users](/windows-server/windows-vps-sizing-remote-users). Then monitor real CPU, RAM, free disk space, database pressure, and active-session count after users begin testing. ## Keep the application's active data close to the app Data placement matters as much as compute size. File-based business applications can become unreliable or slow when the application runs in one location but its primary working data sits across a high-latency or unstable network path. Database-backed applications can also become slow when application and database latency is unnecessarily high. Prefer an architecture where the application and its primary data layer communicate over a fast, controlled path. For remote users, it is often cleaner to bring the user to the application through RDS than to stretch a latency-sensitive file workflow across the user's home or branch connection. That does not mean every file belongs on the same system disk. Separate data volumes, backup destinations, and database roles when the workload or recovery plan justifies it. ## Backups must match the application A VM backup protects the Windows environment, but some business applications need additional recovery layers. | Layer | What it protects | |---|---| | VM backup | Windows Server, installed roles, configuration, full-server recovery | | Snapshot before change | Short-term rollback before updates, migrations, or upgrades | | File-level backup | Shared files, exports, reports, documents | | Application-aware backup | Vendor-specific business application data | | SQL Server backup | Database consistency, restore sequence, point-in-time options where configured | | Off-server copy | Protection outside the production VM/failure domain | | Restore test | Proof that the application and its data can actually be recovered | A backup job showing “success” is not enough. Restore a copy into a safe test location and confirm that the business application can open and use the recovered data. Use [Windows VPS Backup Strategy for Small Businesses](/windows-server/windows-vps-backup-strategy-small-business) for the infrastructure layer and the dedicated SQL backup guide when SQL Server is involved. ## Security: treat hosted business software as production infrastructure Once employees depend on the application, the VM is no longer “just a remote PC.” Minimum controls should include: - named user accounts instead of shared logins; - separate administrator and daily-user accounts; - least privilege for application and file access; - Windows Firewall enabled with only required rules; - controlled RDP/RDS exposure rather than broad public access; - regular Windows and application patching; - Microsoft Defender or an appropriate supported endpoint-security configuration; - account offboarding when staff leave; - backup access separated from normal users; - review of failed logins and relevant event logs. For the server baseline, use [Windows Server Hardening Checklist](/windows-server/windows-server-hardening-checklist) and [Configure Windows Firewall on a Windows VPS](/windows-server/configure-windows-firewall). ## Licensing has multiple layers A working technical setup can still be the wrong production setup if licensing was assumed rather than checked. Typical layers include: | License area | What to verify | |---|---| | Windows Server | Provider/deployment licensing model | | RDS | RDS CAL requirements and CAL/Session Host version compatibility | | SQL Server | Edition, licensing model, bundled/runtime rights where applicable | | Microsoft 365 / Office | Rights for the selected shared/remote environment | | Business application | Server, hosted, remote, multi-user, or concurrent-user terms | | Add-ons | Reporting, payroll, integrations, backup agents, third-party modules | Microsoft states that each user or device connecting to an RD Session Host running Windows Server needs an RDS CAL, and older RDS CAL versions cannot be used to access newer Windows Server Session Host versions. For the Windows/RDS layer, use [Windows Server Licensing on Raff](/windows-server/windows-licensing) and [RDS CAL Licensing on Windows Server](/windows-server/rds-cal-licensing-guide). For application licensing, use the current vendor documentation for the exact release being deployed. ## Pilot the application before migrating production A good pilot uses real workflows with non-production data. Use this sequence: 1. Inventory the current application, users, data, database, printers, services, and integrations. 2. Confirm vendor support for the target Windows Server and remote-access model. 3. Deploy a test Windows VM. 4. Install the exact application release and dependencies. 5. Restore or copy a non-production data set. 6. Test normal user permissions rather than only Administrator. 7. Test concurrent users if the production design is multi-user. 8. Test reports, PDF export, Excel/Office integration, printing, email, and mapped paths. 9. Run a representative heavy workflow such as month-end reporting or a large query. 10. Configure backup and restore a copy. 11. Record CPU, RAM, storage, and session behavior during the test. 12. Only then schedule production migration and rollback. For a broader cutover process, use [Windows Server Migration Checklist for Small Businesses](/windows-server/windows-server-migration-checklist-small-business). ## When a Windows VPS is not the right application host Reconsider the design when: - the application is already fully SaaS and the vendor manages the environment; - the vendor does not support Windows Server or hosted use; - the application cannot run correctly in the required RDS/multi-user model; - physical USB devices, specialist scanners, dongles, or local hardware are mandatory and cannot be redirected reliably; - the workload requires specialized GPU hardware; - high availability is mandatory and the design is only one VM; - the application requires extremely low-latency local network access that has not been validated in a hosted environment; - compliance requirements need controls beyond the team's current architecture and operating process; - nobody owns Windows updates, application updates, backups, restores, and user access. The right question is not “Can this installer run on a VPS?” It is: > Can this exact application, with its real users and data, be operated safely, supportably, and recoverably on this Windows architecture? ## How Raff fits Windows application hosting Raff provides the Windows VM infrastructure layer for teams that need a cloud-hosted Windows Server environment for supported business applications, Remote Desktop workloads, IIS/.NET apps, SQL-backed software, admin tools, and always-on Windows services. Raff Windows VM currently provides Windows Server 2019, 2022, and 2025 options with full administrator access and RDP access. The application owner, MSP, or customer still needs to validate the exact software release, user-access model, RDS licensing, SQL/application licensing, security controls, backups, and recovery process. Use one VM when the workload is genuinely small and the roles coexist comfortably. Split RDS, application, and database roles when concurrency, performance, recovery, or vendor requirements justify it. :::cta Ready to test your application on Windows Server? Start with a Raff Windows VM, validate the exact application and user workflow, then size production from real usage rather than assumptions. [Explore Windows VM](/products/windows-vm) or review [current pricing](/pricing). ::: ## What's next - [Windows VPS Hosting for Small Businesses](/windows-server/windows-vps-small-business) — broader SMB infrastructure decision guide. - [Windows VPS sizing for remote users](/windows-server/windows-vps-sizing-remote-users) — plan CPU and RAM around concurrent users. - [Windows VPS for Remote Desktop](/windows-server/windows-vps-for-remote-desktop) — choose the remote-access model. - [Self-Host QuickBooks Desktop on Windows Server VPS](/windows-server/quickbooks-multi-user-windows-server-vps) — product-specific QuickBooks planning. - [Sage 50, 100 & 300 Cloud Hosting on Windows Server](/windows-server/sage-hosting-windows-vps) — product-specific Sage architecture. - [SQL Server Backup Strategy](/windows-server/mssql-backup-strategy) — database recovery planning. - [Windows VPS Backup Strategy for Small Businesses](/windows-server/windows-vps-backup-strategy-small-business) — infrastructure protection and restore planning. - [Windows Server Migration Checklist for Small Businesses](/windows-server/windows-server-migration-checklist-small-business) — test, cut over, and keep rollback ready. - [Windows Server Hardening Checklist](/windows-server/windows-server-hardening-checklist) — secure the server before production. ## Sources - [Microsoft Learn — Remote Desktop Services overview in Windows Server](https://learn.microsoft.com/en-us/windows-server/remote/remote-desktop-services/overview) - [Microsoft Learn — License Remote Desktop Services with Client Access Licenses](https://learn.microsoft.com/en-us/windows-server/remote/remote-desktop-services/rds-client-access-license) - [Microsoft Learn — Hardware and software requirements for SQL Server 2025](https://learn.microsoft.com/en-us/sql/sql-server/install/hardware-and-software-requirements-for-installing-sql-server-2025?view=sql-server-ver17) - [Microsoft Learn — Windows Server hardware requirements](https://learn.microsoft.com/en-us/windows-server/get-started/hardware-requirements) - [Raff — Windows VM](https://rafftechnologies.com/products/windows-vm) **Sources last verified:** September 2, 2026. --- ### Windows Server Performance Monitoring: PerfMon, CPU, RAM & Disk URL: https://rafftechnologies.com/windows-server/windows-server-performance-monitoring Description: Monitor Windows Server with PerfMon, Task Manager, Resource Monitor, and Data Collector Sets. Track CPU, RAM, disk, network, and workload signals before tuning or resizing a Windows VPS. ## In short Use Windows Server performance monitoring to find the bottleneck **before** you resize or tune the server. Start with Task Manager for a quick check, Resource Monitor for process-level investigation, and Performance Monitor (PerfMon) for historical counters. Track CPU, available memory, paging, disk latency, network activity, and the application itself during both normal and peak workload periods. ## Windows Server performance monitoring starts with a baseline A slow Windows Server does not automatically need more vCPU or RAM. The bottleneck may be CPU pressure, memory paging, storage latency, network conditions, a single process, or the application itself. The useful workflow is: ```text Measure normal workload → capture the slow period → identify the constrained resource → change one variable → measure again ``` Record the baseline **before** users report a problem whenever possible. A single Task Manager screenshot taken after the incident usually cannot explain what happened five minutes or two hours earlier. Microsoft's current Windows Server troubleshooting guidance recommends collecting performance counters over time when a problem is intermittent or cannot be observed live. ## Task Manager, Resource Monitor, and PerfMon have different jobs Windows Server includes several built-in monitoring tools. They overlap, but they are not interchangeable. | Tool | Best use | Limitation | |---|---|---| | Task Manager | Fast current-state CPU, memory, disk, network, and process checks | Little historical context | | Resource Monitor | Process-level CPU, memory, disk, and network investigation | Primarily live troubleshooting | | Performance Monitor (PerfMon) | Historical counters, baselines, Data Collector Sets, reports | Requires choosing useful counters and a collection window | | `perfmon /report` | Quick System Diagnostics report | Point-in-time diagnostic, not continuous monitoring | | `logman.exe` | Scriptable creation/start/stop of Data Collector Sets | Command-line workflow requires planning the counter set | Use the simplest tool that answers the question. Move to PerfMon when the problem is intermittent, happens during peak hours, or needs evidence before a resize decision. ## Performance Monitor provides the historical view Performance Monitor is built into supported Windows Server releases, including Windows Server 2025, 2022, and 2019. Open it from Run or a terminal: ```text perfmon ``` Microsoft documents PerfMon as the Windows interface for real-time performance counters, Data Collector Sets, and reports. The command also supports modes such as: ```text perfmon /res perfmon /report perfmon /sys ``` - `/res` opens Resource View. - `/report` runs the System Diagnostics Data Collector Set and displays its report. - `/sys` opens Performance Monitor. The existing Raff screenshot below shows PerfMon with CPU, memory, disk, and network counters on a Windows VM. ![Windows Server Performance Monitor showing CPU, memory, disk, and network counters on a Raff Windows VM](https://raff-images.s3.raffusercloud.com/windows_server_perfmon_cpu_memory_disk_network_35e97a1dbb.png) ## CPU monitoring separates short bursts from sustained compute pressure CPU spikes during logon, Windows Update, backups, application startup, antivirus scans, report generation, or deployments can be normal. The more important question is whether CPU remains constrained during the workload users care about. Useful counters include: | Counter | What it helps answer | |---|---| | `Processor Information(_Total)\% Processor Time` | Is overall CPU busy during the incident? | | `System\Processor Queue Length` | Is runnable work waiting for CPU time? | | `Process(*)\% Processor Time` | Which process is consuming CPU? | Do not diagnose a CPU bottleneck from one high sample. Correlate sustained CPU activity with queueing, the responsible process, and the time users experienced slowness. If one application owns most of the CPU, application tuning may be more valuable than increasing VM size. ## Memory monitoring shows pressure before users feel it as slowness Windows Server can appear CPU- or disk-bound when the real problem is memory pressure and paging. Useful counters include: | Counter | What it shows | |---|---| | `Memory\Available MBytes` | Remaining physical memory headroom | | `Memory\Pages/sec` | Paging activity that needs interpretation with the workload | | `Process(*)\Working Set` | Approximate physical memory used by individual processes | | `Memory\Committed Bytes` | Memory committed by the operating system and applications | Microsoft's troubleshooting guidance uses available memory as an important health signal, but a production sizing decision should not rely on one universal percentage. A 4 GB application VM and a 64 GB SQL Server have very different acceptable operating patterns. For SQL Server, IIS, and RDS, interpret system memory together with workload-specific counters. If SQL Server intentionally uses most available RAM, for example, review its configured memory limit before assuming Windows itself needs more memory. ## Disk monitoring focuses on latency and workload timing A VM can show moderate CPU and plenty of RAM while users still experience slow application launches, logons, reports, or database activity because storage is the bottleneck. Useful counters include: | Counter | What it helps diagnose | |---|---| | `PhysicalDisk(*)\Avg. Disk sec/Transfer` | Read/write response time seen by Windows | | `PhysicalDisk(*)\Current Disk Queue Length` | Requests waiting on the disk path | | `PhysicalDisk(*)\Disk Transfers/sec` | Storage I/O rate | | `LogicalDisk(*)\% Free Space` | Capacity pressure | Measure the disk **during the slow workload**. A quiet server at 03:00 does not tell you whether storage becomes the limiting resource during a 09:00 login surge, nightly backup, SQL report, or application batch job. Raff Windows VMs use NVMe-backed storage, but the application can still create an I/O bottleneck through database behavior, profile growth, concurrent users, logging, backups, or too many workloads sharing the same VM. ## Network monitoring separates server pressure from connection problems Remote Desktop and distributed business applications depend on both server resources and the network path. Useful counters include: - `Network Interface(*)\Bytes Total/sec`; - network-interface errors where applicable; - application connection failures; - latency and packet loss measured from the user location; - RDP-specific behavior for Remote Desktop workloads. If only one branch or one user reports a slow Remote Desktop session while CPU, RAM, and disk remain normal, investigate the client network, Wi-Fi, routing, packet loss, display settings, and endpoint before resizing the server. Use [RDP Performance Tuning](/windows-server/rdp-performance-tuning) when the workload is specifically Remote Desktop. ## Data Collector Sets capture the problem when nobody is watching PerfMon becomes much more useful when counters are collected automatically. A **Data Collector Set** groups counters and records them at a chosen interval. Microsoft supports creating these sets through the Performance Monitor interface or with `logman.exe`. A simple GUI workflow is: 1. Open **Performance Monitor**. 2. Expand **Data Collector Sets**. 3. Open **User Defined**. 4. Create a new Data Collector Set. 5. Add CPU, memory, disk, network, and workload-specific counters. 6. Choose a collection interval appropriate for the problem. 7. Start the collector before the expected slow period. 8. Stop it after the incident and review the resulting report/log. For a recurring issue, historical capture is usually more useful than repeatedly opening Task Manager and hoping the problem happens while you are looking. ## Logman can automate a basic PerfMon capture For administrators who prefer a repeatable command-line workflow, Windows includes `logman.exe`. The following example creates a small baseline collector that records common counters every 15 seconds: ```cmd logman create counter "Raff-Server-Baseline" ^ -o "C:\PerfLogs\Raff-Server-Baseline.blg" ^ -f bin ^ -v mmddhhmm ^ -c "\Processor Information(_Total)\% Processor Time" ^ "\Memory\Available MBytes" ^ "\Memory\Pages/sec" ^ "\PhysicalDisk(_Total)\Avg. Disk sec/Transfer" ^ "\Network Interface(*)\Bytes Total/sec" ^ -si 00:00:15 ``` Start and stop the collector with: ```cmd logman start "Raff-Server-Baseline" logman stop "Raff-Server-Baseline" ``` Microsoft's own troubleshooting examples use `logman.exe` for longer-running PerfMon captures and vary the sampling interval based on the problem. A short interval gives more detail but also produces more data; a long-running baseline can usually use a less aggressive interval than a short incident capture. ## Workload counters matter as much as operating-system counters CPU, RAM, disk, and network counters tell you **where pressure appears**. The application explains **why**. ### IIS workloads need request and worker-process context Review: - CPU and memory by `w3wp.exe` process; - application-pool behavior; - request latency and error rate; - queueing; - application logs; - recycle events. If IIS is the bottleneck, continue with [IIS Application Pool Tuning](/windows-server/iis-app-pool-tuning) rather than treating the server as a generic CPU problem. ### SQL Server workloads need database context Review: - SQL Server memory configuration; - database file latency; - expensive queries; - waits and blocking; - backup activity; - SQL Server process CPU and memory. If Windows shows memory pressure while SQL Server consumes most RAM, use [MSSQL Memory Tuning](/windows-server/mssql-memory-tuning) before adding memory blindly. ### Remote Desktop workloads need session context Review: - peak concurrent sessions; - CPU during login waves; - memory per active session; - profile growth; - storage activity during logon/logoff; - latency and packet loss from user locations. For capacity planning, use [Windows VPS Sizing for Remote Users](/windows-server/windows-vps-sizing-remote-users). ### File servers need storage and SMB context Review: - capacity growth; - disk latency; - file-operation patterns; - SMB activity; - backup windows; - antivirus or indexing activity during the incident. ## Monitoring data should decide whether the VM is resized A resize is justified when the measurements repeatedly show that the VM resource itself is the constraint. | Finding | Better next action | |---|---| | CPU remains constrained during normal peak workload | Tune the responsible process or add vCPU | | Available memory repeatedly falls too low and paging coincides with slowness | Tune application memory or add RAM | | Disk latency rises during the incident | Investigate I/O pattern, storage layout, database/app behavior, or workload separation | | Only remote users are affected | Investigate latency, packet loss, RDP settings, and client path | | One process creates most pressure | Tune or isolate the application before resizing everything | | Multiple heavy roles compete on one VM | Consider splitting SQL, RDS, IIS, or other roles | The goal is not the largest Windows VM. It is the smallest configuration that gives the workload enough headroom during real peak usage. For a fresh deployment or resize, compare [Raff Windows VM](/products/windows-vm) plans after identifying the constrained resource. :::cta Deploy Windows Now Deploy a Windows VM, establish a baseline, and resize from measured workload data rather than guesswork. ::: ## Monitoring should cover normal hours and the real peak period A useful production baseline should include the workload pattern that matters to the business. Examples: - accounting server: month-end reporting and normal daytime work; - RDS server: morning login wave and busiest concurrent-user period; - IIS server: traffic peak and deployment windows; - SQL Server: reporting, imports, backups, and transaction peaks; - file server: backup window and large file operations. A five-minute capture can confirm that PerfMon works. It is not enough evidence for every sizing decision. Collect long enough to include both the normal state and the problem state you are trying to compare. ## Common monitoring mistakes hide the real bottleneck ### One CPU spike is treated as proof of undersizing Short bursts are common. Diagnose sustained behavior and the process causing it. ### CPU is monitored while RAM and disk are ignored Paging or storage latency can make a server feel CPU-bound even when CPU is not the root cause. ### Counters are collected after the slow period ends Historical Data Collector Sets are valuable because intermittent incidents rarely wait for an administrator to open Task Manager. ### Multiple changes are made before measuring again If you change CPU, RAM, application configuration, and antivirus exclusions at the same time, you will not know which change helped. ### Generic counters replace workload-specific monitoring Windows counters identify resource pressure. IIS, SQL Server, RDS, ERP, or another application still needs its own diagnostic context. ## A practical Windows Server monitoring checklist keeps the process repeatable | Check | Completed when | |---|---| | Normal baseline recorded | CPU, RAM, disk, and network behavior is known | | Peak workload captured | The period users care about is included | | PerfMon/Data Collector Set configured | Historical data can be reviewed after the incident | | Responsible processes identified | Resource pressure is tied to an application or role | | Workload-specific metrics reviewed | IIS/SQL/RDS/file-server context is included | | One bottleneck selected | The next change has a measurable hypothesis | | Post-change capture completed | Improvement or regression is proven with data | ## Validation scope The existing PerfMon screenshot in this article was retained from the previously published Raff Windows Server monitoring content. This September 2026 refresh **does not claim a new Raff lab run** or new benchmark result. Microsoft PerfMon, Data Collector Sets, `perfmon` command options, and `logman.exe` guidance were revalidated against current Microsoft documentation. Commands shown here are operational examples and should be tested against your own server and counter availability before production automation. ## What's next - [Raff Windows VM](/products/windows-vm) — choose or resize Windows compute after identifying the bottleneck. - [Windows VPS Sizing for Remote Users](/windows-server/windows-vps-sizing-remote-users) — capacity planning for concurrent RDP/RDS users. - [IIS Application Pool Tuning](/windows-server/iis-app-pool-tuning) — investigate IIS worker-process pressure. - [MSSQL Memory Tuning](/windows-server/mssql-memory-tuning) — prevent SQL Server and Windows from competing for RAM. - [RDP Performance Tuning](/windows-server/rdp-performance-tuning) — diagnose slow Remote Desktop sessions. ## Sources - Microsoft Learn — [Troubleshoot performance problems in Windows](https://learn.microsoft.com/en-us/troubleshoot/windows-server/performance/troubleshoot-performance-problems-in-windows) - Microsoft Learn — [Troubleshoot issues using Performance Monitor](https://learn.microsoft.com/en-us/troubleshoot/windows-server/support-tools/troubleshoot-issues-performance-monitor) - Microsoft Learn — [`perfmon` command](https://learn.microsoft.com/en-us/windows-server/administration/windows-commands/perfmon) - Microsoft Learn — [Performance Counters Tools](https://learn.microsoft.com/en-us/windows/win32/perfctrs/performance-counters-tools) - Microsoft Learn — [Troubleshoot Cache and Memory Manager Performance Issues](https://learn.microsoft.com/en-us/windows-server/administration/performance-tuning/subsystem/cache-memory-management/troubleshoot) - Sources revalidated: 2026-09-09 --- ### 7 Signs You've Outgrown Your Office Server (And What to Do Next) URL: https://rafftechnologies.com/windows-server/replace-office-server-small-business Description: See seven signs your small business has outgrown its office server and compare local hardware, SaaS, hybrid, and cloud Windows Server replacement options. ## In short Replace an office server when it creates more operational risk than business value: aging hardware, fragile remote access, scattered files, untested backups, rising maintenance effort, workload growth, or unclear recovery. The replacement does not have to be cloud. A small business may choose new local hardware, SaaS, hybrid infrastructure, or a cloud Windows Server. The right option depends on applications, users, licensing, recovery, and local-device dependencies. Age alone does not decide whether a server should be replaced. A five-year-old server with current support, tested backups, documented workloads, and healthy hardware can be less risky than a newer server nobody understands. The real question is simpler: > Is the office server still helping the business work, or has the business started working around the server? This guide keeps that decision practical: identify the warning signs, understand the replacement options, estimate the real operating cost, and plan the move before a failure removes your ability to test and roll back. ## Seven warning signs show when an office server needs replacement | Warning sign | What it usually means | Priority | |---|---|---| | Hardware is aging, unsupported, or difficult to repair | A failure could create a long outage | High | | Remote work depends on the office being online | Access is tied to one building, router, and internet connection | High | | Files are spread across PCs, email, and shared folders | The business lacks one controlled source of truth | High | | Backups exist but restores are untested | Recovery is assumed rather than proven | Critical | | Maintenance consumes more time and money | The server has become an operational burden | Medium/high | | The team, office count, or app workload has grown | The original design no longer fits the business | High | | Owners worry about what happens if the server stops | Business continuity is unclear | Critical | Several warning signs together usually mean the business should plan an office server replacement before an emergency forces the decision. ## Small businesses often keep office servers longer than the workload justifies Office servers stay in production because they are familiar. They may host shared folders, accounting or tax software, ERP and inventory applications, Microsoft Access databases, SQL Server workloads, Remote Desktop sessions, printers and scanners, Active Directory, DNS, scheduled reports, exports, scripts, or old applications nobody wants to disturb. The server was never just a box. It became the center of undocumented workflows. The best time to replace it is while the business can still inventory, test, run both environments in parallel, and roll back. ## Sign 1: aging or unsupported hardware turns a server into a recovery risk Review warranty, storage health, Windows Server support, firmware, spare parts, capacity, and documentation. Treat five years as a review point, not an automatic expiry date. Recurring RAID alerts, unexpected reboots, low disk space, unsupported operating systems, failed updates, hard-to-source parts, and no recent full recovery test are stronger signals than age by itself. ## Sign 2: remote work should not depend on office power and one router A local server often creates a dependency chain from the remote employee through the office internet, router, power, and physical server. If any one of those fails, remote work can stop. Microsoft Remote Desktop Services can provide centrally managed desktops and applications, but it should be planned around users, security, licensing, and capacity rather than used as an emergency remote-control workaround. See [Remote Desktop Server for Business](/windows-server/remote-desktop-server-for-business) and [RD Gateway vs Direct RDP](/windows-server/remote-desktop-gateway-vs-direct-rdp). ## Sign 3: scattered files show that the current environment has lost control of business data If documents live across employee PCs, email attachments, USB drives, personal cloud accounts, and inconsistent shared folders, the problem affects permissions, ownership, offboarding, backup coverage, retention, version control, and recovery. Before migration, identify active and archive data, define folders and owners, remove stale permissions, decide which files actually need Windows file-server behavior, document retention, and test application paths. See [Windows VPS as a Cloud File Server](/windows-server/windows-vps-cloud-file-server). ## Sign 4: a backup without a restore test is only an assumption A successful backup job is not the same as a successful recovery. Define what is backed up, where copies live, how often they run, who sees failures, who can delete recovery points, when restore was last tested, and how long recovery takes. On Raff, snapshots/backups are currently **$0.06/GB/month**. Treat that as an infrastructure cost layer, not a substitute for application-aware recovery where the workload requires it. See [Windows VPS Backup Strategy for Small Businesses](/windows-server/windows-vps-backup-strategy-small-business). ## Sign 5: the real maintenance cost is larger than the hardware invoice A local server's real cost can include hardware, warranty, replacement parts, UPS, electricity, networking, backup software, security tooling, after-hours maintenance, emergency support, and downtime. Cloud hosting is not automatically cheaper. A Windows VPS removes ownership of the physical server hardware, but it does **not** automatically remove Windows administration, application support, licensing, security, backups, or migration work. See [Windows VPS Pricing Explained](/windows-server/windows-vps-pricing-explained). ## Sign 6: growth can make the original server design obsolete before the hardware fails Do not size a replacement by copying the old server's specifications. Size around peak active users, simultaneous applications, database and reporting load, file and profile growth, printing/scanning workflows, backup windows, recovery expectations, and future growth. Use [Windows VPS Sizing for Remote Users](/windows-server/windows-vps-sizing-remote-users) for current Raff plan anchors. ## Sign 7: unclear recovery expectations reveal a business-continuity problem A single cloud VM is not automatically highly available either. Critical workloads may require multiple servers, replication, failover, or another architecture. Define recovery point, recovery time, ownership, and budget before buying “high availability” as a label. ## Office server replacement now has four practical paths ![Comparison infographic showing a traditional office server versus a cloud Windows VPS for remote access, backups, centralized files, and easier scaling](https://raff-images.s3.raffusercloud.com/office_server_vs_cloud_windows_vps_comparison_webp_2812307f21.png) | Replacement path | Best fit | Main trade-off | |---|---|---| | New local server | LAN-heavy workloads, local devices, unreliable internet, strong on-site IT | Business still owns hardware and lifecycle | | SaaS applications | Standard workflows that can move fully to vendor-hosted software | Process changes, data migration, recurring app cost | | Cloud Windows Server / VPS | Supported Windows apps, RDP/RDS users, shared files, office-server replacement | Requires internet, secure access, licensing, sizing, and backups | | Hybrid | Some workloads must stay local while others move | Flexible, but more components to document and support | ## A cloud server for small business should be priced as a complete Windows workload Current Raff examples: | Planning example | Compute | Windows Server Standard SPLA | Starting Windows total | |---|---:|---:|---:| | 2 vCPU / 4 GB / 80 GB | $22.99 | $15.00 | **$37.99/mo** | | 4 vCPU / 8 GB / 120 GB | $40.99 | $15.00 | **$55.99/mo** | | 8 vCPU / 16 GB / 180 GB | $76.99 | $15.00 | **$91.99/mo** | These are infrastructure examples, not performance guarantees. Add what applies to the real workload: - Raff-hosted RDS User SAL: **$8/user/month** when employees use hosted RDS functionality; - additional volumes: **$0.08/GB/month**; - snapshots/backups: **$0.06/GB/month**; - SQL Server or application licensing where applicable; - migration and support work where applicable. Raff Windows VM traffic is **3 Gbps unmetered with no VM egress fees**. The important licensing split is: ```text Raff-hosted SPLA model: VM compute + $15/month Windows Server Standard + $8/user/month RDS User SAL when hosted RDS is used ``` Customer-owned Microsoft licensing is a different path. Under eligible BYOL scenarios, Windows Server licensing, Windows Server CALs, and RDS CALs may apply according to the customer's Microsoft rights. Do not mix customer-owned CAL rules with the Raff-hosted SPLA/SAL model. See [Windows Server Licensing](/windows-server/windows-licensing). :::cta View Pricing Compare current Windows VM compute, Windows licensing, user access, storage, and protection costs before replacing office hardware. ::: ## A Windows VPS is the practical replacement only when the workload fits A cloud Windows Server usually makes sense when the business still needs Windows Server, remote or branch users need one environment, supported Windows applications need centralized access, shared folders are still required, or the office server is aging and unreliable. It is a weaker fit when the only need is document collaboration, the workload depends on specialized local hardware, internet connectivity is unreliable, the vendor does not support hosting/RDS, large LAN files move constantly, or no one will own Windows administration after migration. ## A safe office-server replacement starts with discovery, not copying files Inventory Windows roles, users/groups, file shares, permissions, applications, databases, RDS configuration, printers/scanners, scheduled tasks, certificates, DNS/IPs, firewall rules, backups, and vendor contacts. Then decide what should move, rebuild, replace, or retire. Validate Windows Server support, hosted-environment support, RDS/multi-user support, application licence terms, SQL Server licensing, printing/scanning requirements, integrations, and vendor backup support before production. For Raff-hosted RDS, use RDS User SALs. For customer-owned/BYOL deployments, validate applicable CAL and RDS CAL rights separately. ## Build the new environment beside the old one A safer migration pattern is: ```text Current office server stays online → Replacement environment is built → Apps, users, files, licensing, and backups are tested → Pilot users complete real workflows → Final data sync is performed → Users cut over → Old server remains available for rollback ``` Test real work: files, application logins, reports, printing, scanning, mapped drives, database operations, permissions, remote sessions, backups, and restores. ## Raff provides the Windows infrastructure foundation, not every layer of the migration Raff fits small businesses and MSPs that need a hosted Windows Server foundation for supported business applications, Remote Desktop users, shared files, databases, branch access, and migration away from aging office hardware. Raff provides the VM infrastructure. The business or MSP should still plan and manage application support and licensing, Windows administration, hosted RDS User SALs or applicable customer-owned Microsoft access licensing, user accounts, secure remote access, database configuration, backup retention, restore testing, migration timing, rollback, monitoring, and ongoing support. ## The office server replacement checklist should be complete before cutover | Check | Done | |---|---| | Hardware health and warranty reviewed | ☐ | | Windows Server support status reviewed | ☐ | | Server roles documented | ☐ | | Users, groups, and admins documented | ☐ | | Shared folders and permissions documented | ☐ | | Business apps and versions documented | ☐ | | Vendor hosting/RDS support confirmed | ☐ | | Windows, RDS, SQL, and app licensing reviewed | ☐ | | Printers, scanners, dongles, and local devices listed | ☐ | | Scheduled tasks, scripts, and integrations listed | ☐ | | Current backup success verified | ☐ | | Restore test completed | ☐ | | Replacement option selected | ☐ | | CPU, RAM, and storage sized | ☐ | | Remote-access model selected | ☐ | | Security and firewall rules planned | ☐ | | Backup and retention policy defined | ☐ | | Pilot users selected | ☐ | | Cutover window selected | ☐ | | Rollback process documented | ☐ | | Ongoing support owner assigned | ☐ | If several answers are unknown, the business is not ready to cut over. It is ready to begin discovery. ## Validation scope This September 2026 refresh is a commercial planning and source-of-truth update, not a claim that Raff performed a fresh office-server migration benchmark. Current Raff Windows VM pricing, Windows Server SPLA pricing, hosted RDS User SAL pricing, volume pricing, snapshot/backup pricing, and network terms were revalidated. Microsoft Remote Desktop Services licensing guidance was also rechecked. Application compatibility and licensing still need vendor- and agreement-specific validation before production. ## What's next - [Windows VPS Hosting for Small Businesses](/windows-server/windows-vps-small-business) - [Windows VPS as a Cloud File Server](/windows-server/windows-vps-cloud-file-server) - [Windows VPS Sizing for Remote Users](/windows-server/windows-vps-sizing-remote-users) - [Remote Desktop Server for Business](/windows-server/remote-desktop-server-for-business) - [Windows Server Licensing](/windows-server/windows-licensing) - [Windows VPS Pricing Explained](/windows-server/windows-vps-pricing-explained) - [Raff Windows VM](/products/windows-vm) ## Sources - Microsoft Learn — Remote Desktop Services overview in Windows Server - Microsoft Learn — Plan and design your Remote Desktop Services environment - Microsoft Learn — Remote Desktop Services: choose how you pay - CISA — Cyber Guidance for Small Businesses - Raff — Windows VM - Raff — Pricing - Sources revalidated: 2026-09-09 --- ### Windows Server 2025 Core vs Desktop Experience: Which Should You Choose? URL: https://rafftechnologies.com/windows-server/windows-server-core-vs-desktop-experience Description: Compare Windows Server 2025 Core vs Desktop Experience for a VPS. Learn why Standard vs Desktop Experience is not an edition choice, which roles require GUI, and when Server Core is the better fit. ## In short Choose **Windows Server Core** when the required role and software support it, your team can manage Windows remotely or with PowerShell, and no users need a normal Windows desktop. Choose **Server with Desktop Experience** when the workload needs a local GUI, Remote Desktop Session Host, GUI-dependent business software, or administrators who primarily manage the server through RDP. Microsoft recommends Server Core unless you have a specific need for the additional interface and graphical management tools in Desktop Experience. For Windows Server 2025, 2022, 2019, and 2016, you **cannot switch between Core and Desktop Experience after installation**; changing the installation option requires a clean installation. For many Raff Technologies customers running interactive Windows business software or user desktops, Desktop Experience is the lower-risk choice. For dedicated infrastructure roles such as Active Directory, DNS, DHCP, IIS, Hyper-V, or file services, Server Core is often the cleaner option after role, agent, and vendor compatibility are verified. ## Windows Server Standard vs Desktop Experience is not the real comparison A common search is **“Windows Server Standard vs Desktop Experience,”** but those are not competing editions. **Standard** and **Datacenter** are Windows Server editions. **Server Core** and **Server with Desktop Experience** are installation options available within those editions. In Windows Server 2025 Setup, the choices are effectively: ```text Windows Server Standard → Server Core installation Windows Server Standard with Desktop Experience → Full graphical installation Windows Server Datacenter → Server Core installation Windows Server Datacenter with Desktop Experience → Full graphical installation ``` So if you are deciding between **Windows Server 2025 Standard and Standard with Desktop Experience**, you are not changing the Standard edition license tier. You are choosing whether that Standard installation includes the full graphical desktop and local GUI management tools. That distinction matters because application compatibility, RDS role availability, administration style, and reinstall risk are tied to the **installation option**, while Standard vs Datacenter is a separate edition decision. For edition differences, use [Windows Server 2019 vs 2022 vs 2025](/windows-server/windows-server-version-comparison). ## Quick decision table | Requirement | Better choice | Why | |---|---|---| | Dedicated infrastructure role with remote management | Server Core | Smaller footprint and fewer unnecessary interface components | | RDS Session Host for employee desktop sessions | Desktop Experience | RD Session Host is not included in Server Core | | GUI-dependent accounting, ERP, tax, or legacy software | Desktop Experience | The app or vendor workflow may depend on the desktop shell | | IIS web server managed remotely | Server Core | IIS is supported and can be managed with PowerShell or remote tools | | Active Directory domain controller | Server Core | AD DS is supported and usually does not need a local desktop | | DNS or DHCP server | Server Core | Role-based infrastructure is a strong fit for remote administration | | One administrator learning Windows Server | Desktop Experience | Easier local navigation and troubleshooting | | Automated or standardized server fleet | Server Core | Better fit for repeatable PowerShell and remote-management workflows | | Vendor requires local MMC or GUI administration | Desktop Experience | Reduces compatibility and support risk | | You are unsure whether the software supports Core | Desktop Experience | Reinstalling later is more disruptive than choosing the GUI initially | The best choice is based on workload compatibility first, management model second, and operating-system footprint third. ## Server Core is the minimal Windows Server installation option Server Core is available for Windows Server Standard and Datacenter and does not install the traditional Windows desktop shell. After signing in, administration is centered on: - PowerShell - Command Prompt - SConfig - Windows Admin Center - Remote Server Administration Tools (RSAT) - Server Manager from another Windows machine - remote MMC snap-ins where supported Server Core does **not** mean the machine cannot accept an administrator RDP connection. RDP can be enabled, but the session does not become a normal Windows desktop with Start menu, full Explorer shell, and the complete local GUI toolset. Microsoft documents Server Core as having a smaller disk requirement and a greatly reduced potential attack surface compared with Desktop Experience. That is useful, but it does not replace patching, firewall rules, secure administrator access, monitoring, backups, and role-specific hardening. ## Server with Desktop Experience provides the full local GUI Server with Desktop Experience installs the standard graphical Windows Server interface and broader local management environment. It includes: - the Windows desktop shell - Start menu and File Explorer - Server Manager - Microsoft Management Console - graphical role and feature tools - graphical settings and troubleshooting workflows - broader application compatibility - local GUI support tools Desktop Experience is normally easier for administrators managing one or a few Windows VPS instances directly through RDP. It is also the practical choice for software that expects graphical installers, local desktop interaction, tray applications, GUI administration consoles, or end-user sessions. ## Core differences at a glance | Area | Server Core | Desktop Experience | |---|---|---| | Local interface | PowerShell, Command Prompt, SConfig | Full graphical desktop | | Server Manager locally | No | Yes | | Remote management | Yes | Yes | | Windows Admin Center | Supported | Supported | | RSAT and remote MMC | Supported for applicable tools | Supported | | Disk requirement | Smaller | Larger | | Installed interface components | Fewer | More | | Application compatibility | More limited | Broadest Windows Server compatibility | | Local troubleshooting | Command-line focused | GUI and command-line tools | | Potential attack surface | Greatly reduced | Larger component set | | RDS Session Host | Not included | Supported | | Switching after installation | Clean reinstall required | Clean reinstall required | ## You cannot add Desktop Experience to Server Core later Windows Server 2016, 2019, 2022, and 2025 do not support converting an installed Server Core system into Server with Desktop Experience or vice versa. ```text Server Core → Desktop Experience Desktop Experience → Server Core ``` Both require a clean installation or replacement server. If you choose the wrong option in production, the recovery path normally looks like this: 1. Back up data and document the current configuration. 2. Deploy a replacement VM or reinstall the existing system. 3. Install the required Windows Server option. 4. Recreate roles, applications, users, certificates, firewall rules, and scheduled tasks. 5. Restore or migrate data. 6. Test the workload. 7. Cut over with a rollback path. That reinstall cost is why compatibility uncertainty should usually push a small business toward Desktop Experience until the workload is proven on Core. ## Security favors Core, but operations still matter more than slogans Server Core removes the desktop shell and components that are not needed for its supported server roles. Microsoft explicitly describes its potential attack surface as greatly reduced compared with Desktop Experience. Potential Core advantages include: - smaller operating-system footprint - fewer graphical components - reduced potential attack surface - fewer unnecessary components for dedicated roles - cleaner standardization for automation But Server Core still needs: - current Windows updates - Microsoft Defender or another approved security product - Windows Firewall enabled - restricted administrator access - secure remote-management configuration - logging and monitoring - backups and restore testing - role-specific hardening Desktop Experience can also be secured effectively. A team that cannot safely manage or recover a Core server can create more operational risk than it removes. For either option, use the [Windows Server Hardening Checklist](/windows-server/windows-server-hardening-checklist). ## Server Core saves operating-system footprint, not application workload Server Core needs less disk space because the desktop shell and several graphical components are not installed. It can also avoid background activity tied to those components. That does **not** mean an application will suddenly need much less CPU or RAM. SQL Server, IIS, antivirus, databases, backup agents, and user sessions usually dominate real workload requirements. | Situation | How much the smaller Core footprint matters | |---|---| | Small dedicated DNS, DHCP, or domain controller | Useful | | Large standardized server fleet | Useful at scale | | IIS server with no local GUI dependency | Useful | | SQL or app server dominated by workload demand | Secondary factor | | RDS server with interactive users | Desktop Experience required for Session Host | | Business software that needs a GUI | Compatibility matters more than savings | Do not choose Core merely to make an undersized VM look acceptable. Size the server for the actual workload. ## Server Core is designed for remote administration Core works best when RDP is not treated as the only management strategy. ### SConfig handles common local setup Run: ```powershell SConfig ``` SConfig provides a menu for tasks such as computer name, domain membership, local administrators, Windows Update, Remote Desktop, networking, activation, restart, and shutdown. ### PowerShell is the primary local and remote interface Useful examples include: ```powershell Get-ComputerInfo | Select-Object CsName, WindowsProductName, WindowsVersion, OsBuildNumber Get-WindowsFeature | Where-Object InstallState -eq "Installed" Get-Service | Sort-Object Status, DisplayName Get-NetFirewallProfile | Select-Object Name, Enabled, DefaultInboundAction, DefaultOutboundAction ``` ### Windows Admin Center, RSAT, Server Manager, and MMC can manage Core remotely Microsoft supports remote GUI administration of Server Core. This lets you keep the target server minimal while using graphical tools from another supported Windows management machine. Server Core is therefore not “PowerShell only.” It is a **remote-management-first** operating model. ## Application Compatibility Feature on Demand adds selected GUI tools to Core Windows Server 2019, 2022, and 2025 support the **Server Core Application Compatibility Feature on Demand**. Microsoft documents it as an optional package that adds a subset of Desktop Experience binaries and tools to improve compatibility and troubleshooting without converting Core into Desktop Experience. Depending on the Windows Server version, it can add tools such as: - File Explorer - Microsoft Management Console - Event Viewer - Disk Management - Device Manager - Performance Monitor - Resource Monitor - Hyper-V Manager - Task Scheduler - PowerShell ISE The capability name is: ```powershell ServerCore.AppCompatibility~~~~0.0.1.0 ``` A typical online installation uses: ```powershell Add-WindowsCapability -Online -Name "ServerCore.AppCompatibility~~~~0.0.1.0" ``` A restart is required after installation. Microsoft also notes that after an in-place upgrade to a newer Windows Server release, the App Compatibility FOD may need to be installed again unless it was integrated into a custom image. This package does **not** turn Core into Desktop Experience and does not add unsupported server roles such as RD Session Host. ## Infrastructure roles are the strongest Server Core use cases ### Active Directory Domain Services A dedicated domain controller normally does not need users running desktop applications locally. AD DS is available on Core and can be managed with PowerShell, RSAT, and remote tools. ### DNS and DHCP DNS and DHCP are mature role-based services with strong remote-management paths. They are natural Core candidates. ### IIS web server IIS is available on Server Core. The key question is whether the complete application stack, deployment tooling, frameworks, agents, and vendor support work without Desktop Experience. ### Hyper-V Hyper-V is a classic Core workload because normal management can be remote. ### File and storage services A dedicated file server can use Core when permissions, shares, storage, monitoring, antivirus, and backups are all manageable without a local full desktop. ### Automated infrastructure Core fits environments where configuration, patching, deployment, and monitoring are standardized through scripts and remote tools. ## RDS and interactive business software usually require Desktop Experience ### Remote Desktop Session Host Microsoft does not include **Remote Desktop Session Host** in Server Core. RD Gateway and RD Web Access are also not included in the Server Core image, although some other RDS role services are available. If employees need normal desktop or RemoteApp sessions, use Desktop Experience and plan the required RDS architecture and licensing. For Raff-hosted RDS workloads, the current Raff RDS User SAL is **$8 per user per month** in addition to the Windows VM and applicable Windows Server licensing. See the [RDS CAL Licensing Guide](/windows-server/rds-cal-licensing-guide) before production deployment. ### GUI-dependent business software Accounting, ERP, tax, inventory, legal, trading, and legacy applications may rely on: - graphical installers - desktop shell components - tray applications - interactive user sessions - printer or redirected-device workflows - GUI administration consoles - vendor support procedures based on the desktop Even if an application technically launches on Core, vendor support still matters. Use Desktop Experience unless the exact version and operational workflow are supported and tested on Core. ### One-server environments managed mainly through RDP For a small business with one generalist administrator, the operational simplicity of Desktop Experience often matters more than the smaller Core footprint. ## Workload compatibility matrix | Workload | Server Core | Desktop Experience | Recommendation | |---|---:|---:|---| | Active Directory Domain Services | Yes | Yes | Prefer Core when remote management is established | | DNS Server | Yes | Yes | Prefer Core for a dedicated role | | DHCP Server | Yes | Yes | Prefer Core for a dedicated role | | IIS web server | Yes | Yes | Core when app dependencies support it | | Hyper-V host | Yes | Yes | Core is often the cleaner operational model | | File server | Yes | Yes | Core when local GUI tools are unnecessary | | RDS Session Host | No | Yes | Use Desktop Experience | | Interactive employee desktop | No | Yes | Use Desktop Experience | | GUI-dependent third-party app | Depends | Yes | Prefer Desktop Experience unless vendor supports Core | | Legacy Windows application | Higher compatibility risk | Broadest compatibility | Prefer Desktop Experience | | Local desktop administration | Limited | Full | Use Desktop Experience | | Scripted server fleet | Strong fit | Possible | Prefer Core where supported | Always verify the exact role service, application version, installer, monitoring agent, backup agent, security software, and licensing component before choosing Core. ## IIS works on Core, but the whole web stack must work too A good Core-based IIS deployment has: - a supported .NET/application stack - automated deployment - remote log access - remote IIS or PowerShell administration - external monitoring - documented certificate renewal - tested backup and rollback Desktop Experience is safer if the application depends on a GUI-only installer, desktop automation, local browser components, unverified COM/shell dependencies, or vendor support tools that assume a full desktop. The question is not whether IIS itself works on Core. It does. The question is whether the **complete application** is supportable there. ## A dedicated domain controller is a strong Core candidate A Core domain controller removes unnecessary local desktop components from an identity-critical server. That is valuable when administrators already use RSAT, PowerShell, and remote management. Before deployment, confirm DNS design, time synchronization, system-state backup, a second-domain-controller plan, remote administration, monitoring, and recovery credentials. Do not install unrelated business software or allow normal user work sessions on a domain controller regardless of the installation option. ## Small businesses should choose the option they can safely operate during an incident Choose Core when: - an MSP or experienced Windows administrator manages the server; - the workload is a supported infrastructure role; - remote management is already standard; - the application vendor supports Core; - monitoring and backups are remote and documented. Choose Desktop Experience when: - the server is managed mainly through RDP; - it hosts interactive business software; - users need desktop sessions; - vendor support expects a GUI; - troubleshooting skills are mainly graphical; - there is no separate management workstation or gateway. A smaller operating-system footprint is not useful if the team cannot recover the server confidently. ## Use this five-question decision framework before deployment ### 1. Does the exact role service exist on Server Core? Check Microsoft’s current Server Core role and feature list. Some roles exist while individual role services do not. ### 2. Does the exact application version support Server Core? Verify the installer, runtime dependencies, updates, monitoring, backup agents, licensing services, security tools, printers, and vendor support process. ### 3. Do users need a normal Windows desktop? If employees need desktop or RemoteApp sessions, Desktop Experience is the correct direction. ### 4. Can the team manage the machine without a local full GUI? Core is a strong fit when Windows Admin Center, RSAT, PowerShell remoting, monitoring, and recovery access are already established. ### 5. Can you recover the server without the local desktop? Document provider console access, password recovery, networking rollback, backup restore, remote-management credentials, firewall rollback, and application reinstall steps. ## Common mistakes ### Choosing Core only to save RAM Compatibility and operational readiness matter more than small operating-system savings. ### Assuming RDP gives Core a normal desktop RDP can connect to Core, but the session remains a Server Core environment. ### Assuming every Windows application works on Core Windows Server roles and third-party applications have separate requirements. ### Planning to add the GUI later You cannot convert the installation option after deployment; a clean installation is required. ### Treating Desktop Experience as insecure by definition Desktop Experience has more components, but security still depends on patching, access control, firewalling, monitoring, backups, and operations. ### Treating Core as automatically hardened Core’s smaller attack surface does not fix weak credentials, exposed RDP, excessive privileges, missing backups, or outdated applications. ### Using Server Core for an RDS desktop server RD Session Host is not in Core. Use Desktop Experience for regular employee sessions. ## Recommended choice by VPS scenario | VPS scenario | Recommended option | |---|---| | First Windows VPS for a general administrator | Desktop Experience | | RDP workspace for one or more users | Desktop Experience | | Accounting, ERP, tax, or legacy app server | Desktop Experience unless vendor verifies Core | | Dedicated IIS web server | Server Core after dependency validation | | Dedicated domain controller | Server Core | | DNS or DHCP server | Server Core | | Hyper-V host | Server Core | | File server managed by an MSP | Server Core after agent compatibility checks | | Small office server with mixed roles | Desktop Experience, although separating roles is better | | Automated multi-server environment | Server Core where supported | | Proof of concept with unknown requirements | Desktop Experience or test both before production | ## Raff recommends compatibility first, then footprint For an interactive Windows VPS, business-software host, or RDS workload, Desktop Experience is usually the safest starting point because it offers the broadest compatibility and simplest administration model for small teams. Choose Server Core when all four conditions are true: 1. The exact server role is supported. 2. Every required application and agent supports Core. 3. The administrator can manage and recover the server remotely. 4. No users require a normal Windows desktop session. :::cta Deploy Windows Now Deploy the Windows VM that matches your application, management model, and Remote Desktop requirements. ::: ## Validation scope This guide was revalidated on **September 9, 2026** against current Microsoft Learn documentation for Windows Server 2025, 2022, 2019, and 2016. Microsoft’s current guidance still recommends Server Core unless the additional GUI is needed, confirms that Core and Desktop Experience cannot be converted after installation, and confirms that RD Session Host is not included in Server Core. The current Server Core App Compatibility Feature on Demand was also rechecked. No Raff-specific benchmark is claimed in this article. ## What's next - [Windows Server Initial Setup Checklist](/windows-server/windows-server-initial-setup-checklist) - [Windows Server 2019 vs 2022 vs 2025](/windows-server/windows-server-version-comparison) - [How to Connect to a Windows VPS via RDP](/windows-server/connect-to-windows-vps-via-rdp) - [RDS CAL Licensing Guide](/windows-server/rds-cal-licensing-guide) - [25 PowerShell Commands Every Windows VPS Admin Needs](/windows-server/powershell) - [Windows Server Hardening Checklist](/windows-server/windows-server-hardening-checklist) - [Raff Windows VM](/products/windows-vm) ## Sources - Microsoft Learn — Server Core vs Server with Desktop Experience install options: https://learn.microsoft.com/en-us/windows-server/get-started/install-options-server-core-desktop-experience - Microsoft Learn — What is the Server Core installation option?: https://learn.microsoft.com/en-us/windows-server/administration/server-core/what-is-server-core - Microsoft Learn — Manage a Server Core server: https://learn.microsoft.com/en-us/windows-server/administration/server-core/server-core-manage - Microsoft Learn — Roles, role services, and features included in Server Core: https://learn.microsoft.com/en-us/windows-server/administration/server-core/server-core-roles-and-services - Microsoft Learn — Roles, role services, and features not in Server Core: https://learn.microsoft.com/en-us/windows-server/administration/server-core/server-core-removed-roles - Microsoft Learn — Install the Server Core Application Compatibility Feature on Demand: https://learn.microsoft.com/en-us/windows-server/get-started/server-core-app-compatibility-feature-on-demand - Sources revalidated: 2026-09-09 --- ### How to Set Up SMB over QUIC on Windows Server 2025 with a Let's Encrypt Certificate (No VPN Needed) URL: https://rafftechnologies.com/windows-server/smb-over-quic-windows-server-vps Description: Set up SMB over QUIC on Windows Server 2025 using UDP 443 and a TLS certificate. Includes current edition support, firewall rules, certificate mapping, Windows client testing, and renewal guidance. ## In short SMB over QUIC lets Windows clients reach SMB file shares over an encrypted QUIC connection instead of exposing traditional SMB on TCP 445 to the internet. On Windows Server 2025, SMB over QUIC is available in **Standard and Datacenter editions**. The default deployment path uses **UDP 443** with TLS 1.3 and a certificate whose name matches the server FQDN. Raff Technologies tested the full workflow on Windows Server 2025 using a public DNS name, a Let's Encrypt certificate, SMB certificate mapping, and a remote Windows client. This refresh keeps that test evidence but updates the 2026 guidance around pricing, certificate tooling, renewal, and client compatibility. ## SMB over QUIC is useful when you need remote SMB without exposing TCP 445 Traditional SMB over the public internet is a poor fit because TCP 445 is commonly blocked and should not be broadly exposed. SMB over QUIC changes the transport: the SMB session runs through QUIC over UDP, with TLS 1.3 protecting the connection. Common use cases include: - remote employees mounting a Windows file share without a separate VPN tunnel; - branch offices that need a shared UNC path over the internet; - MSP-managed file servers for distributed client teams; - contractors who need controlled access to specific shares. SMB over QUIC does not replace identity, permissions, endpoint management, backups, or good credential hygiene. It changes the transport, not the authorization model. ## Windows Server 2025 changed the SMB over QUIC edition requirements Older Server 2022 guidance is easy to misread because SMB over QUIC was associated with Azure Edition. On **Windows Server 2025**, Microsoft makes SMB over QUIC available in **Standard and Datacenter** editions as well. That makes the feature practical on hosted Windows Server 2025 VMs outside Azure. ## What you'll need For the workflow in this guide: - Windows Server 2025 Standard or Datacenter; - local administrator access; - the File Server role; - a public DNS name such as `files.example.com`; - a TLS certificate that matches that FQDN; - inbound **UDP 443** for SMB over QUIC; - a supported SMB over QUIC client; - strong user credentials and appropriate share/NTFS permissions. If you use Let's Encrypt HTTP-01 for certificate issuance or renewal, you also need inbound **TCP 80** reachable during validation. If you use DNS-01, TCP 80 is not required for certificate validation. ## Tested on Raff The original lab test was performed on: | Item | Value | |---|---| | Provider | Raff Technologies | | OS | Windows Server 2025 Standard Evaluation | | Build | 26100 | | VM size used in lab | 4 vCPU / 8 GB RAM / 120 GB NVMe | | Region | us-east | | Validation FQDN | `quic-test.raffusercloud.com` | | ACME client used in lab | win-acme 2.2.9.1701 | | Certificate validation | HTTP-01 self-hosting | | Test date | 2026-05-23 | | Tester | Serdar Tekin | The lab verified File Server installation, UDP 443 firewall access, certificate issuance, SMB certificate mapping, share creation, remote client access, and transport verification with `QuicConnectionCount=1` and `TcpConnectionCount=0`. The Evaluation image shown in screenshots was used for documentation testing. It is not the production licensing recommendation for Raff customers. ## Step 1 — Install the File Server role Open PowerShell as Administrator: ```powershell Install-WindowsFeature -Name FS-FileServer -IncludeManagementTools ``` Verify: ```powershell Get-WindowsFeature -Name FS-FileServer ``` Then inspect the SMB server configuration: ```powershell Get-SmbServerConfiguration | Select-Object EnableSMB1Protocol, EnableSMB2Protocol, EnableSMBQUIC, RestrictNamedPipeAccessViaQuic ``` On Server 2025, SMB1 should remain disabled. SMB over QUIC support is built into the current SMB server stack; you do not install a separate QUIC role. Create a test folder if you need one: ```powershell New-Item -Path "C:\QuicShare" -ItemType Directory -Force ``` ## Step 2 — Open UDP 443 for SMB over QUIC The standard SMB over QUIC deployment uses **UDP 443**, not TCP 443. ```powershell New-NetFirewallRule -DisplayName "SMB over QUIC (UDP 443)" ` -Direction Inbound ` -Protocol UDP ` -LocalPort 443 ` -Action Allow ``` Verify: ```powershell Get-NetFirewallRule -DisplayName "SMB over QUIC (UDP 443)" | Format-List DisplayName, Enabled, Direction, Action ``` Microsoft recommends using SMB over QUIC instead of exposing TCP 445 to the internet. Keep TCP 445 restricted to the networks that genuinely require classic SMB access. ## Step 3 — Obtain a certificate for the file-server FQDN SMB over QUIC requires a certificate that matches the name clients use to connect. The original Raff lab used **win-acme 2.2.9.1701** and Let's Encrypt. That tested workflow remains valid for existing win-acme deployments, but the win-acme project has since been succeeded by **simple-acme**, maintained by the same project maintainer. For a new long-lived deployment in 2026, evaluate simple-acme before standardizing on the older win-acme client. The certificate must: - contain the file-server FQDN in the Subject Alternative Name; - be trusted by the client; - include a private key on the server; - remain valid for the lifetime of the SMB certificate mapping. If you use HTTP-01, make sure the DNS name resolves to the server and TCP 80 is reachable during validation. Wildcard certificates require DNS-01. ![Win-acme 2.2.9.1701 main menu running on Windows Server 2025, showing certificate creation options including Create certificate default settings, full options, run renewals, manage renewals, and more options](https://raff-images.s3.raffusercloud.com/large_raff_smb_quic_winacme_main_menu_2026_05_115b43744d.png) The lab stored the certificate in `Cert:\LocalMachine\My` and confirmed that it had a private key. Check your certificate: ```powershell Get-ChildItem Cert:\LocalMachine\My | Sort-Object NotAfter -Descending | Select-Object Subject, Thumbprint, NotAfter, HasPrivateKey ``` `HasPrivateKey` must be `True` for the server certificate you map to SMB. ## Step 4 — Map the certificate to SMB over QUIC Once the certificate is installed, map it to the exact FQDN used by clients. Example: ```powershell New-SmbServerCertificateMapping ` -Name "files.example.com" ` -Thumbprint "YOUR_CERTIFICATE_THUMBPRINT" ` -StoreName "My" ` -Type QUIC ` -Flags None ``` Verify: ```powershell Get-SmbServerCertificateMapping | Format-List Name, Thumbprint, StoreName, Type, Flags ``` The mapping should show the expected name and `Type : QUIC`. ## Step 5 — Create the SMB share and permissions Create a share only after defining both SMB share permissions and NTFS permissions appropriate for the users who need access. Example test share: ```powershell New-SmbShare ` -Name "QuicShare" ` -Path "C:\QuicShare" ` -FullAccess "CONTOSO\FileUsers" ``` For workgroup systems, use a scoped local user instead of a broad group. For domain-joined systems, prefer domain identities and groups. Remember that effective access is the intersection of **share permissions** and **NTFS permissions**. ## Step 6 — Connect from a supported Windows client From a supported Windows client, map the share using QUIC transport. ```powershell net use Z: \\files.example.com\QuicShare /TRANSPORT:QUIC ``` If credentials are required: ```powershell net use Z: \\files.example.com\QuicShare /TRANSPORT:QUIC /USER:CONTOSO\username ``` Avoid embedding plaintext production passwords directly in commands or scripts. Microsoft has expanded SMB over QUIC client support over time, so verify the current edition and build requirements for the client fleet you actually manage rather than relying on an old 2022-era compatibility chart. ## Step 7 — Verify that the connection is really using QUIC A successful mapped drive is not enough. Verify transport. ```powershell Get-SmbMultichannelConnection -ServerName files.example.com | Format-List * ``` In the Raff lab, the proof output included: ```text QuicConnectionCount : 1 TcpConnectionCount : 0 Selected : True ``` ![Get-SmbMultichannelConnection PowerShell output showing QuicConnectionCount equals 1, TcpConnectionCount equals 0, and Selected equals True, confirming SMB is running exclusively over QUIC UDP 443 with zero TCP fallback](https://raff-images.s3.raffusercloud.com/smb_quic_multichannel_verified_2026_05.png) That confirms the client is using SMB over QUIC rather than classic SMB over TCP. ## Certificate renewal needs an SMB mapping check Certificate renewal deserves special attention because SMB over QUIC depends on the certificate mapping remaining valid after renewal. If your ACME client replaces the leaf certificate with a new certificate and thumbprint, verify whether the SMB certificate mapping was updated as part of your renewal workflow. Check the current mapping: ```powershell Get-SmbServerCertificateMapping | Format-List Name, Thumbprint, StoreName, Type ``` Then compare it with the newest certificate for the FQDN: ```powershell Get-ChildItem Cert:\LocalMachine\My | Sort-Object NotBefore -Descending | Select-Object -First 10 Subject, Thumbprint, NotBefore, NotAfter ``` Do not assume that successful ACME renewal automatically guarantees the SMB mapping now points at the newest thumbprint. Build a post-renewal verification step into your operational process. If you still use win-acme, also verify its scheduled task and renewal list: ```powershell .\wacs.exe --list Get-ScheduledTask | Where-Object TaskName -like "*win-acme*" ``` For new deployments, review simple-acme's current renewal and scripting options before implementing the equivalent automation. ## Common errors ### SMB over QUIC does not connect First verify DNS and UDP 443. TCP-based `Test-NetConnection -Port 443` does not prove UDP 443 is reachable, so use firewall logs, packet capture, or another UDP-aware diagnostic if needed. ### The certificate name does not match Clients must connect using a name covered by the certificate. Connecting by raw IP address usually fails certificate validation unless the certificate was specifically issued for that identity, which public ACME certificates generally are not. ### The certificate has no private key Check: ```powershell Get-ChildItem Cert:\LocalMachine\My | Select-Object Subject, Thumbprint, HasPrivateKey ``` Use a certificate entry with `HasPrivateKey : True`. ### Authentication fails Separate transport problems from account problems. Review the server Security log for failed logons and verify username format, password, account state, share permissions, and NTFS permissions. ```powershell Get-WinEvent -FilterHashtable @{LogName='Security'; Id=4625; StartTime=(Get-Date).AddMinutes(-10)} -MaxEvents 10 ``` ### Renewal succeeded but QUIC stopped working later Compare the active SMB certificate mapping with the currently valid certificate thumbprint. If the ACME client issued a replacement certificate, the SMB mapping may need to be refreshed depending on how your automation is built. ## SMB over QUIC should not be treated as a complete security architecture SMB over QUIC protects the network transport, but production deployments still need: - strong identity and credential policies; - least-privilege SMB and NTFS permissions; - supported Windows builds; - endpoint security; - tested backups; - monitoring and failed-logon review; - a certificate renewal process; - a documented offboarding process for remote users. Avoid treating "no VPN needed" as "no other security controls needed." ## Raff sizing should follow workload, not user-count shortcuts The original version of this guide mapped fixed Raff plans to statements such as "up to 50 active users." We removed that because SMB file-server sizing depends heavily on file size, concurrent I/O, antivirus scanning, application behavior, sync patterns, and storage capacity. Current Raff Windows VM examples are: | Plan | Compute | With Windows Server Standard SPLA | |---|---:|---:| | 2 vCPU / 4 GB / 80 GB | $22.99/mo | $37.99/mo | | 4 vCPU / 8 GB / 120 GB | $40.99/mo | $55.99/mo | | 8 vCPU / 16 GB / 180 GB | $76.99/mo | $91.99/mo | Windows Server Standard licensing through Raff SPLA is currently **$15 per instance per month**. Extra volumes are **$0.08/GB-month**, snapshots/backups are **$0.06/GB-month**, and VM traffic is **3 Gbps unmetered with no VM egress fees**. For a file server, size based on concurrent activity, storage requirements, backup strategy, and observed disk/network utilization rather than employee count alone. :::cta Deploy Windows Now Deploy a Windows Server 2025 VM for SMB over QUIC and other Windows workloads. ::: ## Validation scope The original end-to-end SMB over QUIC test was completed on Raff on **May 23, 2026** by Serdar Tekin using Windows Server 2025 Standard Evaluation, build 26100, win-acme 2.2.9.1701, HTTP-01 validation, UDP 443, and a separate Windows client. The article was revalidated on **September 10, 2026** against current Microsoft SMB over QUIC documentation, current Windows Server 2025 behavior, current certificate-tooling status, and Raff pricing/licensing source of truth. No new performance benchmark was run for this September refresh. ## What's next - [Configure Windows Firewall on a Windows VPS](/windows-server/configure-windows-firewall) - [Windows Server hardening checklist](/windows-server/windows-server-hardening-checklist) - [Windows Server licensing guide](/windows-server/windows-licensing) - [Cloud file server for small business](/windows-server/windows-vps-cloud-file-server) - [Raff Windows VM](/products/windows-vm) ## Sources - Microsoft Learn - SMB over QUIC: https://learn.microsoft.com/en-us/windows-server/storage/file-server/smb-over-quic - Microsoft Learn - SMB over QUIC client access control: https://learn.microsoft.com/en-us/windows-server/storage/file-server/smb-over-quic-client-access-control - Microsoft Learn - What's new in Windows Server 2025: https://learn.microsoft.com/en-us/windows-server/get-started/whats-new-windows-server-2025 - Microsoft Learn - New-SmbServerCertificateMapping: https://learn.microsoft.com/en-us/powershell/module/smbshare/new-smbservercertificatemapping - Microsoft Learn - Get-SmbMultichannelConnection: https://learn.microsoft.com/en-us/powershell/module/smbshare/get-smbmultichannelconnection - win-acme official documentation: https://www.win-acme.com/ - simple-acme official documentation: https://simple-acme.com/ - Let's Encrypt challenge types: https://letsencrypt.org/docs/challenge-types/ - Sources revalidated: 2026-09-10 --- ### Windows LAPS on Windows Server 2025: Active Directory Deployment Guide URL: https://rafftechnologies.com/windows-server/windows-laps-windows-server-2025 Description: Deploy Windows LAPS on Windows Server 2025 with Active Directory: schema, OU permissions, Group Policy, encrypted password backup, retrieval, rotation, decryption troubleshooting, and Server 2025 account-management options. ## In short **Windows LAPS** (Windows Local Administrator Password Solution) is built into Windows Server 2025. You do **not** install the legacy Microsoft LAPS MSI. Windows LAPS automatically rotates a managed local administrator password and backs it up to either Windows Server Active Directory or Microsoft Entra ID. For an Active Directory deployment, extend the LAPS schema once, delegate OU permissions, configure a computer-side LAPS policy with `BackupDirectory = 2`, process policy, verify Event ID 10018, and retrieve passwords only through authorized identities. Raff Technologies recommends enabling AD password encryption when your domain functional level and access model support it. ## What is Windows LAPS? Windows LAPS is Microsoft's current local administrator password-management feature for Windows. It regularly changes the password of a managed local administrator account and stores the password in a protected directory location where authorized administrators can retrieve it. Microsoft documents Windows LAPS for: - Windows Server 2025; - Windows Server 2022 with supported updates; - Windows Server 2019 with supported updates; - supported Windows 11 and Windows 10 releases. Windows LAPS can back passwords up to: - **Windows Server Active Directory** for domain-joined devices; - **Microsoft Entra ID** for Microsoft Entra-joined devices. A hybrid-joined device can use either destination, but Windows LAPS does not back the same managed password up to both directories at the same time. ## Windows LAPS vs legacy Microsoft LAPS The old product is commonly called **Microsoft LAPS** or **legacy LAPS**. Windows LAPS is the newer implementation built directly into supported Windows versions. | Area | Windows LAPS | Legacy Microsoft LAPS | |---|---|---| | Delivery | Built into supported Windows | Separate MSI installation | | Windows Server 2025 | Native | Legacy product is not the recommended path | | Active Directory password backup | Yes | Yes | | Microsoft Entra ID backup | Yes | No | | AD password encryption | Yes | No equivalent native encryption model | | Password history | Supported with encrypted AD passwords | No equivalent Windows LAPS history feature | | DSRM password management | Supported on domain controllers | Not equivalent | | Automatic account management | Supported on Windows Server 2025 and later | No | | PowerShell module | `LAPS` | `AdmPwd.PS` | Microsoft has deprecated the legacy Microsoft LAPS product on newer Windows versions. For Windows Server 2025, use **Windows LAPS**, not the old MSI. ### How to install Windows LAPS on Windows Server 2025 There is no separate Windows LAPS installer for Windows Server 2025. If you searched for **how to install LAPS 2025** or **Windows LAPS download**, the important point is that the supported Windows LAPS feature is already part of the operating system. Verify the native module instead of downloading `LAPS.x64.msi`: ```powershell Get-Module -ListAvailable LAPS Get-Command -Module LAPS ``` If the module is unexpectedly missing, verify the Windows Server image and patch state first. Do not solve that problem by installing a legacy LAPS package from an old tutorial. ## How Windows LAPS works with Active Directory A normal Active Directory deployment looks like this: ```text Managed Windows Server or workstation | | Windows LAPS policy v Local administrator password rotated | | encrypted before directory backup when configured v Active Directory computer object | +--> authorized password readers +--> authorized password reset operators ``` The managed computer performs the password rotation locally. It then writes the password information to its own Active Directory computer object, assuming the OU permissions and LAPS policy are configured correctly. Password access is controlled in two layers: 1. **Active Directory ACLs** decide who can query the LAPS password attributes. 2. **Password encryption** can further limit who can decrypt an encrypted password. For encrypted passwords in Active Directory, Microsoft requires a **Windows Server 2016 domain functional level or later**. ## Prerequisites Before deploying Windows LAPS, verify: - Active Directory is healthy. - DNS works correctly for domain members. - Managed devices are domain-joined. - The managed OS supports Windows LAPS. - Windows updates are current enough for Windows LAPS on Server 2019/2022 devices. - You have rights to extend the Active Directory schema. - You have a dedicated OU or a clear OU scope for managed devices. - You have decided who may retrieve local administrator passwords. - You have a test computer before applying policy broadly. - Your domain functional level is Windows Server 2016 or later if you want encrypted AD passwords. For production, do not test the first LAPS policy on every server in the domain. Start with one OU and one non-critical system. ## Step 1 — Verify the Windows LAPS PowerShell module On Windows Server 2025, open PowerShell as Administrator and run: ```powershell Get-Module -ListAvailable LAPS ``` Then list the available cmdlets: ```powershell Get-Command -Module LAPS ``` Important Windows LAPS cmdlets include: | Cmdlet | Purpose | |---|---| | `Update-LapsADSchema` | Extend the Active Directory schema for Windows LAPS | | `Set-LapsADComputerSelfPermission` | Let computers update their own LAPS attributes | | `Set-LapsADReadPasswordPermission` | Delegate password-read permission | | `Set-LapsADResetPasswordPermission` | Delegate password-expiration/reset permission | | `Find-LapsADExtendedRights` | Audit identities with LAPS extended rights | | `Get-LapsADPassword` | Retrieve a backed-up AD password | | `Set-LapsADPasswordExpirationTime` | Mark a stored password for rotation | | `Invoke-LapsPolicyProcessing` | Process the current LAPS policy immediately | | `Reset-LapsPassword` | Immediately rotate the managed local password on the local device | ## Step 2 — Update the Active Directory schema Before Windows LAPS can store password information in Active Directory, extend the schema. Run this once per forest: ```powershell Update-LapsADSchema -Verbose ``` Microsoft documents this as a **one-time forest operation**. You can run it on a supported domain controller or another supported server that has access to the LAPS PowerShell module and the required directory permissions. Do not repeatedly run schema updates as part of normal workstation or server onboarding. ## Step 3 — Put managed devices in a dedicated OU A dedicated OU makes LAPS policy and delegation easier to understand. Example: ```text contoso.com └── Servers └── LAPS-Managed-Servers ``` You can create one with PowerShell: ```powershell New-ADOrganizationalUnit ` -Name 'LAPS-Managed-Servers' ` -Path 'OU=Servers,DC=contoso,DC=com' ``` Move one test computer into the OU before applying policy broadly. For an MSP, separate OUs by customer or administrative boundary rather than giving one support group unrestricted LAPS access to unrelated client systems. ## Step 4 — Allow managed computers to update their own LAPS password Each managed computer needs permission to update its LAPS password information on its own Active Directory computer object. ```powershell Set-LapsADComputerSelfPermission ` -Identity 'OU=LAPS-Managed-Servers,OU=Servers,DC=contoso,DC=com' ``` Verify the returned object matches the OU you intended to modify. Do not grant this permission at the domain root unless you deliberately want that scope. ## Step 5 — Create a dedicated LAPS password-readers group Avoid making every help-desk administrator a Domain Admin just so they can retrieve a local password. ```powershell New-ADGroup ` -Name 'LAPS-Password-Readers' ` -SamAccountName 'LAPS-Password-Readers' ` -GroupScope Global ` -GroupCategory Security ` -Path 'OU=Groups,DC=contoso,DC=com' ``` Add only administrators who actually need local-password recovery access. Use a separate group for password-reset/expiration rights when duties should be separated. ## Step 6 — Delegate password-read permission ```powershell Set-LapsADReadPasswordPermission ` -Identity 'OU=LAPS-Managed-Servers,OU=Servers,DC=contoso,DC=com' ` -AllowedPrincipals 'CONTOSO\LAPS-Password-Readers' ``` Members of Domain Admins already have password-query permission by default. Important: **permission to read LAPS attributes is not automatically permission to decrypt an encrypted password**. If AD password encryption is enabled, the authorized decryptor is controlled separately by `ADPasswordEncryptionPrincipal`. ## Step 7 — Delegate password-reset permission separately ```powershell Set-LapsADResetPasswordPermission ` -Identity 'OU=LAPS-Managed-Servers,OU=Servers,DC=contoso,DC=com' ` -AllowedPrincipals 'CONTOSO\LAPS-Password-Resetters' ``` This permission allows an authorized operator to change the LAPS password-expiration time. It does not let the operator choose a specific replacement password. ## Step 8 — Audit who has LAPS rights before rollout Before storing privileged local passwords in Active Directory, inspect existing extended rights: ```powershell Find-LapsADExtendedRights ` -Identity 'OU=LAPS-Managed-Servers,OU=Servers,DC=contoso,DC=com' ``` Review the output for unexpected principals. This is particularly important in older AD environments where inherited delegation may have accumulated over time. ## Step 9 — Create and link a Windows LAPS Group Policy Open Group Policy Management: ```text gpmc.msc ``` Create a GPO such as: ```text Servers - Windows LAPS ``` Link it only to the managed computer OU first. Edit: ```text Computer Configuration → Policies → Administrative Templates → System → LAPS ``` Windows includes the Windows LAPS administrative template at: ```text %windir%\PolicyDefinitions\LAPS.admx ``` If your environment uses a Group Policy Central Store, Windows Update does not automatically copy the LAPS ADMX/ADML files into that store. Maintain the Central Store deliberately. ## Step 10 — Configure the minimum Windows LAPS policy For an Active Directory deployment, the minimum critical setting is the backup destination. ### Configure password backup directory Set the backup directory to Active Directory. At the policy-data level: ```text BackupDirectory = 2 ``` If `BackupDirectory` is not configured, the remaining LAPS settings do not create a usable password-backup workflow. ### Administrator account to manage If you leave `AdministratorAccountName` unconfigured, Windows LAPS manages the built-in local Administrator account using its well-known RID, even if that account has been renamed. If you configure a custom account in manual account-management mode, make sure the account already exists. ### Password settings Microsoft currently documents defaults including: | Setting | Default | |---|---:| | Password age | 30 days | | Password length | 14 characters | | Password complexity | 4 | | Post-authentication reset delay | 24 hours | | Post-authentication actions | Reset password and sign out | Windows Server 2025 also supports newer password-generation options. `PasswordComplexity = 5` uses a readability-focused character set, and Server 2025 can generate random passphrases using the newer passphrase complexity modes. These Server 2025 features do not require upgrading every domain controller to Server 2025; they depend on the managed device supporting the policy. ## Step 11 — Enable Active Directory password encryption For Windows Server Active Directory, Windows LAPS can encrypt the password before directory backup. The relevant policy is: ```text ADPasswordEncryptionEnabled ``` This requires **Windows Server 2016 domain functional level or later**. The decryptor is controlled by: ```text ADPasswordEncryptionPrincipal ``` If `ADPasswordEncryptionPrincipal` is not configured, Windows LAPS encrypts the password so that the managed device's **Domain Admins** group is the authorized decryptor. If you need a different operational boundary, configure a dedicated group, for example: ```text CONTOSO\LAPS-Password-Readers ``` Windows LAPS supports one encryption principal. If several teams need decryption rights, use a wrapper security group rather than attempting to configure several principals independently. ## Step 12 — Apply Group Policy to the test computer On the managed server: ```powershell gpupdate /force ``` Confirm the GPO is applied: ```powershell gpresult /r ``` For a detailed report: ```powershell gpresult /h C:\Temp\LAPS-GPResult.html ``` If the GPO is missing, fix OU scope, link state, security filtering, replication, or DNS before troubleshooting LAPS itself. ## Step 13 — Force Windows LAPS policy processing Windows LAPS processes active policy periodically. During a controlled test, trigger it immediately: ```powershell Invoke-LapsPolicyProcessing ``` The cmdlet itself is not the final proof of success. Verify the event log and directory state afterward. ## Step 14 — Verify Event IDs 10018 and 10020 For Active Directory backup, Microsoft documents: - **Event ID 10018** — Windows LAPS successfully updated Active Directory with the new password. - **Event ID 10020** — Windows LAPS successfully updated the managed local administrator account. For Microsoft Entra ID backup, the directory-update success event is 10029 instead of 10018. Query the operational log after policy processing and confirm the expected success event for your backup destination. ## Step 15 — Retrieve the local administrator password From an authorized administrative system: ```powershell Get-LapsADPassword ` -Identity 'SERVER01' ` -AsPlainText ``` When AD password encryption is enabled, useful output fields include: - `Source`; - `DecryptionStatus`; - `AuthorizedDecryptor`; - `PasswordUpdateTime`; - `ExpirationTimestamp`. A healthy encrypted-password result normally shows `Source : EncryptedPassword` and `DecryptionStatus : Success`. ### Fix “the account's password is encrypted but you do not have permission to decrypt it” This error is not the same as lacking permission to query the AD attributes. If `Get-LapsADPassword` can find the object but shows an unauthorized decryption status, check: 1. whether `ADPasswordEncryptionEnabled` is enabled; 2. which principal is configured in `ADPasswordEncryptionPrincipal`; 3. the `AuthorizedDecryptor` returned by `Get-LapsADPassword`; 4. whether the administrator is actually a member of that decryptor group; 5. whether group-membership changes have propagated and the administrator has a fresh logon token. Granting `Set-LapsADReadPasswordPermission` alone does **not** override encrypted-password decryption policy. The user needs both the directory read access and the ability to decrypt the password under the configured encryption principal. ### Security warning for `-AsPlainText` `-AsPlainText` intentionally displays the credential in clear text. Do not paste LAPS passwords into tickets, screenshots, chat, scripts, or ordinary log files. ## Step 16 — Test an early password rotation From Active Directory, an authorized operator can expire the stored password: ```powershell Set-LapsADPasswordExpirationTime -Identity 'SERVER01' ``` At the next policy-processing cycle, the managed computer rotates the password. To process immediately on the managed computer: ```powershell Invoke-LapsPolicyProcessing ``` For an exceptional immediate local rotation: ```powershell Reset-LapsPassword ``` After rotation, retrieve the password again and confirm the password and timestamps changed. ## Step 17 — Use Windows Server 2025 automatic account management deliberately Windows Server 2025 supports **Windows LAPS automatic account management**. This is different from the default manual mode. In manual mode: - leave `AdministratorAccountName` empty to manage the built-in Administrator account; - or point it at a custom local account that you provision separately. In automatic account-management mode, Windows LAPS can manage more of the local account lifecycle, including creation of a custom managed account, account naming, enabling/disabling the account, and optional randomized account naming. Automatic account management is supported on Windows Server 2025 and Windows 11 24H2 or later. Treat it as a separate design decision rather than enabling it automatically during the first LAPS rollout. ## Windows LAPS can manage domain-controller DSRM passwords Windows LAPS can also manage and back up **Directory Services Restore Mode (DSRM)** passwords on Active Directory domain controllers. That is a separate recovery scenario from member-server local Administrator management. Define who may retrieve the DSRM password and how domain-controller recovery is documented before enabling it. ## Windows LAPS security best practices ### Use a dedicated OU first Start with one test OU. Do not make a new LAPS policy domain-wide before validating it. ### Use dedicated reader and resetter groups Avoid assigning broad Domain Admin rights to help-desk staff simply to retrieve local passwords. ### Audit extended rights Use `Find-LapsADExtendedRights` before assuming only your new delegation groups can query LAPS attributes. ### Prefer encrypted AD passwords For a Windows Server 2016 or later DFL, enable AD password encryption and deliberately define the decryptor. ### Do not copy passwords into permanent records LAPS passwords are temporary privileged credentials. Treat clear-text retrieval as a sensitive administrative action. ### Keep the local account separate from domain administration Windows LAPS solves the reusable local-admin-password problem. It does not replace separate domain-admin accounts, MFA, Windows Firewall, patching, monitoring, or privileged-access controls. For broader host security, use the [Windows Server Hardening Checklist](/windows-server/windows-server-hardening-checklist). ## Recommended MSP rollout model For MSP-managed Windows environments, align LAPS administrative boundaries with the client boundary. ```text Client A Servers OU → Client A LAPS GPO → Client A LAPS Readers group → Client A LAPS Resetters group Client B Servers OU → Client B LAPS GPO → Client B LAPS Readers group → Client B LAPS Resetters group ``` Avoid one global support group that can retrieve every customer's local administrator password unless that broad access is deliberate and audited. For each client, document OU scope, GPO name, managed account mode, backup destination, read/reset groups, encryption principal, test device, retrieval test, and incident rotation procedure. ## Common Windows LAPS deployment mistakes ### Installing legacy Microsoft LAPS on Windows Server 2025 Windows LAPS is built into Windows Server 2025. Do not follow an old MSI-based tutorial for a new deployment. ### Updating the schema but forgetting OU permissions Schema extension does not automatically let managed computer objects write their LAPS information. Apply `Set-LapsADComputerSelfPermission` at the intended OU scope. ### Giving read permission but not decryption permission When AD password encryption is enabled, ACL read permission alone does not guarantee the administrator can decrypt the password. ### Setting AdministratorAccountName to the renamed built-in Administrator Leave the setting empty when managing the built-in Administrator account. Windows identifies it by RID. ### Configuring a custom account that does not exist in manual mode Manual account-management mode does not create the custom account for you. Windows Server 2025 automatic account management is the separate feature that can manage custom-account creation. ### Leaving BackupDirectory unconfigured Without the backup destination, the deployment does not produce the intended directory-backed password workflow. ### Assuming gpupdate proves LAPS worked `gpupdate /force` shows that Group Policy was processed. Verify Windows LAPS itself with Events 10018/10020 and the backed-up password state. ## Troubleshooting Windows LAPS Use this order when a password does not appear or cannot be retrieved: 1. Confirm the device is domain-joined. 2. Confirm the OS supports Windows LAPS. 3. Confirm the native `LAPS` PowerShell module is available. 4. Confirm `Update-LapsADSchema` completed for the forest. 5. Confirm the computer object is in the intended OU. 6. Confirm `Set-LapsADComputerSelfPermission` was applied to that OU. 7. Confirm the Windows LAPS GPO applies to the computer. 8. Confirm `BackupDirectory = 2` for the AD scenario. 9. Run `Invoke-LapsPolicyProcessing`. 10. Check the Windows LAPS operational log for 10018/10020 or error events. 11. Check AD, DNS, and replication health. 12. Run `Find-LapsADExtendedRights` to audit unexpected delegation. 13. Retrieve with `Get-LapsADPassword` from an authorized identity. 14. If `DecryptionStatus` is unauthorized, inspect `ADPasswordEncryptionPrincipal` and `AuthorizedDecryptor` rather than simply adding more AD read permissions. Do not weaken permissions or disable encryption as the first troubleshooting step. ## Where Raff fits Raff Windows VMs can provide Windows Server infrastructure for Active Directory domain controllers, member servers, RDS environments, SQL Server, and other workloads where Windows LAPS is useful. Windows LAPS itself is an operating-system and identity-management control. You still design the Active Directory topology, private networking, OU structure, Group Policy, delegation, domain-controller redundancy, backups, privileged access, monitoring, and recovery. For production Active Directory, avoid a single domain controller and avoid exposing AD services directly to the public internet. :::cta Deploy Windows Now Deploy a Windows VM for an Active Directory or member-server environment, then apply Windows LAPS, Group Policy, hardening, backups, and private-network controls appropriate to the workload. ::: ## Frequently asked questions ### Is Windows LAPS built into Windows Server 2025? Yes. Windows LAPS is native to Windows Server 2025. You do not need the legacy Microsoft LAPS MSI for a new Server 2025 deployment. ### What is the difference between Windows LAPS and Microsoft LAPS? “Microsoft LAPS” often refers to the older standalone product. Windows LAPS is the Windows-native implementation with Active Directory and Microsoft Entra ID backup, AD password encryption, DSRM support, and newer account-management features. ### Does Windows LAPS require Active Directory? No. Windows LAPS can back passwords up to Windows Server Active Directory or Microsoft Entra ID depending on join state and policy. This guide covers Active Directory. ### Does Windows LAPS create the local administrator account? In default manual mode, no. Windows Server 2025 also supports automatic account management, which can create and manage a custom local account when configured. ### What domain functional level is required for encrypted LAPS passwords? Windows Server 2016 domain functional level or later is required for Windows LAPS password encryption in Active Directory. ### How do I retrieve a Windows LAPS password from Active Directory? Use an authorized identity: ```powershell Get-LapsADPassword -Identity 'SERVER01' -AsPlainText ``` ### How do I force Windows LAPS to process policy now? Run: ```powershell Invoke-LapsPolicyProcessing ``` For AD backup, Event ID 10018 confirms the new password was successfully written to Active Directory. ### How do I immediately rotate the managed local password? Run `Reset-LapsPassword` locally for an exceptional immediate rotation, or expire the AD password with `Set-LapsADPasswordExpirationTime` and then process policy. ## Validation scope This article was revalidated on **September 10, 2026** against Microsoft's current Windows LAPS overview, Active Directory deployment guidance, policy-setting reference, architecture documentation, account-management modes, password/passphrase guidance, event-log reference, and LAPS PowerShell behavior. No fresh Raff lab test was claimed for this refresh. ## What's next - [Promote a Windows VPS to an Active Directory Domain Controller](/windows-server/active-directory-domain-controller) - [Active Directory Group Policy Setup from Scratch](/windows-server/ad-group-policy-setup) - [Windows Server Hardening Checklist](/windows-server/windows-server-hardening-checklist) - [Configure Windows Firewall on a Windows VPS](/windows-server/configure-windows-firewall) - [Raff Windows VM](/products/windows-vm) ## Sources - Microsoft Learn — Windows LAPS overview: https://learn.microsoft.com/en-us/windows-server/identity/laps/laps-overview - Microsoft Learn — Windows LAPS with Windows Server Active Directory: https://learn.microsoft.com/en-us/windows-server/identity/laps/laps-scenarios-windows-server-active-directory - Microsoft Learn — Windows LAPS architecture: https://learn.microsoft.com/en-us/windows-server/identity/laps/laps-concepts-overview - Microsoft Learn — Configure Windows LAPS policy settings: https://learn.microsoft.com/en-us/windows-server/identity/laps/laps-management-policy-settings - Microsoft Learn — Windows LAPS account management modes: https://learn.microsoft.com/en-us/windows-server/identity/laps/laps-concepts-account-management-modes - Microsoft Learn — Windows LAPS passwords and passphrases: https://learn.microsoft.com/en-us/windows-server/identity/laps/laps-concepts-passwords-passphrases - Microsoft Learn — Windows LAPS event logs: https://learn.microsoft.com/en-us/windows-server/identity/laps/laps-management-event-log - Microsoft Learn PowerShell — LAPS module: https://learn.microsoft.com/en-us/powershell/module/laps/?view=windowsserver2025-ps - Sources revalidated: 2026-09-10 --- ### How to Promote Windows Server 2025 to an Active Directory Domain Controller URL: https://rafftechnologies.com/windows-server/active-directory-domain-controller Description: Promote Windows Server 2025 to an Active Directory domain controller with AD DS, DNS, Install-ADDSForest, DSRM, functional-level planning, validation, and production recovery checks. ## In short To promote **Windows Server 2025 to an Active Directory domain controller**, start with a fresh dedicated server, set the final hostname, use stable private addressing, and make sure DNS is planned for Active Directory rather than public resolvers. Install the AD DS role, create the new forest with `Install-ADDSForest`, set and protect the DSRM password, reboot, then verify AD DS, DNS, SYSVOL, NETLOGON, and `dcdiag` before joining production systems. For a new production forest, use a DNS namespace based on a domain you control, such as `ad.example.com`, rather than creating a new `.local` namespace. For production, plan at least two domain controllers, private connectivity, system-state backups, and tested recovery. Raff Technologies originally tested the first-DC workflow on Windows Server 2025 on June 9, 2026. This September refresh preserves that lab evidence while updating the production domain-naming, functional-level, DNS, backup, and recovery guidance. ## Windows Server 2025 domain controller setup at a glance | Situation | Recommendation | |---|---| | New lab or isolated test domain | One dedicated Windows Server VM is enough to learn the workflow | | New production forest | Use a registered DNS namespace or subdomain you control | | All domain controllers will run Windows Server 2025 | Windows Server 2025 functional level is available | | You need Windows Server 2016, 2019, or 2022 DCs to coexist | Plan around Windows Server 2016 functional level | | Existing production domain | Add an additional DC only after DNS, time, connectivity, and replication checks | | Server already runs IIS, SQL Server, RDS, ERP, or business apps | Do not promote it; use a dedicated VM | | Production AD | Run at least two domain controllers | | Remote/cloud deployment | Keep AD traffic on private networking or VPN; do not expose AD ports broadly | | Recovery planning | Use system-state backups and tested AD recovery procedures | The clean first-domain-controller path is: ```text Fresh Windows Server 2025 → rename server → confirm stable IP + AD DNS design → install AD DS → Install-ADDSForest → set DSRM password → reboot → verify AD DS + DNS + SYSVOL + NETLOGON → create test OU/user → run health checks ``` ## This guide covers the first domain controller in a new forest You will build this: ```text Dedicated Windows Server 2025 VM → Hostname: DC01 → AD DS role installed → New forest created → DNS installed during promotion → Server rebooted as domain controller → AD DS, DNS, Netlogon, SYSVOL, OU, and user verified ``` This guide does not fully cover production multi-DC replication topology, Active Directory Sites and Services design, RODC design, hybrid identity, or migration from an existing forest. If you already have a domain and need a second DC, use the additional-domain-controller path later in this article and then review [Active Directory replication topology for 2-DC setups](/windows-server/ad-replication-topology). ## What we tested on Raff The original lab used a fresh Raff Windows VM running Windows Server 2025 Datacenter Evaluation. ![PowerShell output showing the Raff Windows VPS test environment before Active Directory Domain Services promotion.](https://raff-images.s3.raffusercloud.com/01_domain_controller_test_environment_8935adac6f.png) | Item | Value | |---|---| | Provider | Raff Technologies | | OS | Windows Server 2025 Datacenter Evaluation | | Server role | First domain controller in a new forest | | Hostname | `DC01` | | Test domain | `contoso.local` | | Forest NetBIOS name | `CONTOSO` | | AD role | Active Directory Domain Services | | DNS | Installed during promotion | | Original test date | 2026-06-09 | | Tester | Serdar Tekin | The lab verified the server baseline, hostname and IP/DNS pre-flight, AD DS role installation, local Administrator password requirement, `Install-ADDSForest` promotion, AD DS services after reboot, domain-controller verification, DNS zones, and the creation of a first OU and user. The test used `contoso.local` because it was an isolated lab. **Do not copy that namespace into a new production forest.** Current Microsoft design guidance recommends using registered DNS names and does not recommend unregistered suffixes such as `.local`. ## Use a dedicated VM for a domain controller Do not promote a general-purpose Windows server to a domain controller if it already runs production workloads such as: - IIS or public web applications; - SQL Server; - RDS Session Host; - ERP or accounting software; - user file sharing; - business applications; - third-party tools with broad privileges. A domain controller is part of the identity and authentication foundation. Separating application workloads from AD DS reduces the security blast radius and makes patching, troubleshooting, backup, and recovery easier. For sizing, avoid treating one lab specification as a universal production requirement. Directory size, DNS activity, authentication volume, Group Policy, replication, monitoring, backup activity, and failover capacity all matter. See [Windows Server sizing by workload](/windows-server/windows-server-sizing-by-workload) for a broader sizing process. ## Choose the Active Directory DNS name before promotion The DNS namespace is difficult to change later, so choose it deliberately before creating the forest. For a new production forest, prefer a namespace based on a domain your organization controls, for example: ```text ad.example.com corp.example.com ds.example.com ``` Avoid new single-label domains such as: ```text company contoso ``` Also avoid copying the lab-only `.local` pattern into a new production design. Microsoft recommends registered DNS names for Active Directory namespaces because registered names are globally unique. The remainder of the production-oriented examples in this guide use: ```text ad.example.com ``` The screenshots continue to show the original `contoso.local` test environment so the historical lab evidence remains unchanged. ## Plan the Windows Server 2025 functional level before promotion Windows Server 2025 introduces a **Windows Server 2025 domain and forest functional level**. Functional levels determine which domain-controller operating-system versions can participate and which AD DS features are available. The compatibility decision is important: | Desired DC mix | Functional-level planning | |---|---| | Only Windows Server 2025 DCs | Windows Server 2025 functional level can be used | | Windows Server 2025 plus Server 2016/2019/2022 DCs | Use Windows Server 2016 functional level | | Existing domain receiving a Server 2025 DC | Existing domain must already be at least Windows Server 2016 functional level | Do not raise a production forest to Windows Server 2025 merely because the first new DC runs Server 2025. Once the environment needs older supported DC versions, the 2025 functional level is not compatible with them. For a clean new Server 2025-only forest, the simplest promotion command can let the current AD DS deployment workflow select supported defaults. If your design requires explicit functional levels, choose them deliberately after confirming the planned DC operating-system mix. ## What you'll need Before starting, prepare: - a fresh dedicated Windows Server 2025 or Windows Server 2022 VM; - local Administrator access; - a final hostname such as `DC01`; - stable private IP addressing where possible; - an Active Directory DNS namespace chosen before promotion; - a strong local Administrator password; - a strong DSRM password stored outside the server; - private networking or VPN for AD traffic; - a second-DC plan for production; - an AD-aware backup and recovery plan. If you are building this on Raff, deploy the Windows VM first and keep domain services on a private network rather than exposing AD ports publicly. :::cta Deploy Windows Now Deploy a Windows VM for Active Directory, then keep AD DS, DNS, backups, and domain traffic isolated from public application workloads. ::: ## Step 1 — Confirm the Windows Server baseline Run PowerShell as Administrator: ```powershell Get-ComputerInfo | Select-Object ` WindowsProductName, WindowsVersion, OsBuildNumber, ` CsNumberOfLogicalProcessors, CsTotalPhysicalMemory hostname ``` ![PowerShell output showing the Raff Windows VPS test environment before Active Directory Domain Services promotion.](https://raff-images.s3.raffusercloud.com/01_domain_controller_test_environment_8935adac6f.png) Record the Windows version, current hostname, CPU, memory, network configuration, and any pending reboot before making the server a DC. Do not promote a server until its final hostname is set. ## Step 2 — Rename the server and verify IP/DNS Rename the server before promotion: ```powershell Rename-Computer -NewName "DC01" -Restart ``` After reboot, reconnect and verify the hostname and network configuration. ![PowerShell output showing hostname, IP configuration, DNS settings, and reboot status before domain controller promotion.](https://raff-images.s3.raffusercloud.com/02_static_ip_and_hostname_7b429bb2b8.png) ```powershell $adapter = (Get-NetAdapter | Where-Object Status -eq 'Up').Name hostname Get-NetIPAddress -InterfaceAlias $adapter -AddressFamily IPv4 | Select-Object InterfaceAlias, IPAddress, PrefixLength, AddressState Get-DnsClientServerAddress -InterfaceAlias $adapter -AddressFamily IPv4 ``` For a first DC in a new forest, the pre-promotion DNS state depends on the surrounding network. After AD-integrated DNS is installed, domain controllers and domain members must use DNS servers that can resolve the AD DNS zone. Do **not** configure DCs or domain members to use public resolvers such as `8.8.8.8` or `1.1.1.1` as their AD DNS servers. Configure external name resolution through DNS forwarders instead. ## Step 3 — Install Active Directory Domain Services Install the AD DS role and management tools: ```powershell Install-WindowsFeature -Name AD-Domain-Services -IncludeManagementTools ``` Verify it: ```powershell Get-WindowsFeature -Name AD-Domain-Services ``` ![PowerShell output showing Active Directory Domain Services role installed successfully on Windows Server.](https://raff-images.s3.raffusercloud.com/03_ad_ds_role_installed_1c54b4ce97.png) Installing the role does **not** make the server a domain controller. Promotion happens with the AD DS deployment cmdlets in the next step. ## Step 4 — Verify the local Administrator account is protected Before a new-forest promotion, verify the local Administrator account requires a password: ```powershell net user Administrator ``` Look for: ```text Password required Yes ``` ![PowerShell output showing the local Administrator account with Password required set to Yes before AD DS promotion.](https://raff-images.s3.raffusercloud.com/05_local_administrator_password_required_f39de481bf.png) If needed: ```powershell net user Administrator /passwordreq:yes ``` Then set a unique strong password through your normal privileged-access process. Avoid putting production credentials directly into shell history, scripts, tickets, or documentation. ## Step 5 — Promote Windows Server 2025 to the first domain controller For a brand-new forest, use `Install-ADDSForest`. A production-style example is: ```powershell Install-ADDSForest ` -DomainName "ad.example.com" ` -DomainNetbiosName "EXAMPLE" ` -InstallDns ` -Force ``` PowerShell securely prompts for the **SafeModeAdministratorPassword**, also called the DSRM password. Microsoft's current AD DS deployment guidance installs DNS by default for `Install-ADDSForest`; keeping `-InstallDns` here makes the intended result explicit. ![PowerShell output showing Install-ADDSForest running to promote the Windows VPS to the first domain controller of the contoso.local forest.](https://raff-images.s3.raffusercloud.com/04_install_addsforest_command_afd9bf25c3.png) The screenshot shows the original lab command and `contoso.local` test namespace. For a new production forest, use the registered namespace planned earlier. ### Explicit functional levels are optional but must match your DC plan If you deliberately specify `-DomainMode` or `-ForestMode`, do not blindly copy an old `WinThreshold` example. Windows Server 2025 has its own functional level, while Windows Server 2016 remains the newest functional level that supports Server 2016, 2019, and 2022 DCs alongside Server 2025. After promotion, verify the actual levels: ```powershell Get-ADDomain | Select-Object DNSRoot, DomainMode Get-ADForest | Select-Object RootDomain, ForestMode ``` Store the DSRM password securely. It is a recovery credential and should not depend on access to the failed DC itself. ## Step 6 — Sign in after the reboot After promotion and reboot, sign in using the new domain, for example: ```text EXAMPLE\Administrator ``` or: ```text Administrator@ad.example.com ``` The first DC in a new forest holds the initial domain Administrator context and the FSMO roles for that new forest/domain. ## Step 7 — Verify AD DS, DNS, and Netlogon services Run: ```powershell Get-Service -Name "NTDS","ADWS","DNS","Netlogon" | Format-Table Name, Status ``` Expected state is `Running` for the services required by this deployment. ![PowerShell output showing NTDS, ADWS, DNS, and Netlogon services running after domain controller promotion.](https://raff-images.s3.raffusercloud.com/05_post_promotion_services_running_2877f0712b.png) Service state is only one check. Continue with directory, DNS, SYSVOL, and diagnostic verification. ## Step 8 — Verify the domain controller and functional levels ```powershell Get-ADDomain | Select-Object ` DNSRoot, NetBIOSName, DomainMode, ` PDCEmulator, RIDMaster, InfrastructureMaster Get-ADForest | Select-Object RootDomain, ForestMode, SchemaMaster, DomainNamingMaster Get-ADDomainController -Filter * | Select-Object HostName, Domain, Forest, Site, IsGlobalCatalog ``` ![PowerShell output showing contoso.local domain details and the promoted Windows VPS listed as a domain controller.](https://raff-images.s3.raffusercloud.com/06_domain_controller_verification_2782798b19.png) For the first DC, confirm: - the expected DNS domain and NetBIOS name; - the intended domain and forest functional levels; - `DC01` appears as a domain controller; - the Global Catalog is available; - FSMO role holders are known and documented. ## Step 9 — Verify Active Directory DNS Check the zones: ```powershell Get-DnsServerZone | Format-Table ZoneName, ZoneType, IsDsIntegrated, IsReverseLookupZone ``` For `ad.example.com`, expect an AD-integrated domain zone plus the forest-wide `_msdcs` zone. Then check domain-controller locator records: ```powershell Resolve-DnsName -Type SRV _ldap._tcp.dc._msdcs.ad.example.com Resolve-DnsName -Type SRV _kerberos._tcp.ad.example.com ``` If these records cannot be resolved from the DNS server used by domain members, fix DNS before joining clients. ## Step 10 — Create a test OU and user Create an Organizational Unit: ```powershell New-ADOrganizationalUnit ` -Name "Accounting" ` -Path "DC=ad,DC=example,DC=com" ``` Create a test user without embedding the password in the command history: ```powershell $securePassword = Read-Host "Initial password" -AsSecureString New-ADUser -Name "Jane Doe" ` -GivenName "Jane" ` -Surname "Doe" ` -SamAccountName "jane.doe" ` -UserPrincipalName "jane.doe@ad.example.com" ` -Path "OU=Accounting,DC=ad,DC=example,DC=com" ` -AccountPassword $securePassword ` -Enabled $true ``` Verify: ```powershell Get-ADOrganizationalUnit -Filter "Name -eq 'Accounting'" | Select-Object Name, DistinguishedName Get-ADUser -Identity "jane.doe" | Select-Object Name, SamAccountName, UserPrincipalName, Enabled ``` ![PowerShell output showing the Accounting organizational unit and Jane Doe domain user created in Active Directory.](https://raff-images.s3.raffusercloud.com/07_dns_ou_and_user_created_9510a204ac.png) The screenshot preserves the original `contoso.local` lab. The production examples above use `ad.example.com`. ## Step 11 — Verify SYSVOL and NETLOGON Run: ```powershell net share ``` Confirm these shares exist: ```text SYSVOL NETLOGON ``` SYSVOL carries Group Policy and logon-script data. A new DC that does not expose the expected shares is not ready for normal domain use. ## Step 12 — Run DCDIAG and DNS diagnostics Run: ```powershell dcdiag ``` For a DNS-focused check: ```powershell dcdiag /test:dns /v ``` Also confirm DC discovery: ```powershell nltest /dclist:ad.example.com nltest /dsgetsite ``` Investigate repeated DNS, advertising, service, SYSVOL, or connectivity failures before adding production members. ## Add a Windows Server 2025 DC to an existing domain If a domain already exists, do **not** use `Install-ADDSForest`. Use `Install-ADDSDomainController`. Before promotion, confirm: - the existing domain functional level is at least Windows Server 2016 for a Server 2025 DC; - the server uses existing AD DNS; - network and private connectivity to existing DCs work; - time synchronization is healthy; - replication is healthy; - credentials have the required privileges; - the new hostname is unique; - the server is not hosting unrelated production roles. Example: ```powershell $cred = Get-Credential Install-ADDSDomainController ` -DomainName "ad.example.com" ` -InstallDns ` -Credential $cred ` -Force ``` After reboot, verify replication with: ```powershell repadmin /replsummary repadmin /showrepl ``` Then review [Active Directory replication topology for 2-DC setups](/windows-server/ad-replication-topology). ## Domain controllers must use Active Directory-aware DNS Active Directory depends on DNS for locating LDAP, Kerberos, Global Catalog, and other domain services. For a multi-DC environment, every DC and domain member should use DNS servers authoritative for the AD zone. Exact preferred/alternate ordering can vary by topology and promotion stage; the invariant is that AD clients must not bypass AD DNS by pointing directly at public recursive resolvers. For internet lookups, configure forwarders on the DNS servers rather than setting public resolvers on the domain member's NIC. When troubleshooting authentication, replication, Group Policy, or domain joins, check DNS before assuming AD DS itself is broken. ## Do not expose Active Directory ports to the public internet AD DS uses multiple protocols, including DNS, Kerberos, LDAP, SMB, RPC Endpoint Mapper, Global Catalog, and dynamic RPC ports. Modern Windows commonly uses the dynamic RPC range: ```text 49152-65535 ``` That wide service surface is one reason domain traffic belongs on trusted private networking, VPN, or another controlled internal path. Do not make a cloud DC reachable by opening LDAP, Kerberos, SMB, DNS, and RPC broadly to the internet. ## Production Active Directory should have at least two domain controllers A one-DC setup is appropriate for a lab and can be acceptable for temporary testing. It is a single failure point for production identity and AD-integrated DNS. A small production topology is usually: ```text Private network ├── DC01 │ ├── AD DS │ ├── DNS │ ├── Global Catalog │ └── FSMO roles └── DC02 ├── AD DS ├── DNS ├── Global Catalog └── replication partner ``` If both DCs are in one low-latency private network, a single AD site is usually sufficient. If they are in different locations or network subnets, plan Sites, Subnets, and Site Links instead of creating topology by guesswork. ## System-state backup is the recovery foundation for a domain controller Replication is not a backup. Deleting an OU, breaking Group Policy, damaging DNS data, or making an administrative mistake can replicate to other DCs. Microsoft's domain-controller recovery guidance requires regular **system-state backups** for supported disaster-recovery scenarios. System state contains Active Directory data and logs, the registry, SYSVOL, and other operating-system state required for AD recovery. Plan: - regular system-state backups using an AD-compatible backup workflow; - backup copies protected from the live DC; - documented DSRM access; - restore testing; - Active Directory Recycle Bin when appropriate; - recovery procedures for a failed DC and FSMO roles; - VM-level recovery points as an additional infrastructure control, not the only AD backup. Modern virtualization includes VM-Generation ID safeguards that help AD DS detect supported snapshot restores and avoid older USN-reuse problems. That does **not** turn arbitrary VM snapshots into an Active Directory backup strategy. Use system-state backup and documented AD recovery procedures. ## Active Directory Recycle Bin is useful but not a backup Active Directory Recycle Bin can simplify recovery of accidentally deleted AD objects, but it is not enabled by default and enabling it is a forest-wide design decision. It does not replace system-state backup, multi-DC redundancy, or tested disaster recovery. ## Common domain-controller setup mistakes ### Creating a new production `.local` forest The original Raff lab used `contoso.local`, but Microsoft does not recommend unregistered suffixes such as `.local` for new Active Directory namespaces. Use a registered DNS namespace or subdomain you control. ### Hardcoding an old functional level Windows Server 2025 introduces its own domain and forest functional level. Choose the highest level your planned DC operating-system mix supports; do not blindly reuse an old `WinThreshold` command from a tutorial. ### Promoting before renaming the server Set the final hostname before promotion. The DC name becomes part of the directory and DNS design. ### Pointing domain members at public DNS Domain members need AD-aware DNS to find domain services. Use DNS forwarders for external resolution instead of bypassing AD DNS. ### Mixing IIS, SQL Server, RDS, or ERP with AD DS Keep domain controllers focused on identity infrastructure. Role separation improves security and recovery. ### Losing the DSRM password Store DSRM credentials in a secure system accessible during an AD outage. ### Opening AD ports publicly Use private networking or VPN. Active Directory is not a single-port service. ### Treating a second DC as a backup Replication improves availability, but it also replicates unwanted changes. You still need recoverable backups. ### Treating a VM snapshot as the only DC backup Virtualization safeguards help with safe restore behavior, but Microsoft still requires an AD-aware recovery plan and regular system-state backup. ## What Raff recommends for Active Directory on Windows VMs For a small production environment: 1. Use dedicated Windows VMs for the domain controllers. 2. Choose a registered production DNS namespace before promotion. 3. Set the final hostname and stable private addressing first. 4. Keep DC and domain-member DNS pointed at AD DNS servers. 5. Select functional levels around the DC versions the environment must support. 6. Keep AD traffic on private networking or VPN. 7. Run at least two DCs for production. 8. Verify AD DS, DNS, SYSVOL, NETLOGON, `dcdiag`, and replication before relying on the domain. 9. Use Windows LAPS for managed local-administrator passwords on member systems where appropriate. 10. Use focused Group Policy rather than unmanaged per-server configuration. 11. Maintain system-state backups and test recovery. 12. Keep application, SQL Server, and RDS workloads off domain controllers. For the next steps, use the [2-DC replication topology guide](/windows-server/ad-replication-topology), [Group Policy setup guide](/windows-server/ad-group-policy-setup), and [Windows LAPS deployment guide](/windows-server/windows-laps-windows-server-2025). ## Tested on Raff > **Original lab:** Raff Windows VM, Windows Server 2025 Datacenter Evaluation, first domain controller of the `contoso.local` test forest, June 9, 2026, by Serdar Tekin. The lab verified AD DS installation, local Administrator password requirements, `Install-ADDSForest`, reboot, AD DS/DNS/Netlogon/ADWS services, domain-controller status, DNS zones, and creation of an Accounting OU and Jane Doe test user. > **Validation scope — September 10, 2026:** Production domain naming, Windows Server 2025 functional-level interoperability, `Install-ADDSForest` behavior, DNS design, virtualized-DC recovery, and system-state backup guidance were revalidated against current Microsoft documentation. No new Raff lab test is claimed for this refresh. ## What's next - [Connect to a Windows VPS via RDP](/windows-server/connect-to-windows-vps-via-rdp) - [Active Directory Replication Topology for 2-DC Setups](/windows-server/ad-replication-topology) - [Active Directory Group Policy Setup](/windows-server/ad-group-policy-setup) - [Windows LAPS on Windows Server 2025](/windows-server/windows-laps-windows-server-2025) - [Windows Server Hardening Checklist](/windows-server/windows-server-hardening-checklist) - [Windows Server Sizing by Workload](/windows-server/windows-server-sizing-by-workload) - [Raff Windows VM](/products/windows-vm) ## Sources - Microsoft Learn — Active Directory Domain Services overview: https://learn.microsoft.com/en-us/windows-server/identity/ad-ds/get-started/virtual-dc/active-directory-domain-services-overview - Microsoft Learn — Install Active Directory Domain Services: https://learn.microsoft.com/en-us/windows-server/identity/ad-ds/deploy/install-active-directory-domain-services--level-100- - Microsoft Learn — Active Directory Domain Services functional levels: https://learn.microsoft.com/en-us/windows-server/identity/ad-ds/active-directory-functional-levels - Microsoft Learn — Raise domain and forest functional levels: https://learn.microsoft.com/en-us/windows-server/identity/ad-ds/plan/raise-domain-forest-functional-levels - Microsoft Learn — Select the forest root domain: https://learn.microsoft.com/en-us/windows-server/identity/ad-ds/plan/selecting-the-forest-root-domain - Microsoft Learn — Restore a virtualized domain controller: https://learn.microsoft.com/en-us/windows-server/identity/ad-ds/manage/virtual-dc/restore-virtualized-domain-controller - Microsoft Learn — Virtualized domain controller architecture: https://learn.microsoft.com/en-us/windows-server/identity/ad-ds/get-started/virtual-dc/virtualized-domain-controller-architecture - Microsoft Learn — Windows service and network port requirements: https://learn.microsoft.com/en-us/troubleshoot/windows-server/networking/service-overview-and-network-port-requirements - Microsoft Learn — Active Directory replication concepts: https://learn.microsoft.com/en-us/windows-server/identity/ad-ds/get-started/replication/active-directory-replication-concepts - Sources revalidated: 2026-09-10 --- ### Configure Windows Firewall on a Windows VPS URL: https://rafftechnologies.com/windows-server/configure-windows-firewall Description: Configure Windows Firewall safely on a Windows Server VPS: check profiles, audit inbound rules, restrict RDP, create narrow port rules, enable firewall logging, test connectivity, and avoid remote lockouts. ## In short Configure Windows Firewall on a production VPS by keeping every firewall profile enabled, leaving inbound traffic blocked by default, and creating only the exceptions your workload actually needs. Scope rules by profile, protocol, application or port, and trusted source address where possible. Before changing RDP rules remotely, confirm a recovery path. Then test the service, review effective rules, enable useful firewall logging, document the change, and remove temporary rules. ## The safest firewall model is default-deny inbound Windows Firewall is a host-based firewall built into Windows Server. Microsoft’s current guidance keeps the firewall enabled and uses a **default block posture for inbound connections**, with explicit allow rules for required traffic. | Task | Recommended action | |---|---| | Check firewall state | Review Domain, Private, and Public profiles | | Publish a website | Allow only required HTTP/HTTPS traffic | | Administer with RDP | Restrict exposure to trusted sources where practical | | Run SQL Server | Prefer private/trusted access instead of public TCP 1433 | | Run SMB | Keep TCP 445 off the public internet | | Open an application port | Scope protocol, local port, profile, and remote address | | Troubleshoot connectivity | Confirm the application is listening before changing the firewall | | Audit a production server | Review inbound allow rules and firewall logs | For most Windows Server deployments, Microsoft recommends allowing outbound traffic by default because switching to default-deny outbound requires a complete inventory of every application and service that needs network access. Treat outbound blocking as an advanced policy, not a routine VPS hardening shortcut. ## What we tested on Raff The original lab for this guide was performed on a Raff Windows Server 2025 Datacenter Evaluation VM. ![PowerShell output showing Remote Desktop firewall rules with display name, enabled state, direction, action, and profile.](https://raff-images.s3.raffusercloud.com/03_rdp_firewall_rules_496503cd53.png) Test environment: | Item | Value | |---|---| | Environment | Raff Windows VM | | OS | Windows Server 2025 Datacenter Evaluation | | Build | 26100 | | CPU | 4 vCPU | | RAM | Approximately 8 GB | | Test date | 2026-05-24 | | Engineer | Aybars Altınyay | The lab verified: - Windows Firewall profile status; - existing Remote Desktop rules; - creation of a temporary inbound TCP rule; - verification of that rule; - cleanup of the temporary rule. The temporary test used TCP `54321`. It did not expose a real production application. This September 2026 refresh preserves those screenshots and tested commands while revalidating Microsoft guidance for production scoping, rule precedence, logging, centrally managed firewall policy, and Windows remote-management rule groups. ## Step 1 — Check every Windows Firewall profile Run PowerShell as Administrator: ```powershell Get-NetFirewallProfile | Select-Object Name, Enabled, DefaultInboundAction, DefaultOutboundAction, AllowLocalFirewallRules ``` You should see the three main profiles: - Domain; - Private; - Public. ![PowerShell output showing Windows Server 2025 test environment and enabled Windows Firewall profiles on a Raff VPS.](https://raff-images.s3.raffusercloud.com/01_firewall_test_environment_and_profiles_f2234afc5c.png) For a production server, keep the firewall enabled on all profiles. Microsoft’s Windows Server 2025 security baseline uses an enabled firewall with a default-deny inbound stance across Domain, Private, and Public profiles. A value such as `NotConfigured` in a policy field does **not** mean the firewall is disabled. Always verify the `Enabled` state and remember that effective policy can combine local settings with Group Policy or other centralized management. ### Verify which network profile is active Before creating a rule that is limited to one profile, check the current network category: ```powershell Get-NetConnectionProfile | Select-Object InterfaceAlias, NetworkCategory, IPv4Connectivity, IPv6Connectivity ``` A firewall rule should normally be enabled only on the profiles where the workload needs it. Avoid using `-Profile Any` in production simply because it is convenient. ## Step 2 — Review existing RDP firewall rules before changing them Remote Desktop is one of the most sensitive inbound rule groups on a Windows VPS. Run: ```powershell Get-NetFirewallRule -DisplayGroup "Remote Desktop" | Select-Object DisplayName, Enabled, Direction, Action, Profile | Format-Table -AutoSize ``` ![PowerShell output showing existing Remote Desktop firewall rules on a Windows Server VPS.](https://raff-images.s3.raffusercloud.com/02_rdp_firewall_rules_857a850de9.png) To inspect the source-address scope attached to those rules: ```powershell Get-NetFirewallRule -DisplayGroup "Remote Desktop" | Get-NetFirewallAddressFilter | Select-Object Name, RemoteAddress ``` Windows Server normally uses TCP and UDP `3389` for direct RDP. Microsoft warns that exposing Remote Desktop directly to the internet increases risk and recommends a VPN when practical; full RDS environments can also use RD Gateway over HTTPS. Before changing RDP firewall rules on a remote server: 1. Confirm your current public source IP. 2. Confirm you have a dashboard/console/recovery path. 3. Record the existing rules. 4. Make one change at a time. 5. Test a second connection before closing the working session. For general RDP setup, see [How to Connect to a Windows VPS via RDP](/windows-server/connect-to-windows-vps-via-rdp). For multi-user environments, see [Multi-User RDP: 2 Admin Sessions vs RDS Session Host](/windows-server/multi-user-rdp-vs-rds). ## Step 3 — Understand Windows Firewall rule precedence Firewall rules are not evaluated by a simple top-to-bottom list. Microsoft documents these important behaviors: 1. An explicit allow rule can permit traffic that the default inbound block would otherwise deny. 2. An explicit **block** rule takes precedence over a conflicting allow rule. 3. More-specific rules generally take precedence over less-specific rules, except where an explicit block rule conflicts. 4. Windows Firewall does not provide administrator-assigned weighted rule ordering. This matters when troubleshooting. Creating a new allow rule does not necessarily solve the problem if another explicit block rule matches the same traffic. Check matching block rules as well as allow rules: ```powershell Get-NetFirewallRule -Enabled True -Direction Inbound -Action Block | Select-Object DisplayName, Profile, Direction, Action ``` Do not solve a rule conflict by disabling Windows Firewall globally. ## Step 4 — Create a safe temporary test rule The original Raff lab used TCP port `54321` as a disposable demonstration port: ```powershell New-NetFirewallRule ` -DisplayName "Raff Test Inbound Rule TCP 54321" ` -Direction Inbound ` -Protocol TCP ` -LocalPort 54321 ` -Action Allow ` -Profile Any ``` Then verify it: ```powershell Get-NetFirewallRule -DisplayName "Raff Test Inbound Rule TCP 54321" | Select-Object DisplayName, Enabled, Direction, Action, Profile ``` ![PowerShell output showing a temporary inbound Windows Firewall rule created for TCP port 54321.](https://raff-images.s3.raffusercloud.com/04_test_firewall_rule_created_c56078d401.png) `-Profile Any` is retained here because it matches the original controlled lab test. **Do not copy that scope blindly into production.** Production rules should target the profile or profiles where the application actually operates. Also remember that a firewall rule does not start a service. An application still has to bind and listen on that port. Check listeners with: ```powershell Get-NetTCPConnection -State Listen | Select-Object LocalAddress, LocalPort, OwningProcess | Sort-Object LocalPort ``` If nothing is listening on the intended port, opening the firewall will not make the application reachable. ## Step 5 — Remove the temporary test rule Delete temporary rules as soon as the test is complete: ```powershell Remove-NetFirewallRule -DisplayName "Raff Test Inbound Rule TCP 54321" ``` Verify cleanup: ```powershell if (Get-NetFirewallRule -DisplayName "Raff Test Inbound Rule TCP 54321" -ErrorAction SilentlyContinue) { Write-Output "Test firewall rule still exists" } else { Write-Output "Test firewall rule removed" } ``` ![PowerShell output confirming the temporary Windows Firewall test rule was removed.](https://raff-images.s3.raffusercloud.com/05_test_firewall_rule_removed_2b629d4aae.png) Temporary exceptions are easy to forget. Use distinctive names and delete them during the same change session. ## Step 6 — Build narrower rules for production workloads Microsoft recommends making inbound exceptions as specific as practical. A useful rule can combine: - direction; - protocol; - local port; - application or service; - network profile; - remote source address; - interface or authentication requirements where needed. ### Example: public HTTPS service For a public IIS site using HTTPS: ```powershell New-NetFirewallRule ` -DisplayName "Allow HTTPS TCP 443" ` -Direction Inbound ` -Protocol TCP ` -LocalPort 443 ` -Action Allow ` -Profile Public ``` Use the profile that actually matches your network design rather than assuming `Public` on every server. ### Example: application port from one trusted source ```powershell New-NetFirewallRule ` -DisplayName "Allow App TCP 8080 from Office" ` -Direction Inbound ` -Protocol TCP ` -LocalPort 8080 ` -RemoteAddress 203.0.113.10 ` -Action Allow ` -Profile Public ``` `203.0.113.10` is an example documentation address. Replace it with the real trusted source IP or approved subnet. ### Example: scope by application as well as port If a specific application should own the listener, a program rule can reduce accidental exposure: ```powershell New-NetFirewallRule ` -DisplayName "Allow Example Service TCP 8443" ` -Direction Inbound ` -Program "C:\Program Files\Example\service.exe" ` -Protocol TCP ` -LocalPort 8443 ` -RemoteAddress 203.0.113.0/24 ` -Action Allow ` -Profile Public ``` Use the real executable path and vendor-documented port requirements. Microsoft does not support wildcard executable paths in application firewall rules. ## Step 7 — Restrict RDP carefully when the source is stable If administrators connect from a fixed office/VPN IP, source restrictions can reduce who can even reach the RDP service. Do **not** disable the existing broad RDP rules until a replacement path is created and tested. A controlled example for TCP RDP is: ```powershell New-NetFirewallRule ` -DisplayName "RDP TCP 3389 from Admin IP" ` -Direction Inbound ` -Protocol TCP ` -LocalPort 3389 ` -RemoteAddress 203.0.113.10 ` -Action Allow ` -Profile Public ``` If you intentionally use RDP over UDP as well, create a matching UDP rule for the same trusted source. Only after confirming the replacement access path works should you narrow or disable broader RDP allow rules. If the administrator’s public IP changes frequently, use a VPN, RD Gateway, or another controlled administrative access design rather than repeatedly opening 3389 to everyone. Microsoft’s RD Gateway role provides external RDS access over HTTPS and avoids exposing internal RDP ports directly to end users. ## Step 8 — Review common Windows Server ports by exposure, not habit | Port | Common use | Production guidance | |---|---|---| | TCP/UDP 3389 | RDP | Restrict source where practical; consider VPN/RD Gateway | | TCP 80 | HTTP | Open only for workloads that intentionally serve HTTP | | TCP 443 | HTTPS | Normal public web/API port when required | | TCP 1433 | SQL Server | Prefer private/trusted access; do not expose broadly | | TCP 445 | SMB | Keep off the public internet | | TCP 5985 | WinRM HTTP | Avoid broad public exposure | | TCP 5986 | WinRM HTTPS | Restrict to trusted management sources | | Custom ports | Business applications | Follow vendor requirements and scope narrowly | Do not use a “standard ports” table as permission to open everything. The application’s architecture decides which ports are necessary. ## Step 9 — Enable firewall logging for troubleshooting and audit Microsoft recommends logging dropped packets and successful inbound connections when firewall visibility is important. For production systems, Microsoft also recommends increasing the firewall log size to at least 20 MB and using separate log files per profile. Example: ```powershell Set-NetFirewallProfile -Profile Domain ` -LogBlocked True ` -LogAllowed True ` -LogMaxSizeKilobytes 20480 ` -LogFileName "$env:SystemRoot\System32\LogFiles\Firewall\pfirewall_Domain.log" Set-NetFirewallProfile -Profile Private ` -LogBlocked True ` -LogAllowed True ` -LogMaxSizeKilobytes 20480 ` -LogFileName "$env:SystemRoot\System32\LogFiles\Firewall\pfirewall_Private.log" Set-NetFirewallProfile -Profile Public ` -LogBlocked True ` -LogAllowed True ` -LogMaxSizeKilobytes 20480 ` -LogFileName "$env:SystemRoot\System32\LogFiles\Firewall\pfirewall_Public.log" ``` Review the effective settings: ```powershell Get-NetFirewallProfile | Select-Object Name, LogAllowed, LogBlocked, LogFileName, LogMaxSizeKilobytes ``` Firewall logs are useful for answering questions such as: - Is Windows dropping the connection? - Which source IP is trying to connect? - Is the request using the port you expected? - Is a new allow rule actually seeing traffic? For larger environments, forward relevant logs to centralized monitoring rather than relying only on files stored on the server. ## Step 10 — Check whether central policy overrides local rules Domain Group Policy, MDM/CSP policy, and local settings can all affect the effective firewall policy. Microsoft supports disabling **local policy merge** in stricter managed environments. When local rule merging is disabled, an administrator can create a local rule but centrally deployed policy may prevent that local rule from becoming effective. Check the profile view: ```powershell Get-NetFirewallProfile | Select-Object Name, AllowLocalFirewallRules, AllowLocalIPsecRules ``` If a server is centrally managed, troubleshoot the effective policy before repeatedly recreating local rules. In a domain environment, production firewall rules should normally be managed through the organization’s intended policy source rather than one-off local changes. ## Windows Remote Management and Windows Firewall Remote Management are different rule groups A common troubleshooting mistake is treating these two built-in rule groups as interchangeable: ```text Windows Remote Management Windows Firewall Remote Management ``` They serve different management paths. **Windows Remote Management** is associated with WinRM-based remote administration, including PowerShell remoting and management operations that use WinRM. Inspect its rules with: ```powershell Get-NetFirewallRule -DisplayGroup "Windows Remote Management" | Select-Object DisplayName, Enabled, Direction, Action, Profile ``` If WinRM is part of your intended management design, enable that built-in group rather than creating an unnecessarily broad custom port rule: ```powershell Enable-NetFirewallRule -DisplayGroup "Windows Remote Management" ``` PowerShell remoting over WinRM commonly uses TCP `5985` for HTTP and TCP `5986` for HTTPS. Do not expose either port broadly to the public internet. Restrict remote management to trusted networks, VPN paths, management subnets, or approved source addresses. **Windows Firewall Remote Management** is the separate built-in group Microsoft documents for remotely managing Windows Firewall itself. Inspect or enable it with: ```powershell Get-NetFirewallRule -DisplayGroup "Windows Firewall Remote Management" | Select-Object DisplayName, Enabled, Direction, Action, Profile Enable-NetFirewallRule -DisplayGroup "Windows Firewall Remote Management" ``` If you searched for a command such as: ```powershell Get-NetFirewallRule -DisplayGroup "Windows Remote Management" ``` first decide what you are trying to manage. Use the **Windows Remote Management** group for WinRM-based administration; use **Windows Firewall Remote Management** when the requirement is remote administration of the firewall service and its management interfaces. For remote firewall administration through PowerShell, supported NetSecurity cmdlets can also use a CIM session, for example: ```powershell Get-NetFirewallRule -CimSession SERVER01 ``` Before enabling either group, verify the active profile, source-network scope, and whether Group Policy or another central policy controls the effective rule set. ## Step 11 — Test the service from the correct side of the firewall Testing only from inside the server can give a false sense of success. ### Confirm the server is listening ```powershell Get-NetTCPConnection -State Listen | Where-Object LocalPort -eq 443 ``` ### Test from a remote Windows client ```powershell Test-NetConnection YOUR_SERVER_IP -Port 443 ``` For an IP-restricted rule, run the test from an **allowed** source and, when safe, from a **non-allowed** source. The desired result is not simply “the port is open”; it is “the right clients can connect and the wrong clients cannot.” If the remote test fails, check in this order: 1. Is the application running? 2. Is it listening on the expected local address and port? 3. Does an explicit block rule overlap the allow rule? 4. Is the rule enabled on the active profile? 5. Does the rule’s remote-address scope include the client? 6. Is a central policy overriding the local rule? 7. Is another network firewall or routing layer involved? ## A production firewall workflow should be repeatable Use this change sequence: 1. Identify the exact service and business reason. 2. Confirm its vendor-documented ports and protocols. 3. Confirm the service is listening. 4. Identify which clients actually need access. 5. Check the active network profile. 6. Preserve a recovery path before changing RDP/admin rules. 7. Create the narrowest practical rule. 8. Test from the intended client network. 9. Check logs if the test fails. 10. Document the rule name, owner, source scope, port, and reason. 11. Remove temporary or superseded rules. 12. Review exposed rules after major application or architecture changes. For broader host security, pair this workflow with the [Windows Server Hardening Checklist](/windows-server/windows-server-hardening-checklist). :::cta Explore Security Use Windows Firewall together with Raff security controls and a documented server-hardening process rather than relying on a single network rule. ::: ## Useful Windows Firewall PowerShell commands ### List enabled inbound allow rules ```powershell Get-NetFirewallRule -Enabled True -Direction Inbound -Action Allow | Select-Object DisplayName, Profile, Direction, Action | Sort-Object DisplayName ``` ### Show port filters for a rule ```powershell Get-NetFirewallRule -DisplayName "Rule Name" | Get-NetFirewallPortFilter ``` ### Show address filters for a rule ```powershell Get-NetFirewallRule -DisplayName "Rule Name" | Get-NetFirewallAddressFilter ``` ### Find rules by name ```powershell Get-NetFirewallRule | Where-Object DisplayName -Like "*RDP*" ``` ### Disable a rule without deleting it ```powershell Disable-NetFirewallRule -DisplayName "Rule Name" ``` ### Re-enable a rule ```powershell Enable-NetFirewallRule -DisplayName "Rule Name" ``` ### Remove a custom rule ```powershell Remove-NetFirewallRule -DisplayName "Rule Name" ``` ### Open the Advanced Security GUI ```text wf.msc ``` PowerShell is useful for repeatability; Windows Defender Firewall with Advanced Security is useful when you need to inspect profile, scope, program, port, and advanced rule properties visually. ## Common mistakes make firewall rules broader than intended ### Disabling Windows Firewall to troubleshoot an application Do not turn off the firewall as a production fix. Confirm the listener, rule, profile, address scope, and logs instead. ### Using `-Profile Any` for every production rule A lab rule can use `Any` for demonstration, but a production exception should normally be enabled only where the workload requires it. ### Creating a narrow RDP allow rule while leaving a broad allow rule enabled The broad rule still permits traffic. To actually restrict RDP, verify the replacement path and then narrow or disable the broader rule safely. ### Forgetting explicit block-rule precedence An explicit block can override an allow rule. Check for conflicts instead of creating duplicate allow rules. ### Opening SQL Server or SMB to everyone Database and file-sharing protocols should normally be limited to application servers, trusted IPs, private networks, VPN users, or another controlled network path. ### Assuming a listening port means the firewall allows it A listener and a firewall rule are two different conditions. Both must be correct for inbound connectivity. ### Assuming a firewall rule proves the application is secure A firewall reduces network exposure. It does not replace patching, strong authentication, least privilege, application security, monitoring, or backups. ## Raff’s recommendation is to keep the rule set small and explainable For production Windows workloads: - keep Windows Firewall enabled on all profiles; - preserve the default-deny inbound model; - keep outbound allow-by-default unless you operate a managed deny-by-default outbound policy; - scope inbound exceptions to the actual application, port, profile, and client sources; - reduce direct RDP exposure; - keep SMB and database ports away from the public internet; - enable firewall logging when the server needs operational visibility; - distinguish WinRM rules from Windows Firewall remote-management rules; - document every custom rule; - clean up test and superseded rules; - manage policy centrally when the server belongs to a domain or managed fleet. The objective is not to have many firewall rules. It is to have a small set of rules that an administrator can explain and validate. ## Tested on > Tested on Raff Windows Server 2025 Datacenter Evaluation, build 26100, 4 vCPU, approximately 8 GB RAM, on 2026-05-24 by Aybars Altınyay. The original lab verified firewall profile status, Remote Desktop rules, creation of a temporary TCP 54321 inbound rule, verification of that rule, and cleanup. The September 2026 refresh adds Microsoft-sourced production and remote-management guidance without claiming those additional policy scenarios were re-tested in the lab. ## Validation scope The Windows Firewall rule-precedence model, command-line management examples, WinRM/firewall remote-management group distinction, and current NetSecurity cmdlet behavior were revalidated against Microsoft documentation on September 10, 2026. No fresh Raff lab test is claimed for this refresh. ## What's next - [Windows Server Hardening Checklist](/windows-server/windows-server-hardening-checklist) - [How to Connect to a Windows VPS via RDP](/windows-server/connect-to-windows-vps-via-rdp) - [Multi-User RDP: 2 Admin Sessions vs RDS Session Host](/windows-server/multi-user-rdp-vs-rds) - [Windows Server Patch Management Strategy](/windows-server/windows-update-strategy) - [Raff Windows VM](/products/windows-vm) - [Raff Security](/products/security) ## Sources - Microsoft Learn — Windows Firewall overview: https://learn.microsoft.com/en-us/windows/security/operating-system-security/network-security/windows-firewall/ - Microsoft Learn — Windows Firewall rules and recommendations: https://learn.microsoft.com/en-us/windows/security/operating-system-security/network-security/windows-firewall/rules - Microsoft Learn — Manage Windows Firewall with the command line: https://learn.microsoft.com/en-us/windows/security/operating-system-security/network-security/windows-firewall/configure-with-command-line - Microsoft Learn — Configure Windows Firewall logging: https://learn.microsoft.com/en-us/windows/security/operating-system-security/network-security/windows-firewall/configure-logging - Microsoft Learn — New-NetFirewallRule: https://learn.microsoft.com/en-us/powershell/module/netsecurity/new-netfirewallrule?view=windowsserver2025-ps - Microsoft Learn — Set-NetFirewallProfile: https://learn.microsoft.com/en-us/powershell/module/netsecurity/set-netfirewallprofile?view=windowsserver2025-ps - Microsoft Learn — Get-NetFirewallRule: https://learn.microsoft.com/en-us/powershell/module/netsecurity/get-netfirewallrule?view=windowsserver2025-ps - Microsoft Learn — PowerShell remoting over WinRM security: https://learn.microsoft.com/en-us/powershell/scripting/security/remoting/winrm-security - Microsoft Learn — Windows Server 2025 security baseline with OSConfig: https://learn.microsoft.com/en-us/windows-server/security/osconfig/osconfig-how-to-configure-security-baselines - Microsoft Learn — Remote Desktop Gateway: https://learn.microsoft.com/en-us/windows-server/remote/remote-desktop-services/remote-desktop-gateway-role - Sources revalidated: 2026-09-10 --- ### Active Directory Replication Topology for 2-DC Setups URL: https://rafftechnologies.com/windows-server/ad-replication-topology Description: Design a reliable two-domain-controller Active Directory topology with same-site vs multi-site decisions, Sites and Subnets, site links, DNS, FSMO placement, repadmin health checks, and recovery planning. ## In short For most small production Active Directory environments, **two writable domain controllers in one AD site** is the simplest reliable design when both servers share a low-latency private network. Let the Knowledge Consistency Checker (KCC) build replication connections automatically, run AD-integrated DNS on both DCs where appropriate, and verify replication with `repadmin /replsummary` and `repadmin /showrepl`. Use multiple AD sites only when the network topology needs them: different offices, regions, routed locations, or WAN/VPN paths where client locality and intersite replication policy matter. Then map subnets to sites and configure site links intentionally. Microsoft’s default intersite replication interval is **180 minutes**, with a supported minimum of **15 minutes**; 15 minutes is an option, not a universal best practice. Raff Technologies recommends keeping domain-controller traffic on private networking or VPN, maintaining at least two DCs for production, and treating replication as availability—not as backup. ## The two-DC topology decision is usually simple | Scenario | Recommended topology | Why | |---|---|---| | Two DCs in one low-latency private network | One AD site | Simplest topology; KCC handles replication automatically | | Office plus cloud DC | Separate sites when the network paths/subnets are distinct | Helps clients locate an appropriate DC and controls intersite replication | | Two cloud regions | Separate sites when they represent distinct routed locations | Lets you model locality, site-link cost, interval, and schedule | | Two DCs in one region but different subnets | One or more sites depending on actual network topology | A subnet boundary alone does not automatically require a new site | | Branch with limited physical security | Consider an RODC | Can reduce credential exposure at the branch | | Only one production DC | Add another writable DC | Removes a major identity/DNS single point of failure | | MSP serving unrelated customers | Keep customer identity boundaries separate | Avoids mixing unrelated tenants in one forest without a deliberate design | A useful rule is: ```text One reliable network location → usually one AD site. Distinct network locations / WAN paths → model sites and subnets. Production identity → avoid relying on one DC. ``` If you still need to create the first domain controller, start with [Windows Server 2025 Domain Controller Setup](/windows-server/active-directory-domain-controller). ## Active Directory replication topology controls where changes flow Active Directory Domain Services is multi-master for most directory changes. A writable domain controller can accept changes such as password updates, group membership changes, computer joins, DNS records, and many directory-object updates, then replicate them to its partners. Topology determines: - which domain controllers replicate directly; - how same-site and cross-site replication differ; - how clients associate with an AD site; - which network paths intersite replication can use; - how site-link cost, interval, and schedule influence replication; - how resilient authentication and AD-integrated DNS remain when one DC is unavailable. Unhealthy replication can surface as stale group membership, inconsistent Group Policy, missing DNS records, password-change confusion, SYSVOL inconsistency, or clients contacting an unexpected DC. The goal is not to create the most elaborate topology. The goal is to make the AD topology reflect the real network and then prove that replication is healthy. ## Sites, Subnets, Site Links, and KCC each solve a different problem ### AD site An **Active Directory site** represents one or more well-connected IP subnets. Sites influence DC location and replication behavior. A site should describe network topology, not merely an office name or an organizational chart. ### Subnet object A **subnet object** maps an IP prefix to a site, for example: ```text 10.10.0.0/24 → us-east 10.20.0.0/24 → office-ny ``` Subnet mappings are how AD understands where clients and servers live from a network perspective. If you operate multiple sites, missing or incorrect subnet mappings can cause clients to select remote DCs or report that their network location is not mapped to a site. In a very small one-site environment, administrators often leave the default site and do not create elaborate subnet objects. That can work, but saying Sites/Subnets are “not required” is too broad: explicit subnet mappings become important as soon as site-aware locality, multiple routed networks, or future multi-site growth matters. ### Site link A **site link** represents connectivity between two or more AD sites. It carries: - member sites; - cost; - replication frequency; - replication schedule. Cost becomes especially important when more than one route exists between three or more sites. ### KCC The **Knowledge Consistency Checker (KCC)** automatically creates and maintains replication connection objects based on the topology. In normal environments, administrators define the sites, subnets, and site-link policy and let KCC construct the connections. Do not manually build a replication mesh unless you have a documented reason. Manual connection objects make the topology harder to reason about and can interfere with the benefits of automatic topology management. ### Global Catalog A **Global Catalog (GC)** contains a full writable replica of its own domain plus a partial replica of objects from other domains in the forest. In a small single-domain, two-DC deployment, making both DCs Global Catalog servers is usually a practical choice for lookup and logon resilience. Multi-domain forests can require more deliberate GC placement. ## A single-site two-DC deployment is the default small-business pattern Use one AD site when both DCs have reliable, low-latency connectivity and there is no meaningful WAN boundary that should change client locality or replication behavior. Example: ```text AD Site: us-east Private subnet: 10.10.0.0/24 DC01 - writable domain controller - DNS - Global Catalog - FSMO roles initially DC02 - writable domain controller - DNS - Global Catalog - replication partner ``` Do not think of these as a traditional “primary” and “secondary” server for normal directory writes. Active Directory is multi-master for most changes. DC01 may hold FSMO roles, but DC02 is still a writable domain controller and should be able to authenticate users and provide AD-integrated DNS independently when the design calls for it. Within one site, KCC creates the replication connections automatically. You do not need to create an IP site link specifically between two DCs that are already members of the same site. ## Verify a new second DC before relying on it After promoting DC02, confirm both DCs are visible: ```powershell Get-ADDomainController -Filter * | Select-Object HostName, Site, IsGlobalCatalog, IPv4Address ``` Then verify replication: ```cmd repadmin /replsummary repadmin /showrepl ``` Also confirm SYSVOL and NETLOGON exist on both DCs: ```cmd net view \\DC01 net view \\DC02 ``` Expected shares include: ```text SYSVOL NETLOGON ``` A successful promotion wizard is not sufficient evidence by itself. The second DC should have healthy inbound and outbound replication, current AD-integrated DNS data, working locator records, and functioning SYSVOL before you treat it as a resilience path. ## DNS configuration for two domain controllers must avoid DNS islands AD replication problems are often DNS problems. Domain controllers use DNS to locate directory services and each other. Microsoft’s current DNS client guidance is more nuanced than the common “always point each DC to the other DC first” rule. For an **additional DC during promotion**, configure its DNS client to use an existing healthy DNS server that is authoritative for the AD domain. Do not make a newly promoted DC depend only on its own DNS service before you have verified that inbound and outbound AD replication and DNS-zone replication are current. After replication is healthy, a DNS-hosting DC can use itself, another authoritative AD DNS server, or a combination as preferred/alternate DNS depending on topology and failure requirements. The important invariants are: - DCs and domain members use DNS servers authoritative for the AD namespace; - AD-integrated DNS zones and locator records replicate correctly; - no DC or domain member uses an ISP/public resolver as its AD DNS client; - external names are resolved through DNS forwarders or root hints rather than by bypassing AD DNS; - a preferred/alternate pair is designed around real network failure boundaries, not copied blindly from a tutorial. Verify DNS client configuration: ```cmd ipconfig /all ``` Verify AD locator records: ```powershell Resolve-DnsName -Type SRV _ldap._tcp.dc._msdcs.example.com Resolve-DnsName -Type SRV _kerberos._tcp.example.com ``` If you just promoted DC02, confirm both DCs have current domain and `_msdcs` data before changing DNS dependencies. ## Multi-site topology is for real network boundaries Use multiple AD sites when the network has distinct locations or paths where client locality or intersite replication policy matters, for example: - office plus cloud; - two cloud regions; - headquarters plus branch; - a primary site plus a disaster-recovery location; - locations connected by WAN or VPN where bandwidth/latency differs materially. Example: ```text Site: us-east Subnet: 10.10.0.0/24 DC01 Site: office-ny Subnet: 10.20.0.0/24 DC02 Site Link: us-east__office-ny ``` ![Active Directory multi-site topology diagram showing two AD sites, subnet mappings, a site link, and replication between cloud and office domain controllers.](https://raff-images.s3.raffusercloud.com/active_directory_sites_subnets_site_link_diagram_png_1bbf343fca.png) Do not create a second site merely because a second DC exists. Two DCs can belong to the same AD site. Likewise, different subnets can belong to the same site when they are connected as one well-connected network location. ## Step 1 — Create sites that reflect the network Open Active Directory Sites and Services: ```text dssite.msc ``` Create names that identify the network location clearly, for example: ```text us-east office-ny dr-site ``` Avoid generic names such as `site1` or `newsite` that become meaningless later. You can also inspect sites with PowerShell: ```powershell Get-ADReplicationSite -Filter * ``` ## Step 2 — Map every relevant subnet to the correct site In **Active Directory Sites and Services → Subnets**, create the network prefixes used by clients and domain controllers and associate each prefix with its intended site. Example: ```text 10.10.0.0/24 → us-east 10.20.0.0/24 → office-ny ``` Then verify client site discovery: ```cmd nltest /dsgetsite ``` If a client contacts an unexpected remote DC, subnet mapping is one of the first things to check. ## Step 3 — Place each domain controller in the intended site Confirm the DC site assignments: ```powershell Get-ADDomainController -Filter * | Select-Object HostName, Site, IPv4Address ``` Site assignment should match the network where the DC is actually reachable. Do not move DC objects between sites simply to force a preferred server without correcting the subnet/topology design that clients use. ## Step 4 — Configure the site link deliberately For intersite replication, configure the link between sites under: ```text Active Directory Sites and Services → Inter-Site Transports → IP ``` A site link has three planning inputs: | Property | What it controls | |---|---| | Cost | Relative preference when multiple site-link paths exist | | Replication frequency | How often scheduled intersite replication can occur | | Schedule | When the site link is available for replication | You can inspect site links with: ```powershell Get-ADReplicationSiteLink -Filter * | Select-Object Name, Cost, ReplicationFrequencyInMinutes, SitesIncluded ``` ## The default intersite replication interval is 180 minutes Microsoft documents **180 minutes (3 hours)** as the default site-link replication interval and **15 minutes** as the minimum configurable interval. That means this is a valid custom configuration: ```powershell Set-ADReplicationSiteLink ` -Identity "us-east__office-ny" ` -ReplicationFrequencyInMinutes 15 ``` But 15 minutes should not be presented as the default or as the correct value for every SMB deployment. Choose the interval based on: - acceptable directory-change latency; - bandwidth and WAN cost; - number of sites and replication hops; - frequency of identity/DNS changes; - failure and recovery requirements; - whether intersite change notification is deliberately enabled. A shorter interval reduces latency but increases replication traffic. If the default 180 minutes is too slow for the business, test a lower value and monitor the link rather than changing every site link to 15 minutes automatically. Microsoft also supports enabling **change notification on an intersite site link** for designs that need faster cross-site propagation. That is a separate setting and should be enabled intentionally after considering network capacity and topology. ## Same-site and cross-site replication behave differently Within a site, Active Directory is designed for fast replication and uses change notifications. The first replication partner is notified roughly 15 seconds after a change; additional partner notifications follow with a short delay. Across sites, Active Directory is bandwidth-aware and site-link policy matters. By default, the site-link interval is 180 minutes and the link schedule is available throughout the week unless you restrict it. This distinction matters when troubleshooting “replication is slow.” First determine whether the affected DCs are in the same site or different sites. ## Site-link cost matters when more than one path exists In a simple two-site topology with one direct site link, cost usually does not change routing because there is only one available path. With three or more sites, site-link cost helps AD calculate preferred replication routes. Lower total cost is preferred, subject to topology and schedule constraints. Example: ```text Site A ↔ Site B cost 100 Site B ↔ Site C cost 100 Site A ↔ Site C cost 300 ``` The lower-cost path through Site B may be preferred over the higher-cost direct path. Document costs so future administrators understand why they exist. ## Let KCC choose connection objects unless there is a specific exception KCC runs on domain controllers and builds the replication topology from the configured site and site-link model. Normally, you should not manually create persistent connection objects just because you want two DCs to replicate. Manual objects can survive topology changes and make later troubleshooting harder. Inspect current replication partners with: ```cmd repadmin /showrepl ``` Use Active Directory Sites and Services to inspect generated connection objects, but treat manual connection creation as an advanced exception rather than normal setup. ## FSMO roles do not make one DC the normal “master” of the other Active Directory has five operations-master roles: | Role | Scope | Main responsibility | |---|---|---| | Schema Master | Forest | Schema changes | | Domain Naming Master | Forest | Adding/removing domains and partitions | | PDC Emulator | Domain | Time hierarchy, password-change priority, lockout and compatibility functions | | RID Master | Domain | Allocates RID pools | | Infrastructure Master | Domain | Cross-domain reference maintenance | The first DC in a new forest initially holds all five roles. For a small two-DC, single-domain environment, keeping the FSMO roles together on one healthy DC is often a perfectly reasonable operational choice. That does not turn the second DC into a read-only or passive server. Both writable DCs still participate in normal multi-master directory replication. Check the role holders: ```cmd netdom query fsmo ``` Or: ```powershell Get-ADForest | Select-Object SchemaMaster, DomainNamingMaster Get-ADDomain | Select-Object PDCEmulator, RIDMaster, InfrastructureMaster ``` Pay particular attention to the **PDC Emulator** because the domain time hierarchy ultimately depends on it. Document its external time-source design and recovery procedure. ## Transfer FSMO roles when the current owner is healthy For planned role movement: ```powershell Move-ADDirectoryServerOperationMasterRole ` -Identity "DC02" ` -OperationMasterRole SchemaMaster, DomainNamingMaster, PDCEmulator, RIDMaster, InfrastructureMaster ``` Normal patch reboots do not require moving FSMO roles. Transfer them when there is a real operational reason. ## Seize FSMO roles only for a failed owner that will not return normally A role **transfer** is cooperative. A role **seizure** is a recovery action used when the current owner is unavailable. Do not seize roles casually. Before seizure, understand whether the old DC can safely return, whether metadata cleanup is required, and which role-specific recovery rules apply. Document the procedure before an outage, not during one. ## Both DCs are commonly Global Catalog servers in a small single-domain forest For most small single-domain two-DC environments, enabling the Global Catalog on both writable DCs is a practical default. It improves directory lookup and logon resilience if one DC is unavailable. Verify: ```powershell Get-ADDomainController -Filter * | Select-Object HostName, Site, IsGlobalCatalog ``` Do not generalize this into “every DC in every forest must be a GC.” Multi-domain and specialized topologies can require different placement decisions. ## repadmin /replsummary is the fast replication health check `repadmin /replsummary` is one of the most useful first checks when users report inconsistent AD behavior. Run: ```cmd repadmin /replsummary ``` Focus on: - source and destination DSAs; - largest replication delta; - failures; - total attempts; - failure percentage. A healthy environment should not show persistent or increasing replication failures. A recent change can create a normal short delta; repeated DNS, RPC, authentication, or connectivity failures require investigation. ## repadmin /showrepl explains which partner or naming context is failing Run: ```cmd repadmin /showrepl ``` Review: - source DC; - naming context; - last attempt; - last successful replication; - error code and message. Common causes include: - DNS lookup failure; - blocked RPC connectivity; - time problems; - authentication/access errors; - offline DCs; - incorrect routes or firewalls; - stale or failed-DC metadata. When `/replsummary` says replication is unhealthy, `/showrepl` gives you the partner-level detail needed to investigate. ## Force replication only for controlled testing or recovery checks A common command is: ```cmd repadmin /syncall /AeD ``` This can be useful after planned topology work when you want to test replication promptly. It is not a repair strategy for broken DNS, blocked RPC, bad site design, or an offline domain controller. Fix the underlying cause instead of scheduling forced replication as a substitute for healthy topology. ## Client site and DC discovery should match the topology From a domain-joined client: ```cmd nltest /dsgetsite nltest /dsgetdc:example.com ``` If a client belongs to `office-ny` but consistently discovers a remote DC when a local DC should be available, check: 1. the client IP and subnet mask; 2. the subnet object in AD Sites and Services; 3. the subnet-to-site association; 4. DNS and DC locator records; 5. local DC health and reachability. Do not solve an incorrect site mapping by hardcoding clients to one DC. ## SYSVOL and Group Policy depend on healthy domain-controller replication SYSVOL contains Group Policy files and logon scripts. Check that both DCs expose: ```text SYSVOL NETLOGON ``` Then verify Group Policy behavior from a client: ```cmd gpupdate /force gpresult /r ``` If users receive different GPO results depending on which DC they contact, investigate AD replication, SYSVOL/DFSR health, DNS, and GPO state before editing several policies at once. For GPO design after replication is healthy, use [Active Directory Group Policy Setup](/windows-server/ad-group-policy-setup). ## Domain-controller network rules must account for more than LDAP AD DS and replication rely on several protocols, including DNS, Kerberos, LDAP, SMB, RPC Endpoint Mapper, Global Catalog, and dynamic RPC ports. Modern Windows Server commonly uses the dynamic RPC range: ```text 49152-65535 ``` Do not expose this service surface broadly to the public internet. Keep DC-to-DC and domain-member traffic on trusted private networking or VPN and apply firewall rules to the actual topology. For host-side rules, see [Configure Windows Firewall on a Windows VPS](/windows-server/configure-windows-firewall). ## Replication is availability, not backup A second DC protects you from the loss of one domain controller. It does not protect you from every administrative mistake because many unwanted directory changes replicate too. Plan: - regular system-state backups; - tested domain-controller recovery; - protected backup copies outside the live DC; - documented DSRM credentials; - Active Directory Recycle Bin where appropriate; - FSMO recovery procedures; - failed-DC metadata cleanup procedures. VM snapshots or infrastructure recovery points can be useful additional controls, but they should not be the only Active Directory recovery plan. ## A practical monitoring schedule should match business criticality Avoid treating “weekly” or “daily” as universal rules. The more critical the directory, the more useful continuous monitoring or scheduled automated health checks become. At minimum, check replication: - after promoting or demoting a DC; - after changing Sites, Subnets, or Site Links; - after firewall or VPN changes; - after DNS changes; - after a DC outage or restore; - when users report authentication, GPO, or stale-directory behavior. For an actively managed production domain, automate detection of persistent replication failures rather than relying only on a manual monthly checklist. ## Common two-DC topology mistakes are avoidable ### Treating DC01 as “primary” and DC02 as passive Normal AD directory changes are multi-master. FSMO role ownership does not make the other writable DC a passive replica. ### Putting both DCs on the same failure boundary Two VMs do not provide much resilience if they depend on the same fragile host, storage, network path, or administrative failure domain. Separate failure dependencies where practical. ### Creating multiple sites without subnet mappings Sites only help client locality when the network is modeled correctly. Map relevant subnets to the correct sites. ### Setting every site link to 15 minutes Microsoft’s default intersite interval is 180 minutes and the supported minimum is 15 minutes. Pick a lower value only when the latency requirement justifies the additional replication traffic. ### Hardcoding “other DC first, self second” for DNS everywhere DNS client order depends on promotion stage, replication health, topology, and failure design. The consistent rule is to use authoritative AD DNS and avoid public resolvers as AD DNS clients. ### Manually creating connection objects without a reason Let KCC manage normal replication connections. ### Ignoring the PDC Emulator time hierarchy Know which DC holds the PDC Emulator role and how the forest-root PDC is configured for reliable time. ### Opening AD ports to the public internet Use private connectivity or VPN. AD DS is not a single-port public application. ### Treating replication as backup Replication copies mistakes too. Maintain recoverable system-state backups. ## Raff’s recommended baseline for a small two-DC deployment A simple same-site architecture is: ```text Private network │ ├── DC01 │ ├── AD DS │ ├── AD-integrated DNS │ ├── Global Catalog │ └── FSMO roles initially │ └── DC02 ├── AD DS ├── AD-integrated DNS ├── Global Catalog └── writable replication partner ``` For different routed locations: ```text Site A + mapped subnet(s) ↓ configured site link ↓ Site B + mapped subnet(s) ``` Start simple, make the site model match the actual network, and use health checks instead of assuming replication is working. :::cta Deploy Windows Now Deploy Windows VMs for a two-domain-controller Active Directory design, then keep replication, DNS, and administrative traffic on private networking or another controlled path. ::: ## What to verify before production Confirm that: - both writable DCs authenticate domain users; - both resolve AD DNS records; - `_msdcs` and domain DNS data are current; - `repadmin /replsummary` has no persistent failures; - `repadmin /showrepl` shows recent successful replication; - SYSVOL and NETLOGON exist on both DCs; - client site discovery matches subnet mappings; - clients locate an expected healthy DC; - Group Policy behaves consistently; - FSMO owners are documented; - the forest-root PDC time design is documented; - backups and recovery procedures are tested. ## Compatible with Raff Windows VM This architecture is compatible with Raff Windows VM deployments running supported Windows Server domain controllers. This article does **not** claim a fresh “Tested on Raff” lab run because there is no documented September 2026 two-DC replication test record attached to this page. If a future test is published, record the exact Windows Server builds, number of DCs, site/subnet design, private-network topology, test date, tester, screenshots, and `repadmin` results. ## Validation scope This article was revalidated on **September 10, 2026** against current Microsoft guidance for Windows Server DNS client settings and Active Directory replication site links. The refresh specifically corrected overly rigid DC DNS ordering advice and the old implication that 15-minute intersite replication is the default small-business recommendation. Microsoft currently documents a 180-minute default site-link interval and a 15-minute minimum. ## What's next - [Windows Server 2025 Domain Controller Setup](/windows-server/active-directory-domain-controller) - [Active Directory Group Policy Setup](/windows-server/ad-group-policy-setup) - [Windows LAPS on Windows Server 2025](/windows-server/windows-laps-windows-server-2025) - [Windows Server Hardening Checklist](/windows-server/windows-server-hardening-checklist) - [Configure Windows Firewall on a Windows VPS](/windows-server/configure-windows-firewall) - [Raff Windows VM](/products/windows-vm) ## Sources - Microsoft Learn — Active Directory replication concepts: https://learn.microsoft.com/en-us/windows-server/identity/ad-ds/get-started/replication/active-directory-replication-concepts - Microsoft Learn — Determine the site-link replication interval: https://learn.microsoft.com/en-us/windows-server/identity/ad-ds/plan/determining-the-interval - Microsoft Learn — Set-ADReplicationSiteLink: https://learn.microsoft.com/en-us/powershell/module/activedirectory/set-adreplicationsitelink - Microsoft Learn — DNS client settings best practices for Windows Server: https://learn.microsoft.com/en-us/troubleshoot/windows-server/networking/best-practices-for-dns-client-settings - Microsoft Learn — Active Directory topology management with PowerShell: https://learn.microsoft.com/en-us/windows-server/identity/ad-ds/manage/powershell/advanced-active-directory-replication-and-topology-management-using-windows-powershell--level-200- - Microsoft Learn — Windows service and network port requirements: https://learn.microsoft.com/en-us/troubleshoot/windows-server/networking/service-overview-and-network-port-requirements - Sources revalidated: 2026-09-10 --- ### Windows Server Patch Management Best Practices for Production (2026) URL: https://rafftechnologies.com/windows-server/windows-update-strategy Description: Use a production Windows Server patch management process with risk-based prioritization, deployment rings, maintenance windows, rollback protection, reboot control, validation, Hotpatch, and WSUS guidance. ## In short **Windows Server patch management** is the controlled process of assessing, testing, installing, rebooting, validating, and documenting Windows updates without creating unnecessary production downtime. Raff Technologies recommends a risk-based process: prioritize actively exploited or highly exposed vulnerabilities, validate routine monthly security updates through a small deployment ring, patch production during a defined maintenance window, and verify the real application after reboot. Do not use a blanket rule such as "always patch immediately" or "always wait 14 days." The right timing depends on exploitation status, internet exposure, application risk, available mitigations, Microsoft known issues, and the quality of your rollback path. For a small production environment, the practical sequence is: ```text Assess risk -> verify backup and rollback -> test when practical -> patch in a maintenance window -> reboot deliberately -> validate the workload -> document the result ``` ## Windows Server patch management best practices For most production Windows Server workloads, use these practices as the operating baseline: 1. **Prioritize by risk, not only severity.** Known exploitation and internet exposure can justify faster remediation than a normal monthly schedule. 2. **Review Microsoft release health before deployment.** Check the affected Windows Server version and KB for known issues and replacement updates. 3. **Use deployment rings when possible.** Patch a lab, staging system, or lower-risk server before the primary production workload. 4. **Verify backups before change.** Use application-aware backups where required and a short-term VM recovery point when appropriate. 5. **Control the maintenance window.** Decide who installs the update, when restart is allowed, and how long validation may take. 6. **Avoid unnecessary preview updates on healthy production servers.** Reduce change volume unless a preview fixes a problem you actually have. 7. **Validate the application, not just Windows.** A successful boot does not prove IIS, SQL Server, RDS, file shares, accounting software, or automation still works. 8. **Set a rollback deadline.** If the critical workload cannot be restored inside the agreed validation window, execute the recovery plan instead of troubleshooting indefinitely. 9. **Record installed KBs and outcome.** Patch history should be part of the server runbook. 10. **Treat Hotpatch as a restart-reduction tool, not a replacement for patch management.** Baseline updates and other update types can still require reboots. These practices apply whether you update one Windows VPS manually or manage a larger fleet with WSUS, Azure Update Manager, an RMM platform, or another approved patch-management system. ## How to patch Windows Server in production A safe Windows Server patching process has seven stages. | Stage | What to do | |---|---| | 1. Assess | Review the update, CVEs, known exploitation, affected roles, and Microsoft known issues | | 2. Protect | Confirm application backups, VM recovery, administrative access, and rollback ownership | | 3. Validate | Patch a representative lab, staging system, or lower-risk server when practical | | 4. Schedule | Notify users and open a maintenance window with enough time for reboot and smoke tests | | 5. Install | Install only the approved updates using your normal Windows update-management method | | 6. Reboot and test | Restart deliberately when required, then validate Windows and the actual workload | | 7. Close or roll back | Document success, or execute the predefined rollback path if validation fails | For an emergency vulnerability, use the same controls on a shorter timeline rather than abandoning the process. ## Production patching starts with a risk decision | Update situation | Recommended response | |---|---| | Known exploitation affecting an exposed component | Prioritize testing and remediation immediately; compress the normal change window | | Critical/security update with no known exploitation | Validate quickly, then deploy through the normal production patch window | | Normal monthly cumulative security update | Stage through test or low-risk systems, then production after validation | | Out-of-band security update | Review the specific issue and affected component immediately | | Optional nonsecurity preview | Usually skip on production unless it fixes a problem you actually have | | Driver or firmware update | Install only when required and supported for the environment | | Windows Server version upgrade | Treat as a migration or upgrade project, not routine monthly patching | CISA maintains the Known Exploited Vulnerabilities catalog so organizations can use evidence of exploitation as a vulnerability-prioritization signal. Exposure still matters. An internet-facing affected service usually deserves a shorter remediation window than a disabled component on an isolated test server. The goal is not to install every update the minute it appears. The goal is to reduce security exposure without creating avoidable production outages. ## Patch Tuesday gives you a predictable monthly cycle Microsoft's monthly security update is released on the **second Tuesday of each month**, commonly called Patch Tuesday or Update Tuesday. These monthly security releases are cumulative and include security fixes plus previous applicable quality changes. Microsoft also publishes an optional nonsecurity preview release, normally on the **fourth Tuesday of the month**, and can publish out-of-band updates when a newly identified issue or vulnerability requires action outside the normal schedule. That gives production teams a predictable operating rhythm: 1. Review the monthly security release and Microsoft release health. 2. Identify whether the update affects your Windows Server version and enabled roles. 3. Check exploitation signals and vendor advisories. 4. Test or patch a lower-risk ring when practical. 5. Move the update into the production maintenance window. 6. Accelerate the schedule when active exploitation or exposure makes delay unsafe. A fixed "wait 7 to 14 days" rule is less useful than this risk-based model. ## Automatic workstation-style updating is a poor production policy A production server can host RDS sessions, accounting software, SQL Server, IIS, ERP software, file services, automation jobs, or other workloads that users expect to stay available. ![02-windows-update-settings-screen.png](https://raff-images.s3.raffusercloud.com/02_windows_update_settings_screen_ef90ef520c.png) A production update policy should answer these questions before the next monthly release: - Who owns patch approval? - Which server is patched first? - What constitutes an emergency update? - When may the server reboot? - What recovery point exists before change? - Which application checks prove the patch succeeded? - Who communicates downtime to users? - How is the update documented afterward? The server should not discover its maintenance policy during the update itself. ## What Raff tested on Windows Server 2025 The existing screenshots and PowerShell checks in this article were captured on a Raff Windows Server 2025 lab VM on May 24, 2026. ![PowerShell output showing a Raff Windows VPS running Windows Server 2025 with build number, CPU count, and memory details.](https://raff-images.s3.raffusercloud.com/01_windows_update_test_environment_a4c4be52d8.png) | Item | Value | |---|---| | OS | Windows Server 2025 Datacenter | | Build | 26100 | | CPU | 4 vCPU | | RAM | Approximately 8 GB | | Test date | 2026-05-24 | | Engineer | Serdar Tekin | The lab verified update-history inspection, pending-reboot detection, the PSWindowsUpdate community module, update scanning, and Raff dashboard recovery/reboot controls. It did **not** run a controlled production patch benchmark, so this guide does not claim a fixed patch duration, success rate, or downtime figure. ## Use deployment rings instead of a fixed delay A deployment ring gives you a chance to discover a problem before the most important server is affected. | Ring | Example | Purpose | |---|---|---| | Ring 0 | Disposable test VM or lab | Confirm Windows boots and the update installs | | Ring 1 | Staging or low-risk server | Test the real application stack | | Ring 2 | Production server | Deploy after validation and risk review | A small business may not have three permanent servers. The same principle still works. You can create a temporary test VM, patch a lower-risk system first, or validate Microsoft and application-vendor advisories before patching the main production server. The ring should be representative enough to catch meaningful problems. A blank Windows test VM is less useful when the production server depends on IIS modules, SQL Server, printer drivers, RDS, EDR software, or a vendor-specific business application. ## Preflight checks reduce avoidable patch failures Before installing updates, record the current state. A quick view of recently installed hotfixes is: ```powershell Get-HotFix | Sort-Object InstalledOn -Descending | Select-Object -First 10 HotFixID, InstalledOn, Description ``` `Get-HotFix` is useful for a quick check, but it is not a complete inventory of every Windows update package. Use Windows Update history, DISM/package inventory, your patch-management platform, and Microsoft release information when you need full update accounting. Check for a pending component-servicing reboot: ```powershell $key = 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Component Based Servicing\RebootPending' if (Test-Path $key) { Write-Warning 'Component servicing reboot pending' } else { Write-Output 'No component servicing reboot detected' } ``` ![PowerShell output showing recent Windows updates and a pending reboot check on a Windows Server VPS.](https://raff-images.s3.raffusercloud.com/03_update_history_and_pending_reboot_check_64a84eaed5.png) A production preflight should also confirm: - enough free disk space; - healthy Windows services; - application and database backup status; - current VM backup or recovery point; - administrative access outside the normal user workflow; - current application health; - maintenance-window communication; - vendor advisories for the business application; - enough time in the maintenance window for a second reboot if required. For clustered, replicated, or multi-server applications, follow the application vendor's supported patch sequence rather than treating every server as independent. ## Check Windows release health and the Security Update Guide Before production installation, review Microsoft's current information for the affected version and KB. Look for: - known issues; - installation failures; - authentication or networking regressions; - RDP or RDS issues; - printing issues; - .NET or application compatibility notes; - Known Issue Rollback information; - out-of-band replacement updates; - required servicing-stack or prerequisite information. Also check whether the vulnerability affects a role that is actually installed or exposed on the server. A vulnerability affecting an unused component can have a different operational priority from one affecting an internet-facing service. ## Snapshots are rollback points, not the whole backup strategy Before a significant production patch window, create an appropriate recovery point in the Raff dashboard and confirm the application's own backup is healthy where relevant. ![Raff dashboard controls used to create a recovery point or reboot a Windows Server VM before a planned maintenance window.](https://raff-images.s3.raffusercloud.com/05_raff_dashboard_snapshot_or_reboot_b9f7444509.png) Use snapshots for **short-term rollback before change**. Do not treat them as your only backup strategy. For example: - SQL Server should still have database-aware backups. - QuickBooks or ERP data should use the vendor-supported backup process. - Shared files should have file-level or off-server recovery. - Business-critical VMs should have a documented backup retention and restore process. A snapshot can help reverse an operating-system change. It does not replace application-consistent backups, off-server copies, or restore testing. For the broader recovery model, use [Windows VPS Backup Strategy for Small Businesses](/windows-server/windows-vps-backup-strategy-small-business). ## PSWindowsUpdate is optional, not required The Raff lab used **PSWindowsUpdate**, a PowerShell Gallery community module, to scan for updates. It can be useful for administrators who intentionally permit third-party PowerShell modules, but it is not a built-in Windows Server cmdlet and is not Microsoft's required patch-management method. If your organization permits the module, review the package and repository before installation: ```powershell Find-Module PSWindowsUpdate -Repository PSGallery ``` Then install and import it according to your organization's module policy: ```powershell Install-Module -Name PSWindowsUpdate -Repository PSGallery -Scope AllUsers Import-Module PSWindowsUpdate ``` A scan without installation: ```powershell Get-WindowsUpdate ``` ![PSWindowsUpdate scan showing available Windows Server updates without installing them.](https://raff-images.s3.raffusercloud.com/04_pswindowsupdate_scan_e91f94a9fe.png) The important distinction is: ```text Assessment / scan != Installation ``` If you do not permit community PowerShell modules, use Windows Update, SConfig on Server Core, WSUS, Azure Update Manager for eligible managed systems, an RMM platform, or another approved patch-management product. ## WSUS is deprecated but still supported Windows Server Update Services, or **WSUS**, is deprecated in the sense that Microsoft is no longer actively developing new WSUS features. That does **not** mean existing WSUS deployments stopped working or became unsupported overnight. Microsoft states that existing WSUS capabilities and content remain available for deployments, and WSUS continues to be supported for production according to the Windows Server lifecycle. For an existing stable WSUS environment: - do not rip it out solely because the feature is deprecated; - keep the WSUS server itself patched and monitored; - review storage, synchronization, approval, and cleanup health; - document how update rings and reboots are controlled; - plan the long-term management direction rather than assuming WSUS will receive major new features. For a new fleet, compare WSUS with the patch-management platform you already operate, such as Azure Update Manager for Arc-enabled servers, an RMM system, or another supported enterprise update-management product. ## Install updates inside a defined maintenance window A good maintenance window includes enough time for more than the update installer. Plan time for: 1. final health check; 2. application-safe shutdown steps if required; 3. update installation; 4. reboot; 5. possible second reboot; 6. service startup; 7. application smoke tests; 8. user-access verification; 9. rollback decision if validation fails. For manually managed small servers, it is often safer to control the restart explicitly rather than let a script reboot at an unknown point in the change window. If PSWindowsUpdate is part of your approved process, an install command can be: ```powershell Get-WindowsUpdate -Install -AcceptAll ``` Do not add automatic reboot behavior unless the maintenance workflow is specifically designed for unattended restarts and post-reboot validation. ## Configure restart behavior intentionally Windows Update and your management platform should follow the production reboot plan rather than deciding it accidentally. For domain-managed or policy-managed servers, review the effective policy under: ```text Computer Configuration -> Administrative Templates -> Windows Components -> Windows Update -> Manage end user experience -> Configure Automatic Updates ``` Also review the policy: ```text No auto-restart with logged on users for scheduled automatic updates installations ``` That policy applies only in the relevant scheduled Automatic Updates configuration. Test the resulting behavior rather than assuming one registry value controls every update-management system. For Server Core, Microsoft's **SConfig** tool provides a supported interface for basic Windows Update settings. ## Post-patch validation must test the real workload After the server returns, validate the operating system first: ```powershell Get-HotFix | Sort-Object InstalledOn -Descending | Select-Object -First 10 HotFixID, InstalledOn, Description ``` Re-check pending reboot state: ```powershell $key = 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Component Based Servicing\RebootPending' if (Test-Path $key) { Write-Warning 'Component servicing reboot still pending' } else { Write-Output 'No component servicing reboot detected' } ``` Then review required services and logs. A quick stopped-service list can help compare current state with the pre-patch baseline: ```powershell Get-Service | Where-Object Status -eq 'Stopped' | Sort-Object DisplayName | Select-Object -First 30 Name, DisplayName, StartType ``` Many Windows services are intentionally manual or trigger-started, so do not treat every stopped service as a fault. Finally test the workload: | Workload | Minimum post-patch test | |---|---| | IIS | Load the site or API and review application/system errors | | SQL Server | Confirm database service, connection, and a safe test query | | RDP/RDS | Confirm administrative and intended user sign-in paths | | QuickBooks/accounting | Open the application and verify an approved test workflow | | File server | Open a share and test expected permissions | | ERP/LOB app | Start client/service and complete a safe business test | | Automation | Confirm scheduled tasks or services resume normally | The patch window is not complete because the Windows login screen appeared. It is complete when the production workload passes its smoke test. ## Set a rollback deadline before you patch Do not spend an unlimited maintenance window debugging a failed update while users wait. Define the rollback point before change, for example: ```text If the critical application is not healthy within the agreed validation window, stop troubleshooting and execute the documented rollback plan. ``` The recovery method depends on the failure: - uninstall the affected Windows update when Microsoft supports removal; - use Known Issue Rollback when Microsoft provides it for the issue; - restore an application backup if application data changed; - revert a suitable VM recovery point when appropriate; - rebuild or restore from backup when rollback cannot safely repair the state. After recovery, document the failed KB, symptoms, logs, and Microsoft or vendor guidance before attempting deployment again. ## Optional preview updates should normally stay off healthy production servers Microsoft's optional nonsecurity preview release is normally published on the fourth Tuesday of the month. It can be useful for early validation or when it contains a fix for a problem you are actively experiencing. A preview update can make sense when: - it fixes a production issue you need to resolve; - Microsoft or the application vendor recommends it for your exact problem; - you want to validate upcoming nonsecurity changes in a lab. For a healthy production Windows Server, do not install previews merely because they are available. Fewer unnecessary changes mean a smaller troubleshooting surface. ## Windows Server 2025 Hotpatch can reduce restart frequency Windows Server 2025 Standard and Datacenter can use Microsoft **Hotpatch** when the machine meets the current Azure Arc-enabled Hotpatch requirements. Microsoft's current requirements include a supported Windows Server 2025 build, Azure Arc connectivity, and the required virtualization-based security configuration. Server Core and Desktop Experience are supported when the other prerequisites are met. For eligible Windows Server 2025 Arc-enabled systems, Microsoft now states that Hotpatch is available **at no additional Hotpatch charge**. This pricing change took effect in May 2026. The update pattern still includes rebooting: - the first month of each quarter uses a baseline cumulative update that requires restart; - the following two months can use Hotpatch security updates without restart when a Hotpatch is available; - some other update types can still require restart. Hotpatch also does not provide automatic rollback. If a Hotpatch causes a problem, Microsoft's recovery guidance can require uninstalling the latest update and returning to the last functional baseline, which itself can require rebooting. On Raff, Hotpatch should be treated as an optional customer-managed Microsoft capability for eligible Windows Server 2025 systems, not as a default Raff platform feature. ## Emergency patching uses the same controls on a shorter timeline An emergency does not mean abandoning change control. It means compressing it. When a vulnerability is actively exploited or creates unacceptable exposure: 1. Confirm whether the server and installed role are affected. 2. Apply immediate mitigations if Microsoft provides them. 3. Confirm current backups and rollback readiness. 4. Test the update quickly where practical. 5. Schedule the earliest safe production window. 6. Patch and reboot if required. 7. Validate the real application. 8. Monitor logs and service health afterward. CISA's KEV catalog is a useful prioritization input, but it is not the only signal. Internet exposure, privileges required, exploit maturity, business criticality, and compensating controls all affect urgency. ## Patch records should be part of the server runbook For each production patch window, record: | Field | Example | |---|---| | Date/time | Maintenance window timestamp | | Server | Accounting-RDS-01 | | Approved KBs | KB numbers installed | | Pre-check | Backup healthy, disk healthy, app healthy | | Recovery point | Snapshot or backup reference | | Reboots | Number of restarts | | Validation | RDP, application, file, database, or API tests passed | | Issues | None or ticket/reference number | | Owner | Windows administrator | This turns patching into a repeatable operating process instead of a memory-based monthly task. ## Raff production patching checklist Before closing the maintenance window, confirm: - [ ] Microsoft release health and Security Update Guide reviewed - [ ] Exploitation and exposure assessed - [ ] Application or database backup confirmed - [ ] VM recovery point created when appropriate - [ ] Free disk space checked - [ ] Pending reboot state checked - [ ] Approved update list documented - [ ] Maintenance window communicated - [ ] Update installed successfully - [ ] Required reboot completed - [ ] Pending reboot rechecked - [ ] Required Windows services healthy - [ ] RDP or RDS access tested when applicable - [ ] IIS, SQL Server, file shares, or business application smoke test passed - [ ] Event and application logs reviewed for new critical errors - [ ] Rollback decision made before the maintenance deadline - [ ] Installed KBs and result recorded - [ ] Temporary rollback snapshots scheduled for cleanup after stability is confirmed :::cta Explore Windows VM Run production Windows workloads on Raff while keeping patch timing, maintenance windows, rollback, and application validation under your control. ::: ## Common Windows Server patching mistakes ### Waiting a fixed 14 days for every security update A short validation period can be reasonable for routine updates, but known exploitation or an exposed vulnerable role can justify much faster remediation. ### Patching without a rollback path Know how you will recover before changing a business-critical server. ### Treating a snapshot as the only backup Snapshots are change rollback tools. Databases and business applications still need their own recovery strategy. ### Installing optional previews on healthy production servers Every unnecessary update increases change surface. Install preview releases only for a defined reason. ### Using a community PowerShell module without supply-chain review PSWindowsUpdate can be useful, but it is a community module. Apply your organization's normal PowerShell Gallery and module-review policy. ### Allowing automatic reboot to define the maintenance window Configure Windows Update and management tooling so reboot timing matches the operational plan. ### Checking only whether Windows came back online Validate the application, data path, remote access, and required services. ### Leaving pre-patch snapshots indefinitely Short-term rollback points should have an expiration and cleanup process. Long-term recovery belongs in the backup strategy. ## Frequently asked questions ### What is Windows Server patch management? Windows Server patch management is the controlled process of assessing, testing, installing, rebooting, validating, and documenting updates while balancing security exposure against production availability. ### Should I patch Windows Server immediately on Patch Tuesday? Not automatically. Review the affected components, exploitation status, Microsoft known issues, business exposure, and rollback readiness. Routine updates can move through a short validation ring, while actively exploited vulnerabilities may require a compressed emergency process. ### How often should Windows Server be patched? Microsoft releases a cumulative security update on the second Tuesday of each month, with out-of-band updates when needed. Production servers should therefore have a monthly patch process plus an emergency path for urgent vulnerabilities. ### Is PSWindowsUpdate required? No. PSWindowsUpdate is a community PowerShell module. Windows Update, SConfig, WSUS, Azure Update Manager, RMM platforms, and other approved systems can manage Windows Server updates without it. ### Is WSUS still supported? Yes. Microsoft has deprecated WSUS and is no longer actively developing new features, but existing capabilities remain available and WSUS continues to be supported for production deployments under the Windows Server lifecycle. ### Should I snapshot a Windows VPS before patching? A short-term VM recovery point can be useful before a significant change, but it should supplement application-aware backups, off-server copies, and tested restore procedures rather than replace them. ### Can Windows Server 2025 patch without rebooting? Eligible Windows Server 2025 Standard and Datacenter systems can use Azure Arc-enabled Hotpatch for certain security updates. Baseline cumulative updates and other update types can still require restart. ### What should I verify after a Windows Server update? Verify installed update state, pending restart, required Windows services, critical event and application logs, remote access, and the actual production workload such as IIS, SQL Server, RDS, accounting software, file shares, or automation. ## What's next - [Windows Server Hardening Checklist](/windows-server/windows-server-hardening-checklist) - [Windows VPS Backup Strategy for Small Businesses](/windows-server/windows-vps-backup-strategy-small-business) - [Windows Server Performance Monitoring](/windows-server/windows-server-performance-monitoring) - [Windows Server Version Comparison](/windows-server/windows-server-version-comparison) - [MSSQL Backup Strategy on a Windows VPS](/windows-server/mssql-backup-strategy) - [Raff Windows VM](/products/windows-vm) - [Raff Windows Server Hub](/windows-server) ## Sources - Microsoft Learn - Update release cycle for Windows: https://learn.microsoft.com/en-us/windows/deployment/update/release-cycle - Microsoft Learn - Windows Server release information: https://learn.microsoft.com/en-us/windows/release-health/windows-server-release-info - Microsoft Learn - Windows release health: https://learn.microsoft.com/en-us/windows/release-health/ - Microsoft Security Response Center - Security Update Guide: https://msrc.microsoft.com/update-guide/ - Microsoft Learn - Configure Group Policy settings for Automatic Updates: https://learn.microsoft.com/en-us/windows-server/administration/windows-server-update-services/deploy/4-configure-group-policy-settings-for-automatic-updates - Microsoft Learn - Configure Windows Server with SConfig: https://learn.microsoft.com/en-us/windows-server/administration/server-core/server-core-sconfig - Microsoft Learn - Hotpatch for Windows Server: https://learn.microsoft.com/en-us/windows-server/get-started/hotpatch - Microsoft Learn - Manage Hotpatch on Azure Arc-enabled machines: https://learn.microsoft.com/en-us/azure/update-manager/manage-hot-patching-arc-machines - Microsoft Learn - Features removed or no longer developed in Windows Server: https://learn.microsoft.com/en-us/windows-server/get-started/removed-deprecated-features-windows-server - Microsoft Learn - Windows Server Update Services overview: https://learn.microsoft.com/en-us/windows-server/administration/windows-server-update-services/get-started/windows-server-update-services-wsus - CISA - Known Exploited Vulnerabilities Catalog: https://www.cisa.gov/known-exploited-vulnerabilities-catalog - PowerShell Gallery - PSWindowsUpdate: https://www.powershellgallery.com/packages/PSWindowsUpdate - Sources revalidated: 2026-09-11 --- ### Windows Server Hardening Checklist (2026): Secure a Windows VPS URL: https://rafftechnologies.com/windows-server/windows-server-hardening-checklist Description: Harden Windows Server before production with a practical 2026 checklist for accounts, RDP and RD Gateway, Firewall, Defender, SMB, LAPS, auditing, patching, backups, and the Windows Server 2025 security baseline. ## In short A **Windows Server hardening checklist** should reduce the attack surface before the server becomes production infrastructure. Start with recovery, administrator access, Windows Firewall, RDP exposure, Network Level Authentication, Microsoft Defender, SMB, logging, patching, and backups. Then compare the result with Microsoft's role-aware security baseline for the Windows Server version you actually run. For Windows Server 2025, Microsoft provides an OSConfig security baseline with more than 300 settings and separate scenarios for domain controllers, domain-joined member servers, and workgroup member servers. Raff Technologies recommends treating that baseline as the long-term reference rather than applying an arbitrary internet checklist as if it were a compliance standard. For a small Windows VPS, use this order: ```text Recovery -> accounts and admin access -> RDP exposure -> firewall -> Defender -> SMB -> LAPS / local admin password control -> auditing and logs -> patching -> backups -> baseline validation ``` Do not apply dozens of security changes to a remote production server at once. Authentication, firewall, RDP, SMB, Defender, and service changes can lock you out or break business software. ## Windows Server hardening checklist for production | Area | Production check | |---|---| | Recovery | Confirm a current backup or recovery point before high-risk changes | | Accounts | Review local users and the local Administrators group | | Authentication | Use unique administrator credentials and an intentional lockout policy | | RDP | Avoid broad public RDP exposure; use NLA and a controlled admin path | | RD Gateway / VPN | Prefer RD Gateway, VPN, private access, or source-IP restriction when practical | | Firewall | Keep all Windows Firewall profiles enabled and review inbound allow rules | | Defender | Confirm real-time, behavior, and script scanning are active | | SMB | Keep SMBv1 disabled; review SMB signing, guest access, and TCP 445 exposure | | Local admin passwords | Use Windows LAPS where the environment supports it | | Auditing | Record logons, lockouts, account changes, privilege use, and process creation | | PowerShell | Enable useful logging where appropriate and protect sensitive logs | | Updates | Patch with a controlled production process and accelerate known-exploited issues | | Services | Remove unnecessary roles and services only after validation | | Backups | Keep application-aware and off-server recovery where the workload requires it | | Documentation | Record the owner, reason, validation, and rollback plan for security changes | The biggest improvement usually comes from reducing unnecessary exposure and making administration repeatable, not from changing hundreds of registry values manually. ## Windows Server 2025 security baseline should be the reference point Microsoft's Windows Server 2025 security baseline is delivered through OSConfig and is role-aware. Current scenarios include: | Server role | OSConfig security baseline scenario | |---|---| | Domain controller | `SecurityBaseline/WindowsServer/2025/DomainController` | | Domain-joined member server | `SecurityBaseline/WindowsServer/2025/MemberServer` | | Workgroup member server | `SecurityBaseline/WindowsServer/2025/WorkgroupMember` | Microsoft also provides companion scenarios for Secured-core, Microsoft Defender Antivirus, and Windows LAPS in supported configurations. The baseline covers controls such as: - Windows Firewall with a restrictive inbound posture; - legacy protocol reduction; - SMB hardening; - anonymous and guest access restrictions; - credential protections; - Defender and exploit protections; - advanced auditing; - process creation logging with command-line data; - larger event-log capacity; - modern cryptography and protocol settings. OSConfig supports Windows Server 2025. For earlier supported Windows Server releases, use the Microsoft security baseline and Security Compliance Toolkit guidance appropriate to that version and management model. A baseline can affect authentication, file sharing, remote access, applications, and management agents. Test it against the actual server role before broad rollout. ## What Raff tested on Windows Server 2025 The existing screenshots and PowerShell checks in this article were captured on a Raff Windows Server 2025 lab VM on May 24, 2026. ![PowerShell output showing a Raff Windows VPS running Windows Server 2025 with build number, CPU count, and memory details.](https://raff-images.s3.raffusercloud.com/01_hardening_test_environment_edc6037983.png) | Item | Value | |---|---| | OS | Windows Server 2025 Datacenter | | Build | 26100 | | CPU | 4 vCPU | | RAM | Approximately 8 GB | | Test date | 2026-05-24 | | Engineer | Serdar Tekin | That lab verified the inspection commands for local users, administrators, account policy, Windows Firewall, RDP rules, Microsoft Defender preferences, and audit policy. It did not apply every control in this checklist, so this article does not claim a fresh end-to-end hardening benchmark or compliance result. ## Step 1: protect recovery access before changing security settings Before changing authentication, firewall, RDP, services, or SMB settings, confirm how you will recover if the server becomes unreachable. For a production workload, verify: - a recent VM recovery point or backup exists where appropriate; - application-aware backups are healthy for databases and business software; - recovery credentials are documented securely; - you know how to reach the server if normal RDP access stops working; - the rollback owner and decision point are clear. A snapshot can be useful for short-term rollback after a configuration change. It is not a replacement for application-aware backups, off-server copies, or restore testing. ## Step 2: audit administrator accounts Run PowerShell as Administrator and inventory local users: ```powershell Get-LocalUser | Select-Object Name, Enabled, LastLogon ``` Then inspect the local Administrators group: ```powershell Get-LocalGroupMember -Group "Administrators" | Select-Object Name, ObjectClass ``` ![PowerShell output showing local users and members of the local Administrators group on a Windows Server VPS.](https://raff-images.s3.raffusercloud.com/02_local_admin_users_audit_1da1a03661.png) Investigate unknown accounts before removing them. Disable obsolete test users, keep the Guest account disabled, and avoid shared administrator credentials. Check the Guest account: ```powershell Get-LocalUser Guest | Select-Object Name, Enabled ``` If it is enabled and no supported application explicitly requires it: ```powershell Disable-LocalUser -Name "Guest" ``` For routine work inside the server, use non-administrator access when the workload permits it and elevate only when administrative rights are required. Renaming the built-in Administrator account can be part of a managed baseline, but it is not a primary security boundary. Strong unique credentials, restricted remote access, monitoring, and least privilege matter more. ## Step 3: use an intentional account lockout policy Check the current local account policy: ```powershell net accounts ``` ![03-account-policy-status.png](https://raff-images.s3.raffusercloud.com/03_account_policy_status_afb7774d97.png) Do not copy one lockout threshold into every environment without considering the operational effect. A strict threshold slows password guessing but can also make deliberate account-lockout attacks easier. For domain environments, configure the policy centrally. For standalone VPS deployments, document the chosen threshold and test recovery before enforcing it. The important production checks are: - lockout behavior is deliberately configured; - recovery exists if an administrator is locked out; - failed logons are monitored; - local administrator passwords are unique; - shared administrator accounts are avoided. ## Step 4: reduce direct RDP exposure Remote Desktop is often the most exposed administrative path on a Windows VPS. NLA helps, but the stronger design decision is to reduce who can reach RDP in the first place. Keep Windows Firewall enabled on all profiles: ```powershell Get-NetFirewallProfile | Select-Object Name, Enabled, DefaultInboundAction, DefaultOutboundAction ``` Inspect the Remote Desktop rule group: ```powershell Get-NetFirewallRule -DisplayGroup "Remote Desktop" | Select-Object DisplayName, Enabled, Direction, Action, Profile | Format-Table -AutoSize ``` ![04-firewall-and-rdp-status.png](https://raff-images.s3.raffusercloud.com/04_firewall_and_rdp_status_bc691e1fd6.png) For administrative RDP: - restrict source IPs where practical; - prefer private access or a VPN for administrative paths when available; - keep RDP limited to named administrators or intended RDS users; - do not expose SMB, SQL Server, WinRM, or other management ports broadly to the internet; - preserve a recovery path before changing remote-access rules. If several users or administrators need persistent access from external networks, consider a [Remote Desktop Gateway instead of direct RDP](/windows-server/remote-desktop-gateway-vs-direct-rdp). Microsoft documents RD Gateway as an HTTPS-based access layer that accepts external RDP client traffic over TCP 443, with UDP 3391 available for RDP over UDP, while the protected RDP hosts can remain on the internal path rather than publishing TCP 3389 directly. Changing the RDP listening port can reduce commodity scanning noise, but it does not replace access control, NLA, firewall restrictions, RD Gateway, VPN access, or monitoring. For firewall configuration, see [Configure Windows Firewall on a Windows VPS](/windows-server/configure-windows-firewall). ## Step 5: keep Network Level Authentication enabled Network Level Authentication requires authentication before Windows creates a full Remote Desktop session. Microsoft recommends NLA for most environments. Check the RDP NLA policy value: ```powershell Get-ItemProperty ` 'HKLM:\SYSTEM\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp' ` -Name UserAuthentication ``` A `UserAuthentication` value of `1` means NLA is required for that RDP listener configuration. Do not disable NLA merely to support an obsolete client. Upgrade the client or document the temporary compatibility exception and its risk. ## Step 6: keep Windows Firewall enabled and narrowly scoped Microsoft's current Windows Server 2025 baseline keeps Windows Firewall enabled with a restrictive inbound posture. Treat inbound rules as exceptions that must have a workload reason. Useful review commands include: ```powershell Get-NetFirewallProfile ``` and: ```powershell Get-NetFirewallRule -Enabled True -Direction Inbound | Select-Object DisplayName, Profile, Action | Sort-Object DisplayName ``` Review broad `Any` source rules, old temporary rules, duplicated application exceptions, and ports no longer used by the server role. Do not disable Windows Firewall to troubleshoot a connectivity issue. Prove which listener, profile, source, and port are required, then fix the specific rule. ## Step 7: disable SMBv1 and review Windows Server 2025 SMB behavior SMBv1 has significant security weaknesses and is not installed by default on modern Windows Server releases. Verify the server is not relying on it: ```powershell Get-SmbServerConfiguration | Select-Object EnableSMB1Protocol ``` If an old application or device requires SMBv1, treat it as a legacy dependency that needs upgrade, replacement, or isolation rather than weakening the whole server. Review SMB signing configuration: ```powershell Get-SmbClientConfiguration | Select-Object RequireSecuritySignature Get-SmbServerConfiguration | Select-Object RequireSecuritySignature ``` Windows Server 2025 strengthened SMB security, including signing behavior, and Microsoft's Server 2025 security baseline applies additional SMB hardening. Test third-party NAS devices and older SMB servers before enforcing stricter settings across production. Keep TCP 445 off the public internet. Use private networking, VPN access, or another controlled file-access architecture for users across locations. ## Step 8: keep Microsoft Defender active Verify Defender's principal protection settings: ```powershell Get-MpPreference | Select-Object DisableRealtimeMonitoring, DisableBehaviorMonitoring, DisableScriptScanning ``` ![PowerShell output showing Microsoft Defender real-time, behavior, and script scanning settings on Windows Server.](https://raff-images.s3.raffusercloud.com/05_defender_status_9cc732b829.png) For a normal protected baseline, these values should not indicate that real-time, behavior, or script scanning has been disabled. Update signatures with: ```powershell Update-MpSignature -Verbose ``` Attack Surface Reduction rules and Controlled Folder Access can add protection, but they can also interfere with ERP software, Office automation, scripts, installers, and legacy applications. Use an audit or controlled rollout before enforcing them on a production workload. Do not disable antivirus globally to solve an application problem. Use vendor-documented exclusions only when necessary and keep them narrowly scoped. ## Step 9: use Windows LAPS for local administrator passwords where supported Reusing the same local administrator password across servers turns one credential compromise into a fleet-wide problem. **Windows LAPS** can automatically manage and back up a local administrator password for supported Microsoft Entra-joined or Active Directory-joined devices. Microsoft also includes a Windows Server 2025 OSConfig LAPS scenario for supported member-server deployments. For domain-joined environments, prefer centrally managed unique local administrator passwords instead of maintaining a shared static local admin credential. For standalone systems, review the Windows LAPS deployment options that match the device join state and management architecture. See [Windows LAPS on Windows Server 2025](/windows-server/windows-laps-windows-server-2025) for the dedicated workflow. ## Step 10: enable audit events you can actually investigate Check high-value audit categories: ```powershell auditpol /get /subcategory:"Logon" auditpol /get /subcategory:"Account Lockout" auditpol /get /subcategory:"User Account Management" auditpol /get /subcategory:"Process Creation" ``` ![06-audit-policy-status.png](https://raff-images.s3.raffusercloud.com/06_audit_policy_status_9712e21156.png) Microsoft's Server 2025 baseline enables broad advanced auditing and process creation with command-line capture. For a smaller VPS, at minimum make sure you can investigate: - successful and failed logons; - account lockouts; - user-account changes; - administrator and privilege changes; - process creation; - firewall activity relevant to exposed services. Example audit-policy commands: ```powershell auditpol /set /subcategory:"Logon" /success:enable /failure:enable auditpol /set /subcategory:"Logoff" /success:enable auditpol /set /subcategory:"Account Lockout" /success:enable /failure:enable auditpol /set /subcategory:"User Account Management" /success:enable /failure:enable auditpol /set /subcategory:"Process Creation" /success:enable ``` For complete production policy, use Microsoft's advanced audit recommendations or the official baseline rather than stopping at these examples. ## Step 11: retain security logs long enough to be useful A Security log that rolls over too quickly can erase the events you need during an incident review. Microsoft's Server 2025 baseline increases Security log capacity and includes broader audit coverage. Check the current maximum size: ```powershell wevtutil gl Security | Select-String maxSize ``` Choose retention based on event volume and incident-response requirements rather than an arbitrary number. RDP-heavy, file-server, domain-controller, and application servers can generate very different log volumes. For important systems, consider forwarding security events to another logging or monitoring destination so compromise of the server does not remove the only copy of the evidence. ## Step 12: monitor failed logons Windows Security event ID `4625` records failed logon attempts. Review recent failures: ```powershell Get-WinEvent -FilterHashtable @{ LogName='Security' Id=4625 StartTime=(Get-Date).AddHours(-24) } ``` A spike in failed RDP logons should trigger a review of: - direct public RDP exposure; - source-IP restrictions; - administrator usernames; - password and lockout policy; - stale accounts; - patch state; - whether the server should be reachable directly at all. Do not rely on account lockout alone as an anti-brute-force control. ## Step 13: enable useful PowerShell logging PowerShell Script Block Logging records processed script blocks in the Microsoft-Windows-PowerShell/Operational log and can improve incident visibility. Enable it through Group Policy where appropriate. A policy registry configuration is also available: ```powershell $basePath = 'HKLM:\SOFTWARE\Policies\Microsoft\Windows\PowerShell\ScriptBlockLogging' New-Item -Path $basePath -Force | Out-Null Set-ItemProperty -Path $basePath -Name EnableScriptBlockLogging -Value 1 ``` PowerShell logs can contain sensitive values if scripts include tokens, passwords, or connection strings. Design log access and retention accordingly. ## Step 14: remove unnecessary roles and services carefully Reducing unnecessary components lowers attack surface, but randomly disabling services can break applications or management functions. List running services: ```powershell Get-Service | Where-Object Status -eq 'Running' | Sort-Object Name | Format-Table Name, DisplayName ``` Before disabling a role or service: 1. Identify what installed it. 2. Confirm whether Windows or the application uses it. 3. Review Microsoft or vendor documentation. 4. Create a recovery point if the change is material. 5. Change one component at a time. 6. Reboot if required. 7. Test the complete workload. For example, disable Print Spooler only on servers that truly do not print and do not run accounting, ERP, PDF, or other software that depends on printing components. ## Step 15: do not disable IPv6 as generic hardening Do not disable IPv6 simply because the server primarily uses IPv4. Windows components can depend on IPv6 behavior, and an unnecessary change can create difficult networking and domain-service problems. Leave IPv6 enabled unless the network design has a specific documented requirement and the workload has been tested after the change. ## Step 16: make patching part of hardening A server with strong firewall and account settings is still exposed if known vulnerabilities remain unpatched. Use a controlled patch process: - review Microsoft release health and security guidance; - prioritize actively exploited vulnerabilities and exposed affected roles; - verify backup and rollback readiness; - patch during a planned maintenance window; - reboot intentionally when required; - verify Windows and the actual hosted application afterward. For the complete production workflow, see [Windows Server Patch Management Best Practices](/windows-server/windows-update-strategy). ## Step 17: keep backups separate from security configuration Backups and hardening solve different problems. Security controls reduce the probability and impact of compromise; backups give you a recovery path when prevention fails or a hardening change causes damage. A practical production recovery model includes: - application-aware backups where required; - VM or disk-level recovery points; - at least one copy outside the live server; - protected recovery credentials; - documented retention; - periodic restore testing. A snapshot is valuable for short-term rollback. It does not replace ransomware-resistant or off-server backups. See [Windows VPS Backup Strategy for Small Businesses](/windows-server/windows-vps-backup-strategy-small-business). ## Step 18: document each security change and its rollback Keep a short hardening changelog: | Field | Example | |---|---| | Date | Change date | | Control | Required NLA for RDP | | Owner | Windows administrator | | Reason | Reduce unauthenticated RDP exposure | | Validation | RDP login tested through approved path | | Rollback | Restore previous policy or recovery point | This prevents a future administrator from undoing a control simply because nobody remembers why it exists. ## Recommended hardening order for an existing Windows VPS For an already-running server, use an order that minimizes lockout risk: 1. Confirm backups, recovery point, and emergency access. 2. Audit users and Administrators membership. 3. Review account and lockout policy. 4. Confirm Windows Firewall is enabled. 5. Reduce direct RDP exposure and confirm NLA. 6. Move persistent external access behind RD Gateway, VPN, private access, or source restriction where appropriate. 7. Verify SMBv1 is disabled and review SMB signing and TCP 445 exposure. 8. Confirm Defender protection is active. 9. Deploy unique local admin password management such as Windows LAPS where supported. 10. Enable useful audit policy and sufficient log retention. 11. Review PowerShell logging. 12. Patch Windows and exposed applications. 13. Remove unnecessary services and roles carefully. 14. Verify backups and restore procedures. 15. Compare the result with Microsoft's role-appropriate security baseline. 16. Re-test RDP, RDS, IIS, SQL Server, file shares, business software, and automation used by the server. ## Common Windows Server hardening mistakes ### Exposing TCP 3389 broadly and relying only on a strong password Reduce who can reach RDP. NLA, source restrictions, RD Gateway, VPN or private access, and monitoring provide stronger layers than password strength alone. ### Changing the RDP port and calling the server hardened A non-default port can reduce noise but does not change the underlying authentication or authorization boundary. ### Applying a security baseline without testing the workload Baselines deliberately change authentication, SMB, RDP, auditing, credential, and protocol behavior. Test the server role and application workflow before production rollout. ### Disabling Windows Firewall to fix connectivity Fix the specific application listener or firewall rule rather than making the server broadly reachable. ### Re-enabling SMBv1 for an old device Treat the device or application as a legacy dependency that needs replacement or isolation. ### Reusing the same local administrator password across servers Use unique credentials and Windows LAPS or another controlled password-management process where supported. ### Enforcing Defender controls without testing business software ASR and Controlled Folder Access can block legitimate workflows. Test before enforcement. ### Disabling services because the names look unfamiliar Unknown does not mean unnecessary. Research the component, change one item, and validate the workload. ### Calling a checklist compliant This article is operational guidance, not certification. CIS Benchmarks, DISA STIGs, PCI DSS, HIPAA-related controls, ISO 27001 programs, and other frameworks require their own scope, evidence, governance, and validation. ## Raff's role in Windows Server security Raff provides the Windows VM and cloud infrastructure controls around it. Hardening the guest operating system, users, RDP/RDS design, applications, patch policy, and application-aware backups remains an administrator responsibility unless a separate managed service explicitly covers that work. For a small production Windows workload, focus on repeatable secure defaults: restricted administration, Windows Firewall, current patches, Defender, modern SMB, unique local admin credentials, meaningful logs, tested backups, and documented changes. :::cta Deploy Windows Now Deploy a Windows VM, then apply a role-appropriate hardening baseline before moving the workload into production. ::: ## Frequently asked questions ### What is Windows Server hardening? Windows Server hardening is the process of reducing unnecessary attack surface and strengthening authentication, networking, endpoint protection, logging, patching, and recovery controls while keeping the required workload functional. ### What should I harden first on a Windows VPS? Start with recovery access, administrator accounts, direct RDP exposure, Windows Firewall, NLA, Defender, SMB, patching, and backups. These controls usually reduce more practical risk than cosmetic changes such as renaming services or changing ports alone. ### Should I expose RDP directly to the internet? Avoid broad direct RDP exposure when a safer access path is practical. Use source-IP restrictions for narrow administrative access or consider RD Gateway, VPN, or private networking for persistent remote access. Keep NLA enabled and monitor failed logons. ### Is Windows Server 2025 secure by default? Windows Server 2025 includes stronger defaults and modern security features, but production hardening is still required. Microsoft provides an OSConfig security baseline with more than 300 settings and role-specific scenarios for domain controllers, member servers, and workgroup member servers. ### Should SMBv1 be enabled on Windows Server? No for normal modern deployments. SMBv1 is a legacy protocol with significant security weaknesses. Upgrade, replace, or isolate dependencies that still require it instead of enabling it broadly. ### What is Windows LAPS used for? Windows LAPS automatically manages a local administrator password and backs it up through supported Active Directory or Microsoft Entra management scenarios. Its purpose is to prevent static or reused local administrator credentials across managed servers and devices. ### Is this checklist the same as a CIS Benchmark or compliance standard? No. This checklist is practical operational guidance. Formal hardening and compliance standards have their own control sets, evidence requirements, exceptions, testing, and governance. ## Validation scope This article was revalidated on **September 11, 2026** against current Microsoft documentation for Windows Server 2025 OSConfig security baselines, Windows LAPS, SMB security, Network Level Authentication, and Remote Desktop Gateway architecture. The existing Raff screenshots and command checks remain tied to the May 24, 2026 Windows Server 2025 lab described above. No new September 2026 end-to-end hardening lab run is claimed. ## What's next - [Remote Desktop Gateway vs Direct RDP](/windows-server/remote-desktop-gateway-vs-direct-rdp) - [Configure Windows Firewall on a Windows VPS](/windows-server/configure-windows-firewall) - [Windows Server Patch Management Best Practices](/windows-server/windows-update-strategy) - [Windows LAPS on Windows Server 2025](/windows-server/windows-laps-windows-server-2025) - [Windows VPS Backup Strategy for Small Businesses](/windows-server/windows-vps-backup-strategy-small-business) - [Multi-User RDP vs RDS](/windows-server/multi-user-rdp-vs-rds) - [Raff Windows VM](/products/windows-vm) - [Raff Windows Server Hub](/windows-server) ## Sources - Microsoft Learn - Windows Server 2025 security baselines with OSConfig: https://learn.microsoft.com/en-us/windows-server/security/osconfig/osconfig-how-to-configure-security-baselines - Microsoft Learn - Microsoft Security Compliance Toolkit: https://learn.microsoft.com/en-us/windows/security/operating-system-security/device-management/windows-security-configuration-framework/security-compliance-toolkit-10 - Microsoft Learn - Windows Firewall: https://learn.microsoft.com/en-us/windows/security/operating-system-security/network-security/windows-firewall/ - Microsoft Learn - Remote Desktop and Network Level Authentication: https://learn.microsoft.com/en-us/windows-server/remote/remote-desktop-services/remotepc/remote-desktop-allow-access - Microsoft Learn - Remote Desktop Services overview: https://learn.microsoft.com/en-us/windows-server/remote/remote-desktop-services/overview - Microsoft Learn - Ports used by Remote Desktop Services: https://learn.microsoft.com/en-us/troubleshoot/windows-server/remote/ports-used-by-rds - Microsoft Learn - SMB security hardening: https://learn.microsoft.com/en-us/windows-server/storage/file-server/smb-security-hardening - Microsoft Learn - Control SMB signing behavior: https://learn.microsoft.com/en-us/windows-server/storage/file-server/smb-signing - Microsoft Learn - Windows LAPS overview: https://learn.microsoft.com/en-us/windows-server/identity/laps/laps-overview - Microsoft Learn - Advanced audit policy configuration: https://learn.microsoft.com/en-us/windows-server/identity/ad-ds/plan/security-best-practices/advanced-audit-policy-configuration - Microsoft Learn - PowerShell logging: https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_logging - CISA - Known Exploited Vulnerabilities Catalog: https://www.cisa.gov/known-exploited-vulnerabilities-catalog - Sources revalidated: 2026-09-11 --- ### Server Migration Checklist for Windows Server (2026) URL: https://rafftechnologies.com/windows-server/windows-server-migration-checklist-small-business Description: Use this 2026 server migration checklist to move a Windows Server safely. Plan applications, files, SQL Server, Active Directory, RDP/RDS, backups, cutover, rollback, and post-migration validation. ## In short A **server migration checklist** should answer five questions before production moves: what the current Windows Server does, what must move, how the destination will be built, how users will be tested, and exactly how you will roll back if cutover fails. Raff Technologies recommends a side-by-side migration for many small-business Windows workloads because the old server can remain available while the new Windows VM is built, tested, synchronized, and validated. Do not treat migration as a file-copy task. A Windows Server can contain Active Directory, DNS, RDS, SQL Server, IIS, business applications, scheduled tasks, certificates, printers, service accounts, file shares, backup jobs, and integrations that fail independently. For most small businesses, the safe order is: ```text Inventory -> classify workloads -> choose migration method -> build destination -> protect source -> migrate and test -> freeze writes -> final sync -> cut over -> validate users -> keep rollback -> monitor ``` If the source is **Windows Server 2016**, extended support ends on **January 12, 2027**. Start compatibility testing and migration planning before that date rather than treating the support deadline as the project start date. ## Server migration checklist for small businesses Use this as the control list for the project. | Phase | Checklist item | |---|---| | Scope | List every server role, application, database, share, user, service account, certificate, and dependency | | Destination | Decide whether the target is a new physical server, Windows VM, or hybrid environment | | Migration method | Choose in-place upgrade, side-by-side migration, clean rebuild, or role-specific migration | | Access | Plan RDP, RDS, RD Gateway, VPN/private access, DNS, firewall rules, and user authentication | | Applications | Confirm vendor support, installers, versions, licences, service accounts, and data locations | | Files | Inventory shares, NTFS permissions, mapped drives, open files, storage use, and growth | | Databases | Plan SQL Server backup/restore, logins, jobs, connection strings, permissions, and validation | | Active Directory | Review DC health, DNS, FSMO roles, GPOs, replication, DHCP, and time synchronization | | Protection | Take source backups and verify a restore path before migration work starts | | Testing | Test real business workflows, not only server boot or administrator login | | Cutover | Freeze writes, run final sync, switch users and endpoints, then validate | | Rollback | Define the rollback trigger, owner, deadline, data handling, and old-server state | | Monitoring | Watch CPU, RAM, disk, backups, authentication, services, jobs, and user issues after cutover | | Documentation | Record credentials, access paths, licences, backup ownership, support contacts, and recovery steps | ![Roadmap visual showing Windows Server migration phases from inventory to cutover and monitoring](https://raff-images.s3.raffusercloud.com/windows_server_migration_phases_roadmap_webp_5265197bcc.png) The goal is not zero change. The goal is controlled change with enough evidence to know when the destination is ready. :::cta Talk to Windows Engineer Planning a Windows Server migration? Review the source roles, applications, users, storage, licensing, cutover, and rollback path before moving production. ::: ## Choose the migration method before building the destination Microsoft distinguishes several Windows Server upgrade and migration methods, including in-place upgrade, clean install, migration to another server, and cluster rolling upgrade. Starting with Windows Server 2025, supported nonclustered systems can upgrade across as many as four Windows Server versions in one supported path, subject to edition, role, application, and platform restrictions. That does **not** mean every server should be upgraded in place. | Approach | What it does | Best fit | |---|---|---| | In-place upgrade | Installs a newer Windows Server version over the existing OS while retaining supported roles, settings, and data | Simple healthy member or application server where the workload supports the target OS | | Side-by-side migration | Builds a separate destination and moves roles, apps, data, and users to it | Cloud moves, hardware replacement, mixed-role servers, cleaner rollback | | Clean rebuild | Installs the destination from scratch and recreates only required services | Poorly documented, unstable, or heavily cluttered legacy servers | | Role-specific migration | Uses Microsoft or vendor-supported migration workflows for services such as file server, AD DS, DHCP, IIS, or RDS | Infrastructure roles with their own migration requirements | | Cluster rolling upgrade | Upgrades supported cluster nodes in sequence | Supported failover-cluster scenarios where availability must be maintained | For small businesses moving an office server to a cloud Windows VM, **side-by-side migration is often the easiest method to test and reverse**. ![Architecture visual showing side-by-side Windows Server migration from old office server to cloud Windows VPS](https://raff-images.s3.raffusercloud.com/windows_server_side_by_side_migration_architecture_webp_85380d8f15.png) ### When in-place upgrade can make sense Consider it when: - the source server is healthy and well documented; - the server role supports the path; - every business application supports the target Windows Server version; - the hardware or virtualization platform supports the upgrade; - you have a verified full recovery path; - the required downtime is acceptable. ### When side-by-side migration is safer Prefer it when: - you are moving from local hardware to cloud infrastructure; - the server has several unrelated roles; - the source is old, undocumented, or unstable; - Active Directory is involved; - you want to change the storage or network architecture; - vendor software should be installed cleanly; - rollback simplicity matters. Microsoft's current role migration matrix specifically recommends migration rather than treating AD DS as an ordinary in-place upgrade case. ## Windows Server 2016 migrations now have a fixed deadline Windows Server 2016 reaches the end of extended support on **January 12, 2027**. That makes 2026 migration planning especially important for organizations still running Server 2016. A practical schedule is: 1. Inventory and application compatibility now. 2. Choose the target Windows Server release and destination architecture. 3. Build a test destination. 4. Run at least one migration rehearsal for critical applications or data. 5. Schedule production cutover with enough time for remediation before January 12, 2027. If your source is Server 2016, use the dedicated [Windows Server 2016 to 2025 migration guide](/windows-server/migrate-windows-server-2016-to-2025) for version-specific upgrade and AD DS guidance. ## Phase 1: inventory everything the current server does Most failed migrations are discovery failures first. Document: | Area | What to capture | |---|---| | Server identity | Hostname, IP addresses, OS/version/build, edition, activation, domain membership | | Windows roles | AD DS, DNS, DHCP, RDS, IIS, file services, print services | | Applications | Product, version, install path, vendor, licence, support status | | Users | Administrators, staff users, groups, service accounts | | Files | Shares, NTFS permissions, share permissions, mapped drives, storage use | | Databases | SQL instances, databases, jobs, maintenance plans, logins, linked servers | | Scheduled work | Scheduled Tasks, scripts, exports, sync jobs, backup jobs | | Certificates | IIS, RD Gateway, VPN, internal application certificates, expiry dates | | Network | Firewall rules, listening ports, DNS records, NAT, VPN/private paths | | Remote access | Admin RDP, RDS Session Host, RD Gateway, profiles, licensing | | Backups | Software, schedule, destination, retention, encryption, restore status | | Dependencies | Printers, scanners, mapped drives, APIs, SMTP, external shares, vendor services | Useful PowerShell inventory examples include: ```powershell Get-ComputerInfo | Select-Object WindowsProductName, WindowsVersion, OsBuildNumber Get-WindowsFeature | Where-Object InstallState -eq 'Installed' Get-Service | Where-Object Status -eq 'Running' Get-ScheduledTask | Where-Object State -ne 'Disabled' Get-SmbShare Get-NetFirewallRule -Enabled True ``` Do not delete or "clean up" the source during inventory. Record first, then decide what should change. ## Phase 2: classify each workload as migrate, rebuild, replace, or retire Not everything on the old server deserves to reach the new one. | Decision | Meaning | |---|---| | Migrate | Still required and should move with its supported migration method | | Rebuild | Still required, but should be installed cleanly on the destination | | Replace | Better handled by a newer SaaS, managed service, or architecture | | Retire | No longer used and should not consume destination resources | Examples: - Active accounting application: migrate or rebuild. - Old employee profile folders: archive or retire. - Current SQL database: migrate with a database-specific plan. - Legacy application with no Server 2025 support: replace, isolate, or choose a supported target OS. - Abandoned installer directories: retire. - Old local backup folders: replace with the new backup design. This step prevents a clean destination from becoming a copy of years of old server clutter. ## Phase 3: choose the destination from workload data Do not size a new Windows VM from the old server's marketing label alone. Record real use first: - peak CPU; - peak and available RAM; - used disk space; - storage growth; - peak concurrent RDP/RDS sessions; - database size and growth; - backup size; - busiest application periods. For remote-user workloads, use [Windows VPS sizing for remote users](/windows-server/windows-vps-sizing-remote-users). If you are deciding whether cloud hosting is appropriate at all, see [Cloud Windows Server vs Local Office Server](/windows-server/cloud-windows-server-vs-local-office-server). A migration is also a good time to stop placing every role on one Windows Server. Separate roles when it improves security, maintenance, performance isolation, recovery, or vendor support. For example: ```text VM 1: AD DS / DNS VM 2: RDS or business application VM 3: SQL Server when workload and licensing justify separation ``` Do not split roles just to make the diagram look more enterprise. Every extra server adds cost, patching, backup, and operational work. ## Phase 4: plan remote access before users move Remote access changes both architecture and licensing. | Access need | Planning direction | |---|---| | One or two administrators | Restricted administrative RDP may be sufficient | | Staff need daily shared desktop sessions | Use RDS Session Host and the correct hosted licensing model | | Users connect from changing locations | Consider RD Gateway or another controlled access layer | | Users need broad private network access | Consider VPN/private access rather than exposing multiple services publicly | | Users only need a web app | Avoid giving a full Windows desktop unnecessarily | | MSP manages several client servers | Standardize access policy, MFA approach, monitoring, and documentation | For external RDS access, compare [Remote Desktop Gateway vs direct RDP](/windows-server/remote-desktop-gateway-vs-direct-rdp). Do not use Windows Server's administrative Remote Desktop sessions as a substitute for a properly designed multi-user RDS deployment. ## Phase 5: protect the source and prove recovery Before the first major change, protect the environment you already have. | Recovery item | Why it matters | |---|---| | Whole-server backup | Recovery if migration work damages the source | | File backup | Restore shares and user data separately | | SQL/app backup | Consistent recovery for databases and business applications | | System State | Important for supported Windows infrastructure recovery scenarios | | Certificate export | Prevent loss of IIS, RD Gateway, or application identity material | | Configuration export | Preserve firewall, tasks, IIS, application, and role settings | | Restore test | Proves the backup is actually usable | A successful backup job is not a successful restore test. For a production Windows VM destination, review [Windows VPS Backup Strategy for Small Businesses](/windows-server/windows-vps-backup-strategy-small-business) before the cutover. ## Phase 6: build and harden the destination before production data arrives The new Windows Server should be ready before users depend on it. Prepare: - a supported Windows Server version; - correct CPU, RAM, and storage; - current Windows updates; - named administrator accounts; - Windows Firewall rules; - Defender or the approved endpoint-security stack; - remote access controls; - private networking where roles communicate internally; - backup and recovery settings; - monitoring; - DNS and hostname strategy; - application prerequisites; - licensing and activation path. Apply a role-appropriate [Windows Server hardening checklist](/windows-server/windows-server-hardening-checklist) before cutover, not weeks afterward. ## Phase 7: migrate file shares with permissions and paths in mind File migration failures often appear as user problems after cutover rather than copy errors during migration. Inventory: - share names; - NTFS ACLs; - share permissions; - security groups; - file ownership; - mapped drive letters; - UNC paths; - open files; - long paths and unusual filenames; - quotas; - application folders; - backup exclusions or policies. Microsoft's **Storage Migration Service** can inventory and transfer supported file-server data and configuration to newer Windows Server systems. Its workflow includes inventory, transfer, cutover, and post-migration operations. It applies to Windows Server 2025, 2022, 2019, and 2016 scenarios supported by the service. Use it when the file-server scope fits the tool. Do not treat Storage Migration Service as a universal migration engine for SQL Server, Active Directory, or third-party applications. ## Phase 8: migrate applications with vendor support as a hard gate A Windows migration can be technically successful while the business application is unsupported. For each application, confirm: | App item | What to verify | |---|---| | OS support | Does the vendor support the target Windows Server version? | | RDS support | Is multi-user or RemoteApp use supported? | | Installer | Do you have the correct supported installer? | | Licence | Does activation transfer to a new VM or hardware identity? | | Data | Where is production data stored and how is it moved? | | Services | Which Windows service accounts are required? | | Dependencies | .NET, ODBC, runtimes, drivers, Office components, Java, VC++ runtimes | | Printing | Are printer drivers, labels, PDF tools, or redirected printers required? | | Network | What ports, DNS names, UNC paths, APIs, or SMTP services are used? | | Recovery | How do you return users to the source if validation fails? | Test the actual workflow, such as opening a company file, posting a transaction, generating a report, printing, exporting, and closing the application cleanly. ## Phase 9: treat SQL Server as its own migration project SQL Server migration is more than moving `.mdf` and `.ldf` files. Plan: - SQL Server version and edition; - supported database upgrade path; - full, differential, and log backups as appropriate; - database owners; - compatibility level; - SQL and Windows logins; - login SIDs; - SQL Agent jobs; - maintenance jobs; - linked servers; - credentials; - certificates and keys; - Database Mail; - connection strings; - firewall ports; - backup jobs on the destination. For many small-business migrations, backup and restore provides a repeatable test path. Restore the database on the destination before production cutover and point a test application instance at it. Do not call the migration successful until the application, not only SSMS, can use the restored database. ## Phase 10: migrate Active Directory role by role If the old server is a domain controller, use a dedicated AD DS migration plan. Check: | AD area | What to verify | |---|---| | Domain controllers | Current DC list, OS versions, Global Catalog status | | Replication | `repadmin /replsummary` and `repadmin /showrepl` health | | DNS | Zones, forwarders, client DNS configuration, stale dependencies | | FSMO | Current role holders | | GPOs | Drive maps, scripts, security settings, software deployment | | DHCP | Scopes, reservations, options, failover, relay/IP helpers | | Time | PDC and upstream time-source design | | Certificates | AD CS or internal certificate dependencies | | Decommission | Graceful demotion and post-demotion validation | Microsoft's current role matrix lists AD DS migration as supported and says in-place upgrade is not the recommended approach for getting the newer AD DS performance and feature improvements. Build a clean newer DC, replicate, validate, move roles, then demote the old DC through the supported workflow. If the project is specifically Server 2016 to Server 2025, use [Upgrade Windows Server 2016 to 2025](/windows-server/migrate-windows-server-2016-to-2025) for the full DC path. ## Phase 11: create a migration test plan with business owners The administrator should not be the only person testing the destination. | Test area | Example acceptance test | |---|---| | Login | Intended users can sign in and unauthorized users cannot | | RDP/RDS | Remote sessions work from the expected locations | | Files | Users can open, edit, save, and create files with correct permissions | | Accounting/ERP | Approved transaction and reporting workflow succeeds | | SQL Server | Application connects and performs a safe business transaction | | IIS | Site loads, authentication works, API/database connections succeed | | Printing | Required printer, PDF, label, and redirected-print workflows work | | Scheduled tasks | Exports, sync jobs, reports, and scripts execute successfully | | Backups | Destination backup jobs complete | | Restore | At least one representative restore test succeeds | Include the people who actually use the workload. A server can look healthy to an administrator while the accounting team cannot print invoices or the warehouse cannot generate labels. ## Phase 12: write the cutover sequence before the maintenance window A production cutover should be a checklist, not a live brainstorming session. Example: 1. Notify users of the maintenance window. 2. Confirm the latest source backup and restore path. 3. Confirm destination backup is enabled. 4. Stop or freeze production writes where required. 5. Stop application services that would create conflicting writes. 6. Run the final file or database synchronization. 7. Restore or attach final application data on the destination. 8. Change DNS records, aliases, mapped drives, shortcuts, or connection strings. 9. Start destination services. 10. Validate administrator access. 11. Validate business-user access. 12. Test applications, files, reports, printing, jobs, and backups. 13. Decide go-forward or rollback before the agreed deadline. 14. Keep the old environment isolated or read-only until the new system is proven. ![Final Windows Server migration cutover checklist showing backups, apps, files, RDS, SQL, rollback, and monitoring](https://raff-images.s3.raffusercloud.com/windows_server_migration_cutover_checklist_webp_7471522113.png) ## Phase 13: define rollback before you need it Rollback is a planned recovery action, not an admission that the project failed. Document: | Rollback item | Question | |---|---| | Trigger | Which failures require rollback? | | Owner | Who can make the rollback decision? | | Deadline | How long can troubleshooting continue before recovery begins? | | New writes | What happens to data written to the destination after cutover starts? | | Old server | Is the source still intact and isolated from conflicting writes? | | DNS/access | How will users return to the old path? | | Communication | Who tells users and vendors that rollback is in progress? | Do not erase, repurpose, or permanently alter the old server immediately after the first successful login. ## Phase 14: monitor the first days after migration Watch both infrastructure and user behavior. | Signal | Why it matters | |---|---| | CPU | Detect undersizing and application spikes | | RAM | Identify RDS, browser, ERP, and SQL memory pressure | | Disk space | Prevent profile, database, file, and backup failures | | Storage latency | Detect application slowdowns hidden behind normal CPU use | | Backup success | Confirm the new recovery plan is working | | Failed logons | Find access problems and suspicious authentication activity | | Event logs | Catch services, drivers, certificates, and application errors | | Scheduled tasks | Verify reports, sync jobs, and automation survived the move | | SQL jobs | Confirm database maintenance and backups are running | | User reports | Detect workflow failures that technical monitoring cannot see | Migration is complete when the destination is stable, protected, documented, and users can complete normal work. ## Common server migration mistakes ### Copying files before understanding dependencies Inventory roles, applications, services, database connections, mapped drives, certificates, and scheduled tasks first. ### Upgrading every Windows Server in place In-place upgrade is a supported tool, not the default answer for every role. Side-by-side migration often provides cleaner testing and rollback, especially for cloud moves and mixed-role servers. ### Treating Active Directory like a normal application server Use a role-specific DC migration process and validate replication, DNS, FSMO, and client dependencies before demotion. ### Moving SQL databases but forgetting instance objects Databases, logins, jobs, linked servers, credentials, and server-level settings need separate attention. ### Moving daily users onto admin RDP Administrative RDP and a licensed RDS Session Host deployment are not the same thing. ### Forgetting vendor licensing Applications can fail after migration because activation is tied to hardware, hostname, MAC address, licence server, or vendor approval. ### Testing only whether the server boots Validate real business workflows with real users. ### Changing too many names and paths during the same cutover A migration already creates risk. Avoid unnecessary simultaneous changes to hostnames, drive letters, application versions, paths, authentication, and network design unless the project specifically requires them. ### Keeping no rollback window A source server removed immediately after cutover turns every post-migration issue into an emergency. ## How Raff fits a Windows Server migration Raff Windows VMs can be the destination when a business wants to move Windows workloads away from aging office hardware or another cloud VM while keeping a self-managed Windows Server model. Typical migration targets include: - RDP/RDS business application servers; - accounting and tax software; - IIS and ASP.NET applications; - SQL Server workloads; - Windows file-server workloads; - Active Directory and DNS where the architecture supports cloud-hosted DCs; - MSP-managed client servers. Raff provides the Windows VM infrastructure. Application compatibility, guest OS configuration, Microsoft and third-party licensing, role migration, testing, and production cutover still need to be planned for the actual workload. Use [Raff Windows VM](/products/windows-vm) and [pricing](/pricing) only after CPU, RAM, storage, user count, licensing, and backup requirements are understood. :::cta Explore Windows VM Build the destination Windows VM before cutover so applications, users, files, networking, backups, and rollback can be tested in parallel with the source environment. ::: ## Final pre-cutover checklist - [ ] Source server roles and dependencies documented - [ ] Migration method selected per workload - [ ] Vendor application support confirmed - [ ] Windows and application licensing reviewed - [ ] Source backup completed - [ ] Representative restore tested - [ ] Destination built and patched - [ ] Destination hardening completed - [ ] Destination backups enabled - [ ] RDP/RDS/RD Gateway access model tested - [ ] File permissions validated - [ ] SQL databases and server-level dependencies tested - [ ] AD/DNS/DHCP migration validated if applicable - [ ] Printers, reports, exports, integrations, and scheduled tasks tested - [ ] Final synchronization method rehearsed - [ ] Cutover window approved - [ ] Rollback trigger and owner documented - [ ] Old server preservation period defined - [ ] Post-migration monitoring owner assigned If one of these items is unknown, resolve it before production cutover. ## Frequently asked questions ### What is a server migration checklist? A server migration checklist is the documented sequence used to inventory a source server, choose the migration method, protect data, build and test the destination, perform cutover, validate users and applications, and roll back safely if required. ### Is side-by-side migration safer than an in-place upgrade? Often, especially when moving to new hardware or a cloud Windows VM. Side-by-side migration keeps the source available during testing. In-place upgrade can still be appropriate for a healthy supported member or application server with a verified recovery path. ### Can Windows Server 2016 upgrade directly to Windows Server 2025? Yes in supported nonclustered scenarios using the appropriate Windows Server 2025 upgrade path. The server role and application support still matter. For Active Directory domain controllers, Microsoft recommends a migration approach with a clean newer DC rather than treating AD DS as a normal in-place upgrade. ### When does Windows Server 2016 support end? Windows Server 2016 extended support ends on January 12, 2027. Organizations still running it should complete compatibility testing and migration planning before that date. ### Can I migrate a Windows file server without changing every user path? Microsoft Storage Migration Service can migrate supported file-server data and configuration and provides cutover capabilities designed to reduce client-side changes. Whether identity takeover is appropriate depends on the migration design and environment. ### Should I keep the old server after migration? Keep it available according to the written rollback plan until the new environment has passed technical and business validation. Prevent conflicting writes if both environments remain online. ### What should be tested after a Windows Server migration? Test user authentication, RDP/RDS, file permissions, business applications, SQL connectivity, reports, printing, certificates, integrations, scheduled tasks, backups, and at least one representative restore workflow. ## Validation scope This article was revalidated on **September 11, 2026** against Microsoft's current Windows Server upgrade and migration guidance, role migration matrix, Storage Migration Service documentation, and Windows Server 2016 lifecycle information. This is a planning checklist, not a claim that one synthetic lab reproduces every production migration. Application support, data size, directory health, networking, licensing, certificates, and recovery requirements vary by environment. ## What's next - [Upgrade Windows Server 2016 to 2025](/windows-server/migrate-windows-server-2016-to-2025) - [Cloud Windows Server vs Local Office Server](/windows-server/cloud-windows-server-vs-local-office-server) - [Windows VPS Sizing for Remote Users](/windows-server/windows-vps-sizing-remote-users) - [Windows VPS Backup Strategy for Small Businesses](/windows-server/windows-vps-backup-strategy-small-business) - [Remote Desktop Gateway vs Direct RDP](/windows-server/remote-desktop-gateway-vs-direct-rdp) - [Windows Server Hardening Checklist](/windows-server/windows-server-hardening-checklist) - [Raff Windows VM](/products/windows-vm) - [Raff Pricing](/pricing) ## Sources - Microsoft Learn - Plan Your Windows Server Upgrade Path: https://learn.microsoft.com/en-us/windows-server/get-started/install-upgrade-migrate - Microsoft Learn - Upgrade and migrate roles and features in Windows Server: https://learn.microsoft.com/en-us/windows-server/get-started/upgrade-migrate-roles-features - Microsoft Learn - Storage Migration Service overview: https://learn.microsoft.com/en-us/windows-server/storage/storage-migration-service/overview - Microsoft Learn - Migrate a file server using Storage Migration Service: https://learn.microsoft.com/en-us/windows-server/storage/storage-migration-service/migrate-data - Microsoft Learn - Ending Support in 2027: https://learn.microsoft.com/en-us/lifecycle/end-of-support/end-of-support-2027 - Microsoft Learn - RDS Client Access Licenses: https://learn.microsoft.com/en-us/windows-server/remote/remote-desktop-services/rds-client-access-license - Microsoft Learn - SQL Server backup and restore: https://learn.microsoft.com/en-us/sql/relational-databases/backup-restore/back-up-and-restore-of-sql-server-databases - Microsoft Learn - Manage FSMO roles: https://learn.microsoft.com/en-us/windows-server/identity/ad-ds/manage/manage-fsmo-roles - Sources revalidated: 2026-09-11 --- ### Server Migration to Cloud: Local Windows Server Guide (2026) URL: https://rafftechnologies.com/windows-server/local-server-to-cloud-windows-vps-migration Description: Move a local Windows Server to the cloud with a staged migration plan for apps, files, SQL Server, AD, RDS, licensing, backups, cutover, rollback, and validation. ## In short A **server migration to cloud** project should move the business workload, not just the files on a physical server. For a local Windows Server, that means inventorying roles, applications, databases, users, file shares, licences, certificates, scheduled tasks, devices, and remote-access requirements before production data moves. For many small-business migrations, Raff Technologies recommends a **side-by-side approach**: keep the local server available, build the cloud Windows Server separately, test real workflows, complete a final synchronization, cut users over, and retain a controlled rollback path until the new environment is proven. This guide is specifically for moving a **local or office Windows Server to a cloud Windows VM**. For a broader migration control list that also applies to cloud-to-cloud and version-to-version projects, use [Server Migration Checklist for Windows Server](/windows-server/windows-server-migration-checklist-small-business). If you are still deciding whether the server should leave the office at all, start with [Cloud Windows Server for Small Business](/windows-server/cloud-windows-server-vs-local-office-server). ## Should you migrate a local Windows Server to the cloud? A cloud migration is a strong candidate when the existing office server is aging, remote users depend on it, several locations need the same Windows workload, or hardware replacement is approaching. ![Comparison visual showing local office server model versus cloud Windows VPS model for users, apps, files, and backups](https://raff-images.s3.raffusercloud.com/local_server_vs_cloud_windows_vps_operating_model_webp_cc659df50a.png) | Situation | Cloud migration fit | What to verify first | |---|---|---| | Office server is aging or out of warranty | Strong candidate | Application compatibility, storage, backup, target Windows version | | Remote users depend on business software | Strong candidate | RDS model, licensing, latency, printers, user profiles | | Several offices need one shared Windows system | Strong candidate | Internet continuity, access design, application behavior | | Server hosts file shares | Good candidate | Permissions, mapped paths, file size, open files, access method | | Server hosts SQL Server | Good candidate after database planning | SQL version, logins, jobs, backups, I/O, connection strings | | Server is a domain controller | Requires role-specific planning | AD replication, DNS, FSMO, time, demotion path | | Workload depends on USB, serial, scanning, or industrial hardware | Test carefully | Redirection, vendor support, local dependency | | Users work only on one fast LAN | Depends | Whether cloud solves a real operational problem | | User internet connectivity is unreliable | Risky without mitigation | Secondary connectivity or hybrid/local design | | Workload requires high availability | Architecture project | Do not treat one cloud VM as the whole HA design | Cloud infrastructure removes the need to own the physical server, but it does not remove responsibility for Windows, applications, users, security, backups, or licensing. :::cta Talk to Windows Engineer Review your current Windows Server roles, applications, users, storage, RDS model, licensing, and recovery requirements before choosing the cloud destination. ::: ## What actually moves in an office-server migration A long-running office server usually contains more dependencies than its administrator remembers. Treat discovery as a technical deliverable. | Migration area | Examples | |---|---| | Server roles | AD DS, DNS, DHCP, file services, IIS, RDS, print services | | Applications | Accounting, tax, ERP, inventory, Access, custom Windows software | | Databases | SQL Server, vendor databases, Access back ends | | Users and identities | Administrators, staff accounts, groups, service accounts | | File shares | SMB shares, NTFS permissions, mapped drives, ownership | | Remote access | Admin RDP, RDS Session Host, RD Gateway, VPN/private access | | Scheduled work | Tasks, exports, scripts, maintenance jobs, integrations | | Certificates | IIS, RD Gateway, application TLS certificates | | Network dependencies | DNS names, IPs, firewall rules, SMTP, APIs, UNC paths | | Devices | Printers, scanners, label printers, USB/serial devices | | Recovery | Server backup, file backup, database backup, restore procedures | If the server has been in service for years, assume hidden dependencies exist until the inventory proves otherwise. ## Side-by-side migration keeps testing and rollback separate from production Microsoft distinguishes **migration**, where roles and features move to another server, from **in-place upgrade**, where a newer Windows Server version is installed over the existing system. Microsoft's current role matrix also makes clear that some Windows Server roles support migration differently from in-place upgrade. For many local-to-cloud SMB projects, Raff uses side-by-side migration as the default planning pattern because it lets the destination be validated before the source is retired. ![Architecture visual showing side-by-side migration from a local office server to a cloud Windows VPS](https://raff-images.s3.raffusercloud.com/local_server_cloud_vps_side_by_side_migration_webp_8767b51646.png) ```text Local Windows Server stays available -> Cloud Windows Server is built separately -> Roles, apps and data are migrated or rebuilt -> Users test the new environment -> Final synchronization is completed -> Production access switches to the cloud server -> Old server remains controlled for rollback -> Source is retired only after validation ``` Side-by-side is not automatically correct for every role. Use Microsoft or vendor-specific migration procedures for Active Directory, SQL Server, RDS, IIS, file services, and third-party business applications. ## Phase 1: inventory the local Windows Server Document the current system before changing it. | Area | Capture | |---|---| | Server identity | Hostname, Windows Server version/build, edition, IPs, domain/workgroup | | Installed roles | AD DS, DNS, DHCP, RDS, IIS, file services, print services | | Applications | Product, version, installer, vendor, support status, licence model | | Users | Administrators, employees, groups, service accounts | | Files | Shares, ACLs, mapped paths, capacity, growth, open-file behavior | | SQL Server | Instances, databases, recovery models, logins, jobs, linked servers | | Tasks and services | Scheduled Tasks, Windows services, scripts, exports, sync jobs | | Certificates | Purpose, subject, expiry, private-key availability | | Network | Listening ports, firewall rules, DNS records, NAT/VPN dependencies | | Devices | Printers, scanners, dongles, serial devices, label hardware | | Backups | Tool, schedule, retention, destination, encryption, last restore test | Useful inventory commands can include: ```powershell Get-ComputerInfo | Select-Object WindowsProductName, WindowsVersion, OsBuildNumber Get-WindowsFeature | Where-Object InstallState -eq 'Installed' Get-Service | Where-Object Status -eq 'Running' Get-ScheduledTask | Where-Object State -ne 'Disabled' Get-SmbShare Get-NetFirewallRule -Enabled True ``` Do not remove accounts, services, folders, or applications during discovery. Record first, then classify. ## Phase 2: classify each item as migrate, rebuild, replace, or retire Use four buckets: | Decision | Meaning | |---|---| | Migrate | Still required and has a supported move path | | Rebuild | Still required, but should be installed/configured cleanly | | Replace | Better handled by another product, SaaS service, or architecture | | Retire | No longer required and should not move | A cloud migration is an opportunity to stop carrying abandoned installers, stale users, obsolete shares, and unsupported applications into the next server. Examples: - Active company files: migrate. - Current business application: rebuild or migrate according to vendor guidance. - SQL Server database: migrate with a database-specific plan. - Old employee accounts: disable or exclude after ownership review. - Unsupported legacy utility: replace or isolate. - Old local backup archives: retain according to policy, but do not confuse them with the new recovery design. ## Phase 3: choose the destination Windows Server version and licensing model Windows Server 2025 is Microsoft's current LTSC release, but that does not mean every application should move to it immediately. Choose the destination OS from the **application and role support matrix**. For each workload, verify: 1. Which Windows Server versions the vendor supports. 2. Whether RDS or multi-user use is supported. 3. Whether SQL Server or another database has its own version requirements. 4. Whether drivers, printers, scanners, or legacy components support the target OS. 5. Whether the chosen server roles have a supported migration path. Use [Windows Server Version Comparison](/windows-server/windows-server-version-comparison) for the OS decision. For Raff, production Windows Server licensing generally follows one of two paths: - **Raff-provided SPLA licensing**; or - **eligible customer BYOL** under the customer's applicable Microsoft agreement and outsourcing rights. Do not plan a production migration around a Windows Server Evaluation image. Use [Windows Server Licensing on Raff](/windows-server/windows-licensing) for the current SPLA, BYOL, CAL, and RDS licensing model. ## Phase 4: size the cloud Windows Server from real workload data Do not copy the physical server's CPU and RAM numbers blindly, and do not choose a VM solely from employee count. Collect or estimate: - peak concurrent users; - CPU use during important workflows; - available and committed memory; - current disk use and growth; - database size and growth; - backup size and retention; - active RDP/RDS sessions; - user-profile growth; - busiest reporting or month-end periods; - application-specific I/O requirements. For remote desktop workloads, use [Windows VPS Sizing for Remote Users](/windows-server/windows-vps-sizing-remote-users), which maps workload targets to **current Raff VM tiers**. This avoids treating theoretical configurations as live SKUs. Use [Raff Pricing](/pricing) only after CPU, memory, storage, licensing, and backup requirements are known. :::cta View Pricing Compare current Raff Windows VM plans after you have estimated concurrency, CPU, memory, storage, licensing, and recovery needs. ::: ## Phase 5: design admin RDP, RDS, and remote access before cutover Administrative Remote Desktop and daily employee desktop access are different use cases. | Access need | Planning direction | |---|---| | One or two administrators maintain the server | Restricted administrative RDP may be sufficient | | Employees need shared desktop sessions | Plan RD Session Host | | Employees need published Windows applications | Plan RemoteApp/RDS architecture | | Users connect from public networks | Consider RD Gateway or another controlled access layer | | Users need several private services | Consider VPN/private networking rather than publishing each service | | Users only consume an IIS application | Use HTTPS rather than full desktop access | Microsoft's customer-owned RDS model requires compatible RDS CALs for users or devices connecting to RD Session Host. Raff-hosted SPLA deployments use the applicable service-provider licensing model, including RDS User SALs where RDS is consumed. Use [RDS CAL Licensing Guide](/windows-server/rds-cal-licensing-guide) and [Remote Desktop Gateway vs Direct RDP](/windows-server/remote-desktop-gateway-vs-direct-rdp) before production access is opened. ## Phase 6: back up the source and prove the restore path Before migration changes begin, protect the local server. Verify the layers that match the workload: | Recovery layer | Purpose | |---|---| | Whole-server backup | Recover the original system after a failed change | | File backup | Restore shares and business documents independently | | SQL/database backup | Recover databases consistently | | System State | Support relevant Windows infrastructure recovery scenarios | | Application-specific backup | Preserve vendor application data and configuration | | Certificate export | Preserve private keys required by IIS, RD Gateway, or apps | | Configuration export | Preserve tasks, firewall rules, IIS settings, app configuration | | Restore test | Prove that recovery actually works | Do not use “backup completed successfully” as the only recovery test. Restore representative data before the production cutover. Define two business targets: - **RPO**: how much recent data can the business afford to lose? - **RTO**: how long can the workload remain unavailable? Those targets should drive backup frequency, retention, and cutover planning. ## Phase 7: build and harden the cloud destination first The new server should be production-ready before production data arrives. Prepare: - supported Windows Server image; - named administrator accounts; - correct Windows licensing path; - Windows updates; - Windows Firewall rules; - Microsoft Defender or the approved endpoint-security configuration; - RDP/RDS/RD Gateway access model; - private networking where required; - storage layout; - backup configuration; - monitoring; - DNS and naming plan; - application prerequisites; - documentation and recovery access. Use the [Windows Server Hardening Checklist](/windows-server/windows-server-hardening-checklist) before users depend on the destination. ## File-server migration: preserve permissions and paths, not only bytes For a file server, inventory: - share names; - NTFS permissions; - share permissions; - local groups used by ACLs; - mapped-drive letters; - UNC paths embedded in applications; - open files; - quotas; - long paths; - archive data; - backup exclusions and policies. Microsoft's **Storage Migration Service** supports Windows Server 2025, 2022, 2019, and 2016 migration scenarios. Its workflow inventories source data, transfers files and configuration, and supports cutover to a Windows Server destination. It is a file-server migration tool, not a universal migration engine. Microsoft specifically notes that Storage Migration Service does **not** migrate domain controllers as domain controllers. ![File migration visual showing shared folders, NTFS permissions, mapped drives, and final sync moving from local server to Windows VPS](https://raff-images.s3.raffusercloud.com/local_server_file_share_migration_to_windows_vps_webp_c8c613e56e.png) For a file-centric project, use [File Server Migration to Windows VPS](/windows-server/file-server-migration-to-windows-vps) for the dedicated workflow. ## Business-application migration: vendor support is a hard gate An installer launching on the new Windows Server does not prove that the production architecture is supported. For each application, verify: | Item | Question | |---|---| | Windows Server support | Does the exact application release support the target OS? | | Hosted/virtualized use | Does the vendor support the application on a hosted VM? | | RDS support | Can the application run in multiple RDS sessions if required? | | Licence transfer | Does activation move to a new server identity? | | Data location | Where is the live production data stored? | | Database dependency | Which SQL/database version and configuration are required? | | Services | Which service accounts and Windows services are required? | | Devices | Are printers, scanners, USB, serial, or dongles required? | | Integrations | Which APIs, SMTP services, exports, mapped paths, or Office components are used? | | Recovery | How is the application restored and validated? | Test real workflows, not only startup. Create or edit a record, generate a report, print or export, close and reopen the application, and verify the backup/restore process. Use [Windows VPS for Business Software](/windows-server/windows-vps-for-business-software) for architecture and compatibility planning. ## SQL Server migration: move server-level dependencies too SQL Server migration is not complete when the `.mdf` file reaches the destination. Plan: - SQL Server version and edition; - database compatibility; - recovery model; - full/differential/log backups where applicable; - SQL and Windows logins; - login SIDs and orphaned-user handling; - SQL Agent jobs; - linked servers; - credentials and certificates; - Database Mail; - maintenance jobs; - connection strings; - firewall access; - destination backup jobs. For many SMB workloads, backup and restore provides a repeatable way to test the database on the new server before final cutover. Validate the **application against the restored database**, not just database connectivity from SSMS. Use [SQL Server Migration to Windows VPS](/windows-server/sql-server-migration-to-windows-vps) for the database-specific procedure and [SQL Server Backup Strategy](/windows-server/mssql-backup-strategy) for recovery planning. ## Active Directory migration needs its own DC plan If the local office server is a domain controller, do not treat it like an ordinary application server or use Storage Migration Service as the DC migration method. Check: | AD area | Validate | |---|---| | Replication | `repadmin /replsummary` and `repadmin /showrepl` are healthy | | DNS | Zones, forwarders, client DNS settings, stale dependencies | | FSMO roles | Current role holders are documented | | Global Catalog | Correct DCs provide GC where required | | GPOs | Drive maps, scripts, security policy, software deployment | | DHCP | Scopes, reservations, options, failover, relays | | Time | PDC Emulator and upstream time-source design | | Applications | LDAP, DNS, hard-coded DC names, service-account dependencies | | Decommission | Graceful demotion and post-demotion validation | A common side-by-side AD path is to build a supported new DC, allow replication, validate DNS and directory health, move required roles, update dependencies, and then demote the old DC through Microsoft's supported process. For AD topology validation, use [Active Directory Replication Topology](/windows-server/ad-replication-topology). ## Test from the locations and accounts that will actually use the server Do not let the administrator be the only tester. | Test area | Acceptance example | |---|---| | Office user | Can authenticate and complete normal work | | Remote user | Can connect from the real remote location | | Admin access | Approved administration path works | | RDS | User session opens with intended profile and policy | | Files | Open, edit, create, rename, and save with correct permissions | | Business app | Representative transaction or workflow succeeds | | SQL | Application connects and completes expected operations | | Printing | Required printers, PDF output, and labels work | | Integrations | Email, exports, APIs, scheduled syncs work | | Backup | Destination backup completes | | Restore | Representative restore succeeds | Run tests with normal user permissions. Administrator success can hide permission and profile problems that production users will encounter. ## Cutover runbook: freeze, synchronize, switch, validate Write the sequence before the maintenance window. 1. Notify users and confirm the downtime window. 2. Confirm current source backup and restore path. 3. Confirm destination backup and recovery access. 4. Stop or freeze production writes where necessary. 5. Stop services that could create conflicting writes. 6. Run the final file synchronization or database backup/restore. 7. Update DNS, aliases, mapped drives, shortcuts, or connection strings. 8. Start required services on the cloud Windows Server. 9. Validate administrator access. 10. Validate a representative business user. 11. Test files, applications, SQL, reports, printing, scheduled work, and backups. 12. Decide whether to continue or roll back before the agreed decision point. 13. Keep the old server isolated from conflicting writes while rollback remains available. ![Pre-cutover checklist visual for moving a local office server to a cloud Windows VPS](https://raff-images.s3.raffusercloud.com/local_server_cloud_vps_cutover_checklist_webp_ede0671677.png) The cutover should be an execution checklist, not the first time the team decides how data will move. ## Define rollback before production switches A rollback plan should specify: | Item | Question | |---|---| | Trigger | Which failures require rollback? | | Owner | Who can make the rollback decision? | | Deadline | How long can troubleshooting continue before rollback begins? | | New writes | What happens to data created after cutover starts? | | Source state | Is the old server intact and protected from conflicting writes? | | DNS/access | How do users return to the original paths? | | Communication | Who tells users and vendors what changed? | Do not erase or repurpose the old server after the first successful login. Retire it only after the destination passes the agreed technical and business validation period. ## Monitor the first days after migration Watch both infrastructure and workflow signals: - CPU and sustained processor pressure; - available memory and paging; - disk free space and storage latency; - active RDP/RDS sessions; - failed logons; - Windows and application event logs; - SQL Agent jobs and database backups; - scheduled tasks and integrations; - backup completion; - user-reported workflow problems. Use [Windows Server Performance Monitoring](/windows-server/windows-server-performance-monitoring) to establish a repeatable PerfMon baseline instead of diagnosing performance from Task Manager alone. Migration is complete when the destination is stable, recoverable, documented, and real users can complete the work the server exists to support. ## How Raff fits local Windows Server to cloud migration Raff provides the Windows VM infrastructure layer for businesses and MSPs moving supported Windows workloads away from local hardware. Typical destination workloads include: - business applications over RDP/RDS; - accounting and tax software; - ERP and inventory systems; - IIS and ASP.NET applications; - SQL Server-backed workloads; - Windows services and scheduled automation; - supported file-server workloads; - domain services where the network and AD architecture have been designed correctly. Raff Windows VMs provide administrator access, RDP access, NVMe-backed storage, private networking options, and backup/snapshot options. The customer or MSP still owns application compatibility, guest Windows configuration, licensing review, security hardening, backup design, and production migration unless a separate managed service covers those responsibilities. :::cta Deploy Windows Now Build the destination Raff Windows VM before cutover so users, applications, files, networking, backups, and rollback can be tested alongside the local server. ::: ## Final local-server-to-cloud checklist - [ ] Current Windows Server roles inventoried - [ ] Applications and vendor support documented - [ ] Users, groups, and service accounts documented - [ ] File shares, ACLs, and mapped paths documented - [ ] SQL Server dependencies documented - [ ] AD/DNS/DHCP dependencies documented if applicable - [ ] Target Windows Server version validated - [ ] SPLA or eligible BYOL path selected - [ ] Admin RDP vs RDS user access model selected - [ ] Source backup completed - [ ] Representative restore tested - [ ] Destination built, patched, and hardened - [ ] Destination backups enabled - [ ] Real user workflows tested - [ ] Printers, scanners, reports, and integrations tested - [ ] Final synchronization procedure rehearsed - [ ] Cutover sequence written - [ ] Rollback trigger, owner, and deadline documented - [ ] Old server preservation period defined - [ ] Post-migration monitoring owner assigned Resolve unknown items before the production cutover. ## Frequently asked questions ### What is server migration to cloud? Server migration to cloud is the process of moving a workload from a physical or locally hosted server to cloud infrastructure. For Windows Server, this can include roles, applications, databases, files, users, permissions, remote access, licensing, backups, and operational procedures. ### Should I migrate a local Windows Server in place or side by side? For many local-to-cloud projects, side-by-side migration is easier to test and roll back because the source can remain available while a separate destination is built. The correct method still depends on the Windows role, application, data, and vendor-supported migration path. ### Can Storage Migration Service move my whole Windows Server? No. Storage Migration Service is primarily for file-server data and configuration migration. Microsoft supports current Windows Server 2025, 2022, 2019, and 2016 scenarios, but it does not migrate a domain controller as a domain controller and it is not a general application or SQL Server migration engine. ### Do I need RDS CALs after moving Remote Desktop users to the cloud? If users consume RD Session Host in a customer-owned Microsoft licensing model, the applicable RDS CAL rules apply. Raff-hosted SPLA deployments use the applicable service-provider licensing model, including RDS User SALs for hosted RDS use. Administrative RDP is a different use case from employee desktop sessions. ### Can I move an old Windows Server licence to a cloud VM? Not automatically. Raff can provide Windows Server under SPLA, while eligible customer BYOL depends on the customer's Microsoft agreement, qualifying rights, and applicable outsourcing rules. Review [Windows Server Licensing](/windows-server/windows-licensing) before production. ### How long should I keep the old local server after migration? Keep it according to the written rollback plan until the cloud destination has passed technical and business validation. Prevent conflicting writes if both environments remain online. ## Validation scope This article was revalidated on **September 11, 2026** against current Microsoft guidance for Windows Server upgrade and migration methods, role migration, Storage Migration Service, Windows Server 2025 release status, and Remote Desktop Services licensing. The existing four in-article migration visuals and the existing featured image were preserved. This refresh does not claim that one migration method fits every Windows role or that every legacy application will work unchanged in a cloud VM. ## What's next - [Cloud Windows Server for Small Business](/windows-server/cloud-windows-server-vs-local-office-server) - decide whether the office workload should move to cloud infrastructure. - [Server Migration Checklist for Windows Server](/windows-server/windows-server-migration-checklist-small-business) - use the broader migration control list. - [Windows VPS Sizing for Remote Users](/windows-server/windows-vps-sizing-remote-users) - map user and application load to current VM tiers. - [Windows Server Licensing](/windows-server/windows-licensing) - review SPLA, eligible BYOL, CAL, and RDS licensing. - [File Server Migration to Windows VPS](/windows-server/file-server-migration-to-windows-vps) - handle file shares and permissions. - [SQL Server Migration to Windows VPS](/windows-server/sql-server-migration-to-windows-vps) - plan database migration separately. - [Remote Desktop Gateway vs Direct RDP](/windows-server/remote-desktop-gateway-vs-direct-rdp) - secure external Remote Desktop access. - [Windows Server Hardening Checklist](/windows-server/windows-server-hardening-checklist) - secure the destination before production. - [Raff Windows VM](/products/windows-vm) - review the destination platform. - [Raff Pricing](/pricing) - confirm current infrastructure pricing. ## Sources - Microsoft Learn - Upgrade and migrate roles and features in Windows Server: https://learn.microsoft.com/en-us/windows-server/get-started/upgrade-migrate-roles-features - Microsoft Learn - Use Storage Migration Service to migrate a server: https://learn.microsoft.com/en-us/windows-server/storage/storage-migration-service/migrate-data - Microsoft Learn - Storage Migration Service FAQ: https://learn.microsoft.com/en-us/windows-server/storage/storage-migration-service/faq - Microsoft Learn - Windows Server release information: https://learn.microsoft.com/en-us/windows/release-health/windows-server-release-info - Microsoft Learn - RDS Client Access Licenses: https://learn.microsoft.com/en-us/windows-server/remote/remote-desktop-services/rds-client-access-license - Microsoft Learn - Remote Desktop Gateway: https://learn.microsoft.com/en-us/windows-server/remote/remote-desktop-services/remote-desktop-gateway-role - Sources revalidated: 2026-09-11 --- ### File Server Migration to Windows VPS: SMB, Permissions & Cutover URL: https://rafftechnologies.com/windows-server/file-server-migration-to-windows-vps Description: Migrate a Windows file server to a VPS with a current 2026 plan for Storage Migration Service, SMB shares, NTFS permissions, mapped drives, test copies, cutover, rollback, and backup validation. ## In short A **file server migration to Windows VPS** is not just a folder copy. A reliable migration has to preserve or deliberately redesign SMB shares, NTFS permissions, local users and groups, mapped drives, UNC paths, application dependencies, backups, and the cutover path users will follow after the move. Raff Technologies can provide the Windows VM infrastructure for the destination. The migration owner still needs to choose the transfer method, validate permissions and file integrity, decide whether server identity should move, secure remote access, test the real user workflow, and keep rollback available until the new file server is accepted. For Windows Server-to-Windows Server projects in 2026, Microsoft's **Storage Migration Service (SMS)** is the primary Windows-native migration workflow to evaluate. It supports current Windows Server destinations and can inventory a source server, transfer data and configuration, and perform a cutover that moves the source server identity to the destination when the network and domain design allow it. For simpler or more manual migrations, Robocopy remains useful, but switches such as `/MIR` must be handled carefully because mirroring can remove files from the destination. ## Quick decision: which file server migration method fits? | Situation | Recommended direction | Why | |---|---|---| | Windows Server to Windows Server with many shares | Storage Migration Service | Inventories data and can preserve server configuration and identity | | Old physical Windows file server to new Windows VM | Storage Migration Service or staged Robocopy | Both support side-by-side migration | | Small server with a few shares | Robocopy + documented share recreation | Easier to control manually | | Need to preserve server name / client paths | Storage Migration Service cutover if topology supports it | Can move source identity to destination | | Destination is in another network/cloud subnet | Plan DNS/UNC-path cutover carefully | IP transfer may not fit the topology | | Existing destination already has production files | Do not blindly mirror | Copy/mirror behavior can overwrite or remove destination content | | Applications run on the old file server | Reinstall/test separately | Storage Migration Service does not migrate installed applications | | Users depend on Previous Versions | Plan a separate retention/archive path | VSS history needs separate handling | The safest default for most SMB migrations is **inventory -> test transfer -> permission validation -> backup -> final sync -> controlled cutover -> user acceptance -> delayed source retirement**. :::cta Talk to Windows Engineer Review file shares, permissions, server identity, destination storage, access method, and cutover timing before moving production data. ::: ## File server migration is not just copying folders A Windows file server usually contains years of hidden dependencies behind a simple drive letter such as `S:` or `P:`. | Migration area | What can break | |---|---| | SMB shares | Share names, paths, share-level permissions | | NTFS ACLs | User/group access and inherited permissions | | Local users/groups | Permissions tied to local SIDs | | Mapped drives | GPOs, scripts, shortcuts, drive letters | | UNC paths | `\\OldServer\Share` references in apps and documents | | Open files | Files changed during the copy window | | Long paths | Copy failures or application issues | | Applications | Hard-coded paths, services, scheduled tasks | | Backups | New server not protected at cutover | | Previous Versions | VSS history may not move | | Server identity | DNS name, IP, AD computer account | | Remote access | SMB exposure, VPN, RDS, or SMB over QUIC | ![Architecture visual showing local Windows file server migration to cloud Windows VPS with SMB shares, users, backups, and secure access](https://raff-images.s3.raffusercloud.com/file_server_migration_architecture_windows_vps_webp_77a9232aed.png) A migration is complete only when users and applications can work with the destination **without losing access, permissions, data, or a recovery path**. ## Step 1 — Inventory shares, permissions, and dependencies Start with discovery, not copying. Document server identity, shares, share permissions, NTFS ACLs, local users and groups, mapped drives, UNC references, data size, file counts, long paths, open files, scheduled tasks, backup jobs, VSS usage, and applications installed on the server. The inventory should answer: **what breaks if the server name, path, permissions, or share structure changes?** ## Step 2 — Decide what should actually move Split data into active, archive, retire, and review groups. Do not automatically migrate years of obsolete installers, duplicate exports, abandoned profiles, or temporary files. Business owners should approve retention decisions for legal, finance, HR, customer, and regulated data. ## Step 3 — Choose Storage Migration Service or Robocopy Storage Migration Service is the stronger default when you need to migrate more than data. Its workflow is inventory, transfer, validate, then cut over if you want the destination to take over the source identity. Robocopy can be a good fit for controlled manual transfers. A staged pattern is safer than a one-shot production copy: ```text Initial copy -> review logs -> permission validation -> user testing -> freeze writes -> final delta copy -> cutover ``` Be especially careful with `/MIR`: it mirrors source and destination and can remove destination files not present on the source. Test commands with non-production data and keep a backup before a final mirror. ## Step 4 — Plan NTFS and share permissions before transfer ![Visual showing NTFS permissions, security groups, mapped drives, UNC paths, and user access dependencies during file server migration](https://raff-images.s3.raffusercloud.com/file_server_permissions_mapped_drives_migration_webp_7cba06b031.png) Preserve current ACLs only if they are understood and accurate. Otherwise clean up stale users, orphaned SIDs, direct user assignments, broad `Everyone` access, explicit Deny rules, and broken inheritance before cutover. Prefer role-based groups such as `Finance_Read`, `Finance_Modify`, `HR_Read`, and `HR_Modify` where practical. Do not redesign the entire permissions model during the final migration window. ## Step 5 — Decide what happens to local users and groups Some servers use local accounts or local groups in ACLs. Storage Migration Service can migrate local users and groups in supported scenarios, but long-term identity design may still be better with domain or centrally managed identities. Never assume that the same username on two servers means the same SID. ## Step 6 — Plan mapped drives, UNC paths, and server identity Mapped drives and hard-coded UNC paths are a common reason a technically successful migration appears broken to users. Typical dependencies include: ```text S: -> \\OldServer\Shared F: -> \\OldServer\Finance P: -> \\OldServer\Projects ``` Choose whether to preserve the source server identity, use a DNS alias, or update GPOs/scripts/apps to a new hostname. Storage Migration Service can perform an identity cutover, but for office-to-cloud moves you should not assume the old LAN IP can or should move to the VPS. DNS, VPN/private networking, and updated paths are often the cleaner design. ## Step 7 — Understand cutover before using it Cutover can involve Active Directory changes, source and destination restarts, computer-name transfer, network changes, and a controlled interruption. Validate domain permissions, DNS, required firewall rules, application paths, and rollback steps before starting. For cross-subnet or cloud migrations, a manual application/DNS cutover can be easier to reason about than transferring every source network setting unchanged. :::cta Explore Windows VM Use Raff Windows VM as the destination after storage, access, permissions, and cutover requirements are defined. ::: ## Step 8 — Size destination storage for migration headroom Plan for active data, archives, temporary migration copies, logs, backup staging, application working folders, user profiles if RDS is involved, growth, and a healthy free-space margin. Do not rely on a generic CPU/RAM table for every file server; actual sizing depends on user concurrency, applications, storage behavior, and whether RDS or other workloads share the VM. ## Step 9 — Run an initial test transfer ![Migration visual showing test copy, final sync, validation, and cutover from file server to Windows VPS](https://raff-images.s3.raffusercloud.com/file_server_test_copy_final_sync_webp_7ce1e67868.png) Validate file counts, expected data size, share names, NTFS ACLs, share permissions, ownership, long-path failures, skipped/open files, local identities, application paths, and the destination backup state. Review transfer logs rather than relying only on a successful-looking completion message. ## Step 10 — Handle Previous Versions separately If users rely on right-click **Restore previous versions**, define how that history is retained. Options include keeping the old server read-only for a period, archiving historical copies, or relying on a separately tested backup/versioning process. Do not promise that historical VSS data will automatically appear on the destination. ## Step 11 — Reinstall applications that lived on the old server Storage Migration Service does not migrate locally installed applications. Accounting/ERP tools, backup agents, document management software, sync clients, antivirus agents, scheduled integrations, and other services need their own migration and test plan. ## Step 12 — Choose a secure SMB access model Do not expose SMB over TCP 445 broadly to the public internet. Prefer RDP/RDS, VPN/private networking, app-to-file-server private access, or a tested SMB over QUIC design where Windows Server 2025 and supported clients make it appropriate. Windows Server 2025 expanded SMB over QUIC availability. It can be useful for specific remote SMB scenarios, but it still requires certificate planning and a tested client/server configuration. ## Step 13 — Configure backups before production ![Backup and rollback visual for file server migration to Windows VPS with source backup, destination backup, restore test, and rollback path](https://raff-images.s3.raffusercloud.com/file_server_migration_backup_rollback_stack_webp_a01e0adbaa.png) Protect the destination before users begin creating new files there. Use an appropriate combination of VM backup, pre-cutover snapshot, file-level backup, off-server copy, retention, and restore testing based on business RPO/RTO. :::cta Explore Data Protection Protect the destination file server with VM recovery, file-level backups, off-server copies, and tested restores before cutover. ::: ## Step 14 — Run the final sync and freeze writes A controlled cutover usually means: announce the maintenance window, verify source and destination backups, stop writes to the old shares, close applications with open files, run the final delta, review logs, verify permissions, perform the identity/DNS/path cutover, test admin and real-user access, then allow production writes on the destination. ## Step 15 — Test with real users and real applications Use standard, read-only, department, restricted-data, application, remote, and administrator accounts. Test open/edit/save/rename/delete behavior, mapped drives, shortcuts, application exports, service accounts, scanners/printers writing to network folders, and backup capture of newly created data. ## Step 16 — Define rollback before cutover Write down the rollback trigger, decision owner, troubleshooting deadline, how DNS/GPO mappings revert, and what happens to new destination writes. Avoid allowing both old and new shares to be writable independently, because split data makes rollback much harder. ## Common file server migration mistakes - Treating `/MIR` as a harmless copy command. - Assuming Storage Migration Service moves applications. - Forgetting Previous Versions or retention history. - Copying files without validating ACLs. - Changing hostnames without checking UNC paths. - Assuming an office LAN IP can move directly to a cloud VM. - Exposing SMB publicly. - Retiring the old server before real-user and restore validation. ## How Raff fits a file server migration Raff can provide a Windows VM destination for shared-folder and Windows file-server workloads when the required Windows Server, application, licensing, storage, access, and backup requirements are compatible. Typical use cases include replacing an aging local file server, centralizing shared folders for multiple offices, keeping files close to Windows business applications, hosting file shares used inside RDS sessions, and standardizing MSP-managed Windows environments. Raff provides the infrastructure foundation. The business or MSP remains responsible for data ownership, permissions, applications, retention, access design, and migration acceptance unless a specific managed-service agreement says otherwise. For architecture decisions before migration, read [Windows VPS as a Cloud File Server](/windows-server/windows-vps-cloud-file-server). For a broader office-server project, use [Local Office Server to Cloud Windows VPS Migration](/windows-server/local-server-to-cloud-windows-vps-migration). :::cta Deploy Windows Now Create a Raff Windows VM after the file-server storage, access model, migration method, and rollback plan are defined. ::: ## Final file server migration checklist Before production cutover, confirm shares and permissions are inventoried, local identities and mapped drives are documented, application and UNC dependencies are tested, retention/Previous Versions decisions are made, source and destination backups are valid, the migration method is selected, a test transfer is complete, transfer logs are reviewed, the final write freeze is scheduled, DNS/GPO/identity cutover is documented, remote access is secured, and rollback criteria are written. ## Validation scope This September 2026 refresh revalidated the migration guidance against Microsoft's current Windows Server, Storage Migration Service, SMB security, and migration troubleshooting documentation. The existing featured image and all four body diagrams were preserved. This refresh does **not** claim a newly completed end-to-end production file-server migration on Raff. Exact cutover behavior, application dependencies, local identities, permissions, network topology, licensing, and performance must be tested for the customer's environment. ## What's next - [Raff Windows VM](/products/windows-vm) — choose the destination after storage and access requirements are known. - [Raff Pricing](/pricing) — review current Windows VM pricing. - [Windows Server Migration Checklist](/windows-server/windows-server-migration-checklist-small-business) — coordinate the broader migration. - [Local Office Server to Cloud Windows VPS Migration](/windows-server/local-server-to-cloud-windows-vps-migration) — plan a full office-server move. - [Windows VPS as a Cloud File Server](/windows-server/windows-vps-cloud-file-server) — decide whether a Windows file server is the right architecture. - [Windows VPS Backup Strategy](/windows-server/windows-vps-backup-strategy-small-business) — plan recovery before production cutover. - [Remote Desktop Gateway vs Direct RDP](/windows-server/remote-desktop-gateway-vs-direct-rdp) — plan secure remote Windows access. - [Windows Server Hardening Checklist](/windows-server/windows-server-hardening-checklist) — harden the destination. ## Sources - Microsoft Learn — Storage Migration Service overview: https://learn.microsoft.com/en-us/windows-server/storage/storage-migration-service/overview - Microsoft Learn — Migrate a server with Storage Migration Service: https://learn.microsoft.com/en-us/windows-server/storage/storage-migration-service/migrate-data - Microsoft Learn — Storage Migration Service FAQ: https://learn.microsoft.com/en-us/windows-server/storage/storage-migration-service/faq - Microsoft Learn — Storage Migration Service cutover: https://learn.microsoft.com/en-us/windows-server/storage/storage-migration-service/cutover - Microsoft Learn — Storage Migration Service troubleshooting: https://learn.microsoft.com/en-us/troubleshoot/windows-server/backup-and-storage/windows-server-storage-migration-service - Microsoft Learn — What's new in Windows Server 2025: https://learn.microsoft.com/en-us/windows-server/get-started/whats-new-windows-server-2025 - Microsoft Learn — SMB security hardening: https://learn.microsoft.com/en-us/windows-server/storage/file-server/smb-security-hardening - Sources revalidated: 2026-09-11 --- ### Windows Server 2022 vs 2025 vs 2019: Which Should You Choose? URL: https://rafftechnologies.com/windows-server/windows-server-version-comparison Description: Compare Windows Server 2022 vs 2025 vs 2019 across lifecycle, security, compatibility, editions, upgrade paths, requirements, and which version fits your workload. ## In short For a **new Windows Server deployment in 2026**, choose **Windows Server 2025** when your application stack supports it. Choose **Windows Server 2022** when third-party compatibility is more important than having the newest release. Use **Windows Server 2019** only when a legacy application or vendor support requirement still needs it. For most buyers the real decision is **Windows Server 2022 vs 2025**, or **Windows Server 2025 vs 2022**: the order does not change the answer. Server 2025 gives you the longer lifecycle and newer platform features; Server 2022 gives you a more mature compatibility baseline. Raff tested all three versions side by side on identical **2 vCPU / 4 GB** VMs in April 2026. ## Windows Server 2022 vs 2025: which should you choose in 2026? Use this decision first: | Situation | Better starting point | |---|---| | New deployment, software validated on 2025 | **Windows Server 2025** | | Vendor certifies 2022 but not 2025 | **Windows Server 2022** | | Existing healthy Server 2022 workload | Usually keep 2022 until there is a migration reason | | Legacy software requires 2019 | Windows Server 2019 temporarily | | Long-lived greenfield infrastructure | **Windows Server 2025** | | New AD, IIS, file-services, or modern Windows workload | Evaluate **Server 2025** first | | RDP/RDS business software with uncertain vendor support | **Server 2022** until validated | A healthy Server 2022 workload does **not** need an emergency migration simply because Server 2025 exists. Server 2022 remains in extended support through October 2031. But when you are deploying a new VM, replacing infrastructure, refreshing an application, or planning a multi-year workload, Server 2025 is usually the better long-term choice if the full stack is supported. ## Windows Server 2022 vs 2025: quick comparison | Area | Windows Server 2022 | Windows Server 2025 | |---|---|---| | Best use in 2026 | Compatibility-first production | New validated deployments | | Release generation | 2021 | 2024 | | Mainstream support | **October 14, 2026** | **November 14, 2029** | | Extended support | **October 15, 2031** | **November 15, 2034** | | Third-party software maturity | **Very strong** | Improving; verify vendor support | | Security baseline | Mature modern baseline | **Newer defaults and protections** | | Credential Guard | Available | Enabled by default on supported devices | | SMB over QUIC | Limited older scenarios | **Standard and Datacenter support** | | Hotpatch | Azure Edition-specific scenarios | Azure Arc-enabled Server 2025 Standard/Datacenter supported | | Direct in-place upgrade to 2025 | Yes | N/A | | Best for legacy business apps | **Often** | Only after vendor validation | | Best long-term support runway | Good | **Best** | The practical rule: ```text New + validated → Windows Server 2025 Vendor support stops at 2022 → Windows Server 2022 Legacy requirement → Windows Server 2019 ``` ## Windows Server 2022 versions and Windows Server 2025 editions Windows Server **version** is the release generation, such as 2022 or 2025. **Edition** is the feature and licensing tier inside that generation. Microsoft lists Standard, Datacenter, Datacenter: Azure Edition, and Essentials for both Windows Server 2022 and Windows Server 2025. Raff provisions Windows Server Standard for its hosted Windows VM offering. | Edition | Available in 2022 | Available in 2025 | Typical use on a hosted VM | |---|---:|---:|---| | Standard | Yes | Yes | Application, web, RDS, file, and SQL hosts with normal virtualization requirements; this is the Raff-hosted edition | | Datacenter | Yes | Yes | Highly virtualized or software-defined datacenter environments where its additional rights and features matter | | Datacenter: Azure Edition | Yes | Yes | Microsoft Azure and supported Azure-specific environments; not a Raff guest-OS option | | Essentials | Yes | Yes | Small-business edition; Server 2025 Essentials is for up to 25 users and 50 devices and is OEM-only | The edition choice should not be treated as a speed tier. Datacenter is differentiated mainly by virtualization rights and datacenter features, while Standard is the normal fit for many application and business workloads. If you are licensing physical Hyper-V hosts, virtualization rights become much more important than they are when choosing the guest OS for one cloud VM. ## Windows Server 2019 vs 2022 vs 2025 lifecycle **Windows Server 2019 vs 2022 is now largely a lifecycle decision.** Server 2019 left mainstream support in January 2024 and reaches end of extended support on January 9, 2029. Server 2022 stays in mainstream support until October 14, 2026 and receives extended-support security updates until October 15, 2031. For a new deployment, Server 2019 usually makes sense only when a vendor or legacy dependency still requires it. | Version | Release date | Mainstream support | Extended support | Practical role in 2026 | |---|---|---|---|---| | Windows Server 2019 | Nov 13, 2018 | Ended Jan 9, 2024 | Ends Jan 9, 2029 | Legacy compatibility | | Windows Server 2022 | Aug 18, 2021 | Ends Oct 14, 2026 | Ends Oct 15, 2031 | Compatibility-first production | | Windows Server 2025 | Nov 1, 2024 | Ends Nov 14, 2029 | Ends Nov 15, 2034 | New long-term deployments | Microsoft lifecycle pages show dates in Pacific Time, while some release-health tables use adjacent ISO calendar dates. For procurement or compliance records, use the current Microsoft product lifecycle page as the source of record. This comparison page is about **which version to run**, not maintaining a complete lifecycle calendar. For Server 2012 R2, 2016, 2019, 2022, and 2025 support dates in one place, use [Windows Server 2022 end of support dates and the full lifecycle table](/windows-server/windows-server-end-of-life-dates). ## Windows Server 2025 is the stronger greenfield default Choose Windows Server 2025 when: - the deployment is new; - your application vendor supports Server 2025; - you want the longest Microsoft support runway; - you are building a new IIS/.NET, Active Directory, file-services, or general Windows infrastructure stack; - newer Windows Server security and SMB capabilities are useful to the workload; - you expect the server to remain in service for several years. The most important qualification is **application validation**. The operating system can be production-ready while a specific accounting package, ERP release, backup agent, EDR tool, printer driver, or licensing service is not yet certified on it. ## Windows Server 2022 remains the compatibility-first choice Choose Windows Server 2022 when: - the workload already runs reliably on 2022; - a vendor certifies Server 2022 but not Server 2025; - accounting, ERP, tax, RMM, backup, EDR, printer, or line-of-business software compatibility is the main risk; - you want a mature Windows Server platform with security support through 2031; - migration risk is larger than the benefit of moving now. Server 2022 leaving mainstream support in October 2026 does **not** mean the operating system immediately becomes unsupported or insecure. Its extended-support phase continues through October 2031, including security updates under Microsoft's Fixed Lifecycle Policy. ## Windows Server 2019 is now a legacy-compatibility choice Choose Windows Server 2019 when: - a legacy application explicitly requires it; - an older driver or vendor support matrix blocks Server 2022/2025; - you are temporarily matching an existing 2019 environment during a staged migration. Do not choose Server 2019 for a fresh long-lived deployment only because it feels familiar. Its extended support ends in January 2029, leaving a much shorter runway than Server 2022 or 2025. ## Should you upgrade Windows Server 2022 to 2025? Upgrade when the business reason is stronger than the migration risk. A Server 2022 system that is stable, patched, supported by its software vendors, and not due for architectural work can remain on Server 2022. An upgrade becomes more attractive when: - the application is certified on 2025; - Server 2022 mainstream-support status matters to your internal support policy; - you are replacing or moving the VM anyway; - the workload needs Server 2025-specific capabilities; - you want to avoid another OS migration during the expected lifetime of the application; - your security baseline benefits from newer Server 2025 defaults. A poor reason to upgrade is simply “2025 is newer.” ## Windows Server 2022 can be upgraded directly to 2025 Microsoft lists **Windows Server 2022 → Windows Server 2025** as a supported in-place upgrade path for eligible nonclustered systems. Windows Server 2025 also expanded installation-media upgrade paths for eligible nonclustered Windows Server releases from Server 2012 R2 onward, subject to edition, language, role, application, and licensing restrictions. Before an in-place upgrade: 1. Confirm the application vendor supports Server 2025. 2. Confirm installed Windows roles support the upgrade path. 3. Create a full backup and verify recovery. 4. Record network, firewall, service, and application configuration. 5. Schedule downtime. 6. Verify edition and licensing compatibility. 7. Test application, database, RDP/RDS, backup, monitoring, and security after the upgrade. For important business workloads, a **parallel migration to a new Server 2025 VM** can be safer than upgrading the only production server in place because rollback is simpler. If you are coming from Server 2016, use the dedicated [Windows Server 2016 migration guide](/windows-server/migrate-windows-server-2016-to-2025). ## Windows Server 2022 vs 2025 system requirements Searches for this comparison often focus on whether Server 2025 needs materially larger hardware. Microsoft's Windows Server 2025 hardware guidance includes minimum CPU, memory, storage, firmware, and networking requirements. Those requirements are **installation minimums**, not sensible production sizing targets. A real Windows VM should be sized for the software above the OS. RDS users, SQL Server, QuickBooks, IIS applications, antivirus/EDR, monitoring agents, and backup tools can require much more RAM and storage than Windows itself. For most small-business GUI workloads, treat **4 GB RAM as a practical floor**, then size from application behavior and concurrent users rather than from the operating-system minimum alone. Use [Windows VPS sizing for remote users](/windows-server/windows-vps-sizing-remote-users) when RDP/RDS is the main workload. ## Server Core vs Desktop Experience Windows Server 2022 and 2025 can be installed as **Server Core** or **Server with Desktop Experience** for supported Standard/Datacenter scenarios. | Install option | Best fit | |---|---| | Server Core | Infrastructure roles, smaller local GUI surface, remote administration | | Desktop Experience | RDP-administered apps, GUI tools, business software, desktop workflows | Microsoft does not support converting an installed Server Core system into Desktop Experience later. Changing the installation option requires a clean installation. For most Raff business-software and RDP use cases, Desktop Experience is the practical choice. Infrastructure teams comfortable with remote administration and PowerShell may prefer Server Core. ## Security differences that matter Windows Server 2025 does not make Server 2022 insecure. Server 2022 remains a supported modern Windows Server release. The advantage of Server 2025 is that the baseline moves forward. Microsoft documents improvements including: - Credential Guard enabled by default on supported Server 2025 systems; - newer Active Directory security and platform improvements; - SMB over QUIC availability in **Standard and Datacenter**; - stronger SMB security controls and auditing; - Hotpatch support for eligible **Azure Arc-enabled Windows Server 2025 Standard and Datacenter** machines. As of May 19, 2026, Microsoft states Azure Arc-enabled Hotpatch for Windows Server 2025 is available **at no additional Hotpatch cost**. Azure Arc connectivity and Hotpatch eligibility/configuration still apply. The operational value depends on your workload. A legacy accounting package does not automatically benefit from every platform feature, while a new file-service or AD deployment may have stronger reasons to use the newer release. ## Windows Server 2022 vs 2025 for Active Directory For a **new** Active Directory environment, evaluate Server 2025 first because it provides the newest AD DS platform and longest lifecycle. For an existing domain, do not upgrade domain controllers only to make the version number newer. Review: - forest and domain functional-level requirements; - replication health; - backup and system-state recovery; - DNS health; - authentication dependencies; - applications that bind to LDAP; - monitoring and backup-agent compatibility; - change and rollback procedures. Server 2022 remains a sensible DC platform when your environment is standardized on it and there is no immediate requirement to move. ## Windows Server 2022 vs 2025 for IIS and .NET For modern ASP.NET Core applications, both versions can be strong IIS hosts when the required .NET Hosting Bundle and application dependencies are supported. Choose Server 2025 for greenfield deployments after validating the full application stack. Choose Server 2022 when an application vendor, component, or support matrix has not certified 2025. For a current deployment walkthrough, see [.NET 10 Hosting Bundle for IIS on Windows Server](/windows-server/iis-aspnet-core-windows-server-vps). ## Windows Server 2022 vs 2025 for SQL Server Do not choose the OS version independently from the SQL Server version. Check: - SQL Server version and edition; - Microsoft's OS compatibility matrix; - vendor application support; - backup software; - monitoring/EDR agents; - storage latency and capacity; - maintenance windows; - rollback plan. For new validated deployments, Server 2025 gives the longer OS lifecycle. Server 2022 remains the compatibility-first choice when the database application stack has not been fully certified on 2025. For a current deployment path, see [Install SQL Server 2025 on Windows Server](/windows-server/install-sql-server-2025-windows-server-vps). ## Windows Server 2022 vs 2025 for RDP and business software For accounting, tax, ERP, Microsoft Access, trading platforms, and other business software, **vendor support is usually more important than a new OS feature**. Before choosing Server 2025, verify: - application version support; - printer/PDF driver support; - ODBC drivers; - licensing services; - antivirus/EDR support; - backup agents; - RMM agents; - browser/runtime dependencies; - Microsoft 365 Apps requirements if relevant. If the vendor only certifies Server 2022, choose Server 2022. It still has years of security support remaining. If the vendor supports 2025 and the workload is new, choose 2025 and avoid creating an earlier migration deadline. Moving an RD Session Host to 2025 also means the RDS access rights must cover that host version. A 2022 RDS CAL does not license a 2025 Session Host; see the [Windows Server 2025 RDS CAL guide](/windows-server/rds-cal-licensing-guide) for the compatibility rules and hosted-SAL distinction. ## Performance depends more on workload sizing than the version number Do not choose the OS based on generic benchmark claims alone. Application performance depends heavily on: - vCPU generation and allocation; - RAM; - storage latency; - SQL/database configuration; - antivirus exclusions and security policy; - network latency; - application version; - user concurrency; - background jobs. A right-sized Server 2022 VM can outperform an undersized Server 2025 VM. Benchmark **your workload**, not only the operating system. ## Windows Server 2022 vs 2025 cost on Raff Microsoft licensing cost varies by edition, channel, agreement, physical-core licensing, CAL requirements, and hosting model. There is no universal retail price that makes 2022 automatically cheaper than 2025 for every deployment. Compute for a **1 vCPU / 2 GB RAM / 50 GB** Windows VM and the per-instance Windows Server Standard licence are listed on the live [Raff pricing page](/pricing). The version choice between Server 2022 and 2025 does not change the VM compute size you select; size the machine for the workload. RDS User SALs, SQL Server, Microsoft 365 Apps, and third-party application licences are separate considerations. Use the live [Windows VM page](/products/windows-vm) and [pricing page](/pricing) before purchase because compute sizes and commercial terms can change. :::cta Deploy Windows Now Choose the Windows Server version your application stack supports, then size the VM for the actual workload rather than the operating-system minimum. ::: ## What is the next Windows Server version after 2025? Microsoft has **not announced a product name or general-availability date** for the successor to Windows Server 2025. It is, however, publicly testing **Windows Server vNext**, which Microsoft describes as the next Windows Server LTSC Preview. The September 9, 2026 preview build 29659 still carries Windows Server 2025 branding and Microsoft tells testers to refer to it as Windows Server vNext preview. For production planning, Windows Server 2025 remains the current released LTSC baseline and is supported through November 15, 2034. Treat vNext as preview software until Microsoft announces the final product name, release date, licensing, support lifecycle, and production availability. The [Windows Server end-of-life table](/windows-server/windows-server-end-of-life-dates) will be updated when Microsoft publishes the successor's lifecycle dates. ## Recommended version by workload | Workload | Recommended starting point | |---|---| | New Windows VM with modern software | **Server 2025** | | Existing stable Server 2022 workload | Keep 2022 unless there is a migration reason | | Business software with unclear 2025 support | **Server 2022** | | Vendor explicitly supports only 2019 | Server 2019 temporarily | | New Active Directory forest/domain | Evaluate **Server 2025** first | | New IIS / ASP.NET Core app | **Server 2025** after stack validation | | Existing SQL/business app | 2022 or 2025 according to compatibility matrix | | Windows RDP/RDS for SMB users | 2022 if vendor compatibility is uncertain; 2025 if validated | | Long-lived greenfield infrastructure | **Server 2025** | ## Upgrade checklist for Server 2022 to 2025 Before moving a production workload: - [ ] Confirm Microsoft supports the upgrade path. - [ ] Confirm every critical application supports Server 2025. - [ ] Confirm backup, RMM, EDR, and monitoring agents support Server 2025. - [ ] Create and verify a recoverable backup. - [ ] Export or document firewall and network configuration. - [ ] Record service accounts and scheduled tasks. - [ ] Confirm Windows and application licensing. - [ ] Test database connectivity and migrations. - [ ] Plan downtime and rollback. - [ ] Verify RDP/RDS access after the move. - [ ] Verify printing, mapped drives, ODBC, and user profiles for business apps. - [ ] Monitor logs, resource usage, backups, and application health after cutover. For critical workloads, test the process on a clone or staging VM first. ## Frequently asked questions ### Is Windows Server 2025 better than 2022? For new deployments with supported software, usually yes: Server 2025 has the longer lifecycle and newer platform/security features. Server 2022 can still be the better operational choice when third-party software is only certified on 2022. ### Should I upgrade Windows Server from 2022 to 2025? Upgrade when the workload is validated and the lifecycle, security, or platform benefits justify the migration. A healthy Server 2022 system does not need an emergency upgrade simply because mainstream support is ending; extended support continues through October 2031. ### Can Windows Server 2022 be upgraded directly to 2025? Yes. Microsoft lists Server 2022 to Server 2025 as a supported in-place upgrade path for eligible systems. Application, role, edition, language, licensing, and cluster restrictions still apply. ### What is the difference between Windows Server 2022 and 2025? Server 2025 has a longer lifecycle, newer security defaults and AD/SMB enhancements, broader SMB over QUIC availability, and an eligible Azure Arc Hotpatch path. Server 2022 has the advantage of several additional years of third-party application validation and deployment maturity. ### Is Windows Server 2022 still supported? Yes. Mainstream support ends October 14, 2026, and extended support continues through October 15, 2031. ### Should I use Windows Server 2019 in 2026? Only when a compatibility or vendor requirement justifies it. For new long-lived deployments, Server 2022 or 2025 provides a better support runway. ## Tested on Raff > **Tested on:** Three Raff Windows Servers, one per version, 2 vCPU / 4 GB each: Windows Server 2019 Standard build 17763 (RTM), Windows Server 2022 Standard build 20348 (RTM), and Windows Server 2025 Standard build 26100 (RTM). Each VM was provisioned and connected via RDP from macOS 26.3.1 using Microsoft Windows App on April 20, 2026. Tester: Serdar Tekin. > > RTM build numbers are preserved as the original test record. Fully patched production servers show later cumulative-update builds. ## What's next - [Windows Server end-of-life dates](/windows-server/windows-server-end-of-life-dates) - [Windows Server 2016 migration guide](/windows-server/migrate-windows-server-2016-to-2025) - [Windows Server 2025 RDS CAL licensing guide](/windows-server/rds-cal-licensing-guide) - [Windows VPS sizing for remote users](/windows-server/windows-vps-sizing-remote-users) - [Multi-user RDP vs RDS Session Host](/windows-server/multi-user-rdp-vs-rds) - [Raff Windows VM](/products/windows-vm) ## Sources - Microsoft Lifecycle — [Windows Server 2019](https://learn.microsoft.com/en-us/lifecycle/products/windows-server-2019) - Microsoft Lifecycle — [Windows Server 2022](https://learn.microsoft.com/en-us/lifecycle/products/windows-server-2022) - Microsoft Lifecycle — [Windows Server 2025](https://learn.microsoft.com/en-us/lifecycle/products/windows-server-2025) - Microsoft Licensing — [Windows Server 2025 licensing guidance](https://www.microsoft.com/licensing/guidance/Windows-Server-2025) - Microsoft Learn — [What's new in Windows Server 2025](https://learn.microsoft.com/en-us/windows-server/get-started/whats-new-windows-server-2025) - Microsoft Learn — [Hotpatch for Windows Server](https://learn.microsoft.com/en-us/windows-server/get-started/hotpatch) - Microsoft Learn — [Plan your Windows Server upgrade](https://learn.microsoft.com/en-us/windows-server/get-started/upgrade-overview) - Microsoft Learn — [Perform an in-place upgrade](https://learn.microsoft.com/en-us/windows-server/get-started/upgrade-in-place) - Microsoft Learn — [Hardware requirements for Windows Server](https://learn.microsoft.com/en-us/windows-server/get-started/hardware-requirements) - Microsoft Learn — [Windows Server editions comparison](https://learn.microsoft.com/en-us/windows-server/get-started/editions-comparison) - Microsoft Learn — [Server Core vs Desktop Experience](https://learn.microsoft.com/en-us/windows-server/get-started/install-options-server-core-desktop-experience) - Microsoft Windows Server Insiders — [Windows Server vNext Preview Build 29659](https://techcommunity.microsoft.com/discussions/windowsserverinsiders/announcing-windows-server-vnext-preview-build-29659/4554949) - Sources revalidated: 2026-09-10 --- ### Active Directory Group Policy Setup: Create & Configure GPOs (2026) URL: https://rafftechnologies.com/windows-server/ad-group-policy-setup Description: Set up Active Directory Group Policy step by step: create and link GPOs, use GPMC, test with gpupdate and gpresult, configure scope, filtering, loopback, and backups safely. ## In short To set up **Group Policy in Active Directory** safely: ```text Open Group Policy Management (gpmc.msc) → create a test OU → create a new GPO → link it to the test OU → configure user or computer settings → run gpupdate → verify with gpresult → review scope and filtering → back up the GPO → expand to production only after testing ``` Do not start by putting normal day-to-day settings into the **Default Domain Policy**. Do not link a new policy to the whole domain before testing it. Keep GPOs focused, name them clearly, and verify what actually applied instead of assuming the configuration is correct. For Windows Server 2025, 2022, 2019, and 2016, Microsoft documents Group Policy as the centralized way to manage user and computer settings in an Active Directory environment. ## Group Policy setup: quick checklist | Task | Recommended approach | |---|---| | First GPO | Create and test it in a dedicated OU | | Open Group Policy Management | Run `gpmc.msc` or open Group Policy Management | | Computer settings | Link to an OU containing computer objects | | User settings | Link to an OU containing user objects | | Force a refresh | Use `gpupdate`; use `/force` when you intentionally want all settings reapplied | | Verify applied policy | Use `gpresult /r` or an HTML report | | Target a subset of users/computers | Use security filtering carefully | | Target by device condition | Use a WMI filter only when necessary | | RDS-specific user policy | Use loopback processing when the computer location should affect user policy | | Drive maps/printers | Consider Group Policy Preferences | | Production rollout | Use Group Policy Results/Modeling and a test OU first | | Rollback | Back up GPOs before major changes | Simple rule: ```text Use OUs for scope. Use GPOs for configuration. Use gpresult to prove the result. ``` ## What is Group Policy in Active Directory? Group Policy is a Windows management feature that lets administrators centrally configure operating-system, application, security, and user settings. In an Active Directory Domain Services environment, settings are stored in a **Group Policy Object (GPO)**. Microsoft describes a GPO as a collection of policy settings, permissions, and scope information. The GPO has components stored in Active Directory and in SYSVOL on domain controllers. ![Active Directory Group Policy flow showing a GPO created in GPMC, linked to an organizational unit, applied to users or computers, updated with gpupdate, and verified with gpresult.](https://raff-images.s3.raffusercloud.com/active_directory_group_policy_flow_png_80c743e7c3.png) Common Group Policy use cases include: - Windows Firewall and security settings; - RDP configuration; - audit policy; - Windows Update behavior; - browser settings; - screen-lock settings; - scripts; - mapped drives; - printers; - local group configuration; - RDS Session Host behavior; - administrative templates; - registry-based settings. Group Policy settings are divided into two main areas: | Section | Applies to | |---|---| | Computer Configuration | Computer objects | | User Configuration | User objects | Computer policy is evaluated around computer startup and refresh. User policy is evaluated around sign-in and refresh. Some settings require a restart or sign-out before the full effect appears. ## GPO vs OU vs GPO link These three concepts are the foundation of Group Policy. | Term | What it is | Example | |---|---|---| | GPO | The collection of settings | `Server - RDP Security Baseline` | | OU | Active Directory container used to organize objects | `OU=Servers` | | GPO link | Connects a GPO to a site, domain, or OU | Link `Server - RDP Security Baseline` to `OU=Servers` | A GPO is created as a domain object. Linking it to an OU does not move the GPO into that OU; the link controls where the GPO is considered during processing. A single GPO can be linked to more than one supported Active Directory container. Whether it actually applies to a specific user or computer still depends on scope, inheritance, permissions, filtering, and policy-processing rules. ## How to open Group Policy Management Console (GPMC) **Group Policy Management Console**, or GPMC, is the primary management interface for domain Group Policy. Open it with: ```text gpmc.msc ``` On Windows Server, install the Group Policy Management feature if it is not present: ```powershell Install-WindowsFeature GPMC ``` On an administrator workstation, install the appropriate Remote Server Administration Tools and open **Group Policy Management**. Microsoft documents GPMC as the unified console for managing: - Group Policy Objects; - GPO links; - link order; - Group Policy permissions; - WMI filters; - Group Policy Modeling; - Group Policy Results; - GPO backup and restore operations. To edit settings, you need the appropriate permissions on the GPO. To link a GPO to a site, domain, or OU, you also need permission to modify Group Policy links on that container. ## Before you create your first GPO Prepare a safe test environment first. You should have: - a working Active Directory domain; - at least one domain controller; - healthy DNS; - healthy SYSVOL/NETLOGON access; - permission to create/edit/link GPOs; - one test user and/or computer; - a dedicated test OU. If you operate multiple domain controllers, confirm Active Directory replication is healthy before troubleshooting Group Policy behavior: ```cmd repadmin /replsummary ``` If replication or DNS is already broken, Group Policy troubleshooting becomes misleading because the same GPO may not be consistently available where you expect it. If you still need the domain itself, start with [Promote a Windows VPS to an Active Directory Domain Controller](/windows-server/active-directory-domain-controller). ## Step 1 — Create a test OU Do not test the first version of a new GPO against the whole domain. Create a small OU structure such as: ```text contoso.local ├── Servers ├── Workstations ├── Users └── Test ├── Test-Computers └── Test-Users ``` You can create the OUs in **Active Directory Users and Computers** (`dsa.msc`) or with PowerShell: ```powershell New-ADOrganizationalUnit -Name "Test" -Path "DC=contoso,DC=local" New-ADOrganizationalUnit -Name "Test-Computers" -Path "OU=Test,DC=contoso,DC=local" New-ADOrganizationalUnit -Name "Test-Users" -Path "OU=Test,DC=contoso,DC=local" ``` Move one non-critical test computer and test user into the correct OU. A clean OU design reduces Group Policy complexity later. Microsoft specifically recommends using OU structure to support delegation and Group Policy scope rather than creating an unnecessarily complicated policy hierarchy. ## Step 2 — Create a new Group Policy Object You can create the GPO first and link it later, or create and link it in one action. For a first test: 1. Open **Group Policy Management**. 2. Expand the forest and domain. 3. Right-click the test OU. 4. Select **Create a GPO in this domain, and Link it here**. 5. Give the GPO a clear name. Example: ```text Test - Screen Lock Policy ``` Then right-click the GPO and select **Edit**. Use names that explain both the target and the purpose: ```text Server - RDP Security Baseline Server - Windows Update Workstations - Screen Lock Users - Drive Maps RDS - Session Host User Experience ``` Avoid names such as: ```text New Policy Test2 Security Company Policy Random Fix ``` Clear naming becomes important once the domain contains dozens of links and several administrators. ## Step 3 — Configure a simple test setting For a first GPO, choose a setting that is easy to verify and low risk. For example, configure user-side screen saver settings under: ```text User Configuration → Policies → Administrative Templates → Control Panel → Personalization ``` Example values: | Setting | Example value | |---|---| | Enable screen saver | Enabled | | Password protect the screen saver | Enabled | | Screen saver timeout | 900 seconds | This is a safer learning example than starting with domain password policy, firewall lockdown, software deployment, or broad RDP restrictions. ## Step 4 — Make sure you linked the correct policy type to the correct object type A frequent Group Policy mistake is configuring one side of the GPO and linking it to an OU that contains only the other object type. Example: ```text You configure User Configuration settings. The GPO is linked to an OU containing only computers. The user policy does not apply through that normal scope. ``` And the reverse: ```text You configure Computer Configuration settings. The GPO is linked to an OU containing only users. The computer policy does not apply through that scope. ``` For normal Group Policy processing: - user-side settings should be scoped to the relevant user objects; - computer-side settings should be scoped to the relevant computer objects. RDS loopback processing is one deliberate exception discussed later in this guide. ## Step 5 — Update Group Policy with gpupdate Windows refreshes Group Policy automatically, but during testing you usually want to trigger a refresh. Run: ```cmd gpupdate ``` To reapply all policy settings instead of only changed settings: ```cmd gpupdate /force ``` Microsoft documents `/force` as reapplying all policy settings. That means it is useful during testing, but it is not necessary for every normal background refresh. You can also target only one side: ```cmd gpupdate /target:computer ``` or: ```cmd gpupdate /target:user ``` Some client-side extensions require sign-out or reboot to complete processing. `gpupdate` supports `/logoff` and `/boot` for those scenarios. Do not assume that seeing `Computer Policy update has completed successfully` proves every desired setting took effect. Verify the resultant policy next. ## Step 6 — Verify applied GPOs with gpresult `gpresult` displays **Resultant Set of Policy (RSoP)** information for the user and computer. Quick summary: ```cmd gpresult /r ``` Create a readable HTML report: ```cmd gpresult /h C:\GPOReport.html ``` Open: ```text C:\GPOReport.html ``` Check: - Applied Group Policy Objects; - Denied GPOs; - user and computer scope; - security group membership; - policy precedence information. For more detail: ```cmd gpresult /v ``` or: ```cmd gpresult /z ``` If a GPO is not applied, `gpresult` is usually more useful than repeatedly editing the GPO because it tells you what the client actually processed. ## Step 7 — Use Group Policy Results and Modeling GPMC includes two useful tools beyond basic editing. ### Group Policy Results Use **Group Policy Results** to collect resultant policy information for a real user/computer combination. This is useful when troubleshooting: ```text The GPO is linked, but the setting did not apply. ``` ### Group Policy Modeling Use **Group Policy Modeling** to simulate how policy should process under selected assumptions. It is useful before: - moving a computer or user to another OU; - introducing loopback processing; - changing inheritance; - adding security filtering; - rolling a policy into a production OU. Modeling is planning. Results are evidence from an actual target. Use both where appropriate. ## Group Policy processing order: Local, Site, Domain, OU Microsoft documents the normal order as: ```text Local → Site → Domain → parent OU → child OU ``` This is often remembered as **LSDOU**. Later-applied conflicting policy can normally take precedence over earlier policy. But “the closest OU always wins” is too simple for production troubleshooting. The final result can also be affected by: - multiple GPOs linked to the same container; - link order; - Enforced links; - Block Inheritance; - security filtering; - WMI filtering; - disabled user/computer sections; - loopback processing. ### Link order If multiple GPOs are linked to the same site, domain, or OU, GPMC uses link order to determine precedence. Microsoft documents **link order 1** as the highest-precedence link for that container. ### Enforced An **Enforced** GPO link prevents lower-level containers from overriding settings from that enforced higher-level link. Use Enforced sparingly. It is powerful, but overuse makes troubleshooting and delegation harder. ### Block Inheritance **Block Inheritance** on an OU or domain prevents normal inherited GPO links from higher levels from applying there. It does not defeat a higher-level GPO link marked Enforced. Do not use Enforced and Block Inheritance as the first fix for a messy OU structure. Simplify scope when possible. ## Security filtering: who can actually apply the GPO? A GPO being linked to an OU does not mean every object in that OU will necessarily apply it. Security filtering can narrow the target to selected users, computers, or security groups. In GPMC, review both: - **Scope → Security Filtering**; - **Delegation → Advanced** permissions. Two concepts matter: 1. the target must be able to read the GPO as required during processing; 2. the target must have **Apply Group Policy** permission for the GPO to apply. Do not blindly remove default principals and replace them with one group without checking the resulting Read and Apply permissions. A common self-inflicted failure is creating a perfectly linked GPO that the target computer or user can no longer read or apply. For a computer-side GPO, make sure the filtering includes the intended computer accounts or a group that contains them. For a user-side GPO, make sure the intended users/groups are in scope. ## WMI filtering: use it only when OU or security scope is not enough A WMI filter lets Windows evaluate a query on the destination computer and apply the GPO only when the query evaluates as true. Typical reasons include targeting a particular operating-system family or hardware condition. However, WMI filters add processing complexity and can be harder to troubleshoot than OU or security-group targeting. Prefer this order when possible: ```text OU scope → security filtering → WMI filtering only when the target really depends on device state ``` Microsoft documents that a GPO can be linked to one WMI filter, while a WMI filter can be reused by multiple GPOs. ## Group Policy Preferences vs Policies Group Policy Preferences extend Group Policy with settings such as drive maps, printers, shortcuts, registry values, files, folders, and local-group changes. | Type | Typical use | Behavior | |---|---|---| | Policy settings | Security and managed configuration | Designed for enforced management | | Preferences | Operational defaults and convenience settings | Can create/update/replace/delete and support item-level targeting | Examples that fit Preferences well: - mapped drives; - printers; - shortcuts; - environment variables; - selected registry preferences; - files/folders; - local group membership where appropriate. Example path for a drive map: ```text User Configuration → Preferences → Windows Settings → Drive Maps ``` Preferences also support **item-level targeting**, which can apply one preference item based on conditions such as group membership, OU, IP range, operating system, terminal session, or WMI query. Do not use Preferences as a substitute for a security policy when a real policy setting exists for the control you need. ## Domain password policy is different from a normal OU user GPO Domain account policy deserves separate treatment. Do not expect to create different domain-user password rules simply by linking a normal password-policy GPO to different user OUs. Traditional domain password and account-lockout policy is managed at the domain level. If different groups of domain users need different password policies, use **fine-grained password policies** rather than trying to achieve that behavior through ordinary OU-linked password settings. This distinction prevents one of the most common beginner Group Policy design errors. ## Group Policy loopback processing for RDS Session Hosts Normally, user policy follows the **user object's** location in Active Directory. Loopback processing lets user settings be influenced by the **computer object's** location instead. Microsoft describes this as useful for special-purpose computers where the same controlled user experience should apply regardless of who signs in. That makes loopback especially relevant to: - RDS Session Hosts; - shared admin/jump servers; - kiosks; - lab/classroom systems; - other shared-purpose Windows machines. Enable it under: ```text Computer Configuration → Policies → Administrative Templates → System → Group Policy → Configure user Group Policy loopback processing mode ``` There are two modes: | Mode | Behavior | |---|---| | Merge | Normal user GPO list is processed, then user settings based on the computer location are added with higher precedence | | Replace | The normal user GPO list is not used; user settings are gathered based on the computer's Active Directory location | Do not automatically assume Merge is “safer” or Replace is “better.” Choose the mode that matches the intended RDS/user-management design and test it with Group Policy Results before broad deployment. For multi-user environments, see [Multi-user RDP: 2 Admin Sessions vs RDS Session Host](/windows-server/multi-user-rdp-admin-sessions-vs-rds). ## Back up GPOs before major changes GPO backup makes rollback much easier than manually recreating settings. Create a backup folder: ```powershell New-Item -ItemType Directory -Path "C:\GPOBackups" -Force ``` Back up all GPOs: ```powershell Backup-GPO -All -Path "C:\GPOBackups\$(Get-Date -Format yyyy-MM-dd)" ``` Back up one GPO: ```powershell Backup-GPO -Name "Server - RDP Security Baseline" -Path "C:\GPOBackups" ``` Restore a GPO from backup: ```powershell Restore-GPO -Name "Server - RDP Security Baseline" -Path "C:\GPOBackups" ``` Microsoft documents `Restore-GPO` for restoring a backed-up GPO in its original domain. If you need to move settings between domains, use the appropriate copy/import/migration workflow instead of assuming Restore-GPO is a cross-domain migration command. Store production backups somewhere safer than only the local disk of one domain controller. ## A practical starter GPO structure Keep the first design small and purpose-driven. Example OU structure: ```text contoso.local ├── Servers │ ├── Domain Controllers │ ├── RDS Servers │ └── App Servers ├── Workstations ├── Users │ ├── Accounting │ ├── Operations │ └── Admins └── Test ├── Test Users └── Test Computers ``` Example focused GPOs: ```text Server - Baseline Security Server - Windows Update RDS - Session Host User Experience RDS - Session Limits Workstations - Screen Lock Users - Drive Maps Users - Browser Baseline ``` Avoid one giant `Company Policy` GPO containing unrelated settings. Smaller purpose-driven GPOs make ownership, testing, rollback, and troubleshooting easier. ## Group Policy troubleshooting checklist When a GPO does not apply, check in this order: 1. Is the user or computer in the expected OU? 2. Is the correct GPO linked to that site/domain/OU? 3. Is the link enabled? 4. Is the GPO enabled? 5. Is the setting under the correct User or Computer Configuration section? 6. Does the intended principal have the required Read and Apply Group Policy permissions? 7. Is security filtering excluding the target? 8. Is a WMI filter evaluating false? 9. Is Block Inheritance affecting the path? 10. Is a higher-level link Enforced? 11. Is another GPO winning through processing/link order? 12. Does the setting need restart or sign-out? 13. What does `gpresult /h` show under Applied and Denied GPOs? 14. Is SYSVOL/AD replication healthy? 15. Is DNS healthy and is the client actually domain joined? Start with: ```cmd gpupdate gpresult /h C:\GPOReport.html ``` Then investigate the actual reason shown by the client rather than making several unrelated policy changes at once. ## Common Group Policy mistakes ### Editing Default Domain Policy for every setting Keep default policies focused on their intended domain-level role. Create separate GPOs for normal workstation, server, RDS, browser, drive-map, update, and application settings. ### Linking a new GPO to the whole domain first Use a test OU. A bad domain-level link can affect far more systems than intended. ### Confusing user and computer scope A user setting and a computer setting follow different objects during normal processing. Put the target objects in the right OU and link accordingly. ### Using gpupdate /force as a substitute for troubleshooting `/force` reapplies settings. It does not fix a bad link, bad filtering, broken DNS, wrong OU, WMI mismatch, or replication failure. ### Replacing security filtering without checking permissions A GPO can be linked correctly and still fail because the target cannot read or apply it. ### Using WMI filters for everything If an OU or security group can express the target cleanly, use the simpler scope. ### Overusing Enforced and Block Inheritance Both are useful, but excessive use creates a policy tree that is difficult to reason about. ### No GPO backups Back up before major changes and keep the backup away from a single point of failure. ### No RDS loopback design Shared RDS Session Hosts often need user policy based on the server location. Decide deliberately between normal processing, Merge, and Replace. ### Not verifying with gpresult GPMC shows configuration. `gpresult` shows the resultant policy the client reports. ## How Raff fits Active Directory and Group Policy deployments Raff Windows VM can provide the Windows Server infrastructure layer for environments that use Active Directory Domain Services, DNS, Group Policy, RDS, and Windows business applications. A typical architecture can look like: ```text Windows Server VM(s) → Active Directory Domain Services → AD-integrated DNS → Group Policy Management → server / workstation / RDS OUs → tested GPO rollout ``` Raff provides the Windows VM infrastructure. Your team or service provider remains responsible for the Active Directory design, domain-controller redundancy, OU model, GPO strategy, permissions, backups, licensing, and security controls. This article is **not labeled Tested on Raff** because we do not currently have a documented end-to-end Raff lab record for this exact Group Policy workflow. The Windows Server guidance above is based on current Microsoft documentation and standard AD DS/GPMC behavior. :::cta Managing Active Directory or RDS workloads on Windows Server? Deploy a Windows VM with the CPU, RAM, storage, and network capacity your domain services and user workloads need. ::: ## What Raff recommends For a manageable Group Policy environment: 1. Design the OU structure before creating many GPOs. 2. Keep GPOs focused by purpose. 3. Test new policy in a dedicated OU. 4. Use clear names and ownership documentation. 5. Understand User vs Computer Configuration scope. 6. Verify with `gpresult` instead of assuming the link worked. 7. Use security filtering carefully and confirm Read/Apply permissions. 8. Use WMI filtering only where normal scope cannot express the requirement cleanly. 9. Treat loopback processing as an architectural choice for special-purpose computers such as RDS Session Hosts. 10. Back up GPOs before major changes. The goal is not to have more Group Policy Objects. The goal is to have a policy structure that is predictable, testable, and recoverable. ## What's next - [Promote a Windows VPS to an Active Directory Domain Controller](/windows-server/active-directory-domain-controller) - [Active Directory Replication Topology for 2-DC Setups](/windows-server/ad-replication-topology) - [Multi-user RDP: 2 Admin Sessions vs RDS Session Host](/windows-server/multi-user-rdp-admin-sessions-vs-rds) - [RDS CAL Licensing on Windows Server](/windows-server/rds-cal-licensing-guide) - [Windows Server Hardening Checklist](/windows-server/windows-server-hardening-checklist) - [Raff Windows VM](/products/windows-vm) ## Sources - Microsoft Learn — [Group Policy overview for Windows Server](https://learn.microsoft.com/en-us/windows-server/identity/ad-ds/manage/group-policy/group-policy-overview) - Microsoft Learn — [Group Policy Management Console](https://learn.microsoft.com/en-us/windows-server/identity/ad-ds/manage/group-policy/group-policy-management-console) - Microsoft Learn — [Group Policy processing](https://learn.microsoft.com/en-us/windows-server/identity/ad-ds/manage/group-policy/group-policy-processing) - Microsoft Learn — [Group Policy preferences](https://learn.microsoft.com/en-us/windows-server/identity/ad-ds/manage/group-policy/group-policy-preferences) - Microsoft Learn — [Loopback processing of Group Policy](https://learn.microsoft.com/en-us/troubleshoot/windows-server/group-policy/loopback-processing-of-group-policy) - Microsoft Learn — [gpupdate](https://learn.microsoft.com/en-us/windows-server/administration/windows-commands/gpupdate) - Microsoft Learn — [gpresult](https://learn.microsoft.com/en-us/windows-server/administration/windows-commands/gpresult) - Microsoft Learn — [Back up, restore, migrate, and copy Group Policy Objects](https://learn.microsoft.com/en-us/windows-server/identity/ad-ds/manage/group-policy/group-policy-backup-restore) - Microsoft Learn — [Backup-GPO](https://learn.microsoft.com/en-us/powershell/module/grouppolicy/backup-gpo?view=windowsserver2025-ps) - Microsoft Learn — [Restore-GPO](https://learn.microsoft.com/en-us/powershell/module/grouppolicy/restore-gpo?view=windowsserver2025-ps) - Date last verified: 2026-09-02 --- ### Detect and Block RDP Brute-Force Attempts on Windows Server 2025 URL: https://rafftechnologies.com/windows-server/detect-block-rdp-brute-force-windows-server-2025 Description: Detect RDP brute-force attempts on Windows Server 2025 with Security Event 4625, identify attacking source IPs, block confirmed sources with Windows Firewall, and validate access safely. ## In short If a Windows Server is receiving repeated failed Remote Desktop logons, start with **evidence**, not random firewall changes. Windows Security event **4625** records failed logon attempts. In our current Raff Windows Server 2025 validation, repeated public RDP probes were logged as **Logon Type 3** during NLA pre-authentication, while Microsoft defines **Logon Type 10** as `RemoteInteractive` for completed Remote Desktop interactive logon attempts. That distinction matters: do not filter only for Type 10 and assume you have found every RDP-related failure. Instead, correlate the failed logon event with the source IP, targeted username, NLA state, RDP exposure, and timing. A practical response flow is: ```text Repeated RDP login failures | v Confirm Security auditing | v Inspect Event 4625 | v Group failures by source IP / account | v Validate source is not legitimate | v Block confirmed source on the RDP port | v Re-check logs and legitimate access | v Reduce future exposure with allowlisting, VPN/RD Gateway, NLA, MFA, and monitoring ``` For preventive RDP configuration such as Network Level Authentication, IP allowlisting, administrator-account hygiene, and account lockout policy, use [Secure Direct RDP on a Windows VPS](/windows-server/secure-direct-rdp-windows-vps). For broader firewall design, use [Configure Windows Firewall on a Windows VPS](/windows-server/configure-windows-firewall). > **Safety rule:** Do not auto-block every failed login source without review. Shared NAT addresses, mistyped credentials, monitoring systems, administrators on changing networks, and internal infrastructure can create legitimate failures. Confirm the source and preserve a recovery path before changing remote-access rules. ## What an RDP brute-force pattern looks like One failed login is not a brute-force attack. Look for combinations such as: | Signal | Why it matters | |---|---| | Dozens or hundreds of failed logons from one source | Strong automation indicator | | One source trying many usernames | Password spraying / username discovery pattern | | Many sources targeting one administrator account | Distributed credential attack pattern | | Repeated attempts over long periods | Persistent scanning or automated attack | | Failures soon after TCP 3389 is exposed broadly | Public RDP discovery likely | | Successful logon after repeated failures | High-priority incident review | During Raff's Windows Server 2025 validation, a public RDP endpoint received hundreds of failed attempts from individual source IPs within a short observation window. The probes tried usernames such as `Admin`, `administrator`, `ADMINISTRATOR`, `Temp`, and other common account names. That is consistent with automated credential probing rather than a single user mistyping a password. A real incident review should correlate **failed logons, successful logons, account changes, network exposure, and administrator activity**. Do not conclude that the server was compromised only because event 4625 exists. ## Event 4625 is the main failed-logon signal Microsoft documents Security event **4625 — An account failed to log on** for failed authentication attempts on Windows systems. Useful fields include: - `TargetUserName` — account that was attempted; - `LogonType` — type of Windows logon; - `IpAddress` — remote source when Windows records one; - `Status` and `SubStatus` — failure details; - `WorkstationName` — source workstation where available; - authentication package and process information. Microsoft defines **Logon Type 10** as `RemoteInteractive`, the logon type associated with Remote Desktop/Terminal Services interactive access. However, with NLA enabled, some failed RDP authentication attempts can be rejected before a RemoteInteractive session is established. In our Raff Windows Server 2025 test, the repeated public probes appeared as **Logon Type 3** and were still clearly associated with the server's exposed RDP endpoint by timing, source IPs, username patterns, and active connections to the RDP port. The operational lesson is simple: **do not hard-code your investigation to Type 10 only**. Use the event fields and the actual RDP context around the server. ## Step 1 — Record the Windows Server and RDP environment Before changing anything, record the system and current RDP configuration. Run PowerShell as Administrator: ```powershell cls Write-Host "=== WINDOWS SERVER ===" Get-ComputerInfo | Select-Object WindowsProductName, WindowsVersion, OsBuildNumber Write-Host "`n=== HOSTNAME ===" hostname Write-Host "`n=== RDP SERVICE ===" Get-Service TermService | Select-Object Name, Status, StartType Write-Host "`n=== RDP PORT ===" $RdpPort = (Get-ItemProperty ` 'HKLM:\SYSTEM\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp' ` -Name PortNumber).PortNumber $RdpPort Write-Host "`n=== NLA ===" Get-ItemProperty ` 'HKLM:\SYSTEM\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp' ` -Name UserAuthentication | Select-Object UserAuthentication ``` A `UserAuthentication` value of `1` means Network Level Authentication is required. Do not change the RDP port or NLA merely to perform this investigation. This first step is evidence collection. ![PowerShell showing Windows Server 2025 version, Remote Desktop service status, RDP port, and Network Level Authentication state on a Raff Windows VM](https://raff-images.s3.raffusercloud.com/01_rdp_brute_force_test_environment_windows_server_2025_a0476d69c6.png) ## Step 2 — Confirm failed-logon auditing is available Check the current Logon audit policy: ```cmd auditpol /get /subcategory:"Logon" ``` You want failure auditing available so failed authentication is recorded. If this is a standalone lab and failure auditing is not enabled, Microsoft supports configuring advanced audit policy with `auditpol`. A local example is: ```cmd auditpol /set /subcategory:"Logon" /success:enable /failure:enable ``` In a domain-managed environment, Group Policy can control the effective setting. Do not create conflicting local policy without understanding the management source. ## Step 3 — Inspect recent Event 4625 failures Start with a simple query for the last 24 hours: ```powershell Get-WinEvent -FilterHashtable @{ LogName = 'Security' Id = 4625 StartTime = (Get-Date).AddHours(-24) } -ErrorAction SilentlyContinue | Select-Object TimeCreated, Id, Message | Select-Object -First 20 ``` This proves whether the server is recording failed logons, but the message text is too verbose for useful incident analysis. The next step extracts the structured XML fields. ## Step 4 — Extract the fields you need from Event 4625 Run: ```powershell $Failures = Get-WinEvent -FilterHashtable @{ LogName = 'Security' Id = 4625 StartTime = (Get-Date).AddHours(-1) } -ErrorAction SilentlyContinue | ForEach-Object { $EventXml = [xml]$_.ToXml() $Data = @{} foreach ($Item in $EventXml.Event.EventData.Data) { $Data[$Item.Name] = $Item.'#text' } [pscustomobject]@{ TimeCreated = $_.TimeCreated EventID = $_.Id TargetUserName = $Data['TargetUserName'] LogonType = $Data['LogonType'] IpAddress = $Data['IpAddress'] Workstation = $Data['WorkstationName'] Status = $Data['Status'] SubStatus = $Data['SubStatus'] } } $Failures | Sort-Object TimeCreated -Descending | Select-Object -First 30 | Format-Table -AutoSize ``` This gives you the fields that matter for investigation: ```text TimeCreated EventID TargetUserName LogonType IpAddress Workstation Status SubStatus ``` During our current Raff validation, the suspicious RDP probes showed: - Event ID `4625`; - Logon Type `3`; - multiple public source IPs; - repeated attempts against common administrator-style usernames; - status `0xc000006d` for logon failure; - substatus `0xc0000064` on many attempts, indicating that the attempted username did not exist. If you publish screenshots from a real server, redact public IP addresses, real usernames, or domain details unless they are deliberately safe to expose. ![PowerShell showing Windows Security Event 4625 failed RDP authentication attempts with Logon Type 3, source IP, username, status, and substatus on Windows Server 2025](https://raff-images.s3.raffusercloud.com/02_rdp_event_4625_remoteinteractive_failed_logon_f3e133768a.png) ## Step 5 — Group failed attempts by source IP A single event is less useful than the pattern. Group the parsed failures: ```powershell $Failures | Where-Object { $_.IpAddress -and $_.IpAddress -notin @('-', '127.0.0.1', '::1') } | Group-Object IpAddress | Sort-Object Count -Descending | ForEach-Object { $Group = $_.Group [pscustomobject]@{ IpAddress = $_.Name FailedAttempts = $_.Count LogonTypes = (($Group.LogonType | Sort-Object -Unique) -join ', ') Usernames = (($Group.TargetUserName | Sort-Object -Unique) -join ', ') FirstSeen = ($Group.TimeCreated | Measure-Object -Minimum).Minimum LastSeen = ($Group.TimeCreated | Measure-Object -Maximum).Maximum } } | Format-Table -AutoSize ``` This helps distinguish: - one user repeatedly mistyping a password; - one attacking IP testing several accounts; - sustained activity from one address; - a distributed pattern involving many addresses. In the Raff lab, this grouping made the pattern obvious: individual sources had hundreds of failures, while other addresses appeared only once or twice. That is a much stronger signal than reading isolated Event Viewer entries. For a busy public server, retain or forward this evidence rather than relying only on the rolling local Security log. ![PowerShell grouping repeated failed RDP authentication attempts by source IP, failure count, logon type, and targeted usernames on Windows Server 2025](https://raff-images.s3.raffusercloud.com/03_rdp_failed_logons_grouped_by_source_ip_0c235d9960.png) ## Step 6 — Confirm the source before blocking it Do not convert every IP in the table directly into a firewall block. Before blocking, ask: - Is this our office NAT address? - Is this an administrator who recently changed a password? - Is this a VPN egress IP? - Is this an MSP or monitoring system? - Is the targeted account expected to connect remotely? - Is the address already on an approved allowlist? - Is one public IP shared by many legitimate users? A false-positive block can create an outage, especially when several administrators share one corporate egress IP. You can also inspect current established connections to the actual RDP port before blocking a source: ```powershell $RdpPort = (Get-ItemProperty ` 'HKLM:\SYSTEM\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp' ` -Name PortNumber).PortNumber Get-NetTCPConnection ` -LocalPort $RdpPort ` -State Established | Select-Object LocalAddress,LocalPort,RemoteAddress,RemotePort | Format-Table -AutoSize ``` An established TCP connection to the RDP port does **not** prove successful Windows authentication, but it helps distinguish active network connections while you verify which source is your own current administrative session. ## Step 7 — Discover the actual RDP port before writing the rule Do not assume every server still uses TCP 3389. Run: ```powershell $RdpPort = (Get-ItemProperty ` 'HKLM:\SYSTEM\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp' ` -Name PortNumber).PortNumber Write-Host "RDP port: $RdpPort" ``` In our Raff Windows Server 2025 validation, the test VM used the default RDP port **3389**. Changing the RDP port is not a primary anti-brute-force control, but the blocking rule still needs to match the port actually used by the server. ## Step 8 — Block one confirmed hostile source on the RDP port Use the exact confirmed IP. The address below is an RFC 5737 documentation address and will not represent a real attacker: ```powershell $BlockedIP = '203.0.113.45' $RdpPort = (Get-ItemProperty ` 'HKLM:\SYSTEM\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp' ` -Name PortNumber).PortNumber New-NetFirewallRule ` -DisplayName "RDP Brute Force Block TCP - $BlockedIP" ` -Direction Inbound ` -Action Block ` -Protocol TCP ` -LocalPort $RdpPort ` -RemoteAddress $BlockedIP ` -Profile Any ``` If the environment intentionally uses RDP over UDP as well, create the corresponding UDP block for the same confirmed source: ```powershell New-NetFirewallRule ` -DisplayName "RDP Brute Force Block UDP - $BlockedIP" ` -Direction Inbound ` -Action Block ` -Protocol UDP ` -LocalPort $RdpPort ` -RemoteAddress $BlockedIP ` -Profile Any ``` Microsoft's `New-NetFirewallRule` supports source scoping with `-RemoteAddress`, including single IPv4/IPv6 addresses, ranges, and subnets. For incident response, prefer an exact IP unless you have evidence that an entire subnet should be blocked. Blocking broad ranges can affect legitimate users who share the same provider or network. In our controlled test, we created a rule against one confirmed high-volume probe source and verified that Windows Firewall reported the rule as **Enabled**, **Inbound**, and **Block**. ![PowerShell showing a Windows Firewall inbound block rule created for a confirmed high-volume RDP brute-force source on Windows Server 2025](https://raff-images.s3.raffusercloud.com/04_rdp_brute_force_firewall_block_rule_d55375bd42.png) ## Step 9 — Verify exactly what the firewall rule blocks Do not trust the command merely because it returned without an error. Run: ```powershell Get-NetFirewallRule -DisplayName "RDP Brute Force Block*" | Select-Object DisplayName, Enabled, Direction, Action, Profile | Format-Table -AutoSize ``` Then inspect the address scope: ```powershell Get-NetFirewallRule -DisplayName "RDP Brute Force Block*" | Get-NetFirewallAddressFilter | Select-Object Name, RemoteAddress | Format-Table -AutoSize ``` And inspect the port/protocol scope: ```powershell Get-NetFirewallRule -DisplayName "RDP Brute Force Block*" | Get-NetFirewallPortFilter | Select-Object Name, Protocol, LocalPort | Format-Table -AutoSize ``` Verify that: - the rule is enabled; - direction is inbound; - action is block; - source address is the intended IP only; - port is the actual RDP port; - protocol matches the intended RDP path. That is the exact validation we used in the current Raff test before considering the source blocked. ![05-rdp-brute-force-block-rule-verification.png](https://raff-images.s3.raffusercloud.com/05_rdp_brute_force_block_rule_verification_03e0f5a6fa.png) ## Step 10 — Test legitimate RDP before closing the current session When changing firewall rules remotely, keep the current administrator session open. From a separate approved client, confirm that normal RDP access still works. On a Windows client: ```powershell Test-NetConnection YOUR_SERVER_IP -Port 3389 ``` If the server uses a custom RDP port, substitute that port. Then perform a real login using an approved administrator account. The acceptance test is: ```text Confirmed hostile/test source → blocked from RDP Approved administrator source → still connects normally ``` If approved access fails, remove the new block rule from the existing working session or use the provider console/recovery path. ## Step 11 — Re-check event activity after blocking Continue monitoring 4625 events: ```powershell $Since = (Get-Date).AddMinutes(-30) Get-WinEvent -FilterHashtable @{ LogName='Security' Id=4625 StartTime=$Since } -ErrorAction SilentlyContinue | Select-Object TimeCreated, Id, Message | Select-Object -First 20 ``` A Windows Firewall block occurs before Windows authentication. That means blocked connection attempts may no longer create the same 4625 authentication events because the source cannot reach the login path. This is expected. Use firewall logging or upstream network telemetry if you need visibility into packets blocked before authentication. ## Step 12 — Remove a temporary test block safely For a lab or time-limited incident block, remove the exact rule after validation: ```powershell $BlockedIP = '203.0.113.45' $RuleName = "RDP Brute Force Block TCP - $BlockedIP" Remove-NetFirewallRule -DisplayName $RuleName -ErrorAction SilentlyContinue $Rule = Get-NetFirewallRule -DisplayName $RuleName -ErrorAction SilentlyContinue if ($null -eq $Rule) { Write-Host "RDP brute-force test rule removed successfully." } else { $Rule | Select-Object DisplayName,Enabled,Direction,Action } ``` This gives you a clean rollback check instead of assuming the rule was removed. ![PowerShell confirming that the temporary RDP brute-force Windows Firewall block rule was removed successfully after validation](https://raff-images.s3.raffusercloud.com/06_rdp_brute_force_block_rule_removed_7b0f09a736.png) ## Do not build an automatic blocker directly from raw 4625 events without safeguards It is tempting to create a scheduled PowerShell script that automatically blocks every address after five failures. That can create its own outage. Before automating, you need at least: - permanent allowlist for trusted administrator/VPN addresses; - exclusion for loopback and internal management ranges; - threshold and time-window logic; - duplicate-rule handling; - automatic expiry/unblock logic; - logging of every block decision; - false-positive protection; - recovery path if the automation misbehaves; - testing against real NAT/VPN/admin workflows. For a small Windows VPS, **manual review + narrow block + stronger access architecture** is often safer than an untested home-grown IPS script. If repeated RDP attacks are a normal condition, reduce exposure instead of maintaining an ever-growing IP blocklist. ## Account lockout slows password guessing but can also become a DoS control Account lockout is useful, but it has trade-offs. Microsoft publishes different recommended values in different baseline contexts. The important rule is not to copy one number blindly. For a standalone server, inspect local policy: ```cmd net accounts ``` For an Active Directory domain, inspect the effective domain policy: ```powershell Get-ADDefaultDomainPasswordPolicy | Select-Object LockoutThreshold, LockoutDuration, LockoutObservationWindow ``` If fine-grained password policies exist, privileged users can have a different effective policy from the domain default. Lockout policy should complement—not replace—source restrictions, NLA, MFA, gateway/VPN architecture, strong credentials, and monitoring. ## Successful login after a brute-force pattern needs immediate review The most important event is not always the failed login. If repeated 4625 failures are followed by a successful logon for the same account or source, investigate immediately. Review: - Security event 4624 successful logons; - administrator and group membership changes; - new local/domain users; - scheduled tasks; - newly installed services; - PowerShell activity; - Defender detections; - unusual processes; - outbound network connections; - firewall changes; - password resets; - application logs. Blocking the source IP after compromise is not enough. Treat a suspicious successful authentication as an incident-response problem, not merely an RDP tuning problem. ## Stronger long-term defenses are better than a growing blocklist A blocklist handles known sources. It does not stop the next source address. | Control | Why it is stronger | |---|---| | Restrict RDP to fixed trusted source IPs | Most internet scanners never reach authentication | | VPN/private administrative access | Removes broad public RDP exposure | | RD Gateway | Centralizes RDS external access through a controlled gateway | | MFA | Stolen password alone is less useful | | NLA | Requires authentication before full session creation | | Named administrator accounts | Improves accountability and reduces shared-secret risk | | Strong unique credentials | Reduces password reuse/credential stuffing risk | | Account lockout | Slows repeated guessing but must be tuned carefully | | Event monitoring | Detects patterns that preventive controls did not stop | | Per-IP firewall blocks | Useful for confirmed sources, but reactive | For a one-admin server with a stable IP, [Secure Direct RDP on a Windows VPS](/windows-server/secure-direct-rdp-windows-vps) provides the preventive configuration. For multiple users or changing networks, [Remote Desktop Gateway vs Direct RDP](/windows-server/remote-desktop-gateway-vs-direct-rdp) is the better architecture decision page. ## Common mistakes during RDP brute-force response ### Filtering only for Logon Type 10 Type 10 is the RemoteInteractive logon type, but an NLA-protected RDP attempt can fail before that stage. In our Raff validation, repeated public RDP probes appeared as Type 3. Use the server context and event fields, not one logon-type filter alone. ### Blocking before identifying the actual source Do not block a corporate NAT, VPN exit IP, MSP address, or legitimate administrator because it generated a few failed attempts. ### Blocking port 3389 when the server uses a custom RDP port Read the actual `PortNumber` first. ### Creating an allow rule when you intended to create a block Always verify `Action`, `Direction`, `RemoteAddress`, `Protocol`, and `LocalPort` after the rule is created. ### Blocking an entire subnet from one suspicious IP Start with the smallest scope supported by the evidence. ### Closing the current RDP session before testing a second approved connection Keep the working session open until the replacement access path is proven. ### Treating IP blocks as the permanent security architecture Attackers can change source addresses. Reduce the reachable attack surface instead. ### Resetting account lockout policy to extreme values during an incident Aggressive lockout settings can turn password attacks into denial-of-service against legitimate users. Use the organization's documented baseline. ## RDP brute-force response checklist Before closing the incident, confirm: - [ ] Event 4625 failures were verified. - [ ] Logon type was reviewed in context rather than assumed. - [ ] Source IPs and targeted accounts were documented. - [ ] Approved administrator/VPN addresses were excluded from blocking. - [ ] Confirmed hostile sources were blocked with narrow firewall rules. - [ ] Block rule protocol and RDP port were verified. - [ ] Legitimate RDP access was tested from a second session/client. - [ ] Security logs were checked for successful logons after the failure pattern. - [ ] Targeted credentials were reviewed/reset if compromise is plausible. - [ ] NLA is enabled. - [ ] Direct RDP exposure was reviewed. - [ ] VPN, RD Gateway, source allowlisting, or MFA was considered for long-term protection. - [ ] Temporary block rules have an owner and removal/expiry decision. - [ ] Security evidence is retained outside the live server when the incident is material. ## Where Raff fits Raff Windows VM provides the Windows Server infrastructure where administrators can apply Windows Firewall, Security auditing, NLA, account policy, RD Gateway, and other operating-system controls. For a production Windows workload, the stronger architecture is usually not: ```text Public RDP + large attacker blocklist ``` It is closer to: ```text Raff Windows VM | +--> restricted administrative access +--> NLA +--> strong named accounts +--> Windows Firewall +--> monitoring +--> backup/recovery `--> VPN / RD Gateway / MFA where required ``` For MSPs, the repeatable value is to deploy the same access-security baseline across client Windows VMs, then use event evidence to investigate exceptions rather than rebuilding the security model during every incident. Raff provides the Windows VM infrastructure. Windows security policy, firewall rules, identity configuration, and incident response remain administrator responsibilities unless a separate managed service explicitly covers them. ## Frequently asked questions ### Which Windows event shows failed RDP logins? Security event 4625 records failed Windows logon attempts. Microsoft defines Logon Type 10 as `RemoteInteractive`, but do not assume every NLA-protected RDP failure will reach Type 10. In our Windows Server 2025 Raff validation, repeated public RDP probes appeared as Logon Type 3 during pre-authentication. ### Does every event 4625 mean an RDP attack? No. Event 4625 can be generated by many kinds of failed authentication. Inspect the source IP, targeted username, timing, logon type, NLA state, and whether the source is reaching the RDP port before classifying it as Remote Desktop brute-force activity. ### How do I find which IP is brute-forcing RDP? Parse recent Security event 4625 entries, extract the `IpAddress` field, group failures by source IP, and compare attempt counts and usernames. Confirm the address is not an approved administrator, VPN, or corporate NAT before blocking it. ### Can Windows Firewall block one RDP attacker IP? Yes. `New-NetFirewallRule` supports `-RemoteAddress` so you can create an inbound block rule for a confirmed source and scope it to the actual RDP port and protocol. ### Should I automatically block an IP after a certain number of failed RDP logins? Not without safeguards. Automatic blocking needs allowlists, expiry logic, duplicate handling, false-positive protection, logging, and a recovery path. For small environments, manual confirmation plus stronger RDP exposure controls is usually safer. ### Does account lockout stop RDP brute force? It slows repeated password guessing, but it can also let attackers intentionally lock legitimate accounts. Use lockout policy as one layer alongside NLA, source restrictions, MFA, gateway/VPN architecture, strong passwords, and monitoring. ### Is changing the RDP port enough to stop brute-force attacks? No. It may reduce unsophisticated scanning temporarily, but it does not provide meaningful identity protection once the service is discovered. Restrict who can reach RDP and strengthen authentication instead. ### What should I do if a successful RDP login appears after many failures? Treat it as a potential security incident. Review successful logons, account/group changes, processes, scheduled tasks, services, PowerShell activity, Defender detections, firewall changes, and credentials rather than only blocking the source IP. ## What's next - [Secure Direct RDP on a Windows VPS](/windows-server/secure-direct-rdp-windows-vps) - [Configure Windows Firewall on a Windows VPS](/windows-server/configure-windows-firewall) - [Windows Server Hardening Checklist](/windows-server/windows-server-hardening-checklist) - [Remote Desktop Gateway vs Direct RDP](/windows-server/remote-desktop-gateway-vs-direct-rdp) - [Add MFA to Remote Desktop Services](/windows-server/add-mfa-remote-desktop-services-windows-server) - [Raff Windows VM](/products/windows-vm) ## Sources - Microsoft Learn — Security Event 4625, An account failed to log on: https://learn.microsoft.com/en-us/previous-versions/windows/it-pro/windows-10/security/threat-protection/auditing/event-4625 - Microsoft Learn — New-NetFirewallRule (Windows Server 2025 PowerShell): https://learn.microsoft.com/en-us/powershell/module/netsecurity/new-netfirewallrule?view=windowsserver2025-ps - Microsoft Learn — Remote Desktop and Network Level Authentication: https://learn.microsoft.com/en-us/windows-server/remote/remote-desktop-services/remotepc/remote-desktop-allow-access - Microsoft Learn — Remote Desktop access from outside a network: https://learn.microsoft.com/en-us/windows-server/remote/remote-desktop-services/remotepc/remote-desktop-allow-outside-access - Microsoft Learn — Configure Security Baselines for Windows Server 2025: https://learn.microsoft.com/en-us/windows-server/security/osconfig/osconfig-how-to-configure-security-baselines - Microsoft Learn — Fine-grained password policies for Active Directory: https://learn.microsoft.com/en-us/windows-server/identity/ad-ds/get-started/adac/fine-grained-password-policies - Microsoft Learn — Account lockout threshold remediation guidance: https://learn.microsoft.com/en-us/services-hub/unified/health/remediation-steps-ad/set-the-account-lockout-threshold-to-the-recommended-value - Sources verified: 2026-09-01 --- ### Increase RDP Performance: Fix Slow Remote Desktop on Windows Server (2026) URL: https://rafftechnologies.com/windows-server/rdp-performance-tuning Description: Fix slow or laggy Remote Desktop on Windows Server by checking network latency and loss, RDP transport, display settings, CPU/RAM pressure, graphics policies, and concurrent sessions. ## In short To increase RDP performance, check the four likely limits in order: server CPU/RAM/disk pressure, network latency and loss, display demand, and then graphics policies. Raff checked this troubleshooting sequence on a 4 vCPU / approximately 8 GB Windows Server 2025 VM in May 2026; the lab verified the checks and policy states, but did not run a controlled performance benchmark. A practical troubleshooting order is: ```text Check server CPU/RAM/disk → test network latency and packet loss → confirm TCP/UDP RDP transport is not being unnecessarily restricted → reduce display demand for constrained links → review graphics policies only when the workload justifies them → check concurrent/disconnected sessions → retest from another client/network ``` For most Windows Server workloads, this is safer and more useful than applying undocumented frame-rate registry values. ## Remote Desktop slow? Start with the symptom | Symptom | Most useful first check | |---|---| | Mouse and keyboard input feel delayed | Network round-trip time, packet loss, server CPU pressure | | Session freezes briefly or reconnects | Packet loss, VPN/firewall path, TCP/UDP transport, client network | | RDP is smooth at low resolution but slow at 4K or multi-monitor | Display resolution, monitor count, available bandwidth | | Whole Windows VM is slow, not just RDP | CPU, RAM, disk latency, background processes | | Only one user/client is slow | Client Wi-Fi/VPN, display settings, local device, client software | | RDP becomes slow when several users connect | Concurrent-session CPU/RAM demand and application workload | | Login is quick but desktop takes a long time to become usable | User profile, logon scripts, startup apps, updates, security software | | Text is readable but scrolling/video is choppy | Bandwidth, graphics encoding, high-motion workload | | Image becomes blurry while session remains responsive | RDP adapting quality to network conditions rather than a server failure | The symptom helps separate **connection quality** from **server performance**. Treating every slow session as an RDP codec problem often wastes time. ## Why is Remote Desktop slow? RDP continuously transports user input, screen updates, audio and redirected-device traffic between the client and Windows Server. Modern RDP can adapt graphics quality and encoding to network conditions, but it cannot remove physical network latency or create CPU/RAM that the server does not have. The most common causes are: - high network latency between the user and server; - packet loss or an unstable Wi-Fi/VPN path; - RDP falling back to a less suitable transport because UDP is blocked or restricted; - high display resolution or multiple monitors on a constrained connection; - high CPU use on the Windows Server; - low available RAM or memory pressure; - disk pressure that makes the entire desktop feel unresponsive; - too many concurrent sessions for the VM size; - a specific application consuming most server resources; - logon scripts, profile loading, updates, or antivirus activity; - graphics policies that increase quality or encoding work without matching hardware/network capacity. RDP itself is often the messenger rather than the root cause. ## What we tested on Raff The original troubleshooting workflow was checked on a Raff Windows VPS running Windows Server 2025 Datacenter (lab build 26100). ![PowerShell output showing the Windows Server 2025 RDP performance test environment on a Raff Windows VPS.](https://raff-images.s3.raffusercloud.com/01_rdp_performance_test_environment_2847b96921.png) | Item | Value | |---|---| | Provider | Raff Technologies | | OS | Windows Server 2025 Datacenter (lab build 26100) | | Build | 26100 | | VM size | 4 vCPU / approximately 8 GB RAM | | Original lab checks | 2026-05-26 | | Tester | Serdar Tekin | The lab verified: - the Windows Server environment; - TCP 3389 reachability from the client path; - the state of relevant AVC/H.264 Remote Desktop policy settings; - Windows visual-effects settings; - CPU and RAM behavior during an RDP session. ![Task Manager Performance tab showing CPU and memory usage during an RDP session on a Raff Windows Server VPS.](https://raff-images.s3.raffusercloud.com/05_rdp_session_performance_baseline_png_b86befe928.png) We did **not** run a controlled FPS, latency, or codec benchmark. This guide therefore does not claim that a specific graphics policy produced a measured performance gain on the Raff lab VM. ## Step 1 — Check Windows Server resources before changing RDP If the Windows Server itself is overloaded, changing Remote Desktop settings will not solve the root cause. Open **Task Manager → Performance** during the slow session and check: - CPU utilization; - available/used memory; - disk active time and response behavior; - Ethernet/network activity; - which processes are consuming resources. For a quick PowerShell view: ```powershell Get-Process | Sort-Object CPU -Descending | Select-Object -First 15 ProcessName, Id, CPU, @{Name='WorkingSetMB';Expression={[math]::Round($_.WorkingSet64 / 1MB, 1)}} ``` Check system memory: ```powershell $os = Get-CimInstance Win32_OperatingSystem [PSCustomObject]@{ TotalRAM_GB = [math]::Round($os.TotalVisibleMemorySize / 1MB, 2) FreeRAM_GB = [math]::Round($os.FreePhysicalMemory / 1MB, 2) } ``` If one application is consuming most CPU or memory, fix or resize around that workload before blaming RDP. For broader capacity planning, see [Windows Server Sizing by Workload](/windows-server/windows-server-sizing-by-workload). ## Step 2 — Test RDP reachability, latency, and packet loss separately A common mistake is to run a port test and conclude that the network is healthy. ### Check TCP RDP reachability From the client: ```powershell Test-NetConnection SERVER_IP -Port 3389 ``` ![PowerShell Test-NetConnection output verifying TCP 3389 reachability to the Windows Server.](https://raff-images.s3.raffusercloud.com/02_rdp_network_test_2dd1c0a78f.png) A successful result proves that the TCP endpoint is reachable. It does **not** prove low latency, low packet loss, healthy UDP transport, or a responsive Windows desktop. The standard direct RDP port is 3389 and current Windows Server RDS documentation lists both TCP and UDP 3389 for direct client-to-RD-resource traffic. The port can be changed, and RDS deployments using gateways have different network paths. ### Check round-trip behavior ```cmd ping SERVER_IP ``` Look for consistency as well as the average response time. Large swings can make keyboard, mouse, and screen updates feel uneven even when the connection remains established. Some servers or networks block ICMP. In that case, a failed `ping` does not automatically mean RDP is unavailable. ### Check the path and packet-loss clues ```cmd pathping SERVER_IP ``` `pathping` can help identify where loss appears along the route. Interpret intermediary-hop loss carefully because some routers deprioritize ICMP while forwarding normal traffic correctly. The important question is whether the **end-to-end path used by the user** is stable. ## Step 3 — Check physical distance and server region Network latency has a physical component. A user in Europe connecting to a Windows Server hosted far away can have a noticeably different desktop experience from a user close to the server, even if the VM has plenty of CPU and RAM. If RDP is consistently responsive from users near the server but slow from one geography: - test from another network in the affected location; - bypass an unnecessary VPN path for diagnosis where policy permits; - compare direct and corporate-network routes; - choose infrastructure geographically closer to the users when possible. Adding vCPU does not fix round-trip latency caused by distance. ## Step 4 — Make sure RDP transport is not unnecessarily restricted Modern Windows RDP can use UDP as well as TCP. Microsoft’s `Select RDP transport protocols` policy allows the server to use either UDP or TCP, or to force TCP only. When the policy is not configured, Windows chooses the appropriate transport behavior. The Group Policy location is: ```text Computer Configuration → Administrative Templates → Windows Components → Remote Desktop Services → Remote Desktop Session Host → Connections → Select RDP transport protocols ``` For a normal deployment, avoid forcing **Use only TCP** without a reason. If UDP succeeds, Microsoft documents that most RDP traffic can use UDP; if UDP cannot be established, RDP can use TCP. This does **not** mean “UDP is always faster” or that forcing UDP solves every slow session. VPNs, firewalls, NAT devices, client support, and network quality all affect the result. If a specific network has broken or unstable UDP handling, testing TCP-only temporarily can be a useful diagnostic step. Do not turn a troubleshooting workaround into a universal production setting without comparing real user experience. ## Step 5 — Reduce display demand before using server-side hacks Display resolution and frame activity directly affect the amount of data RDP must encode and transmit. Microsoft’s Windows Server RDS network guidance notes that higher display resolution and higher output frame rates require more bandwidth. On a constrained connection, test with a simpler client configuration first. In classic **Remote Desktop Connection (`mstsc`)**: ### Display tab - reduce resolution temporarily; - disable multi-monitor for testing; - avoid an unnecessarily large desktop if the client link is weak. ### Experience tab Start with automatic connection-quality detection. For diagnosis on a constrained link, try reducing visual extras such as: - desktop background; - menu/window animations; - font smoothing where acceptable; - desktop composition effects exposed by the client. Keep **Persistent bitmap caching** enabled unless you are testing a specific client-side rendering issue. If reducing resolution or visual effects makes RDP substantially smoother, the network/display workload is a stronger suspect than raw server CPU. ## Step 6 — Review Windows visual effects on the server For a Windows Server used mainly through RDP, unnecessary local UI effects can be reduced. Open: ```text System Properties → Advanced → Performance → Settings ``` ![Windows Performance Options showing visual effects settings used during the Raff RDP troubleshooting workflow.](https://raff-images.s3.raffusercloud.com/04_windows_visual_effects_settings_png_227a4468b4.png) A practical baseline is **Adjust for best performance**, then selectively enable visual features users actually need. Do not expect this alone to solve network latency. It mainly reduces unnecessary desktop rendering work on the server. ## Step 7 — AVC/H.264 and AVC 444: quality options, not universal speed switches Windows exposes Remote Desktop graphics policies under: ```text Computer Configuration → Administrative Templates → Windows Components → Remote Desktop Services → Remote Desktop Session Host → Remote Session Environment ``` Relevant policies include: - **Configure H.264/AVC hardware encoding for Remote Desktop Connections**; - **Prioritize H.264/AVC 444 graphics mode for Remote Desktop Connections**; - **Configure image quality for RemoteFX Adaptive Graphics**. ![Group Policy showing AVC/H.264-related Remote Desktop settings during the Raff lab check.](https://raff-images.s3.raffusercloud.com/03_rdp_avc444_policy_check_6631ded0a6.png) ### H.264/AVC hardware encoding Microsoft documents that this policy allows compatible hardware encoding to be used, with software encoding as fallback if hardware encoding fails. If the server has no suitable graphics hardware exposed to the Windows guest, enabling the policy does not magically add a hardware encoder. On a normal CPU-only VPS, leave this alone unless you have a specific reason and can validate the resulting CPU/network behavior. ### AVC 444 AVC 444 prioritizes an H.264/AVC mode with full chroma information when both sides support it. It can improve visual fidelity for text and graphics, but higher quality can also increase network demand. Treat AVC 444 primarily as a **quality/encoding choice**, not as a generic “make RDP faster” toggle. ### Do not use undocumented frame-rate registry tweaks This guide previously included a `DWMFRAMEINTERVAL` registry tweak. We removed it. There is no reason to apply undocumented frame-interval values as a standard RDP performance fix on a production Windows Server. First diagnose network quality, server resources, display demand, and supported RDP policies. ## Step 8 — Check whether many RDP sessions are consuming the server RDP can feel fine for one user and become slow as more users run applications simultaneously. List sessions: ```cmd quser ``` or: ```cmd query user ``` Look for: - many active sessions; - disconnected sessions that still have applications running; - users running memory-heavy browsers or business software; - one session consuming most CPU; - server RAM becoming constrained as concurrent users increase. A disconnected session can continue consuming resources. Whether to log it off depends on the user’s workload and your session policy; do not terminate sessions blindly. For multi-user deployments, see [Multiple RDP Users with RDS on Windows Server](/windows-server/multi-user-rdp-vs-rds). ## Step 9 — RDP is slow only after login Sometimes the RDP handshake and credential screen are fast, but the desktop takes a long time to become usable. That usually points away from raw network reachability and toward logon-time work. Check: - user-profile size and profile problems; - Group Policy processing; - logon scripts; - mapped drives or unavailable network shares; - startup applications; - Windows Update activity; - antivirus/EDR scans; - application database or domain-controller connectivity. Use **Event Viewer** and Task Manager during login rather than changing graphics settings first. If every user is slow only after sign-in, the common server-side logon path is more likely than an individual client display setting. ## Step 10 — RDP is slow only for one user or one client If other users are smooth on the same Windows Server, compare the affected client. Test: 1. another network connection; 2. wired Ethernet instead of Wi-Fi; 3. with and without the corporate VPN where security policy allows diagnostic comparison; 4. lower resolution / single monitor; 5. another Windows client device; 6. the same user from a different client; 7. another user from the same client. These A/B tests quickly separate **server**, **account/profile**, and **client/network** causes. ## Step 11 — Video and fast scrolling are choppy RDP is optimized for interactive remote desktop work, but high-motion content can require much more bandwidth and encoding work than normal administration or business applications. Examples include: - video playback; - animated dashboards; - rapidly scrolling image-heavy pages; - design/media applications; - high-resolution multi-monitor desktops. If ordinary typing and application navigation are smooth but video is choppy, do not conclude that the whole RDP connection is broken. Test: - lower display resolution; - a single monitor; - the network path without unnecessary VPN hops; - server CPU during playback; - client/network bandwidth availability; - supported graphics acceleration only when the infrastructure actually provides compatible GPU resources. Avoid “60 FPS registry hacks” as a substitute for measuring the real bottleneck. ## Step 12 — Check firewall and port behavior For direct RDP, Windows Server documentation lists TCP and UDP 3389 as the standard RDP port. If UDP is blocked somewhere in the path, the connection can still use TCP, but the user experience can differ depending on network conditions. Check Windows Firewall rules: ```powershell Get-NetFirewallRule -DisplayGroup "Remote Desktop" | Select-Object DisplayName, Enabled, Direction, Action ``` If you changed the default RDP port, test the actual configured port instead of assuming 3389. For internet-facing production access, do not expose RDP broadly just for convenience. Restrict source access, use appropriate gateway/VPN/security controls, keep Network Level Authentication enabled, and follow a hardening plan. See [Configure Windows Firewall on a Windows VPS](/windows-server/configure-windows-firewall) and [Windows Server Hardening Checklist](/windows-server/windows-server-hardening-checklist). ## How much bandwidth does RDP need? There is no single Mbps value for every Remote Desktop session. Bandwidth demand changes with: - application type; - resolution; - monitor count; - amount of screen change; - audio/video use; - redirected devices; - graphics quality and codec behavior. Microsoft’s Windows Server network guidance gives workload examples ranging from light desktop use to power-user workloads, but the useful production question is whether **your actual user workflow remains stable with low packet loss and enough bandwidth at peak time**. If the connection is bandwidth-constrained, reducing display demand can improve the experience. If the problem is high RTT caused by geography, more bandwidth alone may not remove input delay. ## Common RDP performance mistakes ### Assuming TCP 3389 reachability means the network is healthy It proves the TCP port responds. It does not measure loss, RTT, UDP behavior, or desktop responsiveness. ### Forcing TCP-only everywhere TCP-only can be a useful workaround on a network with broken UDP handling, but it should not be a universal performance setting. Let Windows select suitable RDP transport unless you have a measured reason to override it. ### Enabling AVC 444 because it sounds faster AVC 444 is a graphics-quality/codec policy. Higher visual fidelity is not the same thing as lower latency. ### Applying undocumented FPS registry values Avoid unsupported frame-rate registry recipes. They make troubleshooting harder and can outlive the Windows version they were copied from. ### Adding vCPU to fix geographic latency Compute does not remove network round-trip time between a user and a distant server. ### Blaming RDP when the VM is saturated If CPU, RAM, disk, SQL Server, IIS, or another application is overloaded, fix that workload first. ### Ignoring disconnected sessions Disconnected users may still consume CPU and RAM. Review session policy and resource usage on multi-user systems. ### Running 4K/multi-monitor during diagnosis Start with a simpler display configuration so you can isolate the bottleneck. ## Production troubleshooting checklist Use this sequence when users report slow Remote Desktop: ```text Confirm whether one user or everyone is affected → check CPU/RAM/disk on Windows Server → test TCP port reachability → compare latency and packet-loss behavior → test from another client/network → review RDP transport policy → reduce resolution and monitor count → review AVC/graphics policies only if relevant → check active/disconnected sessions → investigate login/profile/application delays → retest under normal peak workload ``` Keep one change at a time whenever possible. If you change transport, display quality, graphics policies, and VM size simultaneously, you lose the ability to identify which change actually mattered. :::cta RDP still slow after network and client tuning? Run Windows Server closer to your users and size vCPU/RAM for the actual remote workload. [Explore Raff Windows VM](/products/windows-vm). ::: ## How to increase RDP performance: what Raff recommends To increase RDP performance, remove the four limits in order: give the server enough CPU and RAM for the real session load, measure and shorten the network path, lower display demand on constrained links, and only then adjust graphics policies. Raff ran these checks on a 4 vCPU / 8 GB Windows Server 2025 VM in May 2026, and the list below is the order that isolates the cause fastest. 1. Start with server CPU, RAM, disk, and application load. 2. Measure the network path instead of treating a successful 3389 test as a performance test. 3. Keep RDP transport on its normal adaptive behavior unless a specific network requires an override. 4. Reduce resolution and monitor count before changing server internals on constrained links. 5. Treat AVC 444 as a graphics-quality option, not a universal speed setting. 6. Use hardware encoding only when compatible GPU resources actually exist and the workload benefits from them. 7. Avoid undocumented frame-rate registry tweaks. 8. Size the VM for peak concurrent-session workload, not only idle usage. 9. Place Windows infrastructure geographically close to the users when interactive latency matters. 10. Re-test after each change and keep the configuration that solves a measured problem. ## Tested on > Original troubleshooting checks completed on a Raff Windows VPS running Windows Server 2025 Datacenter (lab build 26100), 4 vCPU and approximately 8 GB RAM on 2026-05-26. We verified the server environment, TCP 3389 reachability, relevant AVC/H.264 policy state, Windows visual-effects settings, and CPU/RAM behavior during an RDP session. Tester: Serdar Tekin. Technical guidance and Microsoft references re-reviewed on 2026-09-02. No controlled FPS or input-latency benchmark is claimed. ## What's next - [Windows VPS sizing for remote users](/windows-server/windows-vps-sizing-remote-users) - [What is RDS Gateway](/windows-server/remote-desktop-gateway-vs-direct-rdp) - [RDS CAL licensing guide](/windows-server/rds-cal-licensing-guide) - [Multiple RDP Users with RDS on Windows Server](/windows-server/multi-user-rdp-vs-rds) - [Configure Windows Firewall on a Windows VPS](/windows-server/configure-windows-firewall) - [Windows Server Hardening Checklist](/windows-server/windows-server-hardening-checklist) - [Raff Windows VM](/products/windows-vm) ## Sources - Microsoft Learn — [Network guidelines for Remote Desktop Services](https://learn.microsoft.com/en-us/windows-server/remote/remote-desktop-services/network-guidance) - Microsoft Learn — [Ports used by Remote Desktop Services](https://learn.microsoft.com/en-us/troubleshoot/windows-server/remote/ports-used-by-rds) - Microsoft Learn — [ADMX Remote Desktop Session Host policies: transport, network detection, graphics and AVC](https://learn.microsoft.com/en-us/windows/client-management/mdm/policy-csp-admx-terminalserver) - Microsoft Learn — [Understanding Remote Desktop Protocol](https://learn.microsoft.com/en-us/troubleshoot/windows-server/remote/understanding-remote-desktop-protocol) - Microsoft Learn — [Enable GPU acceleration for remote sessions](https://learn.microsoft.com/en-us/azure/virtual-desktop/graphics-enable-gpu-acceleration) — referenced only for the documented Remote Session Environment H.264/AVC policy behavior; Azure Virtual Desktop-specific features are not assumed to apply to a standard Raff Windows VPS. - Date last verified: 2026-09-02 --- ### Sage 50, 100 & 300 Cloud Hosting on Windows Server (2026) URL: https://rafftechnologies.com/windows-server/sage-hosting-windows-vps Description: Host Sage 50, Sage 100, or Sage 300 on Windows Server with RDS access, right-sized CPU and RAM, backups, security, and migration planning for remote accounting teams. ## In short Sage 50, Sage 100, and Sage 300 can be centralized on Windows Server for remote accounting teams, but they should not be treated as the same workload. Sage 50 is the lightest fit for a small hosted desktop environment. Sage 100 needs closer attention to the exact edition, server role, Remote Desktop Services architecture, and integrations. Sage 300 is a database-backed ERP deployment where SQL Server, reporting, web screens, and recovery planning can matter as much as the Windows VM itself. If you are searching for **Sage 50 cloud hosting**, the practical model is usually to run the Sage application and its company data in a controlled Windows environment and let authorized users connect remotely. That is different from simply making a company file available through Sage Remote Data Access. ## TL;DR - **Sage 50 U.S. 2026** supports Terminal Services on Windows Server 2019 and newer, and its multi-user requirements specifically reference Windows Server 2019 and 2022. - **Sage 100 2026** supports Windows Server 2016, 2019, 2022, and 2025 in its current Supported Platform Matrix. Remote-site access rules depend on the edition and deployment model, so check the exact matrix before building RDS. - **Sage 300 2026** supports Windows Server 2019, 2022, and 2025 as application-server operating systems and SQL Server 2019, 2022, or 2025 for the database tier. - Use **RDS Session Host and RDS CALs** when staff use Windows Server as a multi-user desktop or RemoteApp environment. - Keep the Sage application and its primary data path close together. Avoid turning a latency-sensitive Sage workload into a file share stretched across an unreliable WAN. - Size for **concurrent users, reporting, integrations, SQL Server, and desktop-session memory**, not only the installer minimums. - Backups are not complete until you can restore the Sage data or SQL database and open the application successfully. ![Infographic explaining how to host Sage 50, Sage 100, and Sage 300 on a Windows VPS, with product fit, Raff sizing recommendations, setup steps, RDS access, backups, and security notes.](https://raff-images.s3.raffusercloud.com/sage_hosting_windows_vps_raff_visual_png_81906a553d.png) ## Sage cloud hosting vs Sage Remote Data Access The phrase **Sage cloud hosting** can describe different setups, so define the architecture before choosing a server. | Model | Where Sage runs | Where primary data lives | Best fit | |---|---|---|---| | Local Sage desktop | User's PC | Local PC or office network | One-office teams with reliable local infrastructure | | Sage Remote Data Access | User's local Sage installation | Sage-managed remote data workflow plus local application | Teams that want Sage's built-in remote-data workflow and meet its requirements | | Hosted Sage on Windows Server | Windows Server / RDS environment | Close to the hosted Sage application | Remote teams that want a centralized Windows environment | | Sage 300 app + SQL architecture | Windows application tier plus SQL Server | SQL Server | ERP-style deployments with reporting, integrations, and multiple roles | For a hosted Sage environment, users normally remote into the Windows environment and run Sage there. The application, company data, supporting services, and backups are managed around the same server architecture instead of asking each home or branch-office PC to work directly against a distant file share. This distinction matters most for **Sage 50 cloud hosting**. Sage 50 U.S. 2026 supports Remote Data Access, but Sage also documents a Terminal Services model for Windows Server 2019 and newer. Choose the model that matches the customer's licensing, support requirements, user count, and workflow rather than assuming they are interchangeable. ## Which Sage product are you hosting? | Product | Typical use case | Hosting pattern | Current compatibility notes | |---|---|---|---| | Sage 50 | Small accounting firms, bookkeepers, multi-user accounting | One Windows Server environment for app + company data, with RDS when users need sessions | Sage 50 U.S. 2026 supports multi-user in Premium and higher. Terminal Services requires Windows Server 2019 or newer. | | Sage 100 | SMB ERP, distribution, manufacturing, accounting, integrations | Dedicated Sage application role plus a carefully planned remote-access tier | Sage 100 2026 supports Windows Server 2016/2019/2022/2025. Deployment rules vary by edition; current Sage guidance must be checked before combining RDS and Sage roles. | | Sage 300 | Larger accounting/ERP deployments | Application server + SQL Server, with optional RDS/Citrix and web-screen roles | Sage 300 2026 supports Windows Server 2019/2022/2025 and SQL Server 2019/2022/2025. | The most important rule is to check the **exact Sage product, edition, release, integrations, and add-ons** before production. Sage 50, Sage 100, and Sage 300 have different architecture and support requirements even though they share the Sage name. ## Recommended architecture by Sage product ### Sage 50 cloud hosting For a small Sage 50 team, a single well-sized Windows VM can be a practical architecture: ```text Remote users ↓ RDS / controlled remote access ↓ Windows Server ├─ Sage 50 application ├─ Sage company data ├─ PDF / Office tools if required └─ backup staging ``` Sage 50 U.S. 2026 lists a maximum of five licensed named users for Premium Accounting and up to 40 named users for Quantum Accounting. The infrastructure should still be sized by **simultaneous activity**, not only the number of licensed accounts. For example, five users who keep Sage, Excel, Outlook, PDF tools, and browser tabs open inside RDS can create a much heavier server workload than five occasional users. ### Sage 100 hosting Sage 100 requires more caution because the correct architecture depends on the edition and deployment model. The Sage 100 2026 Supported Platform Matrix recommends a dedicated member/application server and warns about running Sage 100 on a busy domain controller or on a server actively running unrelated applications and services. For remote access, do not assume every Sage 100 edition supports an all-in-one Sage + RDS server. The 2026 matrix explicitly says Sage 100 client/server or Sage CRM Server on the same server as Remote Desktop Services or Citrix is not supported. It also lists Windows Server 2016, 2019, 2022, and 2025 as RDS/Citrix-supported server operating systems. A safer planning model is: ```text Remote users ↓ RDS / Citrix tier ↓ Sage 100 application tier ↓ company data / database / integrations ``` Confirm the customer's exact Sage 100 edition and Supported Platform Matrix before consolidating these roles. ### Sage 300 hosting Sage 300 should be planned like an ERP deployment, not a simple desktop application. | Role | Purpose | |---|---| | Sage 300 application server | Runs Sage 300 programs and shared application components | | SQL Server | Hosts Sage 300 databases | | RDS/Citrix tier | Provides remote access to Sage 300 Classic programs where supported | | Web screen server | Hosts Sage 300 web screens through IIS when used | | Backup/recovery target | Stores recoverable copies outside the production workload | Sage's 2026 Compatibility Guide says Windows Server 2019, 2022, and 2025 are supported for the application server and SQL Server 2019, 2022, and 2025 are supported for the database server. Sage also says Terminal Server/Citrix support applies to Sage 300 Classic programs, not web screens. For web screens, Sage documents Windows Server 2019/2022/2025 with IIS, static content, and ASP.NET, plus a supported SQL Server database for the portal. ## Windows Server compatibility in 2026 Do not choose the Windows Server version from a generic Sage article. Match it to the exact release you are deploying. | Sage release | Windows Server guidance verified September 2026 | |---|---| | Sage 50 U.S. 2026 | Multi-user mode is optimized for Windows Server 2022 and Windows Server 2019 client-server networks. Terminal Services requires Windows Server 2019 or newer. | | Sage 100 2026 | Supported server list includes Windows Server 2016 Standard, 2019 Standard/Datacenter, 2022 Standard/Datacenter, and Windows Server 2025 Standard, with Sage's additional Windows Server 2025 notes. | | Sage 300 2026 | Windows Server 2019, 2022, and 2025 are supported application-server operating systems. | For a new deployment, use the newest Windows Server version that is explicitly supported by the customer's exact Sage release **and** its required integrations, printer drivers, Office version, third-party add-ons, and backup tooling. Do not upgrade the operating system simply because a newer Windows Server release exists. Vendor support for the entire application stack matters more than the server release number. ## Sage hosting sizing: practical Raff starting points The table below is **Raff infrastructure planning guidance**, not a Sage licensing statement or a promise of application performance. Start here, then validate with real users during peak periods. | Workload | Raff planning starting point | Move up when... | |---|---:|---| | Sage 50, 1–3 light users | 4 vCPU / 8 GB RAM / 80–160 GB NVMe | Users also run Office, browsers, PDF tools, or larger company files | | Sage 50, 4–5 active users | 4 vCPU / 16 GB RAM / 160+ GB NVMe | Reporting, month-end, or RDS memory pressure becomes visible | | Sage 50 Quantum, larger team | 8 vCPU / 32 GB RAM / 320+ GB NVMe | Many users are concurrently active or company data/reporting is heavy | | Sage 100, small deployment | 4–8 vCPU / 16 GB RAM / 160–320 GB NVMe | Integrations, reporting, payroll, or RDS/app tiers add load | | Sage 100, heavier deployment | 8+ vCPU / 32 GB+ RAM | Application, RDS, integrations, and data services need separation | | Sage 300, small production | 8 vCPU / 32 GB RAM / storage sized to DB + growth | SQL, reports, web screens, or integrations compete for resources | | Sage 300, larger production | Separate app / SQL / remote-access roles | 10+ users, intensive reporting, large databases, or stricter recovery targets | Why this is deliberately conservative: - Sage 50 U.S. 2026 lists **8 GB RAM minimum** and recommends **16 GB or more for multiple users**. - Sage 100 2026 lists **16 GB RAM** as its recommended minimum server memory and requires 64-bit systems for the 2026 release. - Sage 300 2026's recommended configuration starts its Sage 300 Server role at **32 GB RAM** for Standard and Advanced scenarios and higher for larger Premium deployments. For general user-count planning, read [Windows VPS sizing for remote users](/windows-server/windows-vps-sizing-remote-users). :::cta Hosting Sage for a remote accounting team? Run Sage on a Raff Windows VM with administrator access, NVMe storage, backup options, and enough CPU and RAM headroom for your Windows workload. [Explore Raff Windows VM](/products/windows-vm). ::: ## RDS licensing and remote-user access A Windows VM and an RDP connection are not automatically a licensed multi-user desktop environment. Microsoft requires an RDS Client Access License for each user or device connecting to a Windows Server **RD Session Host**. RDS CAL version compatibility also matters: an older RDS CAL cannot be used to access a newer Windows Server Session Host. Use this decision table: | Scenario | Access planning | |---|---| | One or two administrators maintaining the server | Administrative RDP may be sufficient for server management | | Staff use the server desktop to run Sage every day | Plan RDS Session Host and RDS CALs | | Users need only a published application | Consider RemoteApp/RDS design | | Users connect from branch offices or home | Design a controlled remote-access path; do not rely on broad public RDP exposure | | Sage 100 users are remote | Follow the exact Sage 100 edition's RDS/Citrix architecture rules | Read [RDS CAL licensing on Windows Server](/windows-server/rds-cal-licensing-guide) before putting staff into production sessions. ## Step 1: Inventory the Sage workload before deploying Record these items before choosing a VM: 1. Sage product: 50, 100, or 300. 2. Exact release and edition. 3. Number of licensed users. 4. Peak concurrent users. 5. Company file or SQL database size. 6. Reporting workload. 7. Office/Excel/Outlook integrations. 8. Printers, PDF tools, scanners, and redirected devices. 9. Third-party Sage add-ons. 10. Existing backup and restore process. 11. RPO and RTO requirements. 12. Whether users need full desktops, RemoteApp, or another access method. This inventory prevents the common mistake of choosing a server from user count alone. ## Step 2: Build the Windows environment Before installing Sage: - Install current Windows updates. - Create separate administrator and end-user accounts. - Set the correct time zone. - Keep Windows Firewall enabled. - Restrict remote access to the paths the customer actually needs. - Prepare data and backup locations. - Confirm DNS and outbound access required for licensing and updates. - Take a baseline snapshot before major application installation or migration steps. For Sage 50 U.S. 2026, Sage requires a computer name of 15 characters or fewer. Keep the server name short from the start rather than renaming a production system later. ## Step 3: Keep Sage data close to the application For Sage 50 and other file-sensitive workflows, avoid placing the Sage application on one side of a high-latency WAN while its working data sits on the other. A simple hosted layout might use: | Path | Purpose | |---|---| | `D:\SageData` | Company or shared application data where appropriate | | `D:\SageInstallers` | Installers and approved updates | | `D:\SageBackups` | Local backup staging only | | `D:\SageLogs` | Exported troubleshooting logs | Do not treat a local staging folder as the only backup. Production recovery data should also exist outside the production VM or failure domain. For Sage 300, the SQL database is the primary data layer and needs a database-aware backup strategy. ## Step 4: Install only the components the workload needs ### Sage 50 Sage 50 U.S. 2026 requires .NET Framework 4.8. Desktop Microsoft Excel, Outlook, and Word are required for their corresponding Sage integrations. If users do not need those integrations, do not add extra software to the server by habit. A practical migration test is: 1. Install the correct Sage 50 release. 2. Apply current product updates. 3. Open a sample company. 4. Restore or copy a **non-production** company data set. 5. Test two concurrent users if the planned edition/licensing supports it. 6. Test PDF, Excel, printing, and backup workflows. 7. Only then schedule production cutover. ### Sage 100 Sage 100 2026 is 64-bit only and requires .NET Framework 4.8. Check the 2026 Supported Platform Matrix before installation because architecture rules differ from older versions and because third-party integrations may have their own compatibility requirements. Sage recommends a dedicated member/application server. Keep unrelated server roles off the Sage 100 application server unless the supported architecture clearly permits them. For RDS/Citrix, confirm whether your exact Sage 100 edition is standalone or client/server and follow the platform matrix before combining server roles. ### Sage 300 For Sage 300 2026, design SQL first. Confirm: - Supported SQL Server version and edition. - Database size and expected growth. - Recovery model and backup schedule. - Application-server role. - RDS/Citrix requirement for Classic programs. - Web-screen requirement and IIS role if used. - Reporting and Excel dependencies. - Custom modules and integrations. For database recovery planning, use [SQL Server backup strategy: full, differential & log backups](/windows-server/mssql-backup-strategy) as a starting point, then align it with Sage's own database requirements. ## Step 5: Configure antivirus and firewall rules carefully Do not disable antivirus globally to make Sage faster. Instead: - Follow the current Sage exclusions for the exact product/release. - Limit exclusions to required program/data paths or file types. - Use SQL-aware exclusions for SQL Server data/log locations where applicable. - Keep Downloads and other untrusted locations scanned. - Open only ports required by the selected Sage and RDS architecture. - Avoid exposing SMB or RDP broadly to the public internet. Sage 100's platform documentation explicitly warns that antivirus can affect performance. Use Sage's current antivirus exclusion guidance instead of copying old exclusion lists from forums. ## Step 6: Back up for the application you actually run A useful Sage recovery design has more than one layer. | Backup layer | Purpose | |---|---| | Sage/application backup | Protects data in the format the application expects | | SQL Server backup, when applicable | Protects database consistency and point-in-time recovery options | | VM backup | Helps recover the Windows environment | | Snapshot before major change | Short-term rollback before updates/migration steps | | Off-server copy | Protects against VM, disk, or account-level incidents | | Restore test | Proves the data and application can actually be recovered | Do not call a backup strategy complete because a scheduled job reports “success.” Restore to a separate test location or test database and confirm Sage can open the recovered data. Read [Windows VPS backup strategy for small businesses](/windows-server/windows-vps-backup-strategy-small-business) for the infrastructure layer. ## Step 7: Test the real accounting workflow before cutover Before users go live, test more than login. | Test | Expected result | |---|---| | User signs in | Works without giving normal users administrator rights | | Sage opens | No repair or missing-component prompt | | Company/sample data opens | Correct permissions and data path | | Concurrent users | Works within the licensed/supported model | | Report generation | Completes at acceptable speed | | PDF export | Saves correctly | | Excel export | Works when the required Office integration is installed | | Email workflow | Works with the customer's supported email setup | | Printer redirection | Required printer works from remote session | | Backup | Completes successfully | | Restore | Recovered data opens in a safe test environment | Month-end or year-end reporting can be much heavier than ordinary data entry. Include at least one report-heavy test before declaring the server production-ready. ## How much does Sage cloud hosting cost? There is no single infrastructure price for Sage cloud hosting because the server is only one layer of the total cost. Budget for: - Windows VM CPU, RAM, and storage. - Backup retention and additional storage. - Windows/RDS licensing where required. - Sage licensing and subscriptions. - SQL Server licensing if the Sage 300/100 architecture requires a paid SQL edition. - Microsoft 365/Office licensing if users run Office applications in the hosted environment. - Migration, application support, monitoring, and ongoing management. A two-user Sage 50 environment should not be priced or sized like a 15-user Sage 300 deployment. Use the workload inventory first, then compare the required VM on [Raff Windows VM](/products/windows-vm) and the live [Raff pricing page](/pricing). ## Common Sage hosting mistakes ### Running the app and data across a slow WAN Putting the Sage client on a local PC and the primary data path across an unreliable WAN can introduce latency and file-access problems. For remote users, centralizing app execution and data in the same Windows environment is often cleaner. ### Treating every Sage product as the same architecture Sage 50, Sage 100, and Sage 300 have different support matrices and deployment models. Never reuse one product's server assumptions for another. ### Combining Sage 100 and RDS roles without checking the edition Sage 100 2026 has explicit RDS/Citrix architecture restrictions. Check the exact edition before building an all-in-one server. ### Under-sizing memory The operating system, Sage, RDS sessions, browsers, Excel, PDF tools, antivirus, backups, and SQL Server can all compete for RAM. Size for peak concurrent work, not a quiet login test. ### Treating a VM snapshot as the only backup Snapshots are useful rollback tools, but application-aware data recovery still matters. This is especially important for Sage 300 and SQL Server. ### Giving every user administrator rights Normal accounting users should not need full Windows administrator access. Separate infrastructure administration from daily Sage use. ### Skipping printer, PDF, and Excel tests Remote accounting deployments often fail at the edges: printers, PDF exports, Office integration, email, and mapped paths. Test these before cutover. ## When Windows Server hosting is not the right Sage model A self-managed Windows Server environment may be the wrong choice when: - The customer's Sage release or add-on does not support the planned architecture. - The team wants a fully managed application service and does not want to manage Windows, RDS, Sage, backups, or licensing. - Required scanners, printers, dongles, or local integrations do not work reliably through the remote-access design. - The workload requires high availability beyond what a single VM can provide. - The business has compliance requirements that need a reviewed architecture and operational controls. - A vendor-hosted/SaaS workflow already covers the business requirement with less operational overhead. The right question is not only “Can Sage run on a Windows VM?” It is “Can this exact Sage release, user workflow, and recovery requirement be operated reliably on this architecture?” ## How Raff fits Sage hosting Raff provides the Windows VM infrastructure layer for teams that want to run Windows-based business software in the cloud. A Sage deployment on Raff still requires the customer, MSP, or Sage specialist to validate the exact Sage release, application licensing, RDS licensing, integrations, database design, backups, and user workflow. For a small Sage 50 environment, one correctly sized Windows VM may be enough. For Sage 100, follow the exact edition's supported server/RDS topology. For Sage 300, treat SQL Server and recovery as first-class parts of the architecture and split roles when the workload demands it. :::cta Ready to size the Windows environment? Compare Raff Windows VM options for Sage, RDS, accounting software, and other Windows workloads. [Explore Windows VM](/products/windows-vm). ::: ## What's next - [Windows VPS sizing for remote users](/windows-server/windows-vps-sizing-remote-users) — estimate CPU and RAM by concurrent users and workload. - [RDS CAL licensing on Windows Server](/windows-server/rds-cal-licensing-guide) — plan licensed multi-user desktop access. - [Windows VPS backup strategy for small businesses](/windows-server/windows-vps-backup-strategy-small-business) — build the infrastructure recovery layer. - [Windows VPS for business software](/windows-server/windows-vps-for-business-software) — compare other SMB application workloads. - [SQL Server backup strategy](/windows-server/mssql-backup-strategy) — plan database backups when Sage uses SQL Server. - [Raff Windows VM](/products/windows-vm) — compare the infrastructure layer for a hosted Windows workload. ## Sources - [Sage 50 U.S. Edition 2026 system requirements](https://us-kb.sage.com/portal/app/portlets/results/viewsolution.jsp?solutionid=251027140841793) - [Sage 100 2026 Supported Platform Matrix](https://us-kb.sage.com/portal/app/portlets/results/viewdocument.jsp?solutionid=260415223941073) - [Sage 100 supported versions](https://us-kb.sage.com/portal/app/portlets/results/viewsolution.jsp?solutionid=223924250031477) - [Sage 300 2026 Compatibility Guide](https://docs.sage.com/docs/en/customer/300erp/2026/open/Sage300_CompatibilityGuide.pdf) - [Microsoft Remote Desktop Services overview](https://learn.microsoft.com/en-us/windows-server/remote/remote-desktop-services/overview) - [Microsoft RDS CAL licensing](https://learn.microsoft.com/en-us/windows-server/remote/remote-desktop-services/rds-client-access-license) **Sources last verified:** September 2, 2026. --- ### Windows VPS for Accounting Firms: Remote Access, Apps, Files, and Backups URL: https://rafftechnologies.com/windows-server/windows-vps-accounting-firms Description: Learn when a Windows VPS makes sense for accounting firms that need remote access, QuickBooks, Sage, tax software, client files, backups, security, and cloud Windows Server hosting. A Windows VPS can be a practical cloud server for accounting firms that need remote access to Windows accounting software, tax software, shared client folders, reports, SQL-backed tools, and backups. It works best when the firm plans user count, application support, RDS licensing, file permissions, backup retention, security, and busy-season performance before production. Raff Technologies provides Windows VMs for firms that want a cloud-hosted Windows Server environment instead of relying on one office PC, one aging local server, or scattered desktop installs. Accounting firms do not only need “remote desktop.” They need a reliable place where the team can access the same accounting tools, the same client files, the same reports, and the same Windows environment during normal work and peak season. That is why a Windows VPS for an accounting firm should be planned around the full workflow: - staff and seasonal users; - QuickBooks, Sage, tax software, Access, Excel, PDFs, and reports; - client folders and permissions; - backups and restore testing; - secure remote access; - vendor licensing and support; - migration from old office hardware. A Windows VPS gives the firm the infrastructure layer. The business still needs a correct app, licensing, access, and data-protection plan. :::cta Explore Windows VM Use Raff Windows VM when your accounting firm needs a cloud-hosted Windows Server for remote access, accounting apps, client files, and business workloads. ::: ## Quick verdict: when accounting firms should use a Windows VPS Use this table before moving accounting work to a Windows VPS. | Accounting firm situation | Windows VPS fit | Why | |---|---|---| | Staff need remote access to accounting apps | Strong fit | Users can connect to one hosted Windows environment. | | QuickBooks Desktop or Sage is used by multiple people | Strong fit after vendor/licensing check | App, files, and users can be centralized. | | Tax software needs seasonal remote access | Strong fit after testing | Peak-season users can work in a shared Windows environment. | | Client files are spread across PCs or offices | Good fit | Client folders can be centralized with permissions and backups. | | Local office server is old or unreliable | Strong fit | Cloud Windows VPS can replace the server role. | | Firm has multiple offices | Strong fit with access planning | Branch users can work from one environment. | | Firm uses simple cloud accounting only | Depends | SaaS accounting tools may be enough. | | Heavy local scanning/printing workflows are critical | Depends | Test device redirection and workflow first. | | App vendor does not support RDS/hosted use | Risky | Verify support before production. | | Regulatory/compliance requirements are strict | Needs planning | Access, logging, backups, encryption, and policy ownership matter. | A Windows VPS fits best when the firm still depends on Windows-based accounting workflows but wants access that is less tied to one office machine. ## Why accounting firms move Windows workloads to the cloud Accounting firms usually move to a Windows VPS because one or more of these problems become painful. ![Architecture diagram showing accounting firm staff accessing QuickBooks, Sage, tax software, and client files on a Windows VPS](https://raff-images.s3.raffusercloud.com/windows_vps_accounting_firm_access_architecture_webp_fa36bbfdaa.png) | Problem | What it looks like | How Windows VPS helps | |---|---|---| | Remote work is messy | Staff remote into office PCs or use VPN workarounds | Central Windows environment for users | | Apps live on one machine | QuickBooks, Sage, tax software, or Access is installed locally | Apps can run on the hosted Windows server | | Client files are scattered | Files are on laptops, desktops, USB drives, or old shares | Shared folders and permissions can be centralized | | Backups are unclear | Nobody knows whether yesterday’s data can be restored | Backup and restore planning becomes part of the server model | | Office server is aging | Hardware risk grows during tax season or month-end | Cloud server reduces dependency on office hardware | | Multi-user access is inconsistent | Only one person can use a company file cleanly | RDS/app model can be planned properly | | Seasonal staff need access | Temporary users need a secure workspace | Users can be added, removed, and documented | | MSP support is hard | Every workstation is different | Central server is easier to document and support | For accounting firms, the business risk is not only downtime. It is also client-file access, missed deadlines, broken reports, failed backups, and unclear responsibility. ## Windows VPS vs office PC vs local office server Many accounting firms start with a simple setup: one main office PC, one bookkeeper’s workstation, or one local server. That can work for a while. It becomes risky when remote users, multiple apps, client files, and backups grow. | Area | Office PC | Local office server | Windows VPS | |---|---|---|---| | Best fit | Very small office | On-site team with local IT | Remote or hybrid accounting team | | Remote access | Usually awkward | VPN/RDP/firewall planning needed | Built around remote access | | App centralization | Weak | Good on-site | Good for distributed users | | Client files | Often scattered | Central on LAN | Central in hosted environment | | Backups | Often inconsistent | Depends on local process | Can be designed with VM/file/app backups | | Hardware risk | High | Medium/high over time | Not tied to one office machine | | Multi-location access | Poor | Complex | Stronger fit | | MSP support | Harder | Manageable | Easier to standardize | | Growth | Limited | Hardware upgrade needed | Resize or split roles | The key question is not “cloud or local?” The key question is: where should the accounting workload live so staff can work reliably, securely, and recoverably? ## Common accounting workloads on a Windows VPS ### QuickBooks Desktop QuickBooks Desktop is one of the most common reasons firms look for a Windows VPS. Typical goals: | Goal | Planning point | |---|---| | Multiple users need access | Plan RDS users, Windows users, QuickBooks users, and permissions | | Company file must stay centralized | Keep the company file close to QuickBooks inside the server session | | Remote staff need access | Avoid opening company files across a slow WAN | | Backups must be predictable | Use QuickBooks backup plus server-level backup planning | | Vendor support matters | Verify your QuickBooks license, hosting rules, and support path | For a detailed workflow, use the Raff guide: [Self-Host QuickBooks Desktop Multi-User on a Windows Server VPS](https://rafftechnologies.com/windows-server/quickbooks-multi-user-windows-server-vps). Important: Raff provides the Windows VPS infrastructure. You remain responsible for your QuickBooks license, Intuit support status, application configuration, company file backups, and data integrity. ### Sage 50, Sage 100, and Sage 300 Sage workloads vary by product. | Sage product | Typical fit | |---|---| | Sage 50 | Smaller accounting teams and lighter company-file workloads | | Sage 100 | More planning around users, reporting, integrations, and sometimes SQL | | Sage 300 | More planning around database, modules, integrations, and performance | For Sage-specific planning, use: [Host Sage 50, 100, and 300 on Windows VPS](https://rafftechnologies.com/windows-server/sage-hosting-windows-vps). Do not treat Sage 50, 100, and 300 as the same workload. User count, database behavior, reporting, integrations, and version support can change the right Windows VPS size. ### Tax software Tax software creates seasonal pressure. The firm may have more users, more client documents, more PDF exports, more scanning/printing, and less tolerance for downtime during filing deadlines. A Windows VPS can help when: | Need | Why it helps | |---|---| | Seasonal users | Add documented access for temporary staff | | Client files | Keep tax files and folders centralized | | Remote preparers | Users connect to the hosted Windows environment | | Backup discipline | Protect data before and during tax season | | App consistency | Keep software versions controlled | Use the detailed guide: [Windows VPS for Tax Software](https://rafftechnologies.com/windows-server/windows-vps-tax-software). ### Microsoft Access and legacy accounting apps Some firms still depend on Microsoft Access, older billing tools, legacy reporting apps, or industry-specific Windows software. A Windows VPS can help when the app still needs Windows but users need remote access. Key planning areas: | Area | What to check | |---|---| | Access database design | Split front-end/back-end where appropriate | | File paths | Avoid broken mapped drives and local-only paths | | RDS support | Test with real users | | Backups | Include database files and shared folders | | Vendor support | Confirm support status | | Migration | Test before cutover | Use: [Windows VPS for Microsoft Access and Legacy Apps](https://rafftechnologies.com/windows-server/windows-vps-microsoft-access-legacy-apps). ## Remote access for accountants and bookkeepers Remote access is usually the first reason accounting firms consider a Windows VPS. But there are different access models. | Access model | Best fit | |---|---| | Admin RDP | One or two administrators managing the server | | RDS Session Host | Staff users need daily desktop/app sessions | | RD Gateway | Controlled access for remote RDS users | | VPN/private access | Private network access before connecting | | RemoteApp | Users need specific apps, not a full desktop | Microsoft states that each user or device connecting to an RD Session Host running Windows Server needs a Remote Desktop Services Client Access License. That means staff Remote Desktop access should be planned separately from simple administrator RDP access. For deeper planning, use: - [Remote Desktop Server for Business](https://rafftechnologies.com/windows-server/remote-desktop-server-for-business) - [Remote Desktop Gateway vs Direct RDP](https://rafftechnologies.com/windows-server/remote-desktop-gateway-vs-direct-rdp) - [RDS CAL Licensing on Windows Server](https://rafftechnologies.com/windows-server/rds-cal-licensing-guide) - [Windows VPS sizing for remote users](https://rafftechnologies.com/windows-server/windows-vps-sizing-remote-users) :::cta Talk to Windows Engineer Review accounting users, Remote Desktop access, RDS licensing, QuickBooks or Sage needs, backups, and migration scope before choosing your Windows VPS plan. ::: ## Client files, permissions, and shared folders Accounting firms handle client folders, statements, tax documents, reports, PDFs, exports, and working papers. The file structure matters. A Windows VPS can work as the central place for client files when the access model is secure and backups are planned. Plan: | File area | Recommendation | |---|---| | Client folder structure | Standardize naming before migration | | Permissions | Use Windows groups and least privilege | | Shared folders | Document shares and who can access them | | Mapped drives | Keep drive letters and paths consistent where apps depend on them | | PDF exports | Store reports in predictable folders | | Scans/uploads | Test device workflow before production | | Archive folders | Separate active and historical client data | | Backup scope | Include client files, app data, and database files | | Retention | Align with business and compliance requirements | Do not expose SMB file sharing directly to the public internet. Use Remote Desktop, RDS/RD Gateway, VPN/private access, or another controlled access model. For file-specific planning, use: - [Windows VPS as a Cloud File Server](https://rafftechnologies.com/windows-server/windows-vps-cloud-file-server) - [File Server Migration to Windows VPS](https://rafftechnologies.com/windows-server/file-server-migration-to-windows-vps) ## Backups and restore testing for accounting firms Backups are not optional for accounting workloads. A missed backup can become a client problem. ![Layered protection stack showing permissions, backups, snapshots, off-server copies, and restore testing for an accounting firm Windows VPS](https://raff-images.s3.raffusercloud.com/accounting_firm_windows_vps_protection_stack_webp_a6dcf6c106.png) A backup plan should cover: | Backup layer | Purpose | |---|---| | VM backup | Recover the whole Windows VPS | | Snapshot before changes | Roll back before software updates or migrations | | File-level backup | Restore client folders and documents | | Application backup | Protect QuickBooks, Sage, tax, or Access data using app-safe methods | | SQL/database backup | Protect SQL-backed workloads correctly | | Off-server copy | Reduce risk from server-level or account-level failure | | Restore test | Prove that recovery works | Accounting firms should not rely on only one backup layer. Application-level backups and server-level backups solve different problems. Use: [Windows VPS Backup Strategy for Small Businesses](https://rafftechnologies.com/windows-server/windows-vps-backup-strategy-small-business). :::cta Explore Data Protection Protect accounting workloads with backup, snapshot, and restore planning before client files and production apps move to a Windows VPS. ::: ## Security planning for accounting data Accounting firms handle sensitive client and business data. A Windows VPS should be secured before production use. Minimum planning: | Security area | Recommendation | |---|---| | User accounts | Named users, not shared logins | | Admin access | Separate admin accounts from daily users | | Passwords | Strong credentials and offboarding process | | RDP exposure | Avoid broad direct RDP exposure | | RD Gateway/VPN | Use controlled remote access where appropriate | | Firewall | Restrict allowed ports and sources | | Permissions | Use groups and least privilege | | Backups | Restrict who can delete or modify backups | | Updates | Schedule Windows and app patching | | Logs | Review failed sign-ins and access events | | Devices | Test printers, scanners, and local drive redirection policy | | Documentation | Record users, apps, backups, owners, and support process | Security is not only a technical setting. It is also user onboarding, offboarding, password discipline, access review, backup ownership, and vendor support. Use: [Windows Server Hardening Checklist](https://rafftechnologies.com/windows-server/windows-server-hardening-checklist). ## Sizing a Windows VPS for an accounting firm Do not size the server only by total employee count. Size it by concurrent users and workload type. Use this as a starting point: | Accounting workload | Starting size | When to move up | |---|---:|---| | 1 admin or solo bookkeeper | 2 vCPU / 4 GB RAM | If apps, PDFs, or reports run on the server | | 2-3 light accounting users | 4 vCPU / 8 GB RAM | If users keep browsers, PDFs, Office apps, and accounting apps open | | 3-5 active app users | 4 vCPU / 16 GB RAM | Better for QuickBooks, Sage, tax software, Access, and file work | | 5-10 active users | 8 vCPU / 32 GB RAM | Useful when the server becomes a daily shared workspace | | Tax season workload | Size for peak season | Seasonal users and reports increase pressure | | Sage 100/300 or SQL-backed workload | 8-16 vCPU / 32-64 GB RAM | Consider database load, reports, and integrations | Plan storage for: - accounting app data; - company files; - tax files; - client folders; - PDF reports; - Excel exports; - user profiles; - scanned documents; - database files; - logs; - backups; - 12 to 24 months of growth. For deeper sizing, use: [Windows VPS sizing for remote users](https://rafftechnologies.com/windows-server/windows-vps-sizing-remote-users). ## Pricing factors for accounting firms The monthly VM price is only one part of the cost. | Cost factor | Why it matters | |---|---| | CPU and RAM | Active users, reports, accounting apps, tax tools | | Storage | Client files, databases, reports, backups, growth | | Backups | Retention, restore testing, off-server copies | | Windows licensing | Depends on provider and deployment model | | RDS CALs | Staff Remote Desktop sessions may require licensing | | App licenses | QuickBooks, Sage, tax software, Microsoft 365 Apps | | SQL Server | Some workloads need SQL licensing and separate backup planning | | Migration | Files, apps, users, permissions, databases, cutover | | Support | Windows, RDS, app, printer, and user troubleshooting | | Security | Access controls, hardening, monitoring, offboarding | A very cheap Windows VPS can become expensive if it is too slow, lacks backups, or creates downtime during filing deadlines. For the cost model, use: [Windows VPS Pricing Explained](https://rafftechnologies.com/windows-server/windows-vps-pricing-explained). :::cta View Pricing Compare Raff Windows VM plans when sizing CPU, memory, storage, backups, and monthly cost for your accounting firm. ::: ## Migration path for accounting firms If the firm currently runs accounting software on an office server or workstation, migrate carefully. Use this path: 1. Inventory users, apps, client files, company files, databases, printers, scanners, and integrations. 2. Confirm vendor support and licensing for the planned hosted/RDS model. 3. Choose the Windows VPS size. 4. Build the Windows VPS. 5. Configure access, firewall, users, and backups. 6. Install accounting and tax applications. 7. Copy test data first. 8. Test with real users from real locations. 9. Test printing, scanning, PDF exports, and reporting. 10. Run a restore test. 11. Schedule cutover outside busy hours. 12. Move final data. 13. Keep the old environment available for rollback. 14. Monitor performance and support tickets after cutover. Do not migrate during tax season unless there is a clear emergency and rollback plan. Use: - [Windows Server Migration Checklist for Small Businesses](https://rafftechnologies.com/windows-server/windows-server-migration-checklist-small-business) - [Local Office Server to Cloud Windows VPS Migration](https://rafftechnologies.com/windows-server/local-server-to-cloud-windows-vps-migration) - [File Server Migration to Windows VPS](https://rafftechnologies.com/windows-server/file-server-migration-to-windows-vps) ## When a Windows VPS is not the right fit A Windows VPS is useful, but not universal. Pause when: | Situation | Better next step | |---|---| | Firm only uses cloud accounting apps | SaaS may already solve the need | | App vendor forbids hosted/RDS use | Do not proceed without support path | | Internet is unreliable | Fix connectivity or design fallback | | Heavy scanning/printing workflow is untested | Test devices first | | Firm needs formal compliance architecture | Design access, logging, encryption, policy, and audit process | | High availability is mandatory | Plan redundancy, failover, and recovery architecture | | Users need local offline work all day | Cloud desktop may frustrate users | | Licensing is unclear | Resolve licensing before production | The right answer may be SaaS accounting, local server, Windows VPS, or a hybrid model. Choose based on workflow, not hype. ## How Raff fits accounting firms Raff fits accounting firms that need a cloud-hosted Windows Server environment for remote staff, QuickBooks Desktop, Sage, tax software, Access or legacy apps, client folders, reports, backups, and office server replacement. Raff’s Windows VM product page currently highlights Windows Server 2019, 2022, and 2025 options, full administrator access with RDP, 24/7 expert support, a 99.9% uptime SLA, and Windows VPS hosting from $28.99 a month: $13.99 compute plus the $15.00 Windows Server licence. Raff can provide the Windows VM foundation. Your firm or MSP should still plan: - application licensing; - RDS CAL requirements; - user access; - permissions; - backups; - restore testing; - vendor support; - client-file structure; - security ownership; - migration and rollback. That is the clean way to use Raff: use the platform for the Windows Server foundation, then design the accounting workload properly. :::cta Deploy Windows Now Create a Raff Windows VM when your accounting firm is ready to run remote users, accounting apps, client files, and Windows workloads in the cloud. ::: ## Recommended path by accounting firm situation | Situation | Read next | |---|---| | You need the broad SMB decision guide | [Windows VPS Hosting for Small Businesses](https://rafftechnologies.com/windows-server/windows-vps-small-business) | | You need a remote desktop decision guide | [Remote Desktop Server for Business](https://rafftechnologies.com/windows-server/remote-desktop-server-for-business) | | You need pricing clarity | [Windows VPS Pricing Explained](https://rafftechnologies.com/windows-server/windows-vps-pricing-explained) | | You use QuickBooks Desktop | [Self-Host QuickBooks Desktop Multi-User on a Windows Server VPS](https://rafftechnologies.com/windows-server/quickbooks-multi-user-windows-server-vps) | | You use Sage | [Host Sage 50, 100, and 300 on Windows VPS](https://rafftechnologies.com/windows-server/sage-hosting-windows-vps) | | You use tax software | [Windows VPS for Tax Software](https://rafftechnologies.com/windows-server/windows-vps-tax-software) | | You need shared client folders | [Windows VPS as a Cloud File Server](https://rafftechnologies.com/windows-server/windows-vps-cloud-file-server) | | You are replacing office hardware | [Cloud Windows Server vs Local Office Server](https://rafftechnologies.com/windows-server/cloud-windows-server-vs-local-office-server) | | You are moving files | [File Server Migration to Windows VPS](https://rafftechnologies.com/windows-server/file-server-migration-to-windows-vps) | | You need backups | [Windows VPS Backup Strategy for Small Businesses](https://rafftechnologies.com/windows-server/windows-vps-backup-strategy-small-business) | | You need secure remote access | [Remote Desktop Gateway vs Direct RDP](https://rafftechnologies.com/windows-server/remote-desktop-gateway-vs-direct-rdp) | | You need hardening | [Windows Server Hardening Checklist](https://rafftechnologies.com/windows-server/windows-server-hardening-checklist) | ## Final accounting firm checklist Before moving accounting work to a Windows VPS, confirm: | Check | Done | |---|---| | Accounting and tax applications listed | ☐ | | Vendor support checked | ☐ | | App licenses reviewed | ☐ | | RDS CAL requirements reviewed | ☐ | | Active and seasonal users estimated | ☐ | | CPU/RAM/storage starting point chosen | ☐ | | Client folder structure documented | ☐ | | File permissions planned | ☐ | | Backup layers defined | ☐ | | Restore test planned | ☐ | | Remote access model chosen | ☐ | | Printers/scanners tested | ☐ | | Security hardening reviewed | ☐ | | Migration window selected | ☐ | | Rollback plan documented | ☐ | | Support owner assigned | ☐ | If the checklist feels unclear, do not treat the environment as production yet. ## What's next - Explore [Raff Windows VM](https://rafftechnologies.com/products/windows-vm) when you are ready to compare Windows VM options. - Review [Raff pricing](https://rafftechnologies.com/pricing) before choosing CPU, RAM, storage, and monthly cost. - Read [Windows VPS Hosting for Small Businesses](https://rafftechnologies.com/windows-server/windows-vps-small-business) for the broader SMB guide. - Read [Remote Desktop Server for Business](https://rafftechnologies.com/windows-server/remote-desktop-server-for-business) before rolling out remote staff access. - Read [Windows VPS Pricing Explained](https://rafftechnologies.com/windows-server/windows-vps-pricing-explained) before budgeting the full environment. - Read [Self-Host QuickBooks Desktop Multi-User on a Windows Server VPS](https://rafftechnologies.com/windows-server/quickbooks-multi-user-windows-server-vps) if your firm uses QuickBooks Desktop. - Read [Host Sage 50, 100, and 300 on Windows VPS](https://rafftechnologies.com/windows-server/sage-hosting-windows-vps) if your firm uses Sage. - Read [Windows VPS for Tax Software](https://rafftechnologies.com/windows-server/windows-vps-tax-software) if filing-season workload is the main driver. - Read [Windows VPS Backup Strategy for Small Businesses](https://rafftechnologies.com/windows-server/windows-vps-backup-strategy-small-business) before moving production data. ## Sources - Raff — [Windows VM product page](https://rafftechnologies.com/products/windows-vm) - Raff — [Pricing](https://rafftechnologies.com/pricing) - Raff — [Windows Server Hub](https://rafftechnologies.com/windows-server) - Raff — [Self-Host QuickBooks Desktop Multi-User on a Windows Server VPS](https://rafftechnologies.com/windows-server/quickbooks-multi-user-windows-server-vps) - Raff — [Host Sage 50, 100, and 300 on Windows VPS](https://rafftechnologies.com/windows-server/sage-hosting-windows-vps) - Raff — [Windows VPS for Tax Software](https://rafftechnologies.com/windows-server/windows-vps-tax-software) - Microsoft Learn — [Remote Desktop Services overview in Windows Server](https://learn.microsoft.com/en-us/windows-server/remote/remote-desktop-services/overview) - Microsoft Learn — [License Remote Desktop Services with Client Access Licenses](https://learn.microsoft.com/en-us/windows-server/remote/remote-desktop-services/rds-client-access-license) - Microsoft Learn — [Deploy Remote Desktop Gateway role for Remote Desktop Services](https://learn.microsoft.com/en-us/windows-server/remote/remote-desktop-services/remote-desktop-gateway-role) - Microsoft Learn — [What is SMB File Sharing for Windows and Windows Server?](https://learn.microsoft.com/en-us/windows-server/storage/file-server/file-server-smb-overview) - Microsoft Learn — [Security baselines guide](https://learn.microsoft.com/en-us/windows/security/operating-system-security/device-management/windows-security-configuration-framework/windows-security-baselines) --- ### Upgrade Windows Server 2016 to 2025: Step-by-Step Guide URL: https://rafftechnologies.com/windows-server/migrate-windows-server-2016-to-2025 Description: Upgrade Windows Server 2016 to 2025 before support ends. Learn when direct in-place upgrade is supported and when AD DS, files, SQL, DHCP, or RDS should move side by side. ## In short **Yes. Windows Server 2016 can be upgraded directly to Windows Server 2025 in supported nonclustered member-server and application-server scenarios using Windows Server 2025 installation media.** You do not need to upgrade through Server 2019 or 2022 first. The decision changes when the server is a **domain controller**. For AD DS, Microsoft recommends deploying a clean Windows Server 2025 machine, promoting it as a new DC, replicating Active Directory, transferring FSMO roles, and then demoting the Server 2016 DC instead of treating the DC like a normal in-place OS upgrade. Windows Server 2016 reaches the end of extended support on **January 12, 2027**. For most production environments, plan the move role by role: direct in-place upgrade can be efficient for a simple supported member server, while side-by-side migration is usually easier to validate for domain controllers, file servers, SQL Server, DHCP, RDS, and mixed line-of-business workloads. If the migration also means moving infrastructure, Raff can be used as the Windows Server 2025 destination while you keep the old Server 2016 system available for validation and rollback. ## Can you upgrade Windows Server 2016 directly to 2025? **Yes. You can upgrade Windows Server 2016 to 2025 directly with installation media on a nonclustered member or application server.** Windows Server 2025 extended the supported in-place upgrade path back to Windows Server 2012 R2, so 2016 no longer needs an intermediate hop through 2019 or 2022. Domain controllers and clustered hosts are the exception: migrate those side by side instead. That means a normal member or application server can have a valid **Windows Server 2016 → Windows Server 2025 in-place upgrade** path without stepping through intermediate Windows Server releases first. Before using it, verify edition compatibility, application support, backup/restore readiness, and Microsoft's current in-place upgrade prerequisites. The important distinction is the upgrade method and server role: | Scenario | Recommended approach | |---|---| | Server 2016 member/app server | Direct in-place upgrade can be supported after compatibility and backup checks | | Server 2016 domain controller | Deploy a fresh Server 2025 DC, replicate, transfer roles, then demote the old DC | | Server 2016 file server | Side-by-side file migration is usually easier to validate and roll back | | Server 2016 SQL host | Build the target SQL environment, migrate user databases and server objects separately | | Server 2016 DHCP server | Migrate DHCP configuration and leases, authorize the new server, then retire the old role | | Server 2016 RDS host | Validate application compatibility, RDS licensing, profiles, certificates, and user cutover before migration | | Failover cluster | Follow the cluster-specific rolling upgrade path; do not treat it like a normal standalone server | One more distinction matters: Microsoft's current **Windows Update** upgrade path to Windows Server 2025 is for eligible Windows Server 2019 and 2022 systems. A Server 2016 → 2025 direct upgrade should therefore be planned around the supported installation-media path, not assumed to appear as a normal Windows Update feature upgrade. ## Windows Server 2016 support ends in January 2027 ![Windows Server 2016 reaches end of support on January 12, 2027; plan the move to Windows Server 2025 before then.](https://raff-images.s3.raffusercloud.com/windows_server_2016_end_of_support_thumbnail_png_ba27eb0deb.jpg) Microsoft's current lifecycle information lists: | Version | Mainstream support | Extended support | |---|---|---| | Windows Server 2016 | Ended | **January 12, 2027** | | Windows Server 2025 | Through 2029 | Through **2034** | After extended support ends, Server 2016 no longer receives normal security updates through the standard lifecycle. Organizations that cannot migrate in time should evaluate Microsoft's current Extended Security Updates options directly rather than relying on old percentage-based pricing examples, because ESU availability and commercial terms can change. The full schedule for every version is in the [Windows Server end-of-life dates](/windows-server/windows-server-end-of-life-dates) table. For a production business server, the practical goal is to finish compatibility testing and cutover **before** the January 2027 deadline, not begin the project when the deadline arrives. ## Choose the migration path by workload The old server's role determines the safest approach. ### Domain controller Use a **side-by-side Active Directory migration**. This is the cleanest path because you keep the existing DC available while the new Server 2025 DC replicates and is validated. ### File server Use a side-by-side migration with Storage Migration Service or a controlled file-copy workflow. Validate NTFS ACLs, share permissions, paths, quotas, and client mappings before retiring the source. ### SQL Server Build and patch the destination SQL Server first, then migrate **user databases** and recreate or transfer instance-level objects such as logins, SQL Agent jobs, credentials, linked servers, and configuration. Do **not** plan a cross-version migration by restoring old `master`, `model`, or `msdb` system database backups onto a new major SQL Server version. Treat server-level configuration as a separate migration task. ### Line-of-business application server Check the application vendor's Windows Server 2025 support matrix first. A technically supported Windows in-place upgrade does not guarantee that your ERP, accounting, tax, document-management, or legacy application supports the new OS. ### DHCP Treat DHCP as its own migration step. Export the existing scopes and leases, install and authorize the DHCP role on the new server, import the configuration, update failover or relay settings if used, then validate clients before removing the old DHCP service. ### Remote Desktop Services RDS migrations need additional planning around Session Host roles, licensing, user profiles, certificates, applications, Group Policy, and client access. Administrative RDP and a true multi-user RDS deployment are not the same architecture. See [Multi-User RDP vs RDS Session Host](/windows-server/multi-user-rdp-vs-rds). Budget for [Windows Server 2025 RDS CALs](/windows-server/rds-cal-licensing-guide) before cutover; 2016-era CALs will not license the new host. ## Side-by-side migration vs in-place upgrade Both approaches are valid tools. The role and rollback requirement decide which one you should use. | Area | In-place upgrade | Side-by-side migration | |---|---|---| | Keeps existing apps/settings | Yes | Rebuild and migrate | | Requires second server | No | Yes | | Rollback simplicity | Depends heavily on backup/restore | Old server remains available during validation | | Removes years of OS state | No | Yes | | Best for DC migration | Not preferred | **Preferred** | | Best for simple member server | Often reasonable | Also valid | | Best for hardware/cloud move | Limited | Strong fit | | Best for role separation | No | Strong fit | If the Server 2016 machine is a simple, well-documented member server and every installed application supports Server 2025, an in-place upgrade can reduce migration work. If it is a domain controller, combined file/application server, poorly documented legacy machine, or the migration also moves workloads into a new cloud environment, side-by-side is usually easier to test and recover from. ## Before you start: inventory, backups, and compatibility Do not begin with the Windows Server 2025 installer. Begin with the source environment. Document: - server roles and features; - installed applications and versions; - Windows services; - scheduled tasks; - SMB shares and NTFS permissions; - local users and groups; - Active Directory roles; - DNS zones and forwarders; - DHCP scopes if present; - certificates; - SQL Server instances and databases; - SQL Agent jobs, logins, linked servers, and credentials; - RDS roles and CAL model if present; - application service accounts; - firewall rules and listening ports; - backup jobs and restore procedures; - integrations that connect by hostname, IP address, or UNC path. Create a **current backup and verify that the restore path works**. A migration plan that has never tested recovery is not a rollback plan. For business workloads, also document the current CPU, memory, storage utilization, active users, and database size. That data should drive the destination VM size. ## Destination sizing on Raff If the migration also moves the workload to new infrastructure, size the destination from the actual Server 2016 workload rather than copying the old VM or physical server configuration blindly. Review peak CPU, memory pressure, storage use, active users, database size, and growth before selecting the target. Current Raff Windows VM examples are: | Windows VM | Compute | Windows Server Standard | Starting total | |---|---:|---:|---:| | 2 vCPU / 4 GB / 80 GB | $22.99/mo | $15/mo | **$37.99/mo** | | 4 vCPU / 8 GB / 120 GB | $40.99/mo | $15/mo | **$55.99/mo** | | 8 vCPU / 16 GB / 180 GB | $76.99/mo | $15/mo | **$91.99/mo** | These are starting infrastructure examples, not workload guarantees. RDS User SALs, SQL Server licensing, additional storage, backups, and application licensing are separate when applicable. See [Windows Server licensing](/windows-server/windows-licensing) and the live [Windows VM plans](/products/windows-vm) before deployment. A side-by-side move is especially useful when you want the old Server 2016 system to remain intact while the Server 2025 destination is tested. The decision usually looks like this: | Migration situation | Practical next step | |---|---| | Existing VM is healthy and every role supports in-place upgrade | Evaluate the direct installation-media upgrade path | | You want a cleaner rollback path | Build a separate Server 2025 destination | | The old server combines AD, files, SQL, and apps | Consider splitting roles where it improves recovery or security | | Application vendor has not validated Server 2025 | Resolve compatibility before committing to the cutover | | You are moving providers or leaving aging hardware | Build and validate the new destination before changing production | The correct destination may be **more than one VM**. A migration is a good time to stop running every role on the same server when separation improves security, maintenance, performance isolation, recovery, or vendor support. ```text Windows VM 1 → Active Directory / DNS Windows VM 2 → Business application / RDS Windows VM 3 → SQL Server, if workload and architecture justify separation ``` :::cta Talk to Windows Engineer Review the Server 2016 roles, applications, user count, storage, licensing, and rollback requirements before choosing the Server 2025 destination. ::: ## Phase 1 — Pre-flight checks on the Server 2016 source ### Check AD DS health If the source is a domain controller, validate Active Directory before adding a new DC. ```powershell dcdiag /v repadmin /replsummary repadmin /showrepl ``` Fix DNS, replication, time synchronization, or directory errors before migration. Adding a Server 2025 DC to an unhealthy domain only carries the existing problem forward. ### Check domain and forest functional levels ```powershell Get-ADDomain | Format-List Name, DomainMode Get-ADForest | Format-List Name, ForestMode ``` A Windows Server 2025 DC requires the existing domain and forest to be at least the **Windows Server 2016 functional level**. Windows Server 2012 R2 functional level does not support Server 2025 domain controllers. If the level is lower, plan the functional-level change before attempting promotion and verify all existing DCs support the target level. ### Confirm SYSVOL uses DFSR For domains upgraded from much older Windows Server versions, verify SYSVOL replication is using DFSR rather than legacy FRS. ```cmd dfsrmig /getglobalstate dfsrmig /getmigrationstate ``` A completed migration should report the DFSR migration as finished. Do not introduce a new Server 2025 DC into an environment that still depends on an unsupported legacy SYSVOL replication state. ### Identify FSMO role holders ```powershell netdom query fsmo ``` Record the Schema Master, Domain Naming Master, PDC Emulator, RID Master, and Infrastructure Master before you make changes. ### Inventory shares and permissions ```powershell Get-SmbShare | Format-Table Name, Path, Description -AutoSize Get-SmbShare | ForEach-Object { Write-Host "`n=== Share: $($_.Name) ===" Get-SmbShareAccess -Name $_.Name | Format-Table } ``` Keep this output so you can compare the destination after migration. ## Phase 2 — Prepare the Windows Server 2025 destination Deploy a clean Windows Server 2025 destination and patch it before adding production roles. For a domain-controller migration, use a stable private IP, correct DNS settings, and network connectivity to the existing AD environment. During the initial join phase, the new server should resolve the existing Active Directory domain through an existing DNS/DC path. After patching and confirming connectivity, join the existing domain: ```powershell $domain = "yourdomain.local" $cred = Get-Credential Add-Computer -DomainName $domain -Credential $cred -Restart ``` Replace example names, addresses, and domain values with your own environment. ## Phase 3 — Add the Server 2025 domain controller ![Side-by-side AD migration: a new Windows Server 2025 domain controller is promoted alongside the existing Server 2016 DC before FSMO transfer and demotion.](https://raff-images.s3.raffusercloud.com/active_directory_2016_to_2025_migration_diagram_png_a189dbbe9b.jpg) Microsoft recommends a clean OS install and new DC promotion rather than an in-place OS upgrade of an existing domain controller. Install AD DS: ```powershell Install-WindowsFeature -Name AD-Domain-Services -IncludeManagementTools ``` Then promote the Server 2025 machine as an additional domain controller: ```powershell $dsrmPassword = Read-Host -Prompt "Enter DSRM password" -AsSecureString Install-ADDSDomainController ` -DomainName "yourdomain.local" ` -InstallDns:$true ` -Credential (Get-Credential) ` -SafeModeAdministratorPassword $dsrmPassword ` -NoGlobalCatalog:$false ` -Force:$true ``` Server Manager and the AD DS deployment process can prepare the forest/domain as part of supported promotion workflows when the account has the required rights. Do not move FSMO roles immediately after the first reboot. First verify replication and DNS health. ## Phase 4 — Validate AD replication before role transfer Run: ```powershell repadmin /replsummary repadmin /showrepl ``` Then confirm important directory objects are visible on both old and new DCs: ```powershell Get-ADUser -Filter * | Measure-Object | Select-Object Count Get-ADComputer -Filter * | Measure-Object | Select-Object Count Get-ADGroup -Filter * | Measure-Object | Select-Object Count ``` Object counts are a basic sanity check, not a full replication test. Replication errors must be resolved before the cutover continues. ## Phase 5 — Transfer FSMO roles After the new DC is healthy and replicating, transfer the FSMO roles: ```powershell Move-ADDirectoryServerOperationMasterRole ` -Identity "NEW-DC-01" ` -OperationMasterRole SchemaMaster, DomainNamingMaster, PDCEmulator, RIDMaster, InfrastructureMaster ``` Verify: ```powershell netdom query fsmo ``` All roles that you intended to move should now reference the Server 2025 DC. Also verify Global Catalog status and DNS configuration before changing client dependencies. ## Phase 6 — Move DNS and DHCP dependencies ### DNS Update DHCP options, static servers, network devices, and application configurations that still use the old DC's IP as their DNS server. If you have more than one DC, follow your normal multi-DC DNS client design rather than pointing every DC only at itself. If the new Server 2025 DC eventually becomes the only DC, validate its DNS service and client configuration after the old server is retired. ### DHCP Migrating DHCP from 2016 to 2025 is a separate cutover: 1. Inventory scopes, reservations, options, policies, filters, and failover relationships. 2. Export the Server 2016 DHCP configuration and active leases using the supported Windows Server DHCP migration workflow. 3. Install the DHCP Server role on the Server 2025 destination. 4. Authorize the new DHCP server in Active Directory when applicable. 5. Import scopes and leases. 6. Update routers or DHCP relay/IP helper addresses if the server IP changes. 7. Validate several clients obtain the expected address, gateway, DNS servers, and lease duration. 8. Only then deactivate the old DHCP service. Do not run two independent DHCP servers serving the same scope unless you have intentionally configured supported DHCP failover. ## Phase 7 — Migrate file shares Microsoft Storage Migration Service is designed for moving file-server data and configuration to newer Windows Server systems. It is not an Active Directory domain-controller migration tool. AD DS and file-server migration should be treated as separate workstreams even if the old server currently runs both roles. Storage Migration Service can help inventory and transfer file-server data while preserving important file and share metadata. A typical workflow is: 1. Inventory source files and shares. 2. Select the Server 2025 destination. 3. Map source and destination volumes. 4. Transfer data. 5. Review transfer errors. 6. Run a final synchronization near cutover. 7. Validate NTFS ACLs and share permissions. 8. Decide whether to retain or change the old server identity/hostname based on the migration design. After transfer, compare: ```powershell Get-SmbShare | Format-Table Name, Path, Description -AutoSize ``` with the inventory captured before migration. ## Phase 8 — Migrate SQL Server correctly If SQL Server runs on the Server 2016 machine, decide first whether SQL should remain on the same Windows VM as the application or move to its own server. For a new SQL Server 2025 deployment, use [Install SQL Server 2025 on Windows Server](/windows-server/install-sql-server-2025-windows-server-vps). A safe high-level migration plan is: 1. Install and patch the target SQL Server version. 2. Back up **user databases** on the source SQL instance. 3. Restore the user databases to the target version using a supported database upgrade path. 4. Migrate logins while preserving SIDs where required. 5. Script or migrate SQL Agent jobs. 6. Recreate linked servers, credentials, operators, Database Mail, server-level permissions, and other instance objects as needed. 7. Update application connection strings or DNS aliases. 8. Run DBCC and application smoke tests. 9. Validate backups on the destination. Do not assume old SQL system database backups can simply be restored onto a newer major SQL Server version. Server-level objects need their own migration plan. After migration, apply the [SQL Server 2025 Security Hardening Guide](/windows-server/sql-server-2025-security-hardening-vps). ## Phase 9 — Migrate line-of-business applications The OS upgrade path may be supported while the application itself is not. For each application: 1. Check the vendor's official Windows Server 2025 compatibility statement. 2. Confirm the application version is still supported. 3. Document services, ports, file paths, certificates, and service accounts. 4. Confirm how licensing moves to new hardware or a new VM. 5. Install the supported application version on the destination. 6. Migrate data using the vendor-supported process. 7. Validate a representative user workflow before broad cutover. QuickBooks, Sage, ERP products, tax software, document-management systems, custom .NET applications, and legacy databases all have different migration constraints. Do not use a generic Windows migration procedure as a substitute for vendor documentation. ## Phase 10 — Plan the cutover ![Cutover weekend checklist for a Windows Server 2016 to Windows Server 2025 migration showing preparation, migration, validation, and monitoring tasks.](https://raff-images.s3.raffusercloud.com/Adsiz_tasarim_79d119fa8a.jpg) A production cutover checklist should include: ### Before the maintenance window - source backup completed and verified; - destination backup configured; - AD replication healthy; - new DNS/DC validated; - file delta synchronized; - SQL/app migration rehearsed; - DHCP migration prepared if applicable; - RDS licensing and profile plan confirmed; - firewall rules validated; - rollback criteria documented; - users notified. ### During cutover - stop writes or application services where required; - run final file/database synchronization; - move application endpoints, DNS aliases, or client configuration; - validate user authentication; - validate application login; - validate file access and permissions; - validate database transactions; - validate backup jobs; - validate DHCP/DNS if those roles moved. ### After cutover Do not immediately delete Server 2016. Keep the old environment available according to the rollback plan while you confirm production stability. ## Phase 11 — Demote the Server 2016 domain controller Only demote the old DC after: - FSMO roles have moved; - replication is healthy; - DNS no longer depends on the old DC; - applications no longer use the old server for LDAP/Kerberos/DNS; - DHCP or other co-hosted roles have been migrated; - backup and rollback requirements are satisfied. Use the supported AD DS demotion workflow. After a **graceful demotion**, verify Active Directory Sites and Services, DNS, and the Computers/Domain Controllers containers are clean. Do not automatically delete the old DC's computer object or perform metadata cleanup when the normal demotion completed successfully. Manual metadata cleanup is primarily for failed or forced demotions that leave orphaned DC metadata behind. ## Phase 12 — Raise the AD functional level only when needed After every domain controller runs Windows Server 2025, you can evaluate raising the domain and forest functional levels to Windows Server 2025. Windows Server 2025 functional level enables Server 2025-specific AD DS capabilities such as the optional 32K database page feature. Do not raise the functional level just because the migration is finished. Confirm: - all DCs are Server 2025; - AD replication is healthy; - backups are current; - applications and identity dependencies are validated; - you understand which 2025-only features you intend to use. Older guidance often described functional-level raises as strictly irreversible. Microsoft's current Windows Server 2025 documentation supports lowering a 2025 functional level back to Windows Server 2016 **in specific supported conditions**, provided features that prevent rollback have not been enabled. That does not make rollback something to depend on casually; treat functional-level changes as planned production changes with backups and validation. ## In-place upgrade checklist for a simple member server If you decide that a direct Server 2016 → 2025 in-place upgrade is the better path for a non-DC server, verify all of the following first: - Server 2025 supports the hardware/virtual platform. - The current Server 2016 installation is fully patched and healthy. - Application vendors support Windows Server 2025. - You have a verified full backup and rollback path. - You are using a supported Windows Server 2025 installation-media upgrade path. - Source and target editions are compatible with Microsoft's upgrade restrictions. - You are not trying to switch between Server Core and Desktop Experience during the upgrade. - The server is not booting from an unsupported VHD configuration for in-place upgrade. - NIC Teaming and other documented upgrade blockers have been reviewed. - You have captured network, role, feature, firewall, and application configuration before upgrade. After the upgrade, verify Windows activation/licensing, services, application health, network interfaces, scheduled tasks, firewall rules, event logs, backups, and monitoring. ## Common migration mistakes ### Treating a domain controller like a normal app server A direct OS upgrade may exist as a Windows upgrade path, but Microsoft recommends adding a clean newer DC and demoting the old one. Keep the AD DS migration architecture separate from generic member-server upgrade guidance. ### Raising functional levels before the environment is stable Functional level is not the first migration step. Complete the DC migration and validation first. ### Moving SQL user databases but forgetting instance objects Database backups do not automatically move logins, jobs, linked servers, credentials, and every server-level configuration item. ### Restoring old SQL system databases onto a newer major version Do not use this as a generic cross-version migration technique. Recreate or migrate server-level objects using supported procedures. ### Forgetting DHCP relay or IP helper configuration The DHCP database can migrate successfully while clients still fail because routers continue sending DHCP requests to the old server IP. ### Leaving applications pointed at the old hostname or IP Search configuration files, scheduled tasks, ODBC DSNs, mapped drives, service settings, DNS records, scripts, printers, and line-of-business integrations before shutdown. ### Treating a snapshot as the entire backup strategy A snapshot can help with short-term rollback but does not replace application-aware backups, off-server copies, and restore testing. ## Running a Windows Server 2016 migration on Raff A Windows Server 2016 migration to Raff follows the same role-by-role plan: build the 2025 destination on a Raff Windows VM, replicate or migrate the workload, validate it, then cut over only when the new system passes the required checks. Server 2016 leaves extended support on January 12, 2027, so the migration plan should be driven by the application and role dependencies rather than the deadline alone. A Raff migration project can use: - Windows Server 2025 VMs; - private networking between destination systems; - additional volumes for application or file data; - snapshots and backups for rollback planning; - separate Windows VMs when AD, application, RDS, or SQL roles should not share one operating system; - Raff-provided Windows Server Standard licensing under SPLA, or eligible customer-owned licensing where Microsoft's Flexible Virtualization Benefit requirements are met. Raff-hosted RDS licensing is separate from the Windows Server license and uses **RDS User SALs**. SQL Server and application licensing also remain separate unless explicitly included by the relevant agreement. If the migration is also a provider move, keep the commercial decision separate from the technical cutover: first validate the target architecture, licensing, sizing, backup plan, and rollback path, then move production. The [Windows VM page](/products/windows-vm) shows current plans, while [Windows Server licensing](/windows-server/windows-licensing) covers SPLA, BYOL, CAL, and RDS distinctions. ## Validation scope The Raff Windows content lab has separately validated Windows Server 2025 deployment and core procedures used across this guide, including AD DS role installation/promotion workflows, FSMO transfer, Windows file-server migration tooling, and SQL Server 2025 deployment used by the linked Windows articles. This article does **not** claim that one synthetic lab VM reproduced every possible 2016 → 2025 production migration end to end. Real migrations vary by domain health, applications, data size, networking, certificates, identity integrations, and vendor support requirements. ## What's next - [Windows Server 2019 vs 2022 vs 2025](/windows-server/windows-server-version-comparison) - [Set Up an Active Directory Domain Controller](/windows-server/active-directory-domain-controller) - [Install SQL Server 2025 on Windows Server](/windows-server/install-sql-server-2025-windows-server-vps) - [SQL Server 2025 Security Hardening](/windows-server/sql-server-2025-security-hardening-vps) - [Windows Server 2016 End of Life: Dates, ESU, and Migration Options](/windows-server/windows-server-2016-end-of-life) - [Windows Server Licensing: SPLA, BYOL, CALs & RDS](/windows-server/windows-licensing) - [Raff Windows VM](/products/windows-vm) ## Sources - Microsoft Learn — [Plan your Windows Server upgrade path](https://learn.microsoft.com/en-us/windows-server/get-started/upgrade-overview) - Microsoft Learn — [Perform an in-place upgrade of Windows Server](https://learn.microsoft.com/en-us/windows-server/get-started/upgrade-in-place) - Microsoft Learn — [Upgrade domain controllers to a newer version of Windows Server](https://learn.microsoft.com/en-us/windows-server/identity/ad-ds/deploy/upgrade-domain-controllers) - Microsoft Learn — [Active Directory Domain Services functional levels](https://learn.microsoft.com/en-us/windows-server/identity/ad-ds/active-directory-functional-levels) - Microsoft Learn — [Raise domain and forest functional levels](https://learn.microsoft.com/en-us/windows-server/identity/ad-ds/plan/raise-domain-forest-functional-levels) - Microsoft Learn — [Lower domain and forest functional levels](https://learn.microsoft.com/en-us/windows-server/identity/ad-ds/plan/lower-domain-forest-functional-levels) - Microsoft Learn — [Storage Migration Service overview](https://learn.microsoft.com/en-us/windows-server/storage/storage-migration-service/overview) - Microsoft Learn — [Windows Server release information](https://learn.microsoft.com/en-us/windows/release-health/windows-server-release-info) - Sources revalidated: 2026-09-17 --- Microsoft, Windows Server, Active Directory, SQL Server, Hyper-V, Windows Admin Center, and Storage Migration Service are trademarks or products of Microsoft Corporation. Raff is an independent infrastructure provider and is not affiliated with or endorsed by Microsoft. --- ### Windows Server End of Life Dates: Every Version Compared URL: https://rafftechnologies.com/windows-server/windows-server-end-of-life-dates Description: Every Windows Server end-of-life date in one table: 2012, 2016, 2019, 2022, and 2025, plus what mainstream vs extended support really means and when to act. ## In short For Windows Server lifecycle planning, the date that matters most is the end of **extended support**, when normal security updates stop. The nearest LTSC deadline is **Windows Server 2016 on January 12, 2027**. Windows Server 2019 follows on **January 9, 2029**. Windows Server 2022 is not EOL in 2026: mainstream support ends in October 2026, while extended support continues until **October 14, 2031**. Windows Server 2025 is supported through **November 14, 2034**. The most common end-of-life questions are: - **Windows Server 2016 EOL date:** January 12, 2027. - **Windows Server 2019 EOL date:** January 9, 2029. - **Windows Server 2022 EOL date:** October 14, 2031. Its mainstream phase ends October 13, 2026. - **Windows Server 2025 EOL date:** November 14, 2034. Raff currently offers Windows Server 2019, 2022, and 2025. This guide uses the ISO dates in Microsoft's Windows Server release-information table for consistency; Microsoft Lifecycle pages can display an adjacent calendar date because those pages present support dates in Pacific Time. ## The complete Windows Server end-of-life table In this table, **EOL** means the end of extended support and the normal security-update stream. It does not mean the end of mainstream support. Older releases may have a separate paid Extended Security Updates (ESU) period after EOL. | Version | Released | Extended support / normal security updates through (EOL) | Mainstream support | ESU status | |---|---|---|---|---| | Windows Server 2012 / 2012 R2 | 2012 / 2013 | Ended Oct 10, 2023 | Ended Oct 9, 2018 | Year 3 ends **Oct 13, 2026** | | Windows Server 2016 | 2016 | **Jan 12, 2027** | Ended Jan 11, 2022 | Eligible deployments can receive ESU for up to 3 years, through 2030 | | Windows Server 2019 | 2018 | **Jan 9, 2029** | Ended Jan 9, 2024 | No post-EOL ESU end date published here | | Windows Server 2022 | 2021 | **Oct 14, 2031** | **Oct 13, 2026** | Not applicable while normal support continues | | Windows Server 2025 | 2024 | **Nov 14, 2034** | **Nov 13, 2029** | Not applicable while normal support continues | > Microsoft publishes lifecycle information in more than one view. The Windows Server release-information table uses ISO 8601 dates, while product Lifecycle pages state that dates are shown in Pacific Time. That can make an adjacent calendar date appear in another locale or view. For compliance records, cite the Microsoft page and date convention you used. ## Windows Server support lifecycle: what mainstream and extended support mean The two support phases are frequently confused, and the difference determines how urgent a migration really is: - **Mainstream support** includes security updates, product fixes, and broader servicing under Microsoft's Fixed Lifecycle Policy. - **Extended support** continues security updates after mainstream support ends. When extended support ends, the release no longer receives normal security updates. - **Extended Security Updates (ESU)** are a paid, security-only bridge Microsoft may offer after extended support for eligible older versions. ESU should be treated as migration runway, not a long-term operating model. So a search for "Windows Server 2022 end of life" needs a precise answer: Server 2022 is not at end of life in October 2026. It leaves mainstream support then and continues receiving extended-support security updates until October 14, 2031. ## Check which version and phase you are on Run this in PowerShell on each server: ```powershell Get-ComputerInfo | Select-Object OsName, OsVersion, OsBuildNumber ``` Then map the build number to the version and its deadline: | Build number | Version | Your current lifecycle deadline | |---|---|---| | 9200 / 9600 | Server 2012 / 2012 R2 | ESU Year 3 ends Oct 13, 2026 | | 14393 | Server 2016 | Extended support ends Jan 12, 2027 | | 17763 | Server 2019 | Extended support ends Jan 9, 2029 | | 20348 | Server 2022 | Extended support ends Oct 14, 2031 | | 26100 | Server 2025 | Extended support ends Nov 14, 2034 | For a fleet, run the same check remotely with `Invoke-Command -ComputerName SRV01,SRV02 { Get-ComputerInfo | Select-Object CsName, OsName, OsBuildNumber }`. More fleet-audit commands are in our [PowerShell reference for Windows VPS admins](/windows-server/powershell). ## Windows Server 2012 and 2012 R2 reach the end of ESU in October 2026 Windows Server 2012 and 2012 R2 left extended support in October 2023. Microsoft's standard three-year ESU program reaches its final Year 3 cutoff on **October 13, 2026**. ESU provides critical and important security updates for eligible systems, but it does not restart the normal product lifecycle or add new features. If you still run 2012-era servers, migration should already be in progress. Our [local server to cloud migration guide](/windows-server/local-server-to-cloud-windows-vps-migration) covers file, application, and directory workloads. ## Windows Server 2016 reaches end of extended support on January 12, 2027 **Windows Server 2016 reaches end of support on January 12, 2027.** Until then, it remains in extended support and continues receiving normal security updates under Microsoft's Fixed Lifecycle Policy. Microsoft has also announced Extended Security Updates for eligible Windows Server 2016 Standard and Datacenter deployments after that date. Microsoft describes the ESU window as providing critical and important security updates for **up to three years, through 2030**. Because the currently published documentation does not give this guide a final exact day in 2030, we do not invent one. A related deadline can exist on the same machine: SQL Server 2016 left extended support on July 14, 2026, so an application stack may become unsupported before the Windows Server operating system does. We cover the deadline, ESU choices, and migration options in the dedicated [Windows Server 2016 end-of-life guide](/windows-server/windows-server-2016-end-of-life). For the migration path, see [upgrade Windows Server 2016 to 2025](/windows-server/migrate-windows-server-2016-to-2025). ## Windows Server 2019 EOL date: is Server 2019 still supported? **Yes. Windows Server 2019 is still supported through January 9, 2029.** It is already in extended support, which means security updates continue but the mainstream-support phase has ended. If an application vendor still requires Server 2019, document that dependency and plan the replacement before the final support window. For a new deployment without a compatibility constraint, compare it with the newer releases rather than choosing 2019 only because an older application already uses it. ## Windows Server 2022 end of support date and EOL date **Windows Server 2022 is not EOL in 2026.** Microsoft's ISO release-information table lists mainstream support ending **October 13, 2026** and extended support ending **October 14, 2031**. The product Lifecycle view may show the following calendar day depending on the time-zone presentation. Existing healthy 2022 workloads therefore do not need an emergency migration simply because mainstream support ends in 2026. For new deployments, Server 2025 provides the longer current LTSC support runway when the full software stack is validated. For the practical trade-offs, see our [Windows Server 2022 vs 2025 comparison](/windows-server/windows-server-version-comparison). ## Windows Server 2025 is supported through November 2034 Windows Server 2025 is Microsoft's current Long-Term Servicing Channel release. Microsoft's ISO release-information table lists mainstream support through **November 13, 2029** and extended support through **November 14, 2034**. Raff licenses Windows Server Standard per instance under Microsoft SPLA; current compute and licence pricing is on the [pricing page](/pricing). Customers using their own eligible Microsoft licensing should verify the applicable outsourcing and Flexible Virtualization Benefit rights for the intended hosted deployment. ## Windows Server 2026 release date: what comes after 2025 Microsoft has not announced a Windows Server 2026 LTSC release or a successor LTSC release date in its current Windows Server release information. **Windows Server 2025 remains the current LTSC release.** Microsoft also maintains an Annual Channel focused on container and microservice scenarios, with a shorter support cycle, but those releases are not the next general-purpose LTSC version. For production planning, use Server 2025 as the current long-term baseline and treat future product names or dates as unconfirmed until Microsoft publishes them. See the [Windows Server version comparison](/windows-server/windows-server-version-comparison) for the current deployment choices. ## Database and mail server dates to track alongside The OS is only one layer. Microsoft server applications have their own support schedules: | Product | Extended support ends | |---|---| | SQL Server 2016 | Ended Jul 14, 2026 | | SQL Server 2017 | Oct 12, 2027 | | SQL Server 2019 | Jan 8, 2030 | | SQL Server 2022 | Jan 11, 2033 | | Exchange Server 2016 / 2019 | Ended Oct 14, 2025 | A fully patched Windows Server can still host an unsupported database or application. Audit both the OS and the workloads before deciding what migrates when. ## Which version should you deploy today | Your situation | Practical choice | Why | |---|---|---| | New server, no legacy constraints | Windows Server 2025 | Longest current LTSC support runway | | A vendor app certifies only up to 2022 | Windows Server 2022 | Extended support continues through 2031 | | Anything on 2012/R2 or 2016 | Start migration planning now | Support or ESU deadlines are close | | Anything on 2019 | Plan the replacement window | Extended support ends in January 2029 | If lifecycle planning also means moving the workload to new infrastructure, size and validate the destination before the cutover. Current [Raff Windows VM](/products/windows-vm) plans support Windows Server 2019, 2022, and 2025, and the [Windows Server licensing guide](/windows-server/windows-licensing) explains SPLA, BYOL, CAL, and RDS distinctions. ## Common mistakes reading lifecycle dates - **Treating end of mainstream support as end of life.** Server 2022 leaving mainstream support in October 2026 does not end security updates; extended support continues until 2031. - **Assuming ESU arrives automatically.** ESU is an eligibility and licensing path, not an automatic grace period. - **Tracking only the OS date.** SQL Server, Exchange, and line-of-business applications have separate lifecycles. - **Deploying new systems on older versions without a compatibility reason.** A legacy version creates an earlier migration deadline. - **Planning to the exact deadline.** Leave time for application validation, rollback testing, licensing, and cutover. ## What's next - [Windows Server 2016 end of life: dates, ESU, and migration options](/windows-server/windows-server-2016-end-of-life) - [Upgrade Windows Server 2016 to 2025](/windows-server/migrate-windows-server-2016-to-2025) - [Windows Server 2022 vs 2025](/windows-server/windows-server-version-comparison) - [Windows Server licensing: SPLA, BYOL, CALs and RDS](/windows-server/windows-licensing) - [Raff Windows VM](/products/windows-vm) ## Sources - Microsoft Learn: [Windows Server release information](https://learn.microsoft.com/en-us/windows/release-health/windows-server-release-info) - Microsoft Lifecycle: [Windows Server 2016](https://learn.microsoft.com/en-us/lifecycle/products/windows-server-2016), [Windows Server 2019](https://learn.microsoft.com/en-us/lifecycle/products/windows-server-2019), [Windows Server 2022](https://learn.microsoft.com/en-us/lifecycle/products/windows-server-2022), [Windows Server 2025](https://learn.microsoft.com/en-us/lifecycle/products/windows-server-2025), [Windows Server 2012 R2](https://learn.microsoft.com/en-us/lifecycle/products/windows-server-2012-r2) - Microsoft Lifecycle: [Extended Security Updates FAQ](https://learn.microsoft.com/en-us/lifecycle/faq/extended-security-updates) - Microsoft Learn: [Prepare Extended Security Updates for Windows Server through Azure Arc](https://learn.microsoft.com/en-us/azure/azure-arc/servers/prepare-extended-security-updates) - Microsoft Learn: [Windows Server servicing channels](https://learn.microsoft.com/en-us/windows-server/get-started/servicing-channels-comparison) - Sources revalidated: 2026-09-17 --- ### Windows Server 2016 End of Life: Dates, ESU, and Migration Options URL: https://rafftechnologies.com/windows-server/windows-server-2016-end-of-life Description: Windows Server 2016 support ends January 12, 2027. See the exact lifecycle date, what ESU covers, how pricing works, and when to upgrade or migrate to Windows Server 2025. ## In short Windows Server 2016 reaches **end of extended support on January 12, 2027**. After that date, normal security updates stop unless the server is covered by an eligible Extended Security Updates path. Microsoft offers Windows Server 2016 ESU for up to three additional years, through 2030. For most production workloads, ESU should be migration runway rather than the long-term plan. Raff supports Windows Server 2019, 2022, and 2025, so teams can build a separate destination, validate the workload, and cut over before the Server 2016 deadline. ## Windows Server 2016 support ends January 12, 2027 Windows Server 2016 follows Microsoft's Fixed Lifecycle Policy. | Milestone | Date | Meaning | |---|---|---| | Release | October 15, 2016 | Windows Server 2016 entered general availability | | Mainstream support ended | January 2022 | Feature and non-security servicing became more limited | | **Extended support ends** | **January 12, 2027** | Normal security updates and support end | | ESU period | Up to three years after end of support | Critical and Important security updates for eligible systems | Microsoft's February 2026 end-of-support announcement and its Windows Server 2016 ESU billing documentation both use **January 12, 2027** as the end-of-support date. Microsoft's product Lifecycle page currently shows an adjacent calendar date because that page states its dates are displayed in Pacific Time. For migration planning, use the Microsoft EOS and ESU documentation together and record which date convention your compliance documentation cites. The lifecycle applies to Windows Server 2016 Standard, Datacenter, Essentials, and MultiPoint Premium. There is no separate "Windows Server 2016 R2" release. ## What happens after Windows Server 2016 end of support Windows Server 2016 does not stop booting after the support date. Existing applications and services can continue to run. The change is supportability: - normal Windows Server 2016 security updates stop; - newly discovered vulnerabilities can remain unpatched unless the server is covered by ESU; - software and security vendors may narrow or end support for products running on Server 2016; - unsupported operating systems can create additional compliance, audit, and insurance requirements; - troubleshooting becomes harder when Microsoft or an application vendor requires a supported OS before investigating a problem. If the server is internet-facing, identity-related, or runs business-critical software, waiting until January 2027 to begin compatibility testing increases migration risk. ## SQL Server 2016 is already out of extended support Do not assume the Windows Server lifecycle also covers the database running on it. **SQL Server 2016 reached the end of extended support on July 14, 2026.** A Windows Server 2016 machine can therefore still have a supported operating system in late 2026 while running a SQL Server version that has already left normal extended support. If both products are installed on the same machine, plan the SQL Server upgrade or migration separately from the Windows Server move. ## Windows Server 2016 ESU provides a temporary bridge through 2030 Microsoft announced Extended Security Updates for Windows Server 2016 in February 2026. For eligible Windows Server 2016 Standard and Datacenter systems, ESU can provide **Critical and Important security updates for up to three years after end of support, through 2030**. ESU does not return Windows Server 2016 to normal mainstream or extended support. Microsoft states that ESU does not include: - new features; - customer-requested non-security hotfixes; - design changes. Windows Server 2016 ESU through Azure Arc became configurable in the Azure portal on **August 3, 2026**. Billing for Windows Server 2016 ESU enabled through Azure Arc begins **January 13, 2027**. Microsoft also states that licenses provisioned after EOS are subject to back-billing to the Windows Server 2016 end-of-support date. ## Windows Server 2016 ESU pricing is not one flat per-server number There is no reliable universal dollar figure that applies to every Windows Server 2016 machine. Microsoft documents ESU licensing in terms of factors including: - Standard vs Datacenter edition; - physical or virtual core licensing; - the number of covered cores; - the purchasing route; - eligible licensing agreements and discounts. Azure Arc-enabled ESU provides monthly subscription billing. Commercial Licensing is another route for eligible customers. Microsoft's current ESU eligibility guidance says hosted or on-premises workloads can qualify through routes such as active Software Assurance, qualifying subscription licenses, or license-included service from an SPLA partner, subject to the applicable licensing requirements. For budgeting, use Microsoft's current ESU licensing guidance or an official Microsoft licensing quote for the exact environment. Do not budget from a generic fixed per-server number copied from another configuration. ## Your three realistic options are ESU, in-place upgrade, or migration | Option | Best fit | Main trade-off | |---|---|---| | Extended Security Updates | A real dependency prevents migration before January 2027 | Buys time but keeps the old OS | | In-place upgrade | The existing server and every installed role support the upgrade path | Faster move but retains the existing server state | | Clean migration to Windows Server 2025 | You want an isolated test target and clearer rollback path | Requires migration planning and cutover | ## Option 1 - Use ESU when a real blocker prevents migration ESU is appropriate when an application vendor, hardware dependency, or regulated change process makes migration before the deadline unrealistic. Treat it as a bridge with an exit date. Document: 1. why the workload cannot move now; 2. the exact ESU licensing route; 3. who owns the migration project; 4. the target Windows Server version; 5. the planned retirement date for Server 2016. Azure Arc-enabled ESU is useful for organizations that need monthly subscription billing. Microsoft notes that late enrollment can create back-billing to the Windows Server 2016 end-of-support date. ## Option 2 - Windows Server 2016 can upgrade directly to Windows Server 2025 in supported scenarios Microsoft's current upgrade matrix supports a direct **Windows Server 2016 to Windows Server 2025** in-place upgrade using installation media for eligible nonclustered systems. Starting with Server 2025, Microsoft allows supported nonclustered systems to jump up to four Windows Server versions in one upgrade path. That does not mean every Server 2016 machine should be upgraded in place. Before using the direct path, verify: - the edition and installation option are supported; - the machine meets Windows Server 2025 requirements; - every installed role supports in-place upgrade; - application and driver vendors support Windows Server 2025; - backups and rollback have been tested; - the target Windows Server license and activation method are ready. For hosted VMs, also verify what the provider supports. A clean side-by-side migration may be safer when the workload is important enough that you want the original Server 2016 machine intact during validation. ## Option 3 - Migrate to a new Windows Server 2025 VM A clean migration creates a separate destination instead of replacing the current OS in place. This can make testing and rollback easier because the Server 2016 system remains unchanged until the new workload is verified. Common candidates include: - Active Directory domain controllers; - IIS applications; - file servers; - SQL Server workloads; - accounting and ERP applications; - RDS workloads. For Raff customers, current Windows VM examples are: | Windows VM | Compute | Windows Server Standard SPLA | Monthly total | |---|---:|---:|---:| | 1 vCPU / 2 GB / 50 GB | $13.99 | $15 | **$28.99** | | 2 vCPU / 4 GB / 80 GB | $22.99 | $15 | **$37.99** | | 4 vCPU / 8 GB / 120 GB | $40.99 | $15 | **$55.99** | The Windows Server Standard SPLA charge is **$15 per instance per month**. Optional RDS User SALs, extra storage, backups, and application or database licensing are separate where applicable. Raff Windows VMs include unmetered bandwidth and are available in the **us-east** region. Current plan details are on the [Windows VM page](/products/windows-vm) and [pricing page](/pricing). ## BYOL is not automatic when moving Windows Server to a hosted VPS Do not assume an existing Windows Server license can be moved to any hosted VM. For eligible Microsoft customers, hosted Windows Server BYOL depends on the applicable outsourcing rights and **Flexible Virtualization Benefit** requirements. Windows Server BYOL is not the same as Microsoft's License Mobility through Software Assurance program used for eligible server applications such as SQL Server. If the required BYOL rights do not apply, use the provider's Windows Server licensing model. Raff offers Windows Server Standard licensing through SPLA at **$15 per instance per month**. For a deeper licensing explanation, see [Windows Server Licensing: SPLA, BYOL, CALs & RDS](/windows-server/windows-licensing). ## Which path fits your Server 2016 workload - **Legacy application certified only for Server 2016:** use ESU if eligible, isolate the workload appropriately, and create a dated vendor migration plan. - **Simple standalone server with supported apps:** evaluate the direct Windows Server 2016 to 2025 in-place path. - **Domain controller:** build a newer DC, replicate, transfer roles, validate, and retire the old DC rather than treating the domain controller as a generic in-place upgrade. - **File server:** a side-by-side migration can provide a cleaner rollback path and lets you test permissions before cutover. - **SQL Server 2016 host:** plan the database lifecycle separately because SQL Server 2016 already reached end of extended support in July 2026. - **MSP-managed client fleet:** use ESU for systems with genuine blockers and prioritize internet-facing, identity, and compliance-sensitive workloads for migration. ## A practical migration sequence reduces risk For mixed-role Server 2016 systems, separate the workload into migration units instead of treating the machine as one indivisible box. A typical sequence is: 1. inventory installed roles, applications, certificates, scheduled tasks, shares, ports, service accounts, and dependencies; 2. identify unsupported application and database versions; 3. build the Server 2025 destination; 4. migrate and test data and application components; 5. validate authentication, backups, monitoring, and firewall rules; 6. schedule the cutover; 7. keep a rollback path until the new system is proven; 8. retire or isolate the Server 2016 machine after validation. Our detailed [Windows Server 2016 to 2025 migration guide](/windows-server/migrate-windows-server-2016-to-2025) covers the technical path in more depth. ## Start the project before the January 2027 deadline As of September 2026, the deadline is close enough that inventory and compatibility work should already be underway. A practical sequence for a small environment is: - **September 2026:** inventory Server 2016 systems and classify blockers; - **October to November 2026:** build and test target Server 2025 systems; - **November to December 2026:** migrate production workloads and verify rollback; - **Before January 12, 2027:** complete migrations or enroll genuinely blocked systems in an eligible ESU path. The exact schedule depends on application complexity, change-control requirements, data volume, and vendor support. Avoid treating a generic migration-duration estimate as a guarantee. ## How Raff fits into the migration Raff provides Windows VMs with Windows Server licensing available through Microsoft SPLA, plus BYOL support for customers whose licensing rights permit hosted deployment. For a migration project, the practical use is to create the new Server 2025 destination first, validate the workload, and move production only after the application, authentication, firewall, and backup checks pass. Raff supports **3,000+ customers** and **15,000+ VMs**, with a **99.9% SLA**. If you want a second set of eyes on sizing or the migration path, the Windows engineering contact option is available from this page. ## Common mistakes ### Treating January 12, 2027 as a shutdown date The server keeps running. The problem is loss of normal support and security servicing. ### Assuming ESU is a fixed dollar amount per server ESU cost depends on edition, licensed cores, purchasing route, and applicable discounts. Quote the actual environment. ### Waiting until January to test applications Application compatibility and vendor support are usually harder problems than installing Windows Server itself. ### Forgetting SQL Server lifecycle SQL Server 2016 reached end of extended support in July 2026, before Windows Server 2016. ### Assuming BYOL always transfers to a VPS Hosted Windows Server licensing depends on the rights attached to the license and the hosting model. ### Treating direct in-place upgrade as automatically safe Microsoft supports the 2016-to-2025 installation-media path for eligible nonclustered systems, but application, role, hardware, provider, and rollback requirements still need validation. ## Validation scope This article was revalidated on **September 17, 2026** against Microsoft's Windows Server 2016 Lifecycle page, February 2026 Server 2016 end-of-support announcement, Windows Server ESU through Azure Arc documentation, ESU lifecycle FAQ, ESU billing guidance, and current Windows Server upgrade guidance. Raff pricing and licensing references were also checked against the September 2026 Windows source of truth. ## What's next - [How to migrate Windows Server 2016 to 2025](/windows-server/migrate-windows-server-2016-to-2025) - [Windows Server end-of-life dates](/windows-server/windows-server-end-of-life-dates) - [Windows Server version comparison](/windows-server/windows-server-version-comparison) - [Windows Server licensing guide](/windows-server/windows-licensing) - [Raff Windows VM](/products/windows-vm) ## Sources - Microsoft Lifecycle - Windows Server 2016: https://learn.microsoft.com/en-us/lifecycle/products/windows-server-2016 - Microsoft Windows Server Blog - Planning ahead for Windows Server 2016 end of support: https://www.microsoft.com/en-us/windows-server/blog/2026/02/25/planning-ahead-for-windows-server-2016-end-of-support/ - Microsoft Learn - Windows Server release information: https://learn.microsoft.com/en-us/windows/release-health/windows-server-release-info - Microsoft Learn - Prepare Extended Security Updates for Windows Server through Azure Arc: https://learn.microsoft.com/en-us/azure/azure-arc/servers/prepare-extended-security-updates - Microsoft Learn - Billing service for Extended Security Updates through Azure Arc: https://learn.microsoft.com/en-us/azure/azure-arc/servers/billing-extended-security-updates - Microsoft Lifecycle - Extended Security Updates FAQ: https://learn.microsoft.com/en-us/lifecycle/faq/extended-security-updates - Microsoft Learn - Plan your Windows Server upgrade: https://learn.microsoft.com/en-us/windows-server/get-started/install-upgrade-migrate - Microsoft Lifecycle - SQL Server 2016: https://learn.microsoft.com/en-us/lifecycle/products/sql-server-2016 - Sources revalidated: 2026-09-17 --- ### Install SQL Server 2025 on Windows Server VPS: Requirements & Setup URL: https://rafftechnologies.com/windows-server/install-sql-server-2025-windows-server-vps Description: Install SQL Server 2025 on a Windows Server VPS with verified system requirements, edition guidance, TempDB and memory tuning, firewall hardening, cumulative updates, and post-install checks. ## In short To install SQL Server 2025 on a Windows Server VPS, first confirm the server meets Microsoft's current requirements: a supported x64 Windows version, at least a 1.4 GHz processor, at least 1 GB RAM for non-Express editions, at least 6 GB of available disk space for SQL Server itself, and .NET Framework 4.7.2. For a new deployment, Windows Server 2025 or Windows Server 2022 are both supported choices. Then choose the correct SQL Server edition, use the full **Custom** setup wizard, configure authentication and data paths, tune TempDB and max server memory, patch the instance to your current Microsoft servicing baseline, and open TCP 1433 only to trusted IPs or private networks. Raff Windows VMs can provide the Windows Server layer for this self-managed SQL Server setup. SQL Server production licensing is separate from the Windows Server licence included with a Raff Windows VM. ## SQL Server 2025 requirements Microsoft's current SQL Server 2025 hardware and software requirements are installation minimums, not production sizing targets. | Requirement | Microsoft minimum / support requirement | Practical VPS guidance | |---|---|---| | CPU architecture | x64 only | Modern x86-64 CPU | | CPU speed | 1.4 GHz minimum | 2.0 GHz+; prioritize strong per-core performance | | RAM (Express) | 512 MB minimum | 2-4 GB for a lab or very small workload | | RAM (other editions) | 1 GB minimum | 8 GB+ for most development/staging; 16 GB+ for small production | | Disk space | At least 6 GB available for SQL Server | Leave headroom for databases, TempDB, logs, backups, updates, and growth | | Operating system | Windows 10+ or Windows Server 2019+ | Windows Server 2025 or 2022 for a new server deployment | | .NET Framework | .NET Framework 4.7.2 | Keep Windows fully patched before setup | | Network protocols | Shared Memory, Named Pipes, TCP/IP supported | Enable TCP/IP only when the application needs remote SQL access | SQL Server 2025 is supported on **Windows Server 2025, Windows Server 2022, and Windows Server 2019**. It is not supported on Windows Server 2016. Microsoft also supports SQL Server 2025 on supported Windows 10 and Windows 11 editions, but this guide focuses on Windows Server. Server Core is also supported on supported Windows Server releases. ### Minimum requirements are not production sizing A server meeting Microsoft's minimum requirements can install SQL Server 2025, but that does not mean it is sized for a real database workload. | Workload | Suggested starting point | |---|---| | Learning or test install | 2-4 vCPU / 4-8 GB RAM | | Small app or staging database | 4 vCPU / 8-16 GB RAM | | Small production database | 4-8 vCPU / 16-32 GB RAM | | SQL-heavy production workload | 8+ vCPU / 32+ GB RAM | | ERP, reporting, or multi-user business workload | Size after reviewing database size, concurrency, reporting, and backup windows | For current Raff pricing context, a **4 vCPU / 8 GB / 120 GB** Windows VM is **$55.99/month total**, made up of $40.99 compute plus the $15 Windows Server Standard SPLA licence. An **8 vCPU / 16 GB / 180 GB** Windows VM is **$91.99/month total**. SQL Server Standard or Enterprise licensing, backup storage, application licensing, and other optional services are separate. For broader planning, use [Windows Server Sizing by Workload](/windows-server/windows-server-sizing-by-workload). ## Which SQL Server edition should you install? SQL Server 2025 added separate Standard Developer and Enterprise Developer editions. Developer editions are for development and testing, not production. | Edition | Production use? | Main limits | Best for | |---|---:|---|---| | **Standard Developer** | No | Same feature set as Standard; dev/test licence only | Building and validating apps intended for paid Standard | | **Enterprise Developer** | No | Same feature set as Enterprise; dev/test licence only | Testing Enterprise-only features | | **Express** | Yes | 1 socket / 4 cores, 1,410 MB buffer pool, 50 GB per relational database | Small production databases and lightweight apps | | **Standard** | Yes | 32 cores, 256 GB buffer pool | Many SMB and mid-market production workloads | | **Enterprise** | Yes | Higher scale and Enterprise-only capabilities | Large databases, advanced HA/DR, heavy analytics | | **Evaluation** | No permanent production use | Time-limited 180-day Enterprise evaluation | Temporary lab, proof-of-concept, or migration validation | **This guide uses Standard Developer** because it is suitable for development, staging, and installation validation. The setup flow for paid Standard is similar; the production licensing path is different. Do not run Developer or Evaluation editions as long-term production licensing. ![SQL Server 2025 edition decision flow showing when to choose Standard Developer, Express, Standard, Enterprise, or Evaluation for Windows VPS deployments.](https://raff-images.s3.raffusercloud.com/sql_server_2025_edition_decision_flow_png_e05d76f6bd.png) ## What you will build This guide installs a clean SQL Server 2025 instance on a Windows Server VPS. ```text Windows Server VPS ↓ SQL Server 2025 ├── Database Engine ├── SQL Server Agent where supported/needed ├── TempDB ├── Data files ├── Log files ├── Backups └── Firewall / private access ``` For a small workload, the app and SQL Server can run on one VM. As the workload grows, separating the application and database onto different VMs over a private network can improve isolation and troubleshooting. ![SQL Server 2025 architecture on a Windows Server VPS showing Database Engine, SQL Server Agent, TempDB, data files, log files, backups, firewall rules, and optional private app server access.](https://raff-images.s3.raffusercloud.com/sql_server_2025_windows_vps_architecture_png_229b36c3f3.png) ## What you'll need Before starting, prepare: - a Raff Windows VM or another supported Windows Server environment; - Windows Server 2022 or Windows Server 2025; - local Administrator access; - no pending Windows reboot; - SQL Server 2025 installation media; - SQL Server Management Studio on your workstation or server; - a password manager for the `sa` password if you choose Mixed Mode; - a backup plan before production data is added. ## Quick context: what changed in SQL Server 2025 Practical SQL Server 2025 changes include: - SQL Server 2025 is version **17.x**. - General availability was build **17.0.1000.7** on November 18, 2025. - Standard edition supports up to **32 cores** and a **256 GB buffer pool**. - Express supports up to **50 GB per relational database**. - Web edition is discontinued. - Express with Advanced Services is discontinued because base Express now includes those capabilities. - Standard Developer and Enterprise Developer are separate developer editions. - Resource Governor is available in Standard and Standard Developer. - SQL Server 2025 includes new vector and AI-related database features, but preview features should not be treated as production-ready until Microsoft marks them accordingly. As of **September 17, 2026**, Microsoft lists **CU8, build 17.0.4075.5**, as the latest cumulative update and also lists a September 2026 security-servicing build on the CU8 branch. Before production use, check Microsoft's current SQL Server 2025 build page and patch according to your chosen CU/GDR servicing policy rather than relying only on the RTM build in an old screenshot. ## Step 1 — Prepare the Windows Server VPS Connect to the Windows Server VPS over RDP as Administrator. Before running setup: 1. Install pending Windows updates. 2. Reboot the server. 3. Confirm you can reconnect over RDP. 4. Confirm the system drive has enough free space. 5. Create a clean SQL folder structure. Run PowerShell as Administrator: ```powershell New-Item -ItemType Directory -Path "C:\SQL\Data" -Force New-Item -ItemType Directory -Path "C:\SQL\Logs" -Force New-Item -ItemType Directory -Path "C:\SQL\Backups" -Force New-Item -ItemType Directory -Path "C:\SQL\TempDB" -Force ``` This keeps user databases, transaction logs, backups, and TempDB easier to manage than leaving everything under `C:\Program Files\Microsoft SQL Server\`. If you later use separate disks or volumes, keep the same idea with dedicated paths such as `D:\SQL\Data`, `L:\SQL\Logs`, and `T:\SQL\TempDB`. ## Step 2 — Get SQL Server 2025 media onto the server Windows Server 2025 supports WinGet through the App Installer system component, but availability can depend on the server's update state. If `winget` is present, you can use it to locate packages. For predictable production setup, Microsoft's official SQL Server download and licensing channels remain the source of record for installation media. ### Option 1: Use WinGet when it is available Check first: ```powershell winget --version ``` Then search rather than assuming a package ID: ```powershell winget search "SQL Server 2025" ``` If you use a WinGet package to obtain media, still use the full setup wizard for a production-style install so you can control features, authentication, data paths, TempDB, memory, and service configuration. ### Option 2: Download media from Microsoft Download SQL Server 2025 from Microsoft's SQL Server download or licensing channel appropriate to the edition. For Standard or Enterprise production media, use the entitlement provided through your Microsoft licensing route. For free developer or Express editions, use Microsoft's current SQL Server download resources. Use the full setup wizard instead of a one-click Basic install when you need deliberate control over: - edition; - feature selection; - authentication; - service startup; - data directories; - TempDB; - MaxDOP; - memory; - firewall planning. ### Option 3: Use Evaluation only for a temporary test Microsoft provides a 180-day SQL Server Evaluation edition for temporary Enterprise-feature testing, proof-of-concept work, and migration validation. Do not use Evaluation as a permanent production licensing plan. Do not run SQL Server setup from an ISO mounted through a local RDP redirected drive. Put the media on the server itself or on a network share the server can reliably reach. ## Step 3 — Run the install wizard From PowerShell on the Windows Server VPS, launch setup as Administrator: ```powershell Start-Process -FilePath "C:\SQL2025\StdDev_ENU\setup.exe" -Verb RunAs ``` ![SQL Server 2025 Installation Center showing the Installation tab with New SQL Server standalone installation option highlighted](https://raff-images.s3.raffusercloud.com/large_raff_mssql2025_installation_tab_2026_04_729d6e9fd8.png) Select: ```text Installation → New SQL Server standalone installation or add features to an existing installation ``` ### Edition ![SQL Server 2025 Setup Edition screen with Standard Developer selected from the free edition dropdown](https://raff-images.s3.raffusercloud.com/large_raff_mssql2025_edition_standard_developer_2026_04_ab91f225b9.png) For this guide: ```text Specify a free edition → Standard Developer ``` For production, use the paid Standard or Enterprise licensing path appropriate to your Microsoft entitlement. ### License terms, setup rules, Microsoft Update, and product updates Accept the applicable licence terms. If Microsoft Update is offered, enable it if that matches your patching policy. If setup reports a pending restart, cancel setup, reboot, reconnect, and run setup again. ### Install Rules: the Windows Firewall warning is expected ![SQL Server 2025 Setup Install Rules showing four passed checks and one Windows Firewall warning, expected and safe to proceed](https://raff-images.s3.raffusercloud.com/large_raff_mssql2025_install_rules_firewall_warning_2026_04_47b9e0cc55.png) Do not disable Windows Firewall just to clear the warning. Use this model: ```text Install SQL Server. Decide who needs remote access. Open only the required port. Restrict by source IP or private network. ``` ### Azure Extension for SQL Server: skip unless you need Azure Arc ![SQL Server 2025 Setup Azure Extension screen with the checkbox unticked, skipping Azure Arc registration for a self-hosted Raff Server](https://raff-images.s3.raffusercloud.com/large_raff_mssql2025_azure_extension_unticked_2026_04_d8ee9dca65.png) Leave Azure Extension unchecked unless the deployment specifically requires Azure Arc or Azure-connected SQL features. You can register later if a real requirement appears. ### Feature Selection: install only what the workload needs ![SQL Server 2025 Feature Selection with Database Engine Services, SQL Server Replication, and Full-Text Search ticked — recommended minimum](https://raff-images.s3.raffusercloud.com/large_raff_mssql2025_feature_selection_recommended_2026_04_3ede160712.png) The original Raff lab selected Database Engine Services, Replication, and Full-Text Search. For a fresh production deployment, do **not** treat all three as a universal minimum. Start with: - **Database Engine Services:** required for the database engine. Add only when the application needs them: - **SQL Server Replication:** only for a real replication design. - **Full-Text Search:** when the application uses full-text capabilities. - **PolyBase, Analysis Services, Integration Services, language extensions, or AI-related components:** only when the workload requires them. A smaller installation surface is easier to patch, secure, and troubleshoot. ### Instance Configuration: default instance for a simple single-instance VM ![SQL Server 2025 Setup Instance Configuration with Default instance selected and MSSQLSERVER as the instance ID](https://raff-images.s3.raffusercloud.com/large_raff_mssql2025_instance_configuration_default_2026_04_cb0ed7c26a.png) For a single-purpose SQL VM, a default `MSSQLSERVER` instance is often simpler. Use a named instance when multiple instances, side-by-side versions, or a vendor requirement justify it. ### Server Configuration: Agent and instant file initialization ![SQL Server 2025 Server Configuration with SQL Server Agent startup type set to Automatic and Volume Maintenance Tasks privilege ticked](https://raff-images.s3.raffusercloud.com/large_raff_mssql2025_server_configuration_2026_04_18a913c42e.png) For Standard, Enterprise, or Developer editions where SQL Server Agent is part of the deployment, set Agent to **Automatic** if you will use scheduled jobs, alerts, or backup tasks. Grant **Perform Volume Maintenance Tasks** to the SQL Server Database Engine service when instant file initialization fits your security policy and workload. Leave SQL Server Browser disabled for a default instance unless the architecture requires it. Keep the default collation unless the application vendor requires a specific collation. ### Database Engine Configuration: authentication ![SQL Server 2025 Database Engine Configuration with Mixed Mode authentication selected and Administrator added as SQL Server admin](https://raff-images.s3.raffusercloud.com/large_raff_mssql2025_dbengine_auth_mixed_mode_2026_04_fc140b5592.png) For a standalone, non-domain-joined Windows VPS, Mixed Mode can be practical when applications require SQL logins. If you use Mixed Mode: - set a long, unique `sa` password; - store it in a password manager; - add an attributable Windows administrator as SQL Server admin; - create dedicated application logins later; - do not use `sa` as the normal application login. For domain-joined environments, Windows Authentication may be preferable where the application supports it. ### Data Directories ![SQL Server 2025 Data Directories tab with user databases, logs, and backups separated into clean C:\SQL folder structure](https://raff-images.s3.raffusercloud.com/large_raff_mssql2025_dbengine_data_directories_2026_04_ba8c6fbd7e.png) Use the folder structure created earlier: | Field | Change to | |---|---| | User database directory | `C:\SQL\Data` | | User database log directory | `C:\SQL\Logs` | | Backup directory | `C:\SQL\Backups` | On a single-volume VPS, separate folders do not create separate physical I/O paths. They provide operational clarity. Use genuinely separate volumes only when the workload and recovery design justify them. ### TempDB ![SQL Server 2025 TempDB tab configured with 4 data files at 512 MB each, 64 MB autogrowth, and C:\SQL\TempDB path](https://raff-images.s3.raffusercloud.com/large_raff_mssql2025_dbengine_tempdb_4files_2026_04_a069f32e34.png) The original Raff lab used four equal TempDB data files on a 4 vCPU VM. Treat that as a tested starting configuration, not a universal rule. For small and mid-sized SQL Server VMs, keep TempDB files equal-sized and use fixed MB growth. Start with the setup wizard's recommendation and adjust from measured contention, TempDB growth, and workload behavior. For deeper tuning, use [Configure TempDB for MSSQL Performance](/windows-server/mssql-tempdb-config). ### MaxDOP ![SQL Server 2025 MaxDOP tab showing auto-detected 4 logical CPU cores and MaxDOP set to 4 for the Raff Production plan](https://raff-images.s3.raffusercloud.com/large_raff_mssql2025_dbengine_maxdop_4_2026_04_18cc193292.png) Use the installer recommendation as the starting point, then tune from the workload. Avoid copying a MaxDOP value from another server without considering CPU topology, query concurrency, and application behavior. ### Memory and FILESTREAM Leave FILESTREAM disabled unless the application requires it. After installation, set `max server memory (MB)` so Windows and non-SQL processes retain enough RAM. The dedicated [SQL Server Max Server Memory guide](/windows-server/mssql-memory-tuning) owns the detailed sizing guidance. ### Ready to Install ![SQL Server 2025 Ready to Install summary showing Standard Developer edition with Database Engine, Replication, Full-Text Search and default instance](https://raff-images.s3.raffusercloud.com/large_raff_mssql2025_ready_to_install_summary_2026_04_5d17286cb2.png) Before clicking Install, review edition, selected features, instance name, service startup, data paths, TempDB, MaxDOP, SQL admins, and authentication mode. SQL Setup also writes a configuration file. Do not publish that file if it includes sensitive paths, usernames, or product-key-related information. Click **Install** and review the setup summary before moving on. If any selected feature fails, inspect the SQL Setup logs and resolve the root cause rather than accepting a partial installation. ## Step 4 — Cap SQL Server memory SQL Server uses available memory aggressively by design. A Windows Server VPS also needs RAM for Windows, security software, backups, monitoring, RDP administration, and any co-hosted applications. Example for an 8 GB VM: ```sql EXEC sys.sp_configure 'show advanced options', 1; RECONFIGURE; EXEC sys.sp_configure 'max server memory (MB)', 6144; RECONFIGURE; EXEC sys.sp_configure 'max server memory (MB)'; ``` Treat `6144` as an example for a mostly dedicated SQL Server, not a universal 8 GB value. Shared SQL + IIS/RDP workloads usually need a larger Windows/non-SQL reserve. For current guidance and pressure checks, use [SQL Server Max Server Memory](/windows-server/mssql-memory-tuning). ## Step 5 — Patch SQL Server 2025 to your current servicing baseline Do not leave a production instance on the RTM build simply because the installation succeeded. As of September 17, 2026, Microsoft's SQL Server 2025 build page lists **CU8 (17.0.4075.5)** as the latest cumulative update and a September 2026 security build on the CU8 branch. Microsoft servicing can change after this article is updated, so use the current build-history page before patching. Verify after servicing: ```sql SELECT @@VERSION; ``` and: ```sql SELECT SERVERPROPERTY('ProductVersion') AS ProductVersion, SERVERPROPERTY('ProductLevel') AS ProductLevel, SERVERPROPERTY('ProductUpdateLevel') AS ProductUpdateLevel, SERVERPROPERTY('Edition') AS Edition; ``` Record the build and patch date in the server change log. ## Step 6 — Install SQL Server Management Studio SQL Server Management Studio is maintained separately from the SQL Server engine. A practical approach is: - install SSMS on an administrator workstation when remote management is preferred; - install it on the server only when local GUI administration is useful; - keep SSMS updated independently from SQL Server servicing. Use `localhost` for local management or the approved private/trusted address for remote administration. ## Step 7 — Enable TCP/IP only when remote SQL access is required If applications connect only from the same VM, you may not need remote SQL exposure. If another application server or trusted admin workstation needs SQL access, enable TCP/IP deliberately in SQL Server Configuration Manager and use a documented static port, commonly TCP 1433 for a default instance. Restart the SQL Server service after changing protocol settings. ## Step 8 — Restrict Windows Firewall to trusted SQL clients Do not expose TCP 1433 to the whole internet. Example allowing one trusted documentation IP: ```powershell New-NetFirewallRule ` -DisplayName "SQL Server 2025 TCP 1433 - Trusted Source" ` -Direction Inbound ` -Protocol TCP ` -LocalPort 1433 ` -RemoteAddress "203.0.113.10" ` -Action Allow ``` Replace the documentation address with the real office, VPN, or private-network source. Prefer, in order where practical: - same-server connections; - private networking between app and database VMs; - VPN or controlled management path; - narrow source-IP allowlisting; - no public SQL port when it is not required. ## Step 9 — Create a test database ```sql CREATE DATABASE RaffSqlTest; GO USE RaffSqlTest; GO CREATE TABLE dbo.HealthCheck ( Id int IDENTITY(1,1) PRIMARY KEY, CreatedAt datetime2 NOT NULL DEFAULT sysdatetime(), Message nvarchar(200) NOT NULL ); GO INSERT INTO dbo.HealthCheck (Message) VALUES (N'SQL Server 2025 is working.'); GO SELECT * FROM dbo.HealthCheck; GO ``` Verify file placement: ```sql SELECT name, physical_name FROM sys.master_files WHERE database_id = DB_ID('RaffSqlTest'); ``` ## Step 10 — Create a dedicated application login Do not give an application the `sa` credential. ```sql CREATE LOGIN app_user WITH PASSWORD = 'Use-A-Strong-Unique-Password-Here!'; GO USE RaffSqlTest; GO CREATE USER app_user FOR LOGIN app_user; GO ALTER ROLE db_datareader ADD MEMBER app_user; ALTER ROLE db_datawriter ADD MEMBER app_user; GO ``` For production, grant only the permissions the application actually requires. ## Step 11 — Create and verify the first backup ```sql BACKUP DATABASE RaffSqlTest TO DISK = 'C:\SQL\Backups\RaffSqlTest_full.bak' WITH INIT, COMPRESSION, CHECKSUM, STATS = 10; GO ``` Verify it: ```sql RESTORE VERIFYONLY FROM DISK = 'C:\SQL\Backups\RaffSqlTest_full.bak' WITH CHECKSUM; GO ``` A complete production backup plan also needs retention, off-server copies, alerting, and actual restore testing. See [SQL Server Backup Strategy](/windows-server/mssql-backup-strategy). ## Step 12 — Verify the final install Check services: ```powershell Get-Service -Name MSSQLSERVER, SQLSERVERAGENT | Format-Table Name, Status, StartType ``` Check the SQL build and edition: ```sql SELECT @@VERSION AS Version, SERVERPROPERTY('Edition') AS Edition, SERVERPROPERTY('ProductLevel') AS ProductLevel, SERVERPROPERTY('ProductUpdateLevel') AS ProductUpdateLevel; ``` A final production verification should confirm: - the SQL Server service is running; - Agent is running when the chosen edition and automation design use it; - the edition matches the intended licence; - the SQL build matches the current servicing baseline; - data, log, TempDB, and backup paths match the design; - `max server memory` and MaxDOP are deliberate values; - remote SQL access is restricted to intended sources; - backups and restore testing are configured. ## Common mistakes ### Pending Windows restart blocks setup Reboot before SQL Server setup if Windows reports a pending restart. ### Treating a Basic install as production design Use Custom setup when production requirements include deliberate feature selection, authentication, data paths, TempDB, service configuration, and firewall controls. ### Installing features "just in case" Replication, Full-Text, PolyBase, Analysis Services, Integration Services, and language extensions should be installed because the workload needs them, not because they appear in a generic checklist. ### Leaving TempDB unreviewed Start with sensible equal-sized files and fixed MB growth, then tune from measured TempDB behavior. ### Leaving max server memory effectively unlimited on a shared VM Reserve memory for Windows and every non-SQL workload. ### Using `sa` as the application login Create a dedicated login with only the permissions the application needs. ### Installing SQL Server on a domain controller Use a dedicated Windows Server VM for SQL Server whenever practical. ### Opening TCP 1433 to the internet Use private networking, VPN, or narrow allowlists. Do not expose the database listener broadly. ### Forgetting SQL Server servicing The RTM build is not the current production patch level. Check Microsoft's SQL Server 2025 build history before go-live and during maintenance cycles. ## When to use Standard, Enterprise, Express, or Developer Use **Standard Developer** or **Enterprise Developer** only for development and test scenarios. Use **Express** when the workload fits its CPU, memory, feature, and 50 GB database limits. Use **Standard** for many production business applications, ERP databases, internal tools, IIS/ASP.NET application databases, and moderate reporting workloads. Use **Enterprise** when the workload requires Enterprise-only scale, availability, or feature capabilities. SQL Server Standard and Enterprise production licensing is separate from the Windows Server SPLA licence included with a Raff Windows VM. Confirm SQL Server licence rights through the customer's Microsoft licensing agreement, licensing partner, or other valid entitlement before production deployment. ## Recommended setup by workload | Workload | Recommended edition | Notes | |---|---|---| | Learning SQL Server 2025 | Standard Developer | Free for dev/test | | Staging for a Standard production app | Standard Developer | Matches Standard feature set | | Very small production app | Express | Only if limits are acceptable | | SMB production database | Standard | Common production starting point | | ERP database | Standard | Size RAM and backup strategy carefully | | Heavy reporting | Standard or Enterprise | Depends on workload and features | | HA / advanced enterprise workload | Enterprise | Validate feature and licensing requirements | | Temporary Enterprise feature test | Evaluation | 180-day test only | ## How Raff fits SQL Server hosting Raff provides the Windows Server VM layer for self-managed SQL Server deployments. A common small production pattern is to keep the application and database separate once the workload justifies it: ```text App VM ↓ Private network ↓ SQL Server VM ↓ Backups / monitoring ``` Use [Raff SQL Server Hosting](/products/sql-server-hosting) for the commercial overview, [Raff Windows VM](/products/windows-vm) for the underlying Windows compute options, and [pricing](/pricing) for the current VM ladder. Raff supports **3,000+ customers** and **15,000+ VMs**, with a **99.9% SLA**. SQL Server configuration, database security, application compatibility, SQL Server production licensing, backups, and restore design remain workload-specific responsibilities unless a separate managed service explicitly covers them. ## Tested on Raff > **Tested on Raff:** SQL Server 2025 Standard Developer Edition installed on a Raff Windows Server 2025 VM, 4 vCPU / 8 GB RAM / 120 GB NVMe, Windows Server 2025 Standard build 26100, **us-east region**, on April 24, 2026. Engineer: Serdar Tekin. > > The original test verified media acquisition, Custom setup, Azure Extension disabled, Mixed Mode authentication, four 512 MB TempDB files at `C:\SQL\TempDB`, MaxDOP 4, `C:\SQL\Data` / `C:\SQL\Logs` / `C:\SQL\Backups`, SQL Server Agent set to Automatic, Perform Volume Maintenance Tasks granted, a restricted TCP 1433 firewall rule, local/remote connectivity, and `SELECT @@VERSION`. The screenshots above are from that test. September 2026 source revalidation does not claim a new benchmark. ## What's next - [Connect to a Windows VPS via RDP](/windows-server/connect-to-windows-vps-via-rdp) - [Windows Server Sizing by Workload](/windows-server/windows-server-sizing-by-workload) - [SQL Server Max Server Memory](/windows-server/mssql-memory-tuning) - [SQL Server Backup Strategy](/windows-server/mssql-backup-strategy) - [Windows Server 2022 vs 2025 vs 2019](/windows-server/windows-server-version-comparison) - [Raff SQL Server Hosting](/products/sql-server-hosting) - [Raff Windows VM](/products/windows-vm) ## Sources - Microsoft Learn: [SQL Server 2025 hardware and software requirements](https://learn.microsoft.com/en-us/sql/sql-server/install/hardware-and-software-requirements-for-installing-sql-server-2025?view=sql-server-ver17) - Microsoft Learn: [SQL Server and Windows compatibility matrix](https://learn.microsoft.com/en-us/troubleshoot/sql/database-engine/install/windows/use-sql-server-in-windows) - Microsoft Learn: [SQL Server 2025 release notes](https://learn.microsoft.com/en-us/sql/sql-server/sql-server-2025-release-notes?view=sql-server-ver17) - Microsoft Learn: [Editions and supported features of SQL Server 2025](https://learn.microsoft.com/en-us/sql/sql-server/editions-and-components-of-sql-server-2025?view=sql-server-ver17) - Microsoft Learn: [SQL Server 2025 build versions](https://learn.microsoft.com/en-us/troubleshoot/sql/releases/sqlserver-2025/build-versions) - Microsoft Learn: [Install SQL Server](https://learn.microsoft.com/en-us/sql/database-engine/install-windows/install-sql-server?view=sql-server-ver17) - Microsoft Learn: [Configure Windows Firewall for SQL Server access](https://learn.microsoft.com/en-us/sql/sql-server/install/configure-the-windows-firewall-to-allow-sql-server-access?view=sql-server-ver17) - Microsoft Learn: [tempdb database](https://learn.microsoft.com/en-us/sql/relational-databases/databases/tempdb-database?view=sql-server-ver17) - Microsoft Learn: [Server memory configuration options](https://learn.microsoft.com/en-us/sql/database-engine/configure-windows/server-memory-server-configuration-options?view=sql-server-ver17) - Microsoft Learn: [Configure MaxDOP](https://learn.microsoft.com/en-us/sql/database-engine/configure-windows/configure-the-max-degree-of-parallelism-server-configuration-option?view=sql-server-ver17) - Microsoft Learn: [Install SQL Server Management Studio](https://learn.microsoft.com/en-us/ssms/install/install) - Microsoft Learn: [WinGet](https://learn.microsoft.com/en-us/windows/package-manager/winget/) - Sources revalidated: 2026-09-17 --- *Microsoft, Windows Server, SQL Server, and SQL Server Management Studio are trademarks of Microsoft Corporation. Raff is an independent infrastructure provider and is not affiliated with, sponsored by, or endorsed by Microsoft Corporation.* --- ### .NET 10 Hosting Bundle for IIS: Host ASP.NET Core on Windows Server URL: https://rafftechnologies.com/windows-server/iis-aspnet-core-windows-server-vps Description: Download and install the .NET 10 Hosting Bundle for IIS on Windows Server, verify ASP.NET Core Module V2, publish ASP.NET Core 10, configure IIS, and deploy on a Raff Windows VM. ## In short The **.NET 10 Hosting Bundle** is the Windows installer you need when hosting ASP.NET Core 10 behind IIS. It installs the .NET Runtime, ASP.NET Core Runtime, and **ASP.NET Core Module V2 (ANCM)** so IIS can start and route requests to your application. If you already have a Windows Server and only need the bundle, use Microsoft's official [.NET 10 download page](https://dotnet.microsoft.com/download/dotnet/10.0) or install it with WinGet: ```powershell winget install --id Microsoft.DotNet.HostingBundle.10 --silent --accept-source-agreements --accept-package-agreements ``` For a full deployment, install IIS first, install the Hosting Bundle, publish your application, create a dedicated IIS site and app pool, and expose the site through IIS on ports 80 and 443. Microsoft recommends **No Managed Code** for ASP.NET Core app pools, although the setting is recommended rather than required for the application to start. Raff Windows VMs provide the Windows Server layer for this IIS architecture. If you are still choosing infrastructure, compare [ASP.NET hosting on Raff](/products/aspnet-hosting) and the underlying [Windows VM plans](/products/windows-vm) before deploying. ```text Browser → Windows Server → IIS → ASP.NET Core Module V2 → ASP.NET Core 10 app ``` ![ASP.NET Core 10 app hosted on IIS using ASP.NET Core Module V2 on a Raff Windows VM](https://raff-images.s3.raffusercloud.com/aspnet_core_10_iis_windows_server_architecture_raff_892e99447f.png) ## .NET 10 Hosting Bundle download for Windows Server Download the .NET 10 Hosting Bundle from Microsoft's official [.NET 10 download page](https://dotnet.microsoft.com/download/dotnet/10.0): open the **ASP.NET Core Runtime** section and choose **Hosting Bundle** for Windows. Use the bundle, not only the standalone runtime, because the Hosting Bundle installs the .NET runtime components plus ASP.NET Core Module V2 for IIS. The original Raff test used Hosting Bundle **10.0.7** on a 4 vCPU / 8 GB Windows Server 2025 VM on April 30, 2026. That test record is preserved. For a new deployment today, install the current supported .NET 10 patch rather than reproducing the old lab patch exactly. As of **September 17, 2026**, Microsoft's current .NET 10 release is **10.0.12**, released September 8, 2026. Microsoft marks it as a security patch and recommends upgrading older .NET 10 patch levels. .NET 10 remains an active LTS release through **November 14, 2028**. ```powershell winget install --id Microsoft.DotNet.HostingBundle.10 --silent --accept-source-agreements --accept-package-agreements ``` After installation, verify that both the runtime and IIS integration are present: ```powershell dotnet --list-runtimes Import-Module WebAdministration Get-WebGlobalModule -Name "AspNetCoreModuleV2" | Format-Table Name, Image ``` You should see .NET 10 runtime entries and an `AspNetCoreModuleV2` result. ### What is included in the .NET 10 Hosting Bundle? The Hosting Bundle is designed for running ASP.NET Core applications with IIS. It includes: - the .NET Runtime; - the ASP.NET Core Runtime; - ASP.NET Core Module V2 for IIS integration. The **SDK is separate**. You only need the SDK on the server if you plan to create, build, or publish applications there. | Component | What it is for | Needed on an IIS production server? | | --- | --- | --- | | .NET Runtime | Runs framework-dependent .NET applications | Yes | | ASP.NET Core Runtime | Runs ASP.NET Core applications | Yes | | ASP.NET Core Module V2 | Connects IIS to the ASP.NET Core app | Yes | | .NET SDK | Build, create, and publish commands | Only if you build on the server | ## Who this guide is for This guide is for developers and operators deploying an ASP.NET Core application to Windows Server with IIS. Typical use cases include internal applications, customer portals, APIs, line-of-business systems, and multiple ASP.NET Core sites hosted on one Windows VM. For larger multi-server deployments, containers or a load-balanced architecture may fit better. The focus here is the common single-server or small-cluster IIS deployment pattern. ## What you'll need - Windows Server 2025 or Windows Server 2022; - local administrator access through Remote Desktop Protocol (RDP); - an ASP.NET Core application to deploy; - the .NET 10 Hosting Bundle; - optional: a separate build machine or CI runner; - about 30-45 minutes for a first deployment. If you need help connecting first, see the [RDP connection guide](/windows-server/connect-to-windows-vps-via-rdp). ## .NET 10 is an active LTS release Microsoft's current .NET support policy lists **.NET 10 as an active Long Term Support release through November 14, 2028**. As of September 17, 2026, the latest supported patch is **10.0.12**. Microsoft releases servicing patches during the support lifecycle and requires supported systems to remain current on released updates. Three distinctions matter for IIS: 1. **The Hosting Bundle and SDK are separate.** The Hosting Bundle lets IIS run ASP.NET Core applications. The SDK is needed for `dotnet new`, `dotnet build`, and `dotnet publish`. 2. **ASP.NET Core Module V2 is part of the Hosting Bundle.** IIS uses it to start and route requests to the application. 3. **No Managed Code is recommended, not mandatory.** ASP.NET Core boots CoreCLR itself rather than relying on the classic desktop CLR configured for the IIS app pool. ## Step 1 — Install the Web Server (IIS) role Open PowerShell **as administrator** and run: ```powershell Install-WindowsFeature -Name ` Web-Server, ` Web-Common-Http, ` Web-Static-Content, ` Web-Default-Doc, ` Web-Dir-Browsing, ` Web-Http-Errors, ` Web-App-Dev, ` Web-Net-Ext45, ` Web-AppInit, ` Web-ISAPI-Ext, ` Web-ISAPI-Filter, ` Web-Health, ` Web-Http-Logging, ` Web-Performance, ` Web-Stat-Compression, ` Web-Security, ` Web-Filtering, ` Web-Mgmt-Tools, ` Web-Mgmt-Console ` -IncludeManagementTools ``` Verify IIS and its services: ```powershell Get-WindowsFeature -Name Web-Server | Format-Table Name, InstallState Get-Service -Name W3SVC, WAS | Format-Table Name, Status, StartType ``` Then browse to `http://localhost` from a browser on the server. ![IIS welcome page on Windows Server 2025 — first run after Install-WindowsFeature](https://raff-images.s3.raffusercloud.com/large_raff_iis_welcome_page_localhost_2026_04_6a622a5dad.png) If the IIS welcome page loads, the web server is accepting local requests. **From the Raff test:** IIS installed successfully on Windows Server 2025 without requiring a reboot. That is the observed result from the tested VM, not a guarantee for every Windows Server state. ## Step 2 — Download and install the .NET 10 Hosting Bundle for IIS The Hosting Bundle installs the .NET Runtime, ASP.NET Core Runtime, and ASP.NET Core Module V2. The command used in the original Raff test was: ```powershell winget install --id Microsoft.DotNet.HostingBundle.10 --silent --accept-source-agreements --accept-package-agreements ``` If WinGet is unavailable, download the Windows Hosting Bundle from Microsoft's official [.NET 10 download page](https://dotnet.microsoft.com/download/dotnet/10.0). ### Install IIS before the Hosting Bundle Install IIS first, then install the Hosting Bundle. If the Hosting Bundle was installed before IIS, repair or run the Hosting Bundle again after IIS is present so ASP.NET Core Module V2 is registered correctly. ### Refresh PATH and verify the runtime ```powershell $env:Path = [System.Environment]::GetEnvironmentVariable("Path", "Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path", "User") dotnet --list-runtimes ``` You should see .NET 10 runtime entries similar to: ```text Microsoft.AspNetCore.App 10.0.x [C:\Program Files\dotnet\shared\Microsoft.AspNetCore.App] Microsoft.NETCore.App 10.0.x [C:\Program Files\dotnet\shared\Microsoft.NETCore.App] ``` Verify ASP.NET Core Module V2: ```powershell Import-Module WebAdministration Get-WebGlobalModule -Name "AspNetCoreModuleV2" | Format-Table Name, Image ``` If this returns nothing, repair or reinstall the Hosting Bundle as administrator after IIS is installed. ## Step 3 — Restart IIS hosting services after the bundle install The April 30 Raff test used `iisreset`, and it completed successfully: ```powershell iisreset ``` Microsoft's IIS deployment guidance also supports restarting the server or restarting Windows Process Activation Service and World Wide Web Publishing Service after installing or upgrading the Hosting Bundle: ```powershell net stop was /y net start w3svc ``` Both approaches interrupt IIS-hosted applications. On a production server with existing sites, schedule the restart during a maintenance window. Verify the services after the restart: ```powershell Get-Service -Name W3SVC, WAS | Format-Table Name, Status ``` ## Step 4 — Publish the ASP.NET Core application ### Path A — Build on the server for development or staging The Hosting Bundle does not include the SDK. If the server will create or publish the application, install the .NET 10 SDK: ```powershell winget install --id Microsoft.DotNet.SDK.10 --silent --accept-source-agreements --accept-package-agreements $env:Path = [System.Environment]::GetEnvironmentVariable("Path", "Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path", "User") dotnet --list-sdks ``` Create and publish the sample app: ```powershell New-Item -ItemType Directory -Path "C:\src\RaffSampleApp" -Force Set-Location "C:\src\RaffSampleApp" dotnet new webapp --framework net10.0 --name RaffSampleApp --output . dotnet publish -c Release -o C:\publish\RaffSampleApp --runtime win-x64 --self-contained false ``` **From the Raff test:** the SDK-versus-runtime distinction was the main first-deployment gotcha. The Hosting Bundle can run an ASP.NET Core application but does not provide the SDK commands used to create and publish one. ### Path B — Build elsewhere and copy the publish output For production, build on a workstation or CI/CD runner and deploy the publish output to the Windows Server: ```powershell dotnet publish -c Release -o C:\publish\YourApp --runtime win-x64 --self-contained false ``` Move the **publish output**, not the source tree, to the server using the deployment mechanism appropriate to your environment. ### Framework-dependent publishing is the default here The command above uses: ```powershell --self-contained false ``` That means the app uses the .NET 10 runtime installed by the Hosting Bundle. A self-contained publish embeds the runtime instead: ```powershell dotnet publish -c Release -o C:\publish\YourApp --runtime win-x64 --self-contained true ``` Use self-contained deployment only when you deliberately want the application to carry its own runtime. ### Keep the generated web.config A normal IIS publish creates a `web.config` that connects IIS to ASP.NET Core Module V2. A typical in-process configuration looks like: ```xml ``` Do not delete or casually rewrite this file. IIS uses it to launch and route requests to the application. ## Public traffic should reach IIS, not a separate Kestrel port Running **IIS with ASP.NET Core** means IIS owns ports 80 and 443 and forwards requests to the app through ASP.NET Core Module V2; the application itself does not need a separate public Kestrel port. ```text Public browser request ↓ IIS binding on 80/443 ↓ ASP.NET Core Module V2 ↓ ASP.NET Core app ``` Do not expose a random Kestrel application port to the internet simply because the application can listen directly. ## Step 5 — Create the IIS site and app pool ```powershell Import-Module WebAdministration Stop-Website -Name "Default Web Site" -ErrorAction SilentlyContinue Remove-Website -Name "Default Web Site" -ErrorAction SilentlyContinue New-WebAppPool -Name "RaffSampleAppPool" # Microsoft recommends No Managed Code for ASP.NET Core app pools. Set-ItemProperty -Path "IIS:\AppPools\RaffSampleAppPool" -Name "managedRuntimeVersion" -Value "" New-Website -Name "RaffSampleApp" ` -PhysicalPath "C:\publish\RaffSampleApp" ` -ApplicationPool "RaffSampleAppPool" ` -Port 80 icacls "C:\publish\RaffSampleApp" /grant "IIS AppPool\RaffSampleAppPool:(OI)(CI)RX" ``` ### No Managed Code is recommended, not a 500.30 diagnosis Setting `managedRuntimeVersion = ""` selects **No Managed Code** in IIS Manager. Microsoft documents this as optional but recommended for ASP.NET Core because the app boots CoreCLR itself. A non-empty `managedRuntimeVersion` is worth correcting, but it is not by itself proof of the cause of HTTP 500.30. ### Grant only the permissions the app needs The command above grants read and execute access to the publish folder. If the application must write logs or uploads, grant Modify only on the specific writable directory: ```powershell New-Item -ItemType Directory -Path "C:\publish\RaffSampleApp\logs" -Force icacls "C:\publish\RaffSampleApp\logs" /grant "IIS AppPool\RaffSampleAppPool:(OI)(CI)M" ``` ### Verify the site ```powershell Get-Website -Name "RaffSampleApp" | Format-Table Name, State, PhysicalPath, Bindings Get-IISAppPool -Name "RaffSampleAppPool" | Format-Table Name, State, ManagedRuntimeVersion Invoke-WebRequest -Uri http://localhost -UseBasicParsing | Select-Object StatusCode, StatusDescription ``` Expected results: - the site is `Started`; - the app pool is `Started`; - `ManagedRuntimeVersion` is blank; - `http://localhost` returns HTTP 200. ![ASP.NET Core 10 Razor Pages welcome page on IIS — RaffSampleApp running on Windows Server 2025](https://raff-images.s3.raffusercloud.com/large_raff_iis_aspnet_core_10_welcome_localhost_2026_04_7ae8830635.png) ## Step 6 — Open Windows Firewall for web traffic ```powershell New-NetFirewallRule ` -DisplayName "HTTP (TCP 80)" ` -Direction Inbound ` -Protocol TCP ` -LocalPort 80 ` -Action Allow ` -Profile Any New-NetFirewallRule ` -DisplayName "HTTPS (TCP 443)" ` -Direction Inbound ` -Protocol TCP ` -LocalPort 443 ` -Action Allow ` -Profile Any ``` For production, configure a hostname, valid TLS certificate, and HTTPS before treating the site as ready for users. If several IIS sites share ports 80 and 443, use explicit hostnames rather than broad wildcard bindings. For a tested certificate workflow, see [Free SSL on IIS with win-acme](/windows-server/iis-letsencrypt-win-acme). ## Common IIS and ASP.NET Core errors ### HTTP Error 500.30 — ASP.NET Core app failed to start Treat 500.30 as an application-startup failure. Check these first: 1. Required .NET runtime is missing or out of date. 2. Hosting Bundle or ANCM registration is incomplete. 3. The application throws during startup. 4. The app-pool identity lacks required file permissions. 5. Deployment architecture does not match the server or native dependencies. Check the runtime: ```powershell dotnet --list-runtimes ``` Check ANCM: ```powershell Get-WebGlobalModule -Name "AspNetCoreModuleV2" | Format-Table Name, Image ``` For the actual startup exception, temporarily enable stdout logging in `web.config`: ```xml ``` Create the log folder and grant the app pool write permission, then restart only the affected app pool. Disable stdout logging after diagnosis. ### HTTP Error 500.19 — web.config or IIS configuration error Typical causes include missing ANCM V2, invalid `web.config`, incomplete publish output, or a missing target runtime. ### HTTP Error 502.5 — process failure This is more common with older out-of-process deployments. Check runtime availability, logs, Event Viewer, permissions, and deployment architecture. ### The site works on localhost but not externally Check the firewall and IIS bindings: ```powershell Get-NetFirewallRule -DisplayName "HTTP (TCP 80)", "HTTPS (TCP 443)" | Format-Table DisplayName, Enabled, Direction, Action Get-WebBinding -Name "RaffSampleApp" ``` Then verify the public IP, DNS record, and hostname binding. ### Port 80 is already in use Use hostnames when several sites share port 80: ```powershell New-Website -Name "App1" -PhysicalPath "C:\publish\App1" -ApplicationPool "App1Pool" -Port 80 -HostHeader "app1.example.com" New-Website -Name "App2" -PhysicalPath "C:\publish\App2" -ApplicationPool "App2Pool" -Port 80 -HostHeader "app2.example.com" ``` Create DNS records and HTTPS bindings before production use. ### No .NET SDKs were found The Hosting Bundle is enough to **run** a framework-dependent ASP.NET Core application. It does not include the SDK required to **create, build, or publish** one. ## Multiple ASP.NET Core sites can share one Windows Server Use a separate app pool and deployment folder for each site, isolate file permissions, use No Managed Code unless a documented exception applies, and prefer hostname bindings over arbitrary public ports. If you configure app-pool recycling by memory, remember that the IIS private-memory value is in KB. For example, `2097152` equals 2 GB: ```powershell Set-ItemProperty -Path "IIS:\AppPools\RaffSampleAppPool" ` -Name "recycling.periodicRestart.privateMemory" ` -Value 2097152 ``` A recycle threshold is not a substitute for diagnosing a memory leak. For detailed production settings, see [IIS application pool tuning](/windows-server/iis-app-pool-tuning). ## Persist ASP.NET Core Data Protection keys for production Authentication cookies, antiforgery tokens, password-reset tokens, and other protected payloads can depend on ASP.NET Core Data Protection keys. Production planning should include a deliberate key-persistence strategy. In multi-server deployments, application instances that must decrypt the same protected data need access to a compatible shared key ring. ## When IIS on Windows is the right hosting choice ASP.NET Core also runs on Linux, containers, and managed application platforms. IIS on Windows Server is practical when the application or operations model benefits from: - Windows Authentication; - IIS administration and app-pool isolation; - RDP-based operations; - Windows-only software or libraries; - direct control over bindings, certificates, logs, and server policy. For a self-managed production deployment, the commercial decision is usually not the Hosting Bundle itself because the bundle is free. The buying decision is the Windows infrastructure underneath it. A practical Raff starting point is: | Workload | Raff Windows VM starting point | Current Windows total* | |---|---:|---:| | Small internal ASP.NET Core app | 2 vCPU / 4 GB / 80 GB | **$37.99/mo** | | Production app with more headroom | 4 vCPU / 8 GB / 120 GB | **$55.99/mo** | | Several sites or heavier background work | 8 vCPU / 16 GB / 180 GB | **$91.99/mo** | \*Includes the current compute price plus the $15/month Windows Server Standard SPLA licence. Application databases, extra storage, backups, and other licences are separate. Use [ASP.NET Hosting](/products/aspnet-hosting) for the workload-specific overview, [Windows VM](/products/windows-vm) for the underlying infrastructure, and [pricing](/pricing) for the current plan ladder. Raff supports **3,000+ customers** and **15,000+ VMs**, with a **99.9% SLA**. ## Verify the deployment after every release A simple smoke test should check IIS services, the site, app pool, and an HTTP endpoint: ```powershell param([string]$SiteName = "RaffSampleApp", [string]$Url = "http://localhost") Get-Service -Name W3SVC, WAS | Format-Table Name, Status Get-Website -Name $SiteName | Format-Table Name, State, PhysicalPath, Bindings Get-IISAppPool -Name (Get-Website -Name $SiteName).applicationPool | Format-Table Name, State, ManagedRuntimeVersion Invoke-WebRequest -Uri $Url -UseBasicParsing -TimeoutSec 10 | Select-Object StatusCode, StatusDescription ``` Use this after each deployment and investigate anything other than running services, a started site/app pool, and the expected HTTP response. ## Basic production checklist Before treating the deployment as production-ready, verify that: - IIS is installed and running. - A supported and current .NET 10 Hosting Bundle is installed. - `AspNetCoreModuleV2` is registered with IIS. - The application has a dedicated IIS site and app pool. - The app pool uses No Managed Code unless a documented exception applies. - The app-pool identity has only the required file permissions. - Public traffic reaches IIS on 80/443 rather than a directly exposed application port. - DNS, hostname bindings, and HTTPS are configured correctly. - The application is not running in the `Development` environment. - Secrets are not committed to source code or configuration. - Data Protection keys are persisted appropriately. - Backups or snapshots are configured and restorable. - Windows Server and .NET patching are part of the maintenance plan. - Uptime, disk usage, and application health are monitored. ## Tested on Raff > **Tested on Raff:** ASP.NET Core 10 Razor Pages app on IIS 10, Microsoft .NET 10 Hosting Bundle 10.0.7, Microsoft .NET SDK 10.0.203, Raff Windows Server 2025 VM, 4 vCPU / 8 GB RAM / 120 GB NVMe, Windows Server 2025 Standard build 26100, **us-east region**, April 30, 2026. Engineer: Serdar Tekin. > > The original test verified IIS installation, Hosting Bundle installation through WinGet, ASP.NET Core Module V2 registration, SDK installation, `dotnet new webapp --framework net10.0`, framework-dependent publish, generated `web.config`, dedicated site and app pool, No Managed Code, app-pool file permissions, and HTTP 200 through both `Invoke-WebRequest` and a browser. The screenshots above come from that test. The current supported .NET 10 patch is newer than the test environment, so production servers should be patched to Microsoft's current supported servicing level rather than pinned to 10.0.7. ## What's next - [Free SSL on IIS with win-acme](/windows-server/iis-letsencrypt-win-acme) - [IIS application pool tuning](/windows-server/iis-app-pool-tuning) - [Windows Server Sizing by Workload](/windows-server/windows-server-sizing-by-workload) - [Install SQL Server 2025 on a Windows Server VPS](/windows-server/install-sql-server-2025-windows-server-vps) - [ASP.NET Hosting on Raff](/products/aspnet-hosting) - [Raff Windows VM](/products/windows-vm) ## Sources - Microsoft Learn: [Host ASP.NET Core on Windows with IIS](https://learn.microsoft.com/en-us/aspnet/core/host-and-deploy/iis/?view=aspnetcore-10.0) - Microsoft Learn: [The .NET Hosting Bundle](https://learn.microsoft.com/en-us/aspnet/core/host-and-deploy/iis/hosting-bundle?view=aspnetcore-10.0) - Microsoft Learn: [Publish an ASP.NET Core app to IIS](https://learn.microsoft.com/en-us/aspnet/core/tutorials/publish-to-iis?view=aspnetcore-10.0) - Microsoft Learn: [ASP.NET Core Module for IIS](https://learn.microsoft.com/en-us/aspnet/core/host-and-deploy/aspnet-core-module?view=aspnetcore-10.0) - Microsoft Learn: [Application Pool Identities](https://learn.microsoft.com/en-us/iis/manage/configuring-security/application-pool-identities) - Microsoft Learn: [Configure ASP.NET Core Data Protection](https://learn.microsoft.com/en-us/aspnet/core/security/data-protection/configuration/overview?view=aspnetcore-10.0) - .NET: [.NET support policy](https://dotnet.microsoft.com/en-us/platform/support/policy) - .NET: [.NET 10 downloads](https://dotnet.microsoft.com/download/dotnet/10.0) - Sources revalidated: 2026-09-17 --- *Microsoft, Windows Server, IIS, .NET, and ASP.NET Core are trademarks of Microsoft Corporation. Raff is an independent infrastructure provider and is not affiliated with, sponsored by, or endorsed by Microsoft Corporation.* --- ### Deploy Windows Server 2025 on Raff: Image Choice, VM Creation, and First Boot URL: https://rafftechnologies.com/windows-server/deploy-windows-server-2025-raff Description: Deploy a Windows Server 2025 VPS on Raff, choose the right image and production licensing path, create the VM, confirm it reaches Running, and verify the first boot before continuing to server setup. ## In short To deploy a **Windows Server 2025 VPS on Raff**, open the Windows VM creation flow, choose the `us-east` region, select a VM size that fits the workload, choose Windows Server 2025, set a strong Administrator password, and create the VM. For production, use Raff-provided Windows Server licensing under SPLA or eligible customer BYOL rights. When the VM reaches **Running**, connect over RDP and verify the operating system before installing the workload. ## This guide covers provisioning, not post-deployment configuration Raff already has separate Windows Hub pages for choosing a Windows Server version, connecting over Remote Desktop Protocol (RDP), licensing, and configuring a new server after first login. This page owns one specific job: ```text Choose Windows Server 2025 → choose VM size → confirm production licensing path → create Windows VM → wait for Running → get public IP → make first RDP connection → verify Windows Server 2025 booted correctly ``` It does **not** duplicate: - [Windows Server 2019 vs 2022 vs 2025](/windows-server/windows-server-version-comparison) for operating-system selection; - [How to Connect to a Windows VPS via RDP](/windows-server/connect-to-windows-vps-via-rdp) for client-by-client RDP instructions and troubleshooting; - [Windows Server Initial Setup Checklist](/windows-server/windows-server-initial-setup-checklist) for the first 30 minutes after deployment; - [Windows Server Licensing on Raff](/windows-server/windows-licensing) for SPLA and BYOL licensing guidance. If you have already created the VM and can see the Windows desktop, skip directly to the initial setup checklist. ## Windows Server 2025 is a strong default for new validated workloads Windows Server 2025 is a Long-Term Servicing Channel release. Microsoft lists mainstream support through **November 13, 2029** and extended support through **November 14, 2034**. That support runway makes Server 2025 a practical default for a new environment **when the software you plan to run supports it**. Before deploying, check the application vendor if the server will run: - accounting or tax software; - ERP software; - legacy Microsoft Access applications; - older ODBC drivers; - specialized printer or scanner drivers; - older SQL Server versions; - endpoint security or remote monitoring agents; - software with strict Windows Server certification requirements. If the vendor only supports Server 2022, use Server 2022 rather than creating a Server 2025 VM and discovering the compatibility issue after migration. For the detailed decision, use [Windows Server 2019 vs 2022 vs 2025](/windows-server/windows-server-version-comparison). ## Step 1 — Open the Raff Windows VM creation flow Sign in to the Raff dashboard and open the Windows VM creation page. ![Raff Windows VM creation screen with Windows Server 2025 image and licensing options selected](https://raff-images.s3.raffusercloud.com/raff_windows_server_2025_vm_creation_d355706676.png) Direct dashboard path: ```text /home/create-product/vms/windows ``` You can also start from the [Raff Windows VM product page](/products/windows-vm) and continue to deployment. The creation screen is where you define the VM before Raff provisions the operating system. You will need to make five decisions: 1. region; 2. VM size; 3. Windows Server image; 4. production licensing path; 5. Administrator password. **Verification:** Do not continue until the creation page is specifically configured for a Windows VM rather than a Linux VM. ## Step 2 — Choose `us-east` and size the VM for the workload Choose the Raff `us-east` region for the deployment. Then select a VM size based on what the server will actually run. Windows Server itself is only the baseline. IIS, SQL Server, Remote Desktop Services (RDS), business applications, antivirus, background services, and concurrent users all consume additional CPU and memory. A useful decision pattern is: | Workload | Sizing approach | |---|---| | Light administration | Start with a smaller Windows VM and scale if needed | | IIS or a light internal application | Size for application CPU, memory, and expected traffic | | SQL Server | Prioritize memory, storage behavior, database size, and query load | | RDP/RDS users | Size for concurrent sessions and applications, not total employee count | | ERP or accounting software | Follow the software vendor's supported requirements first | | Mixed app + database workload | Leave headroom or consider separating roles as usage grows | Do not choose a larger VM simply because it runs Windows Server 2025. Choose it because the **workload** needs the capacity. For reference, current Windows totals start at **$28.99/month** for 1 vCPU / 2 GB / 50 GB when the $15/month Windows Server Standard SPLA licence is included. Review current options on [Raff Windows VM](/products/windows-vm) and [Raff pricing](/pricing) before creating a production server. **Verification:** Confirm the selected VM size has enough CPU, memory, and storage for the first workload you plan to install. ## Step 3 — Select Windows Server 2025 and confirm the production licensing path Choose **Windows Server 2025** from the Windows image selector. For a production Raff Windows VM, use one of these supported licensing paths: - **Raff-provided Windows Server licensing under SPLA** when Raff supplies the hosted Windows Server licence; - **eligible customer BYOL** when the customer has qualifying Microsoft rights and the deployment fits Microsoft's applicable outsourcing or Flexible Virtualization rules. Raff currently charges **$15/month per Windows Server Standard instance** when Raff supplies the operating-system licence through its hosted SPLA model. Do not treat a temporary evaluation installation as the production licensing plan. If you are validating software compatibility or migration behavior, keep that activity separate from the production deployment decision. For BYOL eligibility, CALs, RDS licensing, and the distinction between Windows Server outsourcing rights and License Mobility, use [Windows Server Licensing on Raff](/windows-server/windows-licensing). **Verification:** Before creating the VM, confirm that the selected image says **Windows Server 2025** and that the production licensing path is understood. ## Step 4 — Set the Administrator password and save it immediately During VM creation, set a strong password for the Windows `Administrator` account. Use a password manager and generate a long, unique password. Do not reuse a password from another server, Microsoft account, email account, or customer environment. The current Raff Windows workflow expects you to set this password during creation. Save it **before you leave the creation flow**. Your first-login credentials will normally be: ```text Username: Administrator Password: the password you set during VM creation ``` If you later lose the password, the VM details page provides a password-reset action. The detailed recovery workflow is covered in [How to Connect to a Windows VPS via RDP](/windows-server/connect-to-windows-vps-via-rdp). Do not put the password in: - a server name; - a ticket subject; - a shared spreadsheet; - an ordinary chat message; - a screenshot for documentation. **Verification:** Confirm the password is saved in an approved password manager before clicking the final create/deploy action. ## Step 5 — Create the VM and wait for `Running` Submit the VM creation request. The VM will need time to provision the virtual hardware, Windows image, networking, and initial operating-system state. Do not start troubleshooting RDP while the VM is still being created. ![Raff Windows Server 2025 VM details showing Running status and public IPv4 address](https://raff-images.s3.raffusercloud.com/raff_windows_server_2025_vm_running_ip_903e33b876.png) After creation: 1. open **Compute → All Virtual Machines**; 2. select the new Windows VM; 3. wait until its status is **Running**; 4. open the VM details page; 5. copy its **Public IPv4** address. Keep the VM name and public IP together in your server inventory so you know which environment you are connecting to later. **Verification:** The VM should show **Running** and have a public IPv4 address before you attempt the first RDP connection. ## Step 6 — Make the first RDP connection Once the VM is Running, connect to the Windows desktop with RDP. Use: ```text Computer / PC name: Username: Administrator Password: ``` On Windows, you can use the built-in Remote Desktop Connection client. On macOS and mobile platforms, Microsoft provides Windows App. Linux users can use an RDP client such as Remmina or FreeRDP. This article intentionally does not repeat the complete client setup or troubleshooting flow. Follow [How to Connect to a Windows VPS via RDP](/windows-server/connect-to-windows-vps-via-rdp) if you need platform-specific instructions, certificate-warning guidance, password reset, or fixes for port 3389 and credential errors. A first-time certificate warning is expected when connecting directly to a new server by IP with the default RDP certificate. Confirm that you are using the correct VM IP before accepting it. **Verification:** You should reach the Windows Server desktop and be able to open an elevated PowerShell window. ## Step 7 — Verify that Windows Server 2025 booted correctly Before installing IIS, SQL Server, RDS roles, business software, agents, or other workloads, verify the operating system. ![PowerShell on a Raff Windows Server 2025 VM showing the operating system version and build after first boot](https://raff-images.s3.raffusercloud.com/raff_windows_server_2025_first_boot_powershell_2e37eb063d.png) Open **PowerShell as Administrator** and run: ```powershell Get-ComputerInfo | Select-Object CsName, WindowsProductName, WindowsVersion, OsBuildNumber, OsArchitecture ``` Confirm that the output identifies Windows Server 2025. Then check the network state: ```powershell Get-NetIPConfiguration ``` Record: - computer name; - Windows product name; - OS build number; - public IP from the Raff dashboard; - current network adapter configuration. You can also confirm that the Remote Desktop Services service is running: ```powershell Get-Service TermService ``` Expected status: ```text Running ``` Do **not** manually replace the guest network configuration with a static IP, gateway, or DNS server just because this is a cloud VM. An incorrect guest-level network change can break RDP access. Follow the provider networking model and only change guest networking when the workload requires it and you have a recovery path. **Verification:** The Windows product and build are correct, PowerShell opens normally, and networking is present. At that point, provisioning is complete. ## Provisioning ends here; initial server setup starts next A VM reaching the Windows desktop does not mean it is production-ready. The next phase should cover: - Windows Update; - hostname and time zone; - a named administrator account; - Windows Firewall; - Microsoft Defender; - storage and free-space checks; - snapshot or backup planning; - a baseline record before workload installation. Those actions belong in the [Windows Server Initial Setup Checklist](/windows-server/windows-server-initial-setup-checklist). Keeping the handoff explicit prevents two common problems: installing production software before the base OS is ready, and mixing infrastructure provisioning with application troubleshooting. ## Common Windows Server 2025 deployment mistakes ### Choosing Server 2025 before checking software support Server 2025 has a long Microsoft support runway, but an application vendor may still certify only Server 2022. Check the complete software stack before production deployment. ### Treating evaluation as the production licensing plan Testing and production are different decisions. For production on Raff, use the hosted SPLA path or eligible customer BYOL rights and document which licensing model applies before users depend on the server. ### Losing the Administrator password The first password is operationally important. Save it during creation rather than assuming the dashboard will show it later. ### Connecting before the VM reaches Running An RDP timeout during provisioning does not necessarily mean Windows or the firewall is broken. Wait until the dashboard reports the VM as Running and shows its public IP. ### Installing the workload immediately after first login Patch and baseline the server first. A clean initial state makes later troubleshooting much easier. ### Changing the Windows network adapter without a reason A bad static IP, gateway, or DNS change can remove remote access. Confirm the provider networking model before altering the guest configuration. ### Treating administrative RDP as a multi-user desktop service Windows Server administrative access and a real RDS Session Host deployment are different. If several employees will use the server every day, review [Multi-User RDP: 2 Admin Sessions vs RDS Session Host](/windows-server/multi-user-rdp-vs-rds) and the [RDS CAL licensing guide](/windows-server/rds-cal-licensing-guide). ## Deployment checklist | Check | Ready when | |---|---| | Workload supports Server 2025 | Vendor/support requirements are confirmed | | Region | `us-east` selected | | VM size | CPU, RAM, and storage fit the intended workload | | Image | Windows Server 2025 selected | | Production licensing | Raff SPLA or eligible customer BYOL path is understood | | Administrator password | Strong, unique, and saved securely | | VM state | Dashboard shows Running | | Network | Public IPv4 is visible in VM details | | First RDP | Administrator can reach the desktop | | OS verification | PowerShell confirms Windows Server 2025 | | Handoff | Initial setup checklist is the next task | If all checks pass, the Windows Server 2025 VPS has been provisioned correctly and is ready for post-deployment setup. ## What's next - [Windows Server Initial Setup Checklist](/windows-server/windows-server-initial-setup-checklist) — complete the first 30 minutes of server configuration. - [How to Connect to a Windows VPS via RDP](/windows-server/connect-to-windows-vps-via-rdp) — detailed Windows, macOS, Linux, and mobile connection instructions. - [Windows Server 2019 vs 2022 vs 2025](/windows-server/windows-server-version-comparison) — confirm the operating-system choice before production. - [Windows Server Licensing on Raff](/windows-server/windows-licensing) — understand SPLA and eligible BYOL paths. - [Raff Windows VM](/products/windows-vm) — review the Windows VM product. - [Raff pricing](/pricing) — review current VM pricing before deployment. ## Sources - Microsoft Lifecycle — Windows Server 2025: https://learn.microsoft.com/en-us/lifecycle/products/windows-server-2025 - Microsoft Learn — Windows Server release information: https://learn.microsoft.com/en-us/windows/release-health/windows-server-release-info - Microsoft Licensing — Windows Server licensing guidance and Product Terms - Raff Windows VM: https://rafftechnologies.com/products/windows-vm - Raff Windows Server Hub: https://rafftechnologies.com/windows-server - Sources revalidated: 2026-09-17 --- ### Windows Server CALs Explained: User vs Device and When RDS CALs Are Separate URL: https://rafftechnologies.com/windows-server/windows-server-cals-user-vs-device Description: Understand Windows Server CALs for Server 2025: when CALs are required, User vs Device CALs, version compatibility, RDS CALs as additive licenses, External Connectors, and how hosted SPLA differs. ## In short A **Windows Server Client Access License (CAL)** gives a user or device the right to access Windows Server software under Microsoft's customer licensing model. For Windows Server 2025 Standard and Datacenter, internal users or devices generally need a qualifying Windows Server CAL unless a documented exception or CAL-equivalent right applies. Choose a **User CAL** when one person accesses Windows Server from several devices. Choose a **Device CAL** when several people share a smaller number of devices. An **RDS CAL is separate and additive** when Remote Desktop Services functionality is used in a customer-owned deployment. Raff-hosted Windows under SPLA follows the service-provider licensing model instead of ordinary customer Windows Server CAL purchasing. Hosted RDS is licensed separately with RDS User SALs. For the broader licensing model, see [Windows Server Licensing on Raff](/windows-server/windows-licensing). > Microsoft licensing is contract-based. Current Product Terms and the customer's executed Microsoft agreement control if they differ from this guide. ## What is a Windows Server CAL? A Windows Server CAL is an access license. It is not the Windows Server operating-system license itself. Microsoft's Windows Server licensing model separates two layers: 1. **Server licensing** licenses the Windows Server software, normally through core-based licensing. 2. **Access licensing** licenses users or devices that access that Windows Server software. For the conventional customer model, the normal base access license is a **Windows Server CAL**. Microsoft classifies Windows Server CALs as base CALs. Capabilities such as Remote Desktop Services use additive access licenses on top of the base right where applicable. ## Windows Server User CAL vs Device CAL The two CAL types grant access in different ways. | CAL type | Assigned to | Best fit | Example | |---|---|---|---| | **User CAL** | One user | A person who accesses Windows Server from several devices | One employee uses an office PC, laptop, and home computer | | **Device CAL** | One device | A shared endpoint used by several people | Several shift workers share one warehouse terminal | A User CAL follows the licensed user across their devices. A Device CAL follows the licensed device regardless of which permitted user is operating it. ### Choose User CALs when User CALs usually fit when employees have individual accounts, one person uses several devices, staff work from office and home, or the number of users is lower than the number of devices they use. ```text 10 employees Each uses an office desktop, laptop, and home computer → evaluate 10 User CALs ``` ### Choose Device CALs when Device CALs usually fit when several people share fixed workstations, the business operates shifts, or the number of accessing devices is lower than the number of users. ```text 24 shift workers 6 shared warehouse terminals → evaluate 6 Device CALs ``` ## Can you mix User and Device CALs? Yes. Microsoft allows a combination of User and Device CALs when the assignments match the real access model. For example, office employees can use User CALs while a shared reception or warehouse terminal uses a Device CAL. The assignments still need to be documented. CALs are not a floating pool that can be reassigned informally whenever user counts change. ## User CAL vs Device CAL decision table | Situation | Usually better fit | |---|---| | One employee uses several devices | User CAL | | Several employees share one PC | Device CAL | | Remote employees use work and personal devices | User CAL | | Call center uses fixed shared terminals | Device CAL | | Executives access from multiple endpoints | User CAL | | Factory has more workers than terminals | Device CAL | | User and device counts are nearly identical | Compare administration and licensing cost | Do not treat either model as concurrent-session licensing. Five User CALs do not mean any five users may connect at the same time. Each User CAL is assigned to a specific user; each Device CAL is assigned to a specific device. ## When are Windows Server CALs required? Under Microsoft's conventional customer licensing model, Windows Server CAL planning applies when users or devices access licensed Windows Server software unless a specific exception or equivalent access right applies. Common examples include access to: - Active Directory services; - Windows file shares; - print services; - line-of-business applications running on Windows Server; - internal application services; - Windows Server functionality reached indirectly through middleware or another application layer. A user does not have to see a Windows desktop for CAL requirements to matter. Licensing evaluates access to the server software, not only interactive logon. ## CALs are not the same as server licenses Buying Windows Server Standard or Datacenter does not by itself grant unlimited employee access. | Layer | What it licenses | |---|---| | Windows Server core/server license | The Windows Server software/workload | | Windows Server CAL | Base user/device access to licensed Windows Servers | | RDS CAL | Additional Remote Desktop Services access rights | | SQL Server licensing | SQL Server rights, separate from Windows Server | | Microsoft 365 licensing | Microsoft 365 Apps/services, separate from Windows Server | Changing from Standard to Datacenter does not remove the ordinary Windows Server CAL requirement under the conventional customer model. For edition differences, see [Windows Server Standard vs Datacenter](/windows-server/windows-server-standard-vs-datacenter). ## Windows Server CAL vs RDS CAL A **Windows Server CAL** is the base access license. An **RDS CAL** is an additive license for Remote Desktop Services functionality. For a conventional customer-owned RDS deployment, the licensing stack can therefore be: ```text Windows Server license + Windows Server CAL + RDS CAL ``` The RDS CAL does not replace the Windows Server CAL when the base CAL requirement applies. ### Example: employees use an RD Session Host If 12 employees use a Windows Server RD Session Host for shared desktop or RemoteApp access, the customer licensing analysis normally includes the Windows Server license, applicable Windows Server CALs, and applicable RDS CALs. For Per User vs Per Device mode, version compatibility, the RDS licensing server, grace period, and hosted SAL model, use the [RDS CAL Licensing Guide](/windows-server/rds-cal-licensing-guide). ## Administrative RDP is different from employee RDS use Windows Server includes limited Remote Desktop rights for administration. Those administrative connections are not a substitute for a licensed multi-user employee desktop environment. ```text Administrators maintaining the server → administrative Remote Desktop rights Employees using shared desktops or RemoteApp for daily work → Remote Desktop Services licensing model ``` If you are deciding between the two administrative sessions and RD Session Host, see [Multi-User RDP vs RDS Session Host](/windows-server/multi-user-rdp-vs-rds). ## Windows Server CAL version compatibility Windows Server CALs are version-aware. A CAL for a newer Windows Server version can generally access that version and earlier versions. An older CAL does not grant access to a newer Windows Server release. | CAL version | Server 2025 | Server 2022 | Server 2019 | |---|---:|---:|---:| | Windows Server 2025 CAL | Yes | Yes | Yes | | Windows Server 2022 CAL | No | Yes | Yes | | Windows Server 2019 CAL | No | No | Yes | So a Windows Server 2025 CAL can cover access to Server 2025, 2022, and 2019, while a 2022 CAL does not cover Server 2025. Include CAL compatibility in migration planning instead of assuming existing access licenses automatically cover a new server generation. ## CAL exceptions and CAL-equivalent rights Windows Server licensing includes specific exceptions and alternative rights. Microsoft's current guidance includes situations such as qualifying public Internet web workloads, certain HPC use cases, appropriately licensed server-to-server access, and some physical operating-system environments used only to host and manage virtual environments. These exceptions are narrow. An internal IIS application is not automatically exempt merely because it uses HTTP. Microsoft Product Terms also recognize certain subscriptions or suites as CAL-equivalent rights for specific products. Do not assume a generic Microsoft 365 subscription replaces every Windows Server or RDS CAL. Check the exact SKU, assignment, version, and Product Terms. ## What about external users? External users can have a different licensing path from internal employees and onsite contractors. Depending on the scenario, organizations may license external access with individual CALs or a **Windows Server External Connector** assigned to an accessed physical server. Additive capabilities such as RDS can have separate external-access licensing. An External Connector is not automatically cheaper. Compare the external-user population, server count, workload, and current Microsoft terms. ## Indirect access and multiplexing do not remove CAL requirements An application, API, proxy, connection pool, middleware service, or other technology between the user and Windows Server does not automatically reduce required access licenses. ```text 100 employees → business application → middleware service → Windows Server ``` Even if only one middleware identity connects directly to the server, the underlying users and devices may still need to be evaluated under Microsoft's multiplexing rules. This matters for ERP, accounting, internal web applications, file services, and database-backed systems. ## Windows Server CALs, SQL Server, and Active Directory SQL Server licensing is separate from Windows Server licensing. An SQL Server CAL does not replace a Windows Server CAL because they license different products. A deployment can require analysis of both the Windows Server access layer and SQL Server's own Server/CAL or Per Core model. Active Directory Domain Services is also a Windows Server workload. Under the conventional customer licensing model, internal users or devices consuming Windows Server services need the applicable access rights unless an exception or CAL-equivalent right applies. For AD deployment guidance, see [Promote a Windows VPS to an Active Directory Domain Controller](/windows-server/active-directory-domain-controller). ## What changes when Windows Server is hosted by Raff? Customer CAL licensing and service-provider licensing must be kept separate. ### Raff-provided Windows under SPLA When Raff supplies the Windows Server license under Microsoft's **Services Provider License Agreement (SPLA)** model, the hosted workload follows Microsoft's service-provider licensing rules rather than requiring the customer to purchase ordinary Windows Server User or Device CALs for that Raff-provided Windows instance. Raff's current Windows Server Standard licence is **$15/month per instance** in addition to compute. For daily multi-user Remote Desktop Services on the Raff-hosted SPLA model, **RDS User SALs are $8/month per authorized user** and are separate from the Windows Server instance licence. ```text Raff Windows VM + $15/month Windows Server Standard licence + $8/month per authorized RDS user when hosted RDS is required ``` The RDS SAL is assigned by authorized user, not by peak concurrent sessions. ### Customer BYOL If a customer brings eligible Windows Server licences to Raff under Microsoft's applicable outsourcing or Flexible Virtualization rights, the customer's own Microsoft licensing terms apply. That can include Windows Server CALs and, where RDS is used, RDS CALs. Windows Server BYOL should be assessed under the applicable Flexible Virtualization and outsourcing rights. Do not use the separate License Mobility through Software Assurance concept as the Windows Server BYOL mechanism. | Raff deployment | Access-licensing direction | |---|---| | Raff-provided SPLA Windows Server | Service-provider model; ordinary customer Windows Server CAL purchasing does not apply to the Raff-provided workload | | Customer BYOL Windows Server | Review the customer's Windows Server CAL rights | | Customer-owned RDS rights | Review Windows Server CAL + RDS CAL requirements | | Raff-provided hosted RDS under SPLA | Review Windows SPLA + RDS User SAL model | For the complete decision, use [Windows Server Licensing on Raff](/windows-server/windows-licensing). ## How many Windows Server CALs do you need? Count assignments, not concurrent sessions. ### User CAL example ```text 18 employees access Windows Server Each may use multiple devices → evaluate 18 User CALs ``` ### Device CAL example ```text 40 employees work in shifts They share 12 fixed terminals → evaluate 12 Device CALs ``` ### Mixed example ```text 12 office employees with multiple devices + 5 shared warehouse terminals → 12 User CALs + 5 Device CALs may fit ``` These examples illustrate assignment logic only. Final licensing depends on actual access, CAL-equivalent rights, exceptions, external users, and the customer's Microsoft agreement. ## Common Windows Server CAL mistakes ### Assuming the Windows Server license includes unlimited user access The server licence and access licences are different layers under the conventional customer licensing model. ### Buying RDS CALs but forgetting base Windows Server CALs RDS CALs are additive. They do not replace the base Windows Server CAL where that base CAL is required. ### Counting concurrent users instead of licensed users or devices CALs are assigned to users or devices, not to a pool of simultaneous connections. ### Using an older CAL with a newer Windows Server version A Windows Server 2022 CAL does not grant access to Windows Server 2025. ### Assuming a proxy removes CAL requirements Multiplexing and indirect access do not automatically reduce licensing requirements. ### Mixing customer CALs with hosted SPLA SALs Customer-owned licensing and provider licensing are different models. Identify who supplies the Microsoft licence before counting access rights. ## Windows Server CAL planning checklist Before production, document: - [ ] Windows Server version and edition. - [ ] Who supplies the Windows Server licence. - [ ] Whether the deployment uses customer licensing or Raff SPLA. - [ ] Internal users and accessing devices. - [ ] User CAL vs Device CAL assignment model. - [ ] Existing CAL-equivalent rights. - [ ] CAL version compatibility. - [ ] External-user access and External Connector analysis. - [ ] Multiplexing or indirect-access paths. - [ ] Whether Remote Desktop Services is used. - [ ] RDS CAL or hosted RDS SAL requirements. - [ ] SQL Server and other product licensing reviewed separately. - [ ] Final design checked against current Microsoft Product Terms. ## What's next - [Windows Server Licensing on Raff](/windows-server/windows-licensing) - [RDS CAL Licensing Guide](/windows-server/rds-cal-licensing-guide) - [Windows Server Standard vs Datacenter](/windows-server/windows-server-standard-vs-datacenter) - [Multi-User RDP vs RDS Session Host](/windows-server/multi-user-rdp-vs-rds) - [Raff Windows VM](/products/windows-vm) ## Sources - Microsoft Licensing — Windows Server 2025 Licensing Guidance - Microsoft Licensing — Windows Server licensing documents - Microsoft Product Terms — Windows Server - Microsoft Learn — License Remote Desktop Services with Client Access Licenses - Microsoft Licensing — Services Provider License Agreement - Sources revalidated: 2026-09-17 Microsoft licensing terms can vary by agreement, program, product version, geography, and deployment model. Microsoft Product Terms and the customer's executed licensing agreement control if they conflict with this guide. --- ### Windows Server Licensing: SPLA, BYOL, CALs & RDS (2026) URL: https://rafftechnologies.com/windows-server/windows-licensing Description: Understand Windows Server licensing on Raff in 2026: SPLA, BYOL, CALs, RDS SALs, per-VM core minimums, pricing, and which model fits a production Windows VM. ## In short For most production Raff Windows VM buyers, there are two practical Windows Server licensing paths: **Raff-provided SPLA licensing** or **eligible customer BYOL**. Raff currently charges **$15/month per Windows Server Standard instance** under its hosted SPLA model. If users need Remote Desktop Services, Raff-hosted SPLA uses **RDS User SALs at $8 per authorized user per month**. Customer BYOL follows Microsoft's own licensing, CAL, and outsourcing rules instead. Windows Server BYOL is **not** based on License Mobility through Software Assurance. For eligible hosted scenarios, Microsoft's **Flexible Virtualization Benefit** and associated outsourcing rights are the relevant path. At Raff, we treat Windows licensing as a separate deployment decision from VM sizing because the same compute plan can use Raff-provided SPLA licensing or eligible customer BYOL. ## Windows Server licensing on Raff at a glance | Scenario | Windows Server licensing path | Access licensing | Best fit | |---|---|---|---| | Raff provides Windows Server | Raff SPLA | RDS User SALs if RDS is used | Most hosted production VMs | | Customer brings eligible Windows Server licences | BYOL under qualifying Microsoft outsourcing rights / Flexible Virtualization Benefit | Customer CALs and RDS CALs where applicable | Organizations with qualifying Microsoft licensing | The key question is not simply whether you own a Windows Server key. It is **which Microsoft licensing model applies to this hosted workload**. ## Raff Windows Server licensing costs $15 per instance Raff currently prices Windows Server Standard licensing at **$15/month per instance** when Raff supplies the operating-system licence through its SPLA model. That amount is separate from compute. | Raff VM | Compute | Windows Server Standard | Starting total | |---|---:|---:|---:| | 1 vCPU / 2 GB / 50 GB | $13.99 | $15 | **$28.99/mo** | | 2 vCPU / 4 GB / 80 GB | $22.99 | $15 | **$37.99/mo** | | 4 vCPU / 8 GB / 120 GB | $40.99 | $15 | **$55.99/mo** | | 8 vCPU / 16 GB / 180 GB | $76.99 | $15 | **$91.99/mo** | If the workload also uses Remote Desktop Services, add the applicable RDS licensing separately. SQL Server, Microsoft 365 Apps, backup storage, additional volumes, and third-party software are separate where applicable. For the infrastructure breakdown, see [Windows VPS Pricing](/windows-server/windows-vps-pricing-explained). ## SPLA is the simplest production path for many Raff customers Microsoft's **Services Provider License Agreement (SPLA)** is the service-provider licensing framework Raff uses to provide hosted Microsoft software to customers. Under Raff's hosted model, the Windows Server licence is supplied by Raff rather than transferred from the customer into the VM. The practical model is: ```text Raff Windows VM compute + Windows Server Standard SPLA: $15/month per instance + RDS User SALs if Remote Desktop Services is used ``` Do not confuse this with buying or transferring a retail product key. SPLA is a service-provider licensing model. ## SPLA Windows Server does not automatically include RDS Windows Server licensing and Remote Desktop Services licensing are separate layers. Administrative Remote Desktop connections used to manage the server are different from employees using the server as a daily shared Windows desktop or RemoteApp platform. Under Raff's hosted SPLA model, RDS functionality uses **RDS User SALs at $8 per authorized user per month**. Example for five hosted RDS users: ```text 4 vCPU / 8 GB VM $40.99 Windows Server Standard SPLA $15.00 5 RDS User SALs $40.00 --------------------------------------- Starting monthly total $95.99 ``` This does not include Microsoft 365 Apps, SQL Server, backup storage, or third-party application licensing. For RDS-specific rules, see [RDS CAL Licensing Guide](/windows-server/rds-cal-licensing-guide). ## Customer BYOL uses Microsoft's outsourcing rights Some organizations already own eligible Windows Server licences and want to use them on hosted infrastructure. For Windows Server, do **not** use License Mobility through Software Assurance as the default BYOL explanation. Windows Server is not a standard License Mobility product in the way SQL Server and certain server applications can be. For qualifying subscription licences or licences with active Software Assurance, Microsoft's **Flexible Virtualization Benefit** extends outsourcing rights to eligible Authorized Outsourcer scenarios, including shared infrastructure where the Microsoft conditions are met. Raff supports eligible customer BYOL, but the customer's Microsoft agreement, licence status, access rights, and the current Product Terms determine final eligibility. ## Windows Server BYOL can use per-VM licensing when eligible Microsoft permits eligible Windows Server Standard and Datacenter licences to be licensed by virtual machine when the customer has qualifying subscription licences or active Software Assurance. Under that model: - license the virtual cores allocated to the VM; - apply at least **8 core licences per VM**; - maintain at least **16 qualifying core licences per customer**; - maintain the qualifying subscription or active Software Assurance rights; - license users or devices that access Windows Server where CALs are required. A 4-vCPU Windows VM therefore does not automatically mean four Windows Server core licences. The minimums are one reason provider-supplied SPLA can be simpler for smaller hosted VMs. ## Shared Authorized Outsourcer BYOL also affects access rights When a customer uses the Flexible Virtualization Benefit in an eligible outsourcing scenario, Windows Server access rights must be reviewed alongside the server-core licences. For workloads where CALs are required, verify that the customer has the appropriate Windows Server CAL rights and that the subscription or Software Assurance conditions required by the applicable outsourcing model are satisfied. Do not validate only the server-core licences and ignore user or device access rights. For a dedicated CAL explanation, see [Windows Server CALs: User vs Device](/windows-server/windows-server-cals-user-vs-device). ## Windows Server CALs and RDS CALs are separate under BYOL Customer-owned Windows Server licensing normally follows Microsoft's server plus access-licence model. ```text Windows Server core licences + Windows Server CALs where required + RDS CALs if users consume RDS functionality ``` An RDS CAL does not replace the base Windows Server CAL when that base CAL is required. That differs from Raff-hosted SPLA: ```text Raff SPLA Windows Server + RDS User SALs if RDS functionality is used ``` Identifying who supplies the Windows Server licence should happen before counting access licences. ## Two administrative RDP sessions are not a multi-user licensing model Windows Server includes limited Remote Desktop rights for server administration. Those connections are intended for administrators maintaining the server. They are not a substitute for a production RDS deployment used by staff for daily desktops or RemoteApp. If employees need shared Windows sessions, plan the RD Session Host role, the correct RDS licensing model, user profiles, capacity, secure remote access, and backup/recovery. See [Multi-User RDP vs RDS Session Host](/windows-server/multi-user-rdp-vs-rds). ## Standard vs Datacenter does not change the first licensing decision for most Raff VMs Windows Server Standard and Datacenter differ in virtualization and feature rights, but most Raff Windows VM buyers should first answer: 1. Is Raff supplying the Windows Server licence under SPLA? 2. Or is the customer using eligible BYOL rights? 3. Does the workload need RDS? 4. Are Windows Server CALs required under the customer's licensing model? 5. Is another Microsoft product such as SQL Server or Microsoft 365 Apps involved? For the edition feature comparison, see [Windows Server Standard vs Datacenter](/windows-server/windows-server-standard-vs-datacenter). ## SQL Server licensing follows different rules Do not copy Windows Server licensing rules directly to SQL Server. SQL Server is a separate Microsoft product with its own licensing models. Depending on the scenario, SQL Server can involve Per Core licensing, Server + CAL licensing, License Mobility through Software Assurance, Flexible Virtualization Benefit, or provider-supplied licensing where available. Use [SQL Server 2025 Licensing Guide](/windows-server/sql-server-2025-licensing-guide) for the database layer. ## Microsoft 365 Apps requires Shared Computer Activation in multi-user environments If several users sign in to the same Windows Server and use Microsoft 365 Apps, each user needs a qualifying Microsoft 365 licence and the deployment must use **Shared Computer Activation (SCA)** where Microsoft requires it. Microsoft currently lists **Microsoft 365 Business Premium** as the business plan that supports SCA, while plans containing Microsoft 365 Apps for enterprise also support SCA. Microsoft 365 Business Standard does not include SCA rights. For setup and licensing details, see [Shared Computer Activation for Microsoft 365 Apps on RDS](/windows-server/m365-apps-sca). ## Azure Hybrid Benefit is specific to Azure Azure Hybrid Benefit is a Microsoft Azure benefit. It should not be used as a generic explanation for bringing Windows Server licences to any cloud provider. Outside Azure, evaluate Microsoft's applicable outsourcing rights, Flexible Virtualization Benefit, or the provider's service-provider licensing model. ## OEM licences are not a normal cloud BYOL path An OEM Windows Server licence supplied with physical hardware is normally tied to that hardware licensing context. Do not assume an OEM licence from an old office server can simply be moved to a Raff VM. For BYOL, focus on Microsoft's qualifying commercial subscription or active Software Assurance rights and the exact outsourcing entitlement. ## Which Windows Server licensing model fits your deployment? | Situation | Starting point | |---|---| | New production Windows VM with no qualifying existing Microsoft entitlement | **Raff SPLA** | | Customer wants provider-supplied hosted Windows licensing | **Raff SPLA** | | Existing qualifying subscription or active Software Assurance rights | Review **BYOL under Flexible Virtualization Benefit** | | Daily multi-user RDS under Raff licensing | Raff SPLA + **$8/user/month RDS User SALs** | | Daily multi-user RDS under customer BYOL | Customer Windows Server licensing + applicable CALs + RDS CALs | | Microsoft 365 Apps for multiple users | Qualifying Microsoft 365 licences + SCA | | SQL Server workload | Evaluate SQL Server licensing separately | For smaller hosted Windows deployments, provider-supplied SPLA removes the need to prove customer BYOL entitlement. BYOL is relevant when an organization already has qualifying Microsoft commercial licensing and its deployment meets the applicable outsourcing terms. Raff supports **3,000+ customers**, **15,000+ VMs**, and a **99.9% SLA**. Licensing should still be validated for the customer's exact Microsoft agreement before production deployment. ## What's next - [Raff Windows VM](/products/windows-vm) - [Windows VPS Pricing](/windows-server/windows-vps-pricing-explained) - [RDS CAL Licensing Guide](/windows-server/rds-cal-licensing-guide) - [Windows Server CALs: User vs Device](/windows-server/windows-server-cals-user-vs-device) - [Multi-User RDP vs RDS Session Host](/windows-server/multi-user-rdp-vs-rds) - [SQL Server 2025 Licensing Guide](/windows-server/sql-server-2025-licensing-guide) ## Sources - Microsoft Licensing — [Windows Server 2025 Licensing Guidance](https://www.microsoft.com/licensing/guidance/Windows-Server-2025) - Microsoft Licensing — [Windows Server licensing](https://www.microsoft.com/en-us/licensing/product-licensing/windows-server) - Microsoft Licensing — [Flexible Virtualization Benefit](https://www.microsoft.com/licensing/guidance/Flexible-Virtualization-Benefit) - Microsoft Licensing — [SPLA Licensing Guidance](https://www.microsoft.com/licensing/guidance/SPLA) - Microsoft Learn — [License Remote Desktop Services with CALs](https://learn.microsoft.com/en-us/windows-server/remote/remote-desktop-services/rds-client-access-license) - Microsoft Learn — [Shared Computer Activation for Microsoft 365 Apps](https://learn.microsoft.com/en-gb/microsoft-365-apps/licensing-activation/overview-shared-computer-activation) - Sources revalidated: 2026-09-17 Microsoft licensing terms vary by agreement, program, product version, geography, and deployment model. Microsoft Product Terms and the customer's executed Microsoft agreement control if they conflict with this guide. --- ### VPS vs Dedicated Server for Windows Workloads: Cost & Performance URL: https://rafftechnologies.com/windows-server/windows-vps-vs-dedicated-server Description: Compare VPS vs dedicated server for Windows workloads. See differences in cost, performance, isolation, scaling, Remote Desktop, backups, and when each hosting model fits. ## In short For most small and midsize **Windows workloads**, a VPS is the lower-commitment place to start. A **dedicated server** becomes more relevant when the workload specifically needs physical isolation, custom hardware, unusually large local storage, or sustained predictable demand that justifies an entire machine. The useful **VPS vs dedicated server** comparison is not simply which one has more hardware. It is whether the workload needs control of the physical server badly enough to accept the additional cost and operational commitment. Raff provides Windows VMs rather than dedicated servers, so this guide is intended to help buyers decide when a VM is a fit and when a physical server requirement should send them elsewhere. ## VPS vs dedicated server at a glance | Area | Windows VPS | Dedicated server | |---|---|---| | Infrastructure | Virtual Windows Server environment | Entire physical server | | Starting commitment | Lower | Higher | | Scaling | Usually easier to resize or migrate | Often requires hardware change or migration | | Physical isolation | No | Yes | | Custom hardware | Limited to provider plans | Much more flexibility | | Remote Desktop workloads | Strong fit | Strong fit, but often more infrastructure than needed | | Business apps | Strong fit for many SMB workloads | Useful when the workload is unusually large or hardware-sensitive | | Backups and recovery | VM, file and application backup options | Requires server-level recovery planning too | | Best fit | Changing workloads, SMBs, remote teams, application hosting | Predictable heavy workloads, custom hardware, physical-isolation requirements | A practical Raff sales-engineering rule is simple: **if the requirement list never mentions physical isolation or custom hardware, size the Windows VM first.** ## What is a VPS? A VPS is a virtual server with allocated compute, memory, storage, networking, and operating-system access. In this guide, the focus is a VPS running Windows Server with administrator access and Remote Desktop. Common Windows workloads include: - Remote Desktop administration; - accounting and ERP applications; - QuickBooks, Sage, and other Windows software; - IIS and .NET applications; - SQL Server-backed business systems; - shared application servers; - file and document workflows; - migration staging; - MSP-managed client environments. For a small team, the main advantage is not that a VPS is automatically faster than dedicated hardware. It is that the business can start with the capacity it needs now and change the VM as the workload becomes clearer. ## What is a dedicated server? A dedicated server is a physical machine assigned to one customer. The customer receives the resources of that entire server rather than a virtual machine running on shared cloud infrastructure. Dedicated servers are a better fit when the project specifically requires: - physical isolation; - custom CPU or storage configuration; - large local disk arrays; - customer-controlled virtualization; - unusual network or hardware requirements; - sustained high load that makes a full machine economically sensible. That extra control is valuable when the workload needs it. It is unnecessary complexity when the business only needs a reliable Windows Server for users or applications. ## VPS vs dedicated server performance A dedicated server gives one customer the full physical machine, but that does not mean every dedicated server is faster than every VPS. Real application performance depends on: - CPU generation and clock behavior; - number and type of CPU cores; - RAM capacity; - storage latency and throughput; - virtualization configuration; - application design; - database workload; - concurrent users; - network path. A modern Windows VM can be the more practical choice for a small application workload even when a dedicated server has more raw hardware. Choose dedicated hardware because the **workload requires the hardware model**, not because the word dedicated sounds stronger. ## Isolation is the clearest architectural difference A dedicated server gives you physical machine isolation. A Windows VPS gives you virtual machine isolation on shared cloud infrastructure. Physical isolation may matter when: - a security architecture explicitly requires it; - a vendor requires dedicated hardware; - the customer needs control over the host layer; - custom hardware is part of the design. But physical isolation does not replace operating-system security. Both models still require Windows patching, account security, firewall rules, Remote Desktop hardening, backups, logging, monitoring, and application security. A dedicated server with exposed RDP and weak credentials is not safer merely because the machine is physical. ## Cost: compare the whole operating model The useful cost comparison includes the server, operating-system licensing, backup, idle capacity, scaling, and migration effort. | Cost area | Windows VPS | Dedicated server | |---|---|---| | Entry cost | Lower | Higher | | Over-provisioning risk | Lower | Higher if the machine is much larger than the workload | | Scaling | Change VM resources or migrate plans | May require replacing or migrating hardware | | Hardware management | Abstracted by provider | More relevant to the service model | | Backup planning | Still required | Still required | | Migration effort | Usually easier to stage | More hardware commitment | | Idle capacity | Easier to minimize | Full server cost remains | For Raff, the current customer-facing Windows entry is **$28.99/month**, consisting of **$13.99 compute + $15 Windows Server Standard licensing** for 1 vCPU, 2 GB RAM, and 50 GB storage. Other current examples are: | Raff Windows VM | Compute | Windows licence | Starting total | |---|---:|---:|---:| | 1 vCPU / 2 GB / 50 GB | $13.99 | $15 | **$28.99/mo** | | 2 vCPU / 4 GB / 80 GB | $22.99 | $15 | **$37.99/mo** | | 4 vCPU / 8 GB / 120 GB | $40.99 | $15 | **$55.99/mo** | | 8 vCPU / 16 GB / 180 GB | $76.99 | $15 | **$91.99/mo** | Remote Desktop Services licensing, SQL Server, additional storage, backups, and third-party application licences are separate where applicable. Raff Windows VMs use a 3 Gbps public network port with unmetered bandwidth and no VM egress fees. Dedicated-server pricing varies by CPU, storage, location, contract length, and management level, so a single generic dedicated-server price would be misleading. For the full Windows breakdown, see [Windows VPS Pricing](/windows-server/windows-vps-pricing-explained). ## When a Windows VPS fits better ### Remote Desktop for a small team If administrators or users need a hosted Windows environment, a VM lets the business start without renting an entire physical server. For employee multi-user desktops, distinguish ordinary administrative RDP from Remote Desktop Services. See [Multi-User RDP vs RDS Session Host](/windows-server/multi-user-rdp-vs-rds). ### Business application hosting Many accounting, ERP, tax, Access, and line-of-business applications need Windows Server but do not require dedicated hardware. A VM is a good fit when the application vendor supports the operating system and the workload is sized correctly. ### Replacing an office server Moving from aging local hardware to a Windows VM can remove dependence on office power and physical replacement cycles. The migration still needs application testing, backups, and a rollback plan. ### Workloads that may grow unpredictably When user count, database size, or application load is still changing, committing to a fixed physical server too early can create unnecessary over-provisioning. ## When a dedicated server fits better ### Physical isolation is mandatory If the architecture requires an entire physical server assigned to one customer, a VPS does not satisfy that requirement. ### The workload needs custom hardware A dedicated server may allow specific CPU models, storage layouts, RAID designs, accelerators, or network interfaces that standard VM plans do not expose. ### Sustained load is very large and predictable A business running a consistently heavy workload may find that a full physical server is operationally or economically attractive. The important point is that this should be demonstrated by the workload, not assumed before measurement. ### The customer wants its own virtualization layer If the business wants control of the physical host and intends to operate its own virtualization platform, dedicated hardware is the more natural foundation. ## Remote Desktop usually does not require dedicated hardware Remote Desktop is one of the most common reasons small businesses look at Windows hosting. A small-team architecture often looks like: ```text Users ↓ Controlled remote access ↓ Windows VM ├── Business application ├── File access ├── Database/application services └── Backups ``` The first sizing questions should be: 1. How many concurrent users are expected? 2. Which applications will they run? 3. Does the application support multi-user Windows Server or RDS use? 4. How much RAM does the application consume under load? 5. Is SQL Server involved? 6. Are users running browser-heavy or reporting workloads? For concrete sizing ranges, use [Windows VPS Sizing for Remote Users](/windows-server/windows-vps-sizing-remote-users). ## Business applications rarely require physical hardware by default For QuickBooks, Sage, ERP systems, Access databases, and other Windows applications, start with application compatibility and measured sizing requirements. | Workload | Starting point | |---|---| | QuickBooks for a few users | Windows VPS | | Sage or tax application | Windows VPS, sized for user count | | Small ERP application | Windows VPS | | IIS/.NET business app | Windows VPS | | Large SQL-backed ERP with sustained heavy I/O | Benchmark first; dedicated may become relevant | | Vendor explicitly requires dedicated hardware | Dedicated server | For accounting workloads, see [QuickBooks Multi-User Windows Server VPS](/windows-server/quickbooks-multi-user-windows-server-vps). ## Backups do not disappear on either model Both models still need application-aware backups where required, database backups, file restore points, off-server copies, restore testing, and documented recovery procedures. A Windows VPS can make VM-level protection convenient, but snapshots are not automatically a complete backup strategy. For Raff workloads, [Data Protection](/products/data-protection) covers the platform backup and snapshot layer; applications still need their own recovery design where required. ## Migration is usually easier to stage on a Windows VPS For an office-server migration, a side-by-side pattern can reduce cutover risk: ```text Existing server ↓ Build Windows VM ↓ Install and test applications ↓ Copy data ↓ Validate users and backups ↓ Cut over ↓ Keep rollback path temporarily ``` This allows the business to test the target environment before committing to production cutover. Use [Windows Server Migration Checklist for Small Businesses](/windows-server/windows-server-migration-checklist-small-business) before migration. ## Security depends on the design, not the word dedicated For either model: - keep Network Level Authentication enabled for direct RDP where applicable; - restrict Remote Desktop exposure; - use named administrator accounts; - keep Windows updated; - enable Windows Firewall; - monitor authentication events; - protect backups; - use a gateway, VPN, or stronger access model when the risk requires it. For direct RDP hardening, use [Secure Direct RDP on a Windows VPS](/windows-server/secure-direct-rdp-windows-vps). ## Decision matrix ![Decision matrix visual showing when small businesses should choose Windows VPS or dedicated server](https://raff-images.s3.raffusercloud.com/smb_windows_infrastructure_decision_matrix_webp_2f12b5ce0e.png) | Question | Windows VPS | Dedicated server | |---|---:|---:| | Need to start quickly? | ✓ | | | Need easy resizing? | ✓ | | | Small or medium Windows workload? | ✓ | | | Remote users/business apps? | ✓ | | | Replacing office hardware? | ✓ | | | Need physical isolation? | | ✓ | | Need custom hardware? | | ✓ | | Need own hypervisor? | | ✓ | | Sustained very large predictable load? | Maybe | ✓ | The strongest reason to choose dedicated hardware is a requirement that a Windows VM cannot satisfy. Without that requirement, validating the workload on a VM first usually reduces commitment and makes sizing easier. ## How Raff fits the decision Raff does not sell dedicated servers. Raff provides Windows VMs for customers that need a hosted Windows Server environment without starting with physical hardware. Raff is a fit when the requirement is Remote Desktop administration, Windows business applications, Windows-based SaaS or internal tools, SQL-backed application servers, SMB migration from local hardware, MSP-managed Windows environments, or workloads that need room to grow. Raff is not the right fit when the project explicitly requires a physical server, custom hardware, or customer control of the host virtualization layer. Raff supports **3,000+ customers**, **15,000+ VMs**, and a **99.9% SLA**. Buyers should still choose the infrastructure model based on the workload requirement rather than the provider brand. ## What's next - [Raff Windows VM](/products/windows-vm) - [Windows VPS Hosting for Small Businesses](/windows-server/windows-vps-small-business) - [Windows VPS Sizing for Remote Users](/windows-server/windows-vps-sizing-remote-users) - [Multi-User RDP vs RDS Session Host](/windows-server/multi-user-rdp-vs-rds) - [Windows Server Migration Checklist for Small Businesses](/windows-server/windows-server-migration-checklist-small-business) - [Windows Server Hardening Checklist](/windows-server/windows-server-hardening-checklist) ## Sources - Microsoft Learn — [Remote Desktop Services overview](https://learn.microsoft.com/en-us/windows-server/remote/remote-desktop-services/remote-desktop-services-overview) - Microsoft Learn — [License Remote Desktop Services with CALs](https://learn.microsoft.com/en-us/windows-server/remote/remote-desktop-services/rds-client-access-license) - Microsoft Learn — [Hyper-V overview](https://learn.microsoft.com/en-us/windows-server/virtualization/hyper-v/overview) - Microsoft Learn — [Windows Server security](https://learn.microsoft.com/en-us/windows-server/security/) - Raff product and pricing facts revalidated: 2026-09-17 --- ### Azure Windows VPS vs Raff: Azure VM Alternative (2026) URL: https://rafftechnologies.com/windows-server/azure-comparison Description: Compare Azure Windows VMs with Raff Windows VPS for SMB and MSP workloads, including pricing structure, Windows licensing, egress, support, migration complexity, and when each platform is the better fit. ## In short People searching for an **Azure VPS** or **Azure Windows VPS** are usually comparing Microsoft Azure Virtual Machines with a simpler Windows VPS provider. Both can run Windows Server, RDP, IIS, SQL Server, Active Directory, and business software, but they solve different infrastructure problems. Choose **Azure** when the VM is part of a broader Azure architecture that depends on services such as Azure SQL, Azure Functions, Azure App Service, Azure Monitor, Microsoft Entra integrations, Azure Policy, Defender for Cloud, or specific Azure regions and compliance programs. Choose **Raff Technologies** when the workload is mainly a self-managed Windows Server VM and you value a simpler VM-first platform, predictable monthly planning, Raff-provided Windows Server licensing through SPLA or eligible BYOL, and unmetered VM bandwidth without Azure-style internet egress charges. The practical decision is: ```text Need the Azure ecosystem around the VM? Choose Azure. Need the Windows VM itself? Compare Raff directly. ``` ![Azure vs Raff Windows VPS decision framework showing Azure as the better fit for Azure-native services, global regions, and enterprise governance, while Raff fits Windows VPS, RDP, business apps, SQL Server, ERP, predictable cost, and unmetered bandwidth.](https://raff-images.s3.raffusercloud.com/azure_vs_raff_windows_vps_decision_framework_png_1be12d61d2.png) ## Azure Windows VPS vs Raff: quick verdict | Workload | Better starting point | Why | |---|---|---| | QuickBooks, Sage, tax software, ERP, or another Windows business app over RDP | Raff | Focused Windows VM model without requiring Azure-native services | | IIS or ASP.NET application on a self-managed Windows Server | Raff or Azure | Raff is simpler when the app only needs a VM; Azure fits better when the app uses other Azure services | | SQL Server on a self-managed Windows VM | Raff or Azure | Depends on networking, licensing, monitoring, HA, and wider platform dependencies | | Azure SQL, Functions, Service Bus, App Service, or Logic Apps | Azure | These are Azure-native services, not plain VM features | | Enterprise governance using Entra ID, Azure Policy, Defender for Cloud, and Azure Monitor | Azure | Native integration is the main value | | Small business replacing an office Windows server | Raff | A simpler VM-first model is often easier to operate | | MSP hosting separate Windows workloads for clients | Raff | Focused Windows infrastructure and predictable monthly planning can simplify repeatable client environments | | Global multi-region application using several Azure regions | Azure | Azure provides a much broader global cloud footprint | | Remote Windows desktop for a small team | Raff | Good fit when the requirement is primarily Windows Server plus RDS/RDP rather than Azure Virtual Desktop | | Azure Virtual Desktop deployment with Entra and Azure management integrations | Azure | The workload depends on the Azure desktop platform | This is not a comparison of the entire Azure platform against one Raff VM. It is a comparison of **Azure Virtual Machines and Raff Windows VMs for the same self-managed Windows Server workload**. ## What is an Azure VPS? Microsoft does not position the product as "Azure VPS." The comparable Azure service is **Azure Virtual Machines**. An Azure Windows VM gives you administrator access to a Windows Server guest operating system running on Azure infrastructure. You select a VM family and size, disk resources, networking, region, Windows image, and other services you want around it. A Raff Windows VPS is also infrastructure as a service. You receive a Windows VM that you administer yourself, but the product model is intentionally narrower and more VM-focused. For both providers, the customer is still responsible for the guest workload unless a separate managed service says otherwise. That includes areas such as: - Windows configuration; - application installation and updates; - user access; - firewall policy; - database maintenance; - backup design; - restore testing; - monitoring; - RDS design and licensing where applicable. ## Side-by-side comparison | Area | Azure Windows VM | Raff Windows VM | |---|---|---| | Platform scope | Hyperscale cloud platform with a very broad service catalog | Focused cloud VM platform | | Best fit | Azure-connected apps, enterprise governance, global architectures | Windows Server, RDP, business apps, IIS, SQL Server, SMB and MSP workloads | | Billing model | Metered Azure resource pricing with multiple cost components | Monthly, yearly, and hourly PAYG VM billing options | | Windows Server licensing | Windows software charges are part of Windows VM pricing unless eligible Azure Hybrid Benefit is applied | Raff-provided SPLA licensing or eligible customer BYOL | | Storage | Azure Managed Disks are separate resources | Base VM storage is included in the selected Raff plan; extra volumes are optional | | Internet bandwidth | First 100 GB/month of internet egress is currently free, then Azure applies usage-based rates that vary by source continent and routing option | Raff VM traffic is unmetered under current VM network terms | | Networking | VNet, subnet, NIC, NSG, public IP, private endpoints, gateways, routing, and other Azure services | Simpler VM and private-network model | | Managed cloud services | Extensive | Smaller catalog focused around Raff products | | Global region breadth | Extensive | More limited | | Enterprise governance | Deep Azure-native governance and identity ecosystem | Simpler infrastructure controls | | Support path | Microsoft and Azure support plans plus partner ecosystem | Raff infrastructure support focused on the Raff platform and Windows VM workloads | | Migration complexity | Low when staying in Azure; leaving can be simple or complex depending on dependencies | Straightforward target when the source workload is mostly a portable Windows VM | The important difference is not whether both providers can boot Windows Server. They can. The difference is the amount of platform around the VM and whether your workload benefits from that platform. ## Pricing: compare the full Windows VM cost A fair **Azure VM vs VPS** comparison needs more than the compute line item. ![Azure VM vs Raff Windows VPS cost model comparison showing Azure compute, Windows license, disk, public IP, egress, backup, monitoring, and support compared with Raff VM-first pricing, included storage, public IP, and unmetered bandwidth.](https://raff-images.s3.raffusercloud.com/azure_vm_vs_raff_windows_vps_cost_model_png_6f349564c1.png) For Azure, the monthly total can include: - VM compute; - Windows Server software charges unless Azure Hybrid Benefit applies; - managed disks; - public IP and networking resources where applicable; - internet egress after the free allowance; - backup; - snapshots; - monitoring and logs; - security services; - support plans. For Raff, compare: - the selected Windows VM plan; - the applicable Windows Server licensing path; - RDS access licensing if staff use Remote Desktop Services; - optional extra volumes; - optional backup and snapshot storage; - application-specific licensing such as SQL Server or Microsoft 365 Apps. Use the current [Raff pricing page](/pricing) and the Azure Pricing Calculator on the same day. Avoid comparing an old blog price against a current provider quote. ### Why this page does not publish one Azure VM price Azure pricing changes with: - region; - VM family and size; - Windows or Linux image; - pay-as-you-go, reservation, savings plan, or Spot model; - Azure Hybrid Benefit eligibility; - disk type and size; - networking and egress pattern; - backup and monitoring choices; - commercial agreement and currency. One hard-coded Azure monthly figure would therefore be misleading. Build both provider totals around the same CPU, RAM, storage, bandwidth, Windows licensing, backup, and support assumptions. ## Azure internet egress vs Raff unmetered bandwidth Azure's current bandwidth pricing lists the **first 100 GB per month of internet egress as free**. Usage above that allowance is billed by tier, and the rate varies by source continent and whether traffic uses Microsoft's premium global network or the transit-ISP routing preference. That matters when a Windows workload regularly moves data out of the cloud, for example: - large file downloads; - offsite backups; - SQL exports; - document delivery; - web application assets; - media files; - data replication; - migration traffic. Raff's current VM network model uses **unmetered VM bandwidth**, so there is no Azure-style per-GB internet egress line item on the VM bill. Do not assume that every RDP session itself creates huge transfer charges. The cost difference becomes more material when the workload moves larger volumes of files or application data. ## Windows Server licensing: Azure Hybrid Benefit vs Raff SPLA or BYOL The old version of this comparison incorrectly described Raff's production path as starting from an evaluation license. That is not the production licensing model to compare. ### Azure Windows licensing Windows software charges are included in normal Azure Windows VM pricing. Eligible customers can reduce the Windows Server software portion with **Azure Hybrid Benefit**. Microsoft currently requires qualifying Windows Server licenses with active Software Assurance or qualifying subscription rights. For Windows VMs, Azure Hybrid Benefit requires at least **8 eligible core licenses per VM**, even when the VM has fewer than eight virtual cores. Larger VMs require licenses matching the VM core count. Azure Hybrid Benefit can materially change the economics for organizations that already own the right Microsoft licensing. ### Raff Windows licensing For production Raff Windows VMs, the practical choices are: 1. **Raff-provided Windows Server licensing through SPLA**, or 2. **eligible customer BYOL** under the applicable Microsoft outsourcing and Flexible Virtualization Benefit rules. Windows Server BYOL outside Azure should not be described as ordinary License Mobility through Software Assurance. For the current Raff licensing model, use [Windows Server Licensing: SPLA, BYOL, CALs & RDS](/windows-server/windows-licensing). If staff will use the server as a daily shared Remote Desktop environment, also review [RDS CAL Licensing](/windows-server/rds-cal-licensing-guide). Administrative RDP and a production RDS deployment are different licensing scenarios. ## Where Azure is the better fit Azure is usually the stronger choice when the Windows VM is only one component of a larger Azure architecture. ### Azure-native application services Keep the workload on Azure when it materially depends on services such as: - Azure SQL Database; - Azure App Service; - Azure Functions; - Azure Service Bus; - Azure Logic Apps; - Azure Storage; - Azure Key Vault; - Private Endpoints; - Azure Monitor; - Defender for Cloud; - Microsoft Sentinel; - Azure Policy. Moving only the Windows VM would not replace those services. The project would become an application and architecture migration rather than a VM migration. ### Enterprise identity and governance Azure is also a natural fit for organizations that have standardized operations around Microsoft Entra ID, Azure RBAC, Azure Policy, Defender, Sentinel, centralized logging, enterprise landing zones, and existing Azure networking. In those environments, governance integration can be worth more than a lower or simpler VM bill. ### Global and regulated architectures Choose Azure when the workload depends on a specific Azure region, broad global region coverage, sovereign offerings, or Azure-specific compliance and enterprise procurement requirements. A focused VM provider should not pretend to match Azure's global platform footprint. ### Azure Virtual Desktop If the requirement is a large desktop virtualization environment using Azure Virtual Desktop, Azure-native identity and management, the correct comparison is not a single Windows VPS. AVD is its own platform architecture. ## Where Raff is the better fit Raff becomes more compelling when the Azure environment is essentially a self-managed Windows Server with a few basic infrastructure resources around it. A common portable workload looks like: ```text Windows VM + disk + private/public networking + RDP or RDS + installed business application + backup ``` Examples include: - accounting applications; - ERP and inventory software; - tax software; - legacy Windows applications; - IIS and ASP.NET applications; - SQL Server on a self-managed VM; - small RDS environments; - MSP-managed client servers; - replacement for an aging office Windows server. In these cases, Raff can remove platform layers that the workload is not using while keeping the Windows Server environment familiar. ### Predictable monthly infrastructure planning Raff Windows VMs support monthly, yearly, and hourly PAYG billing. For servers that run continuously, monthly or yearly terms can make recurring budgeting straightforward, while hourly PAYG is available when shorter-lived usage is a better fit. That does not automatically make Raff cheaper in every scenario. Azure reservations, savings plans, Azure Hybrid Benefit, or a heavily optimized architecture can materially reduce Azure cost. Compare the actual configuration and licensing rights. ### Simpler platform surface A small business often does not need to learn resource groups, several Azure network resources, multiple billing meters, policy frameworks, and optional management services just to run one Windows business application. A narrower platform can be an advantage when the requirement is narrow too. ### Windows workload focus Raff's Windows Hub and support workflows are built around common Windows VM use cases such as RDP, IIS, SQL Server, Active Directory, business software, migration, firewall configuration, and Windows performance troubleshooting. Application vendors still remain responsible for their own software, and customers remain responsible for guest-OS administration unless a separate managed service applies. ## Shared responsibility is similar for a self-managed VM Switching from Azure VM to Raff Windows VM does not make guest operating-system work disappear. For a self-managed Windows VM on either platform, plan ownership for: - Windows Update; - local and domain accounts; - RDP/RDS security; - Windows Firewall; - IIS and application updates; - SQL Server maintenance; - antivirus or EDR policy; - backup scheduling; - restore testing; - monitoring; - application licensing; - incident response. The physical infrastructure is the provider's responsibility. The guest OS and application workload remain customer responsibilities unless a contract explicitly changes that boundary. ## Azure VM migration to Raff: when it is straightforward Migration is simplest when the Azure VM has few Azure-specific dependencies. ### Good candidate ```text Windows Server IIS or business application SQL Server or local app database RDP/RDS users Managed disk Public/private IP Basic backup ``` ### Needs deeper redesign ```text Windows Server + Azure SQL + Azure Files + Private Endpoints + Entra-dependent services + Key Vault + Service Bus + Functions + Azure Monitor/Sentinel workflows ``` The second architecture is not merely a VM move. Each Azure service needs a replacement, migration, or decision to remain in Azure. ## Step 1: inventory the Azure workload Document: - VM size and utilization; - Windows Server version; - disk sizes and used capacity; - public and private IP configuration; - NSG/firewall rules; - IIS sites; - SQL Server instances; - business applications; - users and service accounts; - RDP/RDS model; - scheduled tasks; - certificates; - backup jobs; - DNS records; - Azure-native dependencies. Do not size the destination from the Azure VM name alone. Review actual CPU, RAM, storage, and application behavior. ## Step 2: identify services that cannot move with the VM Search the Azure subscription and the application configuration for dependencies on: - Azure SQL; - Azure Storage or Azure Files; - Key Vault; - Private Endpoints; - Entra application identities; - Functions; - Logic Apps; - Service Bus; - Azure Backup; - Azure Monitor; - Defender for Cloud; - Sentinel; - Azure-specific DNS or networking. Decide whether each dependency stays in Azure, moves to another service, or is replaced. ## Step 3: choose the Raff destination by workload Select CPU, RAM, and storage based on real utilization and growth rather than matching an Azure SKU name mechanically. Useful planning guides: - [Windows VPS Sizing for Remote Users](/windows-server/windows-vps-sizing-remote-users) - [Windows VPS Pricing](/windows-server/windows-vps-pricing-explained) - [Windows Server Version Comparison](/windows-server/windows-server-version-comparison) If the workload is business-critical, include backup and rollback capacity before cutover. ## Step 4: migrate by application, not just by disk The migration method depends on the workload: - file copy for ordinary data; - SQL Server backup and restore for databases; - application vendor migration tools; - IIS configuration and certificate migration; - side-by-side application installation; - server-role migration for Windows roles; - image-based migration only when the workload and licensing model support it. For business software, vendor-supported migration is generally safer than assuming a cloned disk will behave correctly on different infrastructure. ## Step 5: test the real business workflow Before cutover, verify: - RDP or RDS login; - application launch; - user permissions; - database connectivity; - reports and exports; - printing where needed; - scheduled tasks; - DNS; - firewall rules; - backups; - restore procedure; - external integrations. A successful Windows boot is not sufficient migration validation. For a broader checklist, use [Windows Server Migration Checklist for Small Businesses](/windows-server/windows-server-migration-checklist-small-business). ## When Azure can still be cheaper A comparison page should include the cases where Azure economics improve. Azure can become more competitive when you already have qualifying Azure Hybrid Benefit rights, commit to a reservation or savings plan, use auto-shutdown for non-production systems, right-size aggressively, or replace a self-managed VM with an Azure managed service that reduces operational work. That is why the useful comparison is not: ```text Azure list price vs Raff list price ``` It is: ```text Your optimized Azure architecture vs Your required Raff architecture ``` Include licensing, storage, bandwidth, backups, operations, and the services the application actually needs. ## Decision checklist Choose **Raff Windows VM** when most of these are true: - the workload is primarily one or more Windows Server VMs; - the application is self-managed; - users need RDP or a small RDS environment; - business software or IIS runs directly on Windows Server; - Azure-native services are not central to the workload; - predictable monthly infrastructure cost matters; - outbound data transfer is meaningful; - the team prefers a simpler VM-first platform; - the environment is managed by a small IT team or MSP. Choose **Azure** when most of these are true: - the application depends on multiple Azure-native services; - the organization already operates an Azure landing zone; - Entra, Azure Policy, Defender, Sentinel, or Azure Monitor are core to operations; - global region coverage or an Azure-specific geography is required; - Azure Virtual Desktop is the target architecture; - existing Microsoft licensing makes Azure Hybrid Benefit valuable; - the team already has mature Azure operations and cost-management practices. ## Raff recommendation For a buyer asking only for an **Azure Windows VPS**, start by listing the Azure services the workload actually uses. If the list is mostly: ```text Virtual Machine Disk Network RDP Windows application Backup ``` then Raff is worth comparing as a simpler Azure VM alternative. If the list includes several platform dependencies such as Azure SQL, Functions, Service Bus, Key Vault, Private Endpoints, Entra-based application integrations, Sentinel, or Azure Policy, keeping the workload on Azure may be the better engineering decision. :::cta Talk to Windows Engineer Planning to move a Windows workload off Azure? Review the VM, Windows licensing, RDS, SQL Server, storage, backups, and Azure dependencies before choosing the destination. ::: ## Frequently asked questions ### Is Azure a VPS provider? Azure's comparable product is Azure Virtual Machines rather than a product named Azure VPS. Searchers often use "Azure VPS" to describe an Azure VM with administrator access. ### Is Raff an alternative to Azure Windows VMs? Yes for workloads that mainly need a self-managed Windows Server VM. Raff is not a replacement for the full Azure service catalog, so Azure-native applications may be better kept on Azure. ### Does Azure charge for bandwidth? Azure currently includes the first 100 GB per month of internet egress and then charges usage-based rates that vary by source continent and routing option. Data transfer pricing should be checked on Azure's current bandwidth page when comparing costs. ### Can I use my Windows Server license on Azure? Eligible customers can use Azure Hybrid Benefit with qualifying Windows Server licenses that have active Software Assurance or qualifying subscription rights. Microsoft currently applies a minimum of eight eligible core licenses per VM. ### How is Windows Server licensed on Raff? Raff can provide Windows Server licensing through its SPLA model. Eligible customers can also evaluate BYOL under the applicable Microsoft outsourcing and Flexible Virtualization Benefit rules. See the Raff Windows Server licensing guide for the current production model. ### Is Raff cheaper than Azure? It depends on the workload. Raff can be easier to budget for an always-on standalone Windows VM because its model is narrower and VM bandwidth is unmetered. Azure can become more competitive with Hybrid Benefit, reservations, savings plans, right-sizing, or when Azure managed services replace work you would otherwise operate yourself. ### Should I migrate from Azure to Raff? Consider migration when the workload is mostly a portable Windows VM and does not depend heavily on Azure-native services. Inventory dependencies first, build a parallel destination, test the real business workflow, and keep a rollback path during cutover. ## Validation scope This comparison was revalidated on **September 11, 2026**. Azure bandwidth terms and Azure Hybrid Benefit requirements were checked against current Microsoft documentation. Raff Windows licensing terminology was aligned with Raff's current SPLA/BYOL guidance. Cloud pricing and Microsoft licensing terms can change. Verify Azure pricing, Microsoft Product Terms, and current Raff pricing at the time of purchase. ## What's next - [Raff Windows VM](/products/windows-vm) - [Raff Pricing](/pricing) - [Windows VPS Pricing](/windows-server/windows-vps-pricing-explained) - [Windows Server Licensing](/windows-server/windows-licensing) - [Windows VPS Hosting for Small Businesses](/windows-server/windows-vps-small-business) - [Windows VPS Sizing for Remote Users](/windows-server/windows-vps-sizing-remote-users) - [Windows Server Migration Checklist](/windows-server/windows-server-migration-checklist-small-business) - [RDS CAL Licensing Guide](/windows-server/rds-cal-licensing-guide) ## Sources - Microsoft Azure - Bandwidth pricing: https://azure.microsoft.com/en-us/pricing/details/bandwidth/ - Microsoft Learn - Azure Hybrid Benefit for Windows VMs: https://learn.microsoft.com/en-us/azure/virtual-machines/windows/hybrid-use-benefit-licensing - Microsoft Learn - Azure Virtual Machines documentation: https://learn.microsoft.com/en-us/azure/virtual-machines/ - Microsoft Learn - Shared responsibility in the cloud: https://learn.microsoft.com/en-us/azure/security/fundamentals/shared-responsibility - Microsoft Azure - Pricing Calculator: https://azure.microsoft.com/en-us/pricing/calculator/ - Raff - Windows VM: https://rafftechnologies.com/products/windows-vm - Raff - Pricing: https://rafftechnologies.com/pricing - Raff - Windows Server Licensing: https://rafftechnologies.com/windows-server/windows-licensing - Sources revalidated: 2026-09-11 --- Microsoft, Azure, Windows Server, Microsoft Entra, and related product names are trademarks of Microsoft Corporation. Raff Technologies is an independent infrastructure provider and is not affiliated with, sponsored by, or endorsed by Microsoft Corporation. --- ### Windows VPS Pricing: What It Really Costs in 2026 URL: https://rafftechnologies.com/windows-server/windows-vps-pricing-explained Description: Understand the real cost of a Windows VPS in 2026, including compute, Windows Server licensing, RDS access, backups, storage, bandwidth, support, and workload sizing. ## In short A **Windows VPS price** is not just the VM line item. The recurring total can include compute, Windows Server licensing, Remote Desktop Services access, additional storage, backups, snapshots, SQL Server, application licensing, and support. On Raff, Windows VM compute currently starts at **$13.99/month**, and Windows Server Standard licensing through Raff's SPLA model is **$15/month per instance**, so the current entry Windows Server total starts at **$28.99/month** before optional services. For most business buyers, the useful comparison is not the lowest headline VM price. It is **what the recurring price includes, whether Windows licensing is accounted for, and whether the VM is sized correctly for the workload**. This guide focuses on Windows VPS pricing and monthly cost. If you are choosing or deploying a Windows VPS rather than comparing cost components, see Raff [Windows VPS plans](/products/windows-vm). ## Windows VPS pricing at a glance | Cost layer | Raff current pricing / planning point | |---|---| | Windows VM compute | From **$13.99/month** | | Windows Server Standard SPLA | **$15/month per instance** | | Entry Windows Server total | **$28.99/month** before optional services | | RDS User SAL under Raff-hosted SPLA | **$8/user/month** when RDS functionality is required | | Volumes | **$0.08/GiB/month** | | Snapshots & backups | **$0.06/GB/month** after the applicable free pool | | VM bandwidth | **3 Gbps port, unmetered bandwidth**, no VM egress fees | The entry plan is useful for light Windows workloads, administration, testing, and small services. A business workload may need more CPU, RAM, storage, RDS access, or backup capacity. ## What determines Windows VPS cost The monthly total usually comes from several layers. | Cost factor | Why it matters | |---|---| | CPU | More users, applications, reports, and database work need more compute | | RAM | RDP sessions, browsers, business apps, SQL Server, and profiles consume memory | | Storage | Windows, applications, files, databases, logs, and growth all need capacity | | Windows Server licensing | May be included, optional, BYOL, or billed separately depending on provider | | RDS licensing | Multi-user Remote Desktop Services access has its own licensing model | | SQL Server | Separate Microsoft product and licensing decision | | Backups/snapshots | Recovery capacity and retention add cost | | Additional volumes | Useful when data growth exceeds the base VM disk | | Support | Infrastructure and migration support affect operating cost | | Migration | Moving apps, files, SQL, users, or AD can require project work | The cheapest VM can become the more expensive option if it is under-sized or if important costs only appear after checkout. ## Raff Windows VPS pricing in 2026 Raff separates compute and Windows Server licensing so buyers can see the infrastructure price and Microsoft licensing price independently. Current Windows VM compute plans include: | vCPU | RAM | Storage | Compute price | |---:|---:|---:|---:| | 1 | 2 GB | 50 GB | **$13.99/mo** | | 2 | 2 GB | 50 GB | $17.99/mo | | 2 | 4 GB | 80 GB | $22.99/mo | | 4 | 4 GB | 80 GB | $29.99/mo | | 4 | 8 GB | 120 GB | $40.99/mo | | 8 | 8 GB | 120 GB | $54.99/mo | | 8 | 16 GB | 180 GB | $76.99/mo | | 16 | 16 GB | 200 GB | $112.99/mo | | 8 | 32 GB | 240 GB | $137.99/mo | | 16 | 32 GB | 360 GB | $174.99/mo | Add **$15/month per instance** when Raff supplies Windows Server Standard licensing through SPLA. ### Example totals | Example workload | Compute | Windows Server Standard | Starting total | |---|---:|---:|---:| | Entry Windows Server | $13.99 | $15 | **$28.99/mo** | | 2 vCPU / 4 GB | $22.99 | $15 | **$37.99/mo** | | 4 vCPU / 8 GB | $40.99 | $15 | **$55.99/mo** | | 8 vCPU / 16 GB | $76.99 | $15 | **$91.99/mo** | These totals exclude optional RDS SALs, extra volumes, snapshots/backups beyond any included free pool, and application-specific licensing. ## Windows licensing can change the final price For a production Windows VPS, the permanent licensing path is normally one of these: - **provider-supplied Windows Server licensing**, such as Raff's SPLA model; - **eligible BYOL**, where the customer's Microsoft rights permit hosted deployment under the applicable outsourcing and Flexible Virtualization Benefit terms. Raff's provider-supplied Windows Server Standard licence is **$15/month per instance**. Windows Server BYOL is not the same as License Mobility through Software Assurance. License Mobility applies to eligible server applications such as SQL Server, not to Windows Server itself. Microsoft also makes time-limited evaluation editions technically available for testing. Treat those as lab or migration-validation tools only, not as a production pricing strategy. For the full decision, see [Windows Server Licensing on Raff](/windows-server/windows-licensing). ## RDS can add per-user cost There is an important difference between administrative RDP and a real multi-user RDS environment. Two administrative Remote Desktop sessions are intended for server administration. If employees use the server as a daily shared desktop or RemoteApp platform, plan the workload as **Remote Desktop Services**. Under Raff's hosted SPLA model, RDS access uses **RDS User SALs at $8 per authorized user per month**. Example: ```text 4 vCPU / 8 GB Windows VM $40.99 Windows Server Standard SPLA $15.00 5 RDS User SALs (5 x $8) $40.00 ---------------------------------------- Starting monthly total $95.99 ``` This example is infrastructure + Windows + RDS only. Microsoft 365 Apps, SQL Server, or third-party application licensing can still be separate. For the licensing rules and the difference between customer RDS CALs and hosted SALs, see the [RDS CAL Licensing Guide](/windows-server/rds-cal-licensing-guide). ## How low-cost Windows VPS offers affect the real monthly price A low headline Windows VPS price may exclude licensing, backups, storage, RDS access, or other recurring costs. Before comparing two offers, check: | Question | Why it matters | |---|---| | Is Windows Server licensing included? | Compute-only pricing can look artificially low | | Is the rate promotional? | Renewal pricing may differ | | How much RAM is included? | Very small plans may boot Windows but not fit the workload | | Is bandwidth metered? | Egress charges can materially change total cost | | Are backups included or separate? | Production recovery needs a real plan | | Is RDS licensing included? | Multi-user desktop access is a separate licensing question | | Is support included? | Windows business workloads often need infrastructure help | A low-cost plan can be valid for a small workload. Compare the **complete recurring package**, not only the headline number. ## Windows VPS price should follow the workload A better way to budget is to start from the workload and then map it to a VM. | Workload | Practical starting point | Raff Windows total* | |---|---:|---:| | Light admin / testing | 1 vCPU / 2 GB | **$28.99/mo** | | Small business app / light remote use | 2 vCPU / 4 GB | **$37.99/mo** | | Several business users / heavier app | 4 vCPU / 8 GB | **$55.99/mo** | | Larger RDS or SQL-backed workload | 8 vCPU / 16 GB | **$91.99/mo** | | Heavy business workload | 8 vCPU / 32 GB or larger | **$152.99/mo+** | \*Includes compute plus the $15/month Windows Server Standard SPLA licence. RDS SALs and other optional services are separate. These are starting points, not guarantees. For remote-user sizing, use [Windows VPS Sizing for Remote Users](/windows-server/windows-vps-sizing-remote-users). ## RAM is often the first cost driver for business Windows workloads Windows Server itself, antivirus/EDR, user sessions, browsers, accounting software, SQL Server, and user profiles all consume memory. Typical signals that the VM is under-sized: - slow logins; - frequent paging; - frozen applications; - delayed reports; - RDP sessions that become sluggish when multiple users are active; - SQL Server and RDS competing for memory. Saving a few dollars on RAM is not useful if the server becomes the bottleneck for the whole team. ## Storage pricing has two parts: base disk and growth The base VM includes NVMe storage. Additional Raff Volumes are currently **$0.08/GiB/month**. Plan for: - Windows and updates; - application binaries; - user profiles; - shared files; - databases and transaction logs; - exports and reports; - application logs; - temporary migration data; - growth over the next 12–24 months. Do not size production storage so tightly that normal Windows Update, SQL log growth, or backup staging can fill the disk. For the current block-storage rate and included behavior, use [Raff Volumes](/products/volumes). ## Backups and snapshots belong in the real monthly budget Raff currently prices snapshot and backup storage at **$0.06/GB/month** beyond the applicable free storage pool. For production Windows workloads, budget for recovery before the server goes live. | Protection layer | Purpose | |---|---| | Snapshot | Fast rollback before risky changes | | VM backup | Restore the full server | | File backup | Restore individual files/folders | | SQL/app backup | Application-consistent recovery where needed | | Off-server copy | Separate failure/security boundary | | Restore test | Proves the recovery plan works | A 200 GB billable backup footprint at $0.06/GB/month is about **$12/month**. The actual bill depends on retained data and any included free pool. ## Bandwidth and egress can change the total Windows VPS cost Outbound transfer can materially change the real monthly Windows VPS cost when a plan meters egress separately. Raff Windows VMs use a **3 Gbps public network port with unmetered bandwidth and no VM egress fees**. That matters for: - file transfers; - remote users; - application downloads; - backups sent off-server; - website/application traffic; - migration projects. When comparing Windows VPS pricing, include bandwidth and egress charges instead of looking only at CPU and RAM. ## SQL Server cost is separate from Windows VPS cost A Windows VM does not automatically include SQL Server licensing. SQL Server can add cost through: - Standard or Enterprise licensing; - Server + CAL or Per Core model; - virtual-core minimums; - Software Assurance/subscription rights; - provider-supplied licensing where offered; - backup and storage capacity; - higher CPU/RAM requirements. For the licensing decision, use [SQL Server 2025 Licensing Guide](/windows-server/sql-server-2025-licensing-guide). ## Example Windows VPS monthly budgets ### Small Windows business app ```text 2 vCPU / 4 GB VM $22.99 Windows Server Standard SPLA $15.00 --------------------------------------- Base monthly total $37.99 ``` Add backups or extra storage based on the data footprint. ### Five-user RDS environment ```text 4 vCPU / 8 GB VM $40.99 Windows Server Standard SPLA $15.00 5 RDS User SALs $40.00 --------------------------------------- Base monthly total $95.99 ``` This does not include Microsoft 365 Apps or third-party application licensing. ### SQL-backed application VM ```text 8 vCPU / 16 GB VM $76.99 Windows Server Standard SPLA $15.00 --------------------------------------- Windows infrastructure total $91.99 ``` SQL Server licensing, database backups, and extra storage are separate decisions. ## How to compare Windows VPS pricing fairly Use this checklist: | Comparison area | Check | |---|---| | Compute price | CPU, RAM, base storage | | Windows licensing | Included, separate, or eligible BYOL | | Renewal | Same price or promotional | | Billing | Monthly mechanics and minimums | | Bandwidth | Included transfer and egress charges | | RDS | CAL/SAL model and per-user cost | | Backups | Included pool, price per GB, and retention | | Extra storage | Price per GB/GiB | | Support | Infrastructure-only or Windows-aware support | | Migration | Paid, included, or self-service | | SLA | Uptime terms | | Region | Latency to users | | Scaling | Available larger VM sizes | A slightly higher headline VM price can still produce a lower total monthly cost when licensing, bandwidth, and support are accounted for. ## When a lower-cost Windows VPS plan can fit the workload A small Windows VPS can make sense for: - testing; - lightweight administration; - small services; - one-user tools; - short migration validation; - low-resource Windows applications. Do not choose only by price for: - daily multi-user RDS; - SQL Server production workloads; - accounting/ERP systems; - business-critical file servers; - workloads with strict recovery requirements. The useful question is: **what is the least expensive configuration that safely meets the workload's requirements?** ## How Raff Windows VPS pricing is structured Raff's public Windows pricing separates the compute line from the **$15/month Windows Server Standard SPLA licence**, so the licence-inclusive entry price is **$28.99/month**. RDS User SALs, SQL Server, additional storage, and data protection are separate where the workload requires them. Raff supports **3,000+ customers** and **15,000+ VMs**, with a **99.9% SLA**. See [Windows VPS plans](/products/windows-vm) for current configurations and deployment, and use the [pricing page](/pricing) for current commercial terms. ## What's next - [Raff Windows VM](/products/windows-vm) - [Raff Pricing](/pricing) - [Windows Server Licensing on Raff](/windows-server/windows-licensing) - [Windows VPS Hosting for Small Businesses](/windows-server/windows-vps-small-business) - [Windows VPS Sizing for Remote Users](/windows-server/windows-vps-sizing-remote-users) - [RDS CAL Licensing Guide](/windows-server/rds-cal-licensing-guide) - [SQL Server 2025 Licensing Guide](/windows-server/sql-server-2025-licensing-guide) ## Sources - Raff: [Windows VM](/products/windows-vm) - Raff: [Pricing](/pricing) - Raff: [Block Storage Volumes](/products/volumes) - Microsoft: [Windows Server licensing guidance](https://www.microsoft.com/licensing/guidance/Windows-Server) - Microsoft: [Flexible Virtualization Benefit licensing guidance](https://www.microsoft.com/licensing/docs/view/Flexible-Virtualization-Benefit) - Microsoft Learn: [Remote Desktop Services licensing](https://learn.microsoft.com/en-us/windows-server/remote/remote-desktop-services/rds-client-access-license) - Sources revalidated: 2026-09-17 --- *Microsoft, Windows Server, Remote Desktop Services, and SQL Server are trademarks of Microsoft Corporation. Raff is an independent infrastructure provider and is not affiliated with, sponsored by, or endorsed by Microsoft Corporation.* --- ### Cloud vs Local Windows Server for Small Business: Office Server Replacement Guide URL: https://rafftechnologies.com/windows-server/cloud-windows-server-vs-local-office-server Description: Should a small business replace its office Windows Server with a cloud Windows Server? Compare access, apps, RDS, licensing, backups, security, migration, and fit. ## In short For a small business replacing an office server, the key decision is whether to keep Windows Server on local hardware or move the workload to a cloud-hosted Windows Server VM. Cloud hosting can fit remote access, centralized applications, and hardware-refresh scenarios, while local infrastructure can still be the better choice when LAN performance, attached devices, connectivity, or policy requires it. For Raff Technologies customers, the decision should start with the **Windows workload**, not with a generic cloud-versus-on-premises debate. Identify what the current office server actually does, who uses it, how users connect, which applications and databases depend on it, what must be backed up, and what happens if the server or office becomes unavailable. If you are comparing cloud servers and physical servers in general, use [Local Server vs Cloud Server for Small Business](/learn/guides/local-server-vs-cloud-server-small-business). This Windows Hub guide is specifically about replacing an **office Windows Server** with a hosted Windows Server VM. This guide compares the architectures. If you have already chosen cloud hosting and want to deploy, see [Windows Server hosting on Raff](/products/windows-vm). ## Cloud vs local Windows Server: when should a small business replace its office server? Use this first-pass decision matrix. ![Decision matrix showing when to choose cloud Windows Server or local office server](https://raff-images.s3.raffusercloud.com/cloud_windows_server_decision_matrix_webp_b9051a9c89.png) | Business situation | Better starting point | Why | |---|---|---| | Remote staff need the same Windows applications | Cloud Windows Server | Users can reach one centralized environment without relying on an office server being online | | Multiple offices use the same business system | Cloud Windows Server | One hosted environment can reduce branch-to-branch server duplication | | Existing office server is aging | Cloud Windows Server worth evaluating | Avoids another physical-server purchase if the workload is cloud-suitable | | Accounting, ERP, tax, or legacy Windows apps are used remotely | Cloud Windows Server after vendor review | RDS can centralize supported Windows applications and their data | | All users are on one fast LAN and remote access is rare | Local server can still fit | Local access may be simpler and independent of internet latency | | Specialized scanners, machinery, USB devices, or dongles are critical | Local or hybrid | Hardware dependencies can make hosted deployment difficult | | Internet connectivity at user locations is unreliable | Local or hybrid | Cloud access depends on a usable network path | | Business needs a fully managed personal desktop for every employee | Review managed desktop platforms | One Windows Server VM is not automatically the right end-user-computing platform | | MSP manages several customer environments | Cloud Windows Server often fits | Standardized hosted VMs can simplify repeatable operations and remote support | The answer is workload-specific. Cloud is not automatically better, and keeping a physical server is not automatically safer. :::cta Explore Windows VM Review Raff Windows VM after you know the workload, user count, storage, licensing, backup, and migration requirements. ::: ## What changes when the Windows Server leaves the office A local office server is more than Windows installed on a physical machine. The business also owns the surrounding hardware and facility responsibility. That can include: - server hardware and disks; - UPS and power protection; - cooling and physical security; - router and firewall configuration; - warranty and replacement planning; - local and off-site backups; - remote-access infrastructure; - monitoring and alerting; - Windows patching and application maintenance. Moving the Windows Server role to a cloud VM removes much of the **physical-server ownership**, but it does not remove Windows administration. ![Diagram comparing local office server responsibilities with cloud Windows Server responsibilities](https://raff-images.s3.raffusercloud.com/local_server_vs_cloud_windows_server_comparison_webp_a471fa3105.png) | Area | Local office Windows Server | Cloud Windows Server | |---|---|---| | Physical hardware | Business buys and maintains it | Cloud provider supplies the underlying infrastructure | | Office power | Server depends on local power protection | Server is not tied to office power | | Office internet | Remote users may depend on the office connection | Users connect to the hosted server from their own locations | | Windows administration | Customer/MSP responsibility | Customer/MSP responsibility | | App administration | Customer/MSP responsibility | Customer/MSP responsibility | | Scaling | Upgrade or replace hardware | Resize VM or separate roles | | Backups | Design local and off-site copies | Design VM, file, database, and off-server recovery | | Remote access | Often added to an existing LAN design | Can be designed around remote access from the start | | Hardware replacement | Periodic refresh required | No customer-owned server refresh cycle | The main operational shift is simple: the server becomes independent of one office location, while the guest Windows environment and applications still need an owner. ## When moving an office Windows Server to the cloud is the better fit A cloud Windows Server is strongest when the business problem is tied to **location, remote access, centralized applications, or hardware lifecycle**. ### Remote users need the same environment If employees work from home, branch offices, client sites, or while traveling, a hosted Windows Server can give them one central application environment. This is especially useful for supported workloads such as: - accounting software; - ERP and inventory applications; - line-of-business Windows software; - SQL-backed desktop applications; - IIS and ASP.NET applications; - administrative tools; - Windows services and scheduled automation; - RDS Session Host deployments. For application-specific planning, use [Windows VPS for Business Software](/windows-server/windows-vps-for-business-software). ### The current server is due for replacement A hardware refresh is a natural decision point. Before buying another server, compare the cost and operational requirements of rebuilding the same Windows role in a hosted VM. Do not compare only the purchase price of the physical server with one month of cloud compute. Compare the full lifecycle, including support, backup, power, warranty, remote access, downtime exposure, and eventual replacement. ### Several locations depend on one system A hosted Windows Server can remove the need to make one branch office the infrastructure center for every other office. Users still need reliable internet, but the workload no longer depends on the headquarters router, power supply, or server closet being available. ### The MSP wants a repeatable server model For an MSP, hosted Windows VMs can make server access, documentation, backup policy, patching, and replacement more standardized across customers. The MSP still needs to design tenant separation, credentials, security, backups, and licensing correctly. ## When keeping a local Windows Server is better Some workloads should stay local unless the underlying dependency changes. ### The workload depends on local hardware Examples include: - industrial equipment; - specialist scanners; - USB licence dongles; - serial devices; - local label or production hardware; - software that the vendor supports only with a local hardware topology. Remote redirection can solve some device requirements, but it should be tested before migration. Do not assume that a device working on an office PC will behave correctly inside RDS. ### Most work is LAN-only If all users work in one office and continuously access very large local files, a fast LAN can be more practical than moving those workflows across the internet. ### Internet continuity is weak A cloud Windows Server can keep running through an office outage, but users still need a working internet path to reach it. If the business has unreliable connectivity and no secondary connection, moving a critical LAN workload to cloud infrastructure may create a different availability problem. ### Policy or architecture requires local infrastructure Some environments need on-premises systems because of contractual, operational, regulatory, latency, or integration requirements. Those cases may call for local or hybrid architecture rather than a single cloud VM. ## Cost: compare the complete server role, not one bill The cloud server has an obvious monthly bill. A local server often spreads its cost across several budgets and years. ![Visual showing local office server hidden costs compared with cloud Windows Server monthly infrastructure costs](https://raff-images.s3.raffusercloud.com/office_server_cost_risk_stack_webp_f9e085f294.png) For a realistic comparison, include: | Cost area | Local server | Cloud Windows Server | |---|---|---| | Server hardware | Upfront purchase | Included in provider infrastructure | | Hardware refresh | New purchase every lifecycle | Resize or replace VM without buying hardware | | Power and UPS | Business pays and maintains | Not a customer server-room expense | | Windows licence | Depends on customer licensing | Provider licensing or eligible BYOL, depending on model | | RDS access | Customer licensing where RDS is used | Hosted provider model or eligible customer licensing, depending on deployment | | Backup | Hardware/software/off-site destination | VM and application backup services still need to be budgeted | | IT labor | Hardware plus Windows/app administration | Windows/app administration remains, hardware work is reduced | | Downtime exposure | Hardware, office power, office network | Provider/platform plus user network and guest workload dependencies | | Expansion | New components or server | VM resize or role separation | The goal is not to prove that one model is always cheaper. It is to calculate the cost of delivering the same business outcome. Use [Raff Pricing](/pricing) for current infrastructure pricing after you know the CPU, RAM, storage, backup, and licensing requirements. Avoid making the migration decision from an old hard-coded price example. ## Remote access: admin RDP and employee access are different Windows Server supports Remote Desktop for administration, but a team using the server as a daily shared workspace is an **RDS** use case. Use this distinction: | Need | Typical access model | |---|---| | One or two administrators manage the server | Restricted administrative RDP | | Several staff need full Windows desktop sessions | RD Session Host | | Staff need individual hosted applications | RemoteApp through RDS | | Users connect from external networks | Consider RD Gateway or another controlled access layer | | Users only consume an IIS application | HTTPS, not a full desktop session | | Local PCs connect to a database service | Database access, not RDS solely because Windows Server is used | Microsoft documents Remote Desktop Services as the Windows Server platform for session-based desktops and RemoteApp delivery. RD Gateway can provide RDP access over HTTPS so protected session hosts do not need to expose RDP directly to every external client. Before moving users, review [Multi-User RDP vs RDS Session Host](/windows-server/multi-user-rdp-vs-rds), [RDS Licensing Guide](/windows-server/rds-cal-licensing-guide), and [Remote Desktop Gateway vs Direct RDP](/windows-server/remote-desktop-gateway-vs-direct-rdp). ## Licensing: Raff SPLA and eligible customer BYOL are different paths A hosted Windows Server needs a valid production licensing model. For Raff deployments, there are two broad paths: 1. **Raff-provided Microsoft SPLA licensing** for hosted Windows Server workloads. 2. **Eligible customer BYOL** where the customer's Microsoft agreement and outsourcing rights permit it. Do not treat an Evaluation edition as the normal production licensing path. For Remote Desktop Services, the access model also differs by licensing path. Customer-owned Microsoft deployments use the applicable Windows Server and RDS CAL model. Raff-hosted SPLA deployments use the applicable service-provider licensing model, including RDS User SALs when RDS is consumed. Windows Server BYOL on third-party infrastructure should not be explained as ordinary License Mobility. Review the customer's qualifying Microsoft rights, including the applicable outsourcing and Flexible Virtualization rules. Use [Windows Server Licensing on Raff](/windows-server/windows-licensing) for the current licensing model and pricing instead of relying on static figures in this comparison. ## Business applications need vendor approval before migration A cloud Windows Server can centralize business software, but the VM being technically capable of running the installer does not prove the deployment is supported. Before moving an application, confirm: - supported Windows Server versions; - support for hosted or virtualized deployment; - RDS or multi-user support; - application licence transfer rules; - database version requirements; - Office or PDF integration; - printers and scanners; - service accounts; - scheduled tasks; - file paths and mapped drives; - backup method; - vendor support boundaries. Windows Server 2025 is Microsoft's current LTSC Windows Server release, but the application vendor should determine whether a production workload moves to 2025, remains on 2022, or needs another supported version. Use [Windows Server Version Comparison](/windows-server/windows-server-version-comparison) for the operating-system decision after checking the software support matrix. ## SQL Server can change the architecture A small line-of-business app may place the application, RDS users, and SQL Server on one VM. That can be reasonable for a modest workload, but all three layers then compete for the same CPU, RAM, and storage. Watch for: - SQL Server consuming most available memory; - reporting workloads creating CPU spikes; - database and backup jobs competing for storage I/O; - RDS users creating additional memory pressure; - application and database growth exceeding the original VM design. As the workload grows, separating the application/RDS tier from SQL Server can make capacity, maintenance, and troubleshooting easier. For SQL-backed workloads, use [SQL Server Max Server Memory](/windows-server/mssql-memory-tuning), [SQL Server Backup Strategy](/windows-server/mssql-backup-strategy), and [Windows Server Performance Monitoring](/windows-server/windows-server-performance-monitoring). ## File shares, printers, and devices require special attention An office server often becomes a file server almost by accident. Before replacing it, inventory: - SMB shares; - NTFS permissions; - mapped drives; - large-file workflows; - application data stored on shares; - user home folders; - printers and print drivers; - label printers; - scanners; - scheduled exports; - UNC paths embedded in applications. A cloud Windows Server can host files, but directly stretching SMB across the public internet is not a sensible default. Use a controlled access architecture, such as users working inside the hosted environment, VPN/private connectivity, or another supported file-access pattern. If files are the primary workload, use [Local Office Server to Cloud Windows VPS Migration](/windows-server/local-server-to-cloud-windows-vps-migration) for the detailed migration workflow. ## Backup and recovery must be designed before cutover Moving the VM does not solve backup by itself. A production Windows Server may need several recovery layers: 1. **VM-level recovery** for the operating system and whole-server state. 2. **File-level backup** for user and business files. 3. **Application-aware backup** for supported business applications. 4. **Database-aware backup** for SQL Server or another database engine. 5. **Off-server recovery copies** outside the live VM. 6. **Restore testing** that proves the business can recover. Snapshots are useful before risky changes, but snapshots should not be treated as a complete replacement for application-aware backups and independent recovery copies. Define the business target first: - **RPO**: how much recent data can be lost? - **RTO**: how long can the server remain unavailable? Then design backup frequency, retention, and restore testing around those targets. ## Security improves only if the access design improves A cloud Windows Server is not secure simply because the physical data-center layer is no longer in the office. The guest operating system still needs: - named administrator accounts; - least privilege; - Windows Firewall; - current security updates; - Microsoft Defender or another supported endpoint-security stack; - controlled RDP/RDS access; - account offboarding; - audit logging; - protected backup credentials; - monitoring for failed logons and service failures. Avoid publishing RDP, SMB, SQL Server, or management ports broadly to the internet merely because users need remote access. Use the [Windows Server Hardening Checklist](/windows-server/windows-server-hardening-checklist) before production and compare [Remote Desktop Gateway vs Direct RDP](/windows-server/remote-desktop-gateway-vs-direct-rdp) when multiple users need external desktop access. ## Migration is safer when the old server stays available during testing For many small businesses, **side-by-side migration** provides a cleaner path than changing the existing office server in place. A practical sequence is: ```text Inventory old Windows Server -> identify apps, files, roles, users and licences -> choose destination architecture -> build cloud Windows Server -> patch and harden it -> configure backup and monitoring -> install supported applications -> restore or copy test data -> test real user workflows -> schedule cutover -> freeze source writes -> run final sync / database restore -> switch users -> validate production -> retain rollback until sign-off ``` Do not remove the old server after the first successful administrator login. Keep the rollback path until application owners and business users have validated the new environment. For the complete control list, use [Server Migration Checklist for Windows Server](/windows-server/windows-server-migration-checklist-small-business). ## How Raff fits an office-server replacement Raff provides the hosted Windows VM infrastructure for small businesses and MSPs that want to move supported Windows workloads away from a physical office server. A Raff Windows VM can be the destination for workloads such as: - Remote Desktop administration; - self-managed RDS environments; - supported accounting and ERP applications; - IIS and ASP.NET workloads; - SQL Server-backed applications; - line-of-business Windows software; - Windows services and scheduled automation; - office-server migration projects. Raff Windows VMs provide a cloud Windows Server environment with administrator access, RDP access, NVMe-backed storage, private networking options, backup/snapshot options, and current Windows Server images. Raff does not replace application-vendor support, guest Windows administration, licensing review, backup design, or migration testing. Those still belong to the customer, MSP, or a separately managed service. :::cta Talk to Windows Engineer Review your current office server roles, users, apps, storage, RDS model, licensing, and recovery requirements before choosing the destination VM. ::: ## Office server replacement checklist Before deciding to move, answer these questions: - [ ] What Windows Server roles run today? - [ ] Which applications are business-critical? - [ ] Does each vendor support a hosted Windows Server deployment? - [ ] How many users are active concurrently? - [ ] Do staff need administrative RDP or RDS user sessions? - [ ] Which Microsoft licensing path applies? - [ ] Does SQL Server share the same server? - [ ] What file shares and permissions must move? - [ ] Are printers, scanners, USB devices, or hardware dongles involved? - [ ] Is internet connectivity reliable at the user locations? - [ ] What are the RPO and RTO targets? - [ ] Is there an off-server backup and a restore test? - [ ] Can the new server be tested alongside the old one? - [ ] What triggers rollback during cutover? - [ ] Who owns Windows updates, security, backups, and monitoring after migration? If several answers are unknown, inventory the current server before selecting a VM plan. :::cta Deploy Windows Now When the workload and migration plan are clear, deploy a Raff Windows VM and validate the environment before production cutover. ::: ## Validation scope This article was revalidated on **September 11, 2026** against current Microsoft Windows Server and Remote Desktop Services documentation. Windows Server 2025 was confirmed as the current LTSC Windows Server release, and current RDS guidance was rechecked for Session Host, User/Device CALs, and RD Gateway architecture. The three existing article visuals were preserved. This refresh does **not** claim a new physical-versus-cloud cost benchmark, a new office-server migration lab, or a universal savings percentage. Local-server costs, application behavior, user connectivity, licensing, and recovery requirements vary by environment. ## What's next - [Windows Server hosting on Raff](/products/windows-vm) - review the hosted Windows platform after defining the workload. - [Raff Pricing](/pricing) - check current compute, storage, backup, and licensing pricing. - [Windows Server Licensing](/windows-server/windows-licensing) - choose between Raff SPLA and eligible customer BYOL. - [Windows VPS Sizing for Remote Users](/windows-server/windows-vps-sizing-remote-users) - size CPU and RAM by concurrency and application load. - [Windows VPS for Business Software](/windows-server/windows-vps-for-business-software) - validate the application-hosting architecture. - [Windows VPS for Remote Desktop](/windows-server/windows-vps-for-remote-desktop) - plan remote administration or user access. - [Local Office Server to Cloud Windows VPS Migration](/windows-server/local-server-to-cloud-windows-vps-migration) - execute the move after the decision is made. - [Server Migration Checklist](/windows-server/windows-server-migration-checklist-small-business) - plan test, cutover, rollback, and validation. - [Windows Server Hardening Checklist](/windows-server/windows-server-hardening-checklist) - secure the destination before production. - [Local Server vs Cloud Server for Small Business](/learn/guides/local-server-vs-cloud-server-small-business) - compare cloud and physical servers at the broader infrastructure level. ## Sources - Microsoft Learn - Windows Server release information: https://learn.microsoft.com/en-us/windows/release-health/windows-server-release-info - Microsoft Lifecycle - Windows Server 2025: https://learn.microsoft.com/en-us/lifecycle/products/windows-server-2025 - Microsoft Learn - Remote Desktop Services overview: https://learn.microsoft.com/en-us/windows-server/remote/remote-desktop-services/overview - Microsoft Learn - RDS Client Access Licenses: https://learn.microsoft.com/en-us/windows-server/remote/remote-desktop-services/rds-client-access-license - Microsoft Learn - Remote Desktop Gateway: https://learn.microsoft.com/en-us/windows-server/remote/remote-desktop-services/remote-desktop-gateway-role - Sources revalidated: 2026-09-11 --- ### Add MFA to Remote Desktop Services on Windows Server 2025 URL: https://rafftechnologies.com/windows-server/add-mfa-remote-desktop-services-windows-server Description: Learn how to add MFA to Remote Desktop Services on Windows Server 2025 using RD Gateway, RADIUS authentication, Microsoft Entra MFA, and identity-based protection for secure remote access. ## In short Adding MFA to Remote Desktop Services protects Windows Server access even when passwords are compromised. A production RDS design should combine Remote Desktop Gateway, a RADIUS-based MFA provider, and controlled user access instead of relying only on passwords. This guide explains the MFA architecture behind Windows Server 2025 RDS environments and how administrators should approach identity protection for remote desktop access. ## Why MFA matters for Remote Desktop Services Remote Desktop access is a common target because it provides direct access to business systems. Password-only protection creates risk when credentials are stolen, reused, or exposed. MFA adds another verification step before users receive access. Common risks MFA helps reduce: - stolen password usage; - unauthorized remote access; - compromised administrator accounts; - credential replay attacks. ## MFA architecture for RDS A common production architecture looks like this: ![MFA architecture for Remote Desktop Services on Windows Server 2025 showing the authentication flow from user and Remote Desktop Client through RD Gateway, RADIUS MFA provider, Connection Broker, and Session Host](https://raff-images.s3.raffusercloud.com/mfa_architecture_rds_windows_server_2025_png_2_adf1c8e7ce.png) MFA is normally added at the RD Gateway layer rather than directly exposing Session Hosts to the internet. The authentication flow is: 1. User starts a Remote Desktop connection. 2. RD Gateway receives the request. 3. RADIUS forwards authentication to the MFA provider. 4. The user completes the second verification step. 5. Connection Broker connects the user to the correct Session Host. ## Prerequisites before adding MFA Before configuring MFA, confirm: - Windows Server 2025 RDS deployment is working; - RD Gateway is installed or planned; - Active Directory users are available; - certificates and DNS are configured correctly; - the MFA provider supports RADIUS integration. Start with [Remote Desktop Services Configuration on Windows Server 2025](/windows-server/remote-desktop-services-configuration) if the RDS environment is not deployed yet. ## Choosing an MFA approach for RDS Common options include: ### Microsoft Entra MFA Microsoft Entra MFA can integrate with RDS through Network Policy Server and the MFA extension. This approach fits organizations already using Microsoft identity services. ### RADIUS-based MFA providers Many enterprise MFA platforms support RADIUS authentication. This allows RD Gateway to request additional verification before allowing access. Choose the approach that matches your existing identity platform and operational requirements. ## Configure the MFA authentication workflow The general deployment process is: 1. Install Network Policy Server. 2. Configure RD Gateway authentication through RADIUS. 3. Connect the MFA provider. 4. Register or enroll users. 5. Apply the correct access policies. 6. Test a real user login. Keep administrative recovery access documented before enabling MFA for production users. ## Testing MFA login A successful test should follow this flow: 1. User opens Remote Desktop. 2. User connects through RD Gateway. 3. Username and password are entered. 4. MFA approval is requested. 5. User completes verification. 6. Windows session starts. Test with a normal user account before enabling the policy for all users. ## Troubleshooting MFA for RDS ### MFA prompt does not appear Check: - RD Gateway configuration; - NPS policies; - RADIUS communication; - user enrollment status. ### Authentication times out Review: - firewall rules; - RADIUS ports; - certificates; - network connectivity. ### Some users cannot connect Verify: - Active Directory group membership; - MFA enrollment; - identity policies; - user permissions. ## Direct RDP vs MFA-enabled RDS access | Scenario | Recommended approach | |---|---| | Single administrator | Secured direct RDP | | Multiple users | RDS with MFA | | External employees | RD Gateway + MFA | | Business-critical workloads | Managed Windows infrastructure | MFA becomes increasingly important as the number of users and workloads grows. ## Choosing a secure Windows VPS provider MFA protects identity, but the infrastructure running the workload also matters. For business Windows workloads, consider: - Windows Server expertise; - recovery options; - scalable VM resources; - operational support when access problems happen. A secure Windows VPS combines reliable infrastructure with strong access controls. ## Final MFA checklist - [ ] RD Gateway architecture planned - [ ] RADIUS authentication working - [ ] MFA provider connected - [ ] Users enrolled in MFA - [ ] MFA login tested - [ ] Recovery access documented - [ ] Authentication monitoring enabled ## What's next - [RDP VPS](/products/remote-desktop-vps) — review hosted RDP infrastructure after defining MFA. - [Secure Direct RDP on a Windows VPS](/windows-server/secure-direct-rdp-windows-vps) - [Remote Desktop Services Configuration on Windows Server 2025](/windows-server/remote-desktop-services-configuration) - Deploy Remote Desktop Gateway on Windows Server 2025 --- ### Deploy Remote Desktop Gateway on Windows Server 2025 URL: https://rafftechnologies.com/windows-server/deploy-remote-desktop-gateway-windows-server-2025 Description: Learn how to deploy Remote Desktop Gateway on Windows Server 2025 to secure external RDP access using HTTPS, authorization policies, certificates, and controlled remote desktop connectivity. ## In short Remote Desktop Gateway (RD Gateway) provides a secure way to access Remote Desktop Services from outside the network without exposing internal Session Hosts directly to the internet. It uses HTTPS-based communication, access policies, and certificate-based security to control remote desktop access. This guide explains the role of RD Gateway, its architecture, prerequisites, deployment approach, and how it fits into a secure Windows Server remote access strategy. ## Why use Remote Desktop Gateway? Directly exposing Remote Desktop Protocol (RDP) access to the internet creates unnecessary risk. A public Session Host can become a target for password attacks and unauthorized access attempts. RD Gateway creates a controlled access layer between external users and internal RDS servers. Without RD Gateway: ```text Remote User ↓ Internet ↓ Session Host ``` With RD Gateway: ```text Remote User ↓ HTTPS (443) ↓ RD Gateway ↓ Internal RDS Servers ``` The gateway becomes the secure entry point for remote desktop connections. ## RD Gateway architecture A typical production architecture looks like this: ```text Remote Desktop Client ↓ HTTPS 443 ↓ RD Gateway ↓ Connection Broker ↓ Session Host ``` RD Gateway is commonly combined with MFA to add identity protection before users reach internal Windows workloads. Related: - Secure Direct RDP on a Windows VPS - Add MFA to Remote Desktop Services on Windows Server 2025 ## Prerequisites before deployment Before installing RD Gateway, prepare: - Windows Server 2025 server; - Remote Desktop Services environment; - public DNS record; - valid SSL certificate; - firewall access for HTTPS; - user and resource authorization plan. A production deployment should avoid exposing Session Hosts directly to the public internet. ## Install the Remote Desktop Gateway role ![Windows Server 2025 Add Roles and Features wizard showing Remote Desktop Gateway selected under Remote Desktop Services role services](https://raff-images.s3.raffusercloud.com/01_install_rd_gateway_role_windows_server_2025_png_77a8748097.png) **Alt text:** Windows Server 2025 Add Roles and Features wizard showing Remote Desktop Gateway selected under Remote Desktop Services role services RD Gateway is installed through Windows Server roles. General workflow: 1. Open Server Manager. 2. Add Remote Desktop Services roles. 3. Select Remote Desktop Gateway. 4. Complete the role installation. 5. Configure the gateway with the required certificate and policies. ## Configure RD Gateway policies ![Windows Server RD Gateway Manager showing gateway status, connection authorization policies, and resource authorization policies configuration areas](https://raff-images.s3.raffusercloud.com/02_rd_gateway_manager_overview_0ce9b94b80.png) **Alt text:** Windows Server RD Gateway Manager showing gateway status, connection authorization policies, and resource authorization policies configuration areas RD Gateway uses two important policy types: ### Connection Authorization Policies (CAP) ![Windows Server RD Gateway Connection Authorization Policy showing authentication requirements and allowed user groups for remote access](https://raff-images.s3.raffusercloud.com/03_rd_gateway_connection_authorization_policy_248b7733ae.png) **Alt text:** Windows Server RD Gateway Connection Authorization Policy showing authentication requirements and allowed user groups for remote access CAP controls who is allowed to connect through the gateway. Examples: - administrators only; - specific Active Directory groups; - approved remote users. ### Resource Authorization Policies (RAP) ![Windows Server RD Gateway Resource Authorization Policy showing allowed user groups, RDS Session Hosts, and permitted RDP ports](https://raff-images.s3.raffusercloud.com/04_rd_gateway_resource_authorization_policy_rap_png_5050925d20.png) **Alt text:** Windows Server RD Gateway Resource Authorization Policy showing allowed user groups, RDS Session Hosts, and permitted RDP ports RAP controls which internal resources users can access after authentication. Examples: - specific Session Hosts; - specific server groups; - approved internal networks. Together, CAP and RAP provide controlled access management. ## Configure SSL certificates RD Gateway uses HTTPS communication, which requires a trusted certificate. Important considerations: - certificate name should match the public DNS name; - certificates should come from a trusted certificate authority; - certificates should be renewed before expiration. Certificate problems are one of the most common causes of RD Gateway connection failures. ## Firewall requirements The main external requirement is: ```text TCP 443 HTTPS ``` Avoid exposing: ```text TCP 3389 RDP ``` directly to the public internet when using RD Gateway. The firewall design should allow users to reach the gateway while keeping internal Session Hosts protected. ## Testing RD Gateway access A successful test should confirm: 1. Remote Desktop Client is configured to use the gateway. 2. User authenticates successfully. 3. Gateway accepts the connection. 4. User reaches the assigned Session Host. Test using a normal user account before enabling access for all users. ## Troubleshooting RD Gateway ### Certificate errors Check: - certificate name; - certificate trust chain; - expiration date; - gateway configuration. ### Users cannot connect Review: - CAP policies; - RAP policies; - Active Directory permissions; - network connectivity. ### Gateway works internally but not externally Check: - DNS configuration; - firewall rules; - public certificate configuration; - HTTPS availability. ## RD Gateway with MFA For production environments, RD Gateway is commonly combined with MFA. The recommended flow: ```text User ↓ RD Gateway ↓ MFA Provider ↓ Connection Broker ↓ Session Host ``` This prevents a stolen password from being enough to access Windows workloads. ## Choosing a secure Windows VPS provider RD Gateway protects remote access, but the underlying infrastructure still matters. For business Windows workloads, consider: - reliable Windows Server infrastructure; - recovery options; - scalable resources; - operational support when remote access problems occur. A secure Windows environment requires both strong access controls and dependable infrastructure. ## Final RD Gateway checklist - [ ] RD Gateway installed - [ ] Public DNS configured - [ ] SSL certificate installed - [ ] CAP policies configured - [ ] RAP policies configured - [ ] HTTPS firewall access enabled - [ ] Direct public RDP exposure removed - [ ] MFA considered for production access ## What's next - [hosted Remote Desktop](/products/remote-desktop-vps) — review the hosted Remote Desktop product path after planning RD Gateway. - Secure Direct RDP on a Windows VPS - Add MFA to Remote Desktop Services on Windows Server 2025 - Publish RemoteApp and Remote Desktop Web Client --- ### Shared Computer Activation for Microsoft 365 Apps on RDS URL: https://rafftechnologies.com/windows-server/m365-apps-sca Description: Set up Shared Computer Activation for Microsoft 365 Apps on Windows Server RDS, choose an eligible Microsoft 365 plan, configure ODT, verify SCA, and troubleshoot user activation and profile issues. Shared Computer Activation (SCA) is the Microsoft 365 Apps licensing mode designed for computers that are shared by multiple users. On a Windows Server Remote Desktop Session Host, it lets Office be installed once while each RDS user activates Word, Excel, Outlook, and other Microsoft 365 Apps with their own eligible Microsoft 365 account. For a typical RDS deployment, the licensing stack is: ```text Windows Server / RDS host + Microsoft 365 Apps installed with Office Deployment Tool + SharedComputerLicensing = 1 + Eligible Microsoft 365 license for each user + RDS access licensing ``` The most important 2026 change is Windows Server support. Microsoft now explicitly supports **Microsoft 365 Apps on Windows Server 2025 while Windows Server 2025 remains in Mainstream Support, through October 2029**. Windows Server 2022 remains supported only through October 2026, although Microsoft says security updates for Microsoft 365 desktop apps on Windows Server 2022 will continue through **October 10, 2028** while customers migrate. That makes Windows Server 2025 the stronger starting point for a new Microsoft 365 Apps + RDS deployment in 2026, assuming the rest of your application stack is compatible. ## In short Use Shared Computer Activation when multiple users sign in to the same RDS host and run Microsoft 365 Apps. Install Office with the Office Deployment Tool, set `SharedComputerLicensing` to `1`, assign each user an eligible Microsoft 365 license, and license RDS access separately. | Question | Current answer | |---|---| | Does Windows Server 2025 support Microsoft 365 Apps? | Yes. Microsoft lists support through October 2029 while Server 2025 is in Mainstream Support. | | Does Windows Server 2022 support Microsoft 365 Apps? | Yes, through October 2026; security updates continue through October 10, 2028. | | Is SCA required for a shared RDS host? | Yes, for Microsoft 365 Apps when multiple users share the computer. | | Can Microsoft 365 Business Premium use SCA? | Yes. SCA is a Business Premium entitlement. | | Does Microsoft 365 Business Standard include SCA? | No. | | Does Microsoft 365 licensing replace RDS licensing? | No. They cover different rights. | | Should every user share one Microsoft 365 account? | No. Each user should have their own account and eligible license. | ## What is Shared Computer Activation? Shared Computer Activation is a licensing mode for Microsoft 365 Apps on devices used by multiple people. It is commonly used for: - Remote Desktop Services Session Hosts; - shared Windows computers; - pooled or shared virtual desktops; - call centers and shift-worker environments; - MSP-managed application servers; - business-software servers where users also need Word, Excel, or Outlook. Without SCA, Microsoft 365 Apps activation follows the normal per-user device model. That is appropriate when a user has their own PC, but it is not the right model when many people sign in to one RDS server. With SCA enabled: 1. Microsoft 365 Apps is installed once on the shared computer. 2. User A signs in to Windows and opens an Office app. 3. Microsoft checks User A's eligible Microsoft 365 license. 4. A licensing token is stored in User A's profile. 5. User B signs in separately and receives their own activation state. One user's activation does not activate Office for the entire server. ## Windows Server 2025 vs 2022 for Microsoft 365 Apps Microsoft's current support guidance changes the recommendation for new RDS deployments. | Windows Server version | Microsoft 365 Apps status in September 2026 | |---|---| | Windows Server 2025 | Supported while in Mainstream Support, through October 2029 | | Windows Server 2022 | Supported through October 2026 | | Windows Server 2019 | Main support for Microsoft 365 Apps ended October 14, 2025 | | Windows Server 2016 | Main support for Microsoft 365 Apps ended October 14, 2025 | Microsoft also provides an extended security-update runway for Microsoft 365 desktop apps on Windows Server 2022, 2019, and 2016 through October 10, 2028. That does not make those older combinations equivalent to a currently supported new deployment. For a new environment in late 2026, prefer Windows Server 2025 unless a required application, driver, add-in, or vendor certification still requires Server 2022. If you are maintaining an existing Server 2022 RDS host, build a migration plan rather than treating the October 2026 date as an immediate shutdown date. ## Which Microsoft 365 plans support SCA? Microsoft's current RDS deployment guidance lists these common qualifying paths: - a Microsoft 365 or Office 365 plan that includes **Microsoft 365 Apps for enterprise**; - **Microsoft 365 Business Premium**, which includes Microsoft 365 Apps for business and the SCA entitlement; - supported Project or Visio subscription plans for those desktop apps. A critical distinction is Business Premium versus Apps for business generally. Microsoft explicitly states that the ability to enable Shared Computer Activation is a **Microsoft 365 Business Premium entitlement**, not a general feature of Microsoft 365 Apps for business. A practical planning table: | Plan / entitlement | SCA on shared RDS host | |---|---:| | Microsoft 365 Apps for enterprise | Yes | | Office 365 E3 / E5 with Apps for enterprise | Yes | | Microsoft 365 E3 / E5 with Apps for enterprise | Yes | | Microsoft 365 Business Premium | Yes | | Microsoft 365 Business Standard | No SCA entitlement | | Microsoft 365 Business Basic | No desktop Microsoft 365 Apps | | Microsoft 365 Personal / Family | Not appropriate for this business RDS scenario | Always verify the exact tenant SKU and current Microsoft licensing terms before production. ## Microsoft 365 license vs RDS license Microsoft 365 licensing and Remote Desktop licensing solve different problems. | Component | What it covers | |---|---| | Microsoft 365 Apps entitlement | The user's right to run Word, Excel, Outlook, PowerPoint, and related apps | | RDS access licensing | The user's or device's right to use a Windows Server RDS deployment | | Windows Server license | The server operating-system licensing | | Raff Windows VM | The cloud infrastructure hosting the Windows Server workload | For a typical multi-user hosted environment, think in layers: ```text Microsoft 365 Apps license ≠ Windows Server license ≠ RDS CAL / hosted RDS SAL ``` For Raff-hosted SPLA environments, RDS access uses the hosted-provider licensing model and is handled separately from Microsoft 365 Apps licensing. For customer-owned licensing environments, follow the applicable Microsoft CAL terms. See [RDS CAL Licensing on Windows Server](/windows-server/rds-cal-licensing-guide) and [Microsoft SPLA Licensing Explained](/learn/guides/microsoft-spla-hosted-windows-vms) for the distinction. ## What you will build A straightforward design looks like this: ```text Remote users ↓ RDP / RDS Session Host ↓ Windows Server 2025 or supported alternative ├── Microsoft 365 Apps installed once ├── SharedComputerLicensing = 1 ├── Per-user Microsoft 365 activation ├── User profiles / profile containers └── Internet access to Microsoft licensing services ``` Each user signs in to Windows and Microsoft 365 separately with their own identity. ## Prerequisites Before you install Microsoft 365 Apps, confirm: - a Windows Server version supported by Microsoft 365 Apps; - RDS Session Host if multiple users will use server-based sessions; - an eligible Microsoft 365 license assigned to each user; - RDS licensing planned separately; - local Administrator access for installation; - Office Deployment Tool (ODT); - reliable outbound internet access; - a profile strategy, especially if Outlook is used; - backups or a snapshot before changing an existing production host. Do not install Office first and solve licensing later. For RDS, the OS support lifecycle, user licensing, RDS licensing, and profile design should be decided before production. ## Step 1 — Prepare the RDS host Start with a clean, updated Windows Server environment. 1. Confirm the Windows Server version against Microsoft's current Microsoft 365 Apps support matrix. 2. Install Windows updates. 3. Reboot. 4. Install and configure RDS Session Host if required. 5. Confirm intended users can sign in through the approved RDP/RDS path. 6. Confirm each user has an eligible Microsoft 365 license. 7. Confirm outbound access to Microsoft licensing services. 8. Remove or account for incompatible legacy Office installations. 9. Decide how user profiles and Outlook data will persist. For a new 2026 deployment, Windows Server 2025 is now the preferred lifecycle starting point for this workload. ## Step 2 — Download the Office Deployment Tool Download the Office Deployment Tool from Microsoft and create a working folder: ```powershell New-Item -ItemType Directory -Path "C:\ODT" -Force ``` Extract the ODT files into: ```text C:\ODT ``` The folder should contain `setup.exe` plus your configuration XML. ## Step 3 — Choose the correct Office product ID Use the product ID that matches the user's Microsoft 365 entitlement. For Microsoft 365 Apps for enterprise: ```xml ``` For Microsoft 365 Business Premium's Apps for business installation: ```xml ``` This distinction matters because the installed product must align with the user's licensing entitlement. ## Step 4 — Create configuration.xml with SCA enabled Create: ```text C:\ODT\configuration.xml ``` ### Example: Microsoft 365 Apps for enterprise ```xml ``` ### Example: Microsoft 365 Business Premium ```xml ``` The key setting is: ```xml ``` Microsoft's current RDS deployment documentation specifically requires Shared Computer Activation for a shared RDS installation. ## Step 5 — Decide whether to install OneDrive Do not automatically remove or install OneDrive without considering the RDS profile design. On a simple RDS host, OneDrive can increase profile and disk usage. In larger deployments it can still be appropriate, but it should be planned around: - profile containers; - storage capacity; - Files On-Demand behavior; - tenant policies; - user logon/logoff patterns; - backup expectations. If you do not need OneDrive on the session host, exclude it in ODT. If users do need it, test it under the actual profile strategy. ## Step 6 — Download and install Microsoft 365 Apps Open PowerShell as Administrator: ```powershell cd C:\ODT .\setup.exe /download configuration.xml ``` Then install: ```powershell .\setup.exe /configure configuration.xml ``` If the XML uses `Display Level="None"`, setup runs without a normal interactive installer window. ## Step 7 — Verify Shared Computer Activation After installation, confirm the Click-to-Run configuration: ```powershell $key = 'HKLM:\SOFTWARE\Microsoft\Office\ClickToRun\Configuration' (Get-ItemProperty -Path $key).SharedComputerLicensing ``` Expected result: ```text 1 ``` If the value is missing or `0`, SCA is not enabled correctly. Correct the ODT configuration or use a Microsoft-supported policy/configuration method before user testing. ## Step 8 — Test with two real non-admin users Do not validate the deployment only as Administrator. Test User A: 1. Sign in to the RDS host. 2. Open Word. 3. Sign in with the user's Microsoft 365 work account. 4. Open **File → Account** and confirm the user is licensed. 5. Create, edit, and save a document. Then repeat with User B in a separate session. The success criterion is not simply “Office opens.” Both users should activate independently and retain their own identity and profile state. ## Step 9 — Understand SCA licensing tokens SCA activation information is stored per user and needs periodic renewal from Microsoft's licensing services. On traditional profile configurations, Office licensing data is associated with the user's profile. Reliable internet access is therefore a licensing requirement, not merely an installation convenience. If profiles are deleted or reset at logoff, users may be prompted to activate repeatedly. That is usually a profile-persistence problem rather than an Office binary problem. ## Step 10 — Plan profiles and Outlook carefully Outlook is usually the most demanding part of Microsoft 365 Apps on RDS because the user environment can include: - Outlook profiles; - OST cache data; - signatures; - add-ins; - search indexes; - shared mailboxes; - Microsoft identity tokens; - Teams or browser integration. Common profile approaches include persistent local profiles and profile-container technologies such as FSLogix. The correct choice depends on whether the RDS host is persistent, whether users can move between hosts, and how much Outlook cache data must be retained. For a production RDS farm, profile design should be treated as architecture, not as an afterthought. ## Step 11 — Grant RDS access through groups For a standalone host, users typically receive access through the appropriate Remote Desktop Users / RDS security configuration. Example: ```powershell Add-LocalGroupMember -Group "Remote Desktop Users" -Member "DOMAIN\jane.doe" ``` In a domain, prefer a dedicated group such as: ```text RDS-Office-Users ``` Then manage membership centrally instead of adding users individually on each server. ## Step 12 — Verify every user's license assignment Before troubleshooting an Office activation error, check the Microsoft 365 admin center for the affected user: - correct license SKU assigned; - Microsoft 365 Apps service enabled; - user sign-in allowed; - account not blocked; - MFA / Conditional Access flow tested from the RDS session; - SCA entitlement actually included in the user's plan. A wrong license assignment cannot be fixed by reinstalling Office. ## Common Shared Computer Activation problems ### User has Office but cannot activate on the shared server Check whether the user's plan actually supports SCA. Microsoft 365 Business Standard is a common source of confusion because it includes desktop Office apps for normal user devices but does not grant the Business Premium SCA entitlement. ### Second user fails after the first user activates Office This often indicates that Office was installed without Shared Computer Activation or that the environment was tested only under one profile. Verify: ```powershell $key = 'HKLM:\SOFTWARE\Microsoft\Office\ClickToRun\Configuration' (Get-ItemProperty -Path $key).SharedComputerLicensing ``` Expected: `1`. ### Office repeatedly asks users to sign in Common causes include: - temporary or deleted user profiles; - licensing data not persisting; - Conditional Access or MFA issues; - blocked internet connectivity to Microsoft licensing services; - profile-container problems; - incorrect SCA configuration. Fix the identity/profile path before rebuilding the server. ### Outlook profile disappears after logout This is generally a profile-management issue. Review the persistence strategy, profile cleanup policy, FSLogix or other container configuration, storage capacity, and permissions. ### Business Premium users cannot activate Confirm both the user entitlement and the installed product ID. For the Apps for business product used with Business Premium, the ODT product ID is typically: ```xml ``` ### Server 2022 deployment is approaching end of support As of September 2026, Microsoft 365 Apps on Windows Server 2022 is supported only through October 2026. Microsoft says security updates will continue through October 10, 2028, but new deployments should generally evaluate Windows Server 2025 instead. ## Update channel planning For multi-user RDS hosts, avoid treating Office updates as a consumer-PC task. An Office update can affect every active user on the server. `MonthlyEnterprise` can be a practical controlled channel for many business RDS deployments: ```xml Channel="MonthlyEnterprise" ``` Before standardizing a channel, consider: - add-in compatibility; - accounting/ERP integrations; - maintenance windows; - test rings; - rollback procedures; - Microsoft support lifecycle requirements. ## Security and operations checklist Before production, verify: - supported Windows Server version; - RDS Session Host configuration; - RDS licensing model; - eligible Microsoft 365 licenses; - SCA enabled; - unique identity for each user; - MFA / Conditional Access tested; - user profiles persist correctly; - Outlook tested under load; - OneDrive behavior intentionally configured; - users are not local administrators; - RDP/RDS access is restricted and hardened; - Office update channel documented; - VM backup / snapshot policy configured; - recovery process tested. ## How Raff fits this workload Raff provides the Windows VM infrastructure layer for customer-managed Windows Server workloads. A typical architecture is: ```text Raff Windows VM ↓ Windows Server 2025 ↓ Remote Desktop Services ↓ Microsoft 365 Apps with Shared Computer Activation ↓ Individually licensed users ``` Raff does not replace Microsoft 365 licensing or tenant administration. You still need the correct Microsoft 365 entitlement for each user and the correct RDS licensing model. For infrastructure planning, see [Remote Desktop VPS](/products/remote-desktop-vps), [Windows VPS Sizing for Remote Users](/windows-server/windows-vps-sizing-remote-users), and [Multi-User RDP vs RDS Session Host](/windows-server/multi-user-rdp-vs-rds). :::cta View Windows VM Plans Compare current Windows VM plans for RDS and shared business-software workloads. ::: ## Recommended 2026 deployment path For a new Microsoft 365 Apps RDS deployment today: 1. Start with **Windows Server 2025** unless another required application prevents it. 2. Configure RDS for genuine multi-user access. 3. License RDS separately from Microsoft 365 Apps. 4. Assign every user an eligible Microsoft 365 plan. 5. Install Microsoft 365 Apps with ODT. 6. Enable `SharedComputerLicensing=1`. 7. Test two or more non-admin users. 8. Validate Outlook and profile persistence. 9. Harden RDP/RDS access. 10. Document backups, updates, and support ownership. ## Sources - Microsoft Learn — [Overview of shared computer activation for Microsoft 365 Apps](https://learn.microsoft.com/en-us/microsoft-365-apps/licensing-activation/overview-shared-computer-activation) - Microsoft Learn — [Deploy Microsoft 365 Apps by using Remote Desktop Services](https://learn.microsoft.com/en-us/microsoft-365-apps/deploy/deploy-microsoft-365-apps-remote-desktop-services) - Microsoft Learn — [Windows Server end of support and Microsoft 365 Apps](https://learn.microsoft.com/en-us/microsoft-365-apps/end-of-support/windows-server-support) - Microsoft Learn — [Microsoft 365 Apps migration from Windows Server](https://learn.microsoft.com/en-us/microsoft-365-apps/end-of-support/windows-server-migration) - Microsoft Learn — [Install Remote Desktop Services client access licenses](https://learn.microsoft.com/en-us/windows-server/remote/remote-desktop-services/rds-install-cals) - Sources verified: 2026-09-09 --- ### What Is Remote Desktop Gateway? RD Gateway vs Direct RDP URL: https://rafftechnologies.com/windows-server/remote-desktop-gateway-vs-direct-rdp Description: Remote Desktop Gateway (RD Gateway) brokers encrypted RDP access over HTTPS so users can reach internal Windows resources without publishing each server's RDP port to the internet. Compare RD Gateway with direct RDP. ## In short **Remote Desktop Gateway (RD Gateway)** is a Windows Server Remote Desktop Services role that gives authorized remote users a secure, encrypted path to internal Windows desktops and RemoteApp resources over the internet. Instead of publishing every target server's RDP endpoint directly, clients connect to the gateway and the gateway brokers access to approved internal resources. People often search for **RDS Gateway**, but Microsoft's role name is **Remote Desktop Gateway (RD Gateway)**, part of the Remote Desktop Services platform. For a single administrator with a predictable source IP, tightly restricted direct RDP can be a reasonable management path. For multiple users, changing locations, RemoteApp, RD Session Host, or a business that wants one controlled remote-access entry point, RD Gateway is the cleaner architecture. On a Raff Windows environment, the internet-facing RD Gateway path normally uses **TCP 443**, with **UDP 3391** available when the supported UDP transport is enabled. Target hosts do not need to publish TCP 3389 directly to internet clients, but the gateway still needs the required **internal RDP connectivity** to those targets. This page covers what RD Gateway is and when to use it instead of direct RDP. If you only want direct-RDP hardening steps, use the [Windows Server hardening checklist](/windows-server/windows-server-hardening-checklist). If you are deciding between the two administrative sessions and a true multi-user RDS deployment, use [Multi-User RDP vs RDS Session Host](/windows-server/multi-user-rdp-vs-rds). ## What is Remote Desktop Gateway (RDS Gateway)? Remote Desktop Gateway is a Windows Server role that sits between internet-connected Remote Desktop clients and internal RDS resources. Microsoft describes the role as enabling secure, encrypted connections to Remote Desktop Services resources over the internet without requiring users to establish a traditional VPN first. The basic path is: ```text Remote user | | HTTPS / RD Gateway transport v Remote Desktop Gateway | | internal RDP path v Authorized Windows desktop or RD Session Host ``` The security benefit is architectural: you can publish the gateway as the remote-access entry point instead of publishing TCP 3389 from every target Windows server to the public internet. RD Gateway is not the desktop host itself. The gateway authenticates and authorizes the connection, then brokers it to the allowed internal Windows resource. ## RD Gateway vs direct RDP: quick comparison | Area | Direct RDP | Remote Desktop Gateway | |---|---|---| | Internet-facing path | Client connects directly to the Windows host | Client connects to the gateway first | | Typical external port | RDP is commonly exposed on TCP 3389 unless restricted or translated | HTTPS uses TCP 443; supported RD Gateway designs can also use UDP 3391 | | Public exposure | Each directly reachable RDP host needs its own controlled path | Gateway becomes the main published RDP access layer | | Best fit | Small admin-only access with strict allowlisting | Multiple users, RDS resources, changing locations, centralized policy | | Authorization | Windows account and host/firewall controls | RD CAP and RD RAP plus target-host controls | | Certificates | RDP certificate/security still matters | Public gateway should use a trusted certificate matching its FQDN | | MFA | Added through the chosen identity/access design | Can integrate with NPS and Microsoft Entra MFA designs | | Complexity | Lower | Higher: gateway role, certificate, policies, DNS, monitoring | | Scaling | Each direct endpoint must be managed | Gateway servers can be deployed as a farm/load-balanced design | The important comparison is not "which one makes RDP faster?" It is **where you place the trust boundary and how many public RDP entry points you want to manage**. ## How RD Gateway works A typical connection has four stages: 1. The Remote Desktop client is configured with the RD Gateway hostname. 2. The client establishes the gateway connection over the published RD Gateway transport. 3. RD Gateway evaluates whether the user is allowed to connect and which internal resources that user may reach. 4. The gateway brokers the RDP session to the authorized target server over the internal network path. Microsoft's current RDS role guidance identifies HTTPS on **TCP 443** as the primary external RD Gateway path and also documents **UDP 3391** for the UDP transport. The target Windows server still needs to be reachable from the gateway over the required internal RDP path. The difference is that the target server's RDP port does **not** need to be published directly to every internet client. ## What are RD CAP and RD RAP? RD Gateway uses authorization policies to separate **who may use the gateway** from **what they may reach**. ### Remote Desktop Connection Authorization Policy (RD CAP) An **RD CAP** determines which users or groups are allowed to connect through the gateway and can include conditions such as authentication method or group membership. Think of it as: ```text Who is allowed through this gateway? ``` ### Remote Desktop Resource Authorization Policy (RD RAP) An **RD RAP** determines which internal computers or resource groups an authorized user may access through the gateway. Think of it as: ```text Which Windows resources may this approved user reach? ``` Keeping those questions separate is one of RD Gateway's main advantages over a loose collection of direct public RDP rules. ## RD Gateway vs direct RDP architecture ![Architecture diagram comparing direct RDP access with RD Gateway access for a Windows VPS](https://raff-images.s3.raffusercloud.com/direct_rdp_vs_rd_gateway_architecture_webp_1b0e4927af.png) ### Direct RDP A direct design looks like this: ```text Internet | v Windows Server RDP endpoint ``` For one administrator, this can be simple. But if the server accepts RDP from the entire internet, its authentication endpoint is continuously exposed to scanning and credential attacks. A safer direct-RDP design narrows the exposure with controls such as source-IP allowlisting, Network Level Authentication, named administrator accounts, strong unique credentials, account lockout and monitoring, current Windows security updates, and firewall rules that expose only the required path. For the detailed direct-RDP hardening workflow, see the [Windows Server hardening checklist](/windows-server/windows-server-hardening-checklist). ### RD Gateway A gateway design looks more like this: ```text Internet | v RD Gateway | +--> Windows Server A +--> RD Session Host B +--> Approved RDS resource C ``` Only the gateway needs to be the controlled public RDS entry point. Target hosts can remain behind internal firewall rules that allow RDP from the gateway or other approved management paths. That centralization becomes more valuable as the number of users, servers, offices, and support staff grows. ## What ports does Remote Desktop Gateway use? Plan the RD Gateway network path in two parts: **internet-facing gateway transport** and **gateway-to-target RDP connectivity**. | Traffic | Typical port | Purpose | |---|---:|---| | HTTPS | TCP 443 | Primary encrypted RD Gateway transport | | RD Gateway UDP transport | UDP 3391 | Optional supported UDP path | | Internal RDP | TCP/UDP 3389 as required by the target design | Gateway-to-target RDP connectivity inside the protected network | Do not interpret RD Gateway as "RDP no longer uses 3389 anywhere." The goal is to avoid publishing every target host's RDP endpoint directly to the public internet. Internal connectivity between the gateway and target resources still has to be allowed by your network design. Firewall requirements can vary with Windows Server version, RDS topology, NAT, and whether UDP transport is enabled. Validate the actual Microsoft requirements for the deployment rather than copying a generic port rule into production. ## Does RD Gateway replace a VPN? **Not universally.** RD Gateway can let users reach approved Remote Desktop resources without first connecting to a traditional VPN, which is useful when the only remote requirement is RDP or RemoteApp access. A VPN is broader: it can provide network-level access to many protocols and internal services. RD Gateway is narrower and RDP-focused. | Requirement | Better fit | |---|---| | Reach only approved Windows desktops or RemoteApps | RD Gateway can be a good fit | | Reach file shares, internal web apps, SSH, databases, and many private subnets | VPN or another private-access architecture may fit better | | Give contractors access only to specific RDS resources | RD Gateway can provide a smaller access scope | | Provide full private-network connectivity | VPN/private networking is the broader tool | The right choice depends on the resources users actually need, not on whether one technology is "more secure" in every scenario. ## RD Gateway is different from RD Session Host **RD Gateway** controls the remote path into the RDS environment. **RD Session Host** runs the multi-user Windows desktops and RemoteApp sessions. ```text RD Gateway = secure access path RD Session Host = where user sessions/apps run ``` You can use RD Gateway to access a regular Windows server or as part of a larger RDS deployment. Adding RD Gateway does not itself turn a Windows Server into a properly licensed multi-user desktop host. If employees need daily shared desktops or RemoteApp sessions, review [RDS CAL Licensing](/windows-server/rds-cal-licensing-guide) and [Multi-User RDP vs RDS Session Host](/windows-server/multi-user-rdp-vs-rds). For Raff-hosted RDS under SPLA, plan RDS User SALs separately from the Windows Server instance licence. ## When direct RDP is reasonable Direct RDP can still be appropriate when the environment is genuinely small and administrative: one or two administrators, stable source networks, no daily shared-desktop users, active login monitoring, and a tested recovery path. The key distinction is **restricted direct RDP** versus **broadly exposed direct RDP**. A single server accepting TCP 3389 only from a known corporate IP is a very different risk profile from a server accepting RDP connections from every internet address. ## When RD Gateway is the better fit RD Gateway usually becomes more attractive when several employees use remote Windows resources, users connect from changing networks, you operate multiple Windows servers, you use RD Session Host or RemoteApp, an MSP needs a repeatable access pattern, or you need clearer user/resource policy through CAP and RAP. RD Gateway adds infrastructure, so it should solve a real access-management problem. For one administrator and one server, a properly restricted management path can be simpler. ## Does RD Gateway support MFA? RD Gateway can participate in an MFA design, but **the RD Gateway role is not itself an MFA provider**. Microsoft documents integrating RD Gateway with **Network Policy Server (NPS)** and the **Microsoft Entra multifactor authentication NPS extension**. In that design, the NPS layer participates in the authorization flow and the extension performs the MFA step. Microsoft's deployment guidance places the NPS extension on the NPS server rather than treating the RD Gateway role itself as the MFA engine. MFA should be treated as an additional control, not a replacement for certificates, patching, CAP/RAP design, host firewall rules, logging, or least privilege. ## Certificate requirements RD Gateway is a public-facing encrypted service, so certificate planning is part of the deployment rather than an optional polish step. Use a certificate trusted by the client devices and make sure the certificate name matches the fully qualified domain name users configure for the gateway, for example `rdg.example.com`. Before production rollout, verify the certificate is trusted by client devices, the subject/SAN covers the public gateway hostname, the private key is installed on the gateway, renewal is monitored, and the replacement process is tested before expiration. ## Basic RD Gateway deployment flow A production planning sequence is: 1. Choose the public gateway FQDN and DNS record. 2. Install the Remote Desktop Gateway role service. 3. Import a trusted certificate for the public gateway name. 4. Define RD CAP rules for authorized users/groups. 5. Define RD RAP rules for allowed internal resources. 6. Configure firewall rules for the external and internal paths. 7. Configure Remote Desktop clients to use the gateway. 8. Add MFA/NPS integration if required. 9. Test both allowed and deliberately denied access paths. 10. Add logging, monitoring, backup, and certificate-renewal procedures. Do not make "the session opens" your only acceptance test. A secure deployment should also prove that unauthorized users and unauthorized target resources are denied. ## High availability and scale RD Gateway can be deployed as a farm for additional availability and capacity. If one gateway failure would lock the whole team out, consider a second gateway instance, load balancing, certificate consistency across nodes, centralized policy configuration, monitoring from outside the environment, and a documented emergency administration path. A gateway improves architecture, but a single unmonitored gateway can also become a single point of failure. ## RD Gateway security checklist Before production use, confirm: - [ ] Public target hosts do not expose RDP more broadly than necessary. - [ ] The gateway has a trusted certificate matching its public FQDN. - [ ] RD CAP rules allow only intended users/groups. - [ ] RD RAP rules allow only intended target resources. - [ ] External TCP 443 is configured as required. - [ ] UDP 3391 is enabled only if your design uses the supported UDP transport. - [ ] Internal RDP reachability is restricted to intended paths. - [ ] MFA is configured when the risk model requires it. - [ ] Windows Server and RDS components are patched. - [ ] Gateway and target-host login events are monitored. - [ ] Certificate expiration is monitored. - [ ] Recovery and emergency access procedures are documented. - [ ] RD Session Host users have the required RDS licensing. ## Which should you use on a Windows VPS? For a Windows VPS used only for server administration, direct RDP can be practical when you can restrict it to trusted source addresses and keep the number of administrators small. For a Windows VPS that is becoming a shared workplace, hosts business applications for remote staff, serves RemoteApp sessions, or gives several users access from unpredictable networks, RD Gateway gives you a more deliberate access boundary. A useful progression is: ```text One admin / one server -> restricted management RDP Growing remote team -> RDS architecture review -> RD Gateway for controlled external access -> MFA, policies, monitoring and licensing ``` Raff Windows VMs provide the Windows Server environment and administrator access needed to build either model. The customer still needs to design the RDS roles, certificates, authorization policies, MFA integration, firewall rules, licensing, and recovery plan for the production workload. If the environment is intended for remote employees rather than occasional administration, review [Remote Desktop Hosting](/products/remote-desktop-vps) together with [Windows Server Licensing](/windows-server/windows-licensing) before rollout. ## What's next - [Windows Server hardening checklist](/windows-server/windows-server-hardening-checklist) - [Multi-User RDP vs RDS Session Host](/windows-server/multi-user-rdp-vs-rds) - [RDS CAL Licensing Guide](/windows-server/rds-cal-licensing-guide) - [Windows VPS Sizing for Remote Users](/windows-server/windows-vps-sizing-remote-users) - [RDP Performance Tuning](/windows-server/rdp-performance-tuning) - [Remote Desktop Hosting](/products/remote-desktop-vps) ## Sources - Microsoft Learn — Deploy the Remote Desktop Gateway role - Microsoft Learn — Remote Desktop Services roles - Microsoft Learn — Remote Desktop Services overview in Windows Server - Microsoft Learn — Plan for access from anywhere with Remote Desktop Services - Microsoft Learn — Integrate RD Gateway with Microsoft Entra MFA using the NPS extension - Microsoft Learn — License Remote Desktop Services with CALs - Sources revalidated: 2026-09-17 --- ### Remote Desktop Server Hosting for Business: Setup, Costs & RDS URL: https://rafftechnologies.com/windows-server/remote-desktop-server-for-business Description: Plan a hosted remote desktop server for business on Windows Server: compare RDP, RDS and RD Gateway, current Raff pricing, RDS User SALs, sizing, security, backups, and migration decisions. ## In short A remote desktop server gives employees a shared Windows environment for business apps, files, and remote work. On Raff, the infrastructure is a Windows VM; daily multi-user desktops should use Remote Desktop Services rather than administrative RDP. Current hosted pricing starts with the VM, **$15/month Windows Server Standard SPLA**, and, when RDS is used through Raff's hosted licensing model, **$8/month per RDS User SAL**. ## A remote desktop server centralizes Windows apps and user sessions A **remote desktop server** is a Windows Server environment that users reach over Remote Desktop Protocol instead of running every application and data file on their local PCs. For a business, that can centralize: - accounting and tax software; - ERP and inventory applications; - Microsoft Access and other legacy Windows apps; - shared files and reports; - RemoteApp programs; - support tools used by an MSP or internal IT team; - a consistent Windows workspace for remote or branch-office users. Microsoft continues to include **Remote Desktop Services (RDS)** in Windows Server 2025. RDS supports session-based desktops, RemoteApp, RD Gateway, RD Licensing, Connection Broker, and other roles used to deliver Windows applications and desktops to users. The important distinction is that **a Windows VPS is the infrastructure**. A production remote desktop environment is what you design on top of that infrastructure: access, user licensing, security, sizing, application support, profiles, backups, and recovery. ## Remote desktop hosting fits businesses with centralized Windows workloads A hosted remote desktop server is a strong fit when several people need the same Windows applications or data from different locations. | Business situation | Fit | Why | |---|---|---| | Employees need Windows business apps from home or branch offices | Strong | Apps and data stay in one server environment | | Several users need the same accounting, ERP, tax, or legacy app | Strong after vendor validation | Central app installation and shared data can simplify support | | A company is replacing an office server | Strong | Remote access can be part of the cloud migration design | | An MSP manages repeatable client Windows environments | Strong | Each client can have a documented VM, access model, backup policy, and support path | | Users mainly need browser SaaS | Weak | A remote desktop server may add unnecessary complexity | | Application vendor does not support RDS or multi-session use | Risky | Resolve vendor support before production | | Workload requires GPU-heavy graphics or media | Depends | Test the actual application and latency first | | High availability is mandatory | Architecture decision | One VM is not an HA design | The buying question is therefore not simply “Do I need an RDP server?” It is: **Do my users need a centralized Windows Server workspace that I can secure, license, back up, and support?** ## RDP, RDS, RD Gateway, and Windows VPS solve different problems Buyers often use “RDP server” as a catch-all term. The underlying components are different. | Term | What it is | Typical use | |---|---|---| | RDP | Remote Desktop Protocol | The protocol used to display a remote Windows session | | Administrative RDP | Windows Server administrative remote access | Server setup, patching, troubleshooting, maintenance | | RDS Session Host | Windows Server role for multiple user sessions | Daily employee desktops and RemoteApp workloads | | RD Gateway | HTTPS-based gateway for RDS access | Controlled external access without exposing internal RDP directly | | RD Licensing | RDS licensing role | Tracks/serves the applicable RDS licensing model | | RemoteApp | Publishes individual Windows applications | Users need apps without a full desktop | | Windows VPS / VM | Hosted Windows Server infrastructure | The compute, memory, storage, network, and OS foundation | For a first administrative login to a Raff Windows VM, use the [Windows VPS RDP connection guide](/windows-server/connect-to-windows-vps-via-rdp). For staff using desktop sessions every day, plan RDS instead of stretching administrative RDP into a user platform. ## Administrative RDP is not a substitute for employee RDS sessions Windows Server administrative Remote Desktop access exists for managing the server. It should not be treated as a way to avoid licensing a real multi-user desktop deployment. Use administrative RDP for: - server setup; - Windows Update and patching; - application installation; - troubleshooting; - emergency maintenance. Use **RDS Session Host** when users need their own regular Windows sessions or RemoteApp access for daily work. Microsoft's current RDS licensing guidance states that users or devices connecting to an RD Session Host need appropriate RDS access licensing. Microsoft separately documents **per-user SALs for service providers, hosters, MSPs, and ISVs** as the hosted-service licensing path. For the architectural split, use [Multi-User RDP vs RDS Session Host](/windows-server/multi-user-rdp-vs-rds). ## Raff hosted RDS uses User SALs rather than ordinary customer CAL pricing The licensing model depends on how Windows Server and RDS rights are supplied. ### Raff-hosted SPLA model For a Raff-hosted Windows Server deployment using Raff's SPLA licensing: - Windows Server Standard license: **$15/month per instance**; - RDS User SAL: **$8/month per user** when users need hosted RDS sessions; - the VM compute plan is billed separately; - application licenses such as Microsoft 365 Apps, QuickBooks, SQL Server, ERP, or tax software remain separate from Windows/RDS unless explicitly included by that vendor or agreement. A User SAL is assigned per user in the hosted service model. It is not the same commercial model as buying perpetual RDS CALs for an on-premises server. ### Customer-owned Microsoft licensing A customer with eligible Microsoft licensing can have a different path, but hosted deployment rights must be validated before production. Do not assume that an existing on-premises Windows Server or RDS CAL purchase automatically transfers unchanged to a hosted environment. The detailed licensing decision is covered in [Windows Server Licensing: SPLA, BYOL, CALs & RDS](/windows-server/windows-licensing) and the [RDS CAL Licensing Guide](/windows-server/rds-cal-licensing-guide). ## Remote desktop server cost is VM + Windows + users + the application stack Hosted remote desktop pricing should be calculated from the actual workload, not from one advertised VPS number. The base formula is: ```text Monthly remote desktop infrastructure cost = Windows VM compute + Windows Server license + RDS user licensing when RDS is used + storage / backup additions + application or database licensing ``` Current Raff Windows Server Standard SPLA pricing is **$15/month per instance**. In the Raff-hosted RDS model, **RDS User SAL is $8/month per user**. Illustrative examples using current Raff VM configurations: | Example workload | Raff VM | Compute | Windows Server | RDS User SALs | Infrastructure total* | |---|---|---:|---:|---:|---:| | Admin-only server | 2 vCPU / 4 GB / 80 GB | $22.99 | $15 | Not a staff RDS example | **$37.99/mo** | | 3 light RDS users | 4 vCPU / 8 GB / 120 GB | $40.99 | $15 | 3 × $8 = $24 | **$79.99/mo** | | 5 business-app users | 8 vCPU / 16 GB / 180 GB | $76.99 | $15 | 5 × $8 = $40 | **$131.99/mo** | | 10 active users | 8 vCPU / 32 GB / 240 GB | $137.99 | $15 | 10 × $8 = $80 | **$232.99/mo** | \*Examples are infrastructure/licensing illustrations, not workload guarantees. They exclude application licenses, additional volumes, backup retention, snapshots, migration work, and other software costs. Raff VM traffic is **3 Gbps unmetered with no VM egress fees**, so the main remote-desktop sizing variables are usually CPU, RAM, storage, user concurrency, application behavior, and latency rather than transfer overage. For the full pricing model, use [Windows VPS Pricing Explained](/windows-server/windows-vps-pricing-explained). :::cta View Pricing Compare current Raff Windows VM plans before sizing a hosted Remote Desktop environment. ::: ## Concurrent users and workload type determine the VM size Remote desktop servers should be sized for **peak concurrent users**, not employee headcount. Ten employees with three simultaneous sessions are a different workload from ten people working in Windows all day. Use these current Raff configurations as planning anchors: | Remote desktop workload | Practical Raff starting point | Why | |---|---|---| | 1–2 administrators, light server work | 2 vCPU / 4 GB / 80 GB | Enough for administration and light background roles | | 3 light employee sessions | 4 vCPU / 8 GB / 120 GB | Adds CPU/RAM headroom for multiple sessions | | 3–5 business-app users | 8 vCPU / 16 GB / 180 GB | Better fit for accounting, Office-style workloads, reports, and app services | | About 10 active users | 8 vCPU / 32 GB / 240 GB | More memory for concurrent sessions and user profiles | | RDS plus SQL/ERP or heavier reporting | 16 vCPU / 32 GB / 360 GB or split roles | Database and desktop sessions can contend for CPU/RAM | These are starting points, not guarantees. User behavior can change requirements dramatically. A user running one line-of-business app is different from a user running Outlook, multiple browser tabs, Excel, PDF tools, reporting software, and a locally hosted database at the same time. Use [Windows VPS Sizing for Remote Users](/windows-server/windows-vps-sizing-remote-users) for the deeper 1-, 3-, 5-, and 10-user model. ## RD Gateway is usually a better team access layer than broadly exposed RDP Direct RDP to a public IP is simple for initial administration, but a production team environment should minimize unnecessary exposure. Microsoft documents **RD Gateway** as an RDS role that provides encrypted remote access over HTTPS and can avoid exposing internal RDP directly to external users. For a business deployment, consider: - RD Gateway for controlled external RDS access; - a VPN/private-access layer where appropriate; - Network Level Authentication; - source-IP restrictions for administrative RDP; - named accounts instead of shared Administrator credentials; - MFA at the appropriate access layer; - logging and failed-sign-in monitoring. Compare the models in [RD Gateway vs Direct RDP](/windows-server/remote-desktop-gateway-vs-direct-rdp). ## Business application support must be checked before migration A technically working RDS session does not mean the software vendor supports the deployment. Before moving a production app, verify: | Area | What to confirm | |---|---| | Windows Server version | Vendor supports Server 2022/2025 or the version you plan to run | | Multi-user/RDS support | Application is supported in concurrent or session-host use | | Licensing | User/device/concurrent licensing terms allow the deployment | | Database | SQL Server, local DB, Access, or file-based data architecture is supported | | Printing/scanning | Required redirection and drivers work in RDS | | File paths | UNC paths, mapped drives, and profile paths are compatible | | Updates | Vendor patching process will not break active sessions | | Support boundary | Vendor will support the app when hosted on Windows Server/RDS | This matters especially for accounting, tax, ERP, inventory, healthcare, legal, and legacy line-of-business software. ## User profiles and storage can become the hidden bottleneck Remote desktop workloads create more storage pressure than the operating-system installer suggests. Plan capacity for: - user profiles; - browser caches; - Outlook data where supported; - downloads and documents; - app data and logs; - temporary files; - print spools; - shared folders; - database files; - Windows Update growth; - backup staging if used. Raff volumes are currently **$0.08/GB/month** when additional block storage is needed. Snapshots/backups are **$0.06/GB/month** according to the current Raff product pricing model. Do not size a five- or ten-user RDS server for the amount of free disk space available immediately after Windows installation. ## Backups need to protect both the VM and the business data A remote desktop server can become the working environment for an entire business. Recovery therefore needs more than a single snapshot. Plan for: - VM-level recovery; - file-level backup where needed; - application-aware database backups; - restore testing; - retention that matches business requirements; - an off-server recovery copy where appropriate; - a rollback point before risky updates or migrations. A snapshot is useful before change. It is not automatically a complete backup strategy for SQL Server, QuickBooks, ERP data, shared files, or user profiles. Use [Windows VPS Backup Strategy for Small Businesses](/windows-server/windows-vps-backup-strategy-small-business) before users begin storing production data. ## Remote desktop performance depends on both the VM and the user path When users say “the remote desktop server is slow,” the bottleneck can be anywhere in the path: | Area | Typical symptom | |---|---| | CPU | Slow app launches, reporting, browser rendering | | RAM | Paging, session freezes, slow switching between apps | | Storage | Slow login, profile load, database/file access | | Network latency | Delayed mouse/keyboard response | | Packet loss | Freezes or reconnects | | User profile | Long logon/logoff time | | Application | One app slows everyone down | | Database | Reports and queries stall desktop sessions | | Client device | Display, printer, or redirection problems | If the server is already deployed, use [RDP Performance Tuning](/windows-server/rdp-performance-tuning) and [Windows Server Performance Monitoring](/windows-server/windows-server-performance-monitoring) before resizing blindly. ## A remote desktop server should be hardened before staff depend on it Minimum production controls include: 1. Use named user accounts. 2. Separate administrator accounts from daily user accounts. 3. Keep Network Level Authentication enabled. 4. Restrict administrative RDP exposure. 5. Prefer RD Gateway or another controlled access layer for teams. 6. Keep Windows and business applications patched. 7. Review local and domain Group Policy. 8. Apply least-privilege file and application permissions. 9. Monitor failed logins and unusual account activity. 10. Configure backups and prove that restore works. For the broader baseline, use the [Windows Server Hardening Checklist](/windows-server/windows-server-hardening-checklist) and [Configure Windows Firewall](/windows-server/configure-windows-firewall). ## A safe office-server migration separates build, test, and cutover Many hosted remote desktop projects begin as replacements for an office PC or local Windows Server. Use this migration sequence: 1. Inventory users, applications, files, databases, printers, and dependencies. 2. Confirm software-vendor support for Windows Server and RDS. 3. Decide which Microsoft licensing model will be used. 4. Size the Raff Windows VM for peak concurrent users. 5. Build the new Windows environment. 6. Configure access, firewall, RDS, and RD Gateway/VPN if needed. 7. Install the applications and dependencies. 8. Copy non-production data first. 9. Test real users from real locations. 10. Configure backups and complete at least one restore test. 11. Schedule final data cutover. 12. Keep the old environment available as a rollback path until the new system is stable. A remote desktop migration is successful when users can complete their normal business workflow reliably, not merely when an RDP window opens. ## Raff provides the Windows VM foundation, not a fully managed virtual desktop service Raff is a strong fit when a business, MSP, or IT operator wants to build a Windows Server remote desktop environment with: - administrator-controlled Windows VMs; - Windows Server 2022/2025 workloads; - hourly PAYG compute; - NVMe storage; - 3 Gbps unmetered VM traffic with no VM egress fees; - additional volumes; - snapshots and backups; - RDS User SAL availability in the Raff-hosted licensing model; - direct access to a real support team when infrastructure help is needed. Raff supplies and supports the cloud infrastructure layer. The customer or MSP still owns application support, user design, RDS architecture, profile strategy, domain/GPO design, application licensing, and day-to-day Windows administration unless a separate service agreement says otherwise. If the requirement is a fully provider-managed enterprise virtual desktop platform with profile management, identity orchestration, multi-region failover, and managed user support included, a single self-managed Windows VM is not the same product. ## The production checklist should be complete before the first workday | Check | Ready | |---|---| | Peak concurrent users estimated | ☐ | | Application vendor support confirmed | ☐ | | Windows Server licensing model confirmed | ☐ | | RDS User SAL / customer licensing path confirmed | ☐ | | VM CPU/RAM/storage selected | ☐ | | Administrative RDP vs RDS model decided | ☐ | | RD Gateway/VPN decision made | ☐ | | Named user and admin accounts designed | ☐ | | Profiles and shared storage planned | ☐ | | Firewall rules reviewed | ☐ | | Business applications installed and tested | ☐ | | Backup configured | ☐ | | Restore test passed | ☐ | | Printers/scanners tested if required | ☐ | | Real users tested from real locations | ☐ | | Patch and maintenance window defined | ☐ | | Rollback path documented | ☐ | ## Validation scope > This is a commercial planning and architecture guide, not a claim that Raff performed a fresh multi-user RDS deployment test for this September 2026 revision. Current Raff VM pricing, Windows Server licensing, RDS User SAL pricing, storage pricing, and network terms were revalidated against Raff's current product source of truth. Microsoft RDS roles and CAL/SAL guidance were revalidated against current Microsoft documentation. Application compatibility must still be checked with each software vendor. ## What's next - [Remote Desktop VPS](/products/remote-desktop-vps) — compare and deploy the Windows infrastructure. - [Windows VPS Pricing Explained](/windows-server/windows-vps-pricing-explained) — calculate compute, Windows licensing, storage, and hosted user costs. - [Windows Server Licensing](/windows-server/windows-licensing) — understand SPLA, BYOL, CALs, and hosted RDS licensing. - [Windows VPS Sizing for Remote Users](/windows-server/windows-vps-sizing-remote-users) — size 1, 3, 5, or 10 concurrent users. - [Multi-User RDP vs RDS Session Host](/windows-server/multi-user-rdp-vs-rds) — choose the correct user-session model. - [RD Gateway vs Direct RDP](/windows-server/remote-desktop-gateway-vs-direct-rdp) — design external access. - [RDS CAL Licensing Guide](/windows-server/rds-cal-licensing-guide) — understand customer CALs and RDS licensing mechanics. - [Windows VPS Backup Strategy](/windows-server/windows-vps-backup-strategy-small-business) — design recovery before production. ## Sources - Microsoft Learn — [Remote Desktop Services overview in Windows Server](https://learn.microsoft.com/en-us/windows-server/remote/remote-desktop-services/overview) - Microsoft Learn — [License Remote Desktop Services with Client Access Licenses](https://learn.microsoft.com/en-us/windows-server/remote/remote-desktop-services/rds-client-access-license) - Microsoft Learn — [Remote Desktop Services: choose how you pay](https://learn.microsoft.com/en-us/windows-server/remote/remote-desktop-services/rds-plan-choose-how-you-pay) - Microsoft Learn — [Install Remote Desktop Services client access licenses](https://learn.microsoft.com/en-us/windows-server/remote/remote-desktop-services/rds-install-cals) - Raff — [Windows VM](/products/windows-vm) - Raff — [Pricing](/pricing) - Sources revalidated: 2026-09-09 --- ### Remote Desktop Services Configuration on Windows Server 2025 URL: https://rafftechnologies.com/windows-server/remote-desktop-services-configuration Description: Configure Remote Desktop Services on Windows Server 2025 with Session Host, Connection Broker, licensing, collections, user access, and profile planning. ## In short **Remote Desktop Services configuration** on Windows Server 2025 starts with a domain-backed session deployment: add RD Connection Broker, RD Web Access, and RD Session Host, then configure licensing, create a session collection, restrict it to the correct Active Directory group, and decide how user profiles will persist. On Raff, treat the 120-day RDS grace period as deployment time, not a production licensing plan. This tutorial is for administrators building a classic Windows Server RDS environment for multiple users. It assumes Windows Server is already deployed and patched. If you are still deciding whether you need RDS at all, read [Multi-User RDP: 2 Admin Sessions vs RDS Session Host](/windows-server/multi-user-rdp-vs-rds) first. Raff has deployed **15,000+ VMs for 3,000+ customers**; this tutorial focuses on the configuration decisions that matter after Windows Server is running. ## This tutorial owns the RDS configuration workflow This page covers one specific path: ```text Windows Server 2025 → Active Directory domain membership → Standard session-based RDS deployment → RD Connection Broker → RD Web Access → RD Session Host → RD Licensing → Session collection → User group assignment → User profile strategy → End-to-end verification ``` It does not duplicate the deeper decisions already covered elsewhere: - [RDS CAL Licensing on Windows Server](/windows-server/rds-cal-licensing-guide) owns Per User vs Per Device, BYOL, and Raff SPLA licensing decisions. - [Remote Desktop Gateway vs Direct RDP](/windows-server/remote-desktop-gateway-vs-direct-rdp) owns the external-access architecture. - [RDP Performance Tuning](/windows-server/rdp-performance-tuning) owns session performance. - [Windows Server Licensing on Raff](/windows-server/windows-licensing) owns Windows Server Evaluation, SPLA, and BYOL. - [Windows VPS for Remote Desktop](/windows-server/windows-vps-for-remote-desktop) owns the broader buyer/use-case decision. Microsoft's Standard Deployment wizard can place the main RDS roles on separate servers or combine roles for a smaller environment. This tutorial uses a **domain-joined Standard Deployment** because it gives you Connection Broker, collections, centralized licensing configuration, and a clean path to add Session Hosts later. ## Remote Desktop Services configuration starts with the right architecture A small RDS environment still has separate responsibilities even when several roles share one VM. | RDS component | What it does | Required in this tutorial | |---|---|---| | RD Session Host | Runs multi-user desktops and RemoteApp programs | Yes | | RD Connection Broker | Tracks sessions, reconnects users, and manages collections | Yes | | RD Web Access | Publishes desktops and RemoteApp resources to authorized users | Yes | | RD Licensing | Manages the Windows RDS licensing configuration | Yes | | RD Gateway | Provides controlled external RDP access over HTTPS | No — configure separately before public rollout | For a lab or a very small deployment, you can combine Connection Broker, Web Access, Licensing, and Session Host roles. For production, decide whether role separation is justified by user count, maintenance windows, recovery requirements, and the need to scale Session Hosts independently. Microsoft recommends keeping all RD Session Hosts inside one collection at the same Windows Server version. A Windows Server 2025 collection should therefore not mix 2025 and 2022 Session Hosts. ## The prerequisites should be complete before you install RDS Do not begin the RDS wizard until identity, DNS, patching, and recovery are in a known state. Use this checklist: - Windows Server 2025 is installed, patched, and has a stable hostname. - The server is joined to the Active Directory domain used for RDS users. - Forward and reverse DNS resolution works between the RDS servers and domain controllers. - You have a domain account with the administrative rights needed to add and configure RDS roles. - The intended RDS user group already exists, or you have a naming plan for it. - You have decided whether users receive a full desktop, RemoteApp programs, or both. - You have decided which licensing entitlement applies: customer-owned RDS CALs or Raff-provided SPLA RDS SALs. - You have a backup or snapshot before major role changes. - You know whether users will connect only over a private path or need RD Gateway for internet access. - If you will use User Profile Disks, you have a central SMB share plan and backup plan for that share. For a new Raff VM, complete the [Windows Server initial setup](/windows-server/windows-server-initial-setup-checklist) before adding RDS roles. > **Compatible with Raff:** A prior Raff lab on May 24, 2026 used Windows Server 2025 Datacenter Evaluation, build 26100, and verified the main RDS role components could be installed and detected after restart. The complete workflow in this draft still requires a fresh end-to-end test before publication. ![PowerShell output showing Remote Desktop Services roles installed after restart on a Raff Windows Server lab VM.](https://raff-images.s3.raffusercloud.com/09_rds_roles_installed_after_restart_8b2ad45d71.png) The prior lab gives us a real baseline for role availability. It does **not** justify claiming that the complete deployment, licensing, collection, profile, and user-access workflow below has been freshly tested. ## Step 1 — Add the RDS servers to Server Manager Open **Server Manager** on the server that will manage the deployment. Go to: ```text Manage → Add Servers → Find Now ``` Add every Windows Server that will hold an RDS role. For a small deployment, your inventory might look like this: | Example server | Planned role | |---|---| | `RDS-CB01.corp.example` | RD Connection Broker + RD Web Access + RD Licensing | | `RDS-SH01.corp.example` | RD Session Host | For a single-server lab, one domain-joined Windows Server can hold several roles. Keep the role names distinct in your documentation even when they live on the same VM. Before continuing, confirm that Server Manager shows the target servers as **Online** and that there are no unresolved manageability errors. **Verification:** Server Manager can discover and manage every server that will participate in the RDS deployment. ## Step 2 — Create a Standard session-based RDS deployment In Server Manager, go to: ```text Manage → Add Roles and Features → Remote Desktop Services installation → Standard Deployment → Session-based desktop deployment ``` Do not choose **Quick Start** for this article. Quick Start is useful for a lab, but Standard Deployment makes the role assignment explicit and maps better to a production design. Assign the roles: 1. Select the server that will run **RD Connection Broker**. 2. Select the server that will run **RD Web Access**. 3. Select the server that will run **RD Session Host**. 4. Allow automatic restart if your maintenance window permits it. 5. Review the role mapping. 6. Start the deployment. 7. Wait for Server Manager to report a successful deployment. After the required restart, sign back in with the same administrative account. Run this PowerShell check from the Connection Broker: ```powershell Import-Module RemoteDesktop Get-RDServer ``` Microsoft documents `Get-RDServer` as the cmdlet for listing RDS servers and their roles in a Remote Desktop deployment. **Expected result:** The output lists the servers participating in the deployment and the RDS roles assigned to them. ## Step 3 — Add RD Licensing without treating the grace period as production licensing Open: ```text Server Manager → Remote Desktop Services → Overview → + RD Licensing ``` Select the server that will hold the RD Licensing role and complete the wizard. Then open **Remote Desktop Licensing Manager** from the RDS server list or Server Manager tools. The commercial entitlement path matters here: | Licensing path | What you should have before production | |---|---| | Customer-owned / BYOL RDS | Valid RDS CAL entitlement for the Windows Server version and chosen Per User or Per Device mode | | Raff-provided SPLA RDS | The applicable Raff RDS SAL entitlement and activation/onboarding details for the hosted service | Do not invent or reuse a license-pack key from another environment. The technical configuration must match the entitlement actually assigned to this deployment. Microsoft documents a **120-day licensing grace period** for a newly created RD Session Host. That window exists so you can deploy and configure RDS; it is not a reason to postpone the production licensing decision. On the Connection Broker, open: ```text Remote Desktop Services → Overview → Tasks → Edit Deployment Properties → RD Licensing ``` Choose the licensing mode that matches the deployment. For customer-owned RDS CALs: - domain-joined RDS deployments can use **Per User** or **Per Device**; - workgroup RDS deployments must use **Per Device**. Specify the RD Licensing server and save the deployment properties. Then verify the effective configuration: ```powershell Import-Module RemoteDesktop Get-RDLicenseConfiguration ``` If you are running the command from another server, specify the broker explicitly: ```powershell Get-RDLicenseConfiguration -ConnectionBroker 'RDS-CB01.corp.example' ``` **Verification:** PowerShell returns the intended licensing mode and the RD Licensing server for the deployment. ## Step 4 — Create an Active Directory group for RDS access Do not leave a production collection open to every domain user just because the wizard makes broad access convenient. Create a dedicated Active Directory security group for the people who should receive the desktop or application. Example: ```text RDS-Office-Users ``` Add only approved users to that group. A simple access model is: ```text User account → RDS-Office-Users → Session collection → RD Session Host ``` This keeps RDS authorization separate from local administrator rights and makes onboarding/offboarding easier to audit. Microsoft's collection-management guidance uses Active Directory groups as the authorization source for RDS collections. It also warns that the collection's user-group list cannot be empty: add the narrow group first, then remove a broad group such as Domain Users. **Verification:** The intended test user is a member of the dedicated RDS security group and is not being granted desktop access through an unrelated administrator group. ## Step 5 — Create the RDS session collection A session collection is the unit that ties together Session Hosts, authorized users, connection behavior, and profile settings. In Server Manager, open: ```text Remote Desktop Services → Collections → Tasks → Create Session Collection ``` Create a collection with a clear workload name, for example: ```text OfficeUsers ``` Then: 1. select the RD Session Host server or servers that belong to the collection; 2. add the dedicated Active Directory security group; 3. decide whether User Profile Disks will be enabled now or after the base collection is verified; 4. review the settings; 5. create the collection. You can validate the collection from PowerShell: ```powershell Import-Module RemoteDesktop Get-RDSessionCollection ` -CollectionName 'OfficeUsers' ` -ConnectionBroker 'RDS-CB01.corp.example' ``` Then confirm which Session Hosts belong to it: ```powershell Get-RDSessionHost ` -CollectionName 'OfficeUsers' ` -ConnectionBroker 'RDS-CB01.corp.example' ``` **Verification:** The collection exists, the correct RD Session Host appears inside it, and no unintended Session Host was added. ## Step 6 — Restrict the collection to the intended users Open the collection: ```text Remote Desktop Services → Collections → OfficeUsers → Tasks → Edit Properties → User groups ``` Add: ```text CORP\RDS-Office-Users ``` Once the specific group is present, remove broader access that the deployment does not need. You can inspect the collection authorization settings with PowerShell: ```powershell Get-RDSessionCollectionConfiguration ` -CollectionName 'OfficeUsers' ` -UserGroup ` -ConnectionBroker 'RDS-CB01.corp.example' ``` **Verification:** Only the intended RDS security group, plus any deliberately documented administrative exception, can access the collection. For Raff RDS deployments, put users into scoped Active Directory groups before assigning collections; broad user access is harder to audit later. ## Step 7 — Choose the user profile strategy before onboarding users The profile decision becomes important as soon as you add a second RD Session Host or users need their settings to follow them. Use this starting matrix: | Profile model | Best fit | Main trade-off | |---|---|---| | Local Windows profiles | One Session Host, small environment, simple recovery | User state is tied to that host | | User Profile Disks (UPDs) | Classic RDS collection where users can land on different Session Hosts | Central SMB share becomes part of the availability and backup design | | Another enterprise profile platform | Existing organization standard with its own support model | More moving parts; follow that platform's documentation | Microsoft describes a User Profile Disk as a **per-user, per-collection VHD/VHDX stored on a central share** and mounted when the user signs in. UPDs can roam only inside the collection in which they are configured. If you enable UPDs, prepare a dedicated central SMB share. Example UNC path: ```text \\RDS-FS01.corp.example\RDSProfiles$ ``` Do not place user profile disks on an ordinary shared folder with loose permissions. Microsoft requires the servers in the collection to have the access needed to manage the profile disks. In Server Manager: ```text Remote Desktop Services → Collections → OfficeUsers → Tasks → Edit Properties → User Profile Disks ``` Enable User Profile Disks and specify: - the central UNC path; - the maximum profile-disk size; - any include/exclude policy required for the workload. Then inspect the configuration: ```powershell Get-RDSessionCollectionConfiguration ` -CollectionName 'OfficeUsers' ` -UserProfileDisk ` -ConnectionBroker 'RDS-CB01.corp.example' ``` **Verification:** The collection reports the intended profile-disk path and size. After the first test-user sign-in, confirm a user profile disk is created on the profile share. ## Step 8 — Configure the collection settings deliberately A working collection can still be a poor production environment if session behavior is left unreviewed. Open: ```text Remote Desktop Services → Collections → OfficeUsers → Tasks → Edit Properties ``` Review at least these areas: | Setting area | Decision to document | |---|---| | User groups | Who can connect | | Session | Idle and disconnected-session limits | | Security | Authentication and encryption requirements | | Client settings | Clipboard, printer, drive, audio, and device redirection | | User Profile Disks | Local profiles vs central profile storage | | Load balancing | Relevant when more than one Session Host exists | Do not disable security controls simply to make an old client connect. Fix the client, certificate, identity, or access architecture instead. For environments with several Session Hosts, keep them at the same Windows Server version inside a collection and use Connection Broker to manage user reconnection and distribution. **Verification:** Export or record the final collection settings so another administrator can explain why each non-default value exists. ## Step 9 — Verify the RDS deployment before adding business applications Run the validation from the Connection Broker. ```powershell Import-Module RemoteDesktop $Broker = 'RDS-CB01.corp.example' $Collection = 'OfficeUsers' Get-RDServer -ConnectionBroker $Broker Get-RDSessionCollection ` -CollectionName $Collection ` -ConnectionBroker $Broker Get-RDSessionHost ` -CollectionName $Collection ` -ConnectionBroker $Broker Get-RDLicenseConfiguration ` -ConnectionBroker $Broker Get-RDSessionCollectionConfiguration ` -CollectionName $Collection ` -UserGroup ` -ConnectionBroker $Broker Get-RDSessionCollectionConfiguration ` -CollectionName $Collection ` -UserProfileDisk ` -ConnectionBroker $Broker ``` The deployment is ready for a controlled user test when all of these checks are true: - Connection Broker reports the expected RDS servers and roles. - The session collection exists. - The correct Session Host belongs to the collection. - The licensing mode and license server match the intended entitlement. - The intended Active Directory group is authorized. - The profile configuration matches the design. - A non-administrator test user can sign in. - The user receives only the desktop or resources intended for the collection. - Sign-out completes cleanly. - If UPDs are enabled, the user profile disk is created and remounts on the next sign-in. Do this verification **before** installing accounting software, ERP clients, Office applications, or other business workloads. That separates an RDS infrastructure problem from an application problem. ## Public internet access should be a separate security decision A successful Session Host deployment does not mean you should expose RDP broadly to the internet. If end users connect from external networks, review [Remote Desktop Gateway vs Direct RDP](/windows-server/remote-desktop-gateway-vs-direct-rdp) before rollout. The clean sequence is: ```text Build RDS → verify users and collections → configure licensing → verify profiles → design external access → harden and monitor → onboard production users ``` Keeping RD Gateway out of this tutorial prevents two different jobs from becoming one oversized procedure. ## Scaling should add Session Hosts without changing collection ownership Once the first collection works, scaling should be deliberate. Microsoft supports adding RD Session Hosts to an existing deployment and collection. The Connection Broker can then reconnect users to existing sessions and distribute new connections across available hosts. Before adding another Session Host: - keep the Session Hosts in the collection at the same Windows Server version; - confirm the applications support multi-session use; - make sure the profile strategy is no longer tied to one local host; - document how application updates will stay consistent across hosts; - confirm the license entitlement covers the authorized users or devices; - test maintenance mode and user reconnection behavior. Do not add a second Session Host as a performance fix until you know whether the actual constraint is CPU, RAM, storage, profile I/O, an application, or the network path. Use the [RDP performance tuning guide](/windows-server/rdp-performance-tuning) for that diagnosis. ## Common RDS configuration mistakes ### Building RDS before the server has working domain and DNS configuration Connection Broker, collections, user groups, and profile shares depend on reliable identity and name resolution. Fix the base Windows environment first. ### Treating the 120-day grace period as a licensing strategy The grace period is a technical deployment window. Production still needs the correct customer CAL or Raff SPLA RDS SAL entitlement. ### Leaving Domain Users on every collection Broad collection access is easy to create and hard to audit. Use named security groups that match the workload. ### Mixing Windows Server versions inside one collection Microsoft requires Session Hosts in a collection to stay at the same OS level. Create another collection when a staged upgrade needs a different version. ### Using local profiles after adding multiple Session Hosts A user who lands on another Session Host can get a different local profile. Choose a roaming profile strategy before scaling. ### Putting profile disks on an unprotected share The profile share is user-state infrastructure. Back it up, restrict access, monitor capacity, and include it in recovery planning. ### Installing applications before the base RDS deployment works First prove that Connection Broker, licensing, collection access, user sign-in, and profiles work. Add the application layer afterward. ### Publishing direct internet RDP as the final user-access design Direct RDP and RD Gateway are separate architecture decisions. Use a controlled external-access design for production users. ## Raff's recommended build order keeps troubleshooting simple For a small multi-user Windows environment, build the platform in layers: 1. deploy and patch Windows Server; 2. join the domain and verify DNS; 3. create the Standard session-based RDS deployment; 4. add and configure RD Licensing; 5. create a dedicated RDS user group; 6. create the session collection; 7. configure the user profile model; 8. validate one non-admin user end to end; 9. configure external access and hardening; 10. install the production business applications; 11. onboard users gradually; 12. measure CPU, RAM, storage, login time, and session behavior before scaling. This order gives each failure a smaller search area. A login problem before the application is installed is an RDS, identity, profile, or access problem. A login that works until the business app starts gives you a different diagnostic path. ## Remote Desktop Services configuration is complete when users can be verified end to end A complete **Remote Desktop Services configuration** is more than installing the Session Host role. Connection Broker must know the deployment, licensing must match the real entitlement, the collection must authorize the right users, and the profile model must survive the way users actually connect. On Raff, finish the RDS platform first, then add RD Gateway, hardening, backups, monitoring, and the business workload as separate layers. ## FAQ ### What is Remote Desktop Services configuration on Windows Server 2025? Remote Desktop Services configuration combines RD Session Host, Connection Broker, licensing, collections, user authorization, and profile settings so multiple users can run managed Windows sessions. ### Does an RDS deployment need Active Directory? A Standard RDS deployment with Connection Broker and collections is designed around domain-backed identity. Microsoft also documents limited Session Host configurations without Connection Broker for workgroups, but recommends Standard Deployment when possible. ### Do I need RDS CALs for every Raff RDS user? Customer-owned Windows Server RDS uses the applicable RDS CAL model. Raff-provided hosted licensing uses the applicable SPLA RDS SAL model. Administrative RDP sessions are a different use case. ### How long is the RDS licensing grace period? Microsoft documents a 120-day grace period for a newly created RD Session Host. Use that window to deploy and validate licensing, not as a permanent production licensing method. ### Should I use User Profile Disks for RDS? Use User Profile Disks when users need their Windows profile to follow them between Session Hosts in the same collection. A one-host environment can stay simpler with local profiles if that matches the recovery plan. ### Can I put all RDS roles on one Windows Server? You can combine roles for a small or lab deployment, but production architecture should consider maintenance, recovery, user count, and future Session Host scaling before placing every role on one VM. ## What's next - [RDS CAL Licensing on Windows Server](/windows-server/rds-cal-licensing-guide) — choose the correct RDS entitlement and licensing mode. - [Remote Desktop Gateway vs Direct RDP](/windows-server/remote-desktop-gateway-vs-direct-rdp) — design the external user-access path. - [Multi-User RDP vs RDS Session Host](/windows-server/multi-user-rdp-vs-rds) — confirm RDS is the right access model. - [RDP Performance Tuning](/windows-server/rdp-performance-tuning) — diagnose slow or unstable sessions after rollout. - [Windows Server Licensing on Raff](/windows-server/windows-licensing) — understand Evaluation, SPLA, and BYOL for the operating system. - [Remote Desktop VPS](/products/remote-desktop-vps) — review the Windows VM product and deployment path. ## Sources - Microsoft Learn — [Deploy your Remote Desktop environment](https://learn.microsoft.com/en-us/windows-server/remote/remote-desktop-services/rds-deploy-infrastructure) - Microsoft Learn — [Build and deploy your Remote Desktop Services deployment](https://learn.microsoft.com/en-us/windows-server/remote/remote-desktop-services/rds-build-and-deploy) - Microsoft Learn — [Remote Desktop Services roles](https://learn.microsoft.com/en-us/windows-server/remote/remote-desktop-services/rds-roles) - Microsoft Learn — [Supported configurations for Remote Desktop Services](https://learn.microsoft.com/en-us/windows-server/remote/remote-desktop-services/rds-supported-config) - Microsoft Learn — [License Remote Desktop Services with Client Access Licenses](https://learn.microsoft.com/en-us/windows-server/remote/remote-desktop-services/rds-client-access-license) - Microsoft Learn — [License Remote Desktop session hosts](https://learn.microsoft.com/en-us/windows-server/remote/remote-desktop-services/rds-license-session-hosts) - Microsoft Learn — [Manage users in your RDS collection](https://learn.microsoft.com/en-us/windows-server/remote/remote-desktop-services/rds-user-management) - Microsoft Learn — [Secure data storage with User Profile Disks](https://learn.microsoft.com/en-us/windows-server/remote/remote-desktop-services/rds-plan-secure-data-storage) - Microsoft Learn PowerShell — [RemoteDesktop module](https://learn.microsoft.com/en-us/powershell/module/remotedesktop/?view=windowsserver2025-ps) - Microsoft Learn PowerShell — [Get-RDServer](https://learn.microsoft.com/en-us/powershell/module/remotedesktop/get-rdserver?view=windowsserver2025-ps) - Microsoft Learn PowerShell — [Get-RDLicenseConfiguration](https://learn.microsoft.com/en-us/powershell/module/remotedesktop/get-rdlicenseconfiguration?view=windowsserver2025-ps) - Microsoft Learn PowerShell — [Get-RDSessionCollectionConfiguration](https://learn.microsoft.com/en-us/powershell/module/remotedesktop/get-rdsessioncollectionconfiguration?view=windowsserver2025-ps) --- --- ### How to Publish RemoteApp and Set Up the Remote Desktop Web Client on Windows Server 2025 URL: https://rafftechnologies.com/windows-server/remote-desktop-web-client-windows-server-2025 Description: Publish RemoteApp programs on Windows Server 2025 and set up the Remote Desktop web client with RD Web Access, broker certificates, licensing checks, and browser-based access. ## In short To publish **RemoteApp** and make it available through the **Remote Desktop web client** on Windows Server 2025, first validate the underlying Remote Desktop Services deployment, publish the application from the target session collection, install the `RDWebClientManagement` PowerShell module on the RD Web Access server, import the RD Connection Broker certificate, publish the web client package, and test access from a supported browser. This guide owns one specific workflow: ```text Working Windows Server 2025 RDS deployment → session collection → publish RemoteApp → verify user authorization → prepare RD Web Access → install RDWebClientManagement → import RD Broker certificate → publish the web client → open the web-client URL → launch the RemoteApp as a normal user → verify licensing, certificates, redirection and sign-out ``` It does **not** replace the broader [Remote Desktop Services Configuration on Windows Server 2025](/windows-server/remote-desktop-services-configuration) guide. That page owns the base RDS deployment. This page starts when Connection Broker, RD Web Access, RD Session Host, licensing, and a session collection already exist. Microsoft's current documentation lists Windows Server 2025 for the Remote Desktop web client and RDS collection workflows used in this guide. Because RDS architecture, certificates, licensing, and application behavior vary by environment, validate the sequence in your own deployment before production rollout. ## Why use RemoteApp with the Remote Desktop web client? RemoteApp lets an administrator publish a specific Windows application from an RD Session Host instead of giving every user a full Windows desktop. The Remote Desktop web client gives authorized users a browser-based way to reach the applications and desktops published to them. That combination can fit teams that need centrally hosted Windows software but want a narrower user experience than a full remote desktop. | Requirement | RemoteApp + web client fit | |---|---| | Users need one or several Windows applications | Strong fit | | Users should not receive a full server desktop | Strong fit | | Users connect from Windows, macOS, ChromeOS, or Linux browsers | Good fit with supported browsers | | Users need mobile-browser access | Not a fit; Microsoft currently says mobile devices are not supported by the web client | | Users need a complete Windows desktop | Publish a desktop collection instead of only RemoteApps | | Users connect from the public internet | Plan RD Gateway, certificates, MFA, and external access separately | Microsoft documents web-client access from modern browsers on Windows, macOS, ChromeOS, and Linux. The user still needs valid RDS authorization and the correct published resource. ## Prerequisites Do not begin with the web-client PowerShell module if the underlying RDS deployment is not already healthy. Confirm the following first: - Windows Server 2025 is patched. - The RDS deployment has an RD Connection Broker. - RD Web Access is installed and operational. - At least one RD Session Host is part of a session collection. - The application you want to publish is installed on every Session Host that can serve the collection. - A normal Active Directory test user can access the collection. - RDS licensing is configured for the intended production model. - DNS resolves the names used by the deployment. - Certificates for the RDS deployment are installed and trusted as required. - External users have a controlled access path such as RD Gateway where the architecture requires it. - You have a rollback path before changing the production web client. If the base RDS deployment is incomplete, finish [Remote Desktop Services Configuration on Windows Server 2025](/windows-server/remote-desktop-services-configuration) first. ### Licensing warning before web-client rollout RemoteApp sessions are Remote Desktop Services sessions. A browser does not remove the licensing requirement. Microsoft's current web-client administration guidance warns that the web client should be used with a **Per User** RDS CAL configuration rather than Per Device because Per Device mode can result in licenses being consumed incorrectly for web-client users. Review [RDS CAL Licensing on Windows Server](/windows-server/rds-cal-licensing-guide) before production rollout. If Raff provides the RDS workload under a hosted service-provider licensing model, confirm the applicable hosted RDS entitlement separately. ## Step 1 — Verify the session collection Open **Server Manager** on the RDS management server. Go to: ```text Remote Desktop Services → Collections → select the target collection ``` For this example, assume the collection is named: ```text OfficeApps ``` Before publishing an application, verify: 1. the expected RD Session Host belongs to the collection; 2. the intended user or Active Directory group is authorized; 3. the application exists on the Session Host at the expected path; 4. the collection is configured for the resource model you intend to publish. You can inspect collections with PowerShell: ```powershell Import-Module RemoteDesktop Get-RDSessionCollection ``` Then inspect the target collection: ```powershell Get-RDSessionCollection ` -CollectionName 'OfficeApps' ``` **Verification:** Server Manager and PowerShell should both show the intended collection and Session Host. ## Step 2 — Install and test the application on the Session Host RemoteApp does not package or virtualize the application for you. The application must already run correctly on the RD Session Host. Before publication, validate: - the application launches; - required runtimes are installed; - file paths work; - database or API connectivity works; - the application can save data; - user-specific configuration behaves correctly; - the application's own license permits multi-user/RDS use; - updates and reboots do not break the application path. Do not publish an application to users before it works locally on the Session Host under the intended user context. ## Step 3 — Publish the RemoteApp from Server Manager Open: ```text Server Manager → Remote Desktop Services → Collections → OfficeApps → RemoteApp Programs → Tasks → Publish RemoteApp Programs ``` Select the application you want to publish and complete the wizard. After publication, the application should appear under **RemoteApp Programs** for that collection. Microsoft also provides the `New-RDRemoteApp` cmdlet. Example: ```powershell Import-Module RemoteDesktop New-RDRemoteApp ` -CollectionName 'OfficeApps' ` -DisplayName 'Contoso Accounting' ` -FilePath 'C:\Program Files\Contoso\Accounting.exe' ` -ShowInWebAccess $true ``` Replace the example application name and path with the actual executable. `-ShowInWebAccess $true` makes the RemoteApp eligible to appear through RD Web Access for authorized users. Verify the result: ```powershell Get-RDRemoteApp -CollectionName 'OfficeApps' ``` ## Step 4 — Restrict the RemoteApp to the correct users Publishing the program is not the same as authorizing every user. Use the collection's user group plus RemoteApp-specific restrictions where needed. A practical structure is: ```text AD user → RDS application security group → session collection authorization → RemoteApp authorization → published application ``` For example: ```text CORP\RDS-Accounting-Users ``` `New-RDRemoteApp` supports `-UserGroups` when a RemoteApp should be scoped more narrowly. ```powershell New-RDRemoteApp ` -CollectionName 'OfficeApps' ` -DisplayName 'Contoso Accounting' ` -FilePath 'C:\Program Files\Contoso\Accounting.exe' ` -ShowInWebAccess $true ` -UserGroups 'CORP\RDS-Accounting-Users' ``` Test with both an authorized and an unauthorized user. A proper security test proves that users who should not receive the application cannot see or launch it. ## Step 5 — Confirm RD Web Access is working RD Web Access is part of the Remote Desktop Services deployment and provides the resource layer used by authorized users. Before adding the web client, verify the RD Web Access role is healthy and that the deployment certificates and DNS names are correct. The web client is not a replacement for Connection Broker or RD Web Access. It presents published applications and desktops through the browser on top of the existing RDS deployment. For external access, do not expose Session Hosts directly just because browser access works. Review [Remote Desktop Gateway vs Direct RDP](/windows-server/remote-desktop-gateway-vs-direct-rdp) and [Add MFA to Remote Desktop Services](/windows-server/add-mfa-remote-desktop-services-windows-server) before public rollout. ## Step 6 — Install the RDWebClientManagement module On the RD Web Access server, open **PowerShell as Administrator**. Install the module: ```powershell Install-Module -Name RDWebClientManagement ``` If PowerShell asks whether you trust the repository, verify that you are using the expected PowerShell Gallery source before accepting. After installation, open a fresh elevated PowerShell session and verify the module: ```powershell Get-Module -ListAvailable RDWebClientManagement ``` List its commands: ```powershell Get-Command -Module RDWebClientManagement ``` ## Step 7 — Download the latest Remote Desktop web client package Run: ```powershell Install-RDWebClientPackage ``` This downloads the current web-client package supported by Microsoft's management module. Avoid hard-coding a package version unless you have a specific reason to pin it. ## Step 8 — Export the RD Connection Broker certificate The web client requires the RD Connection Broker certificate to be imported into the web-client configuration. Use the certificate currently assigned to the RDS deployment's Connection Broker role. Export the public certificate as a `.cer` file. Do not export or expose the private key for this step. Example path: ```text C:\RDS\BrokerCert.cer ``` Verify: - the certificate corresponds to the Connection Broker configuration; - the certificate is valid and not expired; - the expected name is present; - the public certificate file is available on the RD Web Access server; - no private key is exposed unnecessarily. ## Step 9 — Import the RD Broker certificate into the web client On the RD Web Access server, run: ```powershell Import-RDWebClientBrokerCert 'C:\RDS\BrokerCert.cer' ``` Microsoft instructs administrators to run this again when the RD Broker certificate is renewed or replaced. If the broker certificate changes but the web client configuration is not updated, users can receive an **unexpected server authentication certificate** error. ## Step 10 — Publish the Remote Desktop web client Microsoft supports publishing a **Test** package first and then a **Production** package. Start with the test client: ```powershell Publish-RDWebClientPackage -Type Test -Latest ``` After validation, publish production: ```powershell Publish-RDWebClientPackage -Type Production -Latest ``` Microsoft documents the production URL format as: ```text https://server_FQDN/RDWeb/webclient/index.html ``` The hostname should match the name covered by the RD Web Access public certificate. The corresponding test path is: ```text https://server_FQDN/RDWeb/webclient-test/index.html ``` ## Step 11 — Sign in as a normal user From a supported desktop browser, open the production or test URL. Microsoft currently documents support for modern browsers including: - Microsoft Edge; - Google Chrome; - Apple Safari; - Mozilla Firefox 55 or later. The web client can be used from Windows, macOS, ChromeOS, and Linux. Microsoft currently says mobile devices are not supported by the web client. Sign in using the format expected by the RDS environment, commonly: ```text DOMAIN\username ``` Use a normal non-administrator test account that belongs to the intended RDS application group. The **All Resources** view should show only the applications and desktops assigned to that user. ## Step 12 — Launch the RemoteApp from the browser Select the published application. The browser may ask for permission to redirect local resources such as clipboard or printer access. Choose settings that match your policy. Test more than whether the application window opens: | Check | Expected result | |---|---| | Authentication | Normal user can sign in | | Authorization | User sees only assigned resources | | Application launch | RemoteApp opens successfully | | Application identity | Correct application and version opens | | File access | Intended server-side paths work | | Clipboard | Works or is blocked according to policy | | Printing | Works or is blocked according to policy | | Reconnect | Session behavior matches design | | Sign-out | Session closes cleanly | | Unauthorized user | Cannot see or launch the RemoteApp | If the application launches only for an administrator, fix application permissions or user-profile dependencies rather than granting administrator rights to end users. ## Step 13 — Verify the URL and certificate chain externally Test from a client that is not the RD Web Access server itself. Verify: - the public hostname resolves correctly; - the certificate presented by the web endpoint is trusted; - there are no browser certificate warnings; - the URL hostname matches the certificate; - external access reaches the intended gateway/web-access path; - internal Session Hosts are not accidentally exposed directly to the internet; - the application launches from the intended user network. For public production access, use [Remote Desktop Gateway vs Direct RDP](/windows-server/remote-desktop-gateway-vs-direct-rdp) to validate the external access architecture. ## RemoteApp vs full desktop publishing Use RemoteApp when users need only one or several Windows applications rather than a complete Windows desktop. | User need | Better publication model | |---|---| | One accounting, ERP, or business application | RemoteApp | | Two or three focused line-of-business apps | RemoteApp | | Complete Windows work environment | Full Remote Desktop | | Server administration | Administrative access, not normal RemoteApp access | | Browser access to a hosted Windows application | RemoteApp + web client can fit | Do not publish a full desktop simply because it is easier if the real requirement is only one application. Narrower publication reduces the normal user's accessible surface and provides a more focused experience. ## How to update the Remote Desktop web client later When Microsoft publishes a newer client package, use: ```powershell Install-RDWebClientPackage ``` Optionally publish it to the test endpoint first: ```powershell Publish-RDWebClientPackage -Type Test -Latest ``` Then promote it to production: ```powershell Publish-RDWebClientPackage -Type Production -Latest ``` Use a test user before promoting an update when RemoteApp is business-critical. ## Certificate renewal procedure When the RD Broker certificate is renewed or replaced: 1. export the new public certificate as `.cer`; 2. copy it to the RD Web Access server; 3. import it again with `Import-RDWebClientBrokerCert`; 4. republish the production web client; 5. test a RemoteApp launch. Example: ```powershell Import-RDWebClientBrokerCert 'C:\RDS\BrokerCert-New.cer' Publish-RDWebClientPackage -Type Production -Latest ``` ## Common Remote Desktop web client problems ### The RemoteApp does not appear Check: - the program is published in the correct collection; - `ShowInWebAccess` is enabled; - the test user is in the collection's allowed group; - RemoteApp-specific user groups allow the user; - the user signed into the correct RDS deployment; - RD Web Access can reach the deployment correctly. ### The web client loads but the app does not launch Check: - RD Connection Broker health; - Session Host health; - RD Gateway/external access path; - certificates; - user authorization; - RDS licensing; - application executable permissions; - event logs on the RDS servers. ### Unexpected server authentication certificate error If the RD Broker certificate was renewed or replaced, re-import the new broker certificate: ```powershell Import-RDWebClientBrokerCert 'C:\RDS\BrokerCert-New.cer' ``` Then republish the production client. ### The browser shows a certificate warning Verify the hostname used in the URL matches the RD Web Access public certificate and that the certificate chain is trusted by the client. ### Per-device licensing warnings appear Microsoft's web-client administration documentation warns about Per Device CAL mode and recommends Per User licensing for the web client. Review the licensing design rather than bypassing the warning. ### Users see more applications than expected Review both the collection authorization and each RemoteApp's user-group scope. Do not rely on hiding icons as an access-control mechanism. ## Security checklist before production rollout Before sending the URL to users, confirm: - [ ] RDS licensing matches the production deployment model. - [ ] Normal users have no unnecessary local administrator rights. - [ ] Only intended AD groups can access the session collection. - [ ] Each RemoteApp is scoped to the correct users/groups. - [ ] RD Web Access uses a trusted certificate. - [ ] The RD Broker certificate imported into the web client is current. - [ ] RD Gateway or another approved external-access architecture is configured where required. - [ ] MFA is enabled when the risk model requires it. - [ ] Session Hosts are not broadly exposed through public RDP. - [ ] Clipboard, drive, printer, and device redirection policies are intentional. - [ ] Windows Server and the published application are patched. - [ ] Backups and restore testing exist for application data. - [ ] A normal user has passed the complete browser launch test. - [ ] An unauthorized user has been tested and denied. ## Where Raff fits Raff Windows VMs can provide the Windows Server infrastructure used for RD Session Host, Connection Broker, RD Web Access, and other RDS roles in a planned deployment. The RDS architecture, Microsoft licensing, application licensing, certificates, user groups, gateway design, MFA integration, and application testing still need to be configured for the production environment. For teams evaluating server capacity, use [Windows VPS Sizing for Remote Users](/windows-server/windows-vps-sizing-remote-users) before moving several users onto one Session Host. :::cta Deploy Windows Now Deploy a Raff Windows VM for your Windows Server 2025 RDS environment and configure the RDS roles, licensing, certificates, and application workflow for your users. ::: ## Frequently asked questions ### What is the Remote Desktop web client? The Remote Desktop web client is Microsoft's browser-based client for accessing remote desktops and RemoteApp resources published by a Remote Desktop Services deployment. Users sign in through a supported desktop browser and receive the resources they are authorized to use. ### Does the Remote Desktop web client work with Windows Server 2025? Microsoft's current web-client documentation lists Windows Server 2025 as an applicable platform. ### Do users need RDS CALs for RemoteApp through the web client? RemoteApp is Remote Desktop Services functionality. The browser client does not remove the applicable RDS licensing requirement. Microsoft also warns that the web client should be used with Per User rather than Per Device CAL configuration. ### Can I publish both RemoteApps and a full desktop from the same collection? Design the collection around the resource type you intend to expose. Microsoft documents different collection publication states for full desktops and RemoteApps, so validate the intended model before rollout. ### What URL do users open? Microsoft documents the production web-client path as `https://server_FQDN/RDWeb/webclient/index.html`, using the server name that matches the RD Web Access public certificate. ### Why do I need the RD Broker certificate? The web client uses the imported RD Connection Broker certificate as part of validating the RDS connection. Microsoft instructs administrators to re-import it whenever the broker certificate is renewed or replaced. ### Can users access the web client from a phone or tablet? Microsoft currently says mobile devices are not supported by the Remote Desktop web client. Use a supported Remote Desktop client for mobile scenarios. ## What's next - [Remote Desktop Services Configuration on Windows Server 2025](/windows-server/remote-desktop-services-configuration) - [RDS CAL Licensing Guide](/windows-server/rds-cal-licensing-guide) - [Remote Desktop Gateway vs Direct RDP](/windows-server/remote-desktop-gateway-vs-direct-rdp) - [Add MFA to Remote Desktop Services on Windows Server 2025](/windows-server/add-mfa-remote-desktop-services-windows-server) - [Windows VPS Sizing for Remote Users](/windows-server/windows-vps-sizing-remote-users) - [Remote Desktop VPS](/products/remote-desktop-vps) ## Sources - Microsoft Learn — Create a Remote Desktop Services collection: https://learn.microsoft.com/en-us/windows-server/remote/remote-desktop-services/rds-create-collection - Microsoft Learn — Set up the Remote Desktop web client for your users: https://learn.microsoft.com/en-us/windows-server/remote/remote-desktop-services/remote-desktop-web-client-admin - Microsoft Learn — Get started with the Remote Desktop web client: https://learn.microsoft.com/en-us/windows-server/remote/remote-desktop-services/remote-desktop-web-client - Microsoft Learn PowerShell — New-RDRemoteApp: https://learn.microsoft.com/en-us/powershell/module/remotedesktop/new-rdremoteapp?view=windowsserver2025-ps - Microsoft Learn PowerShell — Set-RDRemoteDesktop: https://learn.microsoft.com/en-us/powershell/module/remotedesktop/set-rdremotedesktop?view=windowsserver2025-ps - Microsoft Learn — Deploy your Remote Desktop environment: https://learn.microsoft.com/en-us/windows-server/remote/remote-desktop-services/rds-deploy-infrastructure - Microsoft Learn — Remote Desktop Services overview: https://learn.microsoft.com/en-us/windows-server/remote/remote-desktop-services/overview - Sources verified: 2026-08-28 --- ### Secure Direct RDP on a Windows VPS: NLA, IP Allowlisting, and Lockout Policy URL: https://rafftechnologies.com/windows-server/secure-direct-rdp-windows-vps Description: Learn how to secure direct RDP access on a Windows VPS using Network Level Authentication, firewall restrictions, IP allowlisting, account lockout policies, authentication monitoring, and practical hardening steps. ## In short A secure Windows VPS starts with secure remote access. Direct RDP is convenient for administration, but exposing Remote Desktop without protection creates unnecessary risk. The recommended approach is to enable Network Level Authentication (NLA), restrict access with firewall rules and IP allowlisting, protect administrator accounts, configure lockout policies, and monitor authentication activity. This guide focuses on securing direct RDP access to a Windows VPS. It does not replace a full Remote Desktop Services deployment or RD Gateway architecture. ## Why Direct RDP needs hardening Windows VPS servers are commonly targeted because attackers continuously scan public IP addresses for exposed remote access services. Most attacks do not exploit advanced vulnerabilities; they rely on: - weak or reused passwords; - exposed administrator accounts; - unrestricted internet access to TCP 3389; - outdated operating systems; - lack of monitoring. A secure Windows VPS configuration reduces the attack surface before attackers reach the login screen. ## Before changing RDP security settings Avoid locking yourself out while hardening a remote server. Before making changes: - confirm you have working administrator access; - keep an active RDP session open while changing firewall settings; - create a recovery plan or snapshot if available; - test security changes one by one; - avoid removing your only administrator access path. Security improvements should make access more controlled, not impossible for legitimate administrators. ## Direct RDP security checklist Before allowing administrative access: - Enable Network Level Authentication (NLA). - Restrict inbound RDP traffic. - Use IP allowlisting where possible. - Limit who can log in through RDP. - Configure account lockout protection. - Keep Windows Server updated. - Review failed authentication events. - Remove unused accounts. ![Windows Server Remote Desktop settings showing Network Level Authentication enabled for secure RDP connections](https://raff-images.s3.raffusercloud.com/01_enable_rdp_network_level_authentication_e73901fcbf.png) Show: - System Properties → Remote tab - Network Level Authentication checkbox enabled ## Enable Network Level Authentication (NLA) Network Level Authentication requires users to authenticate before a full remote desktop session is created. Benefits: - reduces unnecessary session exposure; - prevents unauthenticated session creation; - adds an additional protection layer before the desktop loads. Verify: ```text System Properties → Remote → Allow connections only from computers running Remote Desktop with Network Level Authentication ``` NLA should be enabled on production Windows VPS deployments unless there is a specific compatibility requirement. ![Windows Defender Firewall inbound rule showing restricted Remote Desktop access with allowed IP addresses](https://raff-images.s3.raffusercloud.com/02_rdp_firewall_ip_allowlist_f9bd7b236d.png) Show: - Remote Desktop TCP-In rule - Scope tab - Allowed remote IP addresses ## Restrict RDP exposure with Windows Firewall A common mistake is allowing RDP from every internet address. A stronger approach is restricting access to known administrator networks: Examples: - company office IP range; - VPN network; - administrator home IP; - private management network. Windows Firewall allows administrators to control which remote IP addresses can reach RDP. The goal is not simply changing the RDP port. Reducing who can reach the service is a much stronger security improvement. ## Protect Windows administrator access RDP security depends heavily on account security. Recommended practices: - avoid using the built-in Administrator account for daily work; - create separate administrator accounts for different people; - remove unused users from Remote Desktop access; - review members of the Administrators group; - use strong unique passwords. You can review who can access RDP through: ```text Local Security Policy → Local Policies → User Rights Assignment → Allow log on through Remote Desktop Services ``` Only users who actually require remote administration should have access. ![Windows Defender Firewall inbound rule showing restricted Remote Desktop access with allowed IP addresses](https://raff-images.s3.raffusercloud.com/03_rdp_account_lockout_policy_ce8ea80d00.png) Show: - Account lockout threshold - Account lockout duration - Reset counter setting ## Configure account lockout protection Account lockout policies reduce the effectiveness of password guessing attacks. Configure through: ```text Local Security Policy → Account Policies → Account Lockout Policy ``` Important settings: - Account lockout threshold: failed attempts before locking. - Account lockout duration: how long the account remains locked. - Reset account lockout counter: how quickly failed attempts are cleared. Choose values that balance security and operational availability. Extremely aggressive lockout policies can create unnecessary administration problems. ![Windows Local Security Policy showing Account Lockout Policy settings for failed login protection](https://raff-images.s3.raffusercloud.com/04_rdp_failed_login_event_monitoring_910a8c4c12.png) Show: - Windows Logs → Security - Event ID 4625 - Failure information ## Monitor failed RDP and authentication attempts Windows Security logs provide visibility into authentication activity. Useful events include: - Event ID 4625 — failed logon. - Event ID 4624 — successful logon. Administrators can investigate: - repeated failed attempts; - unusual login times; - unexpected user accounts; - suspicious access locations. Event monitoring is especially important when a Windows VPS is hosting business applications or remote users. ## Additional Windows VPS RDP hardening steps Beyond the core protections above, consider: ### Keep Windows Server updated Security patches protect against known vulnerabilities. Maintain a regular update process and test important updates before applying them to critical systems. ### Disable unnecessary RDP features Depending on your workload, review: - clipboard redirection; - drive redirection; - printer redirection; - device access. Reducing unnecessary features reduces the attack surface. ### Use backups and recovery planning A secure server also needs a recovery strategy. Snapshots, backups, and documented recovery procedures reduce operational risk. ## When Direct RDP is no longer enough Direct RDP works well for: - one administrator; - small teams; - controlled IP access. As requirements grow, consider: | Situation | Recommended approach | |---|---| | Single administrator | Secured direct RDP | | Multiple Windows users | Remote Desktop Services | | External employees | RD Gateway + MFA | | Business-critical workloads | Managed Windows infrastructure | For larger environments, move from basic RDP hardening toward centralized identity, MFA, and controlled access workflows. ## Choosing a secure Windows VPS provider RDP security is only one part of running Windows workloads. When choosing Windows VPS hosting, consider: - Can you recover quickly if access is lost? - Is Windows Server support available? - Can resources scale when workloads grow? - Are backups and infrastructure reliability considered? - Can you get help when production issues happen? A secure Windows VPS should combine good infrastructure with practical operational support. ## Final Secure RDP Checklist - [ ] Network Level Authentication enabled - [ ] RDP access restricted with firewall rules - [ ] IP allowlisting configured where possible - [ ] Only required users can access RDP - [ ] Account lockout policy configured - [ ] Failed authentication events monitored - [ ] Windows Server patched regularly - [ ] Backup and recovery plan available ## What's next - [hosted Remote Desktop](/products/remote-desktop-vps) — review the hosted Remote Desktop product path after securing direct RDP. - [Remote Desktop Services Configuration on Windows Server 2025](/windows-server/remote-desktop-services-configuration) - Deploy Remote Desktop Gateway on Windows Server 2025 - Add MFA to RD Gateway and RDS User Access --- ### RDP VPS: Using a Windows VPS for Remote Desktop URL: https://rafftechnologies.com/windows-server/windows-vps-for-remote-desktop Description: What an RDP VPS is, when a Windows VPS with RDP fits a small team, and how to plan sizing, security, licensing, and performance before users connect. An RDP VPS, a Windows VPS accessed over Remote Desktop, can be a practical remote desktop server when a small team needs secure access to Windows software, files, admin tools, or business applications from anywhere. Use normal admin RDP for server administration only. Use Remote Desktop Services with proper RDS CAL licensing when multiple users need their own desktop sessions for daily work. ## TL;DR * Use a Windows VPS for Remote Desktop when your team needs a cloud-hosted Windows environment instead of an office PC or local server. * The default RDP access model is for administration, not full multi-user desktop hosting. * If several employees need to work inside the server at the same time, plan for Remote Desktop Services and RDS CALs. * Performance depends on user count, application load, CPU, RAM, storage, network quality, and display settings. * Security matters because RDP is a high-value access path. Plan firewall rules, strong credentials, updates, backups, and monitoring before production. ## What an RDP VPS is and how it works Remote Desktop on a Windows VPS means connecting to a cloud-hosted Windows Server through Remote Desktop Protocol, usually from a local Windows, macOS, Linux, iOS, or Android device. ![Remote Desktop session connected to a Raff Windows VPS showing a Windows Server desktop for small business remote access.](https://raff-images.s3.raffusercloud.com/windows_vps_remote_desktop_session_webp_b57b683f60.png) The Windows VPS runs the desktop environment and applications. The user’s local device becomes the screen, keyboard, mouse, and audio endpoint. A simple model looks like this: ```text User device ↓ Remote Desktop client ↓ Windows VPS public IP or secured access path ↓ Windows Server session ↓ Business software, files, browser, admin tools, or server roles ``` This model is useful when the work needs to happen inside a Windows Server environment. Examples include: * Remote access to business software * Accounting tools * ERP clients * Admin dashboards * Browser-based internal tools * SQL Server tools * IIS administration * PowerShell administration * MetaTrader or other Windows-only software * Shared operational desktops * Temporary contractor access * Small office server replacement The important distinction is that Remote Desktop can mean two different things: | Use case | What it means | | ---------------- | --------------------------------------------------------------------------- | | Admin RDP | One or two administrators connect to manage the server | | RDS Session Host | Multiple users connect to use desktops or apps as a normal work environment | A small team should decide which model it needs before choosing the Windows VPS size, licensing path, and security setup. ## A Windows VPS is useful when the desktop must stay online A Windows VPS makes sense when the Windows environment should stay online even when a user’s laptop, office PC, or local network is unavailable. That is the practical reason many small teams move Remote Desktop workloads to a cloud server. Instead of keeping a desktop tower in the office, the team runs the Windows environment on a VPS and connects to it remotely. Users can access the same server from home, office, travel, or another device. This is especially useful when the workload depends on: * Windows-only software * A shared company file * A database running near the application * A stable desktop session * Long-running automation * 24/7 availability * Centralized administration * One server environment instead of many local PCs For example, an accounting team may want QuickBooks or Sage available from multiple locations. A developer may want a Windows Server environment for IIS and SQL Server. A trading operator may want a Windows session that keeps software running overnight. A Windows VPS gives these workloads a central place to run. The trade-off is operational responsibility. A VPS still needs updates, security controls, backups, user management, and performance monitoring. ## Admin RDP and RDS Session Host solve different problems The biggest mistake in Remote Desktop planning is treating admin RDP and multi-user Remote Desktop as the same thing. They are not the same. ![Decision visual comparing admin RDP and RDS Session Host for server management, multi-user desktop access, licensing, session type, common applications, support model, and best-fit business use cases.](https://raff-images.s3.raffusercloud.com/admin_rdp_vs_rds_session_host_webp_363dbc0d13.png) Admin RDP is for managing the server. It is suitable for administrators who need to sign in, configure services, install updates, check logs, or troubleshoot. RDS Session Host is for user desktops or app sessions. It is suitable when multiple people need to use the Windows environment for daily work. | Requirement | Better fit | | ------------------------------------------------- | ---------------- | | One admin needs to configure the server | Admin RDP | | Two admins occasionally troubleshoot | Admin RDP | | Five employees need daily desktop sessions | RDS Session Host | | Accounting staff need to run QuickBooks remotely | RDS Session Host | | Contractors need separate user sessions | RDS Session Host | | A developer needs IIS and SQL Server admin access | Admin RDP | | A team needs hosted Windows apps | RDS Session Host | For a deeper licensing and access breakdown, read [Multi-User RDP: 2 Admin Sessions vs RDS Session Host](/windows-server/multi-user-rdp-vs-rds). The simple rule: Use admin RDP to manage a server. Use Remote Desktop Services when users are working on the server. ## The decision framework for Remote Desktop on a Windows VPS Use this framework before turning a Windows VPS into a Remote Desktop environment. | Decision area | Admin RDP is usually enough when... | RDS Session Host is better when... | | ------------- | --------------------------------------- | ------------------------------------------------------- | | User count | One or two admins connect occasionally | Multiple employees need daily access | | Purpose | Server management | Desktop or application usage | | Session type | Occasional maintenance session | Separate user work sessions | | Licensing | Standard admin access is enough | RDS CAL planning is required | | Applications | Admin tools, PowerShell, IIS, SQL tools | Accounting, ERP, Office, browser apps, trading software | | Security | Small admin group | User access policy, MFA path, stronger auditing | | Performance | Light management workload | CPU/RAM sizing per user and application | | Support | IT/admin access only | End-user support and session management | | Best fit | Server administration | Remote work or hosted business software | This is the main decision. A Windows VPS can support both models, but the planning is different. Admin access is simple. Multi-user desktop hosting needs more thought around licensing, sizing, session limits, security, and support. :::cta deploy Deploy a Windows VM with full RDP access from $28.99 a month: $13.99 compute plus the $15.00 Windows Server licence. ::: ## Remote Desktop workloads are not all the same Remote Desktop performance depends on what users do inside the session. A single admin opening Server Manager is light. Five users running accounting software during tax season is not the same workload. A trader running multiple charts and expert advisors has different pressure than a bookkeeper entering invoices. | Workload | Typical pressure points | | --------------------------- | -------------------------------------------- | | Basic administration | Low CPU/RAM, occasional login | | Office-style desktop work | RAM, session count, display responsiveness | | Accounting software | RAM, disk, file/database access, backups | | SQL Server administration | RAM, database load, storage performance | | IIS and .NET management | CPU, RAM, app pools, logs | | MetaTrader or trading tools | CPU, RAM, uptime, latency, session stability | | Browser-heavy work | RAM, CPU, profile data | | Multi-user RDS | RAM per user, CPU, licensing, session policy | The more users and applications you add, the less the server behaves like a simple remote admin box. That is when sizing, session management, and performance tuning become important. ## Sizing a Windows VPS for Remote Desktop A Windows VPS for Remote Desktop should be sized around people, applications, and session behavior. ![Task Manager Performance tab showing CPU, memory, disk, and network usage during a Remote Desktop session on a Windows VPS.](https://raff-images.s3.raffusercloud.com/windows_vps_rdp_task_manager_performance_webp_f58a6bac73.png) A small admin-only VPS can be modest. A multi-user RDS server needs more CPU and RAM because every active user session consumes resources. Use this as a planning model: | Scenario | Starting spec direction | Notes | | --------------------------------------- | --------------------------------- | ---------------------------------------------------- | | Admin-only RDP | 2 vCPU / 4 GB RAM | Good for light administration and setup work | | One user running light Windows apps | 2 vCPU / 4–8 GB RAM | Browser-heavy work may need more RAM | | 2–3 users with business software | 4 vCPU / 8 GB RAM | Watch RAM, disk, and app load | | 5–10 users with accounting or ERP tools | 4–8 vCPU / 16 GB RAM or more | Plan RDS, backups, antivirus exclusions, and support | | SQL Server plus RDP users | Larger VM or separated database | SQL Server and RDP sessions compete for RAM | | Trading platform 24/7 | Size by software count and charts | Stability and uptime matter more than minimal cost | Do not size only by login count. A user running one lightweight admin tool is different from a user running Outlook, browser tabs, accounting software, PDFs, Excel, and database-connected software in the same session. ![Visual guide showing Windows VPS sizing considerations for admin-only RDP, single-user Remote Desktop, small team business software, accounting or ERP tools, and SQL Server workloads.](https://raff-images.s3.raffusercloud.com/windows_vps_remote_desktop_sizing_guide_webp_703b0e6969.png) The useful sizing question is: ```text What will each user actually run inside the Remote Desktop session? ``` For performance tuning after launch, read [RDP Performance Tuning for Smooth Remote Desktop](/windows-server/rdp-performance-tuning). ## Licensing is part of the Remote Desktop decision Remote Desktop licensing matters because admin access and user desktop access are different use cases. For basic server administration, normal Remote Desktop access is used by administrators to manage the server. For multi-user desktop or app access, plan Remote Desktop Services and RDS CALs. RDS CAL planning usually depends on: * Number of users or devices * Whether users share devices * Whether users connect from multiple devices * Whether the server is joined to Active Directory * Whether the environment needs per-user or per-device licensing * Whether licensing is BYOL or provider-managed * Whether Office or Microsoft 365 Apps are used in the session For example, a five-person accounting firm where each employee connects from their own laptop usually thinks differently from a shift-based office where many people share the same physical workstations. The safest approach is to decide licensing before inviting users onto the server. For the full licensing breakdown, read [RDS CAL Licensing on Windows Server](/windows-server/rds-cal-licensing-guide) and [Windows Server Licensing on Raff](/windows-server/windows-licensing). ## Security should be planned before users connect Remote Desktop is an access path into the server. Treat it as production infrastructure. ![Windows Defender Firewall inbound rules showing Remote Desktop access controls on a Windows VPS.](https://raff-images.s3.raffusercloud.com/windows_vps_rdp_firewall_rules_webp_bc6a5d3dbe.png) At minimum, a Windows VPS used for Remote Desktop should have: * Strong administrator password policy * Separate user accounts * Least-privilege access * Windows Firewall enabled * RDP access reviewed * Windows updates planned * Microsoft Defender enabled * Audit logging reviewed * Backups configured * Unused services removed * User access removed quickly when someone leaves For small teams, the most common security mistake is convenience. Everyone shares one login, RDP stays open broadly, passwords are reused, and no one reviews access after the first setup. That approach may work for a test server. It is not a good production pattern. For practical hardening steps, read [Windows Server Hardening Checklist](/windows-server/windows-server-hardening-checklist) and [Configure Windows Firewall on a Windows VPS](/windows-server/configure-windows-firewall). ## Remote Desktop performance is a combined system RDP performance is not only about the VPS. It depends on four layers: | Layer | What affects the experience | | ---------------- | ------------------------------------------------------ | | Client device | Screen resolution, local RDP app, display settings | | Network path | Latency, packet loss, ISP route, blocked ports | | Windows VPS | CPU, RAM, disk, background processes | | Session workload | Apps, browser tabs, database tools, charts, user count | A slow session can come from any of these layers. If CPU and RAM are already high inside the VPS, changing display settings will not fix the root problem. If the server is calm but input feels delayed, the network path or client settings may be the issue. A good troubleshooting order is: 1. Check server CPU and RAM. 2. Check network path and RDP connectivity. 3. Review RDP client display settings. 4. Reduce unnecessary visual effects. 5. Tune session policies. 6. Resize the VPS if the workload has outgrown the plan. For the full walkthrough, use [RDP Performance Tuning for Smooth Remote Desktop](/windows-server/rdp-performance-tuning). ## Windows VPS vs office PC for Remote Desktop Many small businesses start by exposing an office PC or local server for remote access. That can work temporarily, but it creates operational limits. | Area | Office PC or local server | Windows VPS | | ------------ | ------------------------------------ | ----------------------------------------- | | Availability | Depends on office power and internet | Runs in cloud infrastructure | | Access | Often tied to office network | Accessible from authorized remote clients | | Maintenance | Usually informal | Centralized server management | | Hardware | Local hardware failures matter | VM can be resized or replaced more easily | | Backups | Often inconsistent | Can be planned around server workload | | Security | Depends on local setup | Can be hardened as server infrastructure | | Scaling | Harder to add capacity | Resize or separate workloads when needed | An office server may be enough when everyone works in one location and downtime is low impact. A Windows VPS becomes more attractive when users are distributed, the office network is unreliable, the software needs to stay online, or the team wants one hosted Windows environment instead of a local machine under someone’s desk. ## Windows VPS vs cloud PC for Remote Desktop A cloud PC and a Windows VPS can both give users remote Windows access, but they are not the same decision. A cloud PC is usually a managed personal desktop. It is often best when each user needs their own individual desktop environment and the organization wants the provider to manage much of the desktop platform. A Windows VPS is usually better when the team needs a server-style Windows environment for shared software, admin tools, databases, IIS, accounting apps, or RDS Session Host planning. | Need | Better fit | | ------------------------------------- | ----------- | | Personal managed desktop per employee | Cloud PC | | Shared Windows Server environment | Windows VPS | | Business software on one server | Windows VPS | | Server administration | Windows VPS | | Minimal IT operations | Cloud PC | | Direct server control | Windows VPS | | RDS Session Host planning | Windows VPS | | Individual employee desktops | Cloud PC | The question is not which one is “better.” The question is whether the team needs personal desktops or a Windows Server environment. ## Raff Windows VPS context Raff Windows VPS fits the Remote Desktop use case when a small team needs a cloud-hosted Windows Server environment for admin work, business software, or RDS planning. Common Raff use cases include: * Remote Desktop access for admins * Hosted accounting software * QuickBooks or Sage environments * SQL Server administration * IIS and .NET application management * Internal tools * Trading platforms * Small business software * RDS Session Host planning * Office server replacement Raff Windows VPS gives teams a simple Windows Server path with cloud VM control, NVMe SSD storage, unmetered bandwidth, 3 Gbps port speed, one IPv4 address, optional IPv6 dual-stack support, and Windows Server version options. This is not the same as saying every Remote Desktop workload should run on one VPS. If a team needs many users, strict compliance, high availability, or managed desktop governance, the design should be reviewed more carefully. But for many small teams, a Windows VPS is a practical starting point because it keeps the Windows environment centralized, accessible, and easier to manage than scattered local machines. ## Common mistakes when using Windows VPS for Remote Desktop ### Treating admin RDP as multi-user desktop hosting Admin RDP is for server management. If multiple users need daily desktop sessions, plan Remote Desktop Services and RDS CALs instead of trying to stretch the admin model. ### Buying by CPU only Remote Desktop sessions are often RAM-sensitive. Browsers, accounting software, Office apps, ERP clients, and SQL tools can consume memory quickly. CPU matters, but RAM is often the first limit users feel. ### Ignoring software behavior Two applications with similar-looking interfaces can behave very differently. QuickBooks, Sage, SQL Server tools, browser apps, trading platforms, and IIS management all create different CPU, RAM, disk, and network pressure. ### Leaving RDP security too open Remote Desktop should not be treated like a casual login page. Review firewall rules, passwords, account access, audit logs, updates, and backups before the server becomes part of daily work. ### Forgetting disconnected sessions Disconnected sessions can keep applications open and continue consuming RAM. For RDS environments, session timeout and disconnected-session policies should be planned. ### Skipping backups A Remote Desktop server often becomes a place where users save files, app data, exports, reports, and configuration. If users depend on the server, backups should be planned before production use. ### Waiting too long to resize A server that worked for one admin may not work for five daily users. Monitor CPU, RAM, disk, and session experience after real usage begins. ## What Raff recommends Start by deciding whether the server is for administration or user work. For admin-only access, keep the setup simple: one or two administrators, strong credentials, firewall review, Windows updates, and basic monitoring. For daily user work, treat the Windows VPS as a Remote Desktop environment. Plan RDS licensing, user accounts, RAM per user, session policy, backups, security, and performance tuning before the team depends on it. For small business software, keep the application and data close together where possible. Do not make users open a database or company file across a slow VPN if the software expects local or LAN-like access. For Remote Desktop performance, check the server load before changing display settings. A slow desktop is often a sizing or workload issue, not only an RDP setting. ## What's next * [RDP VPS](/products/remote-desktop-vps) — review the hosted RDP product path after choosing the access model. * [Connect to a Windows VPS via RDP](/windows-server/connect-to-windows-vps-via-rdp) — step-by-step connection instructions for Windows, macOS, Linux, iOS, and Android. * [RDP Performance Tuning for Smooth Remote Desktop](/windows-server/rdp-performance-tuning) — practical checks for slow Remote Desktop sessions. * [Multi-User RDP: 2 Admin Sessions vs RDS Session Host](/windows-server/multi-user-rdp-vs-rds) — decide when default RDP is enough and when RDS is required. * [RDS CAL Licensing on Windows Server](/windows-server/rds-cal-licensing-guide) — understand per-user and per-device licensing. * [Windows Server Hardening Checklist](/windows-server/windows-server-hardening-checklist) — secure the Windows VPS before production use. ## Sources * [Microsoft Learn — Remote Desktop Services overview in Windows Server](https://learn.microsoft.com/en-us/windows-server/remote/remote-desktop-services/overview) * [Microsoft Learn — Remote Desktop Services roles](https://learn.microsoft.com/en-us/windows-server/remote/remote-desktop-services/rds-roles) * [Microsoft Learn — License Remote Desktop Services with Client Access Licenses](https://learn.microsoft.com/en-us/windows-server/remote/remote-desktop-services/rds-client-access-license) * [Microsoft Learn — License Remote Desktop session hosts](https://learn.microsoft.com/en-us/windows-server/remote/remote-desktop-services/rds-license-session-hosts) * [Raff — Connect to a Windows VPS via RDP](/windows-server/connect-to-windows-vps-via-rdp) * [Raff — Multi-User RDP: 2 Admin Sessions vs RDS Session Host](/windows-server/multi-user-rdp-vs-rds) * [Raff — RDP Performance Tuning for Smooth Remote Desktop](/windows-server/rdp-performance-tuning) * [Raff — RDS CAL Licensing on Windows Server](/windows-server/rds-cal-licensing-guide) --- ### Windows VPS for Remote Employees: Secure Access, Apps, Files, and Backups URL: https://rafftechnologies.com/windows-server/windows-vps-remote-employees Description: Learn when a Windows VPS makes sense for remote employees who need secure access to Windows apps, shared files, Remote Desktop, backups, and a central cloud Windows Server. A Windows VPS can help businesses give remote employees secure access to Windows applications, shared files, internal tools, and a consistent desktop environment from outside the office. It works best when the company plans user count, Remote Desktop access, RDS licensing, RD Gateway or VPN access, file permissions, backups, security, and app support before production. Raff Technologies provides Windows VMs for small businesses and teams that need a practical cloud Windows Server foundation for remote and hybrid work. Remote employees do not always need a full cloud desktop. Sometimes they only need browser-based SaaS tools. But many small businesses still rely on Windows apps, mapped drives, accounting software, legacy tools, SQL-backed apps, or shared office folders. That is where a Windows VPS can make sense. Instead of every remote employee trying to reach an office PC, VPN into a fragile local network, or copy files between devices, users connect to a central Windows environment. The result is simpler to manage: apps stay in one place, business files stay closer to the server, permissions can be controlled, backups can be planned, and the company is not dependent on one physical office machine. :::cta Explore Windows VM Use Raff Windows VM when your remote employees need a cloud-hosted Windows environment for apps, files, and shared workloads. ::: ## Quick verdict: when remote employees should use a Windows VPS Use this table before choosing a Windows VPS for remote staff. | Remote work situation | Windows VPS fit | Why | |---|---|---| | Employees need Windows apps from home or branch offices | Strong fit | Users can connect to one hosted Windows environment. | | Staff need shared files and mapped drives | Strong fit with access planning | Files can stay centralized in the server environment. | | Business app only works well on Windows | Strong fit after vendor check | App can run on Windows Server where supported. | | Employees remote into office PCs today | Strong fit | A Windows VPS is cleaner than workstation-by-workstation access. | | Multiple offices need the same app/data | Strong fit | Teams can work from one shared environment. | | Only SaaS apps are used | Depends | Browser-based tools may already solve the problem. | | Users need heavy graphics or video editing | Depends | Test performance before production. | | Internet connection is unreliable | Risky | Fix connectivity or plan fallback first. | | App vendor does not support RDS/hosted use | Risky | Confirm support before rollout. | | High availability is required | Needs architecture | A single VPS is not a full HA design. | A Windows VPS is strongest when remote employees need access to Windows-based business workflows, not just websites. ## Why remote teams use Windows VPS Remote work creates problems that are easy to ignore until they break daily operations. | Problem | What it looks like | How Windows VPS helps | |---|---|---| | Office PC dependency | Users remote into individual office desktops | Move work to one hosted Windows environment | | File chaos | Files are copied between laptops, email, and USB drives | Centralize shared folders | | VPN frustration | Users struggle with VPN, mapped drives, and local network issues | Connect through a planned Remote Desktop model | | App inconsistency | Different versions run on different machines | Run apps from one controlled server | | Security gaps | Shared passwords or unmanaged devices access files | Use named users and access controls | | Backup uncertainty | Remote files are not consistently protected | Back up the server and business data | | Branch complexity | Offices maintain separate setups | Use one central environment | | MSP support pain | Every endpoint has a different configuration | Standardize support around the server | The goal is not to force every employee into Remote Desktop. The goal is to centralize the Windows workloads that are difficult to run safely across many remote devices. ## Windows VPS vs VPN into the office A VPN can be useful, but it does not automatically solve remote-work infrastructure. | Area | VPN into office | Windows VPS | |---|---|---| | Where apps run | Usually office PCs or local server | Hosted Windows Server | | File access | Often over office network | Inside or near the hosted environment | | Office dependency | High | Lower | | Performance | Depends on office internet and file behavior | Depends on VPS, latency, and session design | | Support model | Endpoint + VPN + office server | Central server + remote session | | Backup model | Depends on local environment | Can be planned around the VPS | | Multi-location access | Can become complex | Centralized | | Best fit | Private access to internal resources | Central Windows workspace for users/apps/files | VPN is not wrong. It may still be useful for private access. But if users are opening large files or Windows apps over VPN, Remote Desktop into a hosted environment may be cleaner. ## Windows VPS vs remote access to office PCs Many small businesses start by letting employees remote into office desktops. That can work temporarily, but it becomes hard to manage. ![Comparison visual showing remote employees using office PCs versus a centralized Windows VPS for apps, files, and backups](https://raff-images.s3.raffusercloud.com/remote_employees_office_pc_vs_windows_vps_webp_c5e51ea253.png) | Area | Office PC remote access | Windows VPS remote access | |---|---|---| | Hardware | Depends on each office PC | Central hosted server | | User experience | Varies by workstation | More consistent | | Backups | Often local or inconsistent | Server-level backup planning | | Access control | Harder to standardize | User/group model can be documented | | Updates | Per workstation | Server/app updates can be controlled | | MSP support | Many devices to troubleshoot | One main environment | | Office power/internet | Required | Not tied to one office PC | | Growth | Messy as users increase | Resize or split roles | A Windows VPS is usually a better long-term model when employees need daily access to the same Windows apps and files. ## Common workloads for remote employees on a Windows VPS ### Accounting, tax, and business apps Remote employees may need access to accounting, tax, ERP, inventory, Access, or legacy Windows software. Good fits include: | Workload | Planning point | |---|---| | QuickBooks Desktop | Company file, multi-user mode, RDS access, backups | | Sage 50/100/300 | Users, database behavior, reports, vendor support | | Tax software | Seasonal users, client files, PDFs, backups | | ERP/inventory | SQL/database load, reports, branch access | | Microsoft Access | File paths, front-end/back-end design, RDS testing | | Legacy apps | Runtime dependencies and vendor support | Use these related guides: - [Windows VPS for Accounting Firms](https://rafftechnologies.com/windows-server/windows-vps-accounting-firms) - [Windows VPS for Tax Software](https://rafftechnologies.com/windows-server/windows-vps-tax-software) - [Windows VPS for ERP and Inventory Software](https://rafftechnologies.com/windows-server/windows-vps-erp-inventory-software) - [Windows VPS for Microsoft Access and Legacy Apps](https://rafftechnologies.com/windows-server/windows-vps-microsoft-access-legacy-apps) ### Shared files and client folders Remote employees often need shared files more than they need a full desktop. A Windows VPS can help when: | Need | Why it helps | |---|---| | Shared department folders | Central folder structure | | Client or project files | Consistent access for remote staff | | Mapped drives | Apps can use expected paths inside the server | | Permissions | Windows groups and NTFS permissions | | Backups | File-level restore and retention planning | | Reports and exports | Store outputs in predictable folders | Do not expose SMB file sharing directly to the public internet. Use a controlled access model such as Remote Desktop, RD Gateway, VPN/private access, or another secure pattern. Use: - [Windows VPS as a Cloud File Server](https://rafftechnologies.com/windows-server/windows-vps-cloud-file-server) - [File Server Migration to Windows VPS](https://rafftechnologies.com/windows-server/file-server-migration-to-windows-vps) ### Remote Desktop sessions Remote Desktop is often the access layer for Windows VPS remote users. There are different models: | Access model | Best fit | |---|---| | Admin RDP | One or two admins managing the server | | RDS Session Host | Staff users need desktop/app sessions | | RD Gateway | Controlled remote access to RDS resources | | VPN/private access | Private network path before access | | RemoteApp | Users need a specific app instead of full desktop | Microsoft describes Remote Desktop Services as a Windows Server platform for securely delivering managed desktops and applications to users at the office, at home, in branch locations, or from partner locations. That matches many remote-employee scenarios. For staff desktop sessions, Microsoft states that each user or device connecting to an RD Session Host running Windows Server needs a Remote Desktop Services Client Access License. Use: - [Remote Desktop Server for Business](https://rafftechnologies.com/windows-server/remote-desktop-server-for-business) - [Remote Desktop Gateway vs Direct RDP](https://rafftechnologies.com/windows-server/remote-desktop-gateway-vs-direct-rdp) - [RDS CAL Licensing on Windows Server](https://rafftechnologies.com/windows-server/rds-cal-licensing-guide) :::cta Talk to Windows Engineer Review remote user count, RDS licensing, RD Gateway, apps, files, backups, and security before choosing your Windows VPS plan. ::: ## Access model: direct RDP, RDS, RD Gateway, or VPN? Do not choose the access model casually. It shapes security, user experience, licensing, and support. | Model | Best fit | Watch out for | |---|---|---| | Direct admin RDP | Admin-only server management | Avoid broad public exposure | | RDS Session Host | Multiple employees need sessions | RDS CALs, profiles, performance | | RD Gateway | Remote users from many locations | Certificate and gateway setup | | VPN + RDP/RDS | Private access required | VPN support and endpoint management | | RemoteApp | Specific apps only | App compatibility and UX | | Browser-based app | Web workloads | May not need Windows VPS for users | Microsoft describes RD Gateway as enabling secure, encrypted connections to RDS resources over the internet without requiring VPN access. For remote employees, that can be a more controlled path than exposing direct RDP broadly. ## Security planning for remote employees Remote work increases the importance of access control. ![Architecture diagram showing remote employees securely accessing Windows apps, shared files, and backups on a Windows VPS](https://raff-images.s3.raffusercloud.com/secure_remote_employee_windows_vps_architecture_webp_aeb37eb871.png) Minimum planning: | Security area | Recommendation | |---|---| | User accounts | Use named users, not shared accounts | | Admin access | Separate admin accounts from daily user accounts | | Passwords | Strong credentials and offboarding process | | RDP exposure | Avoid broad direct RDP exposure | | RD Gateway/VPN | Use controlled access where appropriate | | Firewall | Restrict allowed sources and ports | | Permissions | Use groups and least privilege | | Local redirection | Control clipboard, drive, and printer redirection where needed | | Backups | Restrict who can delete or modify backups | | Updates | Patch Windows and apps deliberately | | Logs | Review failed sign-ins and unusual access | | Offboarding | Remove access quickly when employees leave | Microsoft provides Windows Server security baseline guidance and Security Compliance Toolkit resources for recommended configuration baselines. Use those as a starting point, then adapt based on your business workflow. Use: [Windows Server Hardening Checklist](https://rafftechnologies.com/windows-server/windows-server-hardening-checklist). ## Sizing a Windows VPS for remote employees Size by concurrent users and workload, not total headcount. Use this as a starting point: | Remote employee workload | Starting size | When to move up | |---|---:|---| | 1-2 admins or light users | 2 vCPU / 4 GB RAM | If users run apps or reports | | 3 light remote users | 4 vCPU / 8 GB RAM | If users open Office apps, PDFs, or browsers | | 3-5 active business app users | 4 vCPU / 16 GB RAM | Better for accounting, tax, ERP, Access, or legacy apps | | 5-10 active users | 8 vCPU / 32 GB RAM | If the VPS becomes a daily shared workspace | | Remote users plus SQL/app database | 8-16 vCPU / 32-64 GB RAM | Consider splitting app and database roles | | File-heavy team | Size storage first | Files, profiles, downloads, exports, and growth matter | Storage should include: - app installs; - shared files; - user profiles; - downloads; - reports and exports; - databases; - logs; - backups; - temporary migration data; - 12 to 24 months of growth. Use: [Windows VPS sizing for remote users](https://rafftechnologies.com/windows-server/windows-vps-sizing-remote-users). :::cta View Pricing Compare Raff Windows VM plans when sizing CPU, memory, storage, backups, and monthly cost for remote employees. ::: ## Performance factors for remote employees Remote Desktop performance depends on more than the VPS size. Check: | Factor | Why it matters | |---|---| | Network latency | Affects mouse/keyboard responsiveness | | Packet loss | Causes freezes and disconnects | | User location | Farther locations may feel slower | | CPU | App launches, reports, and background tasks | | RAM | Sessions, browsers, Office apps, and profiles | | Disk performance | Logins, file access, app data | | Printers | Redirection can slow sessions | | Local device quality | Old laptops or bad Wi-Fi affect experience | | App behavior | Some desktop apps are not RDS-friendly | | User habits | Many tabs and files open increase load | If one remote employee has problems but others do not, check local internet, Wi-Fi, VPN, firewall, DNS, endpoint health, and client settings before resizing the server. ## Backups for remote employee workloads A Windows VPS used by remote employees often holds app data, shared files, user profiles, reports, and configuration. Backups should be planned before users depend on it. | Backup layer | Purpose | |---|---| | VM backup | Recover the whole Windows VPS | | Snapshot before changes | Roll back before updates, migrations, or app changes | | File-level backup | Restore documents and shared folders | | User profile backup | Recover user settings and workspace data | | Application/database backup | Protect business app data correctly | | Off-server copy | Reduce risk from VM/account/ransomware issues | | Restore test | Prove recovery works | Do not assume cloud hosting means data is automatically protected. Backup and restore planning is still required. Use: [Windows VPS Backup Strategy for Small Businesses](https://rafftechnologies.com/windows-server/windows-vps-backup-strategy-small-business). :::cta Explore Data Protection Protect remote employee workloads with backup, snapshot, and restore planning before users depend on the Windows VPS. ::: ## Pricing factors for remote employees The monthly VM plan is only one part of the cost. | Cost factor | Why it matters | |---|---| | CPU/RAM | Active users and app workload | | Storage | Files, profiles, app data, backups, growth | | Windows licensing | Depends on provider and deployment model | | RDS CALs | Staff Remote Desktop sessions may require licensing | | App licensing | Accounting, ERP, tax, legal, Office, and other apps | | SQL Server | Some business apps need SQL licensing and backups | | Backups/snapshots | Retention and recovery requirements | | Migration | Users, apps, files, permissions, cutover | | Support | Windows, RDS, app, printer, endpoint troubleshooting | | Security | Access controls, hardening, offboarding | A cheap server can be expensive if it slows down staff, lacks backups, or creates access problems for remote employees. Use: [Windows VPS Pricing Explained](https://rafftechnologies.com/windows-server/windows-vps-pricing-explained). ## Migration path for remote employees If users currently remote into office PCs or use a local server, migrate carefully. Use this path: 1. Inventory remote users, apps, files, devices, and locations. 2. Confirm application support for Windows Server/RDS use. 3. Choose the access model: RDP, RDS, RD Gateway, VPN, or RemoteApp. 4. Choose the Windows VPS size. 5. Build and secure the Windows VPS. 6. Configure users, groups, firewall, and backups. 7. Install business apps and dependencies. 8. Copy test data first. 9. Test with real remote employees from real locations. 10. Test printers, PDFs, downloads, reports, and file paths. 11. Run a restore test. 12. Schedule cutover outside critical hours. 13. Move final data and users. 14. Keep rollback ready. 15. Monitor performance after launch. Use: - [Windows Server Migration Checklist for Small Businesses](https://rafftechnologies.com/windows-server/windows-server-migration-checklist-small-business) - [Local Office Server to Cloud Windows VPS Migration](https://rafftechnologies.com/windows-server/local-server-to-cloud-windows-vps-migration) - [File Server Migration to Windows VPS](https://rafftechnologies.com/windows-server/file-server-migration-to-windows-vps) ## When a Windows VPS is not the right fit for remote employees A Windows VPS is useful, but not universal. Pause when: | Situation | Better next step | |---|---| | All tools are browser-based SaaS | SaaS access may be enough | | Users need offline work all day | Local workflows may be required | | Internet is unreliable | Fix connectivity first | | Heavy graphics or media work is required | Test or use a different platform | | App vendor does not support RDS/hosted use | Do not proceed without support path | | High availability is mandatory | Design redundancy and failover | | Users need direct local hardware access | Test devices before rollout | | Licensing is unclear | Resolve licensing before production | Choose Windows VPS when the remote work problem is actually a Windows workload problem. ## How Raff fits remote employees Raff fits businesses that need a cloud-hosted Windows Server environment for remote employees, Remote Desktop users, business apps, shared files, office server replacement, multi-location teams, and backup-aware Windows workloads. Raff can provide the Windows VM foundation. Your business or MSP should still plan: - user access; - RDS CAL requirements; - application support; - file permissions; - backups; - restore testing; - secure remote access; - user onboarding/offboarding; - migration and rollback; - support ownership. That is the right way to use Raff: run the Windows environment on Raff, then design the remote employee workflow correctly. :::cta Deploy Windows Now Create a Raff Windows VM when your team is ready to give remote employees secure access to Windows apps, files, and shared workloads. ::: ## Recommended path by remote work situation | Situation | Read next | |---|---| | You need the broad SMB guide | [Windows VPS Hosting for Small Businesses](https://rafftechnologies.com/windows-server/windows-vps-small-business) | | You need remote desktop planning | [Remote Desktop Server for Business](https://rafftechnologies.com/windows-server/remote-desktop-server-for-business) | | You need pricing clarity | [Windows VPS Pricing Explained](https://rafftechnologies.com/windows-server/windows-vps-pricing-explained) | | You need sizing help | [Windows VPS sizing for remote users](https://rafftechnologies.com/windows-server/windows-vps-sizing-remote-users) | | You need secure access planning | [Remote Desktop Gateway vs Direct RDP](https://rafftechnologies.com/windows-server/remote-desktop-gateway-vs-direct-rdp) | | You need RDS licensing planning | [RDS CAL Licensing on Windows Server](https://rafftechnologies.com/windows-server/rds-cal-licensing-guide) | | You need shared files | [Windows VPS as a Cloud File Server](https://rafftechnologies.com/windows-server/windows-vps-cloud-file-server) | | You need backups | [Windows VPS Backup Strategy for Small Businesses](https://rafftechnologies.com/windows-server/windows-vps-backup-strategy-small-business) | | You are replacing office hardware | [Cloud Windows Server vs Local Office Server](https://rafftechnologies.com/windows-server/cloud-windows-server-vs-local-office-server) | | You are migrating from local server | [Local Office Server to Cloud Windows VPS Migration](https://rafftechnologies.com/windows-server/local-server-to-cloud-windows-vps-migration) | ## Final remote employee checklist Before rolling out a Windows VPS for remote employees, confirm: | Check | Done | |---|---| | Active remote users estimated | ☐ | | Business apps listed | ☐ | | App vendor support checked | ☐ | | RDS CAL requirements reviewed | ☐ | | Access model chosen | ☐ | | CPU/RAM/storage starting point chosen | ☐ | | Shared folders documented | ☐ | | File permissions planned | ☐ | | Backup layers defined | ☐ | | Restore test planned | ☐ | | Firewall rules planned | ☐ | | User onboarding/offboarding documented | ☐ | | Printers and local devices tested | ☐ | | Real users tested from real locations | ☐ | | Support owner assigned | ☐ | | Rollback plan documented | ☐ | If the checklist is unclear, do not treat the environment as production yet. ## What's next - Explore [hosted Remote Desktop](/products/remote-desktop-vps) when you are ready to compare Windows VM options. - Review [Raff pricing](https://rafftechnologies.com/pricing) before choosing CPU, RAM, storage, and monthly cost. - Read [Remote Desktop Server for Business](https://rafftechnologies.com/windows-server/remote-desktop-server-for-business) before rolling out staff Remote Desktop access. - Read [Windows VPS Hosting for Small Businesses](https://rafftechnologies.com/windows-server/windows-vps-small-business) for the broader SMB decision guide. - Read [Windows VPS Pricing Explained](https://rafftechnologies.com/windows-server/windows-vps-pricing-explained) before budgeting the full environment. - Read [Remote Desktop Gateway vs Direct RDP](https://rafftechnologies.com/windows-server/remote-desktop-gateway-vs-direct-rdp) before choosing an access model. - Read [Windows VPS Backup Strategy for Small Businesses](https://rafftechnologies.com/windows-server/windows-vps-backup-strategy-small-business) before storing production data. ## Sources - Raff — [Windows VM product page](https://rafftechnologies.com/products/windows-vm) - Raff — [Pricing](https://rafftechnologies.com/pricing) - Raff — [Windows Server Hub](https://rafftechnologies.com/windows-server) - Raff — [Remote Desktop Server for Business](https://rafftechnologies.com/windows-server/remote-desktop-server-for-business) - Microsoft Learn — [Remote Desktop Services overview in Windows Server](https://learn.microsoft.com/en-us/windows-server/remote/remote-desktop-services/overview) - Microsoft Learn — [Remote Desktop Services roles](https://learn.microsoft.com/en-us/windows-server/remote/remote-desktop-services/rds-roles) - Microsoft Learn — [License Remote Desktop Services with Client Access Licenses](https://learn.microsoft.com/en-us/windows-server/remote/remote-desktop-services/rds-client-access-license) - Microsoft Learn — [Deploy Remote Desktop Gateway role for Remote Desktop Services](https://learn.microsoft.com/en-us/windows-server/remote/remote-desktop-services/remote-desktop-gateway-role) - Microsoft Learn — [What is SMB File Sharing for Windows and Windows Server?](https://learn.microsoft.com/en-us/windows-server/storage/file-server/file-server-smb-overview) - Microsoft Learn — [SMB security hardening in Windows Server and Windows Client](https://learn.microsoft.com/en-us/windows-server/storage/file-server/smb-security-hardening) - Microsoft Learn — [Security baselines guide](https://learn.microsoft.com/en-us/windows/security/operating-system-security/device-management/windows-security-configuration-framework/windows-security-baselines) --- ### Windows VPS Sizing for Remote Users: 1, 3, 5, 10 Users URL: https://rafftechnologies.com/windows-server/windows-vps-sizing-remote-users Description: Size a Windows VPS for 1, 3, 5, or 10 remote users using peak concurrent sessions, workload type, current Raff VM tiers, RDS licensing, storage, backups, and performance data. ## In short Windows VPS sizing for remote users starts with **peak concurrent sessions and workload**, not total employee count. Use current Raff VM tiers as planning anchors, then validate CPU, RAM, disk, and application behavior during real peak usage. For Raff-hosted RDS, budget the Windows Server licence separately and use **RDS User SALs**, not generic customer-owned RDS CAL assumptions. A Windows VPS is a cloud-hosted Windows Server that remote users access through Remote Desktop Protocol, business software, files, or server-hosted applications. The correct size depends on what users actually do inside the server: light administration, accounting software, Microsoft 365 Apps, ERP tools, SQL Server, browser sessions, or a full Remote Desktop Services environment. Raff Windows VMs provide administrator access, RDP access, NVMe storage, and 3 Gbps unmetered VM traffic with no VM egress fees. The main sizing questions are therefore usually CPU, RAM, storage, concurrency, and application behavior rather than transfer overage. ## Quick sizing table for 1, 3, 5, and 10 remote users Use this table as a **planning baseline**, not a user-count guarantee. Microsoft also treats session-host sizing guidance as a starting point that must be refined against workload and real telemetry. ![Windows VPS sizing matrix for 1, 3, 5, and 10 remote users by CPU, RAM, and workload](https://raff-images.s3.raffusercloud.com/windows_vps_sizing_remote_users_matrix_webp_514a381563.png) | Remote use case | Resource target | Closest current Raff anchor | Notes | |---|---:|---:|---| | 1 admin user | 2 vCPU / 4 GB RAM | 2 vCPU / 4 GB / 80 GB — $22.99/mo | Good for administration, light tools, or one small business app. | | 3 light users | Around 4 vCPU / 8 GB RAM | 4 vCPU / 8 GB / 120 GB — $40.99/mo | Suitable planning anchor for lighter shared workloads. | | 5 business users | Around 8 vCPU / 16 GB RAM | 8 vCPU / 16 GB / 180 GB — $76.99/mo | Safer anchor for accounting, office, and shared application workloads. | | 10 active users | Around 8 vCPU / 32 GB RAM | 8 vCPU / 32 GB / 240 GB — $137.99/mo | Practical starting anchor for active multi-user RDS; heavier roles may need 16 vCPU / 32 GB. | Raff plans are fixed tiers. A sizing target such as 4 vCPU / 16 GB may be useful analytically, but if Raff does not currently sell that exact configuration, choose the nearest suitable live plan rather than treating the target as an available SKU. Size by the number of users active at the same time. Ten employees with three concurrent users do not need the same Windows VPS as ten users working inside the server all day. :::cta View Windows VM Pricing Compare current Raff Windows VM plans after estimating CPU, memory, storage, and concurrent-user demand. ::: ## Remote user count and concurrent sessions are different Size a Windows VPS by peak concurrent sessions, not payroll headcount. A 12-person office may only have 3 people logged in at once, while a 6-person accounting firm may have all 6 users active during month-end close. ![Diagram showing that Windows VPS sizing should use concurrent remote users instead of total employees](https://raff-images.s3.raffusercloud.com/windows_vps_concurrent_users_vs_total_employees_webp_6821f8af0b.png) Use this formula before choosing a plan: ```text Peak concurrent users = total users x expected same-time usage ``` Examples: | Team | Total users | Same-time usage | Peak sessions to size for | |---|---:|---:|---:| | Small owner-operated business | 3 | 1-2 active | 2 sessions | | Accounting office | 8 | 6 active during tax season | 6 sessions | | MSP client environment | 12 | 4 active at once | 4 sessions | | Remote operations team | 10 | 10 active during shift | 10 sessions | CPU and RAM pressure comes from active sessions and what those sessions run. A signed-in user with Outlook, browser tabs, QuickBooks, Excel, and PDF tools can consume far more resources than a mostly idle session. Microsoft's current Remote Desktop session-host sizing guidance separates light, medium, heavy, and power workloads and explicitly recommends validating baseline assumptions against your real applications and users. ## Admin RDP and RDS Session Host change the sizing and licensing model A Windows VPS used by one or two administrators is not the same as a Windows VPS used as a shared desktop for employees. Default Windows Server RDP is for administration. Daily multi-user desktop access belongs in Remote Desktop Services with RDS Session Host and an appropriate licensing model. ![Decision flowchart comparing admin RDP and RDS Session Host for Windows VPS users](https://raff-images.s3.raffusercloud.com/admin_rdp_vs_rds_session_host_decision_webp_140daaf1f6.png) | Scenario | Access model | Sizing/licensing impact | |---|---|---| | One owner logs in to manage software | Default admin RDP | Small plan can work; no RDS user licensing for ordinary admin access. | | Two admins maintain the server | Default admin RDP | Size for admin tools and background workloads. | | Three or more staff need daily desktop sessions | RDS Session Host | Size for concurrent users, profiles, apps, and RDS licensing. | | Users access a web app on IIS | No shared desktop required | Size for IIS/app load, not RDP users. | | Users connect to SQL Server from local PCs | No shared desktop required | Size for database load, not desktop sessions. | For Raff-hosted Windows Server under SPLA, production licensing is currently **$15/month per Windows Server Standard instance**. When staff use hosted RDS desktop/RemoteApp sessions, Raff's hosted licensing model uses **RDS User SALs at $8/month per user**. That is different from a customer-owned Microsoft licensing model, where Windows Server CAL and RDS CAL rules may apply according to the customer's licensing rights. See [Windows Server Licensing](/windows-server/windows-licensing) and [Multi-User RDP vs RDS](/windows-server/multi-user-rdp-vs-rds) before rollout. ## Workload type changes the CPU and RAM requirement Remote users are not equal from a sizing perspective. Five users checking a lightweight internal app can run on a much smaller server than five users running accounting software, Outlook, browser tabs, and reports. | Workload type | Typical behavior | Sizing approach | |---|---|---| | Admin-only | Server Manager, PowerShell, updates, light browser | Size for the server role, not the user session. | | Light office desktop | Browser, PDF tools, light document editing | Give RAM headroom and monitor peak concurrency. | | Accounting software | QuickBooks, Sage, tax tools, shared company files | Prioritize RAM, NVMe storage, backups, and app data locality. | | Microsoft 365 Apps | Outlook cache, Excel, Word, browser-based collaboration | Plan profile storage and RAM per active user. | | ERP or inventory software | Client/server app, reports, database access | Size CPU/RAM with database and reporting peaks in mind. | | Trading software | MetaTrader terminals, charts, EAs, 24/7 sessions | Size by terminal count, charts, and automation load. | | SQL Server on same VPS | Database engine plus RDP users | Reserve RAM for SQL Server or split database to another server. | The biggest mistake is buying by vCPU alone. Remote Desktop can feel slow when RAM is saturated, profiles are bloated, storage is busy, or SQL Server and user sessions compete on the same VM. ## A 1-user Windows VPS is usually simple For one administrator or one light application user, Raff's current **2 vCPU / 4 GB / 80 GB** tier at **$22.99/month** is the practical starting anchor. Move higher when the VM also runs SQL Server Express, IIS, accounting software, automation jobs, or several background services. A current **4 vCPU / 8 GB / 120 GB** tier is **$40.99/month**. Even one-user servers need backups when they hold business files, application databases, licence data, or customer records. ## A 3-user Windows VPS needs workload headroom For three light concurrent users, the current **4 vCPU / 8 GB / 120 GB** Raff tier at **$40.99/month** is a reasonable planning anchor. If the workload is memory-heavy, do not pretend that a nonexistent 4 vCPU / 16 GB Raff SKU exists; move to a live tier that provides enough memory, such as **8 vCPU / 16 GB / 180 GB at $76.99/month**, or test whether the 4/8 tier is sufficient. If all three users need daily desktop sessions, use RDS Session Host rather than treating administrative RDP as a team-desktop solution. ## A 5-user Windows VPS should be treated as production Five active users depending on one server for daily work should be planned around continuity and real peak load, not just first-login performance. For heavier shared business workloads, Raff's current **8 vCPU / 16 GB / 180 GB** plan at **$76.99/month** is the safer live anchor. Lighter workloads may fit a smaller tier after testing. If Raff hosts the Windows Server licence and all five staff need RDS sessions, an example monthly infrastructure/licensing stack is: ```text 8 vCPU / 16 GB / 180 GB Windows VM: $76.99 Windows Server Standard SPLA: $15.00 5 x RDS User SAL: $40.00 ------------------------------------------- Illustrative total: $131.99/month ``` This excludes application licences such as QuickBooks, Microsoft 365 Apps, SQL Server, or third-party business software. ## A 10-user Windows VPS needs a real capacity plan For ten active shared-desktop users, a current Raff **8 vCPU / 32 GB / 240 GB** tier at **$137.99/month** is a practical starting anchor, not a universal guarantee. Heavy accounting, ERP, reporting, browser-heavy work, or SQL Server on the same VM may justify **16 vCPU / 32 GB / 360 GB at $174.99/month** or splitting roles across servers. A hosted RDS cost example for ten users is: ```text 8 vCPU / 32 GB / 240 GB Windows VM: $137.99 Windows Server Standard SPLA: $15.00 10 x RDS User SAL: $80.00 -------------------------------------------- Illustrative total: $232.99/month ``` Again, application licences and optional storage/backup services are separate. At ten users, track peak CPU, available RAM, disk latency, login waves, profile growth, and application-specific bottlenecks before assuming more vCPU is the only answer. ## CPU, RAM, and storage should be measured after launch Avoid hard-coded rules such as “CPU above 70% means upgrade.” A short CPU spike can be normal, while a sustained queue during the exact workload users care about may indicate real CPU pressure. Use [Windows Server Performance Monitoring](/windows-server/windows-server-performance-monitoring) to capture CPU, memory, disk, and network behavior with PerfMon and Data Collector Sets. A practical RAM model is: ```text Total RAM needed = Windows Server baseline + active session memory + application memory + database/cache memory + security/backup overhead + operating headroom ``` There is no universal “2-4 GB per user” truth across all workloads. Browser-heavy, Outlook-heavy, accounting, ERP, and database-backed users can vary dramatically. Storage sizing should include Windows, profiles, downloads, AppData, business files, application databases, logs, temporary files, and backup staging. Raff VM plans include fixed local NVMe storage; additional volumes are available at **$0.08/GB/month**, while snapshots/backups are **$0.06/GB/month**. ## Network quality affects RDP even when the VPS is sized well A correctly sized Windows VPS can still feel slow if the user's network path is unstable. Check latency, packet loss, Wi-Fi quality, RDP display settings, and whether the problem affects one user or everyone. Raff VM traffic uses a **3 Gbps unmetered** connection with no VM egress fees, but the end-to-end Remote Desktop experience still depends on the user's connection and route. Use [RDP Performance Tuning](/windows-server/rdp-performance-tuning) after the server has enough CPU and RAM. ## Licensing must be planned before user rollout Use this split: | Access pattern | Raff-hosted licensing implication | |---|---| | One or two admins manage the server | No RDS User SAL for ordinary administrative access | | Users access an IIS-hosted web app | No RDS User SAL solely for web access | | Users connect directly to SQL Server | No RDS User SAL solely for database access | | Staff sign in to RDS desktop sessions | RDS User SALs apply in Raff's hosted SPLA model | | Staff use RemoteApp from RDS Session Host | RDS User SALs apply in Raff's hosted SPLA model | Customer-owned licensing is a separate path and may involve Windows Server CALs/RDS CALs depending on the customer's Microsoft rights. Do not mix those customer-owned CAL rules with Raff's hosted SPLA/SAL model. ## Recommended starting plans use current Raff tiers | If you need... | Current Raff planning anchor | Compute price | |---|---:|---:| | One admin desktop | 2 vCPU / 4 GB / 80 GB | $22.99/mo | | Three light users | 4 vCPU / 8 GB / 120 GB | $40.99/mo | | Three heavier business users | 8 vCPU / 16 GB / 180 GB | $76.99/mo | | Five active business users | 8 vCPU / 16 GB / 180 GB | $76.99/mo | | Ten active users | 8 vCPU / 32 GB / 240 GB | $137.99/mo | | Heavier ten-user workload | 16 vCPU / 32 GB / 360 GB | $174.99/mo | These are planning anchors, not performance guarantees. Validate with the actual software vendor's support matrix and monitor production usage. ## Common sizing mistakes ### Sizing by total employees Size by peak concurrent users and workload type. ### Treating admin RDP as team desktop access Use RDS Session Host when staff need daily desktop or RemoteApp sessions. ### Treating resource targets as live Raff SKUs A theoretical 4 vCPU / 16 GB target is not automatically an available Raff plan. Map the target to current live tiers. ### Ignoring application behaviour QuickBooks, Outlook, ERP, SQL Server, browsers, and tax software can have very different CPU/RAM patterns. ### Buying too little RAM Memory pressure and paging are common causes of poor RDP responsiveness. ### Forgetting profiles and storage growth Outlook caches, downloads, browser data, logs, reports, and company files grow over time. ### Running every role on one VPS forever As contention becomes visible, separate SQL Server, application, file, or RDS roles where appropriate. ## Validation scope This September 2026 refresh is a **planning and source-of-truth update**, not a fresh Raff benchmark claiming a fixed number of users per plan. Current Raff VM tiers, Windows Server SPLA pricing, RDS User SAL pricing, network terms, volume pricing, and snapshot/backup pricing were revalidated. Microsoft session-host sizing guidance was also rechecked. Always validate final sizing with the actual applications and peak-user behaviour. ## What's next - [Windows Server Performance Monitoring](/windows-server/windows-server-performance-monitoring) — measure CPU, RAM, disk, and network before resizing. - [Multi-User RDP vs RDS](/windows-server/multi-user-rdp-vs-rds) — understand the two admin sessions vs RDS Session Host split. - [Windows Server Licensing](/windows-server/windows-licensing) — compare SPLA, SALs, customer CALs, and BYOL. - [RDP Performance Tuning](/windows-server/rdp-performance-tuning) — improve Remote Desktop responsiveness after sizing is correct. - [RDP VPS](/products/remote-desktop-vps) — review current plans. - [Raff pricing](/pricing) — confirm current pricing before deployment. ## Sources - Microsoft Learn — Session host virtual machine sizing guidelines for Azure Virtual Desktop and Remote Desktop Services - Microsoft Learn — Performance tuning Remote Desktop Session Hosts - Microsoft Learn — License Remote Desktop Services with Client Access Licenses - Microsoft Learn — Choose how you pay for Remote Desktop Services - Raff — Windows Server Licensing - Raff — Windows VM - Raff — Pricing - Sources revalidated: 2026-09-09 --- ### SQL Server Always On: Two-Node Availability Group Setup (2026) URL: https://rafftechnologies.com/windows-server/mssql-always-on-setup Description: Plan and deploy a two-node SQL Server Always On availability group on Windows Server, including WSFC, Basic vs Enterprise AGs, listener, quorum, seeding, failover, backups, and monitoring. ## In short For **SQL Server Always On high availability on Windows Server**, the standard two-node design uses two SQL Server instances on separate nodes of the same Windows Server Failover Cluster (WSFC), with an availability group listener as the application connection point. Keep replica traffic on private networking, use synchronous commit plus automatic failover only when latency and recovery requirements support it, and test the real application through the listener before production. Edition matters. **SQL Server Standard supports Basic Availability Groups**, which are limited to two replicas and one availability database per Basic AG, with no readable secondary and no backups on the secondary. **SQL Server Enterprise** supports the broader Always On feature set for multi-database groups, readable secondaries, backup offload, and larger topologies. Raff Technologies can provide the Windows VM and private-network infrastructure for a self-managed SQL Server HA design. Always On does not replace SQL Server licensing, database administration, backups, monitoring, or a tested failover runbook. ```text Application | v Availability Group Listener | +--> SQL01 Primary replica | +--> SQL02 Secondary replica | v Windows Server Failover Cluster | v Quorum witness ``` The operational rule is simple: ```text Always On reduces downtime. Backups provide point-in-time recovery. You need both. ``` ## SQL Server Always On: what this guide builds This guide covers a traditional **high-availability availability group on Windows Server**. In this model: - SQL01 and SQL02 are separate Windows Server VMs; - each SQL Server instance runs on a different WSFC node; - the replicas use a dedicated database mirroring endpoint for AG data movement; - applications connect through an availability group listener; - a quorum witness is planned for the two-node cluster; - databases use FULL recovery model; - failover, backup, monitoring, and application reconnect behavior are tested before production. SQL Server also supports other availability-group patterns, including read-scale configurations without a cluster manager. Those designs do not provide the same WSFC-managed high-availability behavior and are outside the scope of this two-node HA guide. ## Basic Availability Group vs Enterprise Availability Group ![SQL Server Standard Basic Availability Group versus SQL Server Enterprise Always On comparison showing replica limits, database limits, readable secondary support, backup offload, and best-fit use cases.](https://raff-images.s3.raffusercloud.com/sql_server_standard_vs_enterprise_always_on_png_4a9890110e.png) Choose the SQL Server edition before you build the cluster. | Requirement | SQL Server Standard Basic AG | SQL Server Enterprise AG | |---|---|---| | Two-replica HA for one database | Yes | Yes | | More than one database in the same AG | No | Yes | | Readable secondary | No | Yes | | Backups on secondary replica | No | Yes, subject to supported backup rules | | Multiple secondary replicas | No | Yes | | Read-only routing | No | Yes | | Distributed availability groups | No | Yes | | Best fit | One critical database with simpler HA requirements | Multi-database and advanced HA/DR designs | A Basic AG is not simply a smaller Enterprise AG. Microsoft documents specific Basic AG restrictions, including **two replicas**, **one availability database**, **no read access on the secondary**, and **no backups on the secondary**. A Basic AG also cannot be converted in place into an advanced availability group; plan an Enterprise migration separately if requirements grow. For a detailed edition decision, see [SQL Server Standard vs Enterprise](/windows-server/sql-server-standard-vs-enterprise). ## SQL Server 2025 changes worth knowing Two SQL Server 2025 changes are particularly relevant to an Always On design. First, SQL Server 2025 expands backup options for supported secondary replicas. In addition to the existing secondary-backup capabilities, Microsoft documents support for **full and differential backups on secondary replicas in SQL Server 2025 and later**. This applies to the advanced availability-group scenario, not to Standard Basic AGs, whose secondary-backup restriction remains. Second, SQL Server 2025 adds an optional faster response for persistent AG health failures. WSFC normally tries to restart the availability-group resource before failing it over. SQL Server 2025 allows the AG resource `RestartThreshold` to be set to `0`, which can cause WSFC to fail over immediately when a persistent health issue is detected. Treat this as an advanced operational setting, not a default tweak. Test it against your application's recovery behavior before production. ## Always On vs Failover Cluster Instance vs log shipping These solve different problems. | Architecture | Protects at | Shared storage | Automatic failover | Typical fit | |---|---|---|---|---| | Availability Group | Database level | Not required | Supported in appropriate synchronous WSFC designs | Database HA, readable secondaries, local HA plus DR | | Failover Cluster Instance | SQL Server instance level | Usually requires shared-storage architecture | Yes | Instance-level failover and server-level object continuity | | Log shipping | Database copy / DR | No | No | Lower-complexity DR with manual recovery | An AG does **not** automatically synchronize every server-level object. Logins, SQL Agent jobs, linked servers, credentials, certificates, server-level permissions, and other instance objects need their own synchronization or deployment process. For smaller workloads, good backups plus log shipping can be easier to operate than an AG. Choose Always On when the recovery objective justifies the extra clustering, networking, monitoring, and operational work. ## Recommended two-node architecture on Windows VMs ![SQL Server Always On architecture on Windows Server VPS showing an app server connecting through an availability group listener to primary and secondary SQL replicas, Windows Server Failover Cluster, private network replication, quorum witness, and backups.](https://raff-images.s3.raffusercloud.com/sql_server_always_on_architecture_windows_vps_png_5e7883a9b7.png) A practical layout is: ```text Private network: 10.20.0.0/24 SQL01 - Windows Server - SQL Server - primary replica initially SQL02 - Windows Server - SQL Server - secondary replica initially WSFC - cluster name: SQLCLUSTER - SQL01 + SQL02 as nodes Availability Group - AG_APP01 Listener - sql-app01-listener Witness - file share witness or another supported witness design ``` Keep the two SQL replicas off the same avoidable failure boundary where possible. Two VMs do not provide meaningful HA if a single host, storage dependency, network path, or administrative mistake can take down both at once. ## Prerequisites before you start Prepare the following before creating the AG: - two supported Windows Server VMs; - supported SQL Server versions and editions on both replicas; - matching SQL Server version and cumulative update level where possible; - private IP connectivity between nodes; - working name resolution; - Windows Server Failover Clustering for this HA design; - a quorum plan; - a database mirroring endpoint on each SQL Server instance; - a listener name and network plan; - database backups and restore validation; - monitoring and alerting; - a maintenance window for failover testing. Microsoft explicitly lists **running the AG host as a domain controller as unsupported**. Keep SQL Server replicas on dedicated member servers rather than installing them on your domain controllers. This guide uses the common domain-joined WSFC pattern. Domain-independent Windows availability-group designs also exist, but they require additional DNS, authentication, and certificate planning and should be treated as a separate architecture rather than mixed into a first deployment. ## Step 1 — Define the recovery objective before the cluster Decide: - acceptable downtime (RTO); - acceptable data loss (RPO); - Standard Basic AG or Enterprise AG; - synchronous or asynchronous commit; - automatic or manual failover; - local HA, remote DR, or both; - listener and client-driver requirements; - whether readable secondaries or backup offload are required; - who is allowed to initiate failover; - how the application retries and reconnects. A two-node synchronous AG is a common local-HA pattern. An asynchronous remote replica is usually a DR choice where avoiding write latency matters more than zero-data-loss failover. ## Step 2 — Prepare networking, DNS, and identity For the domain-joined design used here, join SQL01 and SQL02 to the intended Windows domain and verify DNS before installing the cluster. Check each node: ```powershell (Get-CimInstance Win32_ComputerSystem).Domain ``` Verify name resolution: ```powershell Resolve-DnsName SQL01 Resolve-DnsName SQL02 ``` Use private addresses for SQL-node and cluster traffic where possible. Do not use public DNS resolvers as a substitute for the DNS design your Windows domain and listener depend on. If you need Active Directory guidance first, see [Active Directory Replication Topology](/windows-server/ad-replication-topology). ## Step 3 — Match SQL Server configuration on both replicas Keep the replicas operationally consistent: - SQL Server major version; - edition appropriate for the AG type; - cumulative update level; - collation where the application depends on it; - data, log, TempDB, and backup paths; - SQL Server service-account model; - firewall policy; - max server memory and TempDB configuration; - SQL Agent jobs and instance-level dependencies. Example layout: ```text D:\SQL\Data L:\SQL\Logs T:\SQL\TempDB B:\SQL\Backups ``` Matching paths reduce restore and seeding surprises after failover. ## Step 4 — Install Windows Server Failover Clustering Run on both SQL nodes: ```powershell Install-WindowsFeature Failover-Clustering -IncludeManagementTools ``` Verify: ```powershell Get-WindowsFeature Failover-Clustering ``` Then validate the planned nodes: ```powershell Test-Cluster -Node SQL01,SQL02 ``` Review the full validation report. Do not dismiss network or system failures simply because the cluster wizard continues. ## Step 5 — Create the WSFC Example: ```powershell New-Cluster ` -Name SQLCLUSTER ` -Node SQL01,SQL02 ` -StaticAddress 10.20.0.50 ``` Check cluster state: ```powershell Get-Cluster Get-ClusterNode ``` Expected node state should show both nodes available before SQL Server HA configuration continues. The exact cluster IP model depends on your network. Do not copy an example IP into production without confirming that it belongs to the intended private subnet and is unused. ## Step 6 — Configure quorum for the two-node cluster A two-node cluster should have a deliberate witness and quorum design so WSFC can make a safe membership decision when nodes lose communication. Common witness choices include: - file share witness; - cloud witness where supported by the environment; - disk witness for architectures that provide appropriate shared storage. Example file-share witness configuration: ```powershell Set-ClusterQuorum -FileShareWitness "\\WITNESS01\SQLClusterWitness" ``` Verify: ```powershell Get-ClusterQuorum ``` Avoid placing the witness on a dependency that is likely to fail with the same event that takes out both SQL nodes. ## Step 7 — Configure only the network paths the design needs An Always On deployment uses several Windows and SQL Server services. Common ports include: | Purpose | Typical port | |---|---:| | SQL Server client connection | TCP 1433 or your configured SQL port | | AG database mirroring endpoint | TCP 5022 by convention, or your configured endpoint port | | SMB file-share witness | TCP 445 | | DNS | TCP/UDP 53 as required | | Kerberos | TCP/UDP 88 as required | | LDAP | TCP/UDP 389 as required | | WSFC / RPC | Windows clustering and dynamic RPC requirements | The endpoint port is configurable; `5022` is common but not mandatory. Example rule restricted to the private SQL subnet: ```powershell New-NetFirewallRule ` -DisplayName "SQL AG Endpoint 5022" ` -Direction Inbound ` -Protocol TCP ` -LocalPort 5022 ` -RemoteAddress "10.20.0.0/24" ` -Action Allow ``` Do not broadly publish the SQL listener, AG endpoint, cluster RPC surface, or directory-service ports to the internet. ## Step 8 — Enable Always On on both SQL Server instances On each SQL node: 1. Open **SQL Server Configuration Manager**. 2. Open **SQL Server Services**. 3. Open the SQL Server service properties. 4. Select **Always On High Availability**. 5. Enable **Always On Availability Groups**. 6. Restart the SQL Server service. Verify: ```sql SELECT SERVERPROPERTY('IsHadrEnabled') AS IsHadrEnabled; ``` Expected: ```text 1 ``` For the traditional Windows HA design, Microsoft requires each participating SQL Server instance to be on a WSFC node and replicas in a given AG to reside on different nodes of the same WSFC. ## Step 9 — Verify or create the database mirroring endpoint Each SQL Server instance participating in the AG needs a database mirroring endpoint. Check first: ```sql SELECT name, state_desc, role_desc, type_desc FROM sys.database_mirroring_endpoints; ``` If an endpoint does not exist, create one using the authentication model designed for your environment. A common domain-based example is: ```sql CREATE ENDPOINT [Hadr_endpoint] STATE = STARTED AS TCP (LISTENER_PORT = 5022) FOR DATABASE_MIRRORING ( ROLE = ALL, AUTHENTICATION = WINDOWS NEGOTIATE, ENCRYPTION = REQUIRED ALGORITHM AES ); GO ``` Grant endpoint access to the required SQL Server service identities as appropriate for the deployment. ## Step 10 — Prepare the availability database The database needs FULL recovery model before normal AG data protection can be established. ```sql ALTER DATABASE AppDB SET RECOVERY FULL; GO ``` Take a full backup and then a log backup: ```sql BACKUP DATABASE AppDB TO DISK = 'B:\SQL\Backups\AppDB_full.bak' WITH INIT, COMPRESSION, CHECKSUM, STATS = 10; GO BACKUP LOG AppDB TO DISK = 'B:\SQL\Backups\AppDB_log.trn' WITH INIT, COMPRESSION, CHECKSUM, STATS = 10; GO ``` If you seed manually, restore the backups on SQL02 with `NORECOVERY` before joining the database to the AG. ```sql RESTORE DATABASE AppDB FROM DISK = 'B:\SQL\Backups\AppDB_full.bak' WITH NORECOVERY, REPLACE; GO RESTORE LOG AppDB FROM DISK = 'B:\SQL\Backups\AppDB_log.trn' WITH NORECOVERY; GO ``` Automatic seeding is another supported option when the environment and database size make it appropriate. Whichever method you choose, monitor transfer time, log growth, and synchronization rather than assuming seeding completed correctly. ## Step 11 — Create the availability group In SQL Server Management Studio: ```text Always On High Availability → Availability Groups → New Availability Group Wizard ``` For a two-node local HA pair, a common target is: ```text SQL01 - synchronous commit - automatic failover SQL02 - synchronous commit - automatic failover ``` Automatic failover is only safe when the secondary is synchronized and the failover mode and WSFC health meet the required conditions. For a remote DR replica, asynchronous commit plus manual failover is usually more appropriate because synchronous commit can add application write latency over long-distance links. ## Step 12 — Create and use an availability group listener An availability group listener is a virtual network name that lets clients connect without knowing which physical replica is primary. Example: ```text Listener DNS name: sql-app01-listener Listener port: 1433 Listener IP: 10.20.0.60 ``` Applications should connect to the listener rather than to `SQL01` directly. Example connection target: ```text Server=sql-app01-listener;Database=AppDB;Integrated Security=True;TrustServerCertificate=False; ``` For multi-subnet deployments, review current client-driver guidance for settings such as `MultiSubnetFailover=True`. Listener design is simpler in a single subnet, but DNS, virtual IP, client driver, firewall, and certificate behavior still need validation. Test connectivity from the actual application network: ```powershell Test-NetConnection sql-app01-listener -Port 1433 ``` ## Step 13 — Verify synchronization before failover testing Check database-level synchronization: ```sql SELECT ag.name AS availability_group, ar.replica_server_name, db.name AS database_name, drs.synchronization_state_desc, drs.synchronization_health_desc FROM sys.dm_hadr_database_replica_states AS drs JOIN sys.availability_replicas AS ar ON drs.replica_id = ar.replica_id JOIN sys.availability_groups AS ag ON ar.group_id = ag.group_id JOIN sys.databases AS db ON drs.database_id = db.database_id; ``` For a healthy synchronous pair before planned failover, expect the intended secondary database to report `SYNCHRONIZED` and healthy synchronization state. If the database shows `NOT SYNCHRONIZING`, investigate endpoints, SQL error logs, WSFC state, DNS, firewall rules, database state, and the send/redo queues before testing failover. ## Step 14 — Test the listener and manual failover with the real application Do not validate only from SSMS. First prove the application connects through the listener. Then, during a maintenance window, perform a planned manual failover while the target secondary is synchronized. On the target secondary: ```sql ALTER AVAILABILITY GROUP AG_APP01 FAILOVER; GO ``` After failover verify: - the former secondary is now primary; - the listener routes new client connections to the new primary; - the application reconnects without changing its node name; - the former primary rejoins as a secondary; - synchronization returns to healthy state; - SQL Agent jobs and server-level dependencies behave as expected; - monitoring records the event. The database can fail over correctly while the application still fails because of retry logic, login synchronization, DNS behavior, or a node-specific dependency. That is why application-level validation matters. ## Automatic failover requirements For the common two-node WSFC design, automatic failover normally requires: - synchronous-commit replicas; - automatic failover mode configured on the failover partners; - a synchronized secondary; - healthy WSFC membership and quorum; - the AG resource and SQL Server instances healthy enough for the configured failure condition; - applications connecting through a failover-aware endpoint such as the listener. Do not simulate outages by randomly killing infrastructure in production. Use a maintenance window, verified backups, an explicit rollback path, and a defined success criterion. ## SQL Server 2025 fast failover setting SQL Server 2025 allows the availability-group resource `RestartThreshold` to be changed from the default `1` to `0` so WSFC can skip the local AG-resource restart attempt and move directly to failover for a persistent health issue. This can reduce failover delay in the right environment, but it can also make the cluster more aggressive. Evaluate it only after baseline failover behavior is measured and application reconnect behavior is understood. ## Backup strategy for Always On An availability group is not a backup system. Keep a separate recovery strategy with: - full backups; - differential backups where appropriate; - transaction log backups; - backup integrity checks; - off-server or off-instance backup storage; - restore testing; - retention aligned to business requirements; - backup-job monitoring. On Enterprise-class AGs, backup preference can be used to influence where supported backup jobs run. SQL Server 2025 broadens secondary-replica backup capabilities by allowing full and differential backups on supported secondary replicas in addition to existing secondary backup options. For **Standard Basic AGs**, the secondary replica still cannot be used for backups. For a dedicated backup workflow, see [MSSQL Backup Strategy on Windows VPS](/windows-server/mssql-backup-strategy-windows-vps). ## Monitor more than replica role Monitor at least: - replica role; - synchronization state and health; - log send queue; - redo queue; - endpoint connectivity; - listener reachability; - WSFC node and quorum state; - SQL Server error log; - Windows failover-clustering events; - backup success; - transaction-log growth; - disk latency and free space; - SQL Agent jobs; - application connection failures after failover. Example replica query: ```sql SELECT ag.name AS ag_name, ar.replica_server_name, ars.role_desc, ars.connected_state_desc, ars.synchronization_health_desc, ars.operational_state_desc FROM sys.dm_hadr_availability_replica_states AS ars JOIN sys.availability_replicas AS ar ON ars.replica_id = ar.replica_id JOIN sys.availability_groups AS ag ON ar.group_id = ag.group_id; ``` An AG can look superficially online while replication queues, backups, listener connectivity, or cluster health are already degraded. Alert on persistent unhealthy states instead of relying on manual dashboard checks. ## Keep server-level objects synchronized Availability Groups protect selected databases. They do not automatically make the complete SQL Server instance identical on every replica. Track: - SQL logins and SIDs; - SQL Agent jobs; - linked servers; - credentials; - operators and alerts; - server-level permissions; - certificates and keys required by the application; - endpoints; - instance configuration; - application-specific external dependencies. A successful database failover is not useful if the new primary is missing the login, job, certificate, or linked server the workload requires. ## Common SQL Server Always On mistakes ### Treating Always On as backup Logical mistakes can replicate to the secondary. Maintain independent backups and prove that restores work. ### Using Standard Basic AG for a multi-database application A Basic AG protects one availability database. If several databases must fail over as one application unit, use a design that supports that requirement. ### Connecting the application to SQL01 instead of the listener A node-specific connection string defeats much of the application failover benefit. Connect through the listener and test the real client driver. ### Running SQL Server replicas on domain controllers Microsoft does not support availability-group host systems that are domain controllers. Use dedicated member servers for the SQL nodes. ### Assuming two nodes automatically mean safe quorum Design and verify quorum and witness placement. Test loss scenarios rather than assuming the cluster will choose the desired surviving side. ### Exposing SQL and cluster traffic publicly Keep replica, listener, AD, and WSFC communication on private or otherwise controlled network paths. Scope firewall rules to the systems that need them. ### Ignoring server-level objects Synchronize logins, jobs, linked servers, credentials, certificates, and other instance dependencies. ### Never testing failover An untested AG is not a validated recovery plan. Test both SQL failover and application reconnect behavior. ## Raff recommendation for a two-node SQL Server HA deployment For most small-team or MSP deployments that genuinely need SQL Server HA: 1. Define RTO and RPO before selecting the topology. 2. Use Standard Basic AG only when its one-database, two-replica limits fit the workload. 3. Use Enterprise when multi-database failover, readable secondaries, backup offload, or larger replica topologies are requirements. 4. Use two separate Windows VMs with comparable SQL configuration. 5. Keep SQL, WSFC, listener, and directory traffic on private or controlled network paths. 6. Validate WSFC and quorum before creating the AG. 7. Make applications connect through the listener. 8. Keep server-level objects synchronized separately. 9. Test planned failover with the actual application. 10. Maintain independent backups and restore tests. :::cta Deploy Windows Now Deploy Windows VMs for a self-managed SQL Server high-availability architecture, then build and validate WSFC, the availability group, listener, backups, and monitoring for your workload. ::: ## Validation scope This article was revalidated on **September 11, 2026** against current Microsoft documentation for SQL Server 2025 Always On availability groups, WSFC prerequisites, Basic Availability Group restrictions, availability-group listeners, secondary-replica backups, and SQL Server 2025 failover behavior. This is architecture and configuration guidance. It does **not** claim a fresh end-to-end “Tested on Raff” SQL Server Always On lab run because no September 2026 two-node AG test record with screenshots, exact SQL Server builds, failover measurements, and named tester is attached to this page. ## What's next - [Install SQL Server 2025 on a Windows Server VPS](/windows-server/install-sql-server-2025-windows-server-vps) - [SQL Server Standard vs Enterprise](/windows-server/sql-server-standard-vs-enterprise) - [MSSQL Backup Strategy on Windows VPS](/windows-server/mssql-backup-strategy-windows-vps) - [MSSQL Memory Tuning on Windows VPS](/windows-server/mssql-memory-tuning) - [Active Directory Domain Controller on Windows VPS](/windows-server/active-directory-domain-controller) - [Active Directory Replication Topology](/windows-server/ad-replication-topology) - [Windows Server Hardening Checklist](/windows-server/windows-server-hardening-checklist) - [SQL Server hosting](/products/sql-server-hosting) ## Sources - Microsoft Learn — Prerequisites, restrictions, and recommendations for Always On availability groups: https://learn.microsoft.com/en-us/sql/database-engine/availability-groups/windows/prereqs-restrictions-recommendations-always-on-availability - Microsoft Learn — Basic Availability Groups for a single database: https://learn.microsoft.com/en-us/sql/database-engine/availability-groups/windows/basic-availability-groups-always-on-availability-groups - Microsoft Learn — Windows Server Failover Clustering and Always On availability groups: https://learn.microsoft.com/en-us/sql/database-engine/availability-groups/windows/failover-clustering-and-always-on-availability-groups-sql-server - Microsoft Learn — Enable Always On Availability Groups: https://learn.microsoft.com/en-us/sql/database-engine/availability-groups/windows/configuration-of-a-server-instance-for-always-on-availability-groups-sql-server - Microsoft Learn — Availability group listener overview: https://learn.microsoft.com/en-us/sql/database-engine/availability-groups/windows/availability-group-listener-overview - Microsoft Learn — Offload backups to secondary availability-group replicas: https://learn.microsoft.com/en-us/sql/database-engine/availability-groups/windows/active-secondaries-backup-on-secondary-replicas-always-on-availability-groups - Microsoft Learn — Failover and failover modes for availability groups: https://learn.microsoft.com/en-us/sql/database-engine/availability-groups/windows/failover-and-failover-modes-always-on-availability-groups - Microsoft Learn — Editions and supported features of SQL Server 2025: https://learn.microsoft.com/en-us/sql/sql-server/editions-and-components-of-sql-server-2025 - Sources revalidated: 2026-09-11 --- ### SQL Server Backup Strategy: Full, Differential & Log Backups (2026) URL: https://rafftechnologies.com/windows-server/mssql-backup-strategy Description: Build a practical SQL Server backup strategy with full, differential, and transaction log backups. Covers recovery models, RPO/RTO, retention, off-server copies, automation, and restore testing. ## In short A reliable **SQL Server backup strategy** starts with the business recovery target, not a fixed schedule copied from another server. Define how much data you can afford to lose (RPO) and how quickly the database must be restored (RTO), choose the correct recovery model, then combine full, differential, and transaction log backups only where they support those targets. For databases in the `FULL` recovery model, transaction log backups are what make point-in-time recovery possible and keep the log backup chain moving. For `SIMPLE` recovery databases, use full and, where useful, differential backups because transaction log backups are not available. The most important rule is operational: > A backup strategy is not proven until you have restored it successfully and measured how long recovery actually takes. ## SQL Server backup strategy: quick answer | Requirement | Practical starting approach | |---|---| | Dev/test database with low recovery requirements | Regular FULL backups may be enough | | Small production database in SIMPLE recovery | FULL + optional DIFFERENTIAL backups | | Production database needing point-in-time recovery | FULL + optional DIFFERENTIAL + frequent LOG backups | | Very low RPO | Shorter transaction log backup interval | | Large database with long full-backup windows | Use DIFFERENTIAL backups between FULL backups | | Ad-hoc backup before a risky change | Consider a COPY_ONLY FULL backup | | SQL Server Express | Automate with Windows Task Scheduler + `sqlcmd` | | SQL Server Standard / Enterprise | SQL Server Agent is usually the cleaner scheduler | | Business-critical workload | Keep an off-server copy and run restore drills | Do not treat `daily full + 4-hour differential + 15-minute logs` as a universal best practice. Those intervals can be reasonable for some workloads, but the schedule should follow the RPO, RTO, database size, change rate, backup duration, and restore process. ## What are full, differential, and transaction log backups? SQL Server has several backup types, but these three cover the most common production strategy. | Backup type | What it contains | Main role in recovery | |---|---|---| | FULL database backup | The complete database plus enough transaction log to recover the backed-up data consistently | Main restore baseline | | DIFFERENTIAL backup | Extents changed since the most recent conventional full backup | Reduces the amount of data and number of log backups needed during restore | | TRANSACTION LOG backup | Log records not yet backed up in the normal log backup sequence | Point-in-time recovery and shorter data-loss window in FULL/BULK_LOGGED recovery | A differential backup always depends on its **differential base**, normally the most recent conventional full backup. A `COPY_ONLY` full backup does not become a new differential base. ## RPO and RTO should determine the schedule Before deciding how often backups run, define two recovery objectives. | Term | Question it answers | Example | |---|---|---| | RPO — Recovery Point Objective | How much recent data can the business lose? | No more than 15 minutes | | RTO — Recovery Time Objective | How quickly must the database be operational again? | Within 60 minutes | If the RPO is 15 minutes, a transaction log backup every hour cannot meet that target. If the RTO is 30 minutes but restoring the latest full backup takes 45 minutes, the backup schedule is also not meeting the requirement. That is why backup frequency and restore duration must be designed together. ## How often should SQL Server backups run? Use the table below as **planning examples**, not fixed rules. | Workload | FULL | DIFFERENTIAL | LOG | Why | |---|---|---|---|---| | Dev/test or low-change internal database | Daily or according to need | Optional | Not applicable in SIMPLE | Low recovery requirement | | Normal production database | Daily | Every 4–6 hours if useful | Every 15–30 minutes when RPO requires it | Balanced restore chain | | Transaction-heavy business database | Daily | Every 2–4 hours if useful | Every 5–15 minutes when RPO requires it | Smaller potential data-loss window | | Large database with expensive FULL backups | Based on maintenance window | More frequent differentials | Based on RPO | Avoid unnecessary full-backup overhead | A 5-minute log interval is not automatically better than 15 minutes. Shorter intervals create more backup files and operational work. Choose the interval that satisfies the business RPO and that your monitoring, copy, retention, and restore processes can reliably manage. ## What we tested on Raff The original backup workflow was tested on a Raff Windows VPS running Windows Server 2025 Datacenter Evaluation and SQL Server 2025 Express. ![PowerShell output showing the original SQL-related services on the Raff Windows VPS before installing SQL Server Express.](https://raff-images.s3.raffusercloud.com/01_mssql_backup_test_environment_9b44232a75.png) | Item | Value | |---|---| | Provider | Raff Technologies | | OS | Windows Server 2025 Datacenter Evaluation | | SQL Server | SQL Server 2025 Express | | Instance | `SQLEXPRESS` | | SQL version | `17.0.1000.7, RTM` | | Test database | `RaffBackupTest` | | Original test date | 2026-05-26 | | Tester | Serdar Tekin | The lab verified: - SQL Server 2025 Express installation; - SQL Server service state and `sqlcmd` access; - sample database creation; - recovery model inspection and FULL recovery configuration; - backup directory permissions; - FULL, DIFFERENTIAL, and LOG backup commands; - backup files written to disk; - `RESTORE VERIFYONLY` against the full backup. SQL Server Express was useful for validating the backup workflow, but it does not include SQL Server Agent and does not support backup compression. Microsoft currently documents backup compression support for Enterprise, Standard, and Developer editions. This September update reworks the strategy, scheduling, recovery-model, COPY_ONLY, retention, and restore guidance. It does not claim a new end-to-end backup benchmark. ## Recovery models determine what backup strategy is possible Check the recovery model of every user database before designing the schedule: ```sql SELECT name, recovery_model_desc FROM sys.databases ORDER BY name; ``` | Recovery model | Transaction log backups? | Typical use | |---|---:|---| | SIMPLE | No | Dev/test, reporting, or workloads that do not require point-in-time recovery | | FULL | Yes | Production workloads where point-in-time recovery and low RPO matter | | BULK_LOGGED | Yes, with recovery limitations around minimally logged operations | Specialized bulk-load scenarios | Do not choose `FULL` only because the database is important. Choose it because the recovery requirement needs a log backup chain and point-in-time recovery. In the original Raff lab, we switched the test database to FULL recovery: ```sql ALTER DATABASE RaffBackupTest SET RECOVERY FULL; ``` Then verified it: ```sql SELECT name, recovery_model_desc FROM sys.databases WHERE name = 'RaffBackupTest'; ``` ![SQL command output showing the RaffBackupTest sample database and its recovery model.](https://raff-images.s3.raffusercloud.com/05_sample_database_recovery_model_a66ef33199.png) After moving a database from SIMPLE to FULL, take a new full backup as a clean operational baseline before relying on the transaction log backup chain. ## SQL Server Express vs Standard and Enterprise for backups The core `BACKUP DATABASE` and `BACKUP LOG` commands work across SQL Server editions, subject to the recovery model and feature limits. The biggest operational difference for a small self-managed deployment is automation. | Feature | Express | Standard | Enterprise | |---|---:|---:|---:| | FULL database backup | Yes | Yes | Yes | | DIFFERENTIAL backup | Yes | Yes | Yes | | Transaction log backup in FULL/BULK_LOGGED | Yes | Yes | Yes | | SQL Server Agent | No | Yes | Yes | | Windows Task Scheduler + `sqlcmd` | Yes | Yes | Yes | | Backup compression | No | Yes | Yes | Developer edition also supports backup compression, but it is for development/test licensing rather than production use. For edition planning, see [SQL Server Standard vs Enterprise](/windows-server/mssql-standard-vs-enterprise). ## Step 1 — Confirm the SQL Server instance and version Run PowerShell as Administrator: ```powershell Get-Service | Where-Object {$_.Name -like "MSSQL*"} | Select-Object Name, Status, DisplayName ``` ![PowerShell output showing SQL Server SQLEXPRESS service running and sqlcmd available on the Raff Windows VPS.](https://raff-images.s3.raffusercloud.com/03_sql_server_service_running_35a6f952f1.png) Check the SQL Server version: ```powershell sqlcmd -S localhost\SQLEXPRESS -E -C -Q "SELECT @@VERSION AS SQLVersion;" ``` ![SQL Server 2025 Express installer showing successful installation with the SQLEXPRESS instance and SQL engine installed.](https://raff-images.s3.raffusercloud.com/02_sql_server_2025_express_installed_266fb9a8a0.png) The `-C` option trusts the server certificate for this local `sqlcmd` connection. Do not use certificate-trust shortcuts as a substitute for a properly trusted production TLS configuration on remote connections. ## Step 2 — Create a backup directory and permissions Create a local backup folder: ```powershell New-Item -ItemType Directory -Path 'C:\SQL\Backups' -Force ``` Grant the SQL Server Express service account access: ```powershell icacls 'C:\SQL\Backups' /grant 'NT SERVICE\MSSQL$SQLEXPRESS:(OI)(CI)F' ``` Verify the directory: ```powershell Get-ChildItem C:\SQL ``` ![PowerShell output showing the SQL backup folder created for the RaffBackupTest workflow.](https://raff-images.s3.raffusercloud.com/06_backup_folder_created_b2dea5f0fb.png) For production, the backup folder is a staging location, not the entire disaster-recovery plan. Keep a copy outside the live SQL Server VM and preferably across a separate security or failure boundary. ## Step 3 — Take a full SQL Server backup A full backup is the main restore baseline. The Express lab used: ```powershell sqlcmd -S localhost\SQLEXPRESS -E -C -Q "BACKUP DATABASE [RaffBackupTest] TO DISK = N'C:\SQL\Backups\RaffBackupTest_FULL.bak' WITH INIT, CHECKSUM, STATS = 10;" ``` ![sqlcmd output showing a successful full backup of the RaffBackupTest database.](https://raff-images.s3.raffusercloud.com/07_full_backup_created_da7056df86.png) For an edition that supports backup compression: ```sql BACKUP DATABASE [YourDB] TO DISK = N'C:\SQL\Backups\YourDB_FULL.bak' WITH INIT, COMPRESSION, CHECKSUM, STATS = 10; ``` SQL Server 2025 also supports the ZSTD backup-compression algorithm on editions that support backup compression. Do not add a compression algorithm just because it is newer; test backup time, restore time, CPU use, and storage savings for the actual workload. ### Why use CHECKSUM? `WITH CHECKSUM` asks SQL Server to perform additional verification during the backup operation and write backup checksums. It is a useful integrity control, but it does not replace a restore test. ### Avoid one permanent backup file The fixed file name above exists for a readable lab demonstration. In production, use unique timestamped names so each backup set has an independent file and your retention process can manage them safely. Example: ```text YourDB_FULL_20260901_020000.bak ``` ## Step 4 — Take a differential SQL Server backup A differential backup contains data changed since the differential base, normally the most recent conventional full backup. ```powershell sqlcmd -S localhost\SQLEXPRESS -E -C -Q "BACKUP DATABASE [RaffBackupTest] TO DISK = N'C:\SQL\Backups\RaffBackupTest_DIFF.bak' WITH DIFFERENTIAL, INIT, CHECKSUM, STATS = 10;" ``` ![sqlcmd output showing a successful differential backup of the RaffBackupTest database.](https://raff-images.s3.raffusercloud.com/08_differential_backup_created_fc606d71b8.png) Differentials become more valuable when the database is large enough that frequent full backups are expensive, but only a portion of the database changes between full backups. A typical restore with a differential is: ```text Latest conventional FULL → latest DIFFERENTIAL based on that FULL → required LOG backups after the differential → RECOVERY ``` As more data changes after the full backup, differential backups usually become larger. Eventually a new full backup creates a new differential base. ## Step 5 — Take a transaction log backup Transaction log backups apply only to databases using the FULL or BULK_LOGGED recovery models. ```powershell sqlcmd -S localhost\SQLEXPRESS -E -C -Q "BACKUP LOG [RaffBackupTest] TO DISK = N'C:\SQL\Backups\RaffBackupTest_LOG.trn' WITH INIT, CHECKSUM, STATS = 10;" ``` After a valid log backup chain exists, regular log backups reduce the amount of work that can be lost and allow log truncation to progress when no other condition is preventing truncation. A database in FULL recovery with no regular log-backup process can experience continuous transaction-log growth. If the log is growing, check the actual log-reuse wait reason rather than assuming backups are the only possible cause. Use: ```sql SELECT name, recovery_model_desc, log_reuse_wait_desc FROM sys.databases WHERE name = 'RaffBackupTest'; ``` This distinguishes `LOG_BACKUP` from other causes such as active transactions, replication, availability features, or other log-reuse waits. ## Step 6 — Confirm backup files and backup history Check the files on disk: ```powershell Get-ChildItem 'C:\SQL\Backups' | Select-Object Name, Length, LastWriteTime ``` ![PowerShell output showing SQL Server full, differential, and log backup files created on disk.](https://raff-images.s3.raffusercloud.com/10_backup_files_on_disk_0a9d279a84.png) Then inspect SQL Server backup history from `msdb`: ```sql SELECT TOP (50) database_name, CASE type WHEN 'D' THEN 'Full' WHEN 'I' THEN 'Differential' WHEN 'L' THEN 'Transaction Log' ELSE type END AS backup_type, backup_start_date, backup_finish_date, backup_size, compressed_backup_size, is_copy_only FROM msdb.dbo.backupset WHERE database_name = 'RaffBackupTest' ORDER BY backup_finish_date DESC; ``` File existence proves that something was written. Backup history helps confirm what SQL Server believes was completed, when it finished, and whether it was a full, differential, log, or copy-only backup. ## Step 7 — Verify backups, then perform real restore tests Run `RESTORE VERIFYONLY` with checksum against the full backup: ```powershell sqlcmd -S localhost\SQLEXPRESS -E -C -Q "RESTORE VERIFYONLY FROM DISK = N'C:\SQL\Backups\RaffBackupTest_FULL.bak' WITH CHECKSUM;" ``` ![sqlcmd output showing RESTORE VERIFYONLY successfully validated the SQL Server backup file.](https://raff-images.s3.raffusercloud.com/11_restore_verifyonly_result_0c1544d95b.png) `RESTORE VERIFYONLY` is useful because SQL Server reads the backup and verifies that the backup set is complete and readable. It is **not the same as restoring the database and validating the application**. A production restore drill should prove: - the required backup files are available; - the restore sequence is understood; - credentials and permissions work; - the database comes online; - `DBCC CHECKDB` can complete successfully where appropriate; - the application can connect to the restored database; - the measured restore time fits the RTO. ## COPY_ONLY backups: use them for ad-hoc full backups Sometimes you need a one-off full backup before a deployment, migration, or risky maintenance operation but do not want to alter the normal differential backup base. Use `COPY_ONLY`: ```sql BACKUP DATABASE [YourDB] TO DISK = N'C:\SQL\Backups\YourDB_COPY_ONLY.bak' WITH COPY_ONLY, CHECKSUM, STATS = 10; ``` A copy-only full backup: - can be restored like a normal full backup; - does not become the differential base; - does not reset the differential bitmap for later scheduled differential backups. That makes it a good option for ad-hoc administrative backups that should not interfere with the scheduled backup strategy. Do not combine `COPY_ONLY` and `DIFFERENTIAL` expecting a special copy-only differential backup. `COPY_ONLY` does not apply meaningfully to differential backups. ## SQL Server backup compression in 2026 Microsoft currently documents backup compression support for SQL Server Enterprise, Standard, and Developer editions. SQL Server Express does not support creating compressed backups, although editions can restore compatible compressed backups according to Microsoft support rules. SQL Server 2025 adds `ZSTD` as a backup-compression algorithm alongside `MS_XPRESS`. For a production database, compression should be a measured choice: | Benefit | Tradeoff to monitor | |---|---| | Smaller backup files | Additional CPU use | | Less backup I/O in many workloads | Compression performance depends on data and workload | | Faster transfer to off-server storage | Restore behavior should also be tested | If backup windows are already CPU-constrained, test before changing the default across every database. ## Automating SQL Server Express backups SQL Server Express does not include SQL Server Agent, so Windows Task Scheduler is a practical option. A scheduled PowerShell or command task can call `sqlcmd`, for example: ```powershell sqlcmd -S localhost\SQLEXPRESS -E -C -Q "BACKUP DATABASE [YourDB] TO DISK = N'C:\SQL\Backups\YourDB_FULL.bak' WITH INIT, CHECKSUM, STATS = 10;" ``` A production Express setup should automate more than the backup command itself. Include: - unique timestamped filenames; - error handling and exit-code checks; - off-server copy; - retention cleanup; - disk-space monitoring; - alerting when a scheduled task fails; - periodic restore tests. A task that silently fails every night is not a backup system. ## Automating Standard and Enterprise with SQL Server Agent For Standard or Enterprise, SQL Server Agent usually provides a cleaner database-native scheduler. Create separate jobs or job steps for the required backup types and include failure notifications. At minimum monitor: - last successful backup time; - backup duration; - output file size; - free disk space; - failed SQL Agent jobs; - failed off-server copies; - age of the newest full and log backup; - restore-test results. Automation should make backup failure visible, not merely make backups unattended. ## Off-server backups need a separate failure boundary A `.bak` file on the same VM protects against some database-level failures, but it does not protect well against loss of the VM, compromised administrator credentials, ransomware, or accidental deletion of the whole server. Use a second location such as: - S3-compatible object storage; - another backup server; - a separate storage account or project; - another region when the business continuity design requires it. Where the storage platform supports it, stronger designs can also use versioning, retention controls, or immutable/object-lock style protection so a compromised server account cannot immediately delete every recovery point. Keep backup credentials separate from normal application credentials and grant only the permissions the copy process actually needs. ## Retention should follow recovery and compliance needs Do not keep every backup forever, and do not copy an arbitrary seven-day rule without understanding the restore requirement. A retention design should answer: - How far back might the business need to recover? - Are month-end or year-end recovery points required? - How much backup storage is available? - What does compliance require? - How long is the complete restore chain valid? - When can older full, differential, and log backups be deleted without breaking a required recovery path? Example only: | Recovery tier | Example retention | |---|---| | Recent operational backups | 7–14 days | | Daily/weekly recovery points | 30–90 days | | Monthly archival points | Based on business/compliance requirement | Make cleanup chain-aware. Do not delete the full backup or required log files while keeping a differential or later log backup that depends on them for a recovery point you still claim to support. ## Restore sequence for FULL recovery model A common restore path is: 1. Restore the required FULL backup with `NORECOVERY`. 2. Restore the latest applicable DIFFERENTIAL backup with `NORECOVERY`, if used. 3. Restore the required transaction log backups in sequence with `NORECOVERY`. 4. Recover the database at the final desired point. Example lab-style sequence: ```sql RESTORE DATABASE [YourDB_RestoreTest] FROM DISK = 'D:\BackupCopy\YourDB_FULL.bak' WITH NORECOVERY, REPLACE; RESTORE DATABASE [YourDB_RestoreTest] FROM DISK = 'D:\BackupCopy\YourDB_DIFF.bak' WITH NORECOVERY; RESTORE LOG [YourDB_RestoreTest] FROM DISK = 'D:\BackupCopy\YourDB_LOG_001.trn' WITH NORECOVERY; RESTORE DATABASE [YourDB_RestoreTest] WITH RECOVERY; ``` For a point-in-time restore, use the correct transaction log sequence and `STOPAT` on the appropriate final log restore instead of simply recovering the latest possible point. After the test restore: ```sql DBCC CHECKDB('YourDB_RestoreTest') WITH NO_INFOMSGS; ``` Then test the real application path. Database consistency alone does not prove the application can actually recover. ## Common SQL Server backup mistakes ### Using FULL recovery but not taking transaction log backups If point-in-time recovery is required, configure and monitor the log backup schedule. Otherwise the log can continue growing when `LOG_BACKUP` is preventing log reuse. ### Keeping every backup on the SQL Server VM A local backup is useful for fast recovery, but it should not be the only copy of business-critical data. ### Assuming a successful job means the database is recoverable A successful `BACKUP` command is only one part of recovery. Run actual restore drills. ### Resetting the differential base with an ad-hoc full backup Use a `COPY_ONLY` full backup when you need a one-off full backup without changing the normal differential base. ### Overwriting the same backup file forever Use timestamped files and controlled retention so multiple recovery points survive. ### Ignoring backup duration If the full backup takes longer than the maintenance window or the restore takes longer than the RTO, redesign the strategy instead of only changing the schedule. ### Deleting backups without understanding dependencies Differential and log backups depend on earlier backups. Retention cleanup must preserve the complete restore chain for every recovery point you promise. ### No alerts for failed backups or full disks Backups often fail because storage fills, permissions change, credentials expire, or scheduled jobs stop running. Monitor the process, not just the configuration. ## A practical production checklist Before calling a SQL Server database protected, verify: ```text RPO defined → RTO defined → recovery model chosen → full backup scheduled → differential schedule chosen if useful → log backups scheduled if FULL/BULK_LOGGED → unique backup files → off-server copy → retention policy → backup failure alerts → disk-space monitoring → RESTORE VERIFYONLY checks → real restore drill → restore time measured → application recovery validated ``` :::cta Running SQL Server in production? Use a Windows VM sized for the database, backup window, restore testing, and operational headroom. ::: ## What Raff recommends For production SQL Server workloads, design backups around recovery objectives rather than a generic timetable. Use FULL recovery only when the recovery requirement needs the log chain. Add differential backups when they reduce backup/restore overhead. Set the transaction log interval from the RPO. Keep at least one recovery copy outside the live SQL Server VM. Monitor failures and storage. Most importantly, run restore drills and record the real recovery time. For the rest of the SQL Server production stack, pair this guide with [SQL Server Max Server Memory](/windows-server/mssql-memory-tuning), [Configure TempDB for MSSQL Performance](/windows-server/mssql-tempdb-config), [SQL Server Standard vs Enterprise](/windows-server/mssql-standard-vs-enterprise), and [Windows Server Sizing by Workload](/windows-server/windows-server-sizing-by-workload). ## Tested on > Original backup workflow tested on Raff Windows VPS, Windows Server 2025 Datacenter Evaluation, SQL Server 2025 Express, SQLEXPRESS instance, SQL Server version 17.0.1000.7 RTM, 2026-05-26. The lab created FULL, DIFFERENTIAL, and LOG backups, confirmed files on disk, and validated the full backup with RESTORE VERIFYONLY. Tester: Serdar Tekin. Strategy, edition, COPY_ONLY, compression, and recovery guidance re-reviewed against current Microsoft SQL Server documentation on 2026-09-01; no new performance benchmark is claimed. ## What's next - [SQL Server Max Server Memory: How to Configure It Safely](/windows-server/mssql-memory-tuning) — keep SQL Server from starving Windows or other workloads - [Configure TempDB for MSSQL Performance](/windows-server/mssql-tempdb-config) — tune TempDB files, size, and growth - [SQL Server Standard vs Enterprise](/windows-server/mssql-standard-vs-enterprise) — choose the right paid production edition - [Install SQL Server 2025 on a Windows Server VPS](/windows-server/install-sql-server-2025-windows-server-vps) — build a clean SQL Server environment - [Windows Server Sizing by Workload](/windows-server/windows-server-sizing-by-workload) — size CPU, RAM, and storage around the server role - [SQL Server hosting](/products/sql-server-hosting) — deploy Windows Server infrastructure for SQL Server workloads ## Sources - Microsoft Learn — [Back up and restore of SQL Server databases](https://learn.microsoft.com/en-us/sql/relational-databases/backup-restore/back-up-and-restore-of-sql-server-databases?view=sql-server-ver17) - Microsoft Learn — [Full database backups](https://learn.microsoft.com/en-us/sql/relational-databases/backup-restore/full-database-backups-sql-server?view=sql-server-ver17) - Microsoft Learn — [Differential backups](https://learn.microsoft.com/en-us/sql/relational-databases/backup-restore/differential-backups-sql-server?view=sql-server-ver17) - Microsoft Learn — [Transaction log backups](https://learn.microsoft.com/en-us/sql/relational-databases/backup-restore/transaction-log-backups-sql-server?view=sql-server-ver17) - Microsoft Learn — [Copy-only backups](https://learn.microsoft.com/en-us/sql/relational-databases/backup-restore/copy-only-backups-sql-server?view=sql-server-ver17) - Microsoft Learn — [Backup compression](https://learn.microsoft.com/en-us/sql/relational-databases/backup-restore/backup-compression-sql-server?view=sql-server-ver17) - Microsoft Learn — [BACKUP Transact-SQL](https://learn.microsoft.com/en-us/sql/t-sql/statements/backup-transact-sql?view=sql-server-ver17) - Microsoft Learn — [RESTORE VERIFYONLY Transact-SQL](https://learn.microsoft.com/en-us/sql/t-sql/statements/restore-statements-verifyonly-transact-sql?view=sql-server-ver17) - Microsoft Learn — [Backup history and header information](https://learn.microsoft.com/en-us/sql/relational-databases/backup-restore/backup-history-and-header-information-sql-server?view=sql-server-ver17) - Date last verified: 2026-09-01 --- ### SQL Server Max Server Memory: How to Configure It Safely (2026) URL: https://rafftechnologies.com/windows-server/mssql-memory-tuning Description: Configure SQL Server max server memory safely on Windows Server. Learn how much RAM to reserve for the OS, check current settings, detect memory pressure, and tune dedicated or shared Windows VMs. ## In short `max server memory (MB)` is the main SQL Server setting used to stop the database engine from consuming so much memory that Windows Server and other workloads become starved. The right value is not a universal percentage. Start with the total RAM in the VM, reserve enough memory for Windows and every non-SQL workload, then give SQL Server the remainder and validate the choice under real load. For a dedicated SQL Server VM, SQL Server can usually receive most of the available RAM. If the same Windows VM also runs IIS, RDP/RDS users, backup software, monitoring, ERP components, or other business applications, reserve more memory outside SQL Server. The key rule is simple: > Set `max server memory` so Windows Server and non-SQL processes still have enough memory during peak workload. ## What should SQL Server max server memory be? There is no single correct percentage for every server. Use a workload-based starting point instead: | Total VM RAM | Dedicated SQL Server starting point | Shared SQL + IIS/RDP/apps starting point | |---:|---:|---:| | 4 GB | ~2 GB SQL | Usually too constrained for mixed production roles | | 8 GB | ~5 GB SQL | ~4-5 GB SQL | | 16 GB | ~12 GB SQL | ~10-12 GB SQL | | 32 GB | ~26 GB SQL | ~22-26 GB SQL | | 64 GB | ~52-56 GB SQL | ~44-52 GB SQL | | 128 GB+ | Size from measured workload | Size from measured workload | These are **starting examples, not universal best-practice values**. SQL Server edition limits, database working set, backup jobs, RDP sessions, IIS app pools, antivirus, monitoring agents, linked servers, and other processes can change the right value materially. For broader VM sizing, see [Windows Server Sizing by Workload](/windows-server/windows-server-sizing-by-workload). ## What is max server memory in SQL Server? SQL Server uses memory aggressively because memory improves database performance. It keeps frequently accessed data pages and execution plans in memory and also needs memory for query execution, locks, internal structures, columnstore, and other engine operations. `max server memory (MB)` limits the size of the SQL Server memory pool managed by the database engine. It is the most important memory setting for preventing SQL Server from taking too much RAM from the operating system. However, it is important to understand what it is **not**: > `max server memory` is not a hard cap on every byte used by the `sqlservr.exe` process. Some allocations can exist outside the memory controlled by this setting, including thread stacks, certain DLL or provider allocations, and other memory used outside the main SQL Server memory pool. That is why Task Manager can show SQL Server process memory above the configured value in some scenarios. Treat `max server memory` as the primary SQL Server memory control, then validate Windows available memory and actual process behavior after the change. ## Why SQL Server uses so much memory High SQL Server memory usage is not automatically a memory leak. SQL Server is designed to use available RAM for caching and query processing. On a healthy dedicated database server, seeing SQL Server use a large amount of memory can be completely normal. Memory becomes a problem when SQL Server is competing with Windows or other workloads and you start seeing symptoms such as: - Windows paging heavily; - RDP sessions becoming slow or unstable; - IIS worker processes struggling for memory; - backup or monitoring tools failing or slowing down; - `Memory Grants Pending` staying above zero; - Windows reporting sustained low available memory; - SQL Server reporting physical memory pressure; - query latency increasing at the same time memory pressure appears. Do not diagnose a memory problem from Task Manager alone. High SQL memory usage can be healthy; **memory pressure** is the real signal to investigate. ## What we tested on Raff The original configuration workflow was tested on a Raff Windows VPS running Windows Server 2025 Datacenter Evaluation and SQL Server 2025 Express. ![PowerShell output showing a Raff Windows VPS running Windows Server 2025 Datacenter Evaluation with SQL Server SQLEXPRESS service running.](https://raff-images.s3.raffusercloud.com/01_mssql_memory_test_environment_dd652e5e02.png) | Item | Value | |---|---| | Provider | Raff Technologies | | OS | Windows Server 2025 Datacenter Evaluation | | SQL Server | SQL Server 2025 Express | | Instance | `SQLEXPRESS` | | VPS size | 4 vCPU / approximately 8 GB RAM | | Original test date | 2026-05-26 | | Tester | Aybars Altinyay | The original lab verified: - Windows Server and SQL Server service state; - total and free Windows memory; - current SQL Server memory configuration; - SQL Server process memory usage; - setting `max server memory (MB)`; - verifying the new memory cap. This September update improves the sizing guidance and memory-pressure diagnostics. It does not claim a new benchmark or a new end-to-end lab test. ## SQL Server Express note SQL Server Express has edition-specific memory and compute limits, so it does not behave like a larger Standard or Enterprise production instance under load. The configuration workflow is still useful: 1. Check total Windows RAM. 2. Check the existing SQL Server memory settings. 3. Inspect actual SQL Server memory usage. 4. Set `max server memory`. 5. Verify the running value. 6. Monitor Windows and SQL Server pressure signals. For production edition planning, see [SQL Server Standard vs Enterprise](/windows-server/mssql-standard-vs-enterprise). ## Step 1 - Check total and free Windows memory Before changing SQL Server settings, establish the Windows memory baseline. Run PowerShell as Administrator: ```powershell $os = Get-CimInstance Win32_OperatingSystem [PSCustomObject]@{ TotalRAM_GB = [math]::Round($os.TotalVisibleMemorySize / 1MB, 2) FreeRAM_GB = [math]::Round($os.FreePhysicalMemory / 1MB, 2) } ``` ![PowerShell output showing total and free Windows memory on a Raff Windows VPS before SQL Server memory tuning.](https://raff-images.s3.raffusercloud.com/02_windows_memory_baseline_2c732f46bc.png) Run this during both quiet and busy periods when possible. If the server already has low free memory before SQL Server reaches normal workload, do not simply increase the SQL Server memory cap. Identify the other processes using memory or resize the VM. ## Step 2 - Check the current max server memory setting For the `SQLEXPRESS` instance, run: ```powershell sqlcmd -S localhost\SQLEXPRESS -E -C -Q "EXEC sp_configure 'show advanced options', 1; RECONFIGURE; EXEC sp_configure 'max server memory (MB)'; EXEC sp_configure 'min server memory (MB)';" ``` ![sqlcmd output showing current SQL Server min server memory and max server memory configuration values.](https://raff-images.s3.raffusercloud.com/03_current_sql_memory_config_e1b00defa9.png) Look at both: ```text config_value run_value ``` If `max server memory (MB)` is left at an extremely high default value, SQL Server is effectively uncapped within its edition and operating constraints. That can be acceptable in some carefully managed dedicated environments, but it is a poor default for a shared Windows VM where IIS, RDP users, backup agents, or other business applications need predictable memory. ## Step 3 - Check actual SQL Server process memory Use PowerShell to see current SQL Server working set and private memory: ```powershell Get-Process | Where-Object {$_.ProcessName -like "sqlservr*"} | Select-Object ProcessName, Id, @{Name="WorkingSet_MB";Expression={[math]::Round($_.WorkingSet64/1MB,2)}}, @{Name="PrivateMemory_MB";Expression={[math]::Round($_.PrivateMemorySize64/1MB,2)}} ``` ![PowerShell output showing SQL Server process working set and private memory usage on a Windows VPS.](https://raff-images.s3.raffusercloud.com/04_sql_process_memory_usage_af60a9b0b2.png) A low value on a test database only means the current workload is small. It does not prove the instance is correctly sized. Also check SQL Server's view of its memory target: ```sql SELECT total_server_memory_kb / 1024 AS total_server_memory_mb, target_server_memory_kb / 1024 AS target_server_memory_mb FROM sys.dm_os_sys_memory; ``` If your SQL Server version does not expose the information you need through that DMV, use the SQL Server performance counters shown later in this guide. ## Step 4 - Choose a safe max server memory value Start with three questions: 1. How much total RAM does the VM have? 2. What else runs on the VM besides SQL Server? 3. How much memory does Windows still need during peak workload? ### Dedicated SQL Server VM A dedicated SQL Server VM can usually allocate most of its RAM to SQL Server while reserving enough for Windows, security agents, backup software, and administration. Example starting points: | Total RAM | Example SQL max memory | |---:|---:| | 8 GB | 5-6 GB | | 16 GB | 12-13 GB | | 32 GB | 24-28 GB | | 64 GB | 52-56 GB | ### Shared SQL Server + IIS/RDP/apps Reserve more memory when the same Windows VM also hosts user sessions or application services. | Total RAM | Example SQL max memory | |---:|---:| | 8 GB | 4-5 GB | | 16 GB | 10-12 GB | | 32 GB | 22-26 GB | | 64 GB | 44-52 GB | Use more reservation when the server also runs: - IIS application pools; - RDP or RDS user sessions; - ERP or accounting applications; - antivirus/EDR scans; - backup agents; - monitoring agents; - file services; - SSIS or reporting workloads; - other database engines. For the original approximately 8 GB Raff test VM, the lab used: ```text 4096 MB ``` That value was intentionally conservative for a small shared-style test environment. It should not be copied automatically to every 8 GB production database server. ## Step 5 - Set max server memory with T-SQL To set `max server memory (MB)` to 4096 MB on the test instance: ```powershell sqlcmd -S localhost\SQLEXPRESS -E -C -Q "EXEC sp_configure 'show advanced options', 1; RECONFIGURE; EXEC sp_configure 'max server memory (MB)', 4096; RECONFIGURE;" ``` ![sqlcmd output showing max server memory set to 4096 MB for SQL Server on a Windows VPS.](https://raff-images.s3.raffusercloud.com/05_set_max_server_memory_a36e671284.png) The change normally does not require a Windows reboot. SQL Server adjusts memory usage over time, so the process may not immediately drop to the exact new value the moment you run `RECONFIGURE`. ## Step 6 - Verify the new max server memory value Run: ```powershell sqlcmd -S localhost\SQLEXPRESS -E -C -Q "EXEC sp_configure 'max server memory (MB)';" ``` Expected result for the original test: ```text config_value run_value 4096 4096 ``` ![sqlcmd output verifying max server memory is set to 4096 MB.](https://raff-images.s3.raffusercloud.com/06_verify_max_server_memory_aa38c3e9ce.png) If `config_value` and `run_value` match, the setting is active. The next step is not to stop monitoring. Verify that Windows still has healthy memory headroom and that SQL Server is not now too constrained for its workload. ## How to check max server memory in SQL Server You can check the current setting directly in SSMS or through `sqlcmd`: ```sql EXEC sys.sp_configure 'max server memory (MB)'; ``` For a cleaner query against the configuration table: ```sql SELECT name, value AS configured_value, value_in_use FROM sys.configurations WHERE name IN ('min server memory (MB)', 'max server memory (MB)'); ``` Use `value_in_use` to confirm the setting currently applied by SQL Server. ## How to change max server memory in SQL Server Use `sp_configure`: ```sql EXEC sys.sp_configure 'show advanced options', 1; RECONFIGURE; GO EXEC sys.sp_configure 'max server memory (MB)', 12288; RECONFIGURE; GO ``` The example above sets SQL Server to approximately 12 GB. Choose the actual number from the server's RAM, workload, edition, and non-SQL memory requirements. Do not copy `12288` into production merely because it appears in an example. ## What about min server memory? `min server memory (MB)` is often misunderstood. It does **not** force SQL Server to reserve the configured amount immediately at startup. SQL Server grows memory as the workload needs it. After the instance grows above the configured minimum, the setting influences how far the engine will shrink its memory pool under normal memory management. For many Windows VPS workloads, leave `min server memory` at its default unless there is a measured reason to change it. Do not set `min server memory` equal to `max server memory` on a shared Windows VM. That reduces SQL Server's ability to return memory when Windows or another workload needs it. ## How to detect SQL Server memory pressure Do not rely on one metric. Use several signals together. ### 1. Check Windows available memory PowerShell: ```powershell Get-Counter '\Memory\Available MBytes' ``` Sustained low available memory during peak workload is more meaningful than one brief dip. ### 2. Check Memory Grants Pending ```sql SELECT cntr_value AS memory_grants_pending FROM sys.dm_os_performance_counters WHERE counter_name = 'Memory Grants Pending' AND object_name LIKE '%Memory Manager%'; ``` A brief non-zero value can happen under load. A value that stays above zero while queries wait can indicate memory pressure for query execution. ### 3. Compare Total Server Memory and Target Server Memory ```sql SELECT MAX(CASE WHEN counter_name = 'Total Server Memory (KB)' THEN cntr_value END) / 1024 AS total_server_memory_mb, MAX(CASE WHEN counter_name = 'Target Server Memory (KB)' THEN cntr_value END) / 1024 AS target_server_memory_mb FROM sys.dm_os_performance_counters WHERE object_name LIKE '%Memory Manager%' AND counter_name IN ('Total Server Memory (KB)', 'Target Server Memory (KB)'); ``` Interpret the trend with the workload. A single sample is not enough to prove a problem. ### 4. Check whether SQL Server reports physical memory pressure ```sql SELECT physical_memory_in_use_kb / 1024 AS sql_process_memory_mb, process_physical_memory_low, process_virtual_memory_low FROM sys.dm_os_process_memory; ``` A `process_physical_memory_low` value of `1` indicates the SQL Server process has detected low physical memory conditions. ### 5. Check Page Life Expectancy as a trend ```sql SELECT instance_name, cntr_value AS page_life_expectancy_seconds FROM sys.dm_os_performance_counters WHERE counter_name = 'Page life expectancy' AND object_name LIKE '%Buffer Node%'; ``` Older SQL Server advice often used **300 seconds** as a universal warning threshold. Do not use that as a fixed rule on modern servers. PLE is affected by buffer pool size, workload pattern, NUMA, scans, index operations, and normal cache churn. A larger server can have a healthy baseline far above 300 seconds, while a smaller system may behave differently. Watch for a meaningful drop from the server's normal baseline that aligns with slower queries or other memory-pressure signals. ### 6. Check paging and Windows pressure Heavy sustained paging can be a sign that Windows does not have enough memory headroom. Use Task Manager, Resource Monitor, and Windows counters together. If SQL Server, RDP sessions, IIS, and security software are all competing for RAM, reducing SQL Server memory or resizing the VM may be more effective than tuning one query. ### 7. Inspect SQL Server memory clerks To see where SQL Server memory is being consumed: ```sql SELECT TOP (20) type, pages_kb / 1024 AS pages_mb, virtual_memory_committed_kb / 1024 AS virtual_memory_committed_mb FROM sys.dm_os_memory_clerks ORDER BY pages_kb DESC; ``` This is useful when the SQL Server process is using a lot of memory but the reason is not obvious from buffer pool metrics alone. ## Why Page Life Expectancy should not use a universal 300-second rule The old `PLE < 300 = bad` rule was created for much smaller servers and should not be treated as a modern sizing formula. Use PLE to answer questions such as: - What is the normal baseline for this server? - Does PLE collapse during the same workload every day? - Does the drop correlate with `Memory Grants Pending`? - Does Windows available memory also fall? - Are large scans, reporting queries, or index operations causing normal cache churn? - Is one NUMA node behaving differently from another? A PLE drop is a clue, not a verdict. ## Buffer cache hit ratio is not enough by itself A high buffer cache hit ratio does not prove that SQL Server has enough memory, and a lower ratio does not automatically mean the VM needs more RAM. Large scans, new workloads, reporting queries, or a working set bigger than the buffer pool can change the ratio. Use it as supporting context, not as the sole reason to resize a server or change `max server memory`. ## SQL Server uses all available memory - is that a problem? Not necessarily. If SQL Server grows toward its configured memory target while: - Windows still has adequate memory; - paging is not excessive; - RDP/IIS/backup workloads remain responsive; - `Memory Grants Pending` does not remain elevated; - query latency is healthy; then high SQL Server memory usage can be normal. Investigate when high SQL memory usage is accompanied by **pressure outside SQL Server** or **query execution pressure inside SQL Server**. ## Dedicated SQL Server vs SQL Server plus IIS ### Dedicated SQL Server A dedicated database VM is easier to tune because the main memory consumers are SQL Server, Windows, security tools, backup software, and administration. In that design, SQL Server can usually receive a larger share of RAM. ### SQL Server + IIS on the same VM IIS app pools can grow unexpectedly during application load, deployments, background jobs, report generation, or application memory leaks. If SQL Server and IIS share a VM: - leave explicit RAM for IIS; - monitor `w3wp.exe` working sets; - avoid giving SQL Server nearly all system RAM; - consider separating the application and database when either workload begins scaling independently. ## SQL Server plus RDP/RDS users Interactive desktop sessions are less predictable than a dedicated server role. Browsers, Office apps, ERP clients, accounting software, and user profiles can all create memory spikes. For a shared SQL + RDP server: - reserve more memory for Windows and user sessions; - monitor peak concurrent users, not just average users; - watch disconnected sessions that still consume RAM; - avoid tuning SQL Server from an idle snapshot; - split the database from the desktop role when contention becomes frequent. ## What happens if max server memory is too high? If SQL Server is allowed to consume too much RAM, you may see: - low Windows available memory; - paging; - slow RDP sessions; - IIS or application instability; - backup/monitoring processes becoming slow; - general Windows responsiveness problems. The fix can be to lower `max server memory`, reduce other workload demand, or resize/split the VM. ## What happens if max server memory is too low? An overly low memory cap can hurt SQL Server performance. Possible symptoms include: - more physical reads; - higher I/O demand; - frequent cache churn; - query memory-grant pressure; - slower reports or joins; - reduced throughput. Do not lower SQL Server memory merely to make Task Manager show more free RAM. Tune for **workload performance plus Windows headroom**. ## Lock Pages in Memory Lock Pages in Memory (LPIM) allows eligible SQL Server memory allocations to remain locked rather than being paged out by Windows. LPIM can be valuable for production SQL Server workloads, but it is not a substitute for setting a sensible `max server memory` value. If SQL Server is allowed to lock too much memory while the operating system is under-reserved, Windows and other services can still suffer. Configure LPIM only after reviewing Microsoft guidance for your SQL Server version and service account, and test the setting during a maintenance window. ## Common mistakes ### Leaving max server memory effectively unlimited on a shared VM This is one of the easiest ways to make Windows, IIS, or RDP compete with SQL Server for memory. ### Setting max server memory equal to total VM RAM Windows still needs memory. So do security agents, backup software, monitoring, drivers, and administration tools. ### Copying one RAM formula to every SQL Server A 32 GB dedicated database VM and a 32 GB SQL + IIS + RDS server need different memory reservations. ### Treating max server memory as a hard process cap Some SQL Server process memory exists outside the pool controlled by `max server memory`. Validate actual process memory after configuration. ### Using PLE 300 as a universal threshold PLE should be interpreted against the server's normal baseline and alongside other pressure metrics. ### Increasing memory before checking query behavior Missing indexes, large scans, bad plans, spills, blocking, and reporting queries can create performance problems that more RAM only masks. ### Ignoring TempDB and backup workloads Heavy TempDB activity and backup windows can overlap with normal application demand. Review [MSSQL TempDB configuration](/windows-server/mssql-tempdb-config) and [MSSQL backup strategy](/windows-server/mssql-backup-strategy) as part of production tuning. ## A practical tuning sequence Use this order when a SQL Server VM feels memory-constrained: ```text Check Windows available memory → Check current max server memory → Identify non-SQL workloads → Check Memory Grants Pending → Check SQL process memory pressure → Compare Total vs Target Server Memory → Review PLE trend → Review query and TempDB behavior → Adjust max server memory → Re-test at peak load → Resize or split roles if pressure remains ``` That is safer than changing `max server memory` from a generic formula and assuming the problem is solved. :::cta SQL Server running out of memory? Run SQL Server on a Windows VM sized for the database workload, then tune memory with enough headroom for Windows and every other service on the server. ::: ## What Raff recommends For SQL Server on a Windows VM: 1. Measure total RAM and Windows available memory first. 2. Set `max server memory` instead of leaving a shared production VM effectively uncapped. 3. Reserve RAM for Windows and every non-SQL workload. 4. Use a larger SQL allocation on dedicated database VMs and a smaller allocation on mixed-role servers. 5. Monitor `Memory Grants Pending`, SQL process memory pressure, Total/Target Server Memory, Windows available memory, and PLE trend together. 6. Do not use PLE 300 as a universal threshold. 7. Do not treat `max server memory` as an absolute process-memory cap. 8. Review query, TempDB, and storage behavior before assuming the VM only needs more RAM. 9. Resize or separate SQL Server from IIS/RDS when roles repeatedly compete for resources. For deployment sizing, pair this guide with [Windows Server Sizing by Workload](/windows-server/windows-server-sizing-by-workload) and [SQL Server Standard vs Enterprise](/windows-server/mssql-standard-vs-enterprise). ## Tested on > Original configuration workflow tested on Raff Windows VPS, Windows Server 2025 Datacenter Evaluation, SQL Server 2025 Express, SQLEXPRESS instance, approximately 8 GB RAM, 2026-05-26. The lab verified the Windows memory baseline, SQL Server memory configuration, SQL Server process memory usage, setting max server memory to 4096 MB, and verifying the running value. Tester: Aybars Altinyay. Guidance and Microsoft references re-reviewed 2026-09-01; no new benchmark is claimed. ## What's next - [SQL Server Standard vs Enterprise: Features, Limits & Cost](/windows-server/mssql-standard-vs-enterprise) - choose the right production SQL Server edition - [Windows Server Sizing by Workload](/windows-server/windows-server-sizing-by-workload) - size CPU, RAM, and storage around the server role - [Configure TempDB for MSSQL Performance](/windows-server/mssql-tempdb-config) - tune TempDB files and growth settings - [MSSQL Backup Strategy on a Windows VPS](/windows-server/mssql-backup-strategy) - plan full, differential, and log backups - [Install SQL Server 2025 on a Windows Server VPS](/windows-server/install-sql-server-2025-windows-server-vps) - build the SQL Server environment - [SQL Server hosting](/products/sql-server-hosting) - deploy Windows Server infrastructure for SQL Server workloads ## Sources - Microsoft Learn - [Server memory configuration options](https://learn.microsoft.com/en-us/sql/database-engine/configure-windows/server-memory-server-configuration-options) - Microsoft Learn - [Monitor memory usage](https://learn.microsoft.com/en-us/sql/relational-databases/performance-monitor/monitor-memory-usage) - Microsoft Learn - [sys.dm_os_process_memory](https://learn.microsoft.com/en-us/sql/relational-databases/system-dynamic-management-views/sys-dm-os-process-memory-transact-sql) - Microsoft Learn - [sys.dm_os_memory_clerks](https://learn.microsoft.com/en-us/sql/relational-databases/system-dynamic-management-views/sys-dm-os-memory-clerks-transact-sql) - Microsoft Learn - [SQL Server editions and supported features](https://learn.microsoft.com/en-us/sql/sql-server/editions-and-components-of-sql-server-2025) - Microsoft Learn - [Enable the Lock Pages in Memory option](https://learn.microsoft.com/en-us/sql/database-engine/configure-windows/enable-the-lock-pages-in-memory-option-windows) - Date last verified: 2026-09-01 --- ### Configure SQL Server TempDB: Files, Size & Autogrowth (2026) URL: https://rafftechnologies.com/windows-server/mssql-tempdb-config Description: Configure SQL Server TempDB with the right data-file count, equal sizing, sensible autogrowth, fast storage, and monitoring. Includes TempDB-full and PAGELATCH troubleshooting. ## In short A good **SQL Server TempDB configuration** has enough preallocated space for the normal workload, multiple equally sized data files when appropriate, the same growth settings across those data files, and fast storage with enough free capacity. For SQL Server 2016 and later, Microsoft’s general starting guidance is one TempDB data file per logical processor up to eight files. If allocation contention remains, add files in groups of four while continuing to measure the workload. Do not treat file count as the whole TempDB tuning strategy. TempDB pressure can also come from query spills, temporary objects, row versioning, index operations, long-running transactions, slow storage, or simply running out of disk space. ## SQL Server TempDB best-practices checklist | Setting | Practical starting point | |---|---| | Data-file count | 1 per logical processor up to 8 | | More than 8 logical processors | Start with 8; add 4 at a time only if allocation contention remains | | Data-file size | Keep all TempDB data files equal | | Data-file growth | Keep growth settings equal across all data files | | Initial capacity | Pre-size for the typical workload instead of relying on frequent autogrowth | | Autogrowth | Keep enabled as a safety net; use a reasonable fixed increment for predictable capacity planning | | Log files | Normally one TempDB log file | | Storage | Fast I/O; separate storage only when I/O or capacity isolation justifies it | | Monitoring | Space usage, version store, session/task usage, waits, disk latency, free disk space | | Validation | Recheck the final layout after restart and observe the real production workload | For a new SQL Server 2016+ installation, Setup already creates multiple TempDB data files based on logical processor count, up to eight by default. That means the first step is **inspect the current configuration**, not automatically add more files. ## What is TempDB in SQL Server? TempDB is a SQL Server system database used for temporary and intermediate work. SQL Server recreates it every time the Database Engine starts, using the file definitions stored in the instance configuration. Common TempDB consumers include: - local and global temporary tables; - table variables; - sorts and hash operations; - query spills; - internal worktables; - row versioning and version store; - snapshot-based isolation features; - index creation or maintenance operations; - DBCC and other engine operations. A slow query that uses TempDB heavily is not automatically a “TempDB problem.” The root cause can be insufficient memory grants, poor cardinality estimates, inefficient queries, long-running row-versioning transactions, or storage pressure. Configure TempDB well, but diagnose the workload too. ## What we tested on Raff We tested this configuration workflow on a Raff Windows VPS running Windows Server 2025 Datacenter Evaluation and SQL Server 2025 Express. ![PowerShell output showing a Raff Windows VPS running Windows Server 2025 with SQL Server SQLEXPRESS service available for TempDB testing.](https://raff-images.s3.raffusercloud.com/01_tempdb_test_environment_690a6bc455.png) | Item | Value | |---|---| | Provider | Raff Technologies | | OS | Windows Server 2025 Datacenter Evaluation | | SQL Server | SQL Server 2025 Express | | Instance | `SQLEXPRESS` | | CPU | 4 vCPU | | Test database | TempDB system database | | Original test date | 2026-05-26 | | Tester | Serdar Tekin | The lab verified: - SQL Server service state; - the existing TempDB file layout; - CPU and scheduler count; - a four-data-file layout on a 4 vCPU VM; - equal TempDB data-file sizes; - fixed autogrowth settings; - SQL Server restart; - the final TempDB layout after restart. The lab used **64 MB files only to validate the procedure**. Those values are deliberately not presented as a production sizing recommendation. This article does not claim a measured performance improvement from the change because the lab was not a synthetic allocation-contention benchmark. ## Step 1 — Check the current TempDB configuration Before changing anything, inspect the current files, sizes, growth settings, and paths. ```powershell sqlcmd -S .\SQLEXPRESS -E -C -Q "SELECT name, type_desc, physical_name, size * 8.0 / 1024 AS size_mb, CASE WHEN is_percent_growth = 0 THEN growth * 8.0 / 1024 ELSE growth END AS growth_value, is_percent_growth FROM tempdb.sys.database_files ORDER BY file_id;" ``` ![sqlcmd output showing SQL Server edition and version information for a SQLEXPRESS instance.](https://raff-images.s3.raffusercloud.com/02_sql_server_edition_query_6c80bd62eb.png) Review these fields: | Field | Why it matters | |---|---| | `type_desc` | Distinguishes data files from the log file | | `physical_name` | Shows where TempDB is placed | | `size_mb` | Shows current preallocated size | | `growth_value` | Shows the configured growth increment | | `is_percent_growth` | Distinguishes fixed-size growth from percentage growth | Also check free space on the underlying volume. A correct SQL configuration cannot protect a volume that is already close to full. ## Step 2 — Check logical processor count Microsoft’s current general guidance for modern SQL Server is: - **8 or fewer logical processors:** start with the same number of TempDB data files as logical processors; - **more than 8 logical processors:** start with 8 data files; - if allocation contention remains, increase the file count in groups of four, up to the number of logical processors, while measuring the result. Check what SQL Server sees: ```powershell sqlcmd -S .\SQLEXPRESS -E -C -Q "SELECT cpu_count, scheduler_count FROM sys.dm_os_sys_info;" ``` ![sqlcmd output showing SQL Server CPU count and scheduler count used for TempDB file planning.](https://raff-images.s3.raffusercloud.com/03_tempdb_cpu_count_a92461fb79.png) For the 4 vCPU Raff lab, the starting layout was therefore: ```text 4 TempDB data files 1 TempDB log file ``` ### TempDB files per core: practical starting table | Logical processors | Starting data files | |---:|---:| | 1 | 1 | | 2 | 2 | | 4 | 4 | | 8 | 8 | | 12 | 8, then measure | | 16+ | 8, then measure allocation contention | Do not create 16, 24, or 32 files simply because the VM has that many vCPUs. Additional files are specifically useful when they reduce allocation contention; they do not fix every kind of TempDB pressure. ## Step 3 — Keep TempDB data files equal All TempDB **data files** should have the same initial size and the same growth settings. This helps SQL Server distribute allocations more evenly. Avoid an imbalanced layout such as: ```text tempdev 4096 MB tempdev2 1024 MB tempdev3 512 MB tempdev4 512 MB ``` Prefer equal-sized files, for example: ```text tempdev 1024 MB tempdev2 1024 MB tempdev3 1024 MB tempdev4 1024 MB ``` Those numbers are only an example. The correct production size comes from observed TempDB demand, not from the example itself. ## Step 4 — Pre-size TempDB instead of depending on autogrowth Autogrowth should remain available for unexpected demand, but it should not be the normal way TempDB reaches its everyday operating size. Microsoft recommends reproducing the typical workload, observing peak TempDB consumption, accounting for projected concurrency, and then preallocating enough capacity for that workload. A practical workflow is: ```text Observe normal workload → observe heavy reporting / ETL / maintenance → record peak TempDB use → add operational headroom → pre-size the data files equally → leave autogrowth enabled for unexpected demand → monitor the volume ``` Avoid blindly copying a “1 GB per file” or “4 GB per file” rule from another server. A reporting workload, an OLTP application, and a database using heavy row versioning can require very different TempDB capacity. ## Step 5 — Choose sensible TempDB autogrowth For TempDB data files, keep the growth configuration the same across all data files. A fixed MB increment makes capacity planning easier because each growth event has a known size. Microsoft uses 64 MB as an example of a reasonable increment in its TempDB guidance, but the correct value depends on file size, workload, disk capacity, and how quickly the storage can satisfy growth operations. For example: ```sql ALTER DATABASE tempdb MODIFY FILE ( NAME = tempdev, SIZE = 1024MB, FILEGROWTH = 256MB ); ``` Do not choose an extremely small increment that causes constant growth events. Do not choose an enormous increment that can unexpectedly consume a small volume. The goal is predictable, infrequent growth with enough free capacity remaining. ## Step 6 — Apply a multi-file TempDB layout In the Raff lab, we used four TempDB data files with small 64 MB sizes and 64 MB growth increments so the configuration could be validated safely. ```powershell sqlcmd -S .\SQLEXPRESS -E -C -Q "USE master; ALTER DATABASE tempdb MODIFY FILE (NAME = tempdev, SIZE = 64MB, FILEGROWTH = 64MB); ALTER DATABASE tempdb ADD FILE (NAME = tempdev2, FILENAME = 'C:\Program Files\Microsoft SQL Server\MSSQL17.SQLEXPRESS\MSSQL\DATA\tempdev2.ndf', SIZE = 64MB, FILEGROWTH = 64MB); ALTER DATABASE tempdb ADD FILE (NAME = tempdev3, FILENAME = 'C:\Program Files\Microsoft SQL Server\MSSQL17.SQLEXPRESS\MSSQL\DATA\tempdev3.ndf', SIZE = 64MB, FILEGROWTH = 64MB); ALTER DATABASE tempdb ADD FILE (NAME = tempdev4, FILENAME = 'C:\Program Files\Microsoft SQL Server\MSSQL17.SQLEXPRESS\MSSQL\DATA\tempdev4.ndf', SIZE = 64MB, FILEGROWTH = 64MB); ALTER DATABASE tempdb MODIFY FILE (NAME = templog, SIZE = 64MB, FILEGROWTH = 64MB);" ``` ![sqlcmd output showing ALTER DATABASE commands applied to resize TempDB files and add additional TempDB data files.](https://raff-images.s3.raffusercloud.com/04_tempdb_change_command_fea7137144.png) Before using a similar command in production: - change the physical path for the actual SQL Server instance; - choose production sizes from monitoring data; - verify the SQL Server service account can access the destination; - confirm enough free storage exists; - schedule changes that require restart for a maintenance window. ## Step 7 — Restart and verify the final layout TempDB is recreated when SQL Server starts. For changes that require a restart, use a planned maintenance window. For the Express lab: ```powershell Restart-Service -Name 'MSSQL$SQLEXPRESS' -Force ``` Then confirm the service: ```powershell Get-Service -Name 'MSSQL$SQLEXPRESS' ``` ![PowerShell output showing the SQL Server SQLEXPRESS service restarted and running after TempDB configuration changes.](https://raff-images.s3.raffusercloud.com/05_sql_service_restarted_13b11a0bf5.png) Re-run the configuration query: ```powershell sqlcmd -S .\SQLEXPRESS -E -C -Q "SELECT name, type_desc, physical_name, size * 8.0 / 1024 AS size_mb, growth * 8.0 / 1024 AS growth_mb, is_percent_growth FROM tempdb.sys.database_files ORDER BY file_id;" ``` The lab result was: ```text tempdev ROWS 64 MB 64 MB tempdev2 ROWS 64 MB 64 MB tempdev3 ROWS 64 MB 64 MB tempdev4 ROWS 64 MB 64 MB templog LOG 64 MB 64 MB ``` ![sqlcmd output showing the verified TempDB layout after restart with multiple data files and fixed autogrowth settings.](https://raff-images.s3.raffusercloud.com/06_tempdb_layout_after_change_60a8ec2941.png) The important result is not the 64 MB lab size. It is that SQL Server started successfully and the four data files were present with equal size and equal growth configuration. ## How to monitor TempDB space usage Use `sys.dm_db_file_space_usage` to separate free space, user objects, internal objects, and version store usage. ```sql USE tempdb; GO SELECT SUM(unallocated_extent_page_count) * 8.0 / 1024 AS free_space_mb, SUM(version_store_reserved_page_count) * 8.0 / 1024 AS version_store_mb, SUM(user_object_reserved_page_count) * 8.0 / 1024 AS user_objects_mb, SUM(internal_object_reserved_page_count) * 8.0 / 1024 AS internal_objects_mb FROM sys.dm_db_file_space_usage; ``` Run this during the periods that matter: normal business load, reporting peaks, ETL windows, index maintenance, and any workload that previously caused TempDB growth. ### Check TempDB usage by session When TempDB suddenly grows, identify which sessions are consuming space instead of immediately resizing or shrinking it. ```sql SELECT TOP (20) session_id, (user_objects_alloc_page_count - user_objects_dealloc_page_count) * 8.0 / 1024 AS user_objects_mb, (internal_objects_alloc_page_count - internal_objects_dealloc_page_count) * 8.0 / 1024 AS internal_objects_mb FROM sys.dm_db_session_space_usage WHERE session_id > 50 ORDER BY (user_objects_alloc_page_count - user_objects_dealloc_page_count) + (internal_objects_alloc_page_count - internal_objects_dealloc_page_count) DESC; ``` This is especially useful when a single reporting, ETL, or application session is driving a large increase. ## How to detect TempDB allocation contention Multiple TempDB data files are primarily a response to allocation contention, not a generic cure for slow SQL Server performance. Check latch waits: ```sql SELECT wait_type, waiting_tasks_count, wait_time_ms, signal_wait_time_ms FROM sys.dm_os_wait_stats WHERE wait_type LIKE 'PAGELATCH%' ORDER BY wait_time_ms DESC; ``` Then inspect active requests: ```sql SELECT session_id, wait_type, wait_resource, blocking_session_id FROM sys.dm_exec_requests WHERE wait_type LIKE 'PAGELATCH%'; ``` TempDB is database ID `2`. Allocation contention commonly involves PFS, GAM, or SGAM pages. Do not assume every `PAGELATCH` wait is TempDB; verify the database and page involved. SQL Server 2016 and later already include several TempDB allocation improvements that older guidance handled with trace flags. On modern SQL Server, focus first on file count, equal sizing, current cumulative updates, workload behavior, and measured contention rather than copying old trace-flag recipes. ## What should you do if SQL Server TempDB is full? A full TempDB is an operational incident, but the first response should be diagnosis rather than routine shrinking. Check four things quickly: 1. **Is the volume itself full?** Check operating-system free disk space. 2. **Can TempDB files still grow?** Inspect file `MAXSIZE`, growth settings, and available volume capacity. 3. **What is consuming TempDB?** Separate user objects, internal objects, and version store with the DMVs above. 4. **Which sessions or tasks are responsible?** Inspect session/task space usage and active requests. Common causes include: - a large sort or hash spill; - reporting or ETL queries; - large temporary tables; - index operations; - row-versioning pressure; - long-running transactions holding version-store data; - insufficient preallocated space; - an underlying disk that has simply run out of capacity. If the immediate problem is lack of capacity, adding safe temporary capacity can restore service, but the permanent fix should address the workload, file configuration, or storage constraint that caused the incident. ### Should you shrink TempDB? Routine TempDB shrinking is not a tuning strategy. If a one-off operation caused unusual growth, first confirm that the workload is finished and determine the intended steady-state size. Repeatedly shrinking TempDB only to let it autogrow again creates unnecessary work and does not solve the source of the growth. A SQL Server restart also is not a normal “clear TempDB” maintenance technique. TempDB is recreated at startup using its configured file definitions, so restart planning should be based on a genuine maintenance requirement, not used as a substitute for capacity management. ## Where should TempDB files live? Microsoft recommends a fast I/O subsystem. Individual TempDB data files do **not** need separate disks simply because there are multiple files. Use separate storage when it gives a real benefit, such as: - isolating heavy TempDB I/O from user-database I/O; - protecting the OS volume from TempDB capacity spikes; - independently scaling TempDB capacity or IOPS; - reducing a measured disk-level bottleneck. Do not move TempDB from fast storage to slower storage merely to say it is “separate.” Measure latency and throughput on the actual storage path. ## TempDB log-file guidance Multiple data files do not imply multiple log files. In normal configurations, keep one TempDB log file and size it for the workload. Watch for log growth during operations that generate substantial TempDB log activity. Starting with SQL Server 2022, transaction-log growth events up to 64 MB can benefit from instant file initialization under supported conditions, but that does not remove the need to size and monitor the log correctly. ## SQL Server 2025: ADR in TempDB SQL Server 2025 introduces the option to enable **Accelerated Database Recovery (ADR) in TempDB**. Microsoft recommends considering it for benefits such as instant transaction rollback and more aggressive log truncation for transactions in TempDB. Treat this as a separate engine-level decision rather than a replacement for correct file sizing. Enabling or disabling ADR in TempDB requires a Database Engine restart, so validate compatibility and behavior in a test environment before changing a production instance. ## Common TempDB mistakes ### Adding files without confirming the current layout SQL Server 2016+ Setup already creates multiple TempDB files on new installations. Inspect first. ### Creating one file per vCPU above eight without evidence Start with eight on larger servers. Add more in groups of four only when allocation contention remains. ### Unequal data-file sizes or growth settings Keep TempDB data files equal to avoid allocation imbalance. ### Treating autogrowth as normal sizing Pre-size for expected demand. Autogrowth is the safety net. ### Copying a universal TempDB size There is no correct “X GB per core” rule for every workload. Observe actual consumption. ### Moving TempDB to slower storage Separate storage is only useful if it solves a real I/O or capacity problem. ### Shrinking TempDB repeatedly If the files immediately grow again, the steady-state sizing or workload problem has not been solved. ### Assuming every PAGELATCH wait is TempDB Verify database ID and the page involved before changing file count. ### Ignoring version store Snapshot-based workloads and long-running transactions can create substantial TempDB pressure even when temporary-table usage looks normal. ## Production baseline by workload | Workload | Starting approach | |---|---| | Dev/test | Inspect defaults; modest pre-sizing is usually enough | | 2–4 vCPU production SQL Server | 2–4 equal data files, then monitor | | 8 vCPU production SQL Server | Up to 8 equal data files, then monitor | | More than 8 vCPU | Start with 8, add four only for measured allocation contention | | Reporting / ETL heavy | Pre-size from observed peak usage; monitor internal objects and storage latency | | Snapshot / row-versioning heavy | Monitor version store and long-running transactions | | TempDB-full history | Add disk-space alerts and session/task usage diagnostics | :::cta Running SQL Server on Windows? Choose a Windows VM with enough CPU, RAM, fast storage, and operational headroom for the database workload. ::: ## What Raff recommends For a production SQL Server instance, start by checking what SQL Server already configured. Keep TempDB data files equal, pre-size from observed demand, leave growth enabled for unexpected spikes, and monitor both TempDB space and the underlying volume. Use additional files specifically when the CPU count and allocation-contention evidence justify them. Pair TempDB tuning with [SQL Server Max Server Memory](/windows-server/mssql-memory-tuning), [SQL Server Backup Strategy](/windows-server/mssql-backup-strategy), and [Windows Server Sizing by Workload](/windows-server/windows-server-sizing-by-workload). TempDB cannot compensate for memory starvation, undersized storage, or inefficient queries. ## Tested on > Original configuration workflow tested on Raff Windows VPS, Windows Server 2025 Datacenter Evaluation, SQL Server 2025 Express, SQLEXPRESS instance, 4 vCPU, 2026-05-26. The lab checked the TempDB layout and CPU count, added data files, configured equal file size and fixed growth, restarted SQL Server, and verified the final layout. Lab file sizes were intentionally small and are not production recommendations. Guidance re-reviewed against current Microsoft SQL Server documentation on 2026-09-02; no new performance benchmark is claimed. ## What's next - [SQL Server Max Server Memory](/windows-server/mssql-memory-tuning) — prevent SQL Server from starving Windows and other services - [SQL Server Backup Strategy: Full, Differential & Log Backups](/windows-server/mssql-backup-strategy) — design recovery around RPO and RTO - [Install SQL Server 2025 on a Windows Server VPS](/windows-server/install-sql-server-2025-windows-server-vps) — build a clean SQL Server environment - [Windows Server Sizing by Workload](/windows-server/windows-server-sizing-by-workload) — size CPU, RAM, and storage for database workloads - [SQL Server hosting](/products/sql-server-hosting) — deploy Windows Server infrastructure for SQL Server workloads ## Sources - Microsoft Learn — [tempdb database](https://learn.microsoft.com/en-us/sql/relational-databases/databases/tempdb-database?view=sql-server-ver17) - Microsoft Learn — [Recommendations to reduce allocation contention in SQL Server tempdb](https://learn.microsoft.com/en-us/troubleshoot/sql/database-engine/performance/recommendations-reduce-allocation-contention) - Microsoft Learn — [sys.dm_db_file_space_usage](https://learn.microsoft.com/en-us/sql/relational-databases/system-dynamic-management-views/sys-dm-db-file-space-usage-transact-sql?view=sql-server-ver17) - Microsoft Learn — [sys.dm_db_session_space_usage](https://learn.microsoft.com/en-us/sql/relational-databases/system-dynamic-management-views/sys-dm-db-session-space-usage-transact-sql?view=sql-server-ver17) - Microsoft Learn — [Considerations for autogrow and autoshrink](https://learn.microsoft.com/en-us/troubleshoot/sql/database-engine/database-file-operations/considerations-autogrow-autoshrink) - Microsoft Learn — [Move system databases](https://learn.microsoft.com/en-us/sql/relational-databases/databases/move-system-databases?view=sql-server-ver17) - Microsoft Learn — [ADR in tempdb](https://learn.microsoft.com/en-us/sql/relational-databases/accelerated-database-recovery-concepts?view=sql-server-ver17#adr-in-tempdb) - Date last verified: 2026-09-02 --- ### SQL Server 2025 Licensing Guide: Core vs Server + CAL, SPLA, and BYOL URL: https://rafftechnologies.com/windows-server/sql-server-2025-licensing-guide Description: Understand SQL Server 2025 licensing on a Windows VPS: Per Core vs Server + CAL, four-core VM minimums, Software Assurance, SPLA, BYOL, virtualization, HA/DR, and hosted deployment decisions. ## In short **SQL Server 2025 licensing** has two main commercial models: - **Per Core** — available for SQL Server 2025 Standard and Enterprise. You license the compute running SQL Server; users and devices do not need SQL Server CALs under this model. - **Server + CAL** — available for SQL Server 2025 Standard only. You license the server software and also license every user or device that accesses SQL Server, including many indirect-access scenarios. For hosted or virtual SQL Server, the harder question is often not Standard vs Enterprise. It is **who supplies the SQL Server license and which Microsoft rights allow it to run on the chosen infrastructure**. ![Flowchart showing the SQL Server 2025 licensing decision path for a production workload: choose edition (Standard or Enterprise), choose licensing model (Per Core or Server plus CAL), choose deployment or licensing route (customer-owned/BYOL, service-provider licensing where offered, or Microsoft subscription/Software Assurance rights), then size the Windows VM after licensing impact is understood.](https://raff-images.s3.raffusercloud.com/sql_server_2025_licensing_decision_flow_png_8987e79c14.jpg) For most self-managed hosted SQL Server workloads with many or unpredictable users, **Per Core is the simpler model to evaluate** because it does not require counting every accessing user or device. Server + CAL can be attractive for a controlled Standard-edition environment with a small, countable population. This guide owns the **SQL Server licensing-model decision**. For edition features, use [MSSQL Standard vs Enterprise — When to Pay More](/windows-server/mssql-standard-vs-enterprise). For installation, use [Install SQL Server 2025 on a Windows Server VPS](/windows-server/install-sql-server-2025-windows-server-vps). For Windows Server OS licensing, use [Windows Server Licensing on Raff](/windows-server/windows-licensing). > **Licensing note:** Microsoft licensing rights depend on the agreement, purchase channel, Software Assurance or subscription status, deployment model, and provider. Microsoft Product Terms and the customer’s executed agreement control if they differ from this guide. ## SQL Server 2025 licensing models at a glance Microsoft’s current SQL Server 2025 licensing guidance identifies these commercial options: | SQL Server 2025 edition | Per Core | Server + CAL | |---|---:|---:| | Standard | Yes | Yes | | Enterprise | Yes | No | If you already know you need Enterprise, the commercial licensing model is **Per Core**. If Standard fits the workload, you can evaluate either Per Core or Server + CAL. Microsoft also notes that Server + CAL is not the licensing model for its SQL pay-as-you-go billing options. This guide focuses on customer commercial licensing and hosted Windows VM planning rather than Azure SQL service pricing. ## Per Core licensing pays for SQL compute instead of SQL CALs Under the Per Core model, SQL Server licenses are assigned according to the physical cores or virtual cores that run SQL Server, depending on the licensing approach being used. The main advantage is operational simplicity: ```text Licensed SQL compute → users and devices can access SQL Server → no separate SQL Server CAL for each user/device ``` This can be a better fit when: - the application has many users; - users are external or difficult to count; - applications, services, devices, APIs, or middleware access SQL Server; - the user/device population changes frequently; - the database is part of a hosted business application; - CAL administration would be more complex than core licensing. SQL Server core licenses are sold in **two-core packs**, but licensing calculations are based on the number of required core licenses, not simply the number of packs purchased. ## Licensing SQL Server 2025 by virtual machine requires SA or subscription rights Microsoft allows SQL Server 2025 Standard and Enterprise to be licensed by virtual machine under the Per Core model when the licenses have **active Software Assurance or are qualifying software subscription licenses**. For a licensed virtual operating system environment (virtual OSE), Microsoft requires licenses for the virtual cores allocated to that VM, subject to a **minimum of four core licenses per virtual OSE**. If a virtual core maps to more than one hardware thread, Microsoft also requires licensing each hardware thread to which that virtual core is mapped. The practical consequence for a small Windows VM is important: > A very small VM does not automatically create a two-core SQL Server licensing requirement. Under Microsoft’s eligible per-VM core model, the minimum is four core licenses per VM. ### Example core-count planning Assume each vCPU exposed to the VM represents one virtual core and no virtual core maps to multiple hardware threads. Under that simplified assumption: | Windows VM | Virtual cores to consider | Minimum SQL core licenses under eligible per-VM model | |---|---:|---:| | 2 vCPU | 2 | 4 | | 4 vCPU | 4 | 4 | | 6 vCPU | 6 | 6 | | 8 vCPU | 8 | 8 | | 16 vCPU | 16 | 16 | This table is a planning example, not a substitute for checking the actual virtualization mapping and Microsoft entitlement. The four-core minimum matters commercially because infrastructure sizing and SQL licensing cost do not scale identically at the smallest VM sizes. ## Physical-server Per Core licensing is different When licensing a physical server by cores, Microsoft requires enough SQL Server core licenses for the physical cores, with a minimum of **four core licenses per physical processor**. Do not copy a physical-host calculation into a virtual-machine calculation. Microsoft treats these as different licensing approaches with different use rights. This distinction becomes especially important in highly virtualized environments where Enterprise edition plus qualifying Software Assurance or subscription rights can provide broader virtualization benefits. ## Server + CAL licensing is Standard-only and licenses the server plus every accessor SQL Server 2025 Standard can also be licensed using the **Server + CAL** model. At a high level: ```text SQL Server Standard server license + SQL Server CAL for every accessing user or device ``` Microsoft’s current SQL Server 2025 guidance states that **one server license permits one running SQL Server instance in one physical or virtual OSE**. Additional server licenses can be stacked on the same device when additional entitled instances/OSEs are required. A single SQL Server CAL assigned to a user or device can allow that licensed user or device to access more than one properly licensed SQL Server, subject to Microsoft’s terms. Server + CAL is worth evaluating when: - the environment uses Standard edition; - the population is small; - users or devices are easy to count; - access is internal and predictable; - the organization already manages Microsoft CALs cleanly; - future growth is unlikely to make CAL administration expensive. It becomes less attractive when the database is accessed by a large, changing, public, customer-facing, or difficult-to-count population. ## Multiplexing does not reduce SQL CAL requirements This is one of the most common SQL Server licensing mistakes. Putting an application server, API, connection pool, middleware layer, or other multiplexing technology between users and SQL Server does **not** automatically reduce the number of SQL Server CALs required under Server + CAL licensing. Conceptually: ```text 100 users ↓ Web / ERP / application server ↓ One SQL connection pool ↓ SQL Server ``` The fact that SQL Server sees a smaller number of technical connections does not mean only those connection-pool identities need CALs. Microsoft explicitly states that hardware or software used to reduce the number of users or devices directly accessing SQL Server does not reduce the required CAL count. Microsoft also notes that unattended devices accessing SQL Server require CALs under the Server + CAL model. For a customer-facing or high-user application, this is one reason Per Core licensing is often easier to model. ## Per Core vs Server + CAL is mainly a population and deployment decision | Situation | Usually evaluate first | Why | |---|---|---| | Small internal app with 5 known users | Server + CAL or Per Core | Both may be viable; compare total licensing and admin overhead | | 50 employees using an ERP | Per Core | CAL count can become material | | Public web application backed by SQL Server | Per Core | End users are difficult or impractical to license individually | | Devices/services access SQL indirectly | Per Core often simpler | Multiplexing does not erase CAL requirements | | Enterprise edition required | Per Core | Server + CAL is not available for Enterprise | | User count changes frequently | Per Core | Avoid recurring CAL-count administration | | Small stable Standard-edition environment | Server + CAL can be viable | Predictable user/device population may favor CAL economics | Do not choose the model from a generic internet calculator alone. Model the real users, devices, VM cores, edition, growth plan, and deployment rights. ## SQL Server edition choice and licensing choice are separate decisions First ask: ```text What SQL Server features and scale does the workload need? ``` Then ask: ```text How should that edition be licensed in this deployment? ``` For SQL Server 2025, Microsoft documents Standard edition with a **maximum compute capacity of 32 licensed cores**. In Microsoft’s virtual-machine licensing guidance, that 32-core Standard limit is expressed in terms of hardware threads for the VM licensing model. Enterprise is intended for workloads requiring higher scale and additional enterprise capabilities. The canonical feature decision is covered in [MSSQL Standard vs Enterprise — When to Pay More](/windows-server/mssql-standard-vs-enterprise). This page stays focused on licensing. ## Developer, Evaluation, and Express are not normal paid-production substitutes Microsoft identifies **Standard Developer**, **Enterprise Developer**, and **Evaluation** as non-production editions. Express can be used in production within its technical and license limits. | Edition | Typical role | |---|---| | Standard Developer | Development/test against Standard feature set | | Enterprise Developer | Development/test against Enterprise feature set | | Evaluation | Time-limited evaluation/testing | | Express | Small workloads that fit Express limits | | Standard | Main paid production choice for many SMB workloads | | Enterprise | Paid production for advanced scale/features | Microsoft currently documents SQL Server 2025 Evaluation as providing the Enterprise feature set for **up to 180 days**. It must be upgraded to Standard or Enterprise for a normal paid production deployment. Do not deploy Developer edition into production simply because the Windows VM itself is properly licensed. Windows Server and SQL Server are separate Microsoft products with separate licensing requirements. ## SQL Server 2025 adds broader Power BI Report Server use rights A 2025-specific licensing change is easy to miss: Microsoft’s current SQL Server 2025 guidance states that **Power BI Report Server use rights are included with SQL Server 2025 Standard and Enterprise editions even without active Software Assurance**. For pre-2025 SQL Server Enterprise releases, those Power BI Report Server use rights were tied to Enterprise Core licenses with active Software Assurance. This does not mean every Power BI scenario becomes license-free. Microsoft still documents separate Power BI licensing requirements for actions such as publishing shared Power BI reports. The important point for this SQL Server guide is that the base Power BI Report Server use right changed materially with SQL Server 2025. ## Windows Server and SQL Server licensing stack together A SQL Server VM normally involves more than one licensing layer. For a customer-managed commercial deployment, think in layers: ```text Windows VM infrastructure + Windows Server licensing/access rights + SQL Server licensing + RDS licensing if users consume RDS functionality + Microsoft 365 licensing if Office apps are used in shared sessions ``` One layer does not automatically grant another. For example, a correctly licensed Windows Server VM does not automatically include SQL Server Standard licensing. Likewise, buying SQL Server licenses does not create Remote Desktop Services rights for users working through an RD Session Host. Use [Windows Server Licensing on Raff](/windows-server/windows-licensing) and [RDS CAL Licensing Guide](/windows-server/rds-cal-licensing-guide) for those separate layers. ## SPLA and BYOL are different hosted SQL Server routes The **Microsoft Services Provider License Agreement (SPLA)** is Microsoft’s licensing program for service providers and software companies that provide hosted software services to customers. Microsoft describes SPLA as a monthly licensing model for eligible Microsoft products during the agreement term. The service provider reports usage and follows the applicable Services Provider Use Rights (SPUR). This is different from customer BYOL: ```text SPLA → service provider licenses eligible hosted Microsoft software → provider reports usage under SPLA BYOL / customer licensing → customer supplies qualifying licenses → customer must have rights that permit the hosted deployment ``` Do not assume that a provider’s Windows Server SPLA offering automatically includes SQL Server. SQL Server availability, edition, licensing unit, and commercial price must be confirmed for the specific provider/service. For Raff deployments, treat the Windows VM and SQL Server license as separate decisions unless the current commercial offer explicitly says otherwise. ## BYOL depends on entitlement, not whether a product key activates **BYOL** is not one universal Microsoft license transfer rule. A customer may be able to deploy qualifying SQL Server licenses on third-party infrastructure through rights such as: - Software Assurance benefits; - qualifying Microsoft software subscription licenses; - License Mobility through Software Assurance where applicable; - Flexible Virtualization Benefit for eligible outsourcing scenarios; - other rights in the customer’s Microsoft agreement and Product Terms. The exact route depends on the license and provider environment. Do not assume that owning a perpetual SQL Server license automatically means it can be moved to any hosted VM. A product key and a licensing entitlement are not the same thing. ## Flexible Virtualization Benefit can permit SQL Server on an Authorized Outsourcer Microsoft’s **Flexible Virtualization Benefit** expands outsourcing rights for customers with qualifying subscription licenses or licenses with active Software Assurance. Microsoft’s current guidance says an **Authorized Outsourcer** is an outsourcer that is not a Microsoft Listed Provider and is not using a Listed Provider as the datacenter provider for that outsourcing service. Under the Flexible Virtualization Benefit, eligible SQL Server licenses can be deployed on an Authorized Outsourcer’s shared or dedicated servers, subject to the applicable terms. When SQL Server Standard or Enterprise is licensed by virtual machine under this benefit, the same virtual-core rules still apply, including the **four-core minimum per VM** and the hardware-thread mapping rule. Provider qualification matters. The customer should verify the actual hosting arrangement before treating the Flexible Virtualization Benefit as available. ## License Mobility and Flexible Virtualization are not identical SQL Server licenses with active Software Assurance can include **License Mobility through Software Assurance**, which Microsoft describes as a route for running SQL Server on an Authorized License Mobility Partner’s shared servers. Flexible Virtualization Benefit is a separate outsourcing right for qualifying subscription licenses or licenses with active Software Assurance. These mechanisms can overlap in deployment goals but are not interchangeable. When a company asks, “We already own SQL Server, can we bring it to Raff?”, the correct next questions are: - Which SQL Server edition and version? - Per Core or Server + CAL? - Perpetual or software subscription? - Is Software Assurance active? - How is the license currently assigned? - Which outsourcing right covers the intended provider/deployment? - How many virtual cores will the SQL VM use? - Does HA/DR create additional licensing requirements? Do not answer BYOL from the product key alone. ## Software Assurance and subscription rights materially change virtualization Active Software Assurance or qualifying software subscription licenses can provide important SQL Server rights related to: - licensing SQL Server by virtual machine under the Per Core model; - moving licensed virtual OSEs across servers in the same server farm more flexibly; - License Mobility where applicable; - passive failover/disaster-recovery rights; - Enterprise unlimited virtualization when the qualifying physical-core requirements are met; - Flexible Virtualization Benefit where the provider/deployment qualifies. If a customer already pays for Software Assurance, model those rights before buying duplicate licenses or redesigning the VM architecture. ## High availability and disaster recovery can add or remove licensing cost Adding a second SQL Server VM for failover is not just an infrastructure decision. Microsoft’s current SQL Server 2025 licensing guidance states that for each properly licensed physical or virtual OSE with **Software Assurance or qualifying subscription licenses**, the customer may run passive replicas in anticipation of failover, including: - **one passive failover replica for high availability** in a separate OSE; - **one passive failover replica for disaster recovery** in a separate OSE; - **one passive disaster-recovery replica in Azure**, subject to Microsoft’s applicable terms. Microsoft defines a passive replica as one that is not serving SQL Server data to clients or running active SQL Server workloads. The passive replica’s otherwise-required license count cannot exceed the licenses covering the primary OSE. Licenses without qualifying SA/subscription rights do not receive the same HA/DR entitlements. Do not assume that a second SQL VM is automatically license-free because it is called “passive.” Verify what the replica actually does and which Microsoft entitlement covers it. ## SQL Server licensing and VM sizing should be planned together Licensing can influence the VM shape you choose. Example: ```text Application needs 2 vCPU today SQL Server eligible per-VM licensing minimum = 4 core licenses ``` If you are already licensing four SQL cores, a 2-vCPU VM does not reduce the SQL licensing minimum below four cores. But increasing the VM beyond four virtual cores can increase the required SQL core count. That does **not** mean you should oversize the VM just because four licenses are required. VM sizing should still follow workload evidence. Instead, understand both curves: ```text Infrastructure requirement → CPU, RAM, storage, workload Licensing requirement → edition, cores, CAL population, SA/subscription rights ``` Then choose the smallest production configuration that satisfies both performance and licensing requirements with sensible headroom. For workload-level sizing, use [Windows Server Sizing by Workload](/windows-server/windows-server-sizing-by-workload). ## Common SQL Server licensing scenarios ### Small internal business application Assume SQL Server 2025 Standard, a small known employee population, no public/customer access, and a modest database workload. Evaluate both **Server + CAL** and **Per Core**. Server + CAL may be economically attractive if the licensed population is genuinely small and stable. ### ERP used by many employees Assume SQL Server Standard, dozens of employees, and an application server that multiplexes database connections. Do not count only the application server connection. Multiplexing does not reduce CAL requirements. Per Core can be easier to model as user count rises. ### Public SaaS or customer portal A database behind a customer-facing application can have a large or unpredictable number of indirect users. Per Core is generally the model to evaluate because Server + CAL requires licensing users/devices that access the SQL Server software, including indirect access scenarios. ### Enterprise SQL workload If the workload needs Enterprise edition, the licensing model is Per Core. Then model physical-core versus eligible virtual-OSE licensing and any Software Assurance/subscription benefits. ### Existing SQL licenses moving to hosted Windows VMs Do not start migration until entitlement is checked. Review edition, licensing model, active Software Assurance/subscription, outsourcing rights, provider qualification, virtual-core count, license assignment/movement rules, and HA/DR design. Then build the Windows VM around the compliant path. ## Common SQL Server licensing mistakes are expensive ### Assuming one SQL license covers unlimited VMs Virtualization rights depend on edition, licensing model, how the licenses are assigned, and Software Assurance/subscription status. ### Treating BYOL as “upload my key” A product key and a licensing entitlement are not the same thing. Hosted deployment rights must exist independently of whether installation media accepts a key. ### Counting application servers instead of end users under Server + CAL Multiplexing does not erase CAL requirements. ### Using Developer edition for production Developer editions are for development, testing, and demonstration, not normal production workloads. ### Copying Windows Server core minimums into SQL Server Windows Server and SQL Server use different core-licensing rules. Under eligible SQL Server per-VM licensing, the SQL minimum is four core licenses per VM; Windows Server has its own licensing framework. ### Hard-coding an old SQL Server price into architecture Microsoft pricing, reseller pricing, SPLA pricing, and commercial-agreement pricing can differ and change over time. Compare current quotes for the exact licensing route. ### Building HA first and asking about licensing later Replica rights can depend on Software Assurance or subscription rights. Resolve the intended licensing path while designing HA/DR. ## A purchasing checklist should be completed before SQL Server production go-live | Question | Decision | |---|---| | Which SQL Server edition does the application require? | Standard / Enterprise / other | | Is this production? | Yes / No | | Per Core or Server + CAL? | Chosen model | | If Server + CAL, how many users/devices really access SQL? | Documented count | | If Per Core, how many virtual cores will SQL Server use? | Documented count | | Does the four-core per-VM minimum apply? | Verified | | Are the licenses perpetual, subscription, or provider supplied? | Documented | | Is Software Assurance active? | Yes / No | | Is BYOL permitted for the intended provider/deployment? | Verified | | Does HA/DR introduce replica licensing? | Verified | | Is Windows Server licensing handled separately? | Yes | | Is RDS licensing needed for interactive users? | Verified | | Is the licensing route documented before go-live? | Yes | If several of these are unknown, the licensing decision is not ready for production. ## Raff provides the Windows infrastructure layer, not a bundled SQL Server license Raff provides the **Windows Server infrastructure layer** for self-managed SQL Server workloads. A common production architecture is: ![Raff Windows VM architecture showing an Application/IIS server connected over a private network to a SQL Server VM with database backups, monitoring, and optional HA/DR design.](https://raff-images.s3.raffusercloud.com/raff_windows_vm_sql_server_architecture_png_f3da2f49da.png) The Windows VM size can be selected around the application and database workload, while SQL Server licensing is handled as a separate Microsoft licensing decision. Current Raff planning examples make that separation visible: | Windows infrastructure example | Compute | Windows Server Standard SPLA | Windows subtotal before SQL Server | |---|---:|---:|---:| | 4 vCPU / 8 GB / 120 GB | $40.99/mo | $15/mo | **$55.99/mo** | | 8 vCPU / 16 GB / 180 GB | $76.99/mo | $15/mo | **$91.99/mo** | Those totals do **not** include SQL Server licensing, RDS User SALs, additional volumes, backups/snapshots, or third-party application licensing. Raff Windows VM traffic is currently **3 Gbps unmetered with no VM egress fees**. Additional Raff Volumes are **$0.08/GB/month**, and snapshots/backups are **$0.06/GB/month**. For customers migrating an existing SQL-backed application, first determine whether the SQL entitlement is Per Core, Server + CAL, BYOL-eligible, or supplied through an appropriate service-provider route; then choose the Windows VM architecture. **Do not assume SQL Server licensing is bundled with a Raff Windows VM unless the current commercial offer explicitly says so.** :::cta Talk to Windows Engineer Plan the Windows VM around the workload, then validate the SQL Server licensing path before production cutover. ::: Raff is an infrastructure provider, not the customer’s Microsoft licensing authority. The customer’s Microsoft agreement, Product Terms, licensing reseller, or licensing specialist should resolve ambiguous entitlement questions. ## Frequently asked questions ### How is SQL Server 2025 licensed? SQL Server 2025 has two main commercial licensing models: Per Core and Server + CAL. Per Core is available for Standard and Enterprise; Server + CAL is available only for Standard. ### How many SQL Server core licenses does a VM need? Under Microsoft’s eligible Per Core virtual-machine licensing model, you license the virtual cores in the virtual OSE with a minimum of four core licenses per VM. Active Software Assurance or qualifying software subscription licensing is required for this VM licensing model. ### Does a 2-vCPU SQL VM require only two SQL core licenses? Not under the eligible per-VM model described by Microsoft. Even when the VM has two virtual cores, the minimum is four core licenses for the virtual OSE. Verify the actual virtualization mapping and entitlement before purchasing. ### Does SQL Server Enterprise support Server + CAL licensing? No. SQL Server Enterprise uses the Per Core licensing model. Server + CAL is available for SQL Server Standard. ### What does one SQL Server Standard Server + CAL server license allow? Microsoft’s current SQL Server 2025 guidance permits one running SQL Server instance in one physical or virtual OSE for each server license. The users or devices that access SQL Server still need the required CALs, and additional server licenses can be stacked when more entitled instances are needed. ### Do SQL Server CALs apply to indirect users behind an application server? Yes. Server + CAL licensing cannot generally avoid user/device CAL requirements through multiplexing or connection pooling. Microsoft states that reducing the number of direct technical connections does not reduce the required CAL count. ### Can I bring my existing SQL Server license to a hosted VPS? Possibly, but not automatically. Eligibility depends on the exact license, Software Assurance/subscription status, Microsoft outsourcing rights, and provider/deployment model. Verify the entitlement before migration. ### What is the difference between SPLA and BYOL? SPLA is a service-provider licensing program under which the provider licenses eligible Microsoft software used to deliver hosted services. BYOL means the customer deploys its own qualifying licenses under rights that permit that hosted deployment. They are different licensing paths. ### Does Raff Windows VM include SQL Server licensing? Do not assume SQL Server licensing is included. Raff’s Windows VM infrastructure and Windows Server licensing are separate from the customer’s SQL Server licensing decision unless a current commercial offer explicitly states otherwise. ### Do I need SQL Server CALs if I license by core? No SQL Server CALs are required for users or devices accessing SQL Server when it is properly licensed under the Per Core model. ### Does a passive SQL Server failover VM need a license? It depends on the entitlement. Microsoft provides specific passive-replica rights for qualifying licenses with Software Assurance or subscription rights. Verify that the replica is genuinely passive and that the applicable current Microsoft benefit covers it. ### Does SQL Server 2025 include Power BI Report Server rights? Microsoft’s current SQL Server 2025 guidance says Standard and Enterprise editions include Power BI Report Server use rights even without active Software Assurance. Separate Power BI licensing requirements can still apply to specific publishing and sharing scenarios. ## Validation scope This September 2026 refresh is a **licensing source-of-truth update**, not legal advice and not a substitute for Microsoft Product Terms or the customer’s executed agreement. Microsoft’s SQL Server 2025 licensing guidance, Product Terms, Flexible Virtualization Benefit guidance, per-VM four-core minimum, Server + CAL instance rights, Standard 32-core limit, Power BI Report Server change, and HA/DR passive-replica rights were revalidated on September 9, 2026. Current Raff Windows VM, Windows Server SPLA, storage, backup, and network terms were also revalidated. ## What’s next - [MSSQL Standard vs Enterprise — When to Pay More](/windows-server/mssql-standard-vs-enterprise) - [Install SQL Server 2025 on a Windows Server VPS](/windows-server/install-sql-server-2025-windows-server-vps) - [SQL Server Migration to Windows VPS](/windows-server/sql-server-migration-to-windows-vps) - [Windows Server Licensing on Raff](/windows-server/windows-licensing) - [RDS CAL Licensing Guide](/windows-server/rds-cal-licensing-guide) - [Windows Server Sizing by Workload](/windows-server/windows-server-sizing-by-workload) - [Windows VPS Pricing Explained](/windows-server/windows-vps-pricing-explained) - [SQL Server hosting](/products/sql-server-hosting) ## Sources - Microsoft Licensing — SQL Server 2025 Licensing Guidance: https://www.microsoft.com/licensing/guidance/SQL - Microsoft Product Terms — SQL Server: https://www.microsoft.com/licensing/terms/productoffering/SQLServer/OL - Microsoft Licensing — Flexible Virtualization Benefit: https://www.microsoft.com/licensing/guidance/Flexible-Virtualization-Benefit - Microsoft Licensing — Core Based Licensing Models: https://www.microsoft.com/licensing/guidance/Core-based-licensing-models - Microsoft Licensing — Server Virtualization Licensing Guidance: https://www.microsoft.com/licensing/guidance/Server_Virtualization - Microsoft Volume Licensing — Services Provider License Agreement (SPLA): https://www.microsoft.com/en-us/licensing/licensing-programs/spla-program - Microsoft Learn — Editions and supported features of SQL Server 2025: https://learn.microsoft.com/en-us/sql/sql-server/editions-and-components-of-sql-server-2025 - Sources revalidated: 2026-09-09 --- Microsoft licensing terms can vary by agreement, program, product version, geography, and deployment model. Microsoft Product Terms and the customer’s executed licensing agreement control if they conflict with this guide. --- ### SQL Server 2025 Security Hardening Checklist for Windows Server URL: https://rafftechnologies.com/windows-server/sql-server-2025-security-hardening-vps Description: Harden SQL Server 2025 on Windows Server with a practical checklist for authentication, least privilege, TLS, firewall rules, SQL Server Audit, encryption, backups, patching, and verification. ## In short A secure **SQL Server 2025** deployment needs more than a strong `sa` password. Before production, restrict network exposure, verify encrypted client connections, use least-privilege logins, enforce an intentional password policy, keep unnecessary features disabled, enable SQL Server Audit, protect backups, and apply current SQL Server updates. SQL Server 2025 adds stronger security capabilities, including TDS 8.0/TLS 1.3 support and PBKDF2 password hashing, but they do not remove the need for deliberate hardening. ## SQL Server 2025 hardening checklist Use this as the production baseline before an application starts using the instance. | Control | Recommended production state | |---|---| | Authentication | Windows authentication where practical; SQL logins only where required | | `sa` | Disabled after another tested sysadmin exists | | Application logins | Dedicated per application, never `sysadmin` | | Password policy | `CHECK_POLICY = ON`; expiration based on your credential-rotation model | | TCP/IP | Enabled only when remote database access is required | | SQL port exposure | Private network, VPN, or tight source allowlist; never `0.0.0.0/0` | | Connection encryption | Trusted certificate; validate encryption and client compatibility | | Strict encryption | Evaluate `Force Strict Encryption` / `Encrypt=Strict` for TDS 8.0-capable clients | | `xp_cmdshell` | Disabled unless a documented workload genuinely requires it | | SQL Server Audit | Enabled for login, role, permission, and security-sensitive changes | | TDE | Use when at-rest database encryption is required and the edition supports it | | Backup encryption | Use on supported editions and protect certificate/key recovery material | | Patching | Track Microsoft's current SQL Server 2025 CU/GDR build and patch policy | | Restore testing | Required; a successful backup job is not proof of recoverability | This guide follows the [SQL Server 2025 installation guide](/windows-server/install-sql-server-2025-windows-server-vps). If the instance is not installed yet, build it cleanly first, then harden it before production data or public-facing applications are added. ## Secure the authentication model first Authentication mistakes create a larger attack surface than most tuning mistakes. ### Prefer Windows authentication where the environment supports it For domain-managed or otherwise controlled Windows environments, Windows authentication can reduce the number of standalone SQL passwords you need to manage. SQL authentication is still valid when an application requires it, but each SQL login becomes another credential that needs rotation, storage, monitoring, and least-privilege permissions. A useful production rule is: ```text Human administrators → Windows authentication where practical Applications that require SQL authentication → dedicated SQL login per application → minimum database permissions → no shared sa credential ``` ### Disable `sa` after verifying another sysadmin Do **not** disable `sa` before confirming that another administrator can recover and manage the SQL instance. Check current server-role membership: ```sql SELECT sp.name, sp.type_desc, sp.is_disabled, IS_SRVROLEMEMBER('sysadmin', sp.name) AS IsSysadmin FROM sys.server_principals AS sp WHERE sp.type IN ('S','U','G') ORDER BY sp.name; ``` Then verify a separate administrative login through SSMS or `sqlcmd` before disabling `sa`: ```sql ALTER LOGIN sa DISABLE; ``` Verify: ```sql SELECT name, is_disabled, modify_date FROM sys.sql_logins WHERE name = 'sa'; ``` Renaming `sa` can reduce noise from unsophisticated username guessing, but **renaming is not a substitute for disabling an unnecessary privileged login, restricting network access, and monitoring authentication attempts**. ## SQL Server 2025 password policy needs an operational decision Google Search Console shows this page already receiving visibility for **`sql server 2025 password policy`**, so it is worth separating the actual SQL Server controls from generic password advice. For a SQL login, Microsoft exposes two important options: - `CHECK_POLICY = ON` — applies the Windows password policy to the SQL login. - `CHECK_EXPIRATION = ON` — applies password-expiration behavior. For an interactive administrator login, both may fit the organization's policy. For an unattended application credential, blindly enabling password expiration can create an outage if the application cannot rotate the credential safely. A more defensible rule is: ```text CHECK_POLICY = ON + credential rotation designed for the workload + secrets stored outside source code + expiration enabled only when the application and rotation process support it ``` Example application login: ```sql CREATE LOGIN app_raffapp01 WITH PASSWORD = 'REPLACE-WITH-A-UNIQUE-SECRET', DEFAULT_DATABASE = RaffApp01, CHECK_POLICY = ON, CHECK_EXPIRATION = OFF; ``` `CHECK_EXPIRATION = OFF` above is not a recommendation to keep a password forever. It illustrates the difference between **automatic Windows password expiry** and an **application-managed rotation process**. If your application supports safe automated rotation, use the policy that matches your security standard. ### SQL Server 2025 uses PBKDF2 for SQL-authentication password hashes SQL Server 2025 uses PBKDF2 (RFC 2898) with SHA-512 and 100,000 iterations for password-based authentication. This makes offline password-hash cracking more expensive than the older single-pass approach. It can also add a small CPU/login-latency cost, especially in environments that repeatedly create new SQL-authenticated connections instead of using connection pooling. That is another reason to use modern drivers and sensible connection pooling rather than reconnecting for every database operation. ## Least-privilege application logins reduce blast radius Do not solve application permission errors by granting `sysadmin` or `db_owner` permanently. Create a login, map it only to the database it needs, and grant the smallest set of permissions required by the application. Example: ```sql CREATE DATABASE RaffApp01; GO CREATE LOGIN app_raffapp01 WITH PASSWORD = 'REPLACE-WITH-A-UNIQUE-SECRET', DEFAULT_DATABASE = RaffApp01, CHECK_POLICY = ON; GO USE RaffApp01; GO CREATE USER app_raffapp01 FOR LOGIN app_raffapp01; ALTER ROLE db_datareader ADD MEMBER app_raffapp01; ALTER ROLE db_datawriter ADD MEMBER app_raffapp01; GO ``` Verify that the login is not a server administrator: ```sql SELECT sl.name, sl.default_database_name, sl.is_policy_checked, sl.is_expiration_checked, IS_SRVROLEMEMBER('sysadmin', sl.name) AS IsSysadmin FROM sys.sql_logins AS sl WHERE sl.name = 'app_raffapp01'; ``` For applications that need schema changes during deployment, separate **deployment/migration permissions** from the long-running **runtime identity**. A deployment identity can receive the DDL rights the migration process needs, while the runtime identity stays narrower. ## Encrypted SQL Server connections require both protocol and certificate planning One of the biggest corrections to older SQL Server 2025 guidance is this: > **SQL Server 2025 supports TDS 8.0 and TLS 1.3, but that does not mean every client connection automatically uses strict TLS 1.3 encryption.** Microsoft documents multiple connection modes: - `Encrypt=Strict` uses **TDS 8.0** and requires encryption. - `Encrypt=Mandatory` / `true` uses TDS 7.x with encryption. - `Encrypt=Optional` / `false` uses TDS 7.x and can remain optional unless the server requires encryption. SQL Server Configuration Manager also distinguishes **Force Encryption** from **Force Strict Encryption**. ### Use strict encryption only after client compatibility is validated For clients and features that support TDS 8.0, `Encrypt=Strict` or server-side **Force Strict Encryption** provides the strongest current protocol path. TLS 1.3 is available in the strict/TDS 8.0 path when the operating system and client stack support it. Do not enable strict mode blindly on a production instance without testing: - application drivers; - SQL Server Agent; - SSMS/sqlcmd versions; - linked servers; - replication; - Always On components; - monitoring and backup agents; - any vendor application that owns the connection string. ### Use a trusted certificate with the correct server identity Encryption and certificate validation are separate concerns. A client can encrypt a connection while still bypassing certificate validation if `TrustServerCertificate=True` is used. For production remote connections, prefer a certificate whose identity matches the DNS name clients use to reach SQL Server and whose issuing chain the clients trust. After connecting, inspect whether the current SQL connection is encrypted: ```sql SELECT session_id, net_transport, protocol_type, encrypt_option, auth_scheme, client_net_address FROM sys.dm_exec_connections WHERE session_id = @@SPID; ``` `encrypt_option = TRUE` confirms that the connection is encrypted. It does not by itself prove that the client validated the intended certificate identity, so verify the driver/connection-string settings as well. ## Restrict SQL Server network exposure If every application component runs on the same Windows VM, you may not need remote SQL connectivity at all. If another VM or administrator workstation needs to connect, enable TCP/IP deliberately and restrict who can reach the port. In the original Raff test environment, the tested default-instance Custom installation had TCP/IP disabled until it was enabled manually. Treat that as a **lab observation, not a guarantee for every SQL Server installation path**. You can inspect the protocol state for the tested default-instance path with PowerShell: ```powershell $tcpKey = 'HKLM:\SOFTWARE\Microsoft\Microsoft SQL Server\MSSQL17.MSSQLSERVER\MSSQLServer\SuperSocketNetLib\Tcp' Get-ItemProperty -Path $tcpKey | Select-Object Enabled, ListenOnAllIPs, DisplayName ``` After enabling TCP/IP through SQL Server Configuration Manager or the appropriate supported configuration process, restart the SQL Server service and verify the intended port. ### Do not expose TCP 1433 to the whole internet A production SQL Server should normally be reached through one of these patterns, in descending preference for many small deployments: 1. private networking between application and database VMs; 2. VPN-based administrative access; 3. tightly scoped source-IP allowlisting; 4. public SQL access only when a real application requirement makes it unavoidable. Example firewall rule for a known trusted source: ```powershell New-NetFirewallRule ` -DisplayName 'SQL Server TCP 1433 - Trusted Source' ` -Direction Inbound ` -Protocol TCP ` -LocalPort 1433 ` -RemoteAddress '203.0.113.10/32' ` -Action Allow ``` `203.0.113.10` is an RFC 5737 documentation address. Replace it with the real trusted source. Avoid an inbound rule that effectively allows: ```text TCP 1433 RemoteAddress = Any ``` For a Raff deployment with separate application and database VMs, prefer [private Windows VM networking](/products/windows-vm) over exposing the database port publicly when the architecture permits it. ## Keep risky SQL Server features disabled unless they are required SQL Server's attack surface grows when powerful features are enabled only for convenience. `xp_cmdshell` is disabled by default and should usually remain disabled: ```sql SELECT name, value, value_in_use FROM sys.configurations WHERE name = 'xp_cmdshell'; ``` Expected production baseline when the workload does not require it: ```text value = 0 value_in_use = 0 ``` If a vendor product explicitly requires a powerful feature, document: - why it is required; - which identity can invoke it; - what network/filesystem access it creates; - how it is monitored; - whether it can be disabled again after a one-time administrative task. The goal is not “disable every SQL feature.” The goal is **do not enable privileged surface area without a workload reason**. ## SQL Server Audit should record security-sensitive activity SQL Server Audit is available in SQL Server 2025 across Enterprise, Standard, and Express for server and database auditing capabilities documented by Microsoft. A useful baseline records authentication and permission changes without trying to log every query in the system. Create a dedicated audit directory: ```powershell New-Item -ItemType Directory -Path 'C:\SQL\Audit' -Force ``` Then create the server audit and specification: ```sql CREATE SERVER AUDIT Raff_SecurityAudit TO FILE ( FILEPATH = 'C:\SQL\Audit\', MAXSIZE = 100 MB, MAX_ROLLOVER_FILES = 10, RESERVE_DISK_SPACE = OFF ) WITH ( QUEUE_DELAY = 1000, ON_FAILURE = CONTINUE ); GO CREATE SERVER AUDIT SPECIFICATION Raff_SecurityAudit_Spec FOR SERVER AUDIT Raff_SecurityAudit ADD (FAILED_LOGIN_GROUP), ADD (SUCCESSFUL_LOGIN_GROUP), ADD (SERVER_ROLE_MEMBER_CHANGE_GROUP), ADD (DATABASE_ROLE_MEMBER_CHANGE_GROUP), ADD (SERVER_PERMISSION_CHANGE_GROUP), ADD (DATABASE_PERMISSION_CHANGE_GROUP), ADD (SERVER_PRINCIPAL_CHANGE_GROUP), ADD (DATABASE_PRINCIPAL_CHANGE_GROUP), ADD (SCHEMA_OBJECT_CHANGE_GROUP) WITH (STATE = ON); GO ALTER SERVER AUDIT Raff_SecurityAudit WITH (STATE = ON); GO ``` Verify: ```sql SELECT name, type_desc, is_state_enabled, create_date FROM sys.server_audits; ``` And inspect recent audit records: ```sql SELECT TOP (50) event_time, action_id, succeeded, server_principal_name, client_ip, application_name, statement FROM sys.fn_get_audit_file('C:\SQL\Audit\*.sqlaudit', DEFAULT, DEFAULT) ORDER BY event_time DESC; ``` In production, local rolling files are only the first layer. Decide how long the organization needs audit data, who can delete it, and whether logs need to be copied or forwarded to a separate security boundary or SIEM. ## Protect data at rest and backup files according to the edition Do not assume every SQL Server edition supports the same encryption features. Microsoft's current SQL Server 2025 edition matrix documents: | Security feature | Enterprise | Standard | Express | |---|---:|---:|---:| | Transparent Data Encryption (TDE) | Yes | Yes | **No** | | Backup encryption | Yes | Yes | **No** | | Server Audit | Yes | Yes | Yes | | Database Audit | Yes | Yes | Yes | | Always Encrypted | Yes | Yes | Yes | Developer editions are development/test editions that expose the feature set of their corresponding paid edition; they are not normal production licenses. ### TDE protects database files, not every security problem TDE protects data files and log files at rest. It does not replace: - access control; - encrypted client connections; - least privilege; - backup policy; - audit logging; - application-layer security. If you use TDE, the certificate/key recovery process is part of the backup strategy. Losing the required recovery material can make an encrypted database backup impossible to restore elsewhere. ### Backup encryption needs off-server key recovery planning For supported editions, backup encryption is a strong control when `.bak` files can leave the SQL VM. But an encrypted backup is only useful if the organization can restore it. Keep certificate/private-key recovery material and its secret **outside the SQL Server VM** and test the restore procedure on a separate instance. For full/differential/log schedules, retention, restore chains, and off-server copies, use the [SQL Server backup strategy guide](/windows-server/mssql-backup-strategy). ## Patch SQL Server 2025 before production Do not leave a new installation on RTM simply because setup succeeded. As of **September 9, 2026**, Microsoft's SQL Server 2025 build list identifies **CU8 (KB5104822), build 17.0.4075.5, released August 13, 2026** as the latest cumulative update. Check the installed build: ```sql SELECT SERVERPROPERTY('ProductVersion') AS ProductVersion, SERVERPROPERTY('ProductLevel') AS ProductLevel, SERVERPROPERTY('ProductUpdateLevel') AS ProductUpdateLevel, SERVERPROPERTY('Edition') AS Edition; ``` Then compare it with Microsoft's current SQL Server 2025 build list rather than permanently hard-coding CU8 into your operations runbook. A newer CU or GDR can appear after this article is published. A production patch process should include: 1. review the current CU/GDR and known issues; 2. test the update against a representative non-production workload when practical; 3. take and verify the required backups; 4. schedule the maintenance window; 5. apply the update; 6. verify services, database health, application connectivity, jobs, and backups afterward. ## A practical SQL Server 2025 hardening verification A hardening checklist is useful only if you can verify the resulting state. Run the following checks after the configuration changes. ### Verify `sa`, password policy, and privileged SQL logins ```sql SELECT name, is_disabled, is_policy_checked, is_expiration_checked FROM sys.sql_logins ORDER BY name; SELECT sp.name AS LoginName FROM sys.server_principals AS sp JOIN sys.server_role_members AS srm ON sp.principal_id = srm.member_principal_id JOIN sys.server_principals AS rolep ON srm.role_principal_id = rolep.principal_id WHERE rolep.name = 'sysadmin'; ``` Review every SQL-authenticated `sysadmin`. Each one should have a documented operational reason. ### Verify high-risk configuration ```sql SELECT name, value, value_in_use FROM sys.configurations WHERE name IN ( 'xp_cmdshell', 'Ole Automation Procedures', 'Ad Hoc Distributed Queries' ) ORDER BY name; ``` Do not automatically change a setting merely because it appears in this output. Investigate whether the workload requires it first. ### Verify current connection encryption ```sql SELECT session_id, net_transport, encrypt_option, auth_scheme, client_net_address FROM sys.dm_exec_connections WHERE session_id = @@SPID; ``` ### Verify SQL Server Audit ```sql SELECT name, is_state_enabled FROM sys.server_audits; SELECT sas.name, sas.is_state_enabled, sasd.audit_action_name FROM sys.server_audit_specifications AS sas JOIN sys.server_audit_specification_details AS sasd ON sas.server_specification_id = sasd.server_specification_id ORDER BY sas.name, sasd.audit_action_name; ``` ### Verify network exposure from Windows ```powershell Get-NetTCPConnection -State Listen | Where-Object LocalPort -eq 1433 | Select-Object LocalAddress, LocalPort, OwningProcess Get-NetFirewallRule -Enabled True -Direction Inbound -Action Allow | Get-NetFirewallPortFilter | Where-Object LocalPort -eq 1433 ``` If TCP 1433 is listening, confirm the associated inbound rule is actually restricted to the intended source addresses or private network. ## Tested on Raff > **Original live test:** SQL Server 2025 Standard Developer, build 17.0.1000.7 RTM, on Windows Server 2025 Standard build 26100, 4 vCPU / 8 GB RAM / 120 GB storage in Raff `us-east`, tested April 30, 2026 by Serdar Tekin. > > The test verified: disabling `sa` after confirming alternate admin access; a least-privilege application login with password-policy controls; SQL Server Audit with login, role, permission, and schema-related action groups; audit-file capture of failed/successful login activity; TCP/IP enabled for the tested default-instance Custom installation; a tightly scoped Windows Firewall rule using an RFC 5737 documentation IP; and `xp_cmdshell` remaining disabled. > > **Not live-tested in that session:** production certificate replacement, TDE, and encrypted-backup recovery. Those sections are based on current Microsoft documentation and are not presented as Raff test evidence. > > The September 9, 2026 refresh revalidated SQL Server 2025 protocol, edition-feature, password-hashing, and update guidance against current Microsoft documentation. It does not claim a new end-to-end hardening lab run. ## Frequently asked questions ### What are the most important SQL Server hardening steps? Start with network restriction, least-privilege authentication, removal of unnecessary privileged logins, encrypted client connections with proper certificate validation, security auditing, supported encryption for data/backups, current patching, and tested recovery procedures. ### Should the `sa` account be disabled? If another tested administrative login can manage and recover the instance, disabling `sa` reduces exposure to a well-known privileged SQL login. Do not disable it before verifying an alternate sysadmin and recovery path. ### Does SQL Server 2025 force TLS 1.3 for every connection? No. SQL Server 2025 supports TDS 8.0 and TLS 1.3, but strict encryption depends on server and client configuration. `Encrypt=Strict` / Force Strict Encryption uses the TDS 8.0 strict path; mandatory or optional modes can use TDS 7.x and TLS 1.2 depending on configuration. ### Does SQL Server Express support TDE and encrypted backups? No. Microsoft's SQL Server 2025 edition matrix lists TDE and backup encryption for Standard and Enterprise but not Express. SQL Server Audit remains available on Express. ### Should application SQL logins use password expiration? Use `CHECK_POLICY = ON` and design a real credential-rotation process. `CHECK_EXPIRATION = ON` is appropriate only when the application and operations process can rotate the credential safely without causing outages. ### What is the latest SQL Server 2025 cumulative update? As of September 9, 2026, Microsoft lists CU8, build 17.0.4075.5, released August 13, 2026. Always check Microsoft's current build-version page because that answer changes over time. :::cta Deploy Windows Now Build the Windows VM first, then harden SQL Server around the application's real network, authentication, encryption, and recovery requirements. ::: ## What's next - [Install SQL Server 2025 on Windows Server VPS](/windows-server/install-sql-server-2025-windows-server-vps) - [SQL Server Backup Strategy: Full, Differential & Log Backups](/windows-server/mssql-backup-strategy) - [SQL Server 2025 Licensing Guide](/windows-server/sql-server-2025-licensing-guide) - [Windows Server 2022 vs 2025](/windows-server/windows-server-version-comparison) - [SQL Server hosting](/products/sql-server-hosting) ## Sources - Microsoft Learn — [Securing SQL Server](https://learn.microsoft.com/en-us/sql/relational-databases/security/securing-sql-server) - Microsoft Learn — [TDS 8.0](https://learn.microsoft.com/en-us/sql/relational-databases/security/networking/tds-8) - Microsoft Learn — [Connect to SQL Server with strict encryption](https://learn.microsoft.com/en-us/sql/relational-databases/security/networking/connect-with-strict-encryption) - Microsoft Learn — [Configure TLS 1.3 on SQL Server](https://learn.microsoft.com/en-us/sql/relational-databases/security/networking/connect-with-tls-1-3) - Microsoft Learn — [Password policy](https://learn.microsoft.com/en-us/sql/relational-databases/security/password-policy) - Microsoft Learn — [SQL Server 2025 known issues](https://learn.microsoft.com/en-us/sql/sql-server/sql-server-2025-known-issues) - Microsoft Learn — [SQL Server Audit](https://learn.microsoft.com/en-us/sql/relational-databases/security/auditing/sql-server-audit-database-engine) - Microsoft Learn — [Editions and supported features of SQL Server 2025](https://learn.microsoft.com/en-us/sql/sql-server/editions-and-components-of-sql-server-2025) - Microsoft Learn — [Transparent Data Encryption](https://learn.microsoft.com/en-us/sql/relational-databases/security/encryption/transparent-data-encryption) - Microsoft Learn — [Backup encryption](https://learn.microsoft.com/en-us/sql/relational-databases/backup-restore/backup-encryption) - Microsoft Learn — [SQL Server 2025 build versions](https://learn.microsoft.com/en-us/troubleshoot/sql/releases/sqlserver-2025/build-versions) - Sources verified: 2026-09-09 --- *Microsoft, Windows Server, SQL Server, and SQL Server Management Studio are trademarks of Microsoft Corporation. Raff Technologies is an independent infrastructure provider and is not affiliated with, sponsored by, or endorsed by Microsoft Corporation.* --- ### SQL Server Migration to Windows VPS: 2025 Upgrade & Cutover Guide URL: https://rafftechnologies.com/windows-server/sql-server-migration-to-windows-vps Description: Migrate SQL Server to a Windows VPS with a current 2026 workflow: assess compatibility, choose backup/restore or SSMS migration, move logins and jobs, test apps, cut over, and keep rollback ready. ## In short A **SQL Server migration to a Windows VPS** should be treated as a database-and-application cutover, not a file copy. The safest pattern for most small and mid-sized Windows workloads is to build the target server side by side, assess compatibility, restore a test copy, migrate server-level dependencies such as logins and jobs, validate the application, then perform a controlled final cutover with rollback still available. Raff Technologies provides Windows VM infrastructure that can be used as the destination for supported SQL Server workloads. The database owner, MSP, or application team still needs to confirm SQL Server edition and licensing, application compatibility, database recovery requirements, migration method, backup integrity, network access, and post-migration operations. In 2026, there is one important update to older SQL migration advice: Microsoft now documents the **SQL Server migration component in SQL Server Management Studio (SSMS)** as a primary workflow for SQL Server-to-SQL Server assessment and migration. For SQL Server 2025 targets, it can assess upgrade compatibility and use a backup-copy-restore workflow to move databases and logins. Manual backup/restore remains a strong and transparent option when you want full control of the migration sequence. ## Quick decision: which SQL Server migration method should you use? | Situation | Recommended direction | Why | |---|---|---| | Small database and acceptable maintenance window | Full backup + restore | Simple, repeatable, easy to test | | SQL Server-to-SQL Server upgrade | SSMS migration component or tested backup/restore | Current Microsoft-supported migration workflow | | Need to move database plus logins | SSMS migration component can simplify the move | Reduces manual login transfer work | | Large database with short cutover window | Full + differential + log restore sequence | Reduces final data transfer during downtime | | Many SQL Agent jobs / linked servers / server objects | Side-by-side migration with dependency inventory | Database restore alone is incomplete | | TDE-protected database | Transfer required certificate/key material first | Destination must be able to open the encrypted backup/database | | High availability is required | Design HA/DR before migration | A single Windows VPS is not an HA architecture | | App vendor only supports a specific SQL version | Follow vendor-supported target | Application support outranks a newer SQL release | For most Raff Windows VM migrations, **side-by-side build + compatibility assessment + test restore + final cutover** is the cleanest model. :::cta Talk to Windows Engineer Review the source SQL Server version, database size, application dependencies, downtime target, and Windows VM architecture before production cutover. ::: ## SQL Server migration is more than moving `.mdf` and `.ldf` files A production SQL Server instance can include far more than the user database itself. | Migration area | Examples | |---|---| | User databases | Data, log files, compatibility levels | | Logins | SQL logins, Windows logins, SIDs, passwords | | Database users | User-to-login mappings, schemas, roles | | SQL Agent jobs | Backups, imports, exports, reports, maintenance | | Linked servers | Connections to other SQL instances or external systems | | Credentials and proxies | Job execution and external access | | Database Mail | Alerts and automated email | | SSIS / packages | Integration workflows | | Maintenance plans | Index, statistics, cleanup, backup tasks | | Connection strings | IIS apps, Windows apps, services, ODBC, DSNs | | Firewall and network | SQL ports, private networking, admin access | | Certificates and keys | TDE, encrypted connections, application dependencies | | Backups | Full, differential, log, retention, off-server copies | ![Architecture visual showing SQL Server migration to Windows VPS with databases, logins, jobs, connection strings, apps, and backups](https://raff-images.s3.raffusercloud.com/sql_server_migration_architecture_windows_vps_webp_94e69d8dbb.png) A migration is successful only when the **application and its operational dependencies** work on the destination. ## What changed for SQL Server migration in 2026? Microsoft's current guidance for upgrading SQL Server databases to newer versions centers on the migration component in modern SQL Server Management Studio. The migration component can: - assess compatibility issues before an upgrade; - identify breaking or behavior changes; - review deprecated features; - move databases with a backup-copy-restore workflow; - transfer logins during the migration workflow; - support side-by-side SQL Server migration scenarios. For this workflow, Microsoft documents **SSMS 21 or later** as a prerequisite. That matters because older migration checklists often point first to retired or older assessment patterns. In 2026, use Microsoft's current SSMS migration workflow when it matches the project, and keep manual backup/restore as the transparent fallback or preferred DBA-controlled method. ## SQL Server 2025: check the source version before you upgrade SQL Server 2025 is Microsoft's current major SQL Server release. Microsoft documents supported in-place upgrade paths from: - SQL Server 2014 SP3 or later; - SQL Server 2016 SP3 or later; - SQL Server 2017; - SQL Server 2019; - SQL Server 2022. Older SQL Server versions may still be migrated to SQL Server 2025 using a side-by-side migration path rather than a direct in-place upgrade. For backup/restore specifically, Microsoft documents that backups from SQL Server 2008 and later can be restored to SQL Server 2025 when the database compatibility conditions are met. Backup compatibility is **forward-only**: a backup created by a newer SQL Server version cannot be restored to an older SQL Server version. The practical rule is: ```text Old SQL Server -> newer SQL Server Usually possible after compatibility checks Newer SQL Server backup -> older SQL Server Not supported as a normal restore path ``` Do not pick SQL Server 2025 only because it is the newest release. The target version must also be supported by the application vendor, drivers, reporting tools, integrations, and any third-party extensions. ## Step 1 — Inventory the source SQL Server instance Before choosing a migration tool, document what exists. | Inventory item | Capture | |---|---| | SQL Server version | Major version, edition, build/CU | | Instance names | Default and named instances | | Database list | Name, owner, size, status | | Compatibility levels | Current database compatibility level | | Recovery models | Simple, full, or bulk-logged | | Backup history | Full, differential, and log backup pattern | | Logins | SQL and Windows logins | | SQL Agent jobs | Name, owner, schedule, job steps | | Linked servers | Target, provider, credentials | | Maintenance plans | What they do and when they run | | Database Mail | Profiles, accounts, operators | | Certificates / TDE | Certificates, keys, backup locations | | Applications | Which apps connect to each database | | Connection strings | Server, instance, database, auth method | | Storage | Data, log, TempDB, backup paths | | Network | SQL ports and allowed sources | This inventory should answer one question: **what must exist on the destination for production to behave the same way?** ## Step 2 — Decide whether this is migration, upgrade, or both These projects are related but not identical. | Project | Meaning | Risk | |---|---|---| | Same SQL version, new Windows VPS | Infrastructure migration | Lower version-change risk | | Newer SQL version, same application | SQL upgrade + migration | Compatibility risk | | New app + new SQL + new server | Application modernization | Highest number of moving parts | | Local SQL Server to cloud Windows VPS | Infrastructure + network change | Connectivity and latency matter | If the current application is business-critical, changing the SQL Server major version during the same cutover can add unnecessary risk. Sometimes the safer sequence is: 1. migrate to the new Windows VPS on a supported SQL version; 2. stabilize the workload; 3. upgrade SQL Server in a separate tested change. If the source SQL release is near end of support or the application requires a newer version, combining the work may still make sense—but test it as an upgrade project, not just a server move. ## Step 3 — Run a compatibility assessment before a major-version upgrade For a move to a newer SQL Server major version, run the current SSMS migration assessment before cutover. Microsoft's migration component checks areas such as: - breaking changes; - behavior changes; - deprecated features; - target compatibility concerns; - affected database objects. Treat assessment findings as migration blockers until reviewed. Also test the actual application. A compatibility assessment can identify SQL-level issues, but it cannot prove that every third-party application workflow behaves correctly. For older business applications, validate: - ODBC/OLE DB drivers; - .NET SQL client behavior; - stored procedures; - SQL authentication; - deprecated data types or syntax; - reporting tools; - vendor-specific database checks; - database compatibility-level requirements. ## Step 4 — Validate database integrity before you migrate Do not discover source corruption during cutover. Before migration: - confirm recent backups complete successfully; - perform a test restore; - review database health; - run appropriate integrity checks such as `DBCC CHECKDB` according to your DBA process; - confirm enough free disk space for backup, copy, restore, and database growth; - resolve any suspect or recovery-pending databases before migration. Microsoft's current SSMS migration guidance specifically recommends validating the source databases are in a known good state before migration. A successful backup file is not enough. A **successful restore test** is much stronger evidence. ## Step 5 — Choose backup/restore or the SSMS migration component ### Option A: manual backup and restore This is usually the easiest migration method to understand and audit. Typical flow: ```text Source SQL Server -> full backup -> copy backup to destination -> restore on Windows VPS -> migrate server-level dependencies -> point test application to destination -> validate -> final backup/log sequence -> production cutover ``` Use it when you want direct control over backup files, restore options, file placement, and cutover timing. ### Option B: SQL Server migration component in SSMS Microsoft's current migration component can assess and physically migrate SQL Server databases using backup-copy-restore. It can also transfer logins as part of the workflow. This is useful when: - you are moving SQL Server to a newer SQL Server instance; - you want Microsoft's current integrated assessment workflow; - you want assistance transferring databases and logins; - both source and destination can use the required backup/copy shares. It still does not eliminate the need to inventory SQL Agent jobs, linked servers, application settings, certificates, permissions, or rollback. ## Step 6 — Protect TDE certificates and encryption keys Transparent Data Encryption changes the migration plan. If a database is protected by TDE, the destination needs the appropriate certificate or asymmetric key material before the encrypted database backup can be restored or migrated successfully. Before cutover: 1. identify TDE-protected databases; 2. back up the certificate and private key securely; 3. protect the password separately; 4. import the required key material on the target instance; 5. test the restore before production migration. Do not leave certificate/key transfer until the cutover window. ## Step 7 — Plan the recovery model and final cutover sequence Recovery model determines how much of the transaction log can be used during migration. | Recovery model | Migration planning | |---|---| | Simple | Full/differential backups are common; point-in-time restore is limited | | Full | Transaction log backups can reduce final data-loss window | | Bulk-logged | Review bulk operations and restore requirements carefully | Define: - **RPO:** maximum acceptable data loss; - **RTO:** maximum acceptable downtime. For a small database with a one-hour maintenance window, a final full backup may be enough. For a larger or busy database, use a staged restore model: ```text Full backup -> restore WITH NORECOVERY Differential backup -> restore WITH NORECOVERY Transaction log backups -> restore WITH NORECOVERY Final tail/log backup -> restore Recover database Cut over application ``` The exact sequence depends on recovery model and migration design. Test it before the real maintenance window. ## Step 8 — Preserve logins and prevent orphaned users Database users and SQL Server logins are different objects. After a database restore, a database user can exist while its matching server login is missing or has a different SID. This creates an orphaned-user problem. ![SQL Server migration dependency map showing logins, orphaned users, SQL Agent jobs, linked servers, maintenance plans, and connection strings](https://raff-images.s3.raffusercloud.com/sql_server_migration_dependencies_risk_map_webp_e2be9b550e.png) Review: | Security object | What to validate | |---|---| | SQL logins | Name, SID, password transfer method | | Windows logins | Domain or local account availability | | Server roles | Required instance-level permissions | | Database users | Correct login mapping | | Database roles | Application and user access | | Schemas | Ownership and default schema | | Service accounts | Application, agent, integration identities | | Contained users | Whether the application uses them | The SSMS migration component can help move logins, but verify the final mappings rather than assuming every authentication dependency moved correctly. ## Step 9 — Migrate SQL Agent jobs and server-level dependencies A restored database can look healthy while scheduled business processes are silently broken. Check: - SQL Agent jobs; - job schedules; - job owners; - operators and alerts; - maintenance plans; - Database Mail; - linked servers; - credentials and proxies; - SSIS packages; - server-level triggers; - custom error messages; - backup jobs; - import/export scripts; - file-system paths; - Windows Scheduled Tasks outside SQL Server. Microsoft's migration guidance specifically notes preserving automated tasks such as SQL Agent jobs. Treat them as part of the migration, not cleanup after the migration. :::cta Explore Windows VM Use Raff Windows VM as the Windows Server destination after the SQL Server version, application, storage, and migration method are validated. ::: ## Step 10 — Design the destination storage before restoring Do not blindly recreate source drive letters if the target design should change. Plan separately for: - SQL data files; - transaction log files; - TempDB; - backup staging; - application files; - exports and imports; - free-space reserve. Consider the peak migration requirement, not only the final database size. During migration you may temporarily hold: ```text Live database + backup file + restored database files + log growth + temporary migration copies ``` A nearly full disk can turn a simple cutover into an outage. ## Step 11 — Keep application traffic private where practical If the application and SQL Server run on separate Windows VMs, use private networking between them when the architecture supports it. | Architecture | Network guidance | |---|---| | App + SQL on same VM | Local connection; simplest small deployment | | App VM + SQL VM | Private network between tiers | | Admin workstation | Restrict management access to known sources or private path | | Branch app clients | Avoid broadly exposing SQL directly to the internet | | RDS app users | Keep SQL behind the application/RDS layer where possible | Do not expose SQL Server publicly simply because the application needs remote users. Remote users should normally reach the application tier, not an open database port. ## Step 12 — Restore a test copy before production cutover Never make the first restore the production restore. ![SQL Server backup and restore migration flow showing source backup, restore to Windows VPS, testing, final backup, and cutover](https://raff-images.s3.raffusercloud.com/sql_server_backup_restore_migration_flow_webp_0e8363d333.png) A useful test sequence is: 1. build the Windows VPS; 2. install the chosen SQL Server version and current updates; 3. configure storage and service accounts; 4. restore a recent production backup to a test database or isolated target; 5. migrate logins and required server objects; 6. connect a test copy of the application; 7. run business workflow tests; 8. measure performance; 9. test backups on the destination; 10. test a restore from the destination backup chain. As of September 2026, Microsoft's SQL Server update history shows SQL Server 2025 has continued receiving cumulative updates. Build the destination using a supported, patched level rather than assuming RTM media is current. ## Step 13 — Test the application, not just SQL Server Management Studio A successful query in SSMS does not prove the migration. Test with real application workflows: | Area | Example | |---|---| | Authentication | App users and services connect successfully | | Read operations | Existing records open correctly | | Writes | Create/update/delete behaves as expected | | Reports | Business reports run correctly | | Imports | Scheduled and manual imports succeed | | Exports | CSV, Excel, PDF, accounting exports work | | Background jobs | Scheduled tasks complete | | Permissions | Users see only expected data | | Integrations | APIs, linked systems, and file drops work | | Performance | Peak workflows are acceptable | For ERP and inventory workloads, test the operational processes too: reporting, label printing, exports, stock updates, and scheduled integrations. ## Step 14 — Plan connection-string cutover Identify every place that contains the old SQL Server name, IP, or instance. Common locations include: - `web.config`; - `appsettings.json`; - environment variables; - Windows service configuration; - ODBC DSNs; - registry entries; - scheduled scripts; - IIS applications; - reporting tools; - desktop app configuration; - linked applications; - ETL jobs. Decide whether cutover changes: - server hostname; - DNS alias; - instance name; - port; - authentication method; - certificate requirements. Document the rollback value for every change. ## Step 15 — Run the final production cutover A typical controlled cutover looks like this: 1. confirm source health and latest successful backups; 2. notify users of the maintenance window; 3. stop application writes; 4. take the final planned full/differential/log backup sequence; 5. copy the remaining backup files; 6. restore the final sequence on the destination; 7. recover the database; 8. verify database state and integrity checks required by your process; 9. confirm logins, jobs, permissions, linked servers, and certificates; 10. update connection strings, DNS aliases, or application configuration; 11. start the application; 12. run smoke tests and business validation; 13. confirm destination backups and monitoring are active; 14. keep the old SQL Server available for rollback until acceptance criteria are met. Do not decommission the source server during the same moment you declare the migration successful. ## Step 16 — Define rollback before the maintenance window Rollback is not “restore something if it fails.” It is a written decision path. Define: | Question | Example | |---|---| | What triggers rollback? | App cannot write, critical integration fails, unacceptable performance | | Who decides? | DBA + application owner | | How long can you troubleshoot before rollback? | Defined cutover deadline | | What happens to new writes? | Prevent split-brain data before rollback | | How is old app configuration restored? | Saved config/DNS/connection string procedure | | Is the source still intact? | Must remain available until sign-off | Rollback becomes much harder after users start writing independently to the new database. Control when production writes begin. ## Step 17 — Validate backups after the migration The destination should have a recovery plan before the source is retired. | Recovery layer | Purpose | |---|---| | Full SQL backup | Baseline database recovery | | Differential backup | Reduce restore work between full backups | | Transaction log backup | Lower RPO for full-recovery databases | | VM-level backup | Recover the Windows VM environment | | Snapshot before major change | Short-term infrastructure rollback | | Off-server copy | Separate recovery boundary | | Restore test | Prove the new backup chain works | ![SQL Server migration recovery stack showing database backup, VM backup, snapshot, restore test, and rollback readiness](https://raff-images.s3.raffusercloud.com/sql_server_migration_cutover_recovery_stack_webp_9440b5a704.png) Do not treat a VM snapshot as a replacement for a SQL Server-aware backup strategy. :::cta Explore Data Protection Protect the migrated SQL Server with database-aware backups, VM recovery, off-server copies, and tested restore procedures. ::: ## Common SQL Server migration mistakes in 2026 ### Using an old migration-tool checklist Microsoft's current SQL Server-to-SQL Server workflow now includes the migration component in modern SSMS. Revalidate tooling before following an older guide. ### Changing server and SQL major version without application testing A database can restore successfully while the application fails because of drivers, compatibility behavior, or vendor restrictions. ### Forgetting TDE certificates Encrypted databases require the correct key material on the destination. ### Restoring databases but not instance-level dependencies Logins, SQL Agent jobs, linked servers, Database Mail, credentials, proxies, and server configuration can be essential. ### Forgetting that backups are forward-only A backup taken on a newer SQL Server cannot normally be restored to an older major version. Plan rollback before the target becomes the only writable copy. ### Letting SQL Server use all available RAM If the Windows VPS also runs an application or RDS sessions, configure SQL Server memory deliberately. Use [SQL Server Max Server Memory](/windows-server/mssql-memory-tuning). ### Exposing SQL Server to the public internet Use private networking or tightly restricted management paths instead of broad public database access. ### Declaring success before backup verification Migration is not complete until destination backups run and at least one recovery path is validated. ## How Raff fits SQL Server migration Raff can provide the Windows VM infrastructure for supported SQL Server workloads used by business applications, ERP/inventory systems, IIS/.NET applications, Microsoft Access back ends, accounting tools, and MSP-managed client environments. A practical architecture can start with one Windows VM for a small workload. As demand grows, the application/RDS tier and SQL Server tier can be separated over private networking. Raff provides the infrastructure layer; the migration owner still needs to handle: - SQL Server installation and edition choice; - application compatibility; - SQL licensing requirements; - database migration method; - logins and server objects; - backups and restore testing; - application cutover; - monitoring and database administration. For SQL-backed ERP and inventory workloads, pair this guide with [ERP Hosting on Windows VPS](/windows-server/erp-on-vps) and [Inventory & Warehouse Software on Windows VPS](/windows-server/windows-vps-erp-inventory-software). :::cta Deploy Windows Now Create a Raff Windows VM after the SQL Server target version, resource requirements, migration method, and recovery plan are defined. ::: ## Final SQL Server migration checklist Before production cutover, confirm: | Check | Done | |---|---| | Source SQL Server version/edition/build documented | ☐ | | Target SQL Server version supported by the application | ☐ | | SQL Server 2025 upgrade path checked if applicable | ☐ | | SSMS migration assessment completed for major-version upgrade | ☐ | | Database sizes and compatibility levels documented | ☐ | | Recovery models reviewed | ☐ | | Source database integrity validated | ☐ | | Test backup restored successfully | ☐ | | TDE certificates/keys transferred if applicable | ☐ | | Logins and SIDs planned | ☐ | | Orphaned-user check planned | ☐ | | SQL Agent jobs inventoried | ☐ | | Linked servers and credentials inventoried | ☐ | | Database Mail / operators reviewed | ☐ | | Connection strings documented | ☐ | | Firewall/private network plan documented | ☐ | | Destination storage has migration headroom | ☐ | | Real application workflows tested | ☐ | | Final backup/log cutover sequence rehearsed | ☐ | | Rollback trigger and owner documented | ☐ | | Destination backup jobs enabled | ☐ | | Destination restore test scheduled/completed | ☐ | If one of these production-critical items is unknown, resolve it before the final cutover. ## Validation scope This September 2026 refresh revalidated the article against Microsoft's current SQL Server 2025 and SSMS migration documentation. It updates the workflow to include the SQL Server migration component in SSMS, SQL Server 2025 supported upgrade paths, forward-only backup compatibility, TDE migration prerequisites, and current patching expectations. The four existing migration diagrams were preserved. This refresh does **not** claim a new end-to-end SQL Server migration benchmark or a newly completed production migration on Raff. Exact application compatibility, SQL licensing, downtime, and performance must be validated for the customer's workload. ## What's next - [hosted SQL Server](/products/sql-server-hosting) — choose the Windows VM after sizing SQL Server and the application. - [Raff Pricing](/pricing) — review current Windows VM pricing. - [Windows Server Migration Checklist](/windows-server/windows-server-migration-checklist-small-business) — coordinate the broader server cutover. - [Local Server to Cloud Windows VPS Migration](/windows-server/local-server-to-cloud-windows-vps-migration) — plan a full office-server move. - [File Server Migration to Windows VPS](/windows-server/file-server-migration-to-windows-vps) — migrate shares that live beside SQL Server. - [SQL Server Max Server Memory](/windows-server/mssql-memory-tuning) — configure SQL memory after migration. - [SQL Server Backup Strategy](/windows-server/mssql-backup-strategy) — design ongoing database recovery. - [ERP Hosting on Windows VPS](/windows-server/erp-on-vps) — plan a SQL-backed ERP workload. - [Windows Server Hardening Checklist](/windows-server/windows-server-hardening-checklist) — secure the destination server. ## Sources - Microsoft Learn — SQL Server migration documentation: https://learn.microsoft.com/en-us/sql/sql-server/migrate/ - Microsoft Learn — Upgrade SQL Server to the latest version: https://learn.microsoft.com/en-us/sql/sql-server/migrate/guides/sql-server-to-sql-server-upgrade-guide - Microsoft Learn — Upgrade SQL Server using the migration component in SSMS: https://learn.microsoft.com/en-us/ssms/migrate-sql-server-component - Microsoft Learn — Supported version and edition upgrades for SQL Server 2025: https://learn.microsoft.com/en-us/sql/database-engine/install-windows/supported-version-and-edition-upgrades-2025 - Microsoft Learn — SQL Server 2025 release notes: https://learn.microsoft.com/en-us/sql/sql-server/sql-server-2025-release-notes - Microsoft Learn — Latest SQL Server updates and version history: https://learn.microsoft.com/en-us/troubleshoot/sql/releases/download-and-install-latest-updates - Microsoft Learn — Back up and restore SQL Server databases: https://learn.microsoft.com/en-us/sql/relational-databases/backup-restore/back-up-and-restore-of-sql-server-databases - Microsoft Learn — Recovery models: https://learn.microsoft.com/en-us/sql/relational-databases/backup-restore/recovery-models-sql-server - Microsoft Learn — Transfer logins and passwords between SQL Server instances: https://learn.microsoft.com/en-us/troubleshoot/sql/database-engine/security/transfer-logins-passwords-between-instances - Sources revalidated: 2026-09-11 --- ### SQL Server Performance Baseline: Query Store, Wait Stats, and PerfMon URL: https://rafftechnologies.com/windows-server/sql-server-performance-baseline-query-store-wait-stats-perfmon Description: Build a repeatable SQL Server performance baseline with Query Store, wait stats, SQL performance counters, and Windows PerfMon before tuning queries, changing configuration, or resizing a Windows VPS. ## In short A useful **SQL Server performance baseline** answers one question before you change anything: **what was the database and server doing while the workload was healthy, slow, or under peak load?** For SQL Server 2025 on Windows Server, combine four evidence sources: 1. **Query Store** — which queries ran, which plans they used, and how runtime behavior changed over time. 2. **Query Store wait statistics** — which wait categories were associated with specific queries. 3. **Instance-level waits and SQL Server performance counters** — what the Database Engine was waiting for and how SQL memory/engine counters behaved. 4. **Windows PerfMon** — whether CPU, available memory, disk activity, or other Windows resource signals moved at the same time. Use the baseline before changing `max server memory`, adding TempDB files, forcing a query plan, changing indexes, or resizing the VM. One high CPU screenshot or one wait type is not enough evidence for a production change. This guide owns **database-level SQL Server performance baseline and Query Store diagnostics**. For the operating-system-level CPU, RAM, disk, and network baseline, use [Windows Server Performance Monitoring: CPU, RAM, Disk, and Network](/windows-server/windows-server-performance-monitoring). ## Tested on Raff We validated the workflow in this guide on a Raff Windows VM on **2026-08-29**. | Item | Test environment | |---|---| | Provider | Raff Technologies | | Windows | Windows Server 2025 Standard Evaluation | | Windows build | 26100 | | SQL Server | SQL Server 2025 Developer, 17.0.1000.7 RTM | | SQL instance | `MSSQLSERVER` | | Test database | `RaffPerfTest` | | Connection tooling | Microsoft `sqlcmd` v1.10.0 | | Workload | Controlled synthetic test workload | ![SQL Server 2025 Developer installation completed on a Raff Windows VM](https://raff-images.s3.raffusercloud.com/01_sql_server_2025_install_success_raff_vm_8e4616bb10.png) *SQL Server 2025 Developer installation completed successfully on the Raff Windows Server 2025 test VM.* ![SQL Server 2025 version verification on a Raff Windows VM](https://raff-images.s3.raffusercloud.com/02_sql_server_2025_version_raff_vm_6e625da699.png) *SQL Server 2025 version and instance verification from the Raff lab environment.* We verified: - SQL Server 2025 installation and local trusted connection; - Query Store in `READ_WRITE` state; - Query Store wait-stat capture enabled; - Top Query Store runtime statistics from the controlled workload; - Query Store wait categories including Buffer IO, CPU, Memory, Transaction Log IO, and Other Disk IO; - instance-level waits from `sys.dm_os_wait_stats`; - a real `LCK_M_X` wait created with a controlled short blocking test; - SQL Server performance counters including Page Life Expectancy, Total Server Memory, Target Server Memory, and User Connections; - Windows Performance Monitor collection during the test window. The test validates the **procedure**, not production performance. The workload was synthetic and the results are not a Raff benchmark or sizing claim. One detail matters for reproducing the lab evidence: our captured PerfMon screen used CPU, Available MBytes, and disk I/O byte counters. For actual disk-latency analysis, this guide recommends `Avg. Disk sec/Read` and `Avg. Disk sec/Write`; those specific latency counters were not benchmarked in this test. ## What a SQL Server baseline should capture A baseline is not a list of universal “good” numbers. It is a repeatable measurement of your own workload under known conditions. Capture at least three periods when possible: | Period | Why it matters | |---|---| | Normal business load | Shows the server’s ordinary operating pattern | | Known peak workload | Shows what changes when concurrency, reports, imports, or jobs increase | | Reported slow period | Lets you correlate user complaints with query, wait, and OS evidence | For each period, record: - database name and SQL Server version; - timestamp and workload description; - top Query Store queries by duration, CPU, reads, or executions; - regressed queries or plan changes; - Query Store wait categories; - instance-level wait statistics; - SQL Server memory/performance counters relevant to the problem; - Windows CPU, available memory, and disk activity/latency; - any backup, index maintenance, reporting, antivirus, or application job running at the same time. The goal is correlation. A slow query plus storage waits plus increased disk latency is more useful than any one metric alone. ## Query Store is the starting point for database-level evidence Query Store persists query text, execution plans, and runtime statistics inside each user database. Starting with SQL Server 2017, Query Store can also capture wait statistics per query over time. Starting with SQL Server 2022, Query Store is enabled by default for newly created databases. Do not assume that means every database on a SQL Server 2025 instance is collecting data: restored, upgraded, migrated, or intentionally reconfigured databases can have different states. Check the actual state before troubleshooting. ## Step 1 — Verify Query Store state and storage health Run the following in the user database you want to monitor: ```sql SELECT actual_state_desc, desired_state_desc, readonly_reason, current_storage_size_mb, max_storage_size_mb, query_capture_mode_desc, wait_stats_capture_mode_desc FROM sys.database_query_store_options; ``` Review these fields first: | Field | What to check | |---|---| | `actual_state_desc` | Whether Query Store is actually collecting or is read-only/off | | `desired_state_desc` | What state SQL Server is configured to use | | `readonly_reason` | Why collection became read-only when actual and desired states differ | | `current_storage_size_mb` | Current Query Store space usage | | `max_storage_size_mb` | Configured storage ceiling | | `query_capture_mode_desc` | Which queries are being captured | | `wait_stats_capture_mode_desc` | Whether per-query wait statistics are being captured | In our Raff lab, Query Store returned `READ_WRITE`, the desired state was `READ_WRITE`, capture mode was `AUTO`, and wait-stat capture was `ON`. ![Query Store options on SQL Server 2025](https://raff-images.s3.raffusercloud.com/03_query_store_options_sql_server_2025_e1a86e12fd.png) *Query Store running in `READ_WRITE` mode with wait-stat capture enabled on the Raff SQL Server 2025 test database.* Microsoft recommends checking `sys.database_query_store_options` when Query Store appears to have stopped collecting data. Reaching the configured storage limit can make Query Store read-only. ## Step 2 — Enable Query Store wait-stat capture when required If the database is not using Query Store or wait-stat capture is disabled, review the environment before changing it. Microsoft documents this configuration pattern: ```sql ALTER DATABASE [YourDatabase] SET QUERY_STORE = ON ( WAIT_STATS_CAPTURE_MODE = ON ); ``` Replace `[YourDatabase]` with the real test or production database name. Do not copy configuration changes into production only because a tutorial says to. First verify: - Query Store is appropriate for the database and SQL Server version; - enough Query Store storage is available; - the database is not already governed by an organizational SQL configuration standard; - the change is made during a controlled administration window when required by your process. After any change, re-run `sys.database_query_store_options` and confirm the actual state. ## Step 3 — Find top resource-consuming queries SQL Server Management Studio exposes built-in Query Store reports such as: - **Top Resource Consuming Queries**; - **Regressed Queries**; - **Query Wait Statistics**; - **Tracked Queries**; - **Overall Resource Consumption**. You can also query Query Store directly. A practical baseline query is: ```sql SELECT TOP (10) q.query_id, SUM(rs.count_executions) AS executions, CAST( SUM(rs.avg_duration * rs.count_executions) / NULLIF(SUM(rs.count_executions), 0) / 1000.0 AS decimal(12,2) ) AS avg_duration_ms, CAST( SUM(rs.avg_cpu_time * rs.count_executions) / NULLIF(SUM(rs.count_executions), 0) / 1000.0 AS decimal(12,2) ) AS avg_cpu_ms, LEFT(REPLACE(REPLACE(qt.query_sql_text, CHAR(13), ' '), CHAR(10), ' '), 70) AS query_text FROM sys.query_store_query_text AS qt JOIN sys.query_store_query AS q ON qt.query_text_id = q.query_text_id JOIN sys.query_store_plan AS p ON q.query_id = p.query_id JOIN sys.query_store_runtime_stats AS rs ON p.plan_id = rs.plan_id GROUP BY q.query_id, qt.query_sql_text ORDER BY avg_duration_ms DESC; ``` In the controlled Raff workload, this returned the data-generation query and repeated test queries with execution count, average duration, and average CPU time. That confirmed Query Store was capturing runtime evidence as expected. ![Top resource-consuming Query Store queries on SQL Server 2025](https://raff-images.s3.raffusercloud.com/04_query_store_top_resource_queries_dc6bf583e8.png) *Top Query Store runtime results from the controlled Raff SQL Server 2025 workload.* For a real incident, change the sort metric depending on the problem: duration, CPU, logical reads, memory consumption, or execution count can tell different stories. Use **Regressed Queries** when a workload that used to perform well has become slower. A regression can be query-plan related even when the VM itself still has available CPU and memory. ## Step 4 — Use Query Store wait statistics to connect waits to queries Instance-wide wait statistics can tell you what SQL Server has been waiting for, but they do not automatically tell you which query created that wait pattern. Query Store helps close that gap because wait statistics can be associated with stored query plans over time. A useful query is: ```sql SELECT TOP (10) q.query_id, ws.wait_category_desc, CAST(SUM(ws.total_query_wait_time_ms) AS decimal(12,2)) AS total_wait_ms, LEFT(REPLACE(REPLACE(qt.query_sql_text, CHAR(13), ' '), CHAR(10), ' '), 65) AS query_text FROM sys.query_store_wait_stats AS ws JOIN sys.query_store_plan AS p ON ws.plan_id = p.plan_id JOIN sys.query_store_query AS q ON p.query_id = q.query_id JOIN sys.query_store_query_text AS qt ON q.query_text_id = qt.query_text_id GROUP BY q.query_id, ws.wait_category_desc, qt.query_sql_text ORDER BY total_wait_ms DESC; ``` Our test produced Query Store wait categories including: - Buffer IO; - Preemptive; - Memory; - CPU; - Transaction Log IO; - Other Disk IO. ![Query Store wait statistics captured on Raff SQL Server 2025](https://raff-images.s3.raffusercloud.com/05_query_store_wait_statistics_55314f20d3.png) *Query Store wait categories captured from the controlled Raff SQL Server 2025 test workload.* This is a starting point, not an automatic diagnosis. A high wait category tells you where to investigate; it does not prove the root cause by itself. ## Step 5 — Review instance-level wait stats in context For the SQL Server instance, review `sys.dm_os_wait_stats`: ```sql SELECT TOP (20) wait_type, waiting_tasks_count, wait_time_ms, signal_wait_time_ms, wait_time_ms - signal_wait_time_ms AS resource_wait_time_ms FROM sys.dm_os_wait_stats ORDER BY wait_time_ms DESC; ``` The important limitation is that these values are cumulative. They reflect waits accumulated since the SQL Server service started or since the wait statistics were explicitly cleared. That means this is weak evidence: ```text One query of sys.dm_os_wait_stats → one large wait type → immediate configuration change ``` A stronger workflow is: ```text Record wait stats at baseline start → run or observe a known workload window → record again → compare the change → correlate with Query Store and Windows metrics ``` ### Controlled blocking test used in the Raff lab To verify that a real lock wait appeared in `sys.dm_os_wait_stats`, we used a short controlled transaction in the test database. One session held a row update for roughly 12 seconds while a second update attempted to access the same row. The resulting wait statistics included `LCK_M_X` with approximately 10 seconds of resource wait time. This was an intentional lab condition, not a production incident. ![SQL Server instance wait statistics showing a controlled lock wait](https://raff-images.s3.raffusercloud.com/06_sql_server_instance_wait_stats_60e80a0b84.png) *Instance-level wait statistics from the Raff lab, including the intentionally generated `LCK_M_X` wait.* Do not create blocking deliberately on a production database just to validate monitoring. ## What common wait categories can suggest Use wait evidence as a direction for investigation, not as a final diagnosis. | Evidence pattern | Investigate next | |---|---| | Query Store shows CPU-heavy queries and Windows CPU rises at the same time | Query plan, scans, parallelism, application workload, then CPU sizing | | Page I/O-related waits rise and Windows disk latency also rises | Query access pattern, indexes, storage activity, backup/report overlap | | Memory-grant-related waits increase | Query memory grants, concurrency, execution plans, available SQL/Windows memory | | Lock-related waits rise | Blocking chains, transaction duration, application transaction design | | Log-write-related waits rise | Transaction log activity, storage latency, transaction pattern | | TempDB-related contention evidence appears | TempDB usage and configuration, then the dedicated TempDB guide | | Network-related waits appear without VM saturation | Client/application consumption rate, network path, result-set size | The same wait type can have different causes. Always combine waits with query and operating-system evidence. ## Step 6 — Add SQL Server performance counters SQL Server exposes engine counters through Windows Performance Monitor and through `sys.dm_os_performance_counters`. For a first SQL baseline, inspect a small set rather than collecting every counter available. Example: ```sql SELECT object_name, counter_name, instance_name, cntr_value, cntr_type FROM sys.dm_os_performance_counters WHERE counter_name IN ( 'Page life expectancy', 'Total Server Memory (KB)', 'Target Server Memory (KB)', 'User Connections' ) ORDER BY object_name, counter_name, instance_name; ``` In our Raff lab, the query returned the expected SQL Server Buffer Manager, General Statistics, and Memory Manager counters. ![SQL Server performance counters on the Raff SQL Server 2025 lab](https://raff-images.s3.raffusercloud.com/07_sql_server_performance_counters_82b0d801e3.png) *SQL Server memory, connection, and buffer counters captured during the Raff baseline test.* Use these as supporting signals: - **Total Server Memory / Target Server Memory** helps explain SQL Server memory allocation behavior; - **Page life expectancy** can be trended as one memory/cache signal, but should not be judged by one universal threshold; - **User Connections** helps put resource use in concurrency context. For rate counters such as requests per second, sample over a defined interval or use PerfMon rather than treating one raw DMV value as a ready-made rate. Microsoft also exposes a dedicated **SQLServer:Wait Statistics** performance object with counters for categories such as lock waits, log write waits, memory grant queue waits, network I/O waits, page I/O latch waits, and worker waits. ## Step 7 — Correlate SQL evidence with Windows PerfMon SQL Server runs inside Windows. Database evidence becomes much stronger when it matches what the operating system was doing at the same time. For the Windows-side baseline, start with: | Windows counter | What it helps answer | |---|---| | `Processor(_Total)\% Processor Time` | Was the VM CPU actually saturated during the slow period? | | `Memory\Available MBytes` | Did Windows have usable memory headroom? | | `PhysicalDisk(_Total)\Avg. Disk sec/Read` | Did read latency increase? | | `PhysicalDisk(_Total)\Avg. Disk sec/Write` | Did write latency increase? | | `Network Interface(*)\Bytes Total/sec` | Did network throughput change materially? | During our controlled Raff test, we verified PerfMon collection for CPU, available memory, and disk I/O activity. For production latency analysis, add `Avg. Disk sec/Read` and `Avg. Disk sec/Write` explicitly rather than relying on disk byte counters. ![Windows PerfMon SQL Server baseline on a Raff Windows VM](https://raff-images.s3.raffusercloud.com/08_windows_perfmon_sql_baseline_27fbb6e9a4.png) *Windows Performance Monitor during the controlled SQL Server baseline session on Raff.* Do not duplicate the entire Windows PerfMon setup here. The canonical workflow for Task Manager, Resource Monitor, PerfMon, and Data Collector Sets is [Windows Server Performance Monitoring](/windows-server/windows-server-performance-monitoring). For this SQL article, the key requirement is **time alignment**: collect the Windows counters during the same interval you are reviewing in Query Store. ## A practical 30–60 minute baseline workflow For a small production SQL Server or a controlled test environment, use this sequence: 1. Record SQL Server version, VM role, and current workload. 2. Verify Query Store state and wait-stat capture. 3. Note the baseline start time. 4. Start a Windows PerfMon/Data Collector Set or equivalent monitoring window. 5. Run or observe a representative workload. 6. Review Query Store Top Resource Consuming Queries. 7. Review Regressed Queries if relevant. 8. Review Query Store wait categories. 9. Capture instance-level wait stats for the interval or compare before/after snapshots. 10. Review SQL memory/performance counters. 11. Stop the monitoring window. 12. Correlate the timestamps before deciding what to change. Do not use a synthetic workload to claim production performance. A lab validates the procedure; production sizing still requires the customer’s real workload. ## Baseline worksheet Keep a short record for each measurement window: | Field | Example format | |---|---| | Window | 14:00–14:45 UTC | | Workload | Normal business load / month-end report / import job | | SQL version | SQL Server version and build | | Database | Test or production database identifier | | Query Store state | Read write / read only / off | | Top query signal | CPU / duration / reads / executions | | Dominant query wait category | Category from Query Store | | Instance wait change | Largest meaningful delta during window | | Windows CPU | Normal pattern and peak during window | | Available memory | Trend during window | | Disk latency | Read/write trend during window | | SQL memory signal | Total vs target server memory, other relevant counter | | Change made | None / query change / config change / resize | | Result | Better / unchanged / worse after re-test | This makes future incidents much easier to compare with known-good behavior. ## When to tune the query and when to resize the Windows VM A performance baseline should prevent unnecessary infrastructure upgrades as much as it should identify legitimate capacity limits. | Evidence | First action | |---|---| | One or two queries dominate CPU while Windows still has headroom | Investigate query plan, indexes, application pattern | | Query regression appears after plan change | Investigate the regressed plan before resizing | | SQL memory is capped too low while Windows has available memory | Review [MSSQL Memory Tuning](/windows-server/mssql-memory-tuning) | | Windows has persistent memory pressure and SQL plus other services compete | Tune memory allocation and consider more RAM or role separation | | TempDB pressure aligns with workload | Review [Configure TempDB for MSSQL Performance](/windows-server/mssql-tempdb-config) | | Disk latency rises with database I/O during the incident | Investigate query I/O, maintenance overlap, storage path, then infrastructure capacity | | CPU is persistently saturated across the representative workload after query review | Consider additional vCPU or workload separation | | Server hosts IIS/RDS/SQL and workloads compete repeatedly | Consider splitting roles instead of only enlarging one mixed VM | For role-level CPU/RAM planning, use [Windows Server Sizing by Workload](/windows-server/windows-server-sizing-by-workload). ## Query Store regressions should be investigated before plan forcing Query Store can make plan regressions visible and supports plan forcing, but plan forcing should not be the first reflex. Before forcing a plan, document: - the query ID; - old and new plan behavior; - runtime and resource differences; - whether statistics, indexes, compatibility level, application parameters, or schema changed; - whether the old plan is still safe for current data distribution and workload. Plan forcing can be a useful stabilization tool, but it is still a production change that needs validation and a rollback path. ## Do not tune from Page Life Expectancy alone Page Life Expectancy is frequently treated as a pass/fail number. That is too simplistic. PLE can move because of: - workload changes; - scans; - cache churn; - memory configuration; - database size; - maintenance jobs; - concurrent workloads. Use its trend with Windows available memory, SQL total/target memory, query behavior, and workload timing. If memory is the actual bottleneck, the dedicated [MSSQL Memory Tuning](/windows-server/mssql-memory-tuning) guide owns the configuration decision. ## Do not treat one disk-latency number as a universal threshold Disk behavior depends on workload, storage architecture, request size, read/write mix, caching, and concurrency. Instead of writing one number into a runbook as “healthy,” compare: - known-good window; - slow window; - backup or maintenance window; - before/after a query or infrastructure change. The change in latency aligned with the SQL workload is usually more actionable than a generic threshold copied from another environment. ## SQL Server baseline vs Windows Server baseline These pages are intentionally separate canonical owners. **This article owns:** - Query Store; - query regressions; - Query Store wait categories; - `sys.dm_os_wait_stats` as supporting SQL evidence; - SQL Server performance counters; - correlation between SQL and Windows metrics. **Windows Server Performance Monitoring owns:** - generic Windows CPU monitoring; - generic memory monitoring; - generic disk/network monitoring; - PerfMon/Data Collector Set setup independent of SQL Server. This keeps the SQL content useful without creating a competing generic PerfMon article. ## Where Raff fits Raff Windows VMs can host self-managed SQL Server workloads where administrators need control of the Windows Server operating system, SQL Server configuration, storage layout, firewall rules, backups, and performance diagnostics. A practical architecture for a growing workload is: ```text Application / IIS VM ↓ Private network ↓ SQL Server VM ↓ Query Store + SQL metrics + Windows monitoring ``` For a small workload, SQL Server and the application may start on one Windows VM. If baseline evidence shows that the roles repeatedly compete for CPU, RAM, or storage, separating the application and database can create a cleaner scaling and troubleshooting path. Raff provides the infrastructure layer. Query tuning, indexing, SQL Server configuration, licensing, database administration, and application behavior remain administrator responsibilities unless a separate managed service explicitly covers them. :::cta Deploy Windows Now Deploy a Raff Windows VM for your SQL Server workload, establish a performance baseline, and resize only when query and operating-system evidence shows a real infrastructure bottleneck. ::: ## Frequently asked questions ### What is the best way to baseline SQL Server performance? Use Query Store for query plans and runtime history, Query Store wait statistics for query-level wait categories, instance-level waits for broader Database Engine context, and Windows PerfMon for CPU, memory, disk, and network behavior during the same workload window. ### Is Query Store enabled by default in SQL Server 2025? For newly created databases, Query Store is enabled by default starting with SQL Server 2022. Restored, upgraded, migrated, or reconfigured databases may differ, so verify the actual state with `sys.database_query_store_options`. ### Should I clear SQL Server wait stats before every test? Not automatically. Wait stats are cumulative, so a safer operational pattern is often to capture before/after snapshots and compare the delta. Clearing wait stats removes instance history and should be a deliberate administration decision. ### Does a high wait time mean I need a larger VM? No. Waits can come from query plans, blocking, log activity, storage, memory grants, TempDB, network consumption, concurrency, or resource limits. Correlate the wait with Query Store and Windows metrics before resizing. ### Should I use PerfMon or Query Store? Use both. Query Store explains database/query behavior; PerfMon explains what the Windows VM was doing. They answer different parts of the same incident. ### How long should I collect a baseline? Use a window long enough to capture the workload you care about. A 30–60 minute controlled window can validate a troubleshooting workflow, while production baselines often need repeated windows across normal, peak, reporting, backup, or month-end periods. ## What's next - [Install SQL Server 2025 on a Windows Server VPS](/windows-server/install-sql-server-2025-windows-server-vps) - [MSSQL Memory Tuning on a Windows VPS](/windows-server/mssql-memory-tuning) - [Configure TempDB for MSSQL Performance](/windows-server/mssql-tempdb-config) - [Windows Server Performance Monitoring](/windows-server/windows-server-performance-monitoring) - [Windows Server Sizing by Workload](/windows-server/windows-server-sizing-by-workload) - [SQL Server hosting](/products/sql-server-hosting) ## Sources - Microsoft Learn — [Monitor Performance by Using the Query Store](https://learn.microsoft.com/en-us/sql/relational-databases/performance/monitoring-performance-by-using-the-query-store?view=sql-server-ver17) - Microsoft Learn — [Best practices for managing the Query Store](https://learn.microsoft.com/en-us/sql/relational-databases/performance/manage-the-query-store?view=sql-server-ver17) - Microsoft Learn — [Tune performance with the Query Store](https://learn.microsoft.com/en-us/sql/relational-databases/performance/tune-performance-with-the-query-store?view=sql-server-ver17) - Microsoft Learn — [SQL Server Wait Statistics performance object](https://learn.microsoft.com/en-us/sql/relational-databases/performance-monitor/sql-server-wait-statistics-object?view=sql-server-ver17) - Microsoft Learn — [sys.dm_os_wait_stats](https://learn.microsoft.com/en-us/sql/relational-databases/system-dynamic-management-views/sys-dm-os-wait-stats-transact-sql?view=sql-server-ver17) - Microsoft Learn — [sys.dm_os_performance_counters](https://learn.microsoft.com/en-us/sql/relational-databases/system-dynamic-management-views/sys-dm-os-performance-counters-transact-sql?view=sql-server-ver17) - Microsoft Learn — [Monitor resource usage with Performance Monitor](https://learn.microsoft.com/en-us/sql/relational-databases/performance-monitor/monitor-resource-usage-system-monitor?view=sql-server-ver17) - Sources verified: 2026-08-29 --- ### Windows Server Sizing by Workload: IIS, SQL Server, File Server, and Background Services URL: https://rafftechnologies.com/windows-server/windows-server-sizing-by-workload Description: Size a Windows Server by workload instead of user count alone. Compare practical CPU, RAM, storage, and role-splitting guidance for IIS, SQL Server, file servers, and background services. **Windows Server sizing** should start with the server role, not a generic CPU-and-RAM formula. IIS usually needs CPU headroom and memory for app pools; SQL Server is often memory- and storage-sensitive; file servers are driven by capacity, file behavior, and access patterns; background services depend on job concurrency and burst load. Start conservatively, leave headroom, monitor peak usage, and split roles when one workload starts competing with another. A 4 vCPU / 8 GB Windows VM can behave very differently depending on whether it runs a small IIS site, SQL Server, shared files, scheduled automation, or all four at once. That is why Raff treats the **workload role as the first sizing variable** before comparing VM configurations. If your main question is how many resources you need for **1, 3, 5, or 10 Remote Desktop users**, use [Windows VPS Sizing for Remote Users](/windows-server/windows-vps-sizing-remote-users). This guide owns a different decision: sizing Windows Server by the services running on it. ## Windows Server sizing starts with the role The operating system sets a baseline, but the workload determines the real requirement. Microsoft publishes minimum Windows Server hardware requirements, but minimum requirements are not production sizing targets. Start by classifying the server into one primary role: | Primary role | Resource that usually deserves the most attention | Common secondary concern | |---|---|---| | IIS web/application server | CPU and RAM | App pool behavior, logs, HTTPS, application dependencies | | SQL Server | RAM and storage behavior | CPU, TempDB, backups, query concurrency | | File server | Storage capacity and growth | Access pattern, backups, antivirus scanning, SMB behavior | | Background services / automation | CPU bursts and RAM | Schedule overlap, queues, logs, retry behavior | | RDP/RDS server | RAM per concurrent session | CPU, profiles, application mix, licensing | | Domain controller | Predictable baseline capacity | DNS, directory size, authentication volume, redundancy | | Mixed-role server | Contention between roles | Troubleshooting and recovery complexity | The safest sizing process is: ```text Identify primary role → estimate normal load → estimate peak load → leave operational headroom → monitor after launch → resize or split roles when contention appears ``` Do not start by asking, "How much RAM does Windows Server need?" Start with, "What will this server spend most of its time doing?" ## A workload sizing matrix gives a practical starting point The table below is a planning baseline for small and mid-sized Windows workloads. It is not a performance guarantee. Application vendors, database size, request volume, user concurrency, antivirus, backup jobs, and custom software can move the requirement materially. | Workload | Practical starting point | Move up when | |---|---:|---| | Small IIS site or internal web app | 2–4 vCPU / 4–8 GB RAM | Multiple app pools, heavier .NET apps, CPU bursts, or memory growth appear | | Production IIS / ASP.NET workload | 4 vCPU / 8–16 GB RAM | Several sites, background workers, report generation, or sustained traffic share the VM | | Small SQL Server / staging database | 4 vCPU / 8–16 GB RAM | Database cache, reporting, backups, or query concurrency create pressure | | Small production SQL Server | 4–8 vCPU / 16–32 GB RAM | SQL memory demand, TempDB activity, reporting, or mixed app/database roles compete | | Small file server | 2–4 vCPU / 4–8 GB RAM | Users also connect over RDP, indexing is heavy, or security/backup agents add load | | 5–10 user file/app server | 4–8 vCPU / 16–32 GB RAM | File access, profiles, business apps, and backups run at the same time | | Light automation / background services | 2–4 vCPU / 4–8 GB RAM | Jobs overlap, queues grow, or processes stay resident in memory | | Heavy scheduled processing | 4–8+ vCPU / 8–32+ GB RAM | Batch windows miss targets or workers compete with interactive workloads | These ranges are deliberately broad. The role tells you **which direction to watch**, while monitoring tells you whether the chosen size is actually enough. :::cta Deploy Windows Now Choose a Raff Windows VM for the workload, then monitor CPU, memory, storage, and application behavior before scaling further. ::: ## IIS server sizing is driven by application behavior For IIS, size the application rather than the IIS role itself. A static site, an ASP.NET Core API, a legacy ASP.NET Framework application, and ten isolated app pools can all place very different demands on the same Windows Server. A practical IIS starting model: | IIS workload | Starting point | Main thing to watch | |---|---:|---| | Static or very light internal site | 2 vCPU / 4 GB RAM | CPU bursts and available memory | | Small ASP.NET Core app | 2–4 vCPU / 4–8 GB RAM | App working set and request peaks | | Production business web app | 4 vCPU / 8–16 GB RAM | App pools, background work, GC pressure, response time | | Several production sites | 4–8 vCPU / 16+ GB RAM | Per-pool memory, CPU contention, recycle behavior | | IIS plus local SQL Server | Start larger or split roles | SQL and IIS competing for RAM and storage | IIS capacity is often less about a permanent CPU requirement and more about bursts. Authentication, application startup, report generation, image processing, PDF creation, compression, antivirus scanning, and deployment activity can create short periods of much higher demand than normal traffic. Memory becomes especially important when you use multiple application pools. One production site per app pool gives cleaner isolation, but every worker process has its own memory footprint. If the server hosts several apps, add the working sets together rather than sizing from the largest single site. For app-pool configuration after deployment, use [IIS Application Pool Tuning for Production](/windows-server/iis-app-pool-tuning). A useful operating rule is to avoid sizing an IIS production server so tightly that a recycle, deployment, or traffic burst immediately pushes it into paging or sustained high CPU. ## SQL Server sizing should prioritize memory and storage behavior SQL Server changes the sizing model because memory is part of database performance. SQL Server deliberately uses memory for data and plan caching, so a database VM with too little RAM can create unnecessary storage reads and poor query response times. Use these starting points: | SQL workload | Starting point | Notes | |---|---:|---| | Learning or temporary test | 2–4 vCPU / 4–8 GB RAM | Fine for installation validation and light queries | | Small app or staging database | 4 vCPU / 8–16 GB RAM | Watch buffer memory, TempDB, and backup duration | | Small production database | 4–8 vCPU / 16–32 GB RAM | Better starting point for business applications | | SQL-heavy production workload | 8+ vCPU / 32+ GB RAM | Size from real database behavior, not user count | | SQL plus RDS or IIS on same VM | Add headroom or split | Roles can compete directly for memory and storage | Microsoft recommends configuring SQL Server memory so the operating system and other processes retain enough RAM. In practice, that means the VM needs capacity for **Windows plus SQL Server plus everything else running on the server**. This is why a SQL Server should not be sized from database file size alone. A 30 GB database with heavy reporting can be more demanding than a 300 GB mostly archival database. Review: - active database working set; - concurrent queries; - report and export jobs; - TempDB usage; - backup window; - transaction log growth; - antivirus and monitoring overhead; - whether IIS, ERP, or RDS also runs on the same VM. Raff's [SQL Server 2025 installation guide](/windows-server/install-sql-server-2025-windows-server-vps) uses 4 vCPU / 8–16 GB as a small app or staging starting range and 4–8 vCPU / 16–32 GB for small production databases. Treat those as initial planning values, then validate against the workload. When SQL Server begins competing with an application server for memory, separating the roles usually creates a cleaner scaling and troubleshooting path. ## File server sizing is driven by capacity, growth, and access pattern A Windows file server usually needs less CPU than a database server, but storage planning matters much more. Capacity must include not only today's shared folders but also growth, user profiles, logs, exports, backup staging, and application files. Use this starting model: | File server workload | Starting point | Storage planning | |---|---:|---| | Small shared-folder server | 2 vCPU / 4–8 GB RAM | Current data + growth + recovery space | | File server with 3–5 RDP users | 4 vCPU / 8–16 GB RAM | Add user profiles and application files | | 5–10 users with files and apps | 4–8 vCPU / 16–32 GB RAM | Plan for simultaneous file, app, and backup activity | | Document-heavy business | CPU may stay modest | Storage capacity, file count, scanning, indexing, backup windows matter more | | File server plus database/app roles | Size for the other roles too | File storage is no longer the only requirement | For file servers, watch: - free disk space; - file-count growth; - large folders with many small files; - antivirus and endpoint protection scanning; - Windows Search or indexing; - backup and snapshot windows; - remote access latency; - SMB behavior; - user profile growth if the server also hosts RDP/RDS sessions. Do not fill the server close to capacity. A full Windows volume can disrupt user saves, application exports, updates, logs, and backups. If the server is primarily for shared folders, read [Windows VPS as a Cloud File Server](/windows-server/windows-vps-cloud-file-server) for permissions, SMB access, storage growth, and backup planning. ## Background services need sizing around concurrency and bursts Background services can look light during normal observation and then consume most of the server during a scheduled run. The important variable is not the number of Windows services; it is **what those services do at the same time**. Common background workloads include: - Windows services for business applications; - scheduled PowerShell tasks; - import/export jobs; - API workers; - queue consumers; - PDF or report generation; - file conversion; - data synchronization; - antivirus or EDR scans; - backup agents; - monitoring agents; - integration services. A practical starting point: | Background workload | Starting point | Watch for | |---|---:|---| | Few lightweight services | 2 vCPU / 4 GB RAM | Resident memory and log growth | | Several scheduled jobs | 2–4 vCPU / 4–8 GB RAM | Jobs overlapping at the same time | | Data import/export workers | 4 vCPU / 8–16 GB RAM | CPU bursts, disk activity, database calls | | Heavy report or conversion jobs | 4–8+ vCPU / 16+ GB RAM | Batch duration and interactive slowdown | | Workers sharing a production app VM | Add headroom | User-facing app latency during job windows | The scheduling model matters. Four tasks that each need one CPU core are manageable when they run sequentially. The same four jobs launched at 02:00 together may saturate the VM. If scheduled work repeatedly hurts IIS, SQL Server, RDS, or file access, moving those workers to a separate Windows VM can be more predictable than continually increasing one mixed-role server. ## Domain controller sizing should stay simple and redundant A small Active Directory Domain Services (AD DS) environment usually does not need a large VM, but domain controllers should be treated as infrastructure rather than places to stack unrelated workloads. For a small environment, a modest VM can be enough. What matters more is: - directory size; - authentication volume; - DNS activity; - Group Policy processing; - replication; - backup and recovery planning; - having another domain controller where the environment requires resilience. Microsoft's AD DS capacity guidance recommends measuring the workload and leaving capacity for failure scenarios rather than sizing only for the average day. Avoid putting SQL Server, heavy IIS applications, or large RDS workloads on a domain controller just to save one VM. Role separation improves security, maintenance, and troubleshooting. ## CPU sizing should be based on sustained pressure and burst behavior vCPU matters most when the workload is actively computing. Web requests, report generation, compression, encryption, SQL queries, PowerShell jobs, antivirus scans, and application code all create CPU demand. Use CPU monitoring to distinguish normal bursts from a real capacity problem: | Pattern | Interpretation | |---|---| | Short CPU spikes during normal work | Usually acceptable | | High CPU only during scheduled job | Review scheduling or worker separation | | Sustained high CPU during normal usage | Add CPU or investigate application bottleneck | | High CPU plus low memory availability | Fix both constraints; adding CPU alone may not help | | One process dominates CPU | Tune or isolate that workload before resizing everything | Do not upgrade CPU because a single screenshot shows 100% utilization. Measure during normal and peak periods, identify the process creating the load, and determine whether the demand is expected. ## RAM sizing should leave operational headroom RAM is often the first practical constraint on mixed Windows workloads. Windows, application processes, SQL Server, RDP sessions, antivirus, backup software, file cache, and monitoring all compete for the same memory. A simple planning model is: ```text Required RAM = Windows baseline + application working set + database/cache memory + active user sessions + security/backup/monitoring overhead + operational headroom ``` For production workloads, do not aim for a VM that sits near full memory during ordinary use. Sustained memory pressure can create paging, slow application response, longer batch jobs, and poor RDP responsiveness. Raff's remote-user sizing guide uses **20–30% memory headroom** as a practical monitoring target for active RDP environments. The same principle is useful for mixed Windows workloads: leave room for spikes, updates, scans, backups, and service restarts rather than sizing to the exact current working set. ## Storage sizing should include working data and recovery operations Storage sizing has two separate questions: 1. How much capacity does the workload need? 2. What kind of storage activity does the workload generate? Include: - Windows Server and updates; - application binaries; - databases and logs; - shared files; - user profiles; - temporary files; - application logs; - backup staging; - export/import folders; - growth for the next 12–24 months; - free space for maintenance and recovery operations. A file server can need a large volume with modest CPU. SQL Server may need much less total capacity but be more sensitive to database and TempDB I/O. An IIS server may use little storage until application logs, uploads, or generated files start accumulating. Capacity and performance are different sizing dimensions. Treat both explicitly. ## Network requirements depend on where the clients and other roles live Network demand changes with architecture. | Architecture | Network consideration | |---|---| | IIS and SQL on same VM | Less network dependency, more local resource contention | | Separate IIS and SQL VMs | Private network quality and database connection latency matter | | File server used through RDP | User display traffic and file activity stay server-side | | Direct remote file access | Latency and SMB access design become important | | Background worker calling APIs | Outbound reliability and queue retry design matter | | Multi-location business | WAN quality can matter more than raw VM size | Before increasing VM resources for a "slow server," confirm the bottleneck is actually inside the VM. RDP latency, client Wi-Fi, DNS, an external API, or a database on another host can all make a healthy Windows Server feel slow. ## Mixed roles should be split when contention becomes visible Small teams often start with one Windows VM because it is simple. That is reasonable when the workload is small and the operational risk is understood. A single-server pattern might be: ```text Windows VM ├── IIS ├── SQL Server ├── background worker └── shared files ``` The problem appears when those roles compete for the same resources or maintenance window. Split roles when: - SQL Server consumes memory needed by IIS or RDS; - backups slow down user-facing apps; - report jobs create visible CPU spikes; - file scanning or indexing affects database/app latency; - one application restart should not affect another role; - security policy requires stronger separation; - scaling one role forces you to overprovision every other role; - troubleshooting cannot clearly identify which workload caused the issue. A cleaner production architecture is often: ```text IIS / application VM ↓ Private network ↓ SQL Server VM Optional separate file or worker VM when needed ``` Role separation costs more than one VM, but it gives each workload its own capacity envelope, maintenance cycle, access rules, monitoring, and scaling path. ## Raff Windows VM sizing should start simple and remain resize-aware Raff Windows VMs are suitable for Windows workloads where the buyer wants administrator control over IIS, SQL Server, file services, business applications, automation, and remote administration. For sizing, the useful approach is not to find one "correct" server forever. Start with a configuration that has sensible headroom for the identified role, then measure the production workload. Use these signals after launch: | Metric | Healthy pattern | Resize or redesign signal | |---|---|---| | CPU | Short bursts with lower normal usage | Sustained high usage during normal workload | | RAM | Meaningful free memory during peak activity | Persistent memory pressure or paging | | Storage | Predictable growth and free space | Rapid growth, low free space, or long I/O queues | | Application response | Stable during normal and peak use | Slowdowns align with resource saturation | | Batch duration | Completes inside required window | Jobs overrun or interfere with users | | Backups | Complete inside maintenance window | Backup activity regularly affects production | | Role contention | Workloads coexist cleanly | One role repeatedly slows another | Review current configurations on [Raff Windows VM](/products/windows-vm) and [Raff pricing](/pricing). Choose from the live product options instead of copying an old plan price or screenshot into a sizing decision. ## A server-role checklist prevents under-sizing and over-sizing Before choosing the VM, answer these questions: | Question | Why it matters | |---|---| | What is the primary server role? | Identifies the dominant resource pattern | | What else runs on the same VM? | Reveals role contention | | What is the peak workload window? | Average usage can hide the bottleneck | | How much data exists today? | Establishes storage baseline | | How fast is data growing? | Prevents capacity surprises | | Does SQL Server run locally? | Changes RAM and storage planning materially | | Do users run desktop sessions? | Adds RDS/RAM/profile requirements | | Are there scheduled jobs? | Reveals burst CPU and I/O demand | | What backup window is acceptable? | Backup activity can influence sizing | | Can the application be split later? | Determines scaling path | | What happens if one role fails? | Helps decide whether role separation is justified | If these questions are answered before deployment, the first VM choice becomes much easier to defend and adjust. ## What's next - [Windows VPS Sizing for Remote Users](/windows-server/windows-vps-sizing-remote-users) — size 1, 3, 5, and 10-user RDP/RDS workloads. - [IIS Application Pool Tuning for Production](/windows-server/iis-app-pool-tuning) — tune app pools after choosing IIS capacity. - [Install SQL Server 2025 on a Windows Server VPS](/windows-server/install-sql-server-2025-windows-server-vps) — deploy and configure the database role. - [Windows VPS as a Cloud File Server](/windows-server/windows-vps-cloud-file-server) — plan shared files, storage, SMB access, and backups. - [SQL Server hosting](/products/sql-server-hosting) — review current Windows VM configurations. - [Raff pricing](/pricing) — compare current pricing before deployment. ## Sources - Microsoft Learn — Hardware Requirements for Windows Server: https://learn.microsoft.com/en-us/windows-server/get-started/hardware-requirements - Microsoft Learn — Capacity planning for Active Directory Domain Services: https://learn.microsoft.com/en-us/windows-server/administration/performance-tuning/role/active-directory-server/capacity-planning-for-active-directory-domain-services - Microsoft Learn — Server memory configuration options for SQL Server: https://learn.microsoft.com/en-us/sql/database-engine/configure-windows/server-memory-server-configuration-options - Microsoft Learn — Performance Tuning for SMB File Servers: https://learn.microsoft.com/en-us/windows-server/administration/performance-tuning/role/file-server/smb-file-server - Microsoft Learn — IIS application pool defaults: https://learn.microsoft.com/en-us/iis/configuration/system.applicationhost/applicationpools/applicationpooldefaults/ - Raff — Windows VPS Sizing for Remote Users: https://rafftechnologies.com/windows-server/windows-vps-sizing-remote-users - Raff — Windows VM: https://rafftechnologies.com/products/windows-vm - Raff — Pricing: https://rafftechnologies.com/pricing --- ### IIS Application Pool Settings & Tuning for Windows Server (2026) URL: https://rafftechnologies.com/windows-server/iis-app-pool-tuning Description: Configure IIS application pool settings for production on Windows Server, including idle timeout, AlwaysRunning, recycling, memory limits, identity, ASP.NET Core, and troubleshooting. ## In short An **IIS application pool** isolates one or more web applications inside IIS worker processes (`w3wp.exe`). For production, tune the pool around the application's actual behavior rather than copying a universal checklist. `ApplicationPoolIdentity` is a strong default, `AlwaysRunning` plus an idle timeout of `0` can reduce cold starts when memory allows, and **No Managed Code is recommended for ASP.NET Core but is not a hard requirement**. Keep Rapid-Fail Protection enabled, use recycling conservatively, and set memory thresholds only from measured behavior. Raff Technologies tested the workflow on Windows Server 2025 with IIS 10 and a dedicated test pool. This September refresh preserves that lab evidence while tightening identity, ASP.NET Core, recycling, and troubleshooting guidance against current Microsoft documentation. ## IIS application pools isolate applications and worker processes An IIS application pool is a logical boundary that lets websites and applications use separate worker processes, identities, runtime settings, recycle behavior, and failure controls. ```text Website / application ↓ IIS application pool ↓ w3wp.exe worker process ↓ Application code ``` Separate pools are often a good production default when applications need independent identities, recycling, failure isolation, or resource controls. They are not mandatory for every small or related application; the important point is that sharing a pool also shares its process lifecycle and blast radius. ## Recommended IIS application pool settings are workload-dependent Use these values as starting points, not universal requirements. | IIS setting | Production starting point | Notes | |---|---|---| | Pool isolation | Separate pools when isolation matters | Especially useful for unrelated production apps | | Identity | `ApplicationPoolIdentity` | Strong default for local-resource isolation | | Start Mode | `AlwaysRunning` for cold-start-sensitive apps | Starts the pool proactively | | Idle Time-out | `00:00:00` only when the app should stay warm | IIS default is commonly 20 minutes | | Managed Runtime | `No Managed Code` recommended for ASP.NET Core | Not a hard requirement for every ASP.NET Core hosting mode | | Regular recycling | Keep default or use a deliberate schedule | Avoid aggressive restarts | | Private Memory Limit | Only when measured behavior justifies it | It is a recycle threshold, not a RAM reservation | | Queue Length | Keep default unless monitoring proves a reason | Larger queues do not add throughput | | Rapid-Fail Protection | Keep enabled | Prevents repeated crash loops | | CPU limits | Do not set by default | Use only for a deliberate shared-host constraint | ## Tested on Raff The original lab ran on a Raff Windows VM with Windows Server 2025 Datacenter Evaluation and IIS 10. ![PowerShell output showing IIS features installed on a Raff Windows Server VPS test environment.](/uploads/01-iis-app-pool-test-environment.png) | Item | Value | |---|---| | Provider | Raff Technologies | | OS | Windows Server 2025 Datacenter Evaluation | | IIS | IIS 10 | | Test pool | `RaffTestAppPool` | | Original test date | 2026-05-26 | | Tester | Aybars Altinyay | The lab verified IIS feature state, pool creation, recycling settings, idle timeout, start mode, managed runtime, private-memory settings, and final PowerShell verification. These were test values, not universal production requirements. ## Step 1 — Review existing application pools Open IIS Manager: ```text Win + R -> inetmgr Server -> Application Pools ``` ![IIS Manager showing the Application Pools list on a Windows Server VPS.](https://raff-images.s3.raffusercloud.com/02_iis_application_pools_list_54143ecf81.png) Or use PowerShell: ```powershell Import-Module WebAdministration Get-ChildItem IIS:\AppPools ``` For each production pool, review identity, start mode, idle timeout, managed runtime, recycle triggers, memory limits, queue length, and Rapid-Fail Protection before changing anything. ## Step 2 — Create a dedicated pool when isolation is useful For the lab: ```powershell Import-Module WebAdministration New-WebAppPool -Name "RaffTestAppPool" Get-Item IIS:\AppPools\RaffTestAppPool ``` ![PowerShell output showing a RaffTestAppPool application pool created in IIS.](https://raff-images.s3.raffusercloud.com/03_test_app_pool_created_ebf628cdcd.png) Clear pool names make ownership and troubleshooting easier. Avoid placing unrelated production applications in `DefaultAppPool` simply because it already exists. ## IIS idle timeout controls worker-process shutdown after inactivity IIS commonly defaults the application-pool idle timeout to **20 minutes**. Setting it to `00:00:00` disables idle shutdown. For a latency-sensitive app that should stay warm: ```powershell Set-ItemProperty IIS:\AppPools\RaffTestAppPool ` -Name "processModel.idleTimeout" ` -Value "00:00:00" ``` For a longer timeout instead: ```powershell Set-ItemProperty IIS:\AppPools\RaffTestAppPool ` -Name "processModel.idleTimeout" ` -Value "08:00:00" ``` Use `0` only when eliminating cold starts is worth keeping the worker process resident in memory. On a memory-constrained VM hosting many pools, the default or a longer timeout may be a better trade-off. ## Step 4 — Start Mode AlwaysRunning reduces demand-start delay ```powershell Set-ItemProperty IIS:\AppPools\RaffTestAppPool ` -Name "startMode" ` -Value "AlwaysRunning" ``` `AlwaysRunning` starts the application pool proactively, but it does not automatically warm every application path. For applications with expensive startup work, pair it with IIS Application Initialization and a safe warm-up endpoint where appropriate. ## Step 5 — No Managed Code is recommended for ASP.NET Core For ASP.NET Core, Microsoft recommends setting the application pool's **.NET CLR Version** to **No Managed Code** because the ASP.NET Core Module manages the ASP.NET Core application process rather than relying on the classic ASP.NET Framework CLR. ```powershell Set-ItemProperty IIS:\AppPools\RaffTestAppPool ` -Name "managedRuntimeVersion" ` -Value "" ``` This setting is a recommendation, not a hard requirement for every ASP.NET Core hosting configuration. Classic ASP.NET Framework applications may still require the appropriate CLR version. ## IIS application pool recycling should be conservative IIS commonly uses a **1740-minute (29-hour)** regular recycle interval. You can keep the default or replace it with a deliberate schedule when operational requirements call for predictable recycle timing. ![IIS Application Pool Recycling settings showing configurable conditions for recycling a worker process.](https://raff-images.s3.raffusercloud.com/05_app_pool_recycling_settings_ae1ad06377.png) Avoid aggressive recycle intervals as a generic performance fix. Frequent recycling clears warm state and can repeatedly create cold-start latency. Typical triggers include regular interval, specific time, private memory, request count, and configuration changes. Add a trigger only when you understand what problem it is solving. ## Recycling differs from stopping and starting the pool A recycle replaces the worker process while keeping the application pool configured and available for IIS to start a replacement process. ```powershell Restart-WebAppPool -Name "RaffTestAppPool" ``` An explicit stop/start deliberately takes the pool down between actions: ```powershell Stop-WebAppPool -Name "RaffTestAppPool" Start-WebAppPool -Name "RaffTestAppPool" ``` For an app-specific change, recycle or restart the affected pool instead of using `iisreset` and interrupting every IIS application on the server. ## Private-memory limits are recycle thresholds, not RAM allocations IIS expects the private-memory recycle value in KB. Example 1 GB threshold: ```powershell Set-ItemProperty IIS:\AppPools\RaffTestAppPool ` -Name "recycling.periodicRestart.privateMemory" ` -Value 1048576 ``` Reference values: | Memory threshold | KB | |---|---:| | 512 MB | 524288 | | 1 GB | 1048576 | | 2 GB | 2097152 | | 4 GB | 4194304 | Do not copy a memory threshold from another server. Observe normal load, peak load, startup, scheduled work, and recycle behavior first. A threshold can limit the impact of abnormal growth, but it does not diagnose or fix a memory leak. ## ApplicationPoolIdentity is the preferred default for many IIS apps `ApplicationPoolIdentity` gives each application pool its own virtual account and is a strong default when the application primarily uses local resources. To explicitly set it with PowerShell: ```powershell Set-ItemProperty IIS:\AppPools\RaffTestAppPool ` -Name "processModel.identityType" ` -Value 4 ``` The IIS identity type value `4` corresponds to `ApplicationPoolIdentity`. For local file permissions, grant access to the virtual account: ```powershell icacls "C:\Sites\Example" /grant "IIS AppPool\RaffTestAppPool:(OI)(CI)RX" ``` Grant Modify or write access only to directories that actually need it. A dedicated service identity can be appropriate when the application must authenticate to remote Windows resources such as a network share or SQL Server using Windows Authentication. Do not use a personal administrator account as the application pool identity. If you use a specific user identity, configure credentials through a controlled administrative workflow rather than embedding a reusable production password in scripts or source control. ## Application Initialization can warm cold-start-sensitive applications Example: ```xml ``` Use a lightweight, non-destructive endpoint. The application/site may also require preload settings depending on the deployment design. ## Queue length and CPU limits should follow monitoring Increasing queue length does not increase application throughput. If requests queue because the app cannot process them quickly enough, diagnose CPU, memory, blocking calls, database latency, external APIs, and application code first. Likewise, CPU limits should be configured only when you intentionally need to constrain a pool on a shared server. ## Rapid-Fail Protection should remain enabled Rapid-Fail Protection stops an application pool after repeated worker-process failures within its configured interval. It prevents an endless crash/restart loop. Do not disable it to hide a broken deployment. Check Windows Process Activation Service events, application logs, runtime logs, and permissions instead. ## A stopped IIS application pool is not the same as an idle worker process If a pool repeatedly becomes **Stopped**, idle timeout is usually not the root cause. Common causes include: - Rapid-Fail Protection after repeated crashes; - invalid custom identity credentials; - startup failure; - missing file or directory permissions; - native dependency/runtime mismatch; - invalid IIS configuration. Check the pool: ```powershell Get-WebAppPoolState -Name "RaffTestAppPool" ``` Review WAS/W3SVC events: ```powershell Get-WinEvent -LogName System -MaxEvents 200 | Where-Object {$_.ProviderName -match 'WAS|W3SVC'} | Select-Object TimeCreated, Id, ProviderName, LevelDisplayName, Message ``` ## IIS worker-process memory should be measured before tuning thresholds ```powershell Get-Process w3wp -ErrorAction SilentlyContinue | Select-Object Id, ProcessName, CPU, @{Name='WorkingSetMB';Expression={[math]::Round($_.WorkingSet64 / 1MB, 1)}}, @{Name='PrivateMemoryMB';Expression={[math]::Round($_.PrivateMemorySize64 / 1MB, 1)}} ``` Map worker PIDs to pools: ```cmd %windir%\system32\inetsrv\appcmd list wp ``` Collect data across normal and peak traffic before choosing a private-memory recycle threshold. ## Final settings should be verified with PowerShell ```powershell Get-ItemProperty IIS:\AppPools\RaffTestAppPool | Select-Object name, state, managedRuntimeVersion, startMode, @{Name="IdleTimeoutMinutes";Expression={$_.processModel.idleTimeout.TotalMinutes}}, @{Name="IdentityType";Expression={$_.processModel.identityType}}, @{Name="PrivateMemoryKB";Expression={$_.recycling.periodicRestart.privateMemory}}, @{Name="RecycleIntervalMinutes";Expression={$_.recycling.periodicRestart.time.TotalMinutes}} ``` ![PowerShell output showing final IIS application pool settings including idle timeout, start mode, managed runtime, private memory limit, and recycle interval.](https://raff-images.s3.raffusercloud.com/06_app_pool_final_config_e647e79f86.png) In the original Raff lab, the test pool used No Managed Code, AlwaysRunning, a 0-minute idle timeout, and a 1 GB private-memory threshold. Those values were chosen for the lab and are **not** universal requirements. ## Production settings should match the application type | Application type | Typical starting point | |---|---| | ASP.NET Core production app | Dedicated pool when isolation matters, No Managed Code recommended, AlwaysRunning when cold starts matter | | Classic ASP.NET Framework | CLR and identity matched to application requirements | | Static site | Usually minimal tuning | | Internal low-traffic app | Default or longer idle timeout may be sufficient | | Multiple unrelated production apps | Separate pools usually simplify failure isolation and operations | ## Common IIS application pool tuning mistakes - treating idle timeout `0` as mandatory for every production app; - assuming No Managed Code is a hard requirement instead of a Microsoft recommendation for ASP.NET Core; - placing unrelated applications in one pool without considering shared failure/recycle behavior; - setting arbitrary private-memory thresholds; - increasing queue length instead of fixing the throughput bottleneck; - disabling Rapid-Fail Protection; - using `iisreset` for an app-specific change; - storing specific-user application-pool passwords in scripts. ## Production checklist Before considering the pool production-ready, verify identity permissions, runtime configuration, startup/idle behavior, recycling, failure protection, memory behavior, logging, and the application's actual response under load. :::cta Deploy Windows Now Run IIS and ASP.NET Core workloads on a Raff Windows VM with full administrator access, then tune each application pool around measured production behavior. ::: ## Validation scope The original configuration was tested on Raff on **May 26, 2026** by Aybars Altinyay using Windows Server 2025 Datacenter Evaluation and IIS 10. The article was revalidated on **September 10, 2026** against Microsoft's current IIS application-pool identity, process-model, recycling, failure-protection, Application Initialization, and ASP.NET Core hosting guidance. No new performance benchmark was run for this refresh. ## What's next - [.NET 10 Hosting Bundle download and IIS setup](/windows-server/iis-aspnet-core-windows-server-vps) - [Windows Server Sizing by Workload](/windows-server/windows-server-sizing-by-workload) - [win-acme on IIS setup guide](/windows-server/iis-letsencrypt-win-acme) - [Configure Windows Firewall on a Windows VPS](/windows-server/configure-windows-firewall) - [Windows Server Hardening Checklist](/windows-server/windows-server-hardening-checklist) - [ASP.NET hosting](/products/aspnet-hosting) ## Sources - Microsoft Learn — Application Pool Identities: https://learn.microsoft.com/en-us/iis/manage/configuring-security/application-pool-identities - Microsoft Learn — Process Model Settings: https://learn.microsoft.com/en-us/iis/configuration/system.applicationhost/applicationpools/add/processmodel/ - Microsoft Learn — Application Pool Recycling: https://learn.microsoft.com/en-us/iis/configuration/system.applicationhost/applicationpools/add/recycling/ - Microsoft Learn — Failure Settings: https://learn.microsoft.com/en-us/iis/configuration/system.applicationhost/applicationpools/add/failure/ - Microsoft Learn — Application Initialization: https://learn.microsoft.com/en-us/iis/configuration/system.webserver/applicationinitialization/ - Microsoft Learn — Host ASP.NET Core on Windows with IIS: https://learn.microsoft.com/en-us/aspnet/core/host-and-deploy/iis/ - Sources revalidated: 2026-09-10 --- ### win-acme on IIS: Let's Encrypt SSL Setup & Renewal (2026) URL: https://rafftechnologies.com/windows-server/iis-letsencrypt-win-acme Description: Set up Let's Encrypt SSL on IIS with win-acme, verify DNS and HTTP-01 validation, create the HTTPS binding, and confirm automatic renewal. Includes the 2026 simple-acme successor update. ## In short To set up win-acme on IIS for a free Let's Encrypt certificate, first make sure the website works over HTTP, the hostname resolves to your Windows Server, and TCP 80 is reachable for HTTP-01 validation. Then run `wacs.exe`, select the IIS site, let the client create the HTTPS binding, and verify the renewal task. Raff tested this on a Windows Server 2025 VPS with win-acme 2.2.9.1701; the classic client's default renewal age is 55 days. There is one important 2026 update: **win-acme's final 2.2.9.1 line has been succeeded by simple-acme, the actively maintained successor from the same maintainer.** Existing win-acme installations can still follow this guide. For a new deployment, evaluate simple-acme before standardizing on win-acme. ## Quick verdict | Situation | What to do | |---|---| | Existing win-acme installation is working | Keep it stable, verify renewal, and document the installed version | | New IIS server in 2026 | Evaluate simple-acme as the maintained successor before choosing the client | | IIS site already works over HTTP | Proceed to DNS and ACME validation | | Site only has blank IIS bindings | Add the hostname you want to secure | | DNS still points elsewhere | Fix DNS before requesting the certificate | | Port 80 is closed | Open it for HTTP-01 validation or use another challenge method | | Port 443 is closed | Open it before final HTTPS testing | | ACME client is stored in Downloads | Move it to a permanent folder before configuring renewal | | Renewal task is missing | Recreate the task and run a renewal test | Most failures come from DNS, IIS bindings, HTTP validation, or renewal configuration rather than certificate issuance itself. ## What win-acme is in 2026 win-acme is an ACMEv2 client for Windows. It can request TLS certificates from certificate authorities such as Let's Encrypt, store them in Windows, update IIS HTTPS bindings, and create a scheduled task for automatic renewal. The classic win-acme project ended on the **2.2.9.1** release line. Its successor is **simple-acme**, maintained by the same project maintainer and designed as a backwards-compatible replacement. If win-acme is already installed and renewing correctly, there is no need to break a stable server solely to follow a newer project name. If you are building a new long-lived IIS server, review simple-acme first. This guide keeps win-acme as the main workflow because existing deployments remain substantial. ## What we tested on Raff We tested the IIS and win-acme workflow on a Raff Windows VPS running Windows Server with IIS installed. ![PowerShell output showing IIS installed and the World Wide Web Publishing Service running on a Windows Server VPS.](https://raff-images.s3.raffusercloud.com/01_iis_test_environment_png_22a5ac69cf.png) | Item | Value | |---|---| | Provider | Raff Technologies | | OS | Windows Server 2025 Datacenter (lab build) | | Web server | IIS 10 | | ACME client tested | win-acme 2.2.9.1701 | | win-acme release line | 2.2.9.1 | | Validation method | HTTP-01 / IIS workflow | | Original lab test | 2026-05-26 | | Documentation revalidation | 2026-09-09 | | Tester | Serdar Tekin | In the lab, we verified IIS, bindings, firewall rules, win-acme startup, ACME connectivity, certificate creation, IIS binding installation, and the renewal-task workflow. Some certificate creation screenshots are illustrative examples. In production, use your own hostname and verify DNS before requesting a certificate. ## What you'll need - Windows Server 2022 or Windows Server 2025 - Local administrator access - IIS installed with at least one working site - A public domain or subdomain such as `app.example.com` - DNS access for that domain - TCP 80 reachable for the HTTP-01 workflow used here - TCP 443 reachable to serve HTTPS after issuance - win-acme already installed, or another ACME client selected for a new deployment This guide assumes the IIS site works over plain HTTP before certificate issuance. If you still need the server, [deploy a Raff Windows VPS](/products/windows-vm), point the hostname to its public IP, and continue below. ## Step 1 - Confirm IIS is installed and running Open PowerShell as Administrator: ```powershell Get-WindowsFeature -Name Web-Server Get-Service W3SVC ``` Expected result: ```text Web-Server Installed W3SVC Running ``` If IIS is not installed: ```powershell Install-WindowsFeature -Name Web-Server -IncludeManagementTools ``` Then verify again: ```powershell Get-Service W3SVC ``` If you host ASP.NET Core, install the appropriate .NET Hosting Bundle as part of the application deployment. Do not troubleshoot certificates before IIS itself serves the site correctly. ## Step 2 - Check the IIS hostname binding The default IIS workflow works best when the site has the real hostname you want to secure. ```powershell Import-Module WebAdministration Get-WebBinding | Select-Object protocol, bindingInformation ``` ![PowerShell output showing current IIS HTTP and HTTPS bindings for a Windows Server site.](https://raff-images.s3.raffusercloud.com/02_iis_bindings_efb7b1e91f.png) A blank HTTP binding looks like: ```text http *:80: ``` A hostname-specific binding looks like: ```text http *:80:app.example.com ``` If the site has no hostname binding, add one: ```powershell New-WebBinding -Name "Default Web Site" -Protocol http -Port 80 -HostHeader "app.example.com" ``` Then verify: ```powershell Get-WebBinding -Name "Default Web Site" | Select-Object protocol, bindingInformation ``` ### Fix: "No websites with host bindings have been configured in IIS" If win-acme reports: ```text No websites with host bindings have been configured in IIS. ``` first check whether the IIS site only has a blank binding such as `*:80:`. Add the intended hostname to the site and rerun the normal IIS workflow. Advanced/manual source plugins can work without this setup, but the default IIS source expects usable hostname bindings. ## Step 3 - Point DNS to the Windows VPS Create or verify the DNS record: | Type | Name | Value | |---|---|---| | A | `app` | Public IP of your Windows VPS | Verify from the server: ```powershell Resolve-DnsName app.example.com ``` ![PowerShell output showing DNS resolution for the domain pointing to the Raff Windows VPS public IP.](https://raff-images.s3.raffusercloud.com/03_dns_resolve_26d7d29fa9.png) You can also check from another machine: ```powershell nslookup app.example.com ``` Do not continue if DNS points to an old server, load balancer, proxy, or another system that is not prepared to answer the challenge. ## Step 4 - Make HTTP-01 validation reachable This guide uses **HTTP-01**, which requires the ACME validation request to reach your hostname over **TCP port 80**. Enable the standard IIS firewall rules if needed: ```powershell Enable-NetFirewallRule -DisplayName "World Wide Web Services (HTTP Traffic-In)" Enable-NetFirewallRule -DisplayName "World Wide Web Services (HTTPS Traffic-In)" ``` Confirm them: ```powershell Get-NetFirewallRule -DisplayName "World Wide Web Services (*Traffic-In)" | Select-Object DisplayName, Enabled, Direction, Action ``` ![PowerShell output showing Windows Firewall rules enabled for IIS HTTP and HTTPS inbound traffic.](https://raff-images.s3.raffusercloud.com/04_firewall_rules_4181d70887.png) Test port 80 from another machine: ```powershell Test-NetConnection app.example.com -Port 80 ``` Expected: ```text TcpTestSucceeded : True ``` Port **80** is the important validation port for HTTP-01. Port **443** is required to serve the resulting HTTPS website, but it is not the HTTP-01 challenge port. Wildcard certificates require **DNS-01** instead of HTTP-01. ## Step 5 - win-acme download from the official site Download win-acme from [win-acme.com](https://www.win-acme.com/) or the [GitHub releases page](https://github.com/win-acme/win-acme/releases), never from a mirror. The last classic release line is 2.2.9.1; the file we used was version 2.2.9.1701. Extract it to a permanent folder such as `C:\Tools\win-acme`, because the renewal task runs `wacs.exe` from that path for years. Run as Administrator: ```powershell Set-Location "C:\Tools\win-acme" .\wacs.exe ``` ![win-acme console showing version 2.2.9.1701, successful connection to Let's Encrypt, and the certificate creation menu.](https://raff-images.s3.raffusercloud.com/05_win_acme_version_b6f7054fe6.png) For a new 2026 deployment, also review simple-acme before deciding which client to standardize on. ## Step 6 - Create the Let's Encrypt certificate Run: ```powershell .\wacs.exe ``` For a normal local IIS site, choose: ```text N: Create certificate (default settings) ``` Then: 1. Select the IIS site or binding. 2. Confirm the hostname. 3. Use the configured ACME CA, such as Let's Encrypt. 4. Accept the subscriber agreement when prompted. 5. Enter an operations email address you monitor. 6. Let the client install the certificate and update IIS. 7. Let it configure automatic renewal. A successful flow can resemble: ```text Authorization result: valid Requesting certificate Success Installing certificate in the certificate store Adding https binding *:443:app.example.com Adding task for automatic renewal Certificate created successfully ``` ![win-acme console output showing a Let's Encrypt certificate created successfully, HTTPS binding added to IIS, and automatic renewal task configured.](https://raff-images.s3.raffusercloud.com/07_certificate_created_png_68a484b783.png) ## Step 7 - Verify the HTTPS binding in IIS PowerShell: ```powershell Get-WebBinding -Name "Default Web Site" | Select-Object protocol, bindingInformation, certificateHash ``` You should see an HTTPS binding such as: ```text http *:80:app.example.com https *:443:app.example.com ``` You can also check: ```text IIS Manager -> Sites -> Your site -> Bindings ``` ![IIS Manager showing an HTTPS binding on port 443 with a Let's Encrypt SSL certificate selected for the site hostname.](https://raff-images.s3.raffusercloud.com/08_iis_https_binding_png_20055f151b.png) For multiple HTTPS sites on one IP, verify hostname and SNI configuration too. ## Step 8 - Test HTTPS from outside the server From the server: ```powershell Invoke-WebRequest "https://app.example.com" -UseBasicParsing ``` Then test from a separate browser or client. Check that: - the certificate is valid; - the hostname matches; - an old proxy/server is not presenting a stale certificate; - the site loads without redirect loops. Only use `iisreset` when you actually need to refresh IIS state: ```powershell iisreset ``` ## Step 9 - Verify the win-acme scheduled task and renewal A certificate that works today but does not renew is not a finished setup. win-acme creates **one scheduled task** that runs daily and checks all configured renewals. With the default Let's Encrypt production endpoint, the task is typically named similar to: ```text win-acme renew (acme-v02.api.letsencrypt.org) ``` Do not rely on the task name alone. Verify the executable path and task action as well. List configured renewals: ```powershell .\wacs.exe --list ``` Find the scheduled task: ```powershell Get-ScheduledTask | Where-Object TaskName -like "*win-acme*" | Select-Object TaskName, State, TaskPath ``` Inspect what it actually runs: ```powershell Get-ScheduledTask | Where-Object TaskName -like "*win-acme*" | Select-Object -ExpandProperty Actions ``` If the task is missing, repair it with: ```powershell .\wacs.exe --setuptaskscheduler ``` ### How renewal timing works win-acme does not simply wait until the certificate is about to expire. In the final 2.2.9.1 line, the default renewal age is **55 days**. The client can also use ACME Renewal Information (ARI) when supported by the certificate authority, allowing the CA to recommend an earlier or more appropriate renewal window. This is especially important because certificate lifetimes are getting shorter over time. As of September 2026, Let's Encrypt's default certificate lifetime remains **90 days**, but Let's Encrypt has announced a move to **64 days in February 2027** and **45 days in February 2028**. ### Test renewal correctly Running: ```powershell .\wacs.exe --renew ``` only processes renewals that are due. A healthy certificate may therefore do nothing. For an explicit test: ```powershell .\wacs.exe --renew --force --verbose ``` Use forced production renewal sparingly. For issuance troubleshooting, use the ACME test/staging endpoint instead of repeatedly hitting production. ## Step 10 - Use staging while troubleshooting The `--test` switch enables test behavior and uses a test ACME endpoint by default. ```powershell .\wacs.exe --test ``` Use production only after DNS, IIS bindings, firewall behavior, and validation are correct. Let's Encrypt applies rate limits, so repeated production retries are not a substitute for diagnosing the underlying validation error. ## Optional - Unattended IIS setup After the interactive workflow works, you can automate issuance. Example: ```powershell Set-Location "C:\Tools\win-acme" .\wacs.exe ` --source iis ` --siteid 1 ` --host app.example.com ` --validation selfhosting ` --store certificatestore ` --installation iis ` --accepttos ` --emailaddress admin@example.com ``` Do not copy this unchanged into production. Confirm the site ID, hostname, validation method, store, and installation behavior for your server. ## Wildcard certificates require DNS-01 A wildcard such as: ```text *.example.com ``` cannot use HTTP-01 at Let's Encrypt. Use **DNS-01** validation through a supported DNS plugin or another secure automation method capable of creating the required TXT record. If you only need `app.example.com`, HTTP-01 is usually simpler. ## Common win-acme and IIS errors ### "No websites with host bindings have been configured in IIS" Run: ```powershell Get-WebBinding | Select-Object protocol, bindingInformation ``` If the site only has a blank binding, add the intended hostname and retry the default IIS workflow. ### Authorization failed or challenge returned 404 Check DNS: ```powershell Resolve-DnsName app.example.com ``` Then verify the HTTP challenge reaches the same server. URL Rewrite, authentication, IP restrictions, reverse proxies, or application routing can interfere with `/.well-known/acme-challenge/`. ### Timeout during connect Test externally: ```powershell Test-NetConnection app.example.com -Port 80 ``` If it fails, review Windows Firewall and any network firewall or security policy in front of the server. ### Browser still shows the old certificate Check which system is terminating TLS. The certificate may be coming from another IIS binding, reverse proxy, CDN, load balancer, or old server. ### Scheduled task exists but renewal fails Run: ```powershell .\wacs.exe --renew --force --verbose ``` Then inspect win-acme logs and Event Viewer, and verify that the scheduled task still points to the correct executable path. ### The ACME client was installed in Downloads Move it to a permanent directory and repair the scheduled task. Renewal should never depend on a temporary user download folder. ## Troubleshooting commands Check IIS bindings: ```powershell Get-WebBinding | Select-Object protocol, bindingInformation ``` Check DNS: ```powershell Resolve-DnsName app.example.com ``` Check port 80 externally: ```powershell Test-NetConnection app.example.com -Port 80 ``` Check local listeners: ```powershell Get-NetTCPConnection -LocalPort 80 -State Listen ``` Check URL reservations: ```powershell netsh http show urlacl ``` Check WebHosting certificates: ```powershell Get-ChildItem Cert:\LocalMachine\WebHosting | Sort-Object NotAfter -Descending | Select-Object Subject, NotAfter, Thumbprint ``` Check Personal if needed: ```powershell Get-ChildItem Cert:\LocalMachine\My | Sort-Object NotAfter -Descending | Select-Object Subject, NotAfter, Thumbprint ``` Check the renewal task: ```powershell Get-ScheduledTask | Where-Object TaskName -like "*win-acme*" | Select-Object TaskName, State, TaskPath ``` ## What Raff recommends For IIS SSL on a Windows VPS: 1. Make the IIS site work over HTTP first. 2. Add the exact hostname you want to secure. 3. Point DNS to the correct public IP. 4. Confirm TCP 80 is externally reachable for HTTP-01. 5. Keep the ACME client in a permanent folder. 6. Use the interactive IIS flow for the first certificate. 7. Verify the HTTPS binding. 8. Test HTTPS externally. 9. Verify the scheduled renewal task and its executable path. 10. Run a controlled renewal test before considering the setup complete. 11. For a new 2026 deployment, evaluate simple-acme as the maintained successor. :::cta Deploy Windows Now Deploy a Windows VM for IIS, ASP.NET Core, SQL Server, and other Windows workloads. ::: ## Tested on > Originally tested on Raff Windows VPS, Windows Server 2025 Datacenter (lab build), IIS 10, win-acme 2.2.9.1701, HTTP-01 validation workflow, 2026-05-26. Documentation and renewal guidance revalidated on 2026-09-09. Tester: Serdar Tekin. ## What's next - [Connect to a Windows VPS via RDP](/windows-server/connect-to-windows-vps-via-rdp) - [.NET 10 Hosting Bundle for IIS](/windows-server/iis-aspnet-core-windows-server-vps) - [IIS Application Pool Tuning for Production](/windows-server/iis-app-pool-tuning) - [Configure Windows Firewall on a Windows VPS](/windows-server/configure-windows-firewall) - [ASP.NET hosting](/products/aspnet-hosting) ## Sources - win-acme official site: https://www.win-acme.com/ - win-acme GitHub repository: https://github.com/win-acme/win-acme - win-acme getting started: https://www.win-acme.com/manual/getting-started - win-acme automatic renewal: https://www.win-acme.com/manual/automatic-renewal - win-acme command-line reference: https://www.win-acme.com/reference/cli - simple-acme official site: https://simple-acme.com/ - simple-acme GitHub repository: https://github.com/simple-acme/simple-acme - Let's Encrypt challenge types: https://letsencrypt.org/docs/challenge-types/ - Let's Encrypt rate limits: https://letsencrypt.org/docs/rate-limits/ - Let's Encrypt certificate lifetime transition: https://letsencrypt.org/2025/12/02/from-90-to-45 - Microsoft Learn - IIS bindings: https://learn.microsoft.com/en-us/iis/configuration/system.applicationHost/sites/site/bindings/binding - Date last verified: 2026-09-09 --- ### Azure Virtual Desktop Alternative for SMBs: Windows VPS vs AVD (2026) URL: https://rafftechnologies.com/windows-server/azure-virtual-desktop-alternative Description: Compare Azure Virtual Desktop with a Windows VPS for small-business remote access. See when Raff is a simpler AVD alternative, when AVD is better, and how cost, licensing, RDS, security, profiles, and management differ. ## In short A **Windows VPS can be a practical Azure Virtual Desktop alternative** when a small business mainly needs a hosted Windows Server for business applications, shared files, RDP/RDS users, or an office-server replacement. It is not a like-for-like replacement for Azure Virtual Desktop. **Azure Virtual Desktop (AVD)** is the stronger fit when you need a true virtual desktop platform: Windows 10/11 multi-session, pooled or personal host pools, RemoteApp publishing, managed brokering, FSLogix profiles, Azure identity/governance, autoscaling, and a larger desktop fleet. **Raff Technologies Windows VM** is the simpler fit when the requirement is primarily one or a few Windows Server VMs that your team or MSP can manage directly. The decision is therefore: ```text Need a cloud Windows Server for apps, files, RDS, or SMB workloads? -> Consider a Windows VPS Need full VDI, Windows 11 multi-session, host pools, profile infrastructure, and Azure desktop management? -> Azure Virtual Desktop is usually the better fit ``` Do not choose either platform from the word "desktop" alone. Start with the user workflow, application support, identity model, licensing, and operational complexity. ## Azure Virtual Desktop alternative: quick decision table | Requirement | Raff Windows VM / Windows VPS | Azure Virtual Desktop | |---|---:|---:| | One Windows Server for business applications | Strong fit | Possible, but often more platform than required | | Small RDS Session Host environment | Strong fit when RDS is designed and licensed correctly | Also possible | | Windows 10/11 multi-session desktop | No | **Strong fit** | | Pooled host pools | No AVD-style control plane | **Yes** | | Personal virtual desktops | Not an AVD-style desktop service | **Yes** | | RemoteApp at scale | Windows Server RDS can provide RemoteApp | **Yes, natively in AVD** | | Managed gateway/broker control plane | Customer manages the Windows/RDS architecture | **Microsoft manages AVD service infrastructure** | | FSLogix profile-container architecture | Customer-managed if used with RDS | **Common AVD profile model** | | Azure-native identity and governance | Limited to what you build around the VM | **Strong fit** | | Simple small-business Windows server | **Strong fit** | Can be unnecessary complexity | | Existing mature Azure desktop environment | Usually not a reason to migrate | **Strong fit** | | MSP wants simple per-client Windows VMs | **Strong fit** | Depends on MSP's AVD operating model | The most useful distinction is **Windows Server hosting versus desktop virtualization platform**. :::cta Explore Windows VM Use Raff Windows VM when the requirement is a hosted Windows Server for apps, RDS, files, or small-business workloads rather than a full AVD platform. ::: ## What Azure Virtual Desktop actually provides Azure Virtual Desktop is Microsoft's desktop and application virtualization service. Microsoft currently supports full desktops and RemoteApp delivery from Windows client and Windows Server session hosts, including **Windows 10 and Windows 11 Enterprise multi-session**, a capability designed for Azure Virtual Desktop scenarios. A typical AVD environment can include: - one or more **host pools**; - **pooled** or **personal** desktop models; - session host virtual machines; - desktop or RemoteApp application groups; - workspaces presented to users; - Microsoft Entra identity integration; - FSLogix profile containers; - autoscaling or session-host lifecycle controls; - Azure monitoring and policy; - image-management workflows. Microsoft's service also uses a reverse-connect architecture, so a normal Azure Virtual Desktop deployment does not require you to expose inbound RDP ports directly to session hosts. That is materially different from simply deploying one Windows Server VM and enabling Remote Desktop Services. ## What Raff Windows VM provides instead Raff is not trying to recreate the AVD control plane. Raff provides cloud Windows VMs that can run supported Windows Server workloads with administrator access. That model is useful when the business requirement is closer to: - a hosted accounting, tax, ERP, or line-of-business application; - a Windows Server RDS Session Host for a small team; - a Windows file/application server; - IIS or ASP.NET workloads; - SQL Server-backed software; - a cloud replacement for an aging office server; - an MSP-managed Windows environment; - one or several Windows VMs connected through private networking. The customer or MSP still owns the guest operating-system design: user accounts, RDS roles, RD Gateway or VPN decisions, application compatibility, patching, backups, monitoring, and licensing. That extra responsibility is acceptable when the environment is small enough that a direct Windows Server model is easier than operating a complete virtual desktop platform. ## Windows VPS vs AVD: the architectural difference ![Comparison visual showing a complex cloud server setup versus a simpler Windows VPS RDP path for small business remote access, Windows apps, shared files, backups, and storage](https://raff-images.s3.raffusercloud.com/simpler_windows_server_path_windows_vps_rdp_9eda30b9ec.png) A small Windows VPS/RDS environment may look like: ```text Users | v RD Gateway / VPN / controlled RDP path | v Windows Server VM |- RDS Session Host |- business applications |- shared files |- application services ``` An Azure Virtual Desktop environment adds a desktop-virtualization service layer: ```text Users | v Azure Virtual Desktop service | +-> Host pool |- Session host 1 |- Session host 2 |- Session host N | +-> Desktop / RemoteApp application groups +-> Workspace +-> Profile, identity, monitoring, scaling components ``` The second model is more capable for desktop virtualization. It also introduces more architecture to design and operate. ## When a Windows VPS is the better AVD alternative ### You mainly need one shared Windows business server If the requirement is "five employees need access to our Windows accounting application and its data," starting with host pools and enterprise VDI architecture may be unnecessary. A Windows Server VM with properly licensed RDS can be easier to understand, support, and migrate. ### You are replacing an office server Many small companies searching for an AVD replacement are not actually replacing VDI. They are replacing: - a Windows Server in an office closet; - direct RDP into an office network; - a shared accounting or ERP server; - a file/application server that remote staff need to reach. For that project, a side-by-side Windows Server migration can be more natural than redesigning the workload as virtual desktops. Use the [Server Migration Checklist](/windows-server/windows-server-migration-checklist-small-business) before production cutover. ### Your MSP wants one manageable Windows VM per client For some MSPs, a straightforward per-client Windows Server VM is operationally easier than building an AVD tenant, host-pool, profile, image, and autoscaling model for every small customer. That does not mean AVD is bad for MSPs. It means the additional platform should solve a real requirement. ### Your users need Windows Server applications, not Windows 11 desktops A line-of-business application can run perfectly well on Windows Server through RDS without giving every user a Windows 11 virtual desktop. If the vendor supports Windows Server/RDS, that can simplify the application-delivery model. ## When Azure Virtual Desktop is clearly better ### You need Windows 10/11 Enterprise multi-session This is one of AVD's clearest differentiators. If users specifically need a Windows client desktop experience with multi-session density, a normal Windows Server VPS is not an equivalent replacement. ### You need pooled or personal desktop fleets AVD supports pooled host pools for shared capacity and personal host pools for assigned desktops. That is a native desktop-service capability, not something a single Windows VPS replaces. ### You need Microsoft-managed brokering and gateway infrastructure Microsoft manages core AVD service infrastructure. You do not need to build the same RD Gateway and broker architecture you would operate in a traditional RDS deployment. For an RDS environment on a Windows VPS, external access and high availability remain your design responsibility. ### You need Azure-native governance Organizations already using Microsoft Entra ID, Intune, Azure Policy, Azure Monitor, Azure networking, and centralized Azure operations can gain more from keeping desktop infrastructure inside that management model. ### You operate a large or changing desktop fleet Host pools, scaling, image management, profile infrastructure, monitoring, and automation become more valuable as the environment grows. ## Azure Virtual Desktop cost is more than a desktop licence Microsoft separates AVD cost into two broad categories: 1. **Azure resource consumption** 2. **Licensing or access rights** Resource consumption can include: - session host VM compute; - managed disks; - network bandwidth; - profile storage such as Azure Files or Azure NetApp Files for FSLogix; - monitoring/log ingestion; - identity-related infrastructure where required; - image or application storage; - optional supporting services. Microsoft notes that session-host VM compute is usually the largest underlying resource cost, and autoscale, reservations, or savings plans can materially change the result. That makes a generic statement such as "AVD costs $X per user" misleading without defining architecture, region, VM sizes, concurrency, licensing, storage, and operating hours. ## Raff pricing is simpler, but RDS licensing still matters A Raff Windows deployment starts with the selected Windows VM and any required storage/data-protection services. If Raff supplies the production Windows Server licence, the current hosted model uses **SPLA**. For a multi-user hosted RDS environment, Raff's current licensing model is: ```text Windows VM compute + Windows Server Standard SPLA: $15/month per instance + RDS User SALs: $8/authorized user/month when RDS is used + application / SQL / Microsoft 365 licensing where applicable ``` Those licensing values are current as of September 2026 and should be rechecked on [Raff pricing](/pricing) before purchase. Do not use a Windows Server Evaluation image as the normal production plan. Evaluation belongs to temporary testing and compatibility work. For the complete model, read [Windows Server Licensing: SPLA, BYOL, CALs & RDS](/windows-server/windows-licensing). ## AVD licensing uses a different model For **internal business users**, Microsoft requires qualifying Windows, Microsoft 365, or RDS access rights depending on the session-host operating system and scenario. Microsoft also offers **per-user access pricing for external commercial users** through an Azure subscription. That external-user model is distinct from the licensing used for an organization's own employees and contractors. Because AVD licensing depends on the operating system, user type, and Microsoft entitlement, compare the exact Microsoft agreement rather than mapping Raff's RDS SAL price directly to an AVD user licence. ## RDP, RDS, and AVD are not the same thing These terms are often mixed together: | Term | What it is | |---|---| | RDP | The Remote Desktop Protocol used to display and control a remote Windows session | | Remote Desktop for Administration | The built-in administrative remote access on Windows Server | | RDS Session Host | Windows Server role for licensed multi-user desktop and RemoteApp sessions | | RD Gateway | Windows Server role that brokers external RDP access through a controlled gateway | | Azure Virtual Desktop | Microsoft's managed desktop/app virtualization service and control plane | A Windows VM that accepts RDP connections is not automatically an RDS deployment, and an RDS deployment is not automatically equivalent to AVD. For the Windows Server side, see [Multi-User RDP vs RDS Session Host](/windows-server/multi-user-rdp-vs-rds). ## Security: AVD reduces some infrastructure you must expose and manage Azure Virtual Desktop uses reverse connections between session hosts and the AVD service. Microsoft states that normal AVD deployments do not require inbound ports to be opened on session hosts for users to connect. That is a real architectural advantage over publishing direct RDP endpoints. A Windows Server/RDS design on Raff should therefore use a deliberate access model. Depending on the environment: - restrict direct administrative RDP by source where practical; - use [Remote Desktop Gateway](/windows-server/remote-desktop-gateway-vs-direct-rdp) for persistent external RDS access; - use VPN/private access when users need broader network connectivity; - keep Network Level Authentication enabled; - maintain Windows Firewall; - use named user and administrator accounts; - monitor authentication failures; - patch Windows and applications; - maintain off-server backups. The Windows VPS can be simpler operationally, but security does not become optional because the architecture has fewer components. ## User profiles are another important difference Pooled AVD environments commonly use **FSLogix profile containers** so users can move across session hosts while keeping a consistent profile. Microsoft recommends FSLogix profile containers for AVD and supports storage platforms such as Azure Files and Azure NetApp Files. A small single-server RDS deployment may not need the same profile architecture because users repeatedly return to the same Session Host. As you add multiple RDS Session Hosts, however, profile roaming and shared storage become real design problems there too. This is a good example of why a single Windows VPS is simpler only while the environment remains genuinely small. ## Application compatibility can decide the platform before cost does Before comparing monthly bills, ask the application vendor: - Is Windows Server supported? - Is RDS Session Host supported? - Is Windows 11 multi-session supported? - Does the app require a dedicated desktop or device? - How is the application licensed in a hosted environment? - Does it depend on printers, scanners, USB devices, local drivers, or Office automation? - Does it support multiple concurrent users? An accounting or ERP application that is supported on Windows Server RDS can be a strong Windows VPS use case. An application that requires Windows 11 Enterprise multi-session or a managed desktop image strategy points more naturally toward AVD. ## Small-business use cases where Raff can fit ### Accounting and tax software A small accounting team may need one central Windows environment for the application, reports, shared files, printing, and backups. If the application vendor supports RDS, a Windows Server VM can be a direct path. ### ERP and line-of-business applications When users mainly need one Windows application close to its database, Windows Server RDS can avoid creating a separate virtual client OS for every person. ### Remote employees using a shared server If the team needs a consistent Windows workspace rather than individually managed desktops, a small RDS design may be sufficient. ### MSP-managed client environments Raff can fit when an MSP wants a repeatable Windows VM, clear responsibility boundaries, private networking, backups, and a support path without adopting full AVD architecture for every customer. ## Situations where Raff should not be positioned as an AVD replacement Do **not** choose a Raff Windows VM merely to avoid Azure if the actual requirement includes: - Windows 10/11 Enterprise multi-session; - large pooled desktop fleets; - personal desktop assignment; - deep Azure/Entra/Intune governance; - standardized image lifecycle across many desktop hosts; - AVD autoscaling and host-pool management; - existing AVD operations your team already runs well; - a requirement for Microsoft-managed AVD brokering and gateway infrastructure. In those cases, AVD is solving a broader problem than Windows Server hosting. ## Migration from AVD to a Windows VPS is not always one-to-one An AVD environment may contain profile containers, desktop images, host pools, application groups, identity policies, storage, monitoring, autoscale rules, and multiple session hosts. You cannot always "move the AVD VM" and preserve the same operating model. Before replacing AVD with a simpler Windows Server/RDS environment: 1. Inventory users and concurrency. 2. List every published desktop and RemoteApp. 3. Identify application and OS requirements. 4. Review profile data and FSLogix dependencies. 5. Confirm whether Windows Server/RDS is supported by each application. 6. Recalculate Microsoft and application licensing. 7. Design RD Gateway or private access. 8. Build the Windows Server destination. 9. Test real users and application workflows. 10. Plan profile/data migration. 11. Run a controlled cutover. 12. Keep rollback until the new environment is proven. If AVD features are being actively used, migration can remove functionality rather than simply reduce cost. ## Decision framework: AVD or Windows VPS? Use these questions in order: ### 1. What operating system do users need? If Windows 10/11 Enterprise multi-session is mandatory, choose AVD. If Windows Server is supported and appropriate, continue. ### 2. Are you delivering desktops or hosting a business server? If you need a desktop fleet, AVD is usually the stronger platform. If you need one Windows Server for apps/files/RDS, a Windows VPS may be simpler. ### 3. How many session hosts do you expect? One or a few Windows Server hosts can be managed directly. Large pooled fleets benefit more from AVD's control plane. ### 4. Do you need Azure-native governance? If Entra, Intune, Azure Policy, Azure Monitor, Azure networking, and Azure automation are core requirements, AVD has the advantage. ### 5. Who will operate the environment? A smaller Windows Server deployment can be easier for an MSP or Windows administrator. AVD becomes more attractive when the team already has Azure desktop expertise. ### 6. What is the complete monthly cost? Compare compute, storage, profiles, licensing, backups, monitoring, networking, support, and administrator time. Do not compare only the headline VM price. :::cta Talk to Windows Engineer If your team mainly needs a Windows Server for remote users and business applications, review the RDS, licensing, sizing, security, and migration requirements before replacing AVD. ::: ## Frequently asked questions ### What is the best Azure Virtual Desktop alternative for a small business? It depends on whether the business needs VDI or simply a hosted Windows Server. A Windows VPS with properly configured RDS can be simpler for a small team running Windows business applications. If the requirement includes Windows 11 multi-session, host pools, personal desktops, or Azure-native desktop management, AVD is usually the better fit. ### Is a Windows VPS the same as Azure Virtual Desktop? No. A Windows VPS is a virtual Windows Server that you administer. Azure Virtual Desktop is a managed desktop and application virtualization platform with host pools, brokering, workspaces, application groups, and support for Windows client multi-session desktops. ### Can a Windows VPS support multiple remote users? Yes, when Windows Server Remote Desktop Services is deployed and licensed correctly. The two built-in administrative RDP connections are not a general multi-user desktop licensing model. ### Does Azure Virtual Desktop require inbound RDP ports? Microsoft's AVD architecture uses reverse connections, so users do not normally require inbound RDP ports opened directly to the session hosts. Traditional Windows Server/RDS deployments need their remote-access path designed separately. ### Is Azure Virtual Desktop more expensive than a Windows VPS? Not always. AVD cost depends on session-host compute, storage, networking, profiles, monitoring, licensing, concurrency, operating hours, and discounts. A Windows VPS can be simpler to budget for a small fixed environment, but it also requires you or your MSP to manage the Windows/RDS architecture. ### Does Raff include Windows Server and RDS licensing? Raff can provide Windows Server through its SPLA model. As of September 2026, Windows Server Standard is $15 per instance per month and hosted RDS uses $8 per authorized user per month RDS User SALs. Application and other Microsoft product licences remain separate where applicable. ### Should I migrate an existing AVD environment to Raff just to lower cost? Not without a workload review. If you actively use pooled host pools, FSLogix roaming profiles, Windows 11 multi-session, RemoteApp at scale, autoscaling, or Azure-native governance, replacing AVD with a simple Windows Server may remove capabilities your users depend on. ## Validation scope This comparison was revalidated on **September 11, 2026** against Microsoft's current Azure Virtual Desktop overview, deployment, licensing, cost, FSLogix, and recent product-update documentation. Raff licensing guidance was aligned with the current Windows Server Licensing page. This page does not claim that Raff reproduces the AVD control plane or that one platform is universally cheaper. Final fit depends on user count, operating system, applications, identity, licensing, availability, and management requirements. ## What's next - [RDP VPS](/windows-server/windows-vps-for-remote-desktop) — compare the Windows VPS remote-desktop model before choosing an AVD alternative. - [Azure Windows VPS vs Raff](/windows-server/azure-comparison) - [Multi-User RDP vs RDS Session Host](/windows-server/multi-user-rdp-vs-rds) - [Remote Desktop Gateway vs Direct RDP](/windows-server/remote-desktop-gateway-vs-direct-rdp) - [Windows Server Licensing](/windows-server/windows-licensing) - [Windows VPS Sizing for Remote Users](/windows-server/windows-vps-sizing-remote-users) - [Server Migration Checklist](/windows-server/windows-server-migration-checklist-small-business) - [Remote Desktop VPS](/products/remote-desktop-vps) - [Raff Pricing](/pricing) ## Sources - Microsoft Learn - What is Azure Virtual Desktop?: https://learn.microsoft.com/en-us/azure/virtual-desktop/overview - Microsoft Learn - Deploy Azure Virtual Desktop: https://learn.microsoft.com/en-us/azure/virtual-desktop/deploy-azure-virtual-desktop - Microsoft Learn - Licensing Azure Virtual Desktop: https://learn.microsoft.com/en-us/azure/virtual-desktop/licensing - Microsoft Learn - Understand and estimate Azure Virtual Desktop costs: https://learn.microsoft.com/en-us/azure/virtual-desktop/understand-estimate-costs - Microsoft Learn - FSLogix profile containers in Azure Virtual Desktop: https://learn.microsoft.com/en-us/azure/virtual-desktop/store-fslogix-profile - Microsoft Learn - What's new in Azure Virtual Desktop: https://learn.microsoft.com/en-us/azure/virtual-desktop/whats-new - Microsoft Learn - Remote Desktop Services overview: https://learn.microsoft.com/en-us/windows-server/remote/remote-desktop-services/overview - Sources revalidated: 2026-09-11 --- ### Managed vs Unmanaged Windows VPS: Which Should You Choose? URL: https://rafftechnologies.com/windows-server/managed-vs-unmanaged-windows-vps Description: Compare managed and unmanaged Windows VPS hosting, including support responsibilities, security, updates, backups, monitoring, and which model fits different business workloads. A managed Windows VPS means the hosting provider or service team handles more server administration tasks, while an unmanaged Windows VPS gives the customer administrator control and responsibility for maintaining the server. The right choice depends on whether your team wants infrastructure control or someone else to handle operating-system operations. Raff Windows VPS provides the infrastructure layer: Windows Server virtual machines, administrator access, deployment options, and cloud resources. Customers who need application management, patching, monitoring, or ongoing administration should define those responsibilities separately. ## Managed and unmanaged Windows VPS solve different problems The main difference between managed and unmanaged Windows VPS hosting is responsibility. | Area | Managed Windows VPS | Unmanaged Windows VPS | |---|---|---| | Windows updates | Usually handled by provider | Customer responsibility | | Security configuration | Provider-assisted or included depending on service | Customer responsibility | | Application installation | May be included | Customer responsibility | | Troubleshooting | Provider handles more layers | Customer handles server issues | | Administrator access | May be limited depending on provider | Full administrator control is common | | Custom configuration | Depends on provider policies | Customer controls configuration | | Cost | Usually higher | Usually lower | Neither model is automatically better. The correct choice depends on who should own the server operations. ## Unmanaged Windows VPS gives maximum control An unmanaged Windows VPS is closer to owning a remote Windows Server. The provider supplies the virtual machine and infrastructure, while the customer manages the operating system and software. This model fits teams that have: - Windows Server administrators; - IT staff; - developers who need administrator access; - MSPs managing their own clients; - application owners who understand their software requirements. Typical responsibilities include: - Windows updates; - firewall configuration; - user accounts; - application installation; - database configuration; - security hardening; - monitoring; - backups and restore testing. The advantage is flexibility. The customer decides how the server is configured. The trade-off is that the customer also owns more operational work. ## Managed Windows VPS reduces administration work Managed hosting is designed for customers who want someone else to handle more of the server lifecycle. A managed Windows VPS service may include: - operating system updates; - monitoring; - security checks; - troubleshooting; - backup management; - application support; - user administration. The exact scope depends on the provider. Before choosing managed hosting, confirm what is actually included. Important questions: - Are Windows updates included? - Who responds when an application fails? - Are backups configured and tested? - Is security hardening included? - Are third-party applications supported? - Is Remote Desktop Services administration included? A managed label alone does not define the service boundary. ## Security responsibilities change between the two models Security is one of the biggest differences between managed and unmanaged Windows VPS hosting. ![Managed vs unmanaged Windows VPS responsibility model showing who handles updates, security, backups, monitoring, troubleshooting, and server management](https://raff-images.s3.raffusercloud.com/windows_vps_responsibility_model_managed_vs_unmanaged_png_adea522c2a.png) With an unmanaged server, the customer usually owns: - administrator account security; - firewall rules; - RDP exposure; - Windows Defender configuration; - patch schedules; - user permissions; - security monitoring. With managed hosting, some of these tasks may move to the provider. A secure Windows VPS still requires clear ownership. Every production server should have: - strong administrator credentials; - regular updates; - limited remote access; - backups; - tested recovery procedures; - documented users and applications. ## Backups and recovery need clear ownership Backups are often where managed and unmanaged expectations become unclear. A provider may offer infrastructure-level backups, snapshots, or recovery tools, but customers should understand: - what data is protected; - backup frequency; - retention period; - restore process; - who performs recovery. For business applications, a backup plan should include restore testing rather than only creating backup copies. ## MSPs and technical teams often choose unmanaged VPS Managed service providers, developers, and IT teams often prefer unmanaged Windows VPS environments because they already have operational processes. They may want control over: - software installation; - security policies; - client environments; - automation scripts; - monitoring tools; - application stacks. For these users, paying for management they do not need can add unnecessary cost. ## Small businesses often need to evaluate support requirements Small businesses without internal IT staff should focus less on the VPS label and more on who will operate the server. A Windows VPS may require someone to handle: - user access; - software updates; - application issues; - printer configuration; - backups; - security settings. If nobody owns those tasks, a lower-cost unmanaged VPS can become difficult to operate. In that case, a managed provider, MSP partner, or internal IT service may be the better fit. ## How Raff fits the Windows VPS decision Raff provides Windows VPS infrastructure with Windows Server deployment, administrator access, and cloud VM resources. Raff customers manage their own operating system and applications unless additional services are separately arranged. This model works well for: - developers; - IT teams; - MSPs; - businesses with technical staff; - organizations that want control over Windows Server. Before deploying a production Windows VPS, define who owns: - Windows administration; - application support; - security updates; - backups; - user management; - troubleshooting. Clear ownership prevents support gaps later. :::cta Deploy Windows Now Create a Windows VM on Raff when your team wants administrator control over its Windows Server environment. ::: ## Choose managed Windows VPS if... Choose managed hosting when: - your team does not manage Windows Server regularly; - you need someone else to handle routine administration; - server issues need a dedicated operations owner; - application support is part of the service agreement. ## Choose unmanaged Windows VPS if... Choose unmanaged hosting when: - you need full administrator control; - your team manages Windows servers already; - you run custom applications; - you need flexibility for configuration; - you want direct control over updates and software. ## Decision checklist | Question | If yes | |---|---| | Do you have someone who manages Windows Server? | Unmanaged may fit | | Do you need custom software and full control? | Unmanaged may fit | | Do you need someone else to handle updates? | Managed may fit | | Do you need application support included? | Managed may fit | | Is the server business-critical? | Define backup and support ownership first | ## What's next - [Windows VPS pricing](/windows-server/windows-vps-pricing-explained) — compare the recurring cost structure before choosing managed or unmanaged service. - [Windows VPS Sizing for Remote Users](/windows-server/windows-vps-sizing-remote-users) - [Windows VPS for MSP Client Environments](/windows-server/windows-vps-for-msp-client-environments) - [Windows Server Initial Setup Checklist](/windows-server/windows-server-initial-setup-checklist) - [Raff Windows VM](/products/windows-vm) --- ### SQL Server Standard vs Enterprise: Features, Limits & Cost (2026) URL: https://rafftechnologies.com/windows-server/mssql-standard-vs-enterprise Description: Compare SQL Server Standard and Enterprise in 2026, including SQL Server 2025 CPU and memory limits, Always On, licensing, official pricing, performance differences, and when Enterprise is worth the extra cost. ## In short For most production workloads on a Windows VPS, **SQL Server Standard is the right paid edition**. SQL Server 2025 Standard supports up to **32 cores** and **256 GB of buffer pool memory** per instance and includes features such as Resource Governor and columnstore indexes that older comparison guides may still treat as Enterprise-only. Choose **SQL Server Enterprise** when the workload has a specific requirement that Standard cannot meet: full Always On Availability Groups, compute or memory beyond Standard limits, larger failover-cluster designs, more memory-optimized data, or another verified Enterprise-only capability. Do not buy Enterprise simply because the database is in production. Standard is a production edition. The question is whether your workload actually needs an Enterprise-only feature or scale limit. --- ## SQL Server Standard vs Enterprise: quick comparison | Area | SQL Server 2025 Standard | SQL Server 2025 Enterprise | |---|---|---| | Best fit | SMB and mid-tier production workloads | Mission-critical and very large workloads | | Compute limit per instance | Lesser of 4 sockets or 32 cores | Operating system maximum | | Buffer pool memory | 256 GB | Operating system maximum | | Maximum relational database size | 524 PB | 524 PB | | Memory-optimized data per database | 32 GB | Unlimited | | Resource Governor | Yes | Yes | | Columnstore | Yes | Yes | | Full Always On Availability Groups | No | Yes | | Basic Availability Groups | Yes, with limitations | Yes | | Failover Cluster Instance maximum nodes | 2 | 16 | | Licensing models | Server + CAL or Per Core | Per Core | | Typical licensing cost | Lower | Significantly higher | For most Raff Windows Server customers, the practical rule is: > **Start with Standard unless you can name the Enterprise-only feature, scale requirement, or licensing architecture that justifies Enterprise.** --- ## What changed with SQL Server 2025? A lot of SQL Server Standard vs Enterprise comparisons on the web are based on older releases. That can lead to unnecessary Enterprise purchases. SQL Server 2025 Standard is stronger than older Standard releases. Microsoft documents a limit of up to 32 cores per instance and 256 GB of buffer pool memory for Standard. Resource Governor is also available in Standard in SQL Server 2025. That matters because many real-world Windows VPS workloads never approach those limits. A typical ERP database, ASP.NET application backend, accounting database, internal business application, or smaller SaaS workload is more likely to run into problems caused by: - poorly tuned queries - missing or inefficient indexes - insufficient RAM allocation - slow or overloaded storage - bad `max server memory` configuration - missing maintenance jobs - weak backup strategy - running IIS, RDP sessions, and SQL Server on an undersized VM before SQL Server Standard itself becomes the limiting factor. If you are comparing editions for SQL Server 2022 or an older version, use the feature matrix for that exact release. Do not apply the SQL Server 2025 limits blindly to older installations. --- ## When SQL Server Standard is enough Standard is a strong fit when you need a serious production database but do not have a specific Enterprise-only requirement. Typical Standard workloads include: | Workload | Standard fit | |---|---| | ERP or accounting backend | Excellent | | ASP.NET production application | Excellent | | Internal line-of-business software | Excellent | | Small or mid-size SaaS backend | Usually excellent | | Reporting database for an SMB | Usually excellent | | SQL Server workload on a normal Windows VPS | Usually excellent | | Database that has outgrown Express | Excellent | | Single-server production SQL deployment | Excellent | Choose Standard when: - the workload fits within 32 cores - the instance can operate within a 256 GB buffer pool - you need SQL Server Agent and normal production administration features - Basic Availability Groups or another simpler HA design is sufficient - you do not need an Enterprise-only online, availability, or scale feature - licensing cost matters For many businesses, Standard offers the best balance of production capability and licensing cost. --- ## When SQL Server Enterprise is worth the extra cost Enterprise becomes justified when the workload has a concrete technical requirement that Standard cannot satisfy. ### You need full Always On Availability Groups SQL Server Standard supports **Basic Availability Groups**, but they are intentionally limited. Microsoft documents Basic AG support in Standard with a maximum of two replicas and one database per availability group. If you need a full Always On Availability Group design with broader availability-group capabilities, multiple databases, more replicas, or a more advanced read-scale and failover architecture, Enterprise becomes relevant. ### You need more than Standard's compute or memory limits SQL Server 2025 Standard is capped at the lesser of four sockets or 32 cores per instance and 256 GB of buffer pool memory. Enterprise can use the operating system maximum. If the workload genuinely needs more than Standard can address, Enterprise is not just a feature upgrade; it removes a real scale ceiling. ### You need larger failover cluster architecture SQL Server 2025 Standard supports up to two nodes for a Failover Cluster Instance. Enterprise supports up to 16. For normal SMB deployments this may not matter. For larger mission-critical environments, it can. ### You need more memory-optimized data SQL Server 2025 Standard supports up to 32 GB of memory-optimized data per database. Enterprise does not have that edition limit. If In-Memory OLTP is central to the application and the workload exceeds the Standard allowance, Enterprise may be required. ### You need a specific Enterprise-only capability Do not buy Enterprise based on a generic feature list from an old blog post. Identify the exact capability your architecture requires, then confirm it against the Microsoft feature matrix for your SQL Server version. That is a much safer buying process than assuming Enterprise is automatically the 'production' edition. --- ## Is SQL Server Enterprise faster than Standard? **Not automatically.** Enterprise can unlock higher resource ceilings and Enterprise-only performance capabilities, but changing the edition does not automatically fix a slow SQL Server workload. If a Standard instance is slow because of: - missing indexes - expensive queries - blocking - incorrect memory configuration - slow storage - high latency - undersized VM resources - poor maintenance then an Enterprise license alone will not solve the root cause. Before upgrading editions for performance, identify the bottleneck. A useful sequence is: ```text Measure workload -> Identify bottleneck -> Check Standard limit -> Check Enterprise-only feature -> Upgrade only if needed ``` If the bottleneck is simply CPU, RAM, or storage and the workload is still below Standard's edition limits, resizing or tuning the Windows VPS may be the better first move. --- ## Always On: Standard vs Enterprise High availability is one of the most important edition differences. ### SQL Server Standard Standard supports **Basic Availability Groups**. They are useful for simpler HA requirements, but they are limited compared with the full Enterprise feature. A Basic Availability Group supports a limited two-replica, single-database design. ### SQL Server Enterprise Enterprise supports full Always On Availability Groups and is the edition to evaluate when you need a more advanced HA topology. If your requirement is simply 'we need SQL Server to be highly available,' do not jump straight to Enterprise. First define: - how many databases must fail over together - how many replicas you need - whether secondaries must be readable - whether backup workloads should run on secondaries - required RPO and RTO - whether a Basic AG, FCI, application-level design, or full AG is the right architecture Edition should follow the HA design, not the other way around. --- ## SQL Server Standard vs Enterprise pricing SQL Server Enterprise is substantially more expensive than Standard, so the feature decision has a direct infrastructure cost. Microsoft's SQL Server 2025 pricing guidance lists the following **open no-level estimated retail pricing** for perpetual licenses: | License | Microsoft estimated retail price | |---|---:| | SQL Server 2025 Standard - 2-core pack | $3,945 | | SQL Server 2025 Enterprise - 2-core pack | $15,123 | | SQL Server 2025 Standard Server license | $989 | | SQL Server 2025 CAL | $230 per user or device | These prices are useful for understanding the size of the Standard-vs-Enterprise gap, but they are **not a Raff hosted licensing quote** and they are not necessarily what a hosting customer will pay monthly. Actual cost depends on licensing channel, contract, Software Assurance or subscription rights, virtualization model, number of licensed cores, provider terms, and whether you are using BYOL or provider-supplied licensing. For a hosted Windows VPS, ask for the current monthly SQL Server licensing option before using Microsoft retail pricing as your budget. --- ## SQL Server licensing on a Windows VPS or VM The licensing model also differs by edition. ### SQL Server Standard Standard can be licensed using: - **Per Core**, or - **Server + CAL**, where the scenario qualifies ### SQL Server Enterprise Enterprise is licensed **Per Core** under Microsoft's current commercial licensing model. For individually licensed virtual machines under Microsoft Commercial Licensing, current SQL Server 2025 guidance includes minimum core-license requirements and Software Assurance or subscription conditions for licensing by individual VM. Hosted-provider licensing can follow a different provider agreement and commercial model, so do not assume that a Microsoft volume-licensing example maps one-to-one to a hosted Raff VPS. If you already own SQL Server licenses, confirm your BYOL rights before migration. Ownership alone does not automatically mean the license can be moved to any hosted environment. --- ## Can you upgrade SQL Server Standard to Enterprise? Yes. Microsoft lists **SQL Server 2025 Standard to Enterprise** as a supported edition upgrade path. That means you do not need to buy Enterprise on day one purely because you are worried the workload may grow later. A sensible path for many teams is: 1. Start with Standard when it meets the requirements. 2. Monitor CPU, memory, database growth, HA requirements, and feature usage. 3. Identify the exact reason Standard is no longer sufficient. 4. Confirm licensing and edition-upgrade support. 5. Back up the databases and system configuration. 6. Plan a maintenance window and perform the edition upgrade. 7. Re-test application connectivity, SQL Agent jobs, backups, and HA configuration. Clustered installations and some edition-change scenarios have additional restrictions, so always verify the supported upgrade matrix for your exact topology before changing a production server. --- ## How to check whether you are running Standard or Enterprise Before planning an upgrade, query the server instead of guessing from the installer or application documentation. For an Express instance named `SQLEXPRESS`: ```powershell sqlcmd -S .\SQLEXPRESS -E -C -Q "SELECT SERVERPROPERTY('Edition') AS Edition, SERVERPROPERTY('ProductVersion') AS ProductVersion;" ``` For another instance, replace the server and instance name. You can also run the query directly in SQL Server Management Studio: ```sql SELECT SERVERPROPERTY('Edition') AS Edition, SERVERPROPERTY('ProductVersion') AS ProductVersion, SERVERPROPERTY('ProductLevel') AS ProductLevel; ``` ![sqlcmd output showing SQL Server edition and version information for a SQLEXPRESS instance.](https://raff-images.s3.raffusercloud.com/02_sql_server_edition_query_6c80bd62eb.png) Possible results include: - Express Edition - Standard Edition - Enterprise Edition - Developer Edition - Evaluation Edition This is also useful during migrations because the source application's documentation may not accurately reflect the edition currently installed. --- ## Where SQL Server Express fits Express is still a useful free edition for development, demos, very small applications, and lightweight databases. But it should not dominate a Standard vs Enterprise decision. The practical progression is usually: ```text Express -> Standard -> Enterprise only if a specific requirement appears ``` Move from Express to Standard when you need more production headroom, SQL Server Agent, larger resource limits, or better operational flexibility. For most serious SMB production workloads, the main paid-edition decision starts with Standard. --- ## What we checked on Raff We verified the edition and version query workflow on a Raff Windows VPS running Windows Server 2025 with SQL Server 2025 Express. ![PowerShell output showing a Raff Windows VPS running Windows Server 2025 with SQL Server SQLEXPRESS service available.](https://raff-images.s3.raffusercloud.com/01_sql_edition_test_environment_a854995cdd.png) | Item | Value | |---|---| | Provider | Raff Technologies | | OS | Windows Server 2025 Datacenter Evaluation | | SQL Server tested | SQL Server 2025 Express | | Instance | `SQLEXPRESS` | | Original lab test | 2026-05-26 | | Comparison re-verified | 2026-09-01 | | Tester | Serdar Tekin | We did **not** benchmark Standard against Enterprise on Raff for this article. The edition limits, licensing differences, availability features, and supported upgrade paths are based on Microsoft's current SQL Server 2025 documentation. That distinction matters: this article is an edition decision guide, not a performance benchmark claiming that one edition was faster in our lab. --- ## Standard or Enterprise? Decision checklist | Requirement | Best starting point | |---|---| | Normal SMB production database | Standard | | ERP, accounting, or LOB backend | Standard | | SQL Server Agent and production maintenance | Standard | | Up to 32 cores and 256 GB buffer pool | Standard | | Resource Governor is the only concern | Standard in SQL Server 2025 | | Simple two-replica, single-database HA | Evaluate Standard Basic AG | | Full Always On Availability Groups | Enterprise | | More than 32 cores per instance | Enterprise | | More than 256 GB buffer pool | Enterprise | | More than 32 GB memory-optimized data per database | Enterprise | | Large multi-node FCI design | Enterprise | | No clear Enterprise-only requirement | Standard | If you cannot identify the row that forces Enterprise, Standard is usually the safer place to start. --- ## What Raff recommends For most SQL Server workloads running on a Windows VPS, Raff recommends **Standard as the default paid edition**. Choose Enterprise only when the architecture has a documented requirement for Enterprise-only HA, scale, memory, or another specific feature. Also separate the **SQL Server edition decision** from the **Windows VPS sizing decision**. A Standard deployment can still need more vCPU, RAM, faster storage, or a better disk layout. Likewise, an Enterprise license does not compensate for an undersized or badly configured server. If you are planning a SQL Server deployment, [deploy a Raff Windows VPS](/products/windows-vm) sized for the workload, then pair the edition choice with the right memory, backup, storage, and HA plan. --- ## Tested on > Edition/version query workflow originally tested on Raff Windows VPS, Windows Server 2025 Datacenter Evaluation, SQL Server 2025 Express, 2026-05-26. Standard vs Enterprise limits, licensing, pricing, availability features, and upgrade support re-verified against Microsoft SQL Server 2025 documentation on 2026-09-01. Tester: Serdar Tekin. --- ## What's next - [SQL Server 2025 licensing](/windows-server/sql-server-2025-licensing-guide) — review the licensing model before choosing Standard or Enterprise. - [Install SQL Server 2025 on a Windows VPS](/windows-server/install-sql-server-2025-windows-server-vps) - install and prepare SQL Server - [MSSQL Backup Strategy on a Windows VPS](/windows-server/mssql-backup-strategy) - build full, differential, and log backup routines - [MSSQL Memory Tuning on a Windows VPS](/windows-server/mssql-memory-tuning) - configure max server memory safely - [Configure Windows Firewall on a Windows VPS](/windows-server/configure-windows-firewall) - review inbound rules for SQL Server, RDP, and IIS - [SQL Server hosting](/products/sql-server-hosting) - deploy Windows Server for SQL Server, IIS, business apps, and remote administration --- ## Sources - Microsoft Learn - SQL Server 2025 editions and supported features: https://learn.microsoft.com/en-us/sql/sql-server/editions-and-components-of-sql-server-2025 - Microsoft Learn - What's new in SQL Server 2025: https://learn.microsoft.com/en-us/sql/sql-server/what-s-new-in-sql-server-2025 - Microsoft Learn - Supported edition upgrades for SQL Server 2025: https://learn.microsoft.com/en-us/sql/database-engine/install-windows/supported-version-and-edition-upgrades-2025 - Microsoft - SQL Server licensing guidance: https://www.microsoft.com/licensing/guidance/SQL - Microsoft - SQL Server 2025 licensing guide: https://aka.ms/sqlserver2025licensingguide - Microsoft - SQL Server pricing: https://www.microsoft.com/en-us/sql-server/sql-server-pricing *Date last verified: 2026-09-01* --- ### Multi-User RDP: 2 Admin Sessions vs RDS Session Host URL: https://rafftechnologies.com/windows-server/multi-user-rdp-vs-rds Description: Compare Windows Server’s two administrative RDP connections with Remote Desktop Services Session Host for multi-user desktops, including licensing, roles, security, workgroup limits, and when SMB teams should use each model. Remote Desktop Protocol (RDP) is the connection protocol. Remote Desktop Services (RDS) is the Windows Server platform for delivering managed multi-user desktops and RemoteApp programs. The practical decision on a Windows VPS is therefore not “RDP or RDS” in the abstract. It is **Remote Desktop for Administration versus an RD Session Host deployment for end users**. Microsoft documents two concurrent remote connections for Windows Server administration without RDS CALs. Those connections are for administrators maintaining the server. They are not a substitute for licensing a shared desktop used by employees every day. ## In short Use the two built-in administrative RDP connections when one or two administrators occasionally maintain the server. Use **RD Session Host** when employees need their own Windows desktop sessions or RemoteApp access. Customer-owned RDS deployments require the applicable RDS CAL model; Raff-hosted SPLA deployments use RDS SALs for authorized users. A newly created RD Session Host has a 120-day licensing grace period, but that is a deployment window, not a production licensing strategy. ## The decision is administration versus user sessions | Scenario | Two admin RDP connections | RD Session Host | |---|---:|---:| | One administrator maintains Windows Server | Yes | Usually unnecessary | | Two administrators occasionally troubleshoot | Yes | Usually unnecessary | | Three or more employees need separate desktops | No | Yes | | Staff use QuickBooks, ERP, Office apps, or other desktop software daily | No | Yes | | Users access an IIS website from their own devices | Yes, for server admins only | Not required for website users | | Users connect directly to SQL Server from approved clients | Yes, for server admins only | Not required just for database access | | You want RemoteApp publishing | No | Yes | | You need collections and centralized session management | No | Yes | The key question is simple: **are people administering the server, or are people using the server as their workplace?** ## Remote Desktop for Administration has a two-connection limit Microsoft’s current Windows Server troubleshooting guidance states that Remote Desktop supports **two concurrent remote connections for administration** and that those connections do not require RDS CALs. To support more than two administrative connections or multiple end-user sessions, Microsoft directs administrators to install the RD Session Host role and use the appropriate RDS licensing model. That means the built-in two-session model is appropriate for: - server maintenance; - Windows Update checks; - application administration; - Event Viewer and log review; - PowerShell and Server Manager work; - occasional troubleshooting by one or two administrators. It is not intended to become a shared office desktop by creating many local users and rotating them through the same two connection slots. ## The original Raff lab confirmed the two-session behavior The screenshots in this article come from a Raff Windows Server 2025 Datacenter Evaluation lab performed on May 24, 2026. ![PowerShell output showing a Raff Windows VPS running Windows Server 2025 Datacenter Evaluation with build number, CPU count, and memory details.](https://raff-images.s3.raffusercloud.com/01_windows_server_2025_test_environment_ae1e8dac8c.png) | Item | Value | |---|---| | OS | Windows Server 2025 Datacenter Evaluation | | Build | 26100 | | CPU | 4 vCPU | | RAM | Approximately 8 GB | | Test date | 2026-05-24 | | Engineer | Serdar Tekin | The lab verified that two administrative RDP sessions could run concurrently, a third login was blocked until an existing session was disconnected, the main RDS roles were available but not installed on the fresh server, and those roles could be installed for further RDS testing. This August revision keeps that first-hand evidence but does not claim a fresh capacity or licensing benchmark. ## Two active admin sessions do not make the server an RDS host In the lab, two temporary administrator accounts were connected at the same time. ![PowerShell query user output showing two active administrative RDP sessions on a Windows Server VPS.](https://raff-images.s3.raffusercloud.com/05_two_admin_rdp_sessions_active_f22646e8a2.png) That behavior is normal Remote Desktop for Administration. The sessions exist so administrators can manage the operating system. A business should not design its staff workflow around those administrative slots. If users are signing in to run accounting software, ERP clients, Office applications, browser-based business tools, or another desktop application all day, the workload has moved into RDS territory even if only one or two people happen to be connected today. ## The third administrative connection shows the boundary clearly With two administrative sessions already active, the lab attempted another sign-in. ![Windows Remote Desktop warning showing that a third login is blocked because too many users are already signed in.](https://raff-images.s3.raffusercloud.com/06_third_rdp_session_limit_93ec97054f.png) The practical lesson is not “find a way around the limit.” The lesson is that Windows Server separates remote administration from multi-user desktop delivery. Changing a connection-limit Group Policy does not turn the built-in administrative mode into a properly designed RDS deployment. For end users, deploy RD Session Host and license the environment correctly. ## RD Session Host is the Windows Server multi-session role Microsoft defines **RD Session Host (RDSH)** as the RDS role that runs session-based desktops and RemoteApp programs. Multiple users can share one Windows Server while each user receives an isolated session. RDS can also include other roles depending on architecture: | Role | Purpose | |---|---| | RD Session Host | Runs the users’ desktops and RemoteApp programs | | RD Licensing | Issues and tracks RDS CALs in customer-owned CAL deployments | | RD Connection Broker | Reconnects users to sessions and manages collections/load balancing | | RD Gateway | Provides external RDP access over HTTPS rather than exposing internal RDP directly | | RD Web Access | Publishes desktops and RemoteApps through a web portal/feed | A very small deployment may use fewer components than a larger RDS farm. Do not assume that every server needs every role on the same VM. ## Terminal server: The old name for RDS Session Host Windows Server 2008 R2 renamed Terminal Services to Remote Desktop Services, and the terminal server role became RD Session Host. The architecture behind both names is identical: one Windows Server running isolated desktop sessions for multiple users over RDP. If a vendor requirement, an old runbook, or a consultant quote says "terminal server," read it as RD Session Host plus the licensing model described in this article. No current version of Windows Server 2019, 2022, or 2025 installs a component called Terminal Server; the name survives only in legacy documentation and search habits. ## A fresh Windows Server VPS is not an RD Session Host by default Before role installation, the Raff lab checked the main RDS components: ```powershell Get-WindowsFeature RDS-RD-Server, RDS-Licensing, RDS-Connection-Broker, RDS-Web-Access | Format-Table Name, DisplayName, InstallState -AutoSize ``` The features were available but not installed. ![PowerShell output showing Remote Desktop Services roles available but not installed on a fresh Windows Server VPS.](https://raff-images.s3.raffusercloud.com/07_rds_roles_available_before_install_e075b056b3.png) This is an important distinction: **RDP being enabled does not mean RDS Session Host has been deployed**. For a production RDS environment, choose the architecture first, then install only the roles required for that architecture using Microsoft’s supported deployment guidance. ## The original lab also verified RDS role installation During the May 2026 lab, the RDS role components were installed and checked after restart. ![PowerShell output showing Remote Desktop Services roles installed after reboot on a Windows Server VPS.](https://raff-images.s3.raffusercloud.com/09_rds_roles_installed_after_restart_8b2ad45d71.png) That screenshot proves the role state on that specific lab VM. It does not by itself prove a production-ready RDS deployment. Production still requires decisions about: - licensing; - user identities and groups; - session collections where applicable; - certificates; - external access architecture; - profile storage; - application multi-session compatibility; - backups; - monitoring; - capacity planning; - security hardening. ## Multi-user RDS must use the correct licensing model The old version of this article treated every Raff RDS environment as a customer RDS CAL deployment. That is too broad. There are two important models. ### Customer-owned Windows Server / BYOL deployment Microsoft’s standard RDS model uses **RDS Client Access Licenses (RDS CALs)**. Each user or device connecting to an RD Session Host running Windows Server needs the applicable RDS CAL. Two CAL modes exist: - **Per User** — assigned to a user identity; - **Per Device** — assigned to a connecting device. For domain-joined RDS deployments, Microsoft permits either Per User or Per Device mode. For **workgroup RDS deployments, Microsoft requires Per Device CALs; Per User CALs are not permitted**. ### Raff-provided SPLA deployment Raff is a Microsoft SPLA partner. In the hosted service-provider model, Microsoft uses **RDS Subscriber Access Licenses (RDS SALs)** rather than asking the customer to supply ordinary RDS CALs for the hosted service. Microsoft’s RDS role guidance states that service providers need enough RDS SALs to cover the authorized unique users that sign in to the hosted service each month. So the high-level distinction is: ```text Customer-owned / BYOL RDS → RDS CAL model Raff-provided SPLA RDS → RDS SAL model ``` For the detailed licensing decision, read [RDS CAL Licensing on Windows Server](/windows-server/rds-cal-licensing-guide) and [Windows Server Licensing on Raff](/windows-server/windows-licensing). ## The 120-day RDS grace period is not a licensing loophole Microsoft currently documents a **120-day licensing grace period** for a newly created RD Session Host. During that technical grace period, a license server is not required for the session host to accept RDS connections. After the grace period, a customer-owned CAL deployment needs a properly activated RD Licensing server, the correct licensing mode, and valid RDS CALs for users or devices to continue connecting. Do not design a production service around resetting or repeatedly relying on the grace period. Microsoft’s current troubleshooting guidance explicitly recommends implementing a license server and license pack rather than treating a grace-period reset as the solution. For Raff-hosted SPLA services, contractual SPLA licensing obligations are separate from the Windows technical grace-period mechanism. The existence of the 120-day Windows grace period does not create 120 days of free commercial licensing rights. ## Workgroup RDS has an important Per Device limitation A small Windows VPS is sometimes deployed as a standalone workgroup server rather than joining Active Directory. Microsoft’s current licensing configuration guidance says: - domain-joined RDS deployments can use Per User or Per Device CALs; - workgroup RDS deployments must use **Per Device** CALs; - Per User CALs are not permitted for the workgroup configuration. Microsoft has also added authentication requirements for workgroup RD Session Hosts communicating with an RD Licensing server after the security update for CVE-2024-38099. Do not weaken that authentication requirement just to make an old configuration work; Microsoft warns that disabling enforcement increases security risk. If a team is growing beyond a very small standalone deployment, identity architecture should be reviewed before adding more RDS users. ## RDS is for users who need desktops or RemoteApp Use RD Session Host when users need to work inside Windows Server itself. A common example is a [QuickBooks Enterprise server](/windows-server/quickbooks-multi-user-windows-server-vps) where several bookkeepers work in one company file through RDS. Common examples include: - QuickBooks Desktop and accounting applications; - ERP and inventory clients; - Microsoft Access or legacy Windows applications; - line-of-business software that must stay close to its data; - RemoteApp publishing; - a standardized shared Windows desktop for branch or remote staff. Microsoft describes RDS as a platform for delivering full desktops and individual RemoteApp programs. RD Session Host is specifically designed for multiple users sharing a Windows Server instance. ## RDS is unnecessary when users consume a server-side service directly Do not deploy RDS simply because many people use something hosted on the server. | User need | Better model | |---|---| | Visit an IIS website | Users connect over HTTPS; admins use ordinary admin RDP | | Connect to SQL Server from an approved client | Use database connectivity; admins use ordinary admin RDP | | Consume an API | Connect to the API endpoint | | Use a shared file service | Use a controlled file-sharing architecture | | Run a scheduled automation | Use Task Scheduler or a service account | | Administrators maintain the VM | Use the two administrative RDP connections | | Employees need Windows desktops/apps | Use RD Session Host | The deciding factor is not the number of people who benefit from the server. It is whether they need interactive Windows sessions on the server. ## A simple decision framework prevents overbuilding ```text Do users need to sign in to the Windows desktop to do their daily work? | |-- No | Run the application/service normally. | Keep RDP for administrators. | |-- Yes Are the connections only occasional server administration by up to two admins? | |-- Yes | Use Remote Desktop for Administration. | |-- No Deploy RD Session Host. Choose the licensing model. Plan identity, security, profiles, backups, and capacity. ``` :::cta Deploy Windows Now Deploy the Windows VM first, then choose admin-only RDP or a properly licensed RDS design based on how users will actually work. ::: ## Capacity planning belongs after the access-model decision Do not decide between admin RDP and RDS based on a CPU/RAM table. First determine the access model, then size the VM for the real applications and number of concurrent users. Microsoft’s current RDS planning guidance recommends sizing around user personas and actual CPU, memory, storage I/O, network, and application behavior. A multi-session server running browser-heavy office work behaves differently from one running accounting software or database reporting. For concrete planning ranges, use [Windows VPS Sizing for Remote Users: 1, 3, 5, 10 Users](/windows-server/windows-vps-sizing-remote-users). That article owns the sizing guidance so this comparison can stay focused on architecture and licensing. ## Security architecture changes when RDS becomes a user service An administrator connecting directly to a server is different from a workforce using the server all day. For internet access to a Session Host, put a [Remote Desktop Gateway](/windows-server/remote-desktop-gateway-vs-direct-rdp) in front of it instead of exposing 3389. For a production RDS environment: - keep Network Level Authentication enabled; - restrict direct RDP exposure where practical; - use Windows Firewall deliberately; - consider RD Gateway for external access rather than exposing internal RDP broadly; - use non-administrator accounts for normal users; - protect administrator accounts separately; - configure auditing and monitoring; - patch Session Hosts and applications on a controlled schedule; - use valid certificates for released RDS services where required; - test application multi-session compatibility. Microsoft describes RD Gateway as a way to provide external RDP access through HTTPS while reducing direct exposure of internal RDP ports. The full security design depends on the size and sensitivity of the environment. For host-level controls, use the [Windows Server Hardening Checklist](/windows-server/windows-server-hardening-checklist). ## RemoteApp can be better than a full desktop If users need only one or two Windows applications, publishing those applications through RemoteApp can be cleaner than giving everyone a complete server desktop. RemoteApp can reduce user confusion and keep the environment closer to an application-delivery model. It does not remove RDS licensing requirements, and the application still needs to support multi-session use. Choose a full desktop when users need several tightly integrated applications, broad file access inside the session, or a traditional remote-workspace experience. Choose RemoteApp when the application itself is the product the user needs. ## Common mistakes blur the admin/RDS boundary ### Treating two admin sessions as two employee licenses The two built-in connections are for server administration. They are not a general-purpose two-user office desktop entitlement. ### Trying to bypass the two-session limit with Group Policy Changing connection limits does not replace RD Session Host or licensing. If users need multi-session desktops, build RDS correctly. ### Saying every Raff RDS user needs a customer RDS CAL That ignores SPLA. Customer-owned deployments use the applicable CAL model; Raff-provided hosted licensing uses the applicable SPLA SAL model. ### Buying Per User CALs for a workgroup deployment Microsoft does not permit Per User CAL mode for workgroup RDS. Use Per Device or redesign the identity model. ### Treating the 120-day grace period as production licensing The grace period exists to allow deployment and configuration. Plan valid licensing before it expires and before relying on the server for business-critical access. ### Installing every RDS role on one server by default Small and large RDS deployments have different architecture needs. Install the roles the design requires rather than copying a role list from a lab. ### Sizing from user count alone A five-user ERP server and a five-user light-office server can need very different resources. Measure the actual workload. ## Raff’s recommendation starts with the user workflow For a Windows VM that mainly runs IIS, SQL Server, APIs, automation, or another server-side workload, keep RDP as an administrative tool. One or two administrators can maintain the VM without turning it into an RDS environment. If employees need to sign in every day and run Windows applications inside the server, treat the project as RDS from the start. Plan the licensing model, user identities, external access, application compatibility, capacity, backups, and security before onboarding staff. For Raff-hosted licensing, confirm whether the workload will use Raff’s SPLA model. For customer-owned licensing, confirm the customer’s CAL and Windows Server rights separately. ## What's next - [Remote Desktop Services configuration](/windows-server/remote-desktop-services-configuration) — use the deployment guide after deciding that RDS Session Host is the right model. - [RDS CAL Licensing on Windows Server](/windows-server/rds-cal-licensing-guide) - [Windows Server Licensing on Raff](/windows-server/windows-licensing) - [Windows VPS Sizing for Remote Users](/windows-server/windows-vps-sizing-remote-users) - [Windows Server Hardening Checklist](/windows-server/windows-server-hardening-checklist) - [RDP Performance Tuning for Smooth Remote Desktop](/windows-server/rdp-performance-tuning) - [Remote Desktop VPS](/products/remote-desktop-vps) ## Sources - Microsoft Learn — [Troubleshoot Remote Desktop disconnected errors](https://learn.microsoft.com/en-us/troubleshoot/windows-server/remote/troubleshoot-remote-desktop-disconnected-errors) - Microsoft Learn — [Remote Desktop Services overview](https://learn.microsoft.com/en-us/windows-server/remote/remote-desktop-services/overview) - Microsoft Learn — [Remote Desktop Services roles](https://learn.microsoft.com/en-us/windows-server/remote/remote-desktop-services/rds-roles) - Microsoft Learn — [License Remote Desktop Services with Client Access Licenses](https://learn.microsoft.com/en-us/windows-server/remote/remote-desktop-services/rds-client-access-license) - Microsoft Learn — [License Remote Desktop session hosts](https://learn.microsoft.com/en-us/windows-server/remote/remote-desktop-services/rds-license-session-hosts) - Microsoft Learn — [RDS licensing troubleshooting guidance](https://learn.microsoft.com/en-us/troubleshoot/windows-server/remote/troubleshoot-rds-licensing-guidance) - Microsoft Learn — [Remote Desktop Services access from anywhere](https://learn.microsoft.com/en-us/windows-server/remote/remote-desktop-services/rds-plan-access-from-anywhere) - Sources verified: 2026-08-08 --- ### ERP Hosting on Windows VPS: Sizing, RDS & Migration (2026) URL: https://rafftechnologies.com/windows-server/erp-on-vps Description: Plan ERP hosting on a Windows VPS for small and mid-sized businesses. Compare architectures, size CPU and RAM, plan RDS and SQL Server, secure remote access, protect backups, and migrate with rollback. ## In short **ERP hosting on a Windows VPS** is a strong fit when a small or mid-sized business runs Windows-based ERP software and wants one centralized environment for the application, database, files, and remote users. It works best when the ERP vendor supports Windows Server or RDS, the server is sized for concurrent workload rather than employee count, and the migration includes licensing, backup, security, printer, integration, and rollback testing. For Raff Technologies customers, the simplest architecture is often one Windows VM for a small workload, then separate the application/RDS tier from SQL Server when database pressure, user count, availability requirements, or maintenance complexity justify it. Do not move an ERP system to a VPS only because it is called cloud hosting. First confirm four things: 1. the ERP vendor supports the target Windows Server and hosted model; 2. the user access model is clear, including RDS licensing where needed; 3. the database and storage design meet the workload and recovery targets; 4. the business has a tested migration and rollback plan. If those four conditions are met, a Windows VPS can replace aging office hardware while keeping the ERP architecture familiar. ## ERP hosting on Windows VPS: quick decision | Situation | Recommended starting point | |---|---| | 1 to 5 light ERP users | Single Windows VM after vendor sizing check | | Small SQL-backed ERP | Single Windows VM can work, but reserve memory for SQL and Windows | | Several users need full desktop or RemoteApp sessions | Plan RD Session Host and the correct licensing model | | Database workload is becoming the bottleneck | Separate app/RDS and SQL Server roles | | Heavy reporting, integrations, or batch jobs | Consider separate database or worker roles | | Multiple offices need the same ERP system | Central Windows environment with controlled remote access | | ERP is already a supported SaaS service | A Windows VPS may not be necessary | | Vendor requires dedicated hardware or a specific hosting model | Follow the vendor requirement instead of forcing a VPS design | The broad rule is: ```text Windows ERP + centralized users + supported server deployment -> Windows VPS can be a good fit SaaS ERP, unsupported hosting, or hardware-specific requirements -> Keep the supported vendor model ``` ## What ERP hosting actually moves to the cloud ERP hosting is more than copying an application folder to another server. A production ERP environment can include: - Windows Server; - the ERP application or application service; - SQL Server or another database; - shared documents and attachments; - reporting engines; - scheduled tasks; - integration services; - printers and label workflows; - RDP or RDS user sessions; - identity and permissions; - backups and restore procedures; - monitoring and alerting. ![ERP hosting architecture on a Windows VPS showing remote users connecting through RDP or RDS to an ERP application, SQL database, shared files, backups, and monitoring.](https://raff-images.s3.raffusercloud.com/erp_windows_vps_hosting_architecture_png_27e88211f2.png) A successful migration keeps those dependencies working together. A server that boots and opens the ERP login screen is not enough proof that the business workflow is ready. ## When Windows VPS is a good ERP hosting fit A Windows VPS is worth considering when the ERP behaves like a traditional Windows business application and the organization wants to move away from local hardware. Typical fit signals include: - the ERP vendor supports Windows Server; - the application is self-hosted rather than SaaS-only; - users work from several offices or remote locations; - the database needs to stay close to the application tier; - the company wants centralized patching, backup, and administration; - the existing office server is reaching hardware or support limits; - an MSP already manages Windows Server workloads for the customer; - the business expects the environment to grow but does not yet need a large multi-server platform. This can apply to accounting, distribution, manufacturing, inventory, CRM/ERP, and other Windows line-of-business applications. Product names alone do not prove compatibility. Check the vendor's current hosting, Windows Server, database, RDS, and licensing requirements before deployment. For warehouse and inventory-specific workflow considerations, see [Windows VPS for ERP and Inventory Software](/windows-server/windows-vps-erp-inventory-software). ## When ERP on a VPS is the wrong answer Do not force a Windows VPS design when the existing product model already solves the problem better. A different approach is usually safer when: - the ERP is already delivered as SaaS and there is no self-hosted requirement; - the vendor does not support third-party hosting; - the software licence restricts hosting or service-provider use; - a hardware dongle or local device dependency cannot be supported remotely; - the application requires a client operating system rather than Windows Server; - the database or user scale exceeds a sensible single-server design; - the workload has availability or compliance requirements that need a broader architecture; - nobody owns Windows patching, database maintenance, backups, monitoring, and incident response. A VPS gives the customer more control, but it also moves more operational responsibility to the customer or MSP. ## Choose the ERP architecture before choosing the VM size Sizing makes more sense after the application architecture is clear. ### Model 1: single Windows VM ```text Users | v Controlled RDP / RDS access | v Windows VM |- ERP application |- SQL Server or other database |- shared files |- scheduled jobs |- local backup staging ``` This is the simplest starting point for a small ERP workload. Application, database, and user sessions all share CPU, RAM, and storage, so monitoring is important. Use it when: - the vendor supports a single-server deployment; - the user count is modest; - the database is small enough to coexist with the application tier; - short maintenance windows are acceptable; - the business wants the least complex supported architecture. ### Model 2: app/RDS server plus database server ```text Users | v App / RDS Windows VM | v Private network | v SQL Server Windows VM ``` Separate the database when SQL Server competes with user sessions or application services for memory, CPU, or storage I/O. This design can also make database maintenance, backup, troubleshooting, and future resizing easier because the application and database no longer share one resource pool. ### Model 3: multi-server ERP environment A larger ERP deployment can separate RDS, application services, database, file storage, integrations, and supporting services. Use a larger architecture only when the workload or availability target justifies it. More servers add more failure paths, patching, licensing, monitoring, and operational work. ## Which Windows Server version should host ERP in 2026? Use the **newest Windows Server version that the ERP vendor and every required component support**. Windows Server 2025 is Microsoft's current LTSC release and has the longest support runway of the current Windows Server generations. That makes it a strong default for a new build when the ERP vendor has validated it. Windows Server 2022 remains a valid supported choice when the application vendor has not yet certified Server 2025 or when an existing deployment standard requires 2022. Do not select an operating system from age alone. Check: - ERP application support; - database version support; - printer and label drivers; - report engines; - ODBC/OLE DB providers; - backup software; - antivirus or EDR; - RMM agents; - integration services; - vendor support policy. For the broader OS decision, use [Windows Server 2019 vs 2022 vs 2025](/windows-server/windows-server-version-comparison). ## Multi-user ERP access: admin RDP is not the same as RDS One of the most common ERP hosting mistakes is treating Windows Server's administrative Remote Desktop access as a staff desktop platform. If employees need to sign in to Windows Server and run the ERP application every day, the project is usually an **RDS Session Host** workload rather than ordinary administrator RDP. Windows Server RDS can provide: - multi-session desktops; - RemoteApp delivery; - session policies; - centralized application access; - RD Gateway for controlled external access; - licensing and session-management roles. See [Multi-User RDP vs RDS Session Host](/windows-server/multi-user-rdp-vs-rds) before onboarding users. ## RDS licensing depends on who supplies the Microsoft licence Do not use one CAL statement for every hosted ERP environment. ### Customer-owned / BYOL RDS A customer-owned Windows Server deployment uses the applicable Microsoft RDS CAL model. Microsoft provides **Per User** and **Per Device** RDS CALs. Workgroup RDS deployments require Per Device CALs; Per User CALs are not permitted in that workgroup configuration. ### Raff-provided hosted licensing Raff is a Microsoft SPLA partner. Under the Raff-hosted service-provider model, hosted RDS access uses the applicable **RDS User SAL** model rather than customer-owned RDS CALs. The high-level split is: ```text Customer-owned / eligible BYOL deployment -> applicable Windows Server + RDS CAL model Raff-provided SPLA deployment -> hosted Windows Server licensing + RDS User SALs when RDS is used ``` Licensing changes by deployment model and Microsoft agreement, so use [Windows Server Licensing on Raff](/windows-server/windows-licensing) and the [RDS Licensing Guide](/windows-server/rds-cal-licensing-guide) for the current rules and pricing. ## ERP server sizing should follow concurrent workload Do not size an ERP server only by employee count. Two companies with ten employees can have completely different resource requirements. Measure or estimate: - peak concurrent ERP users; - whether users run full RDS desktops or only an ERP client; - database size and active working set; - report complexity; - batch/import jobs; - integrations; - document and attachment volume; - antivirus/EDR overhead; - backup windows; - expected growth; - whether SQL Server shares the same VM. Use the following only as **planning examples**, not guarantees: | Workload | Planning starting point | What can push it higher | |---|---|---| | 1 to 3 light users | 2 to 4 vCPU / 4 to 8 GB RAM | SQL Server, browser-heavy sessions, reporting | | 5 to 10 active ERP users | 4 to 8 vCPU / 16 to 32 GB RAM | RDS sessions, SQL memory, reports, integrations | | 10 to 25 users | 8 to 16 vCPU / 32 to 64 GB RAM | Heavy SQL, printing, reporting, concurrent jobs | | SQL-heavy ERP | Size database tier separately | Working set, query CPU, TempDB and storage latency | | Heavy reporting or batch work | Consider separate worker/reporting role | Long-running reports and imports | The safest approach is to start from the ERP vendor's supported requirements, then validate the server under the real peak workload. After deployment, use [Windows Server Performance Monitoring](/windows-server/windows-server-performance-monitoring) to identify whether CPU, memory, disk, network, or a specific process is the actual bottleneck. ## SQL Server can determine the real ERP server size Many Windows ERP products rely on SQL Server. In those environments, database design can matter more than the ERP application's own executable. Review: - SQL Server edition and licence model; - `max server memory`; - database size and growth; - data and log file layout; - TempDB configuration; - query and index health; - backup duration; - recovery model; - transaction log backup cadence where applicable; - restore time; - storage latency during peak work. If SQL Server and RDS users share the same VM, reserve enough RAM for Windows and user sessions rather than allowing SQL Server to consume nearly all available memory. Continue with [SQL Server Max Server Memory](/windows-server/mssql-memory-tuning) and [SQL Server Backup Strategy](/windows-server/mssql-backup-strategy) for the database layer. ## Storage planning includes more than the database file ERP storage can grow through: - database data files; - transaction logs; - invoices and attachments; - PDFs and report exports; - scanned documents; - integration files; - temporary files; - Windows updates; - local backup staging; - audit and application logs. Plan enough free space for normal growth and recovery operations. A database restore or migration may temporarily need significantly more space than the live database itself. Raff Windows VMs use NVMe-backed storage, but storage technology does not remove the need to measure I/O behavior. A poorly behaving query, large report, backup job, or shared workload can still create disk pressure. ## Backups must protect both the ERP and the database A VM snapshot is useful before a risky change, but it is not automatically a complete ERP recovery plan. A production design can include: 1. **database-aware backups** for SQL Server or the ERP's database engine; 2. **file/application backups** for attachments, configuration, exports, and required application data; 3. **VM-level protection** for infrastructure recovery; 4. **off-server copies** outside the live VM; 5. **restore testing** that proves the ERP actually works after recovery. Define an RPO and RTO before setting the backup schedule: - **RPO**: how much recent data can the business lose? - **RTO**: how long can the ERP remain unavailable? Then test whether the backup chain can meet those targets. The restore drill should include more than restoring a `.bak` file. Confirm user login, reports, integrations, file paths, scheduled jobs, and application connectivity after recovery. ## Secure remote ERP access deliberately Do not expose every internal service just to make the ERP reachable. For a Windows Server/RDS environment: - keep named administrator and user accounts separate; - apply least privilege; - keep Windows Firewall enabled; - avoid exposing SQL Server directly to the public internet; - restrict direct administrative RDP by source where practical; - use [Remote Desktop Gateway](/windows-server/remote-desktop-gateway-vs-direct-rdp), VPN, or another controlled access model for persistent remote-user access; - patch Windows and the ERP stack deliberately; - monitor failed authentication attempts; - protect backup credentials separately from normal application accounts; - maintain a documented offboarding process. Use the [Windows Server Hardening Checklist](/windows-server/windows-server-hardening-checklist) before production rollout. ## Printers, scanners, labels, and local devices can decide migration success ERP migrations often fail in the last 10 percent because the server and database work but operational devices do not. Test the workflows the business actually uses: - invoice printing; - label printers; - barcode workflows; - PDF printers; - scanners; - shared network printers; - redirected printers through RDS; - paper sizes and trays; - check printing where applicable; - local drive or clipboard redirection if required; - vendor-specific drivers. Do not assume a device is compatible because Windows can see it locally. Validate the full remote workflow before cutover. The dedicated [ERP and Inventory Software on Windows VPS](/windows-server/windows-vps-erp-inventory-software) guide covers more of these operational workflow questions. ## ERP migration should be side-by-side when possible A safer migration builds and tests the destination before the source is retired. ![ERP migration checklist showing the process from auditing the current ERP system to building the Windows VPS, migrating data, testing workflows, cutting over, and monitoring backups.](https://raff-images.s3.raffusercloud.com/erp_vps_migration_checklist_png_bda03abe9b.png) A practical sequence is: ```text Inventory current ERP environment -> confirm vendor support and licensing -> build target Windows VM -> install application and database prerequisites -> configure RDS and secure access if required -> restore a test copy of the data -> test real business workflows -> test backups and restore -> schedule cutover -> stop writes on old system -> take final backup / sync -> restore or migrate final data -> validate users and integrations -> keep rollback until production is proven ``` Before migration, inventory: - ERP and database versions; - licences and activation method; - users and groups; - current server specs; - database size; - file/attachment storage; - printers and scanners; - scheduled tasks; - integration endpoints; - mapped drives and UNC paths; - DNS names; - certificates; - service accounts; - firewall rules; - backup and restore procedures. If the ERP uses SQL Server, a database backup/restore or vendor-supported migration method is usually safer than treating the database files like ordinary documents. Use the [Server Migration Checklist](/windows-server/windows-server-migration-checklist-small-business), [Local Server to Cloud Windows VPS Migration](/windows-server/local-server-to-cloud-windows-vps-migration), and [SQL Server Migration to Windows VPS](/windows-server/sql-server-migration-to-windows-vps) where they apply. ## Cutover needs a business validation checklist Before reopening the system to all users, verify: | Area | Validation | |---|---| | Users | Required users can sign in with the correct permissions | | ERP | Application opens and reaches the correct production database | | Data | Record counts or vendor checks match the expected final state | | Reports | Critical reports render and export correctly | | Printing | Invoice, label, PDF, and required device workflows work | | Integrations | Scheduled jobs, APIs, imports, exports, and file drops work | | Database | Backup job and monitoring are active | | Security | Firewall and remote-access rules match the intended design | | Recovery | A recent backup exists outside the live server | | Performance | Peak user workflow is responsive enough for production | | Rollback | Old environment remains available until sign-off | Do not judge success from a single administrator login. ## How Raff fits ERP hosting Raff provides Windows VMs for customers and MSPs that want to run supported Windows business software without owning the underlying physical server. ![Raff dashboard showing a Windows VPS creation screen for deploying a cloud server suitable for ERP hosting.](https://raff-images.s3.raffusercloud.com/raff_windows_vps_create_erp_server_d9af040ef1.png) A small ERP environment can start with one VM, then expand to separate application/RDS and database VMs over private networking when the workload requires it. Raff can be a fit when you need: - Windows Server with administrator access; - RDP or a self-managed RDS architecture; - private networking between application and database VMs; - NVMe-backed storage; - backup and snapshot options; - a migration target for an existing office Windows Server; - a platform an MSP can operate for client workloads. Raff does not determine whether a third-party ERP vendor permits hosting, multi-user RDS, or a specific Windows Server version. Confirm those rights with the software vendor before production deployment. :::cta Talk to Windows Engineer Review your ERP version, users, database, RDS model, storage, backups, migration path, and current server before choosing the Windows VM architecture. ::: ## Common ERP hosting mistakes ### Choosing the VM before understanding the ERP architecture CPU and RAM numbers are not useful if the application requires separate database, integration, or RDS components. ### Treating administrative RDP as employee access If staff use the server as their daily workspace, plan RDS properly instead of relying on administrative sessions. ### Using one licensing rule for every hosted server Customer-owned CAL deployments and Raff-hosted SPLA deployments use different Microsoft licensing models. ### Picking Server 2022 or 2025 without vendor confirmation Use vendor support as the deciding factor. Server 2025 provides a longer Microsoft support runway, but compatibility still controls the application decision. ### Sizing only by user count Concurrent reporting, SQL Server memory, integrations, backup jobs, and RDS applications can matter more than total headcount. ### Keeping all backups on the ERP VM A backup stored only on the production server shares the same failure boundary. Keep a recovery copy elsewhere and test it. ### Skipping printer and integration tests A migration can look successful to IT while accounting or warehouse users cannot complete daily work. ### Migrating without rollback Keep the old environment available until the new ERP server has passed business validation and recovery checks. ## ERP hosting checklist Before production, confirm: ```text ERP vendor supports hosted Windows Server Windows Server version validated Database version validated User concurrency measured RDS access model selected Microsoft licensing path confirmed VM sizing reviewed Database memory/storage reviewed Private/public ports documented RD Gateway/VPN decision made Backup schedule configured Off-server recovery copy available Restore test completed Printers/devices tested Integrations tested Cutover plan approved Rollback path retained Monitoring active ``` :::cta Deploy Windows Now If the ERP vendor supports a Windows Server deployment, compare Raff Windows VM options after you have defined the user, database, storage, and RDS requirements. ::: ## Validation scope This September 2026 refresh revalidated the Windows Server lifecycle and current Microsoft RDS licensing model against Microsoft documentation. It also aligns Raff-hosted RDS wording with Raff's current SPLA licensing guide. The existing diagrams and Raff dashboard image were preserved from the previous article. This refresh does **not** claim a new end-to-end ERP application benchmark, a new vendor certification test, or a fresh ERP migration lab on Raff. ERP compatibility and licensing must be confirmed with the relevant software vendor for the customer's exact version and deployment model. ## What's next - [Windows VPS for business software](/windows-server/windows-vps-for-business-software) — use the broader business-software guide when comparing ERP with other Windows application workloads. - [Raff Windows VM](/products/windows-vm) - review the Windows VM product after sizing the workload. - [Raff Pricing](/pricing) - check current compute and licensing pricing. - [Windows VPS for ERP and Inventory Software](/windows-server/windows-vps-erp-inventory-software) - focus on inventory, warehouse, printer, and branch workflows. - [Multi-User RDP vs RDS Session Host](/windows-server/multi-user-rdp-vs-rds) - choose the correct user-access model. - [Windows Server Licensing](/windows-server/windows-licensing) - compare SPLA and eligible BYOL paths. - [SQL Server Max Server Memory](/windows-server/mssql-memory-tuning) - prevent SQL Server from starving Windows or RDS users. - [SQL Server Backup Strategy](/windows-server/mssql-backup-strategy) - design database recovery around RPO and RTO. - [Server Migration Checklist](/windows-server/windows-server-migration-checklist-small-business) - plan cutover and rollback. - [Windows Server Hardening Checklist](/windows-server/windows-server-hardening-checklist) - secure the server before production. ## Sources - Microsoft Learn - Windows Server 2025 lifecycle: https://learn.microsoft.com/en-us/lifecycle/products/windows-server-2025 - Microsoft Learn - Windows Server release information: https://learn.microsoft.com/en-us/windows/release-health/windows-server-release-info - Microsoft Learn - Remote Desktop Services overview: https://learn.microsoft.com/en-us/windows-server/remote/remote-desktop-services/overview - Microsoft Learn - RDS Client Access Licenses: https://learn.microsoft.com/en-us/windows-server/remote/remote-desktop-services/rds-client-access-license - Microsoft Learn - License Remote Desktop session hosts: https://learn.microsoft.com/en-us/windows-server/remote/remote-desktop-services/rds-license-session-hosts - Microsoft Learn - RDS payment/licensing models: https://learn.microsoft.com/en-us/windows-server/remote/remote-desktop-services/rds-plan-choose-how-you-pay - Sources revalidated: 2026-09-11 --- ### How to Keep Legacy Windows Business Applications Running in the Cloud URL: https://rafftechnologies.com/windows-server/keep-legacy-windows-business-applications-running-cloud Description: A practical decision guide for businesses that still depend on older Windows software. Learn how to assess compatibility, licensing, databases, remote access, migration risk, and whether a cloud Windows server is the right next step. A business application does not become useless simply because it is old. Many companies still depend on Windows software that handles accounting, inventory, estimating, scheduling, customer records, reporting, or internal workflows. The application may work well, employees may understand it, and replacing it may create more risk than value. The real problem is often the aging office server, limited remote access, weak backup process, or growing maintenance burden around the software. Raff Technologies helps businesses run suitable Windows workloads on cloud virtual machines, giving teams a centralized environment for applications, files, remote access, backups, and day-to-day administration. However, moving legacy software is not a simple copy-and-paste exercise. Compatibility, licensing, databases, peripherals, security, and recovery must be assessed before migration. This guide explains when keeping a legacy Windows application in the cloud makes sense, what must be tested, and when replacing the software is the better decision. ## Legacy software is often not the real problem The word *legacy* can describe very different situations. An application may be considered legacy because: - The vendor no longer develops it actively. - It requires an older Windows version or .NET component. - It uses a local database or shared network folder. - It was built specifically for one company. - It has no browser-based or SaaS version. - It depends on a physical license key, printer, scanner, or serial device. - The original developer is no longer available. - The software still works, but the server hosting it is reaching end of life. These conditions do not automatically mean the application must be replaced. The business question is whether the software remains dependable, supportable, secure, and valuable enough to justify preserving. For many small businesses, the application is familiar and deeply connected to daily operations. Replacing it may require data cleanup, workflow redesign, employee training, integrations, and months of disruption. In that situation, moving the existing application to a controlled Windows cloud environment can provide more time to plan a future replacement without forcing an emergency migration. ## When keeping a legacy Windows application makes sense Keeping the application is usually reasonable when it still performs an important business function and the surrounding risks can be controlled. ### The application still supports the workflow Some older applications remain effective because they were designed around a specific process. A custom estimating tool, internal order system, Access-based workflow, or desktop ERP may fit the business better than a modern generic platform. The key question is not whether the interface looks old. It is whether the application continues to produce accurate results, supports current operations, and can be maintained safely. ### Replacing it would create major disruption A software replacement may affect: - Historical data - Reports and templates - Employee responsibilities - Customer-facing processes - Accounting or inventory workflows - Integrations with other systems - Compliance and retention requirements If the business cannot replace everything at once, moving the application from fragile hardware to a cloud Windows server can become an interim modernization step. ### The main risk is the office server Sometimes the software is stable, but the infrastructure is not. Common warning signs include: - The server is several years old. - Hardware support has expired. - Remote work depends on an unreliable VPN. - Backups have never been restored in a test. - Application files are spread across employee computers. - Only one person understands the server. - A hardware failure could stop the business. In this case, the priority is to reduce the infrastructure risk around the application. Our guide to [signs you have outgrown your office server](/windows-server/replace-office-server-small-business) covers these warning signs in more detail. ### The vendor permits hosted or remote use The software license must allow installation in a virtual or hosted environment. Some vendors license by user, device, server, processor, company, database, or physical machine. Others restrict hosting by third parties or require a specific licensing agreement. Always confirm the vendor's current terms before migration. Technical compatibility does not override a licensing restriction. :::cta Explore Windows VM Run suitable Windows workloads on reliable US cloud infrastructure. ::: ## When replacing the application is the better decision Cloud infrastructure can extend the useful life of a legacy application, but it cannot solve every underlying problem. Replacement should be considered when: - The software depends on an unsupported operating system. - Security updates are no longer available. - The vendor has ended support and no internal expertise remains. - The database is frequently corrupt or unstable. - The application cannot support current user or reporting requirements. - Critical integrations no longer work. - The license does not permit virtualization or hosting. - The application requires unavailable physical hardware. - The cost of keeping it running is higher than replacing it. - The business cannot recover the application from backup. An important distinction is whether the business is preserving a useful application or merely postponing an unavoidable failure. A cloud Windows server is a strong option when it removes hardware dependence and improves access, recovery, and administration. It is not a substitute for supported software, valid licensing, or a long-term application strategy. ## Start with an application dependency inventory Before selecting a server or planning a cutover, document everything the application needs. ![Cloud readiness assessment for a legacy Windows application covering compatibility, licensing, database, peripherals, remote access, and migration suitability](https://raff-images.s3.raffusercloud.com/legacy_windows_application_cloud_readiness_check_webp_f1e035ae12.png) A useful inventory should include: | Dependency | Questions to answer | |---|---| | Operating system | Which Windows versions are supported? Does it require Desktop Experience? | | Application version | What exact version and build are installed? Is installation media available? | | Runtime components | Does it require a specific .NET Framework, Java version, Visual C++ runtime, ODBC driver, or COM component? | | Database | Does it use SQL Server, SQL Server Express, Access, Firebird, MySQL, PostgreSQL, SQLite, or proprietary files? | | File locations | Where are program files, data files, exports, templates, attachments, and reports stored? | | User access | Is it single-user, multi-user, client-server, or Remote Desktop based? | | Licensing | Is the license tied to a server name, MAC address, disk, USB key, user, or activation portal? | | Devices | Does it depend on printers, scanners, label printers, card readers, serial ports, or USB devices? | | Integrations | Does it exchange data with accounting, email, payment, CRM, warehouse, or reporting systems? | | Scheduled tasks | Are exports, imports, reports, backups, or data-sync jobs automated? | | Security | Which service accounts, local users, permissions, firewall rules, and shared folders are required? | | Recovery | Is there a verified application-level backup and a documented restore procedure? | Do not rely only on the application's installation folder. Many older systems store important components elsewhere, including the registry, Windows services, shared folders, database instances, scheduled tasks, user profiles, and system directories. A dependency inventory also helps reveal whether the migration is straightforward or whether specialist vendor involvement is required. ## Confirm Windows Server compatibility before migration The destination operating system must support the application and all required components. Microsoft identifies application compatibility as a major consideration for Windows Server deployments and tests a range of Microsoft and third-party software. However, broad Windows Server compatibility does not guarantee that a specific older application will run correctly. The software vendor's support statement and your own testing remain essential. Before migration, confirm: - Supported Windows Server editions and versions - 32-bit or 64-bit requirements - Required .NET Framework versions - Database engine compatibility - Required Windows features and roles - Whether the application needs a graphical desktop - Whether services can run under modern security policies - Whether the installer still works - Whether antivirus or endpoint protection interferes with the application ### Avoid assuming that compatibility mode is enough Windows compatibility settings can help with some older desktop applications, but they should not be treated as a migration plan. An application may launch successfully and still fail during printing, exporting, reporting, database access, or multi-user activity. Testing must cover the complete business workflow rather than only opening the program. ### Check vendor support separately from technical operation An application may technically run on a newer Windows Server version while remaining unsupported by the vendor. That distinction matters when the business depends on vendor assistance, regulated records, or critical operations. Document the decision clearly if the application will operate outside its vendor-supported environment. ## Test the application in a separate cloud environment The safest migration starts with a test server that does not affect production. Build the proposed Windows environment, install the application, restore a copy of the data, and validate the full workflow. The test environment should be as close as possible to the planned production configuration. ### Test more than application startup A useful test plan should include: 1. Installation and activation 2. User sign-in and permissions 3. Database connection 4. Opening existing records 5. Creating and editing data 6. Reports and exports 7. Printing and scanning 8. Email integration 9. File attachments and shared folders 10. Scheduled tasks and services 11. Multi-user activity 12. Application backup and restore 13. Sign-out and reconnection behavior 14. Performance during realistic use Representatives from the departments that use the application should participate in testing. An IT administrator may confirm that the application launches, while an experienced employee may immediately notice that an essential report, shortcut, template, or workflow is missing. ### Use a written acceptance checklist Record each tested function, the expected result, the actual result, and the person who approved it. This creates a practical go/no-go decision rather than relying on general impressions. The test also provides early information about CPU, memory, storage, and user-density requirements before the production server is sized. ## Plan remote access and multi-user licensing correctly Many legacy applications were designed to run close to their database and data files. Installing the application on each remote employee's computer and sending data over a public connection can be slow, unreliable, or unsafe. A common cloud model is to run the application and its data on the same Windows environment, then let users access the application through Remote Desktop Services. In this design, processing stays near the data and only the screen, keyboard, and mouse interactions travel between the user and server. Microsoft describes Remote Desktop Services as a platform for centrally delivering managed desktops and applications to users in offices, homes, branches, and partner locations. This centralization can simplify application management and reduce the need to install the software on every endpoint. ### Administrative RDP is not a multi-user deployment Windows Server's administrative Remote Desktop sessions are intended for server administration. They are not a substitute for a properly licensed environment where employees use business applications concurrently. For a business deployment, evaluate: - Remote Desktop Session Host - Remote Desktop Licensing - User or device access model - RDS CAL or service-provider licensing requirements - Session security and timeouts - Profile and printer behavior - Application permissions Microsoft states that each user or device connecting to a Windows Server Remote Desktop Session Host generally needs an appropriate RDS client access license. Service providers may use different licensing models, such as subscriber access licenses, depending on the deployment and agreement. Our guides to [Remote Desktop Server for business](/windows-server/remote-desktop-server-for-business) and [multi-user RDP licensing](/windows-server/multi-user-rdp-admin-sessions-vs-rds-session-host) explain the distinction in more detail. ## Review the database before moving the application The application interface may be the visible part of the system, but the database usually carries the greatest business risk. First identify: - Database engine and version - Database size - Recovery model - Authentication method - Service accounts - Data and log file locations - Maintenance jobs - Backup schedule - Integrity-check process - Required ports and drivers - Vendor-specific migration procedure ### Use database-native backup and restore methods Copying a virtual machine or taking a snapshot does not remove the need for application-consistent database backups. For SQL Server, Microsoft recommends a backup and restore strategy that reflects the database's recovery requirements. The correct process may include full, differential, and transaction-log backups depending on the recovery model and acceptable data-loss window. The migration test should include restoring the database to the destination and confirming that the application can connect, read, write, report, and back up correctly. ### Do not move live database files casually Copying active database files while services are running can produce an unusable or inconsistent copy. Use supported backup, detach/attach, export, replication, or vendor-recommended procedures. For complex SQL Server environments, review our [SQL Server migration to Windows VPS guide](/windows-server/sql-server-migration-to-windows-vps). ## Separate files, application data, and backups Older business applications often combine several types of storage: - Program installation files - Database files - User-uploaded documents - Templates - Report exports - Scanned records - Shared folders - Application backups - System-level backups These should not be treated as one undifferentiated folder. A stronger design defines: - Where the application is installed - Where active business data is stored - Which folders users can access - Which service accounts need permissions - Where application backups are written - How backups leave the production server - How long backups are retained Additional storage volumes may help separate growing data from the operating-system disk. Off-server backup copies reduce dependence on the production VM and its primary storage. If shared files are a major part of the workload, see [Windows VPS cloud file server](/windows-server/windows-vps-cloud-file-server) and [file server migration to Windows VPS](/windows-server/file-server-migration-to-windows-vps). :::cta Explore Data Protection Add backups and recovery planning to your Windows environment. ::: ## Check printers, scanners, USB devices, and local integrations Peripheral dependence is one of the most common reasons a legacy application migration becomes more difficult than expected. Examples include: - Receipt and label printers - Document scanners - Signature pads - Barcode readers - Serial-port devices - USB license dongles - Local accounting printers - Specialized forms - Check-printing hardware - Machine-control equipment Remote Desktop can redirect some local printers and devices, but support depends on the device, driver, application, connection method, and security policy. A device that works on a local office server may not behave the same way through a hosted session. Before migration: 1. List every required device. 2. Record the model and driver version. 3. Confirm whether the vendor supports Remote Desktop use. 4. Test the exact workflow from a normal employee endpoint. 5. Identify a fallback process. Workloads tied to industrial machines, specialized local hardware, low-latency control systems, or unsupported USB devices may be poor candidates for a standard cloud Windows VM. ## Confirm application and Microsoft licensing Licensing should be treated as a separate workstream rather than a final administrative detail. Review: - Windows Server licensing - Remote Desktop licensing - SQL Server licensing - Application licensing - Database user or processor licensing - Microsoft Office or Microsoft 365 application rights - Third-party components - Vendor hosting restrictions - Multi-company or multi-tenant restrictions A license that permits installation on a company-owned office server may not automatically permit installation on third-party cloud infrastructure. Some applications require a hosted edition, updated agreement, or license transfer. Ask the vendor direct questions: - Is installation on a cloud virtual machine permitted? - Is Remote Desktop or multi-user access supported? - Can the license be transferred from the old server? - Is reactivation required after migration? - Is the license tied to hardware identifiers? - Does the vendor support the planned Windows Server version? - Can the vendor assist during cutover? Keep written confirmation with the migration documentation. ## Size the Windows environment around real usage Legacy applications vary widely. A simple file-based application used by three employees may need modest resources. A multi-user ERP with SQL Server, reporting, document storage, and scheduled processes may need considerably more. Size the environment based on: - Concurrent users, not only total employees - CPU use during reports and batch jobs - Memory used by the application and database - Database cache requirements - Storage capacity and growth - Storage latency and I/O activity - User profiles - Antivirus and backup overhead - Remote Desktop session density - Peak business periods ### Start from observed production behavior Collect performance data from the existing server where possible: - CPU utilization during normal and peak periods - Available memory and paging - Disk latency and queue length - Database size and growth - Network usage - Concurrent sessions - Report completion times Do not size only from the old server's hardware label. An aging server may be overprovisioned, underprovisioned, or constrained by slow storage rather than CPU. ### Leave room for migration and growth The new environment should have enough capacity for: - Data-copy operations - Database restore and indexing - Windows updates - Security tools - Backups - Temporary files - User growth A short test under representative load is more reliable than selecting a plan from user count alone. ## Build a migration plan with a rollback path A successful migration has a clear sequence, owner, acceptance test, and fallback plan. ![Five-stage migration framework for moving a legacy Windows business application to the cloud with discovery, testing, preparation, cutover, protection, and rollback](https://raff-images.s3.raffusercloud.com/legacy_windows_application_cloud_migration_framework_webp_cf03365850.png) ### Phase 1: Discovery - Document application and dependencies. - Confirm vendor support and licensing. - Record users, permissions, services, tasks, and integrations. - Measure current resource usage. - Define recovery objectives. ### Phase 2: Test environment - Create the destination Windows VM. - Install required Windows roles and components. - Install the application and database engine. - Restore a copy of production data. - Test business workflows with key employees. - Resolve compatibility and performance issues. ### Phase 3: Migration preparation - Select the maintenance window. - Communicate downtime and responsibilities. - Create verified backups. - Reduce DNS or integration dependencies where relevant. - Prepare user accounts and access controls. - Document the final data synchronization method. - Define rollback criteria. ### Phase 4: Cutover - Stop application changes on the old server. - Take the final application and database backup. - Transfer or restore current data. - Start services on the destination. - Validate permissions and integrations. - Test critical transactions. - Release users in controlled groups. ### Phase 5: Stabilization - Monitor CPU, memory, storage, logs, and sessions. - Confirm scheduled tasks and backups. - Resolve printer and profile issues. - Test a restore. - Keep the old environment isolated but available during the agreed rollback period. - Decommission the old server only after formal approval. Do not destroy or repurpose the source server immediately after cutover. Keep a controlled rollback window, but prevent users from accidentally continuing work in both systems. For a broader planning framework, use our [Windows Server migration checklist for small businesses](/windows-server/windows-server-migration-checklist-small-business). ## Protect the new environment after migration Moving an application to the cloud changes the infrastructure, but it does not automatically secure the workload. The environment should include: - Unique named user accounts - Least-privilege permissions - Multi-factor authentication where supported - Restricted Remote Desktop exposure - Firewall rules limited to required services - Current Windows security updates - Endpoint protection - Database-level access controls - Encryption in transit where applicable - Backup retention outside the production server - Restore testing - Monitoring of failed sign-ins and service errors - Documented administrator access Avoid exposing application database ports directly to the public internet. Where possible, keep the application and database on private interfaces or the same protected environment. Remote access should also be designed around the business risk. Direct RDP exposure with weak credentials is not an acceptable long-term strategy. Consider secure access controls, source restrictions, gateways, or private networking based on the deployment. :::cta Explore Security Review practical protections for your Windows cloud workloads. ::: ## Backups must protect the application, not only the server A virtual machine backup is useful, but recovery planning should cover multiple failure scenarios. | Failure scenario | Required protection | |---|---| | Accidental record deletion | Application or database backup with suitable retention | | Corrupted database | Verified database-native backup and restore procedure | | Failed Windows update | System backup, snapshot, or rollback plan | | Ransomware or credential compromise | Isolated, retained off-server backups | | Deleted VM | Independent backup outside the production instance | | Application misconfiguration | Configuration export and documented settings | | Full regional or provider issue | Business continuity plan and independent data copies where required | Snapshots can be useful before updates or major changes, but they should not be the only backup method. A snapshot tied to the same production environment may not protect against every deletion, account, corruption, or provider-level scenario. The most important backup question is not, “Did the job run?” It is, “Can the business restore the application and resume work within an acceptable period?” Schedule restore tests and document the steps, credentials, dependencies, and expected recovery time. ## Where a Raff Windows VM can fit A Raff Windows VM can provide a centralized cloud environment for suitable legacy Windows applications, databases, shared data, and remote users. Typical use cases include: - Moving an application from aging office hardware - Centralizing a custom Windows business application - Hosting an application and its database near each other - Providing controlled remote access to distributed employees - Separating business workloads from employee PCs - Adding cloud storage, snapshots, and backup processes - Supporting a staged transition before future software replacement Raff provides US-based cloud virtual machines with AMD EPYC processors, DDR5 memory, NVMe SSD storage, and unmetered bandwidth. Businesses can also use supporting platform services such as volumes, private cloud networking, snapshots, backups, and data-protection options according to workload requirements. The exact design depends on the application's compatibility, licensing, user count, database, storage, peripherals, and recovery requirements. Raff cannot make unsupported software supported or override a vendor's licensing terms, so these points must be confirmed before deployment. :::cta Talk to Windows Engineer Discuss your application, users, database, and migration requirements. ::: ## When a standard cloud Windows VM may not be suitable A standard Windows VM may not be the right destination when the application requires: - Unsupported legacy Windows versions - Physical security keys that cannot be redirected - Direct serial, industrial, or machine-control interfaces - Specialized GPU acceleration - Very low-latency local equipment communication - Large-scale high-availability database clusters - Vendor-certified physical hardware - Constant access during unreliable internet connectivity - Licensing that prohibits hosted infrastructure - Regulatory controls beyond the proposed environment These constraints do not always prevent cloud adoption, but they may require specialized infrastructure, application redesign, vendor involvement, or a hybrid architecture. An honest assessment before migration is far less expensive than discovering a critical limitation during cutover. ## A practical decision framework Use the following questions to decide whether to keep, move, or replace the application. ### Keep it on the current server temporarily when: - The server is still supported and stable. - A replacement project is already funded and near completion. - The application cannot be migrated without vendor changes. - A cloud test has not yet been completed. ### Move it to a cloud Windows environment when: - The application remains valuable. - The office server creates operational risk. - Vendor licensing permits hosting. - The application works on a supported Windows Server version. - Remote access and centralized management are priorities. - Database and peripheral requirements have been tested. - A verified backup and rollback plan exists. ### Replace it when: - The application is insecure or unsupported. - Essential business requirements are no longer met. - Migration costs exceed replacement value. - Vendor or internal expertise has disappeared. - Data cannot be recovered reliably. - Critical integrations cannot be maintained. The best choice may also be a staged approach: stabilize the current application in the cloud, reduce infrastructure risk, then replace the software on a deliberate schedule. ## Conclusion: modernize the environment without rushing the application decision Many small businesses do not need to replace a useful Windows application simply because the server beneath it is old. A carefully planned cloud migration can remove dependence on aging hardware, centralize access, improve recovery options, and give the business more control over when and how the application is eventually replaced. The decision should still be evidence-based. Confirm Windows compatibility, vendor support, licensing, database recovery, user access, peripherals, security, and performance in a test environment before production cutover. When the software remains valuable and the infrastructure is the main weakness, moving it to a suitable Windows cloud environment can be a practical next step. When the application itself is the risk, replacement should not be postponed indefinitely. For broader planning, see [Windows VPS for business software](/windows-server/windows-vps-for-business-software) — use the broader business-software guide when deciding how to host legacy Windows applications. ## Sources - Microsoft Learn — [Microsoft server applications compatibility for Windows Server](https://learn.microsoft.com/en-us/windows-server/get-started/application-compatibility) - Microsoft Learn — [Remote Desktop Services overview in Windows Server](https://learn.microsoft.com/en-us/windows-server/remote/remote-desktop-services/overview) - Microsoft Learn — [License Remote Desktop Services with Client Access Licenses](https://learn.microsoft.com/en-us/windows-server/remote/remote-desktop-services/rds-client-access-license) - Microsoft Learn — [Back up and restore of SQL Server databases](https://learn.microsoft.com/en-us/sql/relational-databases/backup-restore/back-up-and-restore-of-sql-server-databases) - Microsoft Learn — [Storage Migration Service overview](https://learn.microsoft.com/en-us/windows-server/storage/storage-migration-service/overview) --- ### QuickBooks Server Hosting on Windows VPS: Multi-User Setup Guide URL: https://rafftechnologies.com/windows-server/quickbooks-multi-user-windows-server-vps Description: Compare QuickBooks server hosting options, understand Intuit's VM support boundary, and configure a QuickBooks Desktop or Enterprise server with RDS, QBDSM, permissions, sizing, and backups. ## In short For a customer-managed QuickBooks server in 2026, use a Windows Server version your QuickBooks Desktop Enterprise release supports, deploy RDS for real multi-user desktop access, and keep the company file close to QuickBooks Database Server Manager. Intuit currently lists Windows Server 2016, 2019, and 2022 for Enterprise, not Server 2025. Intuit also limits support for virtual environments, so Raff should be treated as self-managed Windows infrastructure, not Intuit-authorized QuickBooks hosting. ## Choose the QuickBooks hosting model first “QuickBooks hosting” can mean several different architectures, and the support model is not the same for all of them. | What you need | Better fit | |---|---| | Intuit-authorized hosted QuickBooks Desktop | An Intuit-authorized hosting provider | | Customer-controlled Windows Server for QuickBooks | A self-managed Windows Server environment such as a Raff Windows VM, with Intuit's VM support boundary understood | | Several staff using a shared remote desktop | Windows Server + RDS Session Host + correct RDS licensing + QuickBooks licensing | | A company file shared to LAN users | Supported Windows Server + QBDSM + correct share/NTFS permissions | | No need to maintain Desktop infrastructure | Evaluate QuickBooks Online or Intuit's current hosted offering | Raff provides customer-controlled Windows VM infrastructure. Raff is **not** an Intuit Authorized Hosting Provider and does not provide QuickBooks licensing or Intuit application support. A search for a “QuickBooks dedicated server” does not necessarily mean a dedicated physical machine is required. On Raff, the comparable option is a customer-controlled Windows VM sized for the QuickBooks workload. ## Current Intuit support boundary for Windows Server and VMs Before choosing a VM size, decide whether the production environment must remain inside Intuit's supported hosting model. Current Intuit guidance separates **operating-system compatibility** from **virtual-environment support**: - QuickBooks Desktop Enterprise technical specifications currently list **Windows Server 2016, 2019, and 2022**. - Windows Server 2025 is not currently listed in the Enterprise technical specifications. - Intuit's QuickBooks Desktop 2024 system requirements state that **virtual environments are not supported**. - Intuit's network guidance separately lists virtual servers/virtual machines as **not recommended**. - Intuit says QuickBooks Desktop can run under Terminal Services, but Terminal Services troubleshooting assistance is limited to QuickBooks Desktop Enterprise. - Intuit maintains a separate Authorized Hosting Program for supported third-party QuickBooks Desktop hosting. The practical distinction is important: a Windows Server release can be technically compatible with QuickBooks while a generic VM deployment still falls outside Intuit's supported hosting model. ## Can you run QuickBooks Enterprise on Windows Server? Yes. QuickBooks Desktop Enterprise can use a Windows Server that hosts the company file through QuickBooks Database Server Manager and supports multiple users, subject to the exact QuickBooks release, Windows Server version, licensing, and Intuit support boundary. For a customer-managed deployment in 2026, **Windows Server 2022 is the newest server release currently listed by Intuit**. Treat Windows Server 2025 as unsupported for QuickBooks until Intuit explicitly adds it to the current Enterprise technical specifications. Before production, document: - the exact QuickBooks Desktop edition and release; - active QuickBooks licensing and subscription status; - whether Intuit vendor support is required; - Windows Server version; - RDS / Terminal Services use; - Microsoft 365 or Office integration; - payroll and bank-feed requirements; - third-party add-ons; - printer and PDF workflows; - backup and restore process. ## QuickBooks Desktop server requirements in 2026 Intuit's current Enterprise technical specifications list Windows Server 2016, 2019, and 2022. The same guidance provides server-memory recommendations for multi-user environments. | Concurrent users | Intuit server RAM guidance | |---:|---:| | Up to 5 users | 8 GB | | 10 users | 12 GB | | 15 users | 16 GB | | 20+ users | 20+ GB | Treat those values as vendor guidance for QuickBooks itself, not a complete RDS sizing formula. A shared desktop server also needs headroom for Windows, user sessions, browsers, endpoint protection, Office apps, printing, backup jobs, and any other software running beside QuickBooks. A practical starting range for a self-managed Raff environment is: | Workload | Starting direction | |---|---| | 1–3 light users | 4 vCPU / 8 GB RAM | | Up to 5 business users | 4 vCPU / 8–16 GB RAM | | 6–10 users | 8 vCPU / 16 GB RAM | | 11–15 users | 8 vCPU / 16–32 GB RAM | | 16–20+ users | 8+ vCPU / 32+ GB RAM | | Large company files / heavy reports | Size from monitored workload | These are planning ranges, not performance guarantees. Size from peak concurrent users and the complete desktop workload. For broader planning, see [Windows VPS Sizing for Remote Users](/windows-server/windows-vps-sizing-remote-users). ## Step 1 — Install QuickBooks Desktop Download QuickBooks Desktop from your Intuit account or another official Intuit installer source and run it as Administrator. For an RDP-based lab where users work inside the server, install the QuickBooks application on the server rather than treating the VM only as a remote file share. ![QuickBooks Desktop Enterprise 2024 installer Ready to Install screen on a Raff Server](https://raff-images.s3.raffusercloud.com/medium_raff_qb_ready_to_install_redacted_2026_04_bb172ca66e.png) After installation, reboot if required and confirm QuickBooks opens normally before enabling multi-user hosting. ## Step 2 — Enable Host Multi-User Access Open QuickBooks Desktop and go to: ```text File → Utilities → Host Multi-User Access ``` ![QuickBooks Host Multi-User Access prompt with Yes, No, Help buttons — the step that registers QBDSM](https://raff-images.s3.raffusercloud.com/medium_raff_qb_host_multiuser_prompt_2026_04_e9035f76a1.png) Confirm the prompt. ![QuickBooks confirmation that multi-user hosting is enabled and the folder must now be scanned with QBDSM](https://raff-images.s3.raffusercloud.com/medium_raff_qb_multiuser_setup_confirmation_2026_04_d9f5ae0c1b.png) The QuickBooks database service name is version-specific. For example, the 2024 Raff lab used `QuickBooksDB34`. Check the actual service on your system instead of assuming a service number. ```powershell Get-Service | Where-Object { $_.Name -like "QuickBooksDB*" -or $_.Name -like "*QB*" } | Format-Table Name, Status, StartType -AutoSize ``` ## Step 3 — Document the hosting components Multi-user mode involves more than the menu setting. Document: - QuickBooks version; - QuickBooks database service name; - company-file folder; - QBDSM scan status; - `.ND` network descriptor files; - dynamic port shown by QBDSM; - Windows Firewall rules; - NTFS permissions; - Windows users; - QuickBooks internal users; - backup location. This gives you a troubleshooting baseline before ports or permissions are changed. ## Step 4 — Check QuickBooks Database Server Manager Open **QuickBooks Database Server Manager (QBDSM)** and review the **Port Monitor** tab. ![QBDSM Port Monitor tab showing the dynamic port for QuickBooks 2024 — not the static 55378-55382 range cited elsewhere](https://raff-images.s3.raffusercloud.com/medium_raff_qbdsm_port_monitor_qb2024_2026_04_0dbe5a73cf.png) Use the port shown by your installation. Do not copy a port from an old forum post or a different QuickBooks release. If troubleshooting connectivity, first confirm the database service: ```powershell Get-Service | Where-Object {$_.Name -like "QuickBooksDB*"} ``` Then review QuickBooks-created firewall rules and the QBDSM port shown on the server. ## Step 5 — Create a dedicated company-file folder Use a clear folder rather than storing live company files under Desktop, Downloads, or a personal profile. ```powershell New-Item -ItemType Directory -Path "C:\\QuickBooksCompanyFiles" -Force ``` Keep live `.QBW` files, backup files, and user downloads logically separated. ## Step 6 — Scan the company-file folder with QBDSM In QuickBooks Database Server Manager, open **Scan Folders**. ![QuickBooks Database Server Manager Scan Folders tab empty state before any folder has been added](https://raff-images.s3.raffusercloud.com/medium_raff_qbdsm_scan_folders_empty_2026_04_a640aee05c.png) Add the folder and start the scan. ![QBDSM successful scan on Raff Windows Server with Network Diagnostics Repair successful status confirming multi-user works](https://raff-images.s3.raffusercloud.com/medium_raff_qbdsm_scan_success_2026_04_4b410daf2f.png) A successful scan prepares the folder for multi-user access and can create or update the `.ND` network descriptor next to the company file. ```powershell Get-ChildItem "C:\\QuickBooksCompanyFiles" -Filter "*.ND" ``` Do not publish `.ND` file contents without reviewing them for hostnames or IP information. ## Step 7 — Configure Windows file permissions deliberately Intuit's multi-user hosting documentation requires the Windows user accessing the company file to have appropriate file permissions and describes **Full control** as part of the standard company-file requirements. Do not grant Full Control to `Everyone` or make accounting users local administrators. Use a dedicated group instead. ```text QB-Users QB-Admins ``` Then grant the required company-folder access only to the group that needs it. If your security policy uses tighter permissions than Intuit's documented model, treat that as a tested exception and validate multi-user operation carefully. For users working through RDS on the same server, do not expose SMB to the public internet. ## Step 8 — Give each person a separate Windows account Avoid shared Windows credentials. ```powershell $password = Read-Host "Password for new user" -AsSecureString New-LocalUser -Name "jane.doe" -Password $password -FullName "Jane Doe" ``` For RDS users, grant access through the appropriate Remote Desktop / RDS security groups rather than making users administrators. ## Step 9 — Create separate QuickBooks users Windows users and QuickBooks users are different identities. Inside QuickBooks, create a separate QuickBooks account for each person and assign only the role needed for their accounting work. The cleaner audit model is: ```text One Windows identity + One QuickBooks identity ``` Avoid shared QuickBooks administrator credentials. ## Step 10 — License RDS separately from QuickBooks The two built-in Windows Server administrative RDP sessions are for administration, not for a team using QuickBooks as a daily shared desktop. For real multi-user desktop access, deploy Remote Desktop Services correctly and license the access model separately from QuickBooks. There are two licensing contexts to distinguish: - **Customer-owned Microsoft environments:** use the applicable Microsoft licensing model, including RDS CALs where the customer's agreement permits the deployment. - **Raff-hosted SPLA environments:** Raff provides RDS access through **RDS User SALs at $8 per authorized user per month**. QuickBooks licensing is separate from both. ```text QuickBooks licence / seat ≠ Windows Server licence ≠ RDS CAL or hosted RDS SAL ``` For the detailed decision path, read [Windows Server 2025 RDS CAL licensing](/windows-server/rds-cal-licensing-guide), [Multi-User RDP: 2 Admin Sessions vs RDS Session Host](/windows-server/multi-user-rdp-vs-rds), and [Microsoft SPLA Licensing Explained](/learn/guides/microsoft-spla-hosted-windows-vms). ## Step 11 — Test with real non-admin users Do not validate the deployment only as Administrator. 1. User A signs in through the intended RDP/RDS path. 2. User A opens QuickBooks and the company file. 3. User B signs in separately. 4. User B opens the same company file. 5. Both users perform safe test actions. 6. Confirm reports, printing, and PDF export if those workflows matter. 7. Close and reopen sessions. 8. Reboot the server and repeat the connection test. If a workflow fails, record the exact error, user, time, file path, QBDSM service state, and whether the issue affects one user or everyone. ## Step 12 — Use layered backups A QuickBooks server should have more than one recovery layer. ### QuickBooks-aware backups Use QuickBooks' own backup workflow where appropriate so the company file has an application-level recovery path. ### Server-level recovery Use VM-level backups or snapshots for server recovery and before high-risk changes such as Windows updates, QuickBooks upgrades, RDS changes, or major permission changes. ### Off-server copies Keep recovery copies outside the live VM. A backup stored only on the same server does not protect against deletion, ransomware, or VM loss. Most importantly, test a restore. A successful backup job is not the same as a proven recovery process. ## Common QuickBooks server problems ### H202 usually points to hosting or connectivity Check: - QuickBooks database service state; - QBDSM folder scan; - `.ND` file; - Windows Firewall rules; - company-file path; - permissions. ```powershell Get-Service | Where-Object {$_.Name -like "QuickBooksDB*"} ``` ### Users can open QuickBooks but not the company file Review both Windows file permissions and QuickBooks internal user permissions. Confirm the affected user is opening the intended company file and is not relying on an obsolete shortcut. ### The setup works until reboot Verify the QuickBooks database service and required RDS components return to the expected state after restart. ### A damaged company file is not a QBDSM problem Do not keep changing firewall rules if the file itself is damaged. Restore a known-good QuickBooks backup or use Intuit's supported repair/support path. ## Security controls for a QuickBooks server A QuickBooks company file contains sensitive business and financial data. If real data is present, treat the server as a production accounting system. Use: - individual Windows accounts; - least-privilege administration; - no public SMB exposure; - Windows Firewall enabled; - secure RDP/RDS access; - Windows updates; - endpoint protection; - protected backups; - access reviews when staff change; - logging and monitoring; - restore testing. Do not disable antivirus entirely to solve a QuickBooks problem. If vendor-documented exclusions are required, apply only the specific exclusions needed and review them against your security policy. ## QuickBooks hosting cost: compare the complete model QuickBooks hosting costs depend on the support and management model. An **Intuit-authorized hosting provider** typically packages hosting and management under its own per-user commercial terms. A **customer-managed Windows VM** separates infrastructure, Windows Server licensing, RDS access, QuickBooks licensing, administration, and recovery. For a five-user Raff self-managed example: ```text 4 vCPU / 8 GB / 120 GB VM $40.99 Windows Server Standard SPLA $15.00 5 RDS User SALs (5 x $8) $40.00 ---------------------------------------- Windows + RDS monthly total $95.99 ``` This **$95.99/month** example excludes QuickBooks licensing, backups, extra storage, Microsoft 365 Apps, and other application licensing. If the workload needs more than 8 GB RAM, choose a larger plan rather than forcing the environment into this example size. Use [QuickBooks Hosting on Raff](/products/quickbooks-vps) for workload-specific plan guidance and [Raff Pricing](/pricing) for the current Windows VM ladder. The architecture decision should not be based on infrastructure cost alone. If the accounting workload requires Intuit-authorized hosting or vendor-backed support for the hosted environment, choose that support model first. ## How Raff fits a QuickBooks deployment Raff provides the Windows infrastructure layer: VM compute, storage, networking, remote administration, and platform backup/snapshot capabilities. Raff does **not** provide an Intuit-authorized QuickBooks hosting service, QuickBooks licensing, company-file repair, or Intuit application support. | Requirement | Better path | |---|---| | Intuit-authorized hosted QuickBooks Desktop | Intuit-authorized hosting provider | | Fully managed QuickBooks environment | Managed/authorized QuickBooks hosting service | | Customer-controlled Windows VM for evaluation or a knowingly self-managed deployment | Raff Windows VM, with the Intuit support boundary understood | | New business without a Desktop dependency | Evaluate QuickBooks Online and current Intuit offerings | Raff supports **3,000+ customers** and **15,000+ VMs**, with a **99.9% SLA**. Those infrastructure trust signals do not change Intuit's application-support rules. ## Validation scope The screenshots in this article were captured during an **April 2026 Raff Windows Server 2022 lab** using QuickBooks Desktop Enterprise 2024 trial software. The lab verified installation, Host Multi-User Access, QuickBooks database service registration, QBDSM Port Monitor, folder scanning, `.ND` generation, and company-folder hosting behavior. The exact VM specification for that historical lab is not asserted here because it is not documented strongly enough in the retained evidence to meet Raff's current “Tested on Raff” standard. The screenshots remain valid evidence of the listed workflow only. This is **not** a claim that Intuit supports QuickBooks Desktop on Raff VMs, and it is not a certification of every QuickBooks release, RDS design, add-on, printer workflow, or production environment. ## Production checklist Before using real accounting data, confirm: - Intuit licensing and support path accepted; - exact QuickBooks edition/version documented; - Windows Server version verified against current Intuit requirements; - virtual-environment support limitation understood; - RDS model and Microsoft licensing confirmed; - QBDSM service running; - company folder scanned; - Windows permissions reviewed; - separate Windows and QuickBooks users created; - SMB not exposed publicly; - two-user workflow tested; - printing/PDF/add-ons tested where needed; - backups configured; - off-server recovery copy available; - restore test completed; - support/runbook documented. ## What's next - [Windows VPS for business software](/windows-server/windows-vps-for-business-software) — compare the broader Windows business-software hosting model alongside QuickBooks. - [QuickBooks Hosting on Raff](/products/quickbooks-vps) - [Windows VPS Sizing for Remote Users](/windows-server/windows-vps-sizing-remote-users) - [Multi-User RDP: 2 Admin Sessions vs RDS Session Host](/windows-server/multi-user-rdp-vs-rds) - [Windows Server 2025 RDS CAL Licensing Guide](/windows-server/rds-cal-licensing-guide) - [RDP Performance Tuning](/windows-server/rdp-performance-tuning) - [Windows Server Version Comparison](/windows-server/windows-server-version-comparison) - [Raff Windows VM](/products/windows-vm) - [Raff Pricing](/pricing) ## Sources - Intuit: [QuickBooks Desktop Enterprise technical specs](https://quickbooks.intuit.com/desktop/enterprise/technical-specs/) - Intuit: [Recommended networks for QuickBooks](https://quickbooks.intuit.com/learn-support/en-us/help-article/product-system-requirements/recommended-networks-quickbooks/L3k00H1gQ_US_en_US) - Intuit: [Host company data in multi-user mode](https://quickbooks.intuit.com/learn-support/en-us/help-article/multi-user-mode/hosting-company-data-multi-user-mode-quickbooks/L6vU3qBNE_US_en_US) - Intuit: [Hosting providers authorized by Intuit](https://quickbooks.intuit.com/learn-support/en-us/help-article/product-setup/hosting-providers-authorized-intuit/L3RAbICtq_US_en_US) - Microsoft Learn: [Remote Desktop Services licensing](https://learn.microsoft.com/en-us/windows-server/remote/remote-desktop-services/rds-client-access-license) - Raff: [Microsoft SPLA Licensing Explained](/learn/guides/microsoft-spla-hosted-windows-vms) - Sources revalidated: 2026-09-17 --- *QuickBooks, QuickBooks Desktop, QuickBooks Enterprise, and Intuit are trademarks of Intuit Inc. Raff is not affiliated with or endorsed by Intuit and is not an Intuit Authorized Hosting Provider.* --- ### Inventory & Warehouse Software on Windows VPS: RDS, SQL & Devices URL: https://rafftechnologies.com/windows-server/windows-vps-erp-inventory-software Description: Plan inventory and warehouse software on a Windows VPS, including RDS users, SQL databases, scanners, label printers, branch access, backups, security, and migration. ## In short A Windows VPS is a good fit for **inventory and warehouse software** when the application still depends on Windows Server, SQL Server, shared folders, Remote Desktop, or a centralized environment for multiple locations. It is especially useful when office, warehouse, and branch users need the same application and data without depending on one physical server in one building. Raff Technologies provides the Windows VM infrastructure for this kind of workload. The buyer or MSP still needs to validate the software vendor's hosting rules, RDS requirements, database design, scanners and printers, backup method, security model, and migration plan before production. If your main question is broader **ERP hosting**, use [ERP Hosting on Windows VPS](/windows-server/erp-on-vps). This page has a narrower job: deciding whether a Windows VPS can support the operational side of inventory and warehouse software, where local devices, printing, database latency, branch access, and recovery often decide whether the deployment succeeds. ## Quick verdict: when a Windows VPS fits inventory software | Situation | Windows VPS fit | Main risk to test | |---|---|---| | 3-10 users need the same Windows inventory app | Good fit | RDS sessions, licensing, and concurrency | | Several offices or warehouses need one database | Good fit | WAN latency and connection quality | | Inventory software uses SQL Server | Good fit after sizing | SQL memory, storage I/O, backups | | Users need label printers or barcode scanners | Depends | Device and printer redirection | | App uses mapped drives or shared folders | Good fit | Paths, permissions, and secure access | | Software vendor supports hosted Windows Server | Stronger fit | Follow vendor architecture requirements | | Software is already SaaS and meets the workflow | VPS may not be needed | Avoid recreating SaaS infrastructure yourself | | Hardware dongles or specialized USB devices are mandatory | Test first | RDP redirection may not support the device reliably | | Warehouse internet is unreliable | Risky | The business needs a connectivity fallback | | High availability is mandatory | Not a single-VPS decision | Design redundancy and database recovery separately | The best candidate is a supported Windows inventory application with a known database, predictable concurrent users, testable peripherals, and a documented recovery plan. :::cta Explore Windows VM Use Raff Windows VM as the infrastructure layer for supported inventory, warehouse, ERP-adjacent, and remote business workloads. ::: ## Inventory hosting is different from generic ERP hosting The existing [ERP Hosting on Windows VPS](/windows-server/erp-on-vps) guide owns the broad ERP decision: architecture, Windows Server version, RDS, SQL Server, licensing, sizing, migration, and hosted ERP trade-offs. Inventory and warehouse deployments have a different operational center of gravity. They frequently depend on: - barcode scanners; - label and receipt printers; - warehouse workstations; - branch connectivity; - shared import/export folders; - scheduled synchronization jobs; - SQL Server or another local database; - mapped drives or UNC paths; - shipping integrations; - accounting exports; - handheld devices; - local or redirected peripherals. That is why an inventory deployment can pass a simple server test and still fail in production. The application may launch correctly while labels print incorrectly, scanners do not redirect, a branch experiences latency, or scheduled imports still point to the old server. ## What moves when inventory software is hosted on Windows VPS A local inventory system often begins as one office server or workstation. Moving it to a Windows VPS centralizes the Windows environment so authorized users and locations connect to one hosted system. ![Architecture visual showing ERP and inventory users accessing software on a Windows VPS with database, reports, and backups](https://raff-images.s3.raffusercloud.com/erp_inventory_windows_vps_access_architecture_webp_01d2a87437.png) The change looks like this: | Area | Local server | Windows VPS | |---|---|---| | Server location | Office or warehouse | Cloud-hosted Windows Server VM | | User access | LAN, local client, VPN | RDP/RDS, RD Gateway, VPN/private access, or app-specific access | | Branch users | Often site-specific | Central environment for multiple locations | | Database | Local SQL/file database | Hosted with the app or on a separate database VM | | Printers/scanners | Direct local connection | Must be tested through the remote workflow | | Backups | Often local | VM + database + file-level recovery can be planned centrally | | Hardware failure | Office server can stop operations | Workload is no longer tied to one local server | | Support | May require local access | MSP/team can manage a known hosted environment | Cloud hosting removes local server hardware from the critical path, but it does **not** remove operational dependencies. Internet access, devices, vendor support, database health, backups, and user permissions still need owners. ## Choose between Windows VPS, managed ERP hosting, and SaaS Before migrating, make sure a Windows VPS is actually the right hosting model. | Model | Best when | You manage | |---|---|---| | Windows VPS | You need control of a supported Windows app/server environment | OS, app, users, RDS, database, backups, monitoring | | Managed ERP hosting | You want a specialist to manage more of the ERP stack | Depends on provider contract | | SaaS ERP/inventory | The vendor already provides the full workflow as a service | Mostly users, configuration, and business process | | Local server | Devices and local network access dominate the workload | Hardware, power, backups, server administration | A Windows VPS should not be chosen just because it is cheaper than a managed ERP service. It makes sense when the business or MSP is comfortable operating the Windows workload and the application vendor supports that model. ## Vendor support comes before infrastructure choice Before choosing a VM size, verify the inventory software's supported architecture. Confirm: | Question | Why it matters | |---|---| | Which Windows Server versions are supported? | Unsupported OS versions can block vendor support. | | Is RDS/Remote Desktop supported? | Daily multi-user sessions may require a different application mode. | | Which database is required? | SQL Server, file databases, or vendor engines have different needs. | | Can app and database share one server? | Small deployments may; larger ones may need separation. | | Is cloud/VPS hosting allowed? | Some software licences restrict hosting models. | | Are terminal-server installations supported? | Some apps require per-user installation or special configuration. | | Which printers/scanners are supported? | Device compatibility can decide whether the migration works. | | Are hardware dongles required? | USB redirection may not be a safe assumption. | | How should the application be backed up? | Vendor-aware backup may be required in addition to VM protection. | | What does vendor support need during an incident? | Logs, versions, database access, and remote support may be required. | Do not interpret “the app installs on Windows” as proof that it is supported on Windows Server, RDS, or third-party hosting. ## Remote users: RDP administration is not the same as RDS One administrator connecting to a Windows server is different from several employees using the server as their daily desktop. | Access pattern | Direction | |---|---| | One MSP/admin user | Restricted administrative RDP may be enough | | Several staff run the app on the server | Plan RD Session Host | | Users connect from many external locations | Consider RD Gateway or another controlled access layer | | Staff only need a web interface | Do not give full desktop access unnecessarily | | App client runs locally and connects to private services | Consider VPN/private networking and vendor guidance | Microsoft's Remote Desktop Services platform supports session-based desktops and applications. If employees use an RD Session Host, licensing must be planned under the applicable Microsoft licensing model. Use [Multi-User RDP vs RDS Session Host](/windows-server/multi-user-rdp-vs-rds), [RDS CAL Licensing](/windows-server/rds-cal-licensing-guide), and [Remote Desktop Gateway vs Direct RDP](/windows-server/remote-desktop-gateway-vs-direct-rdp) before production rollout. ## Scanners and label printers are a first-class migration test Warehouse migrations often fail around peripherals rather than CPU or RAM. Microsoft supports policy-controlled redirection of resources such as printers, drives, COM ports, smart cards, and some USB devices in Remote Desktop scenarios. But support for redirection does not guarantee that a specific inventory device, vendor driver, or workflow will behave correctly. Test the exact hardware. Create a device test matrix: | Device | What to test | |---|---| | USB barcode scanner | Input accuracy and behavior inside the remote session | | Network barcode scanner | Network path, app integration, and latency | | Label printer | Driver, paper/label size, tray, orientation, and print speed | | Receipt printer | Session mapping and formatting | | Standard office printer | Remote Desktop Easy Print or vendor driver behavior | | Scale / serial device | COM/USB dependency and vendor support | | Handheld terminal | Browser/API/client connectivity | | USB licence dongle | Whether remote hosting and redirection are supported at all | Do not stop at “Windows can see the printer.” Test the business action: receive item, scan barcode, update quantity, print label, move stock, and reprint a historical document. ## Printer redirection should be tested with real user sessions Microsoft documents Remote Desktop printer redirection and the Remote Desktop Easy Print path for supported Windows Server environments. Group Policy can also allow or prevent printer redirection. For an inventory deployment, verify: 1. the client sees the local printer; 2. the RDS session redirects it as expected; 3. the application sees the correct printer name; 4. label dimensions are preserved; 5. print jobs do not route to another user's printer; 6. reconnecting the RDS session does not break mappings; 7. the workflow still works after Windows or driver updates. A generic office printer test is not enough if production depends on 4x6 shipping labels, thermal printers, or specialized warehouse devices. ## Database design usually determines performance Many inventory applications depend on SQL Server or another database. The Windows application itself may use modest resources while reports, stock queries, imports, or integrations create the real load. ![Workload planning visual for ERP and inventory software showing users, SQL database, reports, integrations, and backup load on a Windows VPS](https://raff-images.s3.raffusercloud.com/erp_inventory_database_workload_planning_webp_965a15c340.png) Common patterns: | Architecture | When it fits | Main concern | |---|---|---| | App + database on one VM | Small supported deployment | CPU/RAM/I/O contention | | RDS/app VM + separate SQL VM | Growing multi-user workload | Private network and database administration | | App on Windows VPS + vendor-hosted DB | Vendor-specific design | Latency and support boundaries | | File-based database | Smaller legacy apps | File locking, corruption risk, backups | | Web inventory app + SQL backend | Browser users | Database, IIS/app tier, and security | If SQL Server shares the same VM as user sessions, reserve enough memory for Windows, RDS users, and the application. Do not let SQL Server consume nearly all available RAM. Use [SQL Server Max Server Memory](/windows-server/mssql-memory-tuning) and [SQL Server Backup Strategy](/windows-server/mssql-backup-strategy) for the database layer. ## Size for concurrency and peak operations Do not size an inventory server by total employee count. Measure or estimate: - concurrent RDS users; - database working set; - peak stock-count activity; - report generation; - batch imports and exports; - e-commerce synchronization; - shipping/label jobs; - backup windows; - antivirus/EDR overhead; - file and attachment growth; - branch latency; - SQL Server on the same VM or separate. Use these only as planning examples: | Workload | Starting point | When to move higher | |---|---:|---| | 1 admin/test user | 2 vCPU / 4 GB RAM | Database or reporting runs locally | | 2-3 light users | 4 vCPU / 8 GB RAM | RDS desktop workload grows | | 3-5 active inventory users | 4 vCPU / 16 GB RAM | Reporting, PDFs, labels, and SQL compete | | 5-10 active users | 8 vCPU / 32 GB RAM | Shared daily workspace or heavier database | | App + active SQL workload | 8-16 vCPU / 32-64 GB RAM | Database pressure remains high | | Heavy reports/integrations | Split roles | Long jobs interfere with interactive users | Start from the software vendor's supported requirements, then validate under real peak operations. For broader RDS sizing, use [Windows VPS sizing for remote users](/windows-server/windows-vps-sizing-remote-users). :::cta View Pricing Compare Raff Windows VM plans after you estimate concurrent users, SQL load, storage, branch access, and device requirements. ::: ## Multi-location inventory systems need a network test A central Windows VPS can simplify branch access, but every location becomes dependent on connectivity to the hosted environment. Test each office or warehouse for: | Test | Why it matters | |---|---| | Normal latency | Determines interactive responsiveness | | Packet loss | RDP and database clients can feel unstable even when bandwidth is adequate | | Peak-hour behavior | Shared internet links may degrade during busy periods | | Failover connection | Warehouse operations may need backup internet | | DNS and firewall behavior | Branch policies can block required access | | Printing path | Local printers may behave differently by site | | File transfers | Large imports/exports can affect sessions | If the workload depends on constant availability, a second internet circuit or cellular failover at critical locations may matter more than adding another vCPU to the server. For the broader branch-office decision, use [Windows VPS for Multiple Offices](/windows-server/windows-vps-multi-location-business). ## Shared folders, imports, and mapped drives need an inventory Inventory software often includes file-based integrations that are easy to miss. Document: - UNC paths; - mapped drives; - CSV import/export folders; - EDI file drops; - PDF and report output folders; - shipping label directories; - scheduled PowerShell or batch scripts; - Windows Scheduled Tasks; - service-account permissions; - accounting export paths; - scanner drop folders; - backup staging paths. During migration, every path that includes the old server name should be treated as a dependency. If shared folders are a major part of the workload, use [Windows VPS as a Cloud File Server](/windows-server/windows-vps-cloud-file-server) and [File Server Migration to Windows VPS](/windows-server/file-server-migration-to-windows-vps). ## Backups must protect the transaction system, not just the VM A VM backup or snapshot is useful, but inventory recovery often requires a consistent database plus application files, configurations, integrations, and shared documents. Plan multiple recovery layers: | Layer | Purpose | |---|---| | Database-aware backup | Recover SQL Server or vendor database correctly | | Application/file backup | Protect configs, attachments, exports, and shared data | | VM-level backup | Recover the Windows environment | | Snapshot before change | Short-term rollback before upgrades or migration steps | | Off-server copy | Avoid keeping the only recovery data on the production VM | | Restore test | Prove the application and data work after recovery | Define: - **RPO:** how many minutes or hours of inventory transactions can be lost? - **RTO:** how long can receiving, picking, shipping, or invoicing stop? A warehouse that ships continuously usually needs a different recovery target from a small office that updates inventory a few times per day. A restore drill should test the actual workflow: sign in, open inventory, update a record, run a report, print a label, and verify integrations. :::cta Explore Data Protection Protect inventory and warehouse workloads with database-aware backups, VM recovery, off-server copies, and restore testing. ::: ## Security should separate users, admins, apps, and databases An inventory server can contain customer records, pricing, stock information, purchasing history, supplier data, employee activity, and accounting exports. Minimum planning: | Area | Recommendation | |---|---| | Staff accounts | Named accounts, not shared logins | | Administrator accounts | Separate from everyday user sessions | | RDS access | Use the appropriate multi-user architecture | | RDP exposure | Restrict administrative access rather than broadly opening it | | SQL Server | Do not expose database ports publicly without a specific design | | Firewall | Allow only required sources and services | | Printer/drive redirection | Enable only what the workflow requires | | Backups | Protect recovery data from ordinary user access | | Patching | Coordinate Windows, database, drivers, and application updates | | Vendor support access | Make temporary access controlled and auditable | | Offboarding | Remove users, sessions, and credentials promptly | Use [Windows Server Hardening Checklist](/windows-server/windows-server-hardening-checklist) before production access is enabled. ## Migration should prove the warehouse workflow end to end A safe migration is usually side-by-side. 1. Inventory application version, database, users, integrations, printers, scanners, and file paths. 2. Confirm vendor support for Windows Server, RDS, virtualization, and the target database version. 3. Record the current server specs and peak workload. 4. Build the destination Windows VPS. 5. Configure secure administration, user access, backups, and monitoring. 6. Install the inventory application and database prerequisites. 7. Restore or copy non-production data. 8. Test from every important office or warehouse location. 9. Test barcode scanning, labels, reports, imports, exports, and accounting/shipping integrations. 10. Run a recovery test. 11. Schedule cutover outside the busiest operational period. 12. Stop writes to the old environment. 13. Run the final database/file migration. 14. Revalidate users and devices. 15. Keep the old environment available for rollback until production is accepted. The migration is complete only when normal warehouse actions work—not when the Windows server simply boots. ## Cutover checklist for inventory and warehouse software Before reopening production, confirm: | Check | Done | |---|---| | Correct production database is active | ☐ | | User logins and permissions work | ☐ | | RDS sessions and licensing model are correct | ☐ | | Branch offices can connect | ☐ | | Barcode scanners work | ☐ | | Label and receipt printers work | ☐ | | Reports and PDFs generate correctly | ☐ | | Imports and exports work | ☐ | | Shipping/accounting integrations work | ☐ | | Scheduled jobs run | ☐ | | SQL/database backup completes | ☐ | | VM/file backup completes | ☐ | | Off-server recovery copy exists | ☐ | | Monitoring is active | ☐ | | Rollback path remains available | ☐ | For a broader cutover framework, use [Windows Server Migration Checklist](/windows-server/windows-server-migration-checklist-small-business). ## How Raff fits inventory and warehouse workloads Raff can provide the Windows VM foundation for supported inventory and warehouse applications that need Windows Server, Remote Desktop/RDS, SQL Server, private networking, shared files, backups, or a migration destination away from local hardware. A small environment can begin with one Windows VM. When database load or user concurrency grows, the application/RDS role and SQL Server role can be separated over private networking. Raff is not the inventory software vendor. We do not determine whether a third-party product supports Windows Server, RDS, a specific SQL Server version, a scanner, or a licensing dongle. Those requirements should be confirmed with the application vendor before production. The useful division of responsibility is: ```text Raff -> Windows VM infrastructure Business or MSP -> application, users, RDS, database, devices, backups, monitoring, and operations Software vendor -> application compatibility and product support ``` :::cta Deploy Windows Now Deploy a Raff Windows VM after validating your inventory software, users, database, device workflow, and recovery requirements. ::: ## When to use the broader ERP guide instead Use [ERP Hosting on Windows VPS](/windows-server/erp-on-vps) when your question is mainly about: - ERP hosting architecture; - Windows Server version selection; - ERP server sizing; - RDS and Microsoft licensing; - SQL Server architecture; - hosted ERP vs SaaS; - general ERP migration. Stay on this page when the difficult part is: - warehouses and branches; - inventory users; - barcode scanners; - label/receipt printers; - file imports and exports; - operational integrations; - device redirection; - stock-count and shipping workflows. That separation prevents two Raff pages from competing for the same broad ERP search intent. ## Validation scope This September 2026 refresh separates this article from Raff's broader ERP hosting guide and revalidates the current Remote Desktop device/printer redirection concepts against Microsoft documentation. The existing diagrams were preserved. This refresh does **not** claim a new end-to-end test of a specific ERP, inventory, WMS, scanner, or label-printer product on Raff. Compatibility must be validated for the exact software version, Windows Server version, RDS model, driver, and device before production. ## What's next - [Windows VPS for business software](/windows-server/windows-vps-for-business-software) — use the broader business-software guide for adjacent ERP, database, and application workloads. - [ERP Hosting on Windows VPS](/windows-server/erp-on-vps) — use the main ERP hosting decision guide. - [Raff Windows VM](/products/windows-vm) — review Windows infrastructure options after validating the workload. - [Raff Pricing](/pricing) — compare current VM and licensing costs. - [Windows VPS sizing for remote users](/windows-server/windows-vps-sizing-remote-users) — estimate concurrent-user resources. - [Multi-User RDP vs RDS Session Host](/windows-server/multi-user-rdp-vs-rds) — choose the correct access model. - [Windows VPS for Multiple Offices](/windows-server/windows-vps-multi-location-business) — plan branch access. - [SQL Server Migration to Windows VPS](/windows-server/sql-server-migration-to-windows-vps) — move SQL-backed inventory systems. - [Windows VPS Backup Strategy](/windows-server/windows-vps-backup-strategy-small-business) — define recovery before production. - [Windows Server Hardening Checklist](/windows-server/windows-server-hardening-checklist) — secure the environment. ## Sources - Microsoft Learn — Remote Desktop Services overview: https://learn.microsoft.com/en-us/windows-server/remote/remote-desktop-services/overview - Microsoft Learn — Remote Desktop Services licensing: https://learn.microsoft.com/en-us/windows-server/remote/remote-desktop-services/rds-client-access-license - Microsoft Learn — Remote Desktop printer redirection troubleshooting: https://learn.microsoft.com/en-us/troubleshoot/windows-server/remote/printer-redirection-not-work - Microsoft Learn — Remote Desktop Services device and resource redirection policies: https://learn.microsoft.com/en-us/windows/client-management/mdm/policy-csp-remotedesktopservices - Microsoft Learn — SQL Server recovery models: https://learn.microsoft.com/en-us/sql/relational-databases/backup-restore/recovery-models-sql-server - Raff — ERP Hosting on Windows VPS: /windows-server/erp-on-vps - Raff — Windows VM: /products/windows-vm - Sources revalidated: 2026-09-11 --- ### Tax Software Hosting on Windows VPS: Remote Access Guide (2026) URL: https://rafftechnologies.com/windows-server/windows-vps-tax-software Description: Plan tax software hosting on a Windows VPS for remote preparers, with vendor compatibility, RDS licensing, security, backups, seasonal sizing, and migration checks. ## In short **Tax software hosting on a Windows VPS can work well when the tax application's vendor supports Windows Server or hosted Remote Desktop deployments.** The important part is compatibility: do not assume that software which runs on a Windows 11 workstation is automatically supported on Windows Server, RDS, or a third-party cloud VM. Raff Technologies provides Windows VMs that can host supported Windows workloads for tax firms, accountants, and MSP-managed practices. Before production, confirm the exact tax year and software version, supported Windows Server release, multi-user model, RDS requirements, data paths, printers and scanners, backup method, and vendor support policy. The vendor differences are meaningful in 2026. Drake Tax currently lists Windows Server 2019, 2022, and 2025 as supported operating systems and supports dedicated-server network configurations. Lacerte currently documents Windows Server 2016, 2019, and 2022 as file-server operating systems and lists Windows Remote Desktop Services or Citrix as hosted-environment options. TaxAct Professional's current public system requirements list Windows 11, not Windows Server, so a generic Windows Server VPS should not be presented as supported without direct confirmation from TaxAct for the exact deployment. ## Is a Windows VPS a good fit for your tax software? Use this decision table before selecting infrastructure. | Situation | Windows VPS fit | What to verify | |---|---|---| | Vendor explicitly supports Windows Server | Good candidate | Exact supported Server version and tax-year release | | Vendor documents RDS or terminal-server use | Good candidate | User licensing, memory per user, printing, profiles | | Several preparers need the same application and client data | Good candidate | Multi-user licensing and concurrent-access behavior | | Seasonal staff work remotely | Good candidate | Peak concurrency, RDS, access security, bandwidth | | Client files need centralized storage | Good candidate | Supported data path, permissions, backup and restore | | Vendor lists only Windows desktop operating systems | Do not assume support | Ask the vendor before using Windows Server | | Software depends on local USB devices or special scanners | Test first | Redirection and vendor-supported workflow | | Firm needs a fully managed desktop service | Broader architecture decision | RDS stack, support ownership, identity and security | | Internet access is unreliable | Higher operational risk | Secondary connectivity and contingency plan | A Windows VPS is the infrastructure layer. It does not override the tax software vendor's licensing, operating-system support, or deployment rules. :::cta Talk to Windows Engineer Planning remote tax software access? Review the exact application version, supported Windows Server release, users, RDS licensing, storage, backups, and device workflow before deployment. ::: ## Tax software hosting is a seasonal infrastructure problem Tax practices often have a sharp difference between off-season and filing-season demand. A server that feels comfortable in summer can become constrained when more preparers connect, more PDF documents are open, and more client data is processed during peak filing periods. ![Tax season workload planning visual for Windows VPS users, storage, backups, and remote access](https://raff-images.s3.raffusercloud.com/tax_season_windows_vps_workload_planning_webp_96f8ca7dc6.png) Plan for the busiest realistic period, not average annual use. | Peak-season factor | Why it matters | |---|---| | Concurrent preparers | Determines RDS session count and memory pressure | | Longer working hours | Reduces convenient maintenance windows | | PDFs and client documents | Increases storage and backup volume | | Scanning and printing | Adds device-redirection and driver dependencies | | E-file deadlines | Makes downtime more expensive operationally | | Seasonal hires | Requires account, licensing, and access lifecycle planning | | Software updates | Can require restarts or application validation | | Sensitive taxpayer data | Raises the importance of access control, encryption, and recovery | If the tax platform is business-critical, treat the Windows VM as production infrastructure from day one. ## Vendor compatibility comes before VM sizing The correct order is: 1. Confirm the exact software and tax-year version. 2. Confirm the vendor-supported operating system. 3. Confirm whether server, network, RDS, Citrix, or hosted deployment is supported. 4. Confirm application and user licensing. 5. Then size the VM and design remote access. A technically successful installation is not the same as a vendor-supported deployment. ### Drake Tax on Windows Server Drake's current system-requirements documentation, updated in April 2026, lists these supported operating systems for the desktop version: - Windows 11 - Windows Server 2019 - Windows Server 2022 - Windows Server 2025 Drake also states that its software can be networked with a dedicated server, which it recommends, or with a peer-to-peer network. Its current documentation says Windows Server 2016 is no longer supported after Drake Tax 2025. That makes Drake a clearer candidate for a Windows Server VM than software whose vendor only lists a desktop operating system. Still verify the exact tax-year release, licensing, integrations, scanners, and multi-user workflow before migration. ### Lacerte on Windows Server and RDS Lacerte's current public requirements are more specific. Intuit currently lists Windows Server 2016, 2019, and 2022 as supported file-server operating systems and lists **Windows Remote Desktop Service or Citrix** as supported hosted-environment patterns. The same requirements specify at least 2 GB RAM per user for the hosted environment. That is useful evidence for firms researching how multiple preparers can access the same Lacerte environment, but it also creates an important limitation: the current public requirements do **not** list Windows Server 2025 as a supported Lacerte file-server OS. Do not choose Server 2025 for Lacerte only because it is Microsoft's newest LTSC release. Follow Intuit's current compatibility list for the exact Lacerte release. Lacerte also states that file-share and sync services such as Dropbox, Google Drive, and OneDrive are not supported for its data storage, backup, or sharing purposes. Use the vendor's supported data architecture instead of placing the live tax database in a generic sync folder. ### TaxAct Professional on a Windows VPS TaxAct needs a different answer. Its current 2026 public Professional system-requirements page lists **Windows 11** as the supported operating system and does not list Windows Server in that requirements table. TaxAct also provides its own local-network and cloud-networking options for Professional editions. Therefore, do not market a standard Windows Server VPS as automatically supported for TaxAct Professional. If your firm specifically wants TaxAct on Raff, confirm the intended deployment directly with TaxAct and document the supported architecture before production. This distinction matters because users already search for phrases such as "TaxAct VPS." The safe answer is compatibility first, not "Windows software means it will work on Windows Server." ## Windows Server version choice is application-specific Windows Server 2025 is the current Microsoft LTSC release, but tax software vendors can certify operating systems on a different schedule. | Software example | Current public vendor position | Infrastructure implication | |---|---|---| | Drake Tax | Server 2019, 2022, 2025 listed | Server 2025 can be considered for supported Drake releases | | Lacerte | Server 2016, 2019, 2022 listed; RDS/Citrix hosted use documented | Server 2022 is the newest currently listed server OS | | TaxAct Professional | Windows 11 listed in current public requirements | Verify before choosing Windows Server | | Other tax software | Varies | Check vendor requirements for the exact version | Vendor requirements change. Recheck them before each major tax-year upgrade instead of treating this table as permanent compatibility certification. Use [Windows Server Version Comparison](/windows-server/windows-server-version-comparison) after the tax vendor has established which Server versions are acceptable. ## Remote access: administrative RDP is not the same as employee RDS A common small-business mistake is deploying one Windows Server and treating unrestricted administrator RDP as the multi-user workplace. ![Workflow visual showing remote tax preparers accessing tax software on a Windows VPS](https://raff-images.s3.raffusercloud.com/tax_software_windows_vps_remote_access_workflow_webp_fc5decdf6a.png) Use the access model that matches the job: | User pattern | Recommended planning direction | |---|---| | One or two administrators maintain the VM | Restricted administrative RDP | | Preparers need daily Windows desktop sessions | RDS Session Host architecture | | Users connect from changing public networks | RD Gateway, VPN, or another controlled access layer | | Application only exposes a web interface | Do not provide a full Windows desktop unnecessarily | | MSP manages several tax-firm environments | Standardize identity, access, patching, backups, and logging | Microsoft states that a user or device connecting to an RD Session Host running Windows Server requires the applicable RDS access licence. In a customer-owned Microsoft licensing model, this generally means RDS User or Device CALs. In a Raff-hosted SPLA deployment, hosted RDS access follows the applicable service-provider licensing model, including RDS User SALs. The licensing path and the technical RDS configuration should be decided before staff begin using the server. Read [RDS CAL Licensing Guide](/windows-server/rds-cal-licensing-guide) for the distinction and [Remote Desktop Gateway vs Direct RDP](/windows-server/remote-desktop-gateway-vs-direct-rdp) before publishing Remote Desktop access to the internet. ## Security is part of the tax-software architecture Tax practices store taxpayer information that is valuable to attackers. In June 2026, the IRS again reminded tax professionals that a Written Information Security Plan, or WISP, is required and should be tailored to the firm's size, scope, complexity, and sensitivity of customer data. The IRS Security Summit checklist also recommends core controls including antivirus protection, a firewall, multifactor authentication where offered, backup software or services, drive encryption, and secure VPN use. ![Backup and security stack visual for tax software running on a Windows VPS](https://raff-images.s3.raffusercloud.com/tax_software_windows_vps_backup_security_stack_webp_257ff68d1a.png) For a hosted Windows Server, translate that into concrete infrastructure controls: - give every preparer a named account; - separate administrator accounts from daily user accounts; - restrict inbound access instead of exposing RDP broadly; - use MFA-capable access layers where the architecture supports them; - keep Windows and the tax application patched; - protect and monitor backup credentials separately from normal user access; - encrypt appropriate data at rest and in transit; - review failed logons and security events; - limit file permissions to the users who need the client data; - document offboarding for seasonal staff; - keep the security and recovery plan outside the server itself. Use the [Windows Server Hardening Checklist](/windows-server/windows-server-hardening-checklist) as the technical baseline. This article is infrastructure guidance, not legal or regulatory advice; firms should apply their own compliance and professional-adviser requirements. ## Size for peak concurrent preparers, not employee count The old approach of saying "five tax users need exactly X vCPU and Y GB RAM" is too rigid. Tax applications have different vendor requirements, and the same number of users can generate very different load depending on PDFs, browser sessions, document management, scanners, SQL components, and other applications running in the same RDS session. Collect these inputs first: - peak concurrent preparers; - vendor minimum and recommended memory; - vendor-specific per-user RDS memory guidance; - CPU utilization during return calculation and reporting; - PDF/document workload; - user-profile size; - current and prior-year client-data size; - backup and snapshot storage; - other applications that run in the same sessions; - peak-season growth margin. For Lacerte specifically, Intuit's current hosted-environment requirements call for at least 2 GB RAM per user in supported RDS or Citrix environments. That is a vendor minimum for Lacerte, not a complete VM sizing formula. Windows, security software, profiles, browser/PDF tools, and other applications also need memory. Use [Windows VPS Sizing for Remote Users](/windows-server/windows-vps-sizing-remote-users) to map the measured workload to current Raff VM tiers instead of relying on stale hard-coded plan sizes. :::cta View Windows VM Pricing Estimate the production VM only after you know the supported Windows Server version, peak concurrent users, application memory, storage, RDS licensing, and backup requirements. ::: ## Storage planning must include the whole client workflow The tax application installer is usually a small part of the storage footprint. Plan capacity for: | Storage area | Examples | |---|---| | Application data | Current and prior-year returns, indexes, configuration | | Client documents | W-2s, 1099s, IDs, statements, workpapers | | PDFs | Copies of returns, organizers, signed forms, reports | | User profiles | Desktop, Documents, Downloads, application profile data | | Shared folders | Intake, review, export, archive workflows | | Backup staging | Application-specific backup sets and exports | | Windows overhead | Updates, component store, logs, temporary files | | Recovery headroom | Space needed for restore or migration work | Do not place live application data in OneDrive, Dropbox, or another sync folder unless the tax-software vendor explicitly supports that architecture. Both Lacerte and TaxAct publish restrictions around file-sync services for application data workflows. ## Backup design: snapshots help, but they are not the backup strategy Use several recovery layers where the workload requires them: | Recovery layer | Purpose | |---|---| | Application-native backup/export | Recover data in the format the vendor expects | | File-level backup | Recover documents, exports, and supported data folders | | VM backup | Recover the full Windows server state | | Snapshot before a risky change | Short-term rollback around updates or configuration changes | | Off-server copy | Reduce dependency on the production VM and credentials | | Restore test | Prove recovery before filing-season pressure | Define the business targets before choosing frequency: - **RPO:** how much recent tax-work data can the firm afford to lose? - **RTO:** how long can preparers be unable to work? A backup job showing "successful" does not prove that the tax application and client data can be restored. Test representative recovery before peak season. Use [Windows VPS Backup Strategy for Small Businesses](/windows-server/windows-vps-backup-strategy-small-business) for the broader recovery design. ## Printers, scanners, PDF tools, and portals need real-user testing Tax workflows often combine the tax application with hardware and browser-based services. Test from the same endpoints and networks staff will use in production. | Workflow | Test | |---|---| | Printing | Correct printer appears and output matches expected forms | | PDF generation | Returns and reports export without driver or path issues | | Scanning | TWAIN/device workflow works in the supported architecture | | Client documents | Upload, download, open, edit, and save paths are controlled | | Browser portals | IRS, state, vendor, and client portals function in the session | | E-file workflow | Transmission prerequisites and internet access work as expected | | Multi-monitor | Preparers can work efficiently in remote sessions | | Clipboard/drive redirection | Security policy matches the firm's data-handling requirements | For Lacerte, Intuit specifically documents printer and scanner requirements and notes that DMS requires a TWAIN-compliant driver. Drake also lists TWAIN-compliant scanners for relevant document workflows. Do not discover these limitations during a filing deadline. ## Plan updates around filing deadlines Windows and tax-software updates are both necessary, but production changes should have a maintenance process. A practical sequence is: 1. Confirm the latest good backup. 2. Check vendor release notes or support notices. 3. Apply the change during a low-impact window. 4. Reboot if required. 5. Confirm Windows services and RDS availability. 6. Launch the tax application with a normal user account. 7. Open representative client data. 8. Test PDF, printing, scanning, and e-file related workflow where applicable. 9. Confirm the next backup completes. A snapshot can provide a convenient short rollback point before an update, but it should not replace application-aware backup and restore testing. ## Migration to a Windows VPS before tax season Avoid changing the production platform close to a major filing deadline unless the current environment has a more serious failure risk. Use a side-by-side migration when practical: ```text Existing tax environment stays available -> Build the Windows VM -> Confirm OS and vendor compatibility -> Configure RDS and secure access -> Install the exact tax application version -> Copy non-production/test data -> Validate preparer workflows -> Configure and test backups -> Schedule final data synchronization -> Cut users over -> Keep controlled rollback available ``` For firms moving from an office server, use [Server Migration to Cloud: Local Windows Server Guide](/windows-server/local-server-to-cloud-windows-vps-migration) for the cutover and rollback framework. ## Windows VPS vs vendor-hosted tax software A self-managed Windows VPS is not always the best answer. | Requirement | Self-managed Windows VPS | Vendor-hosted option | |---|---|---| | Full Windows Server control | Strong | Usually more limited | | Combine several supported Windows apps | Strong | Depends on offering | | Custom networking/security | Strong | Provider-defined | | Tax-app vendor owns hosting stack | No | Often yes | | Windows/RDS administration required from your team/MSP | Yes | Often reduced | | Application support path | Infrastructure and app support are separate | Can be simpler when hosting is vendor-aligned | | Flexibility for unrelated workloads | Higher | Usually lower | For example, Intuit also sells a hosted Lacerte option. A firm that only needs Lacerte and wants the vendor-aligned hosted experience should compare that with managing its own supported RDS environment. A firm or MSP that needs multiple supported Windows applications, custom access controls, or its own server administration may prefer a Windows VM. The right answer is based on workload ownership, not simply which option is called "cloud." ## How Raff fits tax software hosting Raff is a fit when the **vendor-supported architecture requires a Windows Server VM** and the firm or its MSP wants control of the server environment. A Raff Windows VM can provide the infrastructure for supported workloads including: - Windows Server application hosting; - Remote Desktop/RDS environments; - centralized application and client-data workflows; - private networking; - NVMe-backed VM storage; - snapshots and backup options; - seasonal VM resizing when the workload needs more resources. Raff does not certify tax applications on behalf of Drake, Intuit, TaxAct, or another vendor. Vendor compatibility, tax-software licensing, client-data controls, RDS design, Windows administration, and compliance remain part of the deployment plan. For Microsoft licensing, Raff can provide Windows Server through SPLA, while eligible customer BYOL depends on the customer's Microsoft agreement and applicable rights. Review [Windows Server Licensing on Raff](/windows-server/windows-licensing) before production. :::cta Deploy Windows Now Use Raff Windows VM as the infrastructure layer after your tax-software vendor confirms the target Windows Server and remote-access architecture. ::: ## Pre-deployment checklist for tax firms - [ ] Exact tax product and tax-year version documented - [ ] Vendor-supported Windows version confirmed - [ ] Server/RDS/hosted deployment support confirmed - [ ] Application licence and concurrent-user model confirmed - [ ] Windows Server SPLA or eligible BYOL path selected - [ ] RDS licensing path selected if staff use Session Host - [ ] Peak concurrent preparers estimated - [ ] Vendor memory guidance recorded - [ ] Client-data and PDF storage growth estimated - [ ] Printers and scanners tested - [ ] File paths and application-data locations documented - [ ] Named user and administrator accounts separated - [ ] Remote access restricted and hardened - [ ] Backup layers configured - [ ] Representative restore tested - [ ] WISP/security controls mapped to the hosted environment - [ ] Update and reboot window defined - [ ] Production migration and rollback runbook written - [ ] Real preparers completed acceptance testing If vendor support is unclear, resolve that before buying or migrating production infrastructure. ## Frequently asked questions ### Can I host tax software on a Windows VPS? Yes, when the tax-software vendor supports the exact Windows Server, network, RDS, or hosted architecture you plan to use. Compatibility varies by vendor and tax-year release, so a successful installation alone is not enough evidence for production support. ### Does Drake Tax support Windows Server 2025? Drake's current public system requirements list Windows Server 2019, 2022, and 2025 for the desktop version. Confirm the exact Drake Tax release and your network, licensing, scanner, and multi-user requirements before deployment. ### Can multiple preparers use Lacerte through Remote Desktop Services? Intuit's current Lacerte requirements list Windows Remote Desktop Service or Citrix as hosted-environment options on supported file-server operating systems and specify at least 2 GB RAM per user. The current page lists Windows Server 2016, 2019, and 2022, not Windows Server 2025. ### Can I run TaxAct Professional on a Windows Server VPS? Do not assume it. TaxAct Professional's current public system requirements list Windows 11 and do not list Windows Server in the operating-system requirements. TaxAct also provides its own network options. Confirm your intended hosted/server architecture directly with TaxAct before production. ### Do remote tax preparers need RDS licensing? When employees use RD Session Host on Windows Server, the deployment needs the applicable Microsoft RDS licensing. Customer-owned licensing generally uses RDS User or Device CALs. Raff-hosted SPLA environments follow the applicable service-provider licensing model, including RDS User SALs. ### Is a VM snapshot enough to protect client tax data? No. A snapshot is useful for short-term rollback, but production recovery should also include the application/vendor-supported backup method, appropriate file or VM backups, an off-server recovery path, and tested restores. ### Does moving tax software to a cloud VM satisfy IRS security requirements? No. Hosting location alone does not satisfy a tax firm's security obligations. The IRS states that tax professionals need an information security plan and recommends safeguards such as antivirus, firewalls, multifactor authentication where available, backups, encryption, and secure remote-access practices. ## Validation scope This article was revalidated on **September 11, 2026** against current public documentation from Drake Software, Intuit Lacerte, TaxAct Professional, Microsoft Remote Desktop Services, and the IRS. No "Tested on Raff" claim is made for Drake, Lacerte, or TaxAct because this refresh does not have a current named-engineer compatibility test and screenshot for those applications. Vendor requirements remain the source of truth for supported software versions and deployment models. ## What's next - [Windows VPS for business software](/windows-server/windows-vps-for-business-software) — compare the broader Windows business-software hosting model before standardizing tax workloads. - [Raff Windows VM](/products/windows-vm) - review the Windows infrastructure platform. - [Raff Pricing](/pricing) - check current VM, storage, backup, and licensing pricing. - [Windows Server Licensing](/windows-server/windows-licensing) - review SPLA, eligible BYOL, CAL, and RDS licensing. - [RDS CAL Licensing Guide](/windows-server/rds-cal-licensing-guide) - understand multi-user Session Host licensing. - [Windows VPS Sizing for Remote Users](/windows-server/windows-vps-sizing-remote-users) - size for peak concurrent users and actual workload. - [Remote Desktop Gateway vs Direct RDP](/windows-server/remote-desktop-gateway-vs-direct-rdp) - choose a safer remote-access model. - [Windows Server Hardening Checklist](/windows-server/windows-server-hardening-checklist) - secure the production server. - [Windows VPS Backup Strategy for Small Businesses](/windows-server/windows-vps-backup-strategy-small-business) - design recovery before filing season. - [Server Migration to Cloud](/windows-server/local-server-to-cloud-windows-vps-migration) - plan migration and rollback from an office server. - [Windows VPS for MSP Client Environments](/windows-server/windows-vps-for-msp-client-environments) - standardize tax-firm environments managed by an MSP. ## Sources - IRS - Written Information Security Plans are essential for tax pros: https://www.irs.gov/newsroom/written-information-security-plans-are-essential-for-tax-pros - IRS - Tax Security 2.0: Taxes-Security-Together Checklist: https://www.irs.gov/tax-professionals/tax-security-2-point-0-the-taxes-security-together-checklist - IRS - Protect Your Clients; Protect Yourself: https://www.irs.gov/tax-professionals/protect-your-clients-protect-yourself - Drake Software - Drake Tax System Requirements: https://kb.drakesoftware.com/KB/Drake-Tax/11776.htm - Drake Software - Network Setup: https://kb.drakesoftware.com/kb/Drake-Tax/11851.htm - Intuit Accountants - Lacerte system requirements: https://accountants.intuit.com/support/en-us/help-article/product-system-requirements/lacerte-system-requirements/L4QtkL7WO_US_en_US - TaxAct Professional - System Requirements: https://www.taxact.com/professional/system-requirements - TaxAct Professional - Tax Year 2026 setup resources: https://www.taxact.com/professional/resources/setupguide - Microsoft Learn - RDS Client Access Licenses: https://learn.microsoft.com/en-us/windows-server/remote/remote-desktop-services/rds-client-access-license - Microsoft Learn - Install RDS CALs: https://learn.microsoft.com/en-us/windows-server/remote/remote-desktop-services/rds-install-cals - Sources revalidated: 2026-09-11 --- ### Cloud File Server for Small Business: Windows VPS Guide URL: https://rafftechnologies.com/windows-server/windows-vps-cloud-file-server Description: Plan a cloud file server for small business on Windows Server: compare SMB, RDP/RDS, VPN, SMB over QUIC, storage, backups, security, pricing, and migration. ## In short A **cloud file server for small business** makes sense when users or Windows applications still need shared folders, NTFS permissions, mapped drives, or server-side file paths, but the business no longer wants those files tied to one office machine. A Windows VPS can provide that server environment. The key decisions are how users reach the files, how much storage will grow, how backups work, and whether SaaS collaboration would be simpler. A cloud file server is not just a folder on a remote VM. It is production infrastructure with permissions, access policy, storage growth, backup retention, restore testing, monitoring, and a documented support owner. For many SMBs, the practical choice is between three models: - SaaS document collaboration for browser-first file work; - a hosted Windows file server for SMB/NTFS and Windows application dependencies; - a hybrid design when some workflows should stay local. ## A Windows VPS fits a cloud file server when Windows file semantics still matter Use this table before moving shared folders to the cloud. | Situation | Windows VPS file-server fit | Why | |---|---|---| | Users work inside RDP/RDS Windows sessions | Strong | Files stay next to the apps and user sessions | | Business apps depend on UNC paths or mapped drives | Strong after testing | Windows file paths and NTFS permissions remain available | | Small team needs centralized departmental folders | Good | One controlled server can replace scattered office shares | | Multiple offices need the same files | Good with access planning | Centralized storage can reduce office-to-office duplication | | Users want public SMB over TCP 445 from anywhere | Poor | Public SMB exposure should be avoided | | Team mainly needs co-authoring and browser sharing | Depends | Microsoft 365, Google Workspace, or another SaaS platform may be simpler | | Very large media files move continuously over the LAN | Depends | Latency and transfer patterns may favor local or specialized storage | | Application uploads need scalable object APIs | Poor | Object storage is a different and usually better model | The strongest Raff use case is not generic “cloud storage.” It is a **hosted Windows Server file environment** for businesses that still depend on Windows applications, Remote Desktop, SMB/NTFS permissions, or office-server-style workflows. ## Cloud file server and cloud storage are not the same product Searches for “cloud file server” often mix two different requirements. | Requirement | Windows cloud file server | SaaS cloud storage | |---|---|---| | SMB shared folders | Strong fit | Usually different access model | | NTFS permissions | Strong fit | Different permission model | | Mapped drives for Windows apps | Strong fit | Depends on vendor/client tooling | | Legacy app UNC paths | Strong fit after testing | Often poor fit | | Browser collaboration | Basic | Strong | | Real-time co-authoring | Limited | Strong | | Public share links | Not the main use case | Strong | | Windows application data locality | Strong | Depends on app architecture | If the business problem is simply “employees need documents from anywhere,” SaaS may be easier. If the problem is “our accounting, Access, ERP, or legacy Windows application needs shared paths and controlled Windows permissions,” a Windows file server is a different requirement. ## A Windows VPS file server uses SMB and NTFS permissions On Windows Server, file sharing normally combines: - SMB for network file access; - NTFS permissions for folders and files; - users and security groups; - auditing and access review; - backup and restore policy. Microsoft describes SMB as the Windows protocol for shared resources such as files, printers, and named pipes. A hosted Windows file server may hold: | File type | Examples | |---|---| | Shared business folders | Accounting, HR, operations, client files | | Application data | Legacy app folders, Access back ends, accounting exports | | Reports and PDFs | Statements, invoices, tax documents, signed forms | | User workspaces | Shared departmental folders and app working directories | | Scripts and admin tools | MSP scripts, PowerShell tools, installers | | Archives | Prior-year or inactive business data | Treat the VM as production infrastructure when the business depends on those files. ## Public SMB exposure is the wrong default access model Classic SMB over TCP 445 should not be broadly exposed to the public internet. Microsoft’s current SMB security guidance recommends segmentation and isolation around SMB traffic, and its SMB over QUIC documentation explicitly says not to allow TCP 445 inbound when using the internet-facing QUIC model. Use a controlled access design instead: | Access model | Best fit | |---|---| | Users open files inside RDP/RDS sessions | Windows apps and files should stay together | | VPN/private network before SMB | Endpoints need mapped drives or direct share access | | RD Gateway | Users need controlled Remote Desktop access rather than direct file-share exposure | | SMB over QUIC | Modern Windows file access over untrusted networks where prerequisites fit | | Public TCP 445 | Avoid | The network path should be chosen before users are onboarded. ## SMB over QUIC gives Windows Server 2025 a modern remote-file option Windows Server 2025 makes **SMB over QUIC available in Standard and Datacenter**, whereas Windows Server 2022 limited the server feature to Datacenter: Azure Edition. Microsoft describes SMB over QUIC as an alternative SMB transport designed for untrusted networks such as the internet. It uses TLS 1.3 and typically UDP 443 instead of exposing classic SMB on TCP 445. Important planning points: - it is opt-in, not automatically enabled; - the client side is Windows 11; - a valid server certificate is required; - authentication still needs a supported identity model; - the firewall should permit the QUIC path, not public TCP 445; - the application must still behave correctly over the remote file path. SMB over QUIC can be attractive when remote employees genuinely need SMB file semantics from Windows endpoints. It does not replace SaaS collaboration, backup policy, permissions, or application testing. ## Windows Server 2025 also strengthens SMB security defaults Microsoft’s current Windows Server 2025 guidance adds stronger SMB security capabilities, including newer signing, auditing, firewall, authentication-rate-limiting, and QUIC controls. Current Microsoft documentation specifically states that Windows Server 2025 requires outbound SMB signing by default. Do not weaken signing or authentication merely to make an old NAS, guest share, or legacy device connect. Treat that dependency as something to test, isolate, upgrade, or replace. For the broader operating-system baseline, use [Windows Server Hardening Checklist](/windows-server/windows-server-hardening-checklist). ## Remote Desktop can be simpler than WAN SMB for many business applications A cloud file server and a Remote Desktop server often overlap. ![Architecture visual showing remote users accessing shared files on a Windows VPS through RDP, RDS, VPN, or controlled access](https://raff-images.s3.raffusercloud.com/windows_vps_cloud_file_server_access_architecture_webp_d95873377f.png) For a Windows business application, it can be cleaner to run both the application and its files inside the same hosted Windows environment and let users connect through RDP/RDS. | Pattern | When it works well | |---|---| | RDP/RDS users open files inside the server | App and data should stay close together | | Users map SMB shares over a private/VPN path | Endpoint file access is required | | SMB over QUIC | Modern Windows endpoints need SMB over untrusted networks | | Raw WAN SMB with high latency | Test carefully; some apps perform poorly | | Browser-first documents | SaaS collaboration may be better | This matters for Microsoft Access, accounting software, tax applications, ERP, legacy apps, and other file-sensitive Windows workloads. If several employees need daily Windows sessions, plan the environment as RDS rather than treating administrative RDP as a team workspace. Under Raff’s hosted model, Windows Server Standard SPLA is **$15/month per instance**, and hosted RDS functionality uses **RDS User SALs at $8/user/month**. See [Remote Desktop Server for Business](/windows-server/remote-desktop-server-for-business) for the user-session model. ## A Windows file server and object storage solve different problems ![Comparison visual showing Windows VPS file server versus object storage for business files and application uploads](https://raff-images.s3.raffusercloud.com/windows_vps_file_server_vs_object_storage_webp_e8507619d6.png) | Requirement | Windows VPS file server | Object storage | |---|---|---| | SMB shared folders | Strong | Not the native model | | NTFS permissions | Strong | Different model | | Legacy Windows file paths | Strong | Usually poor | | Application uploads | Depends | Strong | | Static assets | Depends | Strong | | Large public downloads | Depends | Strong | | User desktop workflows | Strong | Poor | | S3-compatible APIs | Not the purpose | Strong | Use a Windows file server when Windows users and applications need filesystem semantics. Use object storage when applications need scalable object-based storage for uploads, backups, assets, or programmatic access. ## Folder and permission design should happen before migration Do not copy an old office share structure blindly. A simple structure might be: ```text D:\Shares \Accounting \Operations \Clients \HR \Projects \Apps \Archive ``` Every top-level folder should have: - a business owner; - defined read/modify groups; - a retention rule; - a backup priority; - a documented migration source. Use security groups instead of assigning permissions user by user. A practical model might use groups such as `Accounting_Read`, `Accounting_Modify`, `HR_Read`, and `HR_Modify`. Share permissions and NTFS permissions both matter. Document why access exists so the file server does not drift into broad, unexplained permissions over time. ## Storage sizing should map business data to current Raff capacity File-server workloads are often storage-driven. Plan for production files, application data, profiles, logs, temporary files, archive growth, and backup staging. Do not treat a theoretical 500 GB or 1 TB target as if it were a base Raff VM SKU. Current Windows VM plans include fixed local NVMe storage, and additional block storage can be added with Raff Volumes at **$0.08/GB/month**. Current planning anchors include: | Raff Windows VM | Base NVMe | Compute | Windows Server SPLA | Starting Windows total* | |---|---:|---:|---:|---:| | 2 vCPU / 4 GB | 80 GB | $22.99 | $15.00 | **$37.99/mo** | | 4 vCPU / 8 GB | 120 GB | $40.99 | $15.00 | **$55.99/mo** | | 8 vCPU / 16 GB | 180 GB | $76.99 | $15.00 | **$91.99/mo** | \*Before extra volumes, backups, RDS User SALs, application licensing, or migration work. For example, an additional 500 GB Raff Volume is **$40/month** at the current $0.08/GB rate. That lets the file footprint grow independently from the base VM tier when the architecture allows it. These examples are infrastructure planning anchors, not performance guarantees. File count, active users, application behavior, antivirus scanning, backup windows, and latency still matter. :::cta View Pricing Compare current Raff Windows VM, Windows licensing, storage, and protection costs before building a production file server. ::: ## Backups need to cover both the server and the files A cloud file server should not go live without a recovery model. Use separate layers for different failures: | Layer | Purpose | |---|---| | Snapshot | Fast rollback before risky changes | | VM backup | Recover the Windows environment | | File-level backup | Restore individual files or folders | | Application-aware backup | Protect databases and app data consistently | | Off-server copy | Reduce dependence on one server/account/failure boundary | | Restore test | Prove that recovery works | Raff snapshots/backups are currently **$0.06/GB/month**. A 500 GB protected footprint would therefore be about **$30/month** before considering retention behavior or additional application-specific backup copies. Do not confuse a green backup job with a successful restore. Test one-file, folder, and larger restores before the business depends on the system. Use [Windows VPS Backup Strategy for Small Businesses](/windows-server/windows-vps-backup-strategy-small-business) for the full recovery design. ## Security controls should be in place before production data arrives ![Layered visual showing Windows VPS file server permissions, backups, snapshots, off-server copies, and restore testing](https://raff-images.s3.raffusercloud.com/windows_vps_file_server_backup_permission_stack_webp_d29befad13.png) Minimum planning: | Area | Recommendation | |---|---| | Public exposure | Do not broadly expose SMB/TCP 445 | | Users | Use named users and groups | | Admin access | Separate administrator accounts from daily users | | Permissions | Apply least privilege and document folder owners | | Remote access | Use RDP/RDS, VPN/private access, or SMB over QUIC where appropriate | | SMB | Keep SMBv1 disabled and preserve modern signing/security controls | | Backups | Restrict who can modify or delete recovery points | | Audit | Record relevant sign-ins and permission changes | | Patching | Keep Windows Server and business apps current | | Endpoint risk | Control how business files leave the hosted environment | Raff supplies the Windows VM infrastructure. Operating-system permissions, SMB configuration, application support, user governance, and backup policy still need an administrator or MSP owner. ## Performance depends on how the files are used A file server can be slow even when CPU and RAM look normal. Watch: - file size and file count; - disk latency; - active users; - application locking behavior; - WAN latency; - antivirus/EDR scanning; - search indexing; - backup windows; - profile growth if RDS users share the server. Common symptoms: | Symptom | Possible cause | |---|---| | Folder browsing is slow | Huge directories, latency, indexing, permissions | | Saving files is slow | Network path, disk latency, antivirus scanning | | App files lock | Application design or multi-user file behavior | | RDP users are slow | CPU/RAM pressure, profiles, or user network path | | Backups slow production | I/O contention or backup schedule | | Disk fills unexpectedly | Profiles, exports, duplicate data, logs, staging | Use [Windows Server Performance Monitoring](/windows-server/windows-server-performance-monitoring) before resizing blindly. ## Migration from an office file server should be staged A safer migration sequence is: 1. Inventory existing shares, users, groups, NTFS ACLs, and applications. 2. Separate active, archive, duplicate, and obsolete data. 3. Choose the Windows VM and additional storage plan. 4. Build the new folder and permission structure. 5. Copy sample/non-production data first. 6. Test real application paths and user workflows. 7. Configure backups and complete a restore test. 8. Run the bulk data copy. 9. Schedule a final delta sync and cutover. 10. Redirect users/applications to the new paths. 11. Keep the old server available for rollback until the new system is proven. 12. Monitor file errors, latency, permissions, and disk growth after cutover. If the file server is one part of a larger office-server replacement, use [Office Server Replacement for Small Business](/windows-server/replace-office-server-small-business) before the cutover. ## A Windows cloud file server is not always the best answer Choose another model when: | Situation | Better direction | |---|---| | Team mainly needs real-time document co-authoring | SaaS collaboration platform | | Public web applications need scalable asset storage | Object storage | | Users move very large media files all day | Local or specialized storage workflow | | Application needs LAN-like latency | Test before cloud migration | | Branch internet is unreliable | Fix connectivity or keep critical data local | | Nobody owns Windows administration or backups | Define operating ownership first | | Compliance requirements are still undefined | Complete architecture/policy review before production | The wrong pattern is copying an old office share to a VPS, opening TCP 445 publicly, and calling the project complete. ## Raff fits small-business file servers that still need Windows Raff is a fit when a business or MSP needs a Windows Server foundation for: - shared business folders; - Windows applications that depend on file paths; - Remote Desktop or RDS users; - office-server replacement; - branch access; - NTFS permissions; - storage that can grow with additional volumes; - backup and snapshot planning. Current Raff Windows VMs use NVMe-backed storage and **3 Gbps unmetered VM traffic with no VM egress fees**. The infrastructure layer can scale through larger VM tiers or added block storage, while the business/MSP retains control of Windows, users, permissions, applications, backup policy, and migration. ## Validation scope This September 2026 refresh is a **commercial planning and source-of-truth update**, not a claim that Raff ran a fresh file-server benchmark or SMB over QUIC lab for this revision. Current Raff VM pricing, Windows Server SPLA pricing, volume pricing, snapshot/backup pricing, RDS User SAL pricing, and network terms were revalidated. Microsoft SMB security and SMB over QUIC behavior were rechecked against current Microsoft documentation. Test actual applications, endpoints, certificates, access paths, and restore procedures before production. ## What's next - [Windows VPS for small business](/windows-server/windows-vps-small-business) — use the broader SMB decision guide when planning a cloud file server. - [Raff Windows VM](/products/windows-vm) — choose the Windows infrastructure. - [Windows VPS Pricing Explained](/windows-server/windows-vps-pricing-explained) — calculate the full monthly Windows cost. - [Windows VPS Backup Strategy](/windows-server/windows-vps-backup-strategy-small-business) — design recovery and retention. - [Windows Server Hardening Checklist](/windows-server/windows-server-hardening-checklist) — secure Windows and SMB before production. - [Windows VPS Sizing for Remote Users](/windows-server/windows-vps-sizing-remote-users) — plan CPU/RAM when users also work through RDP/RDS. - [Office Server Replacement for Small Business](/windows-server/replace-office-server-small-business) — plan the broader on-premises-to-cloud decision. - [RD Gateway vs Direct RDP](/windows-server/remote-desktop-gateway-vs-direct-rdp) — design remote desktop access. ## Sources - Microsoft Learn — What is SMB File Sharing for Windows and Windows Server? - Microsoft Learn — SMB security hardening in Windows Server and Windows Client - Microsoft Learn — SMB over QUIC - Microsoft Learn — What's new in Windows Server 2025 - Microsoft Learn — Secure SMB Traffic in Windows Server - Microsoft Learn — Control SMB signing behavior - Raff — Windows VM - Raff — Pricing - Sources revalidated: 2026-09-09 --- ### Windows VPS for MSPs: Client Hosting, RDS, Backups & Security URL: https://rafftechnologies.com/windows-server/windows-vps-for-msp-client-environments Description: A practical Windows VPS guide for MSPs: standardize client Windows Server environments, RDS access, licensing, backups, security, migration, monitoring, and support boundaries. ## In short A Windows VPS can be a strong infrastructure layer for an MSP when a client needs Windows-only business software, Remote Desktop access, a replacement for an aging office server, shared files, SQL-backed applications, or a centralized Windows environment for multiple locations. Raff Technologies provides Windows Server VMs that MSPs can use as the infrastructure underneath their own managed service. The important distinction is that the VPS provider supplies the Windows compute platform, while the MSP still owns the client design: user access, application support, RDS licensing, backups, monitoring, documentation, security policy, and day-to-day client support. For an MSP, the goal should not be to sell “a VPS.” The goal is to create a repeatable Windows service that can be deployed, supported, backed up, migrated, and eventually offboarded without reinventing the process for every client. ## Quick verdict: when Windows VPS fits an MSP client | Client situation | Windows VPS fit | MSP planning requirement | |---|---|---| | Client needs one Windows-only business app | Strong fit | Confirm vendor support, sizing, backups, and user access. | | 3-10 users need a shared Windows environment | Good fit with RDS planning | Plan Session Host, RDS CALs, profiles, printers, and concurrency. | | Client is replacing an aging office server | Strong fit | Inventory hidden services, files, apps, jobs, and rollback requirements. | | Multiple offices need the same app or data | Strong fit | Test latency and access from every location. | | Client uses QuickBooks, Sage, ERP, tax, Access, or legacy software | Good fit after testing | Verify vendor licensing and deployment support. | | Client needs a cloud file server | Good fit with secure access design | Plan SMB, permissions, mapped drives, backups, and remote access. | | Client requires a fully managed desktop platform | Not a one-VM decision | Design RDS/VDI architecture and management responsibilities first. | | Client requires high availability | Not a single-VPS solution | Design redundancy, recovery, and database/application failover. | The best MSP use case is a **well-defined Windows workload with a known support owner, backup policy, access model, and recovery target**. :::cta Explore Windows VM Use Raff Windows VM as the infrastructure layer for client Windows workloads, remote access, business apps, and migrations. ::: ## MSP clients buy an outcome, not a server Most SMB clients never ask an MSP for a “Windows VPS.” They ask for a business problem to be solved. Typical requests sound like: - “Our accounting software needs to work from home.” - “The office server is old and we do not want to buy another one.” - “Both branches need the same inventory system.” - “We need several users in the same Windows application.” - “Our Access database only works properly in the office.” - “We need a Windows server for a legacy app.” - “Can you move this SQL-backed app out of the server closet?” The MSP translates that request into an architecture. A Windows VPS can be the right foundation, but the service still needs migration, configuration, access, backup, monitoring, security, and user support around it. That is the difference between **reselling infrastructure** and delivering a **managed Windows service**. ## Why MSPs standardize client Windows environments Standardization lowers support cost and reduces mistakes. ![Architecture diagram showing MSP client Windows VPS environments with remote users, business apps, backups, and security controls](https://raff-images.s3.raffusercloud.com/msp_client_windows_vps_architecture_webp_715a9e763e.png) An MSP can define a small number of repeatable patterns instead of building every Windows server differently. | Standard | What the MSP defines | |---|---| | OS baseline | Supported Windows Server versions and patch policy | | Access model | Admin RDP, RDS, RD Gateway, VPN/private access, or app-only access | | User model | Named accounts, groups, admin separation, offboarding | | Backup model | Frequency, retention, off-server copy, restore ownership | | Monitoring | CPU, RAM, disk, backup success, services, logins, event logs | | Security | Firewall, least privilege, patching, Defender/security tooling, logging | | Documentation | VM spec, apps, users, licensing, backups, change history, runbook | | Migration | Discovery, test build, pilot, cutover, rollback | | Escalation | What the MSP owns versus what the infrastructure or app vendor owns | The technical value is not only consistency. The commercial value is that a technician can support the next client using a familiar process instead of learning a completely different environment. ## Keep client environments separate by default For most MSP workloads, one client should have its own Windows VPS rather than sharing a server with unrelated customers. ![Visual showing separate Windows VPS environments for different MSP clients with isolated backups, users, and access policies](https://raff-images.s3.raffusercloud.com/msp_client_separation_windows_vps_webp_561c17086d.png) Client separation simplifies: | Area | Why separate client VMs help | |---|---| | Security | One client's users and data are not mixed with another client's environment. | | Backups | Restore points map cleanly to one client. | | Billing | Infrastructure cost can be assigned to that customer. | | Performance | One client's workload is less likely to interfere with another's. | | Change management | App updates affect only the intended client. | | Troubleshooting | Logs, services, users, and applications are easier to isolate. | | Offboarding | A departing client can be transferred or retired without touching others. | | Documentation | The VM, users, apps, backups, and support history stay in one record set. | A shared MSP management server can still make sense for internal tooling, monitoring, automation, or jump-host functions. Client business applications and data should normally stay isolated unless there is a deliberate architecture for multi-tenancy. ## Windows VPS vs managed Windows VPS for MSP clients The phrase “managed Windows VPS” can mean very different things. MSPs should define the boundary instead of assuming the hosting provider manages the same things they do. | Layer | Typical infrastructure provider role | Typical MSP role | |---|---|---| | Physical/cloud infrastructure | Provider | — | | VM provisioning | Provider | MSP selects and configures | | Windows Server OS | Provider makes image available | MSP patches and administers unless contract says otherwise | | RDP access | Provider enables VM access | MSP controls who can connect | | Business application | — | MSP/client/app vendor | | RDS deployment | — | MSP designs and configures | | RDS CALs | Provider may supply Windows licensing framework | MSP verifies client licensing requirements | | File permissions | — | MSP | | App-specific backups | — | MSP/client/app vendor | | Monitoring | Infrastructure and/or platform-specific | MSP monitors client workload according to contract | | User support | Platform support for provider service | MSP supports end users and client workflow | For Raff specifically, the current Windows offering provides Windows Server 2019, 2022, and 2025 options, full administrator access through RDP, Microsoft SPLA licensing, infrastructure support, and migration assistance. The MSP should still treat client application management, RDS design, backups, users, and operating procedures as part of its own managed-service scope. This separation is useful commercially because it lets the MSP keep ownership of the client relationship while using Raff as the Windows infrastructure layer. ## Remote Desktop design should be standardized before onboarding clients “RDP” is often used as shorthand for several different remote-access patterns. MSPs should distinguish them. | Access pattern | Best fit | |---|---| | Restricted admin RDP | MSP technicians or one administrative user | | RDS Session Host | Multiple client users need Windows desktop or RemoteApp sessions | | RD Gateway | Controlled remote access for RDS users across external networks | | VPN/private access | Internal services, file shares, or management paths | | Web application | Client users only need browser access | Microsoft describes Remote Desktop Services as the Windows Server platform for delivering managed desktops and applications to users across offices, homes, branches, and partner locations. If ordinary staff use an RD Session Host, RDS licensing also needs to be part of the quote and onboarding process. Microsoft states that each user or device connecting to an RD Session Host needs an RDS Client Access License. The MSP should decide whether the deployment uses Per User or Per Device licensing and document who owns that licensing process. Read [RDS CAL Licensing on Windows Server](https://rafftechnologies.com/windows-server/rds-cal-licensing-guide) and [Remote Desktop Gateway vs Direct RDP](https://rafftechnologies.com/windows-server/remote-desktop-gateway-vs-direct-rdp) before standardizing client remote-access packages. ## Build service tiers around workload, not employee count A 20-person company might have only two people using the Windows server. A 6-person accounting office might keep five concurrent RDS sessions open all day. Employee count is not enough for sizing. Start with **concurrent users + application load + database load + storage growth + backup window**. | Client workload | Starting planning range | Watch for | |---|---:|---| | 1-2 administrative users | 2 vCPU / 4 GB RAM | Background tools, antivirus, app services | | 3 light remote users | 4 vCPU / 8 GB RAM | Browsers, PDFs, Office workloads | | 3 business-app users | 4 vCPU / 16 GB RAM | Accounting, tax, Access, legacy apps | | About 5 active users | 4 vCPU / 16 GB RAM | Persistent sessions and reporting | | About 10 active users | 8 vCPU / 32 GB RAM | Shared desktop workload throughout the day | | Heavy ERP/SQL workload | 8-16 vCPU / 32-64 GB RAM | Database and RDS session contention | These are starting points, not guarantees. The application vendor's requirements and real client behavior should override a generic sizing table. A useful MSP pattern is to define three or four internal service profiles such as **light app**, **standard business app**, **multi-user RDS**, and **heavy database/app**. Then monitor real usage and resize only when the workload shows the need. Use [Windows VPS sizing for remote users](https://rafftechnologies.com/windows-server/windows-vps-sizing-remote-users) for the detailed sizing process. :::cta View Pricing Compare Raff Windows VM plans after estimating concurrent users, application load, memory, storage, and recovery requirements. ::: ## Backups must be part of the MSP contract Backups are not an optional infrastructure checkbox once a client depends on the server. Define the recovery service in business terms: | Backup decision | What the MSP should define | |---|---| | RPO | How much recent data the client can lose | | RTO | How long the workload can be unavailable | | VM backup | Whether the full Windows environment is recoverable | | File-level backup | Whether individual documents and folders can be restored | | App-aware backup | SQL Server, accounting, ERP, or other stateful app protection | | Retention | How many restore points and how long they are kept | | Off-server copy | Where recovery data exists outside the VM | | Restore owner | Who performs the recovery | | Test cadence | How often a real restore is validated | The client should understand what “backup included” actually means. A restore after accidental deletion is different from full VM recovery, database point-in-time recovery, or ransomware recovery. A good MSP agreement says what is protected, what is not protected, how often backups run, how long data is kept, and what recovery time is realistic. Use [Windows VPS Backup Strategy for Small Businesses](https://rafftechnologies.com/windows-server/windows-vps-backup-strategy-small-business) when defining the client policy. :::cta Explore Data Protection Define backup frequency, retention, off-server recovery, and restore testing before the client environment goes live. ::: ## Migration is where an MSP can add the most value A client moving from an office server rarely needs only a VM. They need discovery and risk reduction. A repeatable MSP migration process can be: 1. Inventory the source server, users, apps, files, databases, jobs, printers, and integrations. 2. Identify which workloads move, rebuild, retire, or remain local. 3. Confirm application vendor support and licensing. 4. Define user access and RDS requirements. 5. Build the destination Windows VPS. 6. Apply the MSP security and monitoring baseline. 7. Configure backups before production data is moved. 8. Migrate non-production data or restore a test copy. 9. Test with real client users. 10. Validate printing, file paths, reports, exports, and scheduled jobs. 11. Schedule the final cutover. 12. Keep the source environment available for rollback until the new system is proven. 13. Record final configuration and hand the environment into normal support operations. The value of the MSP is visible here: a hosting provider can supply a Windows VM, but the MSP understands the customer's applications, deadlines, users, and operational risk. If the client is replacing local infrastructure, read [Local Office Server to Cloud Windows VPS Migration](https://rafftechnologies.com/windows-server/local-server-to-cloud-windows-vps-migration), [File Server Migration to Windows VPS](https://rafftechnologies.com/windows-server/file-server-migration-to-windows-vps), and [SQL Server Migration to Windows VPS](https://rafftechnologies.com/windows-server/sql-server-migration-to-windows-vps). ## Security should be a repeatable baseline Do not configure every client server from memory. A minimum MSP Windows baseline should cover: | Area | Baseline question | |---|---| | Admin identities | Are technicians using named admin accounts? | | Client identities | Are users separated from administrators? | | RDP exposure | Is direct public access minimized and restricted? | | Firewall | Are inbound rules documented and limited? | | Patch policy | Is there a maintenance window and restart process? | | Endpoint/security tooling | Is the chosen Windows security stack configured and monitored? | | Logging | Are failed logins and critical events reviewed? | | Backups | Can ordinary users or compromised credentials delete recovery data? | | Vendor access | Is temporary third-party access controlled and removed afterward? | | Offboarding | Can one user be removed without disrupting the whole environment? | Microsoft publishes Windows security baselines and the Security Compliance Toolkit for recommended configuration guidance. These are useful starting points, but an MSP should not present a generic baseline as proof of compliance with a client's industry requirements. ## Monitoring must map to an action A dashboard alone is not a managed service. Each alert needs an owner and response expectation. Useful Windows VPS monitoring for MSP clients includes: | Signal | Why it matters | |---|---| | CPU | Detect sustained workload pressure | | RAM | Catch memory exhaustion before sessions fail | | Disk free space | Prevent profile, database, backup, and export failures | | Backup status | Detect failed recovery jobs | | Windows services | Confirm business-critical services remain running | | RDS session count | Understand real concurrency | | Failed logins | Surface suspicious or broken access | | Event logs | Troubleshoot repeated OS or application failures | | Application logs | Identify problems before the client reports them | | Patch/restart status | Keep maintenance visible and controlled | For every signal, decide whether it creates a ticket, sends an alert, pages an engineer, or is only reviewed during scheduled maintenance. ## Documentation is what makes the service transferable The environment should not depend on the technician who built it. Each client record should contain: | Document | Minimum contents | |---|---| | Client workload summary | What the VM does and who depends on it | | VM specification | vCPU, RAM, storage, Windows version, region | | User/access model | Admins, users, RDS, RD Gateway, VPN/private access | | Licensing notes | Windows, RDS, SQL, and application licensing responsibilities | | Application inventory | Installed software, versions, vendor contacts, dependencies | | Backup policy | Frequency, retention, restore owner, last restore test | | Monitoring policy | Signals, thresholds, response owner | | Change log | Upgrades, incidents, migrations, major changes | | Recovery runbook | Steps to restore service | | Offboarding plan | Data export, credential removal, retention, server retirement | Store the recovery instructions somewhere accessible even when the client VM is unavailable. ![Checklist visual for MSPs managing Windows VPS client environments including sizing, access, backups, monitoring, security, and documentation](https://raff-images.s3.raffusercloud.com/msp_windows_vps_operational_checklist_webp_f9cad970ce.png) ## Choose the infrastructure provider around MSP operations MSPs should compare Windows providers on operational fit rather than only the lowest VM price. Ask: | Provider question | Why it matters to an MSP | |---|---| | Which Windows Server versions are available? | Client app support may depend on the OS version. | | Is Windows licensing clear? | Licensing confusion creates quoting and compliance risk. | | Do you get full administrator access? | MSPs need control of the client server. | | How is Remote Desktop access delivered? | Initial deployment and troubleshooting depend on it. | | Are backups/snapshots available? | Recovery should not require building everything from scratch. | | Can the VM be resized? | Client workloads change over time. | | Is migration assistance available? | Office-server replacement is often the actual project. | | Is infrastructure support available 24/7? | MSP escalation paths matter during incidents. | | Is pricing understandable month to month? | MSPs need predictable client margins. | | Can each client environment remain isolated? | Security, billing, and offboarding are cleaner. | This page should help an MSP make that operational decision without competing with Raff's broader Windows Server hub for generic “Windows Server hosting” searches. ## How Raff fits MSP client hosting Raff fits MSPs that want a Windows infrastructure provider underneath their own managed-service offer. The current Raff Windows VM service supports Windows Server 2019, 2022, and 2025, provides full administrator access through RDP, uses Microsoft SPLA licensing for Windows Server, and offers 24/7 infrastructure support. Raff also provides migration assistance for teams moving Windows workloads from another provider or local infrastructure. That means the MSP can focus on the client layer: applications, users, RDS, security policy, backups, monitoring, documentation, and support—while using Raff for the cloud Windows VM foundation. Raff should not be described as the MSP for the client. The cleaner model is: ```text Raff = Windows infrastructure layer MSP = managed service, client operations, applications, users, backups, monitoring, and support ``` That boundary makes it easier to package a repeatable client service and keep the end-customer relationship with the MSP. :::cta Deploy a Windows VM Deploy a Raff Windows VM when you are ready to build or migrate a client Windows environment. ::: ## MSP client environment checklist Before production, confirm: | Check | Done | |---|---| | Client workload and business owner documented | [ ] | | Application vendor support checked | [ ] | | Concurrent user count estimated | [ ] | | Windows Server version selected | [ ] | | VM size selected from workload, not company headcount | [ ] | | Admin access method documented | [ ] | | Staff RDS requirements reviewed | [ ] | | RDS CAL responsibility documented | [ ] | | Client environment isolated from unrelated customers | [ ] | | Firewall/security baseline applied | [ ] | | Backup frequency and retention defined | [ ] | | Restore owner and RPO/RTO defined | [ ] | | Restore test completed or scheduled | [ ] | | Monitoring signals and escalation path documented | [ ] | | Patch window agreed with client | [ ] | | Migration rollback plan written | [ ] | | App support boundary documented | [ ] | | Offboarding/export process documented | [ ] | If those items are repeatable, the MSP has a service model. If every answer is different for every client, the next step is standardization before scaling sales. ## What's next - [Remote Desktop server for business](/windows-server/remote-desktop-server-for-business) — use the broader business RDS guide when standardizing client Remote Desktop environments. - Read [Windows VPS sizing for remote users](https://rafftechnologies.com/windows-server/windows-vps-sizing-remote-users) before selecting client resources. - Read [Windows VPS for Multiple Offices](https://rafftechnologies.com/windows-server/windows-vps-multi-location-business) when a client has branch users. - Read [Windows VPS for Business Software](https://rafftechnologies.com/windows-server/windows-vps-for-business-software) for accounting, ERP, SQL, and legacy app planning. - Read [Windows VPS Backup Strategy for Small Businesses](https://rafftechnologies.com/windows-server/windows-vps-backup-strategy-small-business) before production onboarding. - Read [Remote Desktop Gateway vs Direct RDP](https://rafftechnologies.com/windows-server/remote-desktop-gateway-vs-direct-rdp) before standardizing remote access. - Read [RDS CAL Licensing on Windows Server](https://rafftechnologies.com/windows-server/rds-cal-licensing-guide) before multi-user Session Host deployments. - Read [Local Office Server to Cloud Windows VPS Migration](https://rafftechnologies.com/windows-server/local-server-to-cloud-windows-vps-migration) for office-server replacements. - Review [Remote Desktop VPS](/products/remote-desktop-vps) and [pricing](https://rafftechnologies.com/pricing) when quoting the infrastructure layer. ## Sources - Microsoft Learn — [Remote Desktop Services overview in Windows Server](https://learn.microsoft.com/en-us/windows-server/remote/remote-desktop-services/overview) - Microsoft Learn — [License Remote Desktop Services with Client Access Licenses](https://learn.microsoft.com/en-us/windows-server/remote/remote-desktop-services/rds-client-access-license) - Microsoft Learn — [Deploy Remote Desktop Gateway role for Remote Desktop Services](https://learn.microsoft.com/en-us/windows-server/remote/remote-desktop-services/remote-desktop-gateway-role) - Microsoft Learn — [Security baselines guide](https://learn.microsoft.com/en-us/windows/security/operating-system-security/device-management/windows-security-configuration-framework/windows-security-baselines) - Microsoft Learn — [Microsoft Security Compliance Toolkit](https://learn.microsoft.com/en-us/windows/security/operating-system-security/device-management/windows-security-configuration-framework/security-compliance-toolkit-10) - Raff — [Windows VM](https://rafftechnologies.com/products/windows-vm) - Raff — [Windows Server Hub](https://rafftechnologies.com/windows-server) - Raff — [Pricing](https://rafftechnologies.com/pricing) --- ### Windows VPS for Multiple Offices: Apps, Files & Remote Desktop URL: https://rafftechnologies.com/windows-server/windows-vps-multi-location-business Description: Learn when a Windows VPS fits a business with multiple offices, how to centralize Windows apps and files, and how to plan Remote Desktop, RDS licensing, security, backups, and migration. ## In short For a business with multiple offices, a Windows VPS can replace the pattern of keeping separate Windows servers, app installations, and file copies at each location. Users connect to one cloud-hosted Windows Server for shared business software, files, and Remote Desktop sessions, while IT manages one environment instead of several branch servers. Raff Technologies provides Windows VMs for this type of centralized workload. The model is a strong fit when two or more offices need the same Windows applications or data and have reliable internet access. It is a weaker fit when branch connectivity is unreliable, local files are extremely large, or the workload needs high availability beyond a single VM. The key design decisions are not the number of offices. They are **peak concurrent users, application behavior, remote-access method, licensing, latency, backup requirements, and recovery targets**. ## Quick verdict: when a Windows VPS fits multiple offices | Business situation | Windows VPS fit | Why | |---|---|---| | Two or more offices use the same Windows business app | Strong fit | One server keeps the app and data in one environment. | | Staff need the same desktop from office, home, and client sites | Strong fit with RDS planning | Users can work through centralized Remote Desktop sessions. | | Branches share files, reports, exports, or database-backed apps | Good fit | Data can stay close to the application instead of being copied between offices. | | The company is replacing an aging office server | Good fit | Removes dependency on hardware located in one branch. | | An MSP supports several locations | Good fit | One documented cloud environment is easier to standardize and support. | | Internet quality differs heavily between branches | Test first | Remote sessions depend on latency, packet loss, and ISP reliability. | | Staff move very large local files all day | Depends | Local or synchronized storage can be better for some workflows. | | The workload requires multi-server HA | Not a one-VM solution | Build redundancy rather than treating one VPS as highly available. | The strongest use case is a small or midsize team that needs **one Windows workspace for multiple offices** rather than separate servers in every location. :::cta Explore Windows VM Run one cloud-hosted Windows Server environment for shared apps, files, and remote access across multiple locations. ::: ## Why separate office servers become difficult to manage A branch server can work well when a company has one location. The problems usually appear after a second or third office is added. ![Comparison visual showing separate branch office servers versus one centralized Windows VPS for multi-location businesses](https://raff-images.s3.raffusercloud.com/branch_servers_vs_centralized_windows_vps_webp_b061c42f5e.png) | Separate-office problem | What users and IT experience | |---|---| | Different copies of the same files | Staff are unsure which version is current. | | App installs vary by location | Updates and troubleshooting become inconsistent. | | One office becomes the unofficial “main server” | Other branches depend on that office's power and internet. | | VPN rules accumulate over time | Access becomes harder to document and secure. | | Backups differ by branch | Some locations may be protected better than others. | | Hardware ages at different times | Replacement planning becomes unpredictable. | | Remote staff are handled as exceptions | Workarounds become the normal operating model. | | User offboarding is fragmented | Accounts and permissions can remain active in multiple systems. | Centralizing the shared workload does not eliminate administration, but it removes many branch-specific differences. ## What changes when multiple offices use one cloud Windows Server A Windows VPS moves the shared Windows environment out of a specific office and into a cloud-hosted VM. Branch staff, remote employees, and administrators then connect to the same environment through the access method you choose. ![Architecture visual showing multiple business locations accessing one Windows VPS for apps, files, and remote desktop sessions](https://raff-images.s3.raffusercloud.com/multi_location_windows_vps_access_architecture_webp_39feaabc89.png) | Area | Separate office-server model | Central Windows VPS model | |---|---|---| | Server location | One or more branches | Cloud-hosted Windows VM | | Business apps | Installed per office or on a branch server | Centralized on one Windows environment | | Files | Spread between PCs and office servers | Centralized where the workflow fits | | User access | LAN plus branch-specific VPN rules | RDP/RDS, RD Gateway, VPN, or app-specific access | | Backups | Different process at each location | One primary server and backup policy | | Scaling | Replace or upgrade local hardware | Resize the VM or split server roles | | IT support | Depends on physical office equipment | Support a consistent hosted environment | | Branch outage | Can take the local server offline | Other branches may continue if the server itself remains reachable | The cloud server still needs patching, user management, firewall rules, monitoring, backup testing, and application maintenance. Cloud hosting changes where the server runs; it does not make Windows Server self-managing. ## Remote Desktop hosting for multiple offices: what a Windows VPS does “Remote Desktop hosting” is a commercial search term, but it can describe several different services. A Windows VPS is the infrastructure layer: you receive a Windows Server VM and build the access model on top of it. A fully managed hosted-desktop service may also manage user desktops, RDS components, licensing operations, policies, and support. For a multi-location business, the distinction matters: | Option | You manage | Best fit | |---|---|---| | Windows VPS with admin RDP | Windows Server, security, apps, backups | One or two administrators | | Windows VPS with RDS | Session Host, licensing, users, policies, apps | Staff working inside shared Windows sessions | | Windows VPS with RD Gateway | Gateway, certificates, policies, RDS roles | Remote users connecting from multiple networks | | Fully managed hosted desktop | Provider manages more of the desktop stack | Teams that do not want to administer RDS | | SaaS/web application | Mostly app-level access | Users only need one browser-based application | Do not buy a larger VPS as a substitute for choosing the right access architecture. First decide whether staff need a full Windows desktop, a RemoteApp-style experience, a web application, or only file access. ## Design the access method before migrating apps Remote access should be decided before business software or shared data moves to the new server. | Access need | Recommended direction | |---|---| | One or two administrators maintain the VM | Restrict administrative RDP to trusted access paths. | | Staff need daily Windows desktop sessions | Plan Remote Desktop Services and RDS CALs. | | Users connect from many external networks | Consider RD Gateway or another controlled access layer. | | Users only need an internal web application | Publish the application instead of providing full desktop access. | | Users need Windows file shares | Use a controlled private/VPN access pattern or work inside RDS sessions. | | An MSP manages the environment | Standardize account, firewall, backup, and offboarding procedures. | Microsoft describes Remote Desktop Services as the Windows Server platform for delivering managed desktops and applications to users across office, home, branch, and partner locations. Microsoft also documents RD Gateway as a way to provide encrypted RDP access over HTTPS without exposing the internal RDP service directly to the internet. For a deeper comparison, read [Remote Desktop Gateway vs Direct RDP](https://rafftechnologies.com/windows-server/remote-desktop-gateway-vs-direct-rdp). ## RDS licensing matters when staff use the server as a workplace Administrative Remote Desktop access and multi-user staff access are not the same licensing scenario. Microsoft states that each user or device connecting to an RD Session Host running Windows Server needs an RDS Client Access License. RDS CALs are available in **Per User** and **Per Device** models. The right model depends on how employees and devices access the session host. Before rolling out staff sessions, answer these questions: 1. How many people will use the server? 2. Will one person connect from several devices, or will several people share the same device? 3. Is the Session Host joined to a domain or operating in a workgroup? 4. Which Windows Server version is running? 5. Who is responsible for deploying and tracking the licensing server and CALs? Do not treat RDS licensing as a task to solve after users are already dependent on the server. Review [RDS CAL Licensing on Windows Server](https://rafftechnologies.com/windows-server/rds-cal-licensing-guide) before production rollout. ## Size for concurrent users, not the number of offices A business with five offices might have only four people connected at once. A two-office accounting company might have 20 simultaneous sessions during month-end. The second workload is much heavier even though it has fewer locations. Use peak concurrency and workload type as the starting point. | Workload pattern | Starting point | Move up when | |---|---:|---| | 1-2 administrative users | 2 vCPU / 4 GB RAM | Business applications also run on the server. | | 3 light desktop users | 4 vCPU / 8 GB RAM | Sessions include many browser tabs, PDFs, or Office apps. | | 3 business-app users | 4 vCPU / 16 GB RAM | Accounting, tax, Access, or legacy apps run continuously. | | About 5 active users | 4 vCPU / 16 GB RAM | Multiple users remain signed in throughout the day. | | About 10 active users | 8 vCPU / 32 GB RAM | The VM becomes a shared daily workspace. | | Heavy ERP or SQL workload | 8-16 vCPU / 32-64 GB RAM | Database, reports, and user sessions compete for resources. | These are planning ranges, not guarantees. Application vendors, database size, report complexity, antivirus, user behavior, and background services can change the requirement significantly. Use [Windows VPS sizing for remote users](https://rafftechnologies.com/windows-server/windows-vps-sizing-remote-users) for a more detailed sizing workflow. :::cta View Pricing Compare Windows VM plans after estimating peak concurrent users, application load, memory, and storage requirements. ::: ## Shared business applications are often the best reason to centralize Multiple offices usually benefit most when they need the same stateful Windows application or database-backed workflow. | Workload | Why centralization can help | |---|---| | Accounting software | Staff use one application environment and data set. | | Tax software | Seasonal and branch users can connect to the same server. | | Microsoft Access applications | Front-end and data workflows can remain close to the server environment. | | ERP or inventory systems | Branches work against one operational system. | | Legacy Windows software | The application runs in one standardized Windows Server environment. | | SQL Server tools | Database administration and client software can be centralized. | | IIS / ASP.NET applications | Internal or customer-facing Windows web apps can run on the hosted server. | | Reporting software | Teams work from the same reports and exports. | A single Windows VPS can be a practical first architecture for a small team. As usage increases, separate the roles that are competing for resources—for example, Session Host, database, application server, or file server. If the goal is primarily to host existing Windows business software, see [Windows VPS for Business Software](https://rafftechnologies.com/windows-server/windows-vps-for-business-software). ## Shared files need a controlled design A cloud Windows Server can also act as a file server, but direct SMB access from arbitrary internet locations is not the design to aim for. | File pattern | Fit | |---|---| | Users work inside RDP/RDS sessions | Strong fit because application and files stay close together. | | Windows applications require shared paths | Good fit after application testing. | | Offices need one controlled folder structure | Good fit with permissions and backups. | | Users need file-level recovery | Good fit with a layered backup plan. | | Users want direct SMB from anywhere | Use a secure private access model instead. | | Users need real-time document collaboration | SaaS collaboration tools may be better. | | Teams transfer large media files continuously | Test latency and throughput before production. | Microsoft documents SMB as the Windows protocol used for network file sharing and provides features such as SMB signing and encryption. The practical rule is to keep file access behind a controlled network or session model rather than exposing Windows file sharing broadly. Read [Windows VPS as a Cloud File Server](https://rafftechnologies.com/windows-server/windows-vps-cloud-file-server) if shared folders are a primary requirement. ## Printing, scanners, and local devices can decide the project Infrastructure migrations often fail on a small operational detail rather than CPU or RAM. Before moving a branch application, test the peripherals users depend on. Check each location for: - local and network printers; - label printers and receipt printers; - document scanners; - USB license dongles; - local database connectors; - mapped drives and UNC paths; - accounting or tax-software print workflows; - browser-based hardware integrations. If a device requires direct local access, confirm how it behaves through RDP/RDS before the production cutover. Do not assume every local peripheral will redirect cleanly into a remote session. ## Backups are easier to standardize after centralization One major advantage of moving the shared workload out of several offices is that backup policy can be built around one primary server instead of several inconsistent branch systems. ![Layered visual showing backup and security planning for a multi-location Windows VPS workload](https://raff-images.s3.raffusercloud.com/multi_location_windows_vps_backup_security_stack_webp_1f674a06f5.png) A practical design can include: | Backup layer | Purpose | |---|---| | VM backup | Recover the complete Windows VM. | | Snapshot before major changes | Create a short-term rollback point before updates or migrations. | | File-level backup | Restore individual folders and documents. | | Application-aware backup | Protect databases and stateful business applications correctly. | | Off-server copy | Reduce dependence on one VM or account. | | Restore testing | Prove that the recovery procedure actually works. | Define recovery goals before migration: - **RPO** — how much recent data the business can afford to lose. - **RTO** — how long the business can operate without the server. A two-location accounting firm during a filing deadline may need a much tighter recovery target than a five-location company using the server only for periodic reports. Read [Windows VPS Backup Strategy for Small Businesses](https://rafftechnologies.com/windows-server/windows-vps-backup-strategy-small-business) before moving production data. :::cta Explore Data Protection Plan backups, snapshots, and tested recovery before multiple offices depend on one Windows server. ::: ## Security must cover every office and remote user Centralization reduces the number of servers but increases the importance of access controls on the central one. | Security area | Recommended control | |---|---| | User accounts | Use named accounts instead of shared credentials. | | Administration | Separate admin identities from daily user accounts. | | Remote access | Avoid broadly exposing direct RDP to the public internet. | | Firewall rules | Allow only the access paths the design requires. | | RDS / RD Gateway | Use a controlled remote-access architecture where appropriate. | | Permissions | Assign access through groups and least privilege. | | Backups | Restrict who can alter or delete recovery data. | | Patching | Schedule Windows and application updates. | | Logging | Review authentication failures and unusual access. | | Offboarding | Remove access promptly when a user leaves. | Every branch, laptop, home office, and administrator becomes part of the security boundary. A company network should not be treated as trusted simply because the device is physically inside an office. ## Network quality is part of Remote Desktop performance A Windows VPS can have enough CPU and RAM and still feel slow to one location if that branch has poor connectivity. Check each office for: | Network factor | User impact | |---|---| | Latency | Higher latency makes interactive sessions feel delayed. | | Packet loss | Can cause freezes, disconnects, and inconsistent performance. | | Upload capacity | Matters for scans, PDFs, and files sent to the server. | | Download capacity | Matters for retrieved files and session data. | | Wi-Fi quality | Poor local wireless can look like a server problem. | | Firewall policy | Can block or interrupt remote-access traffic. | | ISP reliability | A branch internet outage disconnects that office even if the VPS is healthy. | Test from every office before cutover. If four branches perform well and one does not, investigate the local network before resizing the server. Use [RDP Performance Tuning](https://rafftechnologies.com/windows-server/rdp-performance-tuning) when troubleshooting client, network, display, and server-side bottlenecks. ## Migrate one location or user group at a time A multi-office migration should prove the workflow before every branch depends on it. 1. Inventory servers, applications, files, users, printers, and locations. 2. Identify the office that currently hosts the main data or application. 3. Measure peak concurrent users across all sites. 4. Choose the remote-access model. 5. Confirm application vendor support and RDS licensing requirements. 6. Create the Windows VPS. 7. Install and configure business applications. 8. Move non-production data first. 9. Configure security and backups. 10. Test a restore before production. 11. Test from every office, including printing and file workflows. 12. Move a small pilot group first. 13. Schedule the production cutover outside peak hours. 14. Keep a documented rollback path until the new environment is proven. 15. Review CPU, memory, disk, session count, and user feedback after migration. If you are replacing an existing branch server, use [Local Server to Cloud Windows VPS Migration](https://rafftechnologies.com/windows-server/local-server-to-cloud-windows-vps-migration) and [Cloud Windows Server vs Local Office Server](https://rafftechnologies.com/windows-server/cloud-windows-server-vs-local-office-server) as the next planning steps. ## When one Windows VPS is not enough Do not force every multi-location workload onto a single VM. | Situation | Better direction | |---|---| | Many users run heavy desktop sessions | Split roles or design a larger RDS environment. | | Database workload is resource-intensive | Separate the database from user sessions. | | Downtime must be minimal | Design redundancy and recovery instead of one server. | | Branch internet is unreliable | Improve connectivity or preserve a local fallback workflow. | | Very large files are location-specific | Consider local storage, synchronization, or another data architecture. | | Compliance requirements are strict | Review logging, retention, access, and data-location requirements first. | | Software vendor does not support hosted/RDS deployment | Follow the vendor-supported architecture. | | The company wants desktops fully managed | Compare managed desktop or VDI services. | The Windows VPS should solve a specific centralization problem. It should not become a single point where unrelated server roles accumulate indefinitely. ## How Raff fits a multi-office Windows workload Raff is a fit when the business or MSP wants the Windows VM infrastructure and plans to manage the Windows Server environment, applications, users, licensing, backups, and security around it. A common path is: 1. deploy a Raff Windows VM; 2. install the required Windows business software; 3. choose administrative RDP, RDS, RD Gateway, VPN, or application-specific access; 4. centralize only the files and data that belong with the workload; 5. configure backups and security before production; 6. test from every branch; 7. resize or split roles when actual usage requires it. Raff should not be positioned as a substitute for a complete RDS, VDI, Active Directory, or high-availability design. For a small team that needs one cloud-hosted Windows environment across several offices, however, a Windows VM can be a straightforward infrastructure starting point. :::cta Deploy Windows Now Create a Raff Windows VM when your team is ready to test a centralized Windows environment across multiple offices. ::: ## Recommended next step by business type | Business type | Practical next step | |---|---| | Two-office small business | Test one Windows VPS with real users from both locations. | | Multi-location accounting firm | Validate app support, RDS licensing, printing, and backups before cutover. | | Retail or branch company | Centralize back-office apps first; test local device dependencies separately. | | Tax firm with seasonal staff | Size for peak-season concurrency, not the quietest month. | | MSP-managed customer | Standardize access, monitoring, backup, and offboarding documentation. | | Legacy Windows app user | Test the application over RDP/RDS before migrating production data. | | File-heavy business | Benchmark file transfer and interactive performance from every branch. | | Compliance-heavy organization | Review controls and recovery requirements before choosing the architecture. | The safest first move is a test server with representative users from each location. Confirm login, application launch, printing, file access, backup, and restore before the old office-server workflow is retired. ## What's next - [Windows VPS for small business](/windows-server/windows-vps-small-business) — use the broader SMB guide when planning a centralized Windows environment for multiple offices. - Read [Windows VPS sizing for remote users](https://rafftechnologies.com/windows-server/windows-vps-sizing-remote-users) before choosing CPU and memory. - Read [Cloud Windows Server vs Local Office Server](https://rafftechnologies.com/windows-server/cloud-windows-server-vs-local-office-server) if you are replacing branch hardware. - Read [Windows VPS Backup Strategy for Small Businesses](https://rafftechnologies.com/windows-server/windows-vps-backup-strategy-small-business) before moving production data. - Read [Remote Desktop Gateway vs Direct RDP](https://rafftechnologies.com/windows-server/remote-desktop-gateway-vs-direct-rdp) before choosing external access. - Read [Windows VPS as a Cloud File Server](https://rafftechnologies.com/windows-server/windows-vps-cloud-file-server) if shared folders are part of the plan. - Read [Windows VPS for Business Software](https://rafftechnologies.com/windows-server/windows-vps-for-business-software) for application-hosting decisions. - Read [RDS CAL Licensing on Windows Server](https://rafftechnologies.com/windows-server/rds-cal-licensing-guide) before staff use Session Host desktops. - Review [Raff Windows VM](https://rafftechnologies.com/products/windows-vm) and [pricing](https://rafftechnologies.com/pricing) when you are ready to test the production size. ## Sources - Microsoft Learn — [Remote Desktop Services overview in Windows Server](https://learn.microsoft.com/en-us/windows-server/remote/remote-desktop-services/overview) - Microsoft Learn — [Remote Desktop Services roles](https://learn.microsoft.com/en-us/windows-server/remote/remote-desktop-services/rds-roles) - Microsoft Learn — [License Remote Desktop Services with Client Access Licenses](https://learn.microsoft.com/en-us/windows-server/remote/remote-desktop-services/rds-client-access-license) - Microsoft Learn — [License Remote Desktop session hosts](https://learn.microsoft.com/en-us/windows-server/remote/remote-desktop-services/rds-license-session-hosts) - Microsoft Learn — [What is SMB File Sharing for Windows and Windows Server?](https://learn.microsoft.com/en-us/windows-server/storage/file-server/file-server-smb-overview) - Microsoft Learn — [SMB features in Windows and Windows Server](https://learn.microsoft.com/en-us/windows-server/storage/file-server/smb-feature-descriptions) - Raff — [Windows VPS sizing for remote users](https://rafftechnologies.com/windows-server/windows-vps-sizing-remote-users) - Raff — [Cloud Windows Server vs Local Office Server](https://rafftechnologies.com/windows-server/cloud-windows-server-vs-local-office-server) - Raff — [Windows VPS Backup Strategy for Small Businesses](https://rafftechnologies.com/windows-server/windows-vps-backup-strategy-small-business) - Raff — [Remote Desktop Gateway vs Direct RDP](https://rafftechnologies.com/windows-server/remote-desktop-gateway-vs-direct-rdp) - Raff — [Windows VM product page](https://rafftechnologies.com/products/windows-vm) - Raff — [Pricing](https://rafftechnologies.com/pricing) --- ### Windows VPS for Property Management Companies: Apps, Files, and Remote Access URL: https://rafftechnologies.com/windows-server/windows-vps-property-management-companies Description: Learn when a Windows VPS fits property management companies that need shared business applications, lease and owner records, maintenance workflows, accounting access, backups, and remote teams. A Windows VPS for property management companies can centralize supported Windows business applications, accounting tools, lease and owner records, maintenance documents, reports, shared folders, and remote user sessions in one cloud-hosted Windows Server environment. It is strongest for small and midsize property managers that still depend on Windows-based software, mapped drives, local databases, shared documents, or an aging office server. It is less useful when the company already runs entirely on vendor-hosted browser applications and cloud document platforms. Raff Technologies provides the Windows VM infrastructure. The property management company or its MSP remains responsible for application compatibility, software licensing, Remote Desktop Services licensing, user permissions, database administration, backups, security, migration, and recovery. This article is different from [Windows VPS for Real Estate Offices](https://rafftechnologies.com/windows-server/windows-vps-real-estate-offices). The real estate article focuses on brokerage and transaction workflows. This guide focuses on recurring property operations: leases, rent and owner reporting, maintenance coordination, vendor records, property-level permissions, and multi-location staff access. :::cta Explore Windows VM Centralize property apps, records, users, and reporting on Windows. ::: ## Quick verdict: when a Windows VPS fits property management Use this table before moving a property management workload to a Windows VPS. | Property management situation | Windows VPS fit | Why | |---|---|---| | The core application supports Windows Server or RDS | Strong fit after vendor confirmation | The app, database, reports, and users can share one hosted environment. | | Managers, accountants, and maintenance coordinators work remotely | Strong fit | Authorized users can reach the same Windows environment from different locations. | | Lease, owner, vendor, and property files are scattered | Strong fit | Shared folders and permissions can be centralized. | | An aging office server hosts property or accounting software | Strong fit after dependency review | The workload can move away from one physical machine. | | Several offices manage the same properties | Strong fit with connectivity planning | Teams can work from one controlled environment. | | The company uses desktop accounting alongside property software | Good fit | Accounting tools, reports, exports, and files can remain close together. | | Check printing, document scanning, or local printers are critical | Test before production | Driver, redirection, security, and workflow behavior vary. | | The main property platform is already vendor-hosted SaaS | Depends | A Windows VPS may only be useful for accounting, files, legacy tools, or integrations. | | The vendor prohibits hosted or multi-user deployment | Poor fit | Use a supported deployment model. | | The business needs application-level high availability | Not a single-VM decision | Design redundancy, database recovery, and failover separately. | The strongest candidate is a residential, commercial, or mixed-property management company that needs one controlled Windows environment for staff, business applications, records, reports, and backups. The goal is not to move every process into Remote Desktop. The goal is to centralize the Windows workloads that are currently difficult to secure, support, and recover. ## Why property management companies outgrow office-based systems Many property management companies begin with a practical setup: one office server, a shared drive, desktop accounting software, a property application, and several staff PCs. That model becomes harder to manage as the portfolio, team, and document volume grow. | Common problem | What it looks like in practice | How a Windows VPS can help | |---|---|---| | Property software is tied to one office | Remote staff depend on VPN workarounds or office PCs | A supported application can run in one cloud-hosted Windows environment. | | Files are organized differently by employee | Lease, inspection, owner, and vendor records are difficult to find | Shared folders and permissions can be standardized. | | Accounting and property data are separated | Staff export and email files between departments | Applications and approved shared folders can remain close together. | | The office server is aging | Hardware, power, storage, and warranty risks increase | The workload moves away from one physical server. | | Several branches maintain separate copies | Property records and reports become inconsistent | Users can work from one controlled environment. | | Former employees retain access or copies | Offboarding is incomplete | Named users and central permissions are easier to review. | | Backups are unclear | Nobody can prove that the application or database can be restored | Backup layers and restore tests can be documented. | | Growth requires another server purchase | More users, properties, reports, and documents increase load | A VM can be resized and storage can be expanded. | The business benefit is not simply replacing an office server with a cloud server. It is giving property managers, accounting staff, leasing teams, maintenance coordinators, and administrators one controlled place to reach the applications and records they use every day. ## Property management workloads that fit a Windows VPS ### Property management and accounting applications A Windows VPS can host property management or accounting software when the vendor supports the operating system, hosted deployment, database, and multi-user access model. Potential workloads include: - property and unit records; - tenant or resident records; - owner records; - lease administration; - charges and payment records; - accounts receivable and payable; - owner statements; - general ledger and financial reports; - security deposit records; - vendor records; - maintenance costs; - property budgets; - bank reconciliation tools; - year-end exports; - custom reports; - document generation. Do not assume that every desktop property application supports Windows Server or Remote Desktop Services. Confirm the exact version, database engine, licensing model, and support terms with the vendor before migration. When accounting is the primary workload, read [Windows VPS for Accounting Firms](https://rafftechnologies.com/windows-server/windows-vps-accounting-firms). ### Lease, owner, property, and vendor documents Property management companies generate a large volume of operational records. A Windows VPS can centralize: - leases and amendments; - owner agreements; - property and unit documents; - move-in and move-out records; - inspection reports; - maintenance photos and attachments; - vendor contracts; - invoices and purchase records; - insurance certificates; - notices and correspondence; - property reports; - owner statements; - bank and accounting exports; - archived tenant records; - templates and forms. Moving a disorganized file structure to the cloud does not fix it. Clean up duplicate folders, naming rules, property codes, access groups, retention requirements, and archive ownership before migration. Read [Windows VPS as a Cloud File Server](https://rafftechnologies.com/windows-server/windows-vps-cloud-file-server) when shared files are the main problem. ### Maintenance and work-order administration A Windows VPS can support the administrative side of maintenance operations when the software is compatible. Potential uses include: - work-order entry; - assignment and scheduling; - vendor contact records; - estimate and invoice review; - property notes; - maintenance history; - recurring maintenance schedules; - purchase approvals; - inspection records; - photos and attachments; - cost reporting; - exported work lists. Mobile maintenance applications and vendor portals may remain separate SaaS systems. The Windows VPS can still host the back-office application, reporting tools, accounting integration, or shared records when the workflow supports it. ### Owner reporting and month-end work Month-end can create more server load than normal daily use. The environment may need to process: - owner statements; - property-level income statements; - rent-roll reports; - delinquency reports; - accounts payable batches; - bank reconciliation; - management fee calculations; - vendor payment reports; - general ledger exports; - PDF generation; - spreadsheet exports; - archived report packages. Size for reporting peaks, database activity, and PDF or spreadsheet generation, not only the number of people who can log in. ### Remote and multi-location staff Property management work is often distributed across a main office, leasing locations, property sites, home offices, and external accounting or IT support. A centralized Windows VPS can give authorized users access to the same: - supported property application; - accounting tools; - reports; - shared folders; - templates; - property records; - vendor documents; - maintenance records; - archived files; - administrative utilities. Use named accounts and role-based permissions. Property managers, accountants, leasing staff, maintenance coordinators, executives, and IT providers should not automatically receive the same desktop or folder access. Read [Windows VPS for Multi-Location Small Businesses](https://rafftechnologies.com/windows-server/windows-vps-multi-location-business) for the broader branch-office model. ## A practical property management architecture A small or midsize property management company may use this pattern: ![Property managers, accounting staff, leasing teams, maintenance coordinators, and remote staff accessing applications, files, databases, permissions, and backups through a Windows VPS](https://raff-images.s3.raffusercloud.com/property_management_windows_vps_architecture_png_bb5e5d7b45.png) The cloud Windows environment becomes the shared business workspace. Browser-based services and local devices remain separate where that design is safer or better supported. A good architecture answers seven questions: 1. Which application is the source of truth for property and financial records? 2. Which users need a full desktop, a RemoteApp, or only shared files? 3. Which integrations require local software or a service account? 4. Which documents must remain close to the application? 5. Which printers, scanners, or check-printing devices are business-critical? 6. What happens when an office or property site loses internet access? 7. Who owns recovery when the application, database, integration, or server fails? ## Remote Desktop access should follow job roles Microsoft describes Remote Desktop Services as a Windows Server platform for delivering managed desktops and applications to users in offices, homes, branches, and partner locations. A property management company should design access around the actual job. | User role | Likely access need | |---|---| | Owner or executive | Portfolio reports, approvals, financial visibility, and dashboards | | Property manager | Property records, leases, work orders, vendor information, and reports | | Accounting team | Receivables, payables, bank reconciliation, owner statements, and exports | | Leasing staff | Unit records, applicant or tenant documents, templates, and approved reports | | Maintenance coordinator | Work orders, vendor records, schedules, costs, and attachments | | Administrative staff | Shared documents, forms, reports, and data entry | | External accountant | Restricted accounting access for an approved period | | MSP or IT provider | Administration, patching, monitoring, backups, and recovery | If employees use an RD Session Host for daily desktop or RemoteApp sessions, Microsoft requires an appropriate RDS Client Access License for each connecting user or device. Administrative sessions are not a substitute for a licensed multi-user environment. Use these related guides: - [Remote Desktop Server for Business](https://rafftechnologies.com/windows-server/remote-desktop-server-for-business) - [Windows VPS for Remote Employees](https://rafftechnologies.com/windows-server/windows-vps-remote-employees) - [Remote Desktop Gateway vs Direct RDP](https://rafftechnologies.com/windows-server/remote-desktop-gateway-vs-direct-rdp) - [RDS CAL Licensing on Windows Server](https://rafftechnologies.com/windows-server/rds-cal-licensing-guide) :::cta Talk to Windows Engineer Plan users, applications, integrations, storage, backups, and migration first. ::: ## Printers, scanners, check printing, and integrations need testing A migration can be technically successful while daily office workflows still fail. Property management teams may depend on: - office printers; - PDF printers; - document scanners; - check printers; - MICR-capable printing workflows; - signature pads; - USB licensing devices; - local email clients; - browser extensions; - document-signing tools; - payment portals; - banking portals; - watched folders; - local export or import utilities; - spreadsheet templates; - service accounts and scheduled tasks. Remote Desktop can redirect some printers, drives, clipboard content, and other resources, but policy, client settings, drivers, application behavior, and the device communication method affect the result. Test the complete business process, not only whether Windows detects the device. | Dependency | Acceptance test | |---|---| | Office printer | Correct queue, paper size, duplex settings, speed, and user access | | PDF workflow | Correct file name, save location, permissions, and application attachment behavior | | Document scanner | TWAIN or WIA requirement, multi-page scans, resolution, naming, and upload path | | Check printing | Approved printer, paper, alignment, security controls, and accounting-software support | | Signature device | Vendor support, redirection method, and session behavior | | Payment or bank portal | Browser compatibility, authentication, export or upload workflow, and user role | | Email integration | Supported client, SMTP or API settings, attachment behavior, and service account | | Document signing | Browser or desktop requirement, file path, and final document storage | | Scheduled export | Service account, file path, schedule, error handling, and duplicate prevention | | Application integration | Supported API, ODBC, file transfer, service, or vendor-approved method | Do not weaken security controls only to make an old workflow function. When a local device or integration cannot be supported safely, keep that component local or replace the workflow. ## Application databases and integrations determine real performance The visible desktop application may not be the main resource consumer. Database queries, owner reports, payment imports, document generation, and month-end jobs can create more load than user sessions. Document: - database engine and version; - database size and monthly growth; - number of properties and units; - peak concurrent users; - reporting peaks; - payment and bank imports; - accounting exports; - scheduled jobs; - integrations and APIs; - ODBC connections; - service accounts; - file paths and mapped drives; - document-generation tools; - transaction-log growth; - database recovery model; - backup windows; - restore process. Keep the application and database close to each other. Avoid placing a file-based database across a wide-area network path. If the database becomes large or business-critical, consider separating Remote Desktop, application, and database roles. SQL Server backup and restore planning must match the database recovery model. A VM-level backup alone does not replace application-aware database protection. ## Size for concurrent users and peak reporting Do not size a property management Windows VPS by total employee count. Size it by concurrent sessions, application requirements, database activity, reports, integrations, and file growth. Use the following only as initial test ranges: | Workload | Initial test size | Increase resources when | |---|---:|---| | One administrator or reporting user | 2 vCPU / 4 GB RAM | The app, browser, PDF tools, and reports compete for memory | | 2-3 light office users | 4 vCPU / 8 GB RAM | Several sessions and documents stay open together | | 3-5 active business users | 4 vCPU / 16 GB RAM | Property app, accounting, database, and reports share one VM | | 6-10 active users | 8 vCPU / 32 GB RAM | The server becomes a daily shared workspace | | SQL-backed property or accounting platform | 8-16 vCPU / 32-64 GB RAM | Database working set, reports, imports, and integrations need more capacity | | Document-heavy portfolio | Size storage separately | Leases, inspections, invoices, photos, and reports grow quickly | | High-availability requirement | Multi-server assessment | One VM does not provide application-level failover | For a five-user office, 4 vCPU and 16 GB RAM can be a reasonable test starting point. It is not a performance guarantee. Raff's current sizing documentation recommends dedicated CPU plans for Windows responsiveness and lists 4 vCPU / 8 GB as the starting infrastructure plan for a light multi-user RDP terminal server. Property management workloads commonly need more memory once accounting tools, databases, browsers, PDFs, and reports run together. Measure during representative workflows: - user logon time; - application launch time; - property or tenant lookup time; - posting and save time; - owner statement generation; - rent-roll report duration; - bank or payment import duration; - PDF generation; - CPU peaks; - available memory; - disk latency; - database waits; - backup duration; - session disconnects; - storage growth. Read [Windows VPS Sizing for Remote Users](https://rafftechnologies.com/windows-server/windows-vps-sizing-remote-users) before choosing a production plan. ## Plan storage around records, profiles, and growth Property management environments can grow faster than expected because application data and documents expand at different rates. Plan capacity for: - Windows and application installation; - property management database; - accounting database; - transaction logs; - lease and owner documents; - inspection files and photos; - vendor invoices and contracts; - maintenance attachments; - statements and reports; - scanned documents; - user profiles; - temporary PDF and export files; - integration logs; - backup staging; - migration copies; - 12 to 24 months of growth. Keep the operating system, database, documents, and backups logically separated where the application supports it. Raff Volumes can add block storage that outlives the VM, but volume layout and backup scope should be designed before moving production data. ## Security must protect property, financial, and personal records A property management Windows environment may contain personal contact information, lease records, owner records, financial data, bank exports, vendor information, maintenance records, credentials, and remote-access pathways. Minimum controls include: | Security area | Planning requirement | |---|---| | Identities | Named users, strong authentication, and prompt offboarding | | Administration | Separate privileged accounts from daily user accounts | | Remote access | Use controlled RDS, RD Gateway, VPN, or private-access design | | Firewall | Permit only required ports and sources | | Permissions | Limit access by role, property, department, or responsibility | | Shared folders | Use groups and least privilege instead of broad access | | Service accounts | Document purpose, ownership, permissions, and credential rotation | | Updates | Plan Windows, application, browser, and integration maintenance | | Logging | Review failed logons, account changes, and unusual access | | Backups | Protect backup deletion rights and recovery credentials | | Vendor access | Make access approved, time-bound, and monitored where possible | | Documentation | Record owners, dependencies, recovery order, and support contacts | Do not expose unrestricted RDP, SMB, or database ports directly to the public internet. Microsoft recommends blocking inbound SMB from the internet and using segmentation and controlled access for file-sharing traffic. Microsoft's Windows Server security baselines provide a standardized hardening starting point, but baseline changes can affect legacy applications and must be tested before production. This article is not legal, privacy, payment-security, housing, or compliance advice. Review applicable requirements with qualified advisers and the relevant software vendors. Read [Windows Server Hardening Checklist](https://rafftechnologies.com/windows-server/windows-server-hardening-checklist) before production rollout. ## Backups must protect the server, database, files, and recovery process A property management backup plan needs more than a copy of the Windows disk. Use layered protection: | Protection layer | Purpose | |---|---| | Application-aware database backup | Protect property, accounting, payment, and reporting data correctly | | File backup | Recover deleted or changed leases, reports, invoices, and records | | VM backup | Recover the broader Windows environment | | Snapshot before change | Create a short-term rollback point before updates or migration | | Off-server copy | Reduce risk from server, account, or ransomware incidents | | Retention policy | Preserve recovery points for the required business period | | Restore test | Prove that applications, data, permissions, and workflows are usable | | Recovery documentation | Preserve owners, credentials, sequence, dependencies, and contacts | A successful backup notification does not prove the operation can resume. Restore the database to a test environment. Open the property application. Confirm property, lease, owner, and accounting records. Generate an owner statement. Open shared documents. Validate permissions, integrations, scheduled jobs, and printing. Raff VMs support point-in-time snapshots and automated daily or weekly backup schedules with configurable retention. Application owners still need to define database protection, file-level recovery, off-server copies, and restore procedures. Read [Windows VPS Backup Strategy for Small Businesses](https://rafftechnologies.com/windows-server/windows-vps-backup-strategy-small-business) before moving production records. :::cta Explore Data Protection Protect property applications, databases, documents, and recovery points. ::: ## Internet outages and business continuity need a fallback A cloud-hosted Windows environment depends on connectivity from the office or property site. Define what happens when users cannot reach the server. Possible fallback measures include: - a secondary office internet connection; - cellular failover; - locally available emergency contact information; - locally stored building and vendor emergency procedures; - approved manual maintenance intake; - a process for recording payments or documents for later entry; - offline copies of critical property instructions; - a reconciliation process after connectivity returns; - a defined point at which financial or data-entry work pauses. Do not assume mobile data is a recovery plan until it has been tested from the actual office. Signal strength, carrier congestion, VPN behavior, firewall rules, and data limits can change the result. The business should know whether a one-hour outage delays reporting, blocks leasing administration, stops payment posting, prevents maintenance coordination, or halts the whole office. That impact determines the connectivity and recovery design. ## Migration should start with discovery and one bounded workflow A property management migration is safer when the first phase has a clear scope. ### 1. Inventory the current environment Document: - applications and versions; - databases; - users and groups; - properties, units, and portfolio size; - file shares and permissions; - mapped drives; - printers and scanners; - check-printing workflow; - email and document-signing integrations; - payment and banking exports or imports; - scheduled tasks and services; - ODBC connections; - service accounts; - storage usage and growth; - backup jobs; - remote offices and home users; - recovery requirements; - vendor and MSP contacts. ### 2. Classify every dependency Mark each item as: - cloud candidate; - local office dependency; - browser-based external service; - integration between systems; - unsupported or unknown; - replacement candidate. Unknown dependencies should block production cutover until they are tested. ### 3. Confirm vendor and licensing support Ask the application vendor: - Is Windows Server supported? - Is virtual or hosted deployment supported? - Is Remote Desktop Services supported? - Which database edition and version are required? - Are multiple concurrent users supported? - Are printers, scanners, check printing, and PDF workflows supported remotely? - Does the product require a USB device, local service, or desktop Office installation? - Are payment, bank, email, and document-signing integrations supported? - Will the vendor support the application after migration? ### 4. Build a parallel test environment Create a test Windows VPS, install the software, restore a copy of the data, and create non-administrator accounts for representative roles. Test from the office, home, branch, and external accountant or MSP networks where applicable. ### 5. Validate complete workflows Test: - login and authentication; - application launch; - property and tenant lookup; - lease and document access; - charge or payment entry using test data; - owner statement generation; - rent-roll and financial reports; - invoice entry and approval; - work-order entry; - PDF generation; - printing and scanning; - check printing where applicable; - payment and bank imports or exports; - email and document-signing workflow; - file open and save; - scheduled jobs; - backup; - database restore; - loss of connectivity; - rollback. ### 6. Schedule a low-risk cutover Avoid month-end, owner reporting periods, major portfolio onboarding, rent-processing peaks, or other critical business windows. Run the final backup and data synchronization. Validate the destination. Release users in a controlled order. Keep the previous environment available until the business owner, application owner, accounting owner, and IT owner approve the new workflow. ### 7. Monitor the first operating cycle Track performance and support issues through a normal reporting, accounting, maintenance, and leasing cycle. Monitor: - CPU and memory; - disk capacity and latency; - database performance; - session disconnects; - application errors; - printing and scanning issues; - integration failures; - backup success; - restore readiness; - support tickets; - user feedback. Use the [Windows Server Migration Checklist for Small Businesses](https://rafftechnologies.com/windows-server/windows-server-migration-checklist-small-business) and [Local Office Server to Cloud Windows VPS Migration](https://rafftechnologies.com/windows-server/local-server-to-cloud-windows-vps-migration) before production cutover. ## When a Windows VPS is not the right fit A Windows VPS should not be forced into every property management workflow. | Situation | Better next step | |---|---| | The company already uses a complete vendor-hosted SaaS platform | Use the SaaS platform unless another Windows workload justifies a server | | The vendor prohibits Windows Server, cloud, or RDS deployment | Use the supported model or replace the application | | Critical workflow depends on unsupported local hardware | Keep the dependent component local or redesign the workflow | | Internet outages cannot interrupt office work | Preserve local capability or build tested connectivity redundancy | | Check printing cannot be secured or supported remotely | Keep the approved printing workflow local | | The database requires high availability | Design database redundancy and failover rather than relying on one VM | | Security ownership is undefined | Assign access, patching, backup, and incident owners first | | Restore testing cannot be completed | Keep the environment in test status | | Users only need browser applications and cloud documents | Avoid adding Windows infrastructure without a clear benefit | | No one owns application vendor support | Resolve support responsibility before migration | The right answer may be SaaS, Windows VPS, local server, or a hybrid design. Place each workload where it can be supported and recovered. ## How Raff supports property management workloads Raff fits property management companies that need a cloud-hosted Windows Server foundation for supported business applications, accounting, shared documents, remote users, multi-location access, and replacement of an aging office server. Raff Windows VMs provide selectable Windows Server templates, Administrator and RDP access, dedicated or shared CPU plan families, SSD storage, optional attached Volumes, snapshots, automated backups, security groups, VPC networking, performance metrics, VM resizing, and human support. The property management company or its MSP remains responsible for: - application compatibility; - vendor licensing; - RDS licensing; - user roles and offboarding; - database administration; - printer and scanner testing; - check-printing controls; - payment, bank, email, and signing integrations; - backup retention; - restore testing; - Windows and application updates; - security hardening; - migration and rollback; - business continuity; - legal and compliance decisions. Raff should be the infrastructure layer under a documented property management workflow, not a shortcut around vendor support, licensing, security, or recovery planning. ## Recommended path by property management situation | Situation | Recommended path | |---|---| | One office has an aging property-management server | Test the application, database, users, documents, backups, and restore on one Windows VPS | | Managers and accounting staff need remote access | Use a controlled RDS or remote-access design with named users and licensing | | Several offices manage the same portfolio | Centralize the supported application, then test every site's connectivity and workflow | | Shared property documents are the main problem | Use a structured file-server design with permissions and backup | | Accounting and property software run together | Size around month-end reporting, database memory, and exports | | Printers, scanners, and checks are critical | Test exact models, drivers, permissions, and user sessions before cutover | | The main property platform is SaaS | Use a Windows VPS only for workloads SaaS does not solve | | SQL Server drives performance | Size around database memory, reports, jobs, and recovery requirements | | High availability is mandatory | Evaluate a multi-server application and database architecture | ## Final property management Windows VPS checklist Before putting the environment into production, confirm: | Check | Done | |---|---| | Applications and versions inventoried | ☐ | | Vendor support for Windows Server confirmed | ☐ | | Hosted and RDS licensing reviewed | ☐ | | Active users and roles documented | ☐ | | Properties, units, and reporting peaks documented | ☐ | | Database requirements documented | ☐ | | Shared folders and permissions planned | ☐ | | Lease, owner, vendor, and maintenance records classified | ☐ | | Printers and PDF workflows tested | ☐ | | Scanners tested | ☐ | | Check-printing workflow reviewed | ☐ | | Payment, bank, email, and signing integrations tested | ☐ | | Service accounts and scheduled jobs documented | ☐ | | Network flows and firewall rules documented | ☐ | | Internet-outage fallback tested | ☐ | | CPU, RAM, and storage starting point selected | ☐ | | Storage growth estimated | ☐ | | Application-aware database backups configured | ☐ | | File-level and off-server recovery copies planned | ☐ | | File, database, and application restores tested | ☐ | | Migration window approved | ☐ | | Rollback path documented | ☐ | | System, accounting, security, and recovery owners named | ☐ | | Old environment retained until final approval | ☐ | An incomplete checklist means the system is still a test environment. ## What's next - [Windows VPS for small business](/windows-server/windows-vps-small-business) — use the broader SMB decision guide when planning property-management application hosting. A Windows VPS for property management companies works best when the business centralizes supported Windows applications and records, tests local devices and integrations, and proves that backups can restore the complete workflow. Read [Windows VPS for Real Estate Offices](https://rafftechnologies.com/windows-server/windows-vps-real-estate-offices) for brokerage and transaction workflows. Review [Windows VPS for Accounting Firms](https://rafftechnologies.com/windows-server/windows-vps-accounting-firms) when accounting software is the main workload. Use [Windows VPS as a Cloud File Server](https://rafftechnologies.com/windows-server/windows-vps-cloud-file-server) when shared property documents are the main problem. Explore [Raff Windows VM](https://rafftechnologies.com/products/windows-vm) when the users, applications, database, devices, storage, backups, and migration path are documented well enough to build a test environment. :::cta Deploy Windows Now Build a test environment for your property management workload. ::: ## Sources - Microsoft Learn — [Remote Desktop Services overview in Windows Server](https://learn.microsoft.com/en-us/windows-server/remote/remote-desktop-services/overview) - Microsoft Learn — [Remote Desktop Services roles](https://learn.microsoft.com/en-us/windows-server/remote/remote-desktop-services/rds-roles) - Microsoft Learn — [Install Remote Desktop Services client access licenses](https://learn.microsoft.com/en-us/windows-server/remote/remote-desktop-services/rds-install-cals) - Microsoft Learn — [Printer redirection and drive redirection troubleshooting](https://learn.microsoft.com/en-us/troubleshoot/windows-server/printing/printer-hard-drive-not-redirect-to-remote-desktop-session) - Microsoft Learn — [Secure SMB Traffic in Windows Server](https://learn.microsoft.com/en-us/windows-server/storage/file-server/smb-secure-traffic) - Microsoft Learn — [SMB security hardening](https://learn.microsoft.com/en-us/windows-server/storage/file-server/smb-security-hardening) - Microsoft Learn — [Configure Security Baselines for Windows Server 2025](https://learn.microsoft.com/en-us/windows-server/security/osconfig/osconfig-how-to-configure-security-baselines) - Microsoft Learn — [Recovery models for SQL Server](https://learn.microsoft.com/en-us/sql/relational-databases/backup-restore/recovery-models-sql-server) - Microsoft Learn — [Full database backups for SQL Server](https://learn.microsoft.com/en-us/sql/relational-databases/backup-restore/full-database-backups-sql-server) - Raff Docs — [Virtual Machines](https://docs.rafftechnologies.com/products/build/virtual-machines) - Raff Docs — [Plans and sizing](https://docs.rafftechnologies.com/products/build/virtual-machines/concepts/plans-and-sizing) - Raff Docs — [Virtual Machine features and limits](https://docs.rafftechnologies.com/products/build/virtual-machines/details/features-and-limits) - Raff Docs — [Enable backups](https://docs.rafftechnologies.com/products/build/virtual-machines/quickstart-guides/enable-backups) - Raff — [Windows VPS for Real Estate Offices](https://rafftechnologies.com/windows-server/windows-vps-real-estate-offices) - Raff — [Windows VPS for Accounting Firms](https://rafftechnologies.com/windows-server/windows-vps-accounting-firms) - Raff — [Windows VPS Backup Strategy for Small Businesses](https://rafftechnologies.com/windows-server/windows-vps-backup-strategy-small-business) - Raff — [Windows Server Migration Checklist for Small Businesses](https://rafftechnologies.com/windows-server/windows-server-migration-checklist-small-business) - Raff — [Windows VM product page](https://rafftechnologies.com/products/windows-vm) --- ### Windows Server 2025 RDS CAL Guide: User vs Device CALs, Cost, Grace Period URL: https://rafftechnologies.com/windows-server/rds-cal-licensing-guide Description: Understand Windows Server 2025 RDS CAL licensing: User vs Device CALs, version compatibility, the 120-day grace period, license server requirements, pricing, and when hosted SPLA uses RDS SALs instead. ## In short **RDS CAL licensing** applies when users or devices access Windows Server through **Remote Desktop Services (RDS)**, such as an RD Session Host delivering shared desktops or RemoteApp programs. For customer-owned deployments, Microsoft offers **RDS User CALs** and **RDS Device CALs**. For Windows Server 2025, the CAL generation must cover Windows Server 2025. A 2022 RDS CAL does not cover a 2025 Session Host, while a 2025 CAL can cover compatible older hosts. A newly created RD Session Host also receives Microsoft's 120-day technical grace period. For Raff-hosted RDS, the licensing model is different: Raff uses Microsoft SPLA and RDS Subscriber Access Licenses (SALs). The current Raff RDS SAL price is **$8 per authorized unique user per month**. For the broader Windows licensing model, see [Windows Server Licensing on Raff](/windows-server/windows-licensing). :::cta rentrds Rent Microsoft RDS user licences (SPLA) monthly with your Raff Windows server: $8 per user per month, on the same bill as the server. You buy nothing up front. ::: ## RDS CAL licensing: what you actually need The licensing question starts with the workload, not the RDP client. | Scenario | RDS licensing required? | Notes | |---|---|---| | One or two administrators maintain Windows Server through the built-in administrative Remote Desktop connections | No RDS CAL for those administrative connections | These connections are for server administration, not employee desktop use | | Employees use an RD Session Host for full Windows desktops | Yes | Customer-owned deployments use the applicable RDS User or Device CAL model | | Users launch RemoteApp programs from RD Session Host | Yes | RemoteApp is RDS functionality | | Users visit an IIS website hosted on Windows Server | No RDS CAL just for visiting the site | They are consuming a web service, not an RDS session | | Users connect to SQL Server from an approved client | No RDS CAL just for database connectivity | Separate Windows/SQL licensing may still apply | | Raff provides a hosted RDS service under SPLA | RDS SAL model | Raff currently charges $8/month per authorized unique RDS user | The two built-in administrative connections are not "two free employee licenses." If staff use the server as a shared workplace, design it as an RDS workload. For the architecture decision, read [Multi-User RDP: 2 Admin Sessions vs RDS Session Host](/windows-server/multi-user-rdp-vs-rds). ## What is an RDS CAL? An **RDS Client Access License (RDS CAL)** gives a user or device the right to access Remote Desktop Services functionality on Windows Server under Microsoft's customer licensing model. Microsoft provides two licensing modes: - **Per User:** assigned to a user, who can access the RDS environment from multiple devices. - **Per Device:** assigned to a device, which can be used by multiple users. The RD Session Host is configured for one licensing mode, and the RD Licensing server issues or tracks the appropriate licenses. ## Windows Server CAL vs RDS CAL An RDS CAL does not replace the underlying Windows Server access license. In Microsoft's customer-owned Windows Server licensing model, the stack can look like this: ```text Windows Server license + Windows Server CAL for applicable users/devices + RDS CAL for users/devices that use Remote Desktop Services ``` The exact Windows Server CAL requirement depends on the customer's Microsoft agreement and licensing program. The important point is that **RDS CALs are additive rights for RDS functionality**, not substitutes for the base Windows Server licensing model. Hosted SPLA services use a different service-provider model and should not be mixed conceptually with customer CALs. ## Windows Server 2025 RDS CAL requirements A **Windows Server 2025 RDS CAL** is required for each applicable user or device that accesses an RD Session Host running Windows Server 2025 under Microsoft's customer CAL model. Microsoft's version-compatibility rule is straightforward: - a newer RDS CAL can access the same or an older Windows Server version; - an older RDS CAL cannot access a newer Windows Server version; - the RD Licensing server must run the same Windows Server version as the installed RDS CAL pack or a later version. That means a Windows Server 2022 RDS CAL does not cover a Windows Server 2025 Session Host, while a 2025 RDS CAL can cover compatible 2022 or 2019 Session Hosts. ## RDS User CAL vs Device CAL Choose the licensing mode based on how people actually access the environment. | Decision factor | RDS User CAL | RDS Device CAL | |---|---|---| | Assigned to | A user | A device | | Best fit | Users who connect from several devices | Shared PCs, kiosks, shift-based devices | | Domain-joined RDS | Supported | Supported | | Workgroup RDS | Not permitted | Required mode for workgroup deployment | | Typical example | 10 employees each using laptop + home PC | 20 shift workers sharing 6 terminals | ### Choose Per User when - each employee has a distinct identity; - users may connect from multiple devices; - the RDS deployment is domain-joined; - licensing by person matches the workforce better than licensing endpoint devices. ### Choose Per Device when - several people share a smaller number of devices; - the environment uses kiosks or shift workstations; - the deployment is a Windows workgroup rather than Active Directory. Do not select the mode only because one appears cheaper in a reseller catalog. Count real users and real connecting devices first. ## Workgroup RDS must use Per Device licensing Microsoft's current guidance distinguishes domain-joined and workgroup deployments. A domain-joined RD Session Host can use **Per User** or **Per Device** licensing. A workgroup RD Session Host must use **Per Device** licensing; Per User mode is not permitted for the workgroup scenario. If a small workgroup deployment is becoming a larger multi-user service, review whether an Active Directory-backed design is now more appropriate rather than trying to force unsupported Per User behavior. ## RDS CAL version compatibility table Before buying CALs, check the [Windows Server support lifecycle](/windows-server/windows-server-end-of-life-dates) for every Session Host you plan to keep in service. | RD Session Host | 2025 RDS CAL | 2022 RDS CAL | 2019 RDS CAL | |---|---:|---:|---:| | Windows Server 2025 | Yes | No | No | | Windows Server 2022 | Yes | Yes | No | | Windows Server 2019 | Yes | Yes | Yes | The same-versus-newer rule also matters on the **license server** side: the license server OS must be the same version as the CAL pack or newer. ## The 120-day RDS grace period Microsoft provides a **120-day licensing grace period** for a newly created RD Session Host. During that technical window, the Session Host can accept RDS connections before an RD Licensing server is fully configured. Before the grace period ends, a customer-owned CAL deployment should have: 1. an activated RD Licensing server; 2. a valid RDS CAL pack installed; 3. the RD Session Host pointed to the correct license server; 4. the licensing mode set to Per User or Per Device as appropriate. Once the grace period expires, licensing misconfiguration can cause users to receive Remote Desktop licensing errors and prevent normal RDS access. The grace period is **not a commercial licensing loophole**. Contractual Microsoft licensing obligations are separate from the technical timer in Windows Server. The same is true for Raff-hosted SPLA: the Windows grace-period mechanism does not create 120 days of free hosted-user licensing. ## How to configure RDS licensing at a high level For a customer-owned RDS deployment, the high-level sequence is: 1. Install the **Remote Desktop Licensing** role service. 2. Open **Remote Desktop Licensing Manager** and activate the license server. 3. Install the appropriate RDS CAL pack. 4. Configure the RD Session Host licensing mode. 5. Configure which license server the Session Host should use. 6. Validate the configuration before the grace period expires. Microsoft documents the supported configuration process in [License Remote Desktop Session Hosts](https://learn.microsoft.com/en-us/windows-server/remote/remote-desktop-services/rds-license-session-hosts). ## How to check if RDS is licensed When troubleshooting, verify the whole licensing chain rather than only checking whether an RDP session opens. Check: - the **RD Licensing** role is installed where expected; - the license server is activated; - the correct RDS CAL pack is installed; - the CAL version covers the RD Session Host version; - the Session Host is configured for the intended Per User or Per Device mode; - the Session Host is configured to use the intended license server; - the Session Host can resolve and reach the license server; - **RD Licensing Diagnoser** does not report licensing configuration errors. You can also inspect installed role state with PowerShell: ```powershell Get-WindowsFeature RDS-Licensing, RDS-RD-Server | Format-Table Name, InstallState ``` A working session during the 120-day grace period does not prove that production licensing is configured correctly. ## How much does an RDS CAL cost? There is no single permanent retail RDS CAL price that is safe to hard-code into a licensing guide. Customer CAL pricing varies by Windows Server generation, User versus Device CAL, pack size, reseller or Microsoft sales channel, geography, currency, agreement, taxes, and promotions. Use Microsoft's current Store listing or an authorized licensing reseller for a purchase quote. Raff-hosted RDS uses a different commercial model. The current Raff RDS User SAL is **$8/month per authorized unique user** under the hosted SPLA service model. See [Remote Desktop hosting on Raff](/products/remote-desktop-vps). This is not a concurrent-session price. If ten people are authorized to use the hosted RDS environment during a month, plan ten SALs even if only three are normally connected at the same time. ## Raff-hosted RDS cost examples For a Raff-hosted Windows Server environment, budget the Windows VM and RDS SALs separately. A 2 vCPU / 4 GB / 80 GB Windows VM currently costs **$37.99/month total**, including the $15 Windows Server Standard SPLA charge. RDS SALs are then added for the authorized users. | Authorized RDS users | RDS SALs | Example Windows VM | Example monthly total* | |---:|---:|---:|---:| | 1 | $8 | $37.99 | **$45.99** | | 5 | $40 | $37.99 | **$77.99** | | 10 | $80 | $37.99 | **$117.99** | | 20 | $160 | $37.99 | **$197.99** | \*Illustrative VM + Windows Server + RDS SAL total only. Real RDS workloads may require more CPU/RAM, additional storage, backups, Microsoft 365 licensing, application licensing, SQL Server licensing, or a separate RD Gateway/identity design. For sizing, use [Windows VPS Sizing for Remote Users](/windows-server/windows-vps-sizing-remote-users). For current infrastructure pricing, see [Raff Windows VM](/products/windows-vm) and [pricing](/pricing). ## Does Windows Server 2025 include RDS CALs? No. Buying or licensing Windows Server 2025 does not automatically provide the RDS CALs needed for RD Session Host users or devices in a customer-owned licensing model. Think of them as separate layers: ```text Windows Server licensing -> allows the Windows Server workload Windows Server CALs where applicable -> allow users/devices to access the server software RDS CALs -> add the right to use Remote Desktop Services functionality ``` For a hosted SPLA service, Microsoft uses the provider's service-provider licensing model instead. ## Does RDP require an RDS CAL? **Not every use of the RDP protocol requires an RDS CAL.** Microsoft permits two concurrent Remote Desktop connections for Windows Server administration without RDS CALs. Those connections are for administrators managing the server. If employees use **RD Session Host** for shared desktops or RemoteApp programs, the applicable RDS licensing model is required. ## Customer RDS CALs vs hosted RDS SALs This is the most important distinction for Raff customers. | Deployment model | RDS access license | |---|---| | Customer-owned Windows Server licensing | RDS User CALs or RDS Device CALs under the customer's Microsoft agreement | | Raff-provided hosted Windows service under SPLA | RDS User SALs under the service-provider licensing model | For Raff-hosted RDS, the current RDS User SAL price is **$8 per authorized unique user per month**. Microsoft SPLA licensing counts authorized users, not just peak concurrent sessions. If you are [hosting QuickBooks on a server](/windows-server/quickbooks-multi-user-windows-server-vps) for a remote team, each person authorized to use the hosted RDS service needs the applicable CAL or hosted SAL rights in addition to the application's own licensing. ## BYOL and RDS CALs: what outsourcing rights actually cover Windows Server licensing on third-party infrastructure depends on the customer's exact entitlement, Software Assurance or subscription rights where applicable, the provider relationship, and the **Flexible Virtualization Benefit** rules that apply to eligible Windows Server licenses. RDS access rights also depend on the customer's licensing agreement and deployment model. Do not assume that customer-owned Windows Server or RDS rights can simply be moved to any hosted environment without checking the applicable outsourcing terms. For Windows Server BYOL, Flexible Virtualization Benefit and outsourcing rights are the relevant concepts. **License Mobility through Software Assurance is not the Windows Server BYOL mechanism**; it applies to eligible server applications such as SQL Server. If you want to bring customer-owned Windows Server and RDS rights to Raff, verify the exact entitlement with a Microsoft licensing specialist or reseller before production deployment. ## Can RDS CALs be moved to another server? There are two separate ideas that are often mixed together: 1. **Moving or rebuilding the RD Licensing server.** CAL packs can be reinstalled or migrated through Microsoft's supported activation and licensing process when a license server is replaced. 2. **Reassigning the underlying user/device entitlement.** Reassignment rights and timing depend on the applicable Microsoft licensing terms and agreement. Do not treat migration of the license-server role as proof that every license can be freely reassigned at any time. ## Common RDS licensing errors ### The grace period expired Symptoms can include Remote Desktop licensing warnings or rejected user sessions. Configure and activate the RD Licensing server, install valid licenses, and verify that the Session Host is using the correct server and mode. ### The CAL version is too old for the Session Host A Windows Server 2022 RDS CAL does not cover a Windows Server 2025 RD Session Host. Use rights that cover the host version. ### The license server OS is too old for the CAL pack A Windows Server 2022 license server cannot host a Windows Server 2025 RDS CAL pack. Upgrade or deploy a license server on Windows Server 2025 or later. ### Workgroup deployment configured for Per User Workgroup RDS requires Per Device licensing. Change the design to the supported model rather than forcing Per User behavior. ### Session Host cannot find the license server Check DNS resolution, firewall/network connectivity, configured license-server name, and RD Licensing Diagnoser. ### The server is in the wrong licensing mode A Per User CAL pack does not help if the Session Host is configured for Per Device, and vice versa. Confirm the intended mode across the deployment. ### Administrative RDP is being used as an employee desktop workaround The two administrative connections are for server administration. If employees need daily Windows sessions, deploy and license RD Session Host properly. ## RDS licensing checklist Before putting a customer-owned RD Session Host into production, confirm: - [ ] The Windows Server version is documented. - [ ] The customer licensing model is documented. - [ ] The RDS licensing mode is Per User or Per Device by design. - [ ] Workgroup deployments use Per Device. - [ ] The RDS CAL generation covers the Session Host version. - [ ] The RD Licensing server version can host the CAL pack. - [ ] The licensing server is activated. - [ ] The CAL pack is installed. - [ ] The Session Host points to the correct license server. - [ ] RD Licensing Diagnoser shows no unresolved licensing errors. - [ ] The 120-day grace period is not being used as the production licensing plan. - [ ] Customer CAL licensing is not being confused with hosted SPLA SAL licensing. For Raff-hosted RDS, document the number of authorized users and include the current **$8/user/month RDS SAL** in the monthly cost model before onboarding users. ## What's next - [Multi-User RDP: 2 Admin Sessions vs RDS Session Host](/windows-server/multi-user-rdp-vs-rds) - [Windows Server Licensing on Raff](/windows-server/windows-licensing) - [Windows Server 2025 editions and versions](/windows-server/windows-server-version-comparison) - [Windows VPS Sizing for Remote Users](/windows-server/windows-vps-sizing-remote-users) - [Remote Desktop VPS](/products/remote-desktop-vps) ## Sources - Microsoft Learn: https://learn.microsoft.com/en-us/windows-server/remote/remote-desktop-services/rds-client-access-license - Microsoft Learn: https://learn.microsoft.com/en-us/windows-server/remote/remote-desktop-services/rds-license-session-hosts - Microsoft Licensing: https://www.microsoft.com/licensing/spur/en-US/productoffering/WindowsServer/all - Microsoft Store: https://www.microsoft.com/en-us/d/windows-server-2025-remote-desktop-services/dg7gmgf0pwhb - Sources revalidated: 2026-09-17 --- Microsoft licensing terms can vary by agreement, program, product version, geography, and deployment model. Microsoft Product Terms and the customer's executed licensing agreement control if they conflict with this guide. --- ### How to Connect to a Windows VPS via RDP URL: https://rafftechnologies.com/windows-server/connect-to-windows-vps-via-rdp Description: Connect to a Windows VPS with Remote Desktop from Windows, macOS, Linux, iPhone, iPad, or Android, then fix common RDP login, port, certificate, and connectivity errors. ## In short To connect to a Windows VPS, copy its public IP address, open an RDP client, enter the IP, sign in with `Administrator`, and use the password set during VM creation. On Windows, **Remote Desktop Connection (`mstsc`) remains Microsoft's generally available client** for direct remote-PC connections. On macOS, iOS, iPadOS, and Android, use **Windows App**. Keep Network Level Authentication enabled and restrict direct RDP exposure where practical. If you do not have a Windows VPS with RDP yet, see [RDP VPS hosting on Raff](/products/remote-desktop-vps). ## The Windows VPS RDP login takes six steps For a standard Raff Windows VM, the first connection is: ```text 1. Confirm the Windows VM is Running. 2. Copy its Public IPv4 address. 3. Open your Remote Desktop client. 4. Enter the public IP address. 5. Sign in as Administrator with your VM password. 6. Verify the server identity and complete the connection. ``` The normal direct-RDP port is `3389`. Microsoft documents both TCP and UDP 3389 for direct Remote Desktop traffic, although the exact transport used by a session can depend on the client and network path. If you are still choosing a server rather than connecting to one you already own, see [Raff Windows VM](/products/windows-vm). This guide is intentionally focused on **connection and first login**, not broad Windows VPS purchasing intent. ## Use the right Remote Desktop client in 2026 Microsoft's client lineup has changed, so use the client that is currently supported for your platform and connection type. | Local device | Recommended path for a direct Windows VPS connection | Notes | |---|---|---| | Windows 10/11 | **Remote Desktop Connection (`mstsc`)** | Generally available and built into Windows | | Windows with Windows App | Windows App can connect to a remote PC | Remote-PC connections in Windows App are still preview as of September 2026 | | macOS | **Windows App** | Supports direct remote-PC connections | | iPhone / iPad | **Windows App** | Supports direct remote-PC connections | | Android / ChromeOS | **Windows App** | Supports direct remote-PC connections | | Linux | Remmina or FreeRDP | Third-party/open-source clients, not Microsoft clients | For Windows users, there is no need to replace `mstsc` just because Windows App exists. Microsoft currently directs users who want a generally available Windows remote-PC client to continue using Remote Desktop Connection. ## You need the IP address, Administrator account, and password Before connecting, prepare: - a Raff Windows VM with status **Running**; - its **Public IPv4** address; - the Administrator password set during VM creation; - an RDP client on your local device; - network access to the RDP service. The standard Raff first-login username is: ```text Administrator ``` If your RDP client tries to use a different local or Microsoft account automatically, use: ```text .\Administrator ``` The `.` tells Windows to use the remote server's local account database rather than a domain account. ## Get the Windows VPS IP from the Raff dashboard ![VM details page on app.rafftechnologies.com showing the IP address field, credentials panel, and the Password action in the top toolbar](https://raff-images.s3.raffusercloud.com/large_raff_dashboard_vm_details_windows_server_2026_04_e539f4c973.png) The existing Raff dashboard workflow for this guide is: 1. Sign in to the Raff dashboard. 2. Open **Compute → All Virtual Machines**. 3. Select your Windows VM. 4. Confirm the VM is **Running**. 5. Copy the **Public IPv4** address. You set the Administrator password during VM creation. Save it in a password manager rather than relying on a browser tab or temporary note. ### Reset the password if you no longer have it If the Administrator password is lost, use the password-reset action from the VM details page rather than repeatedly guessing credentials. After a reset: 1. wait for the reset operation to complete; 2. remove any stale saved credentials from the RDP client if necessary; 3. reconnect with `Administrator` and the new password. Repeated failed sign-ins can trigger account-lockout behavior if a lockout policy is configured. ## Connect from Windows with Remote Desktop Connection Remote Desktop Connection is built into supported Windows versions and remains the simplest generally available path for a direct Windows VPS connection. 1. Press `Win + R`. 2. Enter: ```text mstsc ``` 3. Select **OK**. 4. In **Computer**, enter the Windows VPS public IP. 5. Select **Show Options** if you want to enter the username before connecting. 6. Use: ```text Administrator ``` 7. Select **Connect**. 8. Enter the Administrator password. 9. Review the certificate/server-identity prompt before continuing. Microsoft also supports launching a connection directly from the command line: ```text mstsc /v:203.0.113.42 ``` Replace the documentation IP with your actual server address. ### Save the RDP profile if you connect often In Remote Desktop Connection: 1. select **Show Options**; 2. configure the server and username; 3. select **Save As**; 4. save the `.rdp` file in a controlled location. Do not distribute an `.rdp` file together with shared credentials. Each administrator should have an attributable account where the environment requires it. ## Connect from macOS with Windows App Microsoft Windows App is the current Microsoft client for direct remote-PC connections on macOS. 1. Install **Windows App** from the Mac App Store. 2. Open Windows App. 3. Add a new **PC**. 4. Enter the Windows VPS public IP as the PC name. 5. Add or enter the `Administrator` account. 6. Enter the password. 7. Save and open the connection. 8. Review the certificate prompt before accepting it. Windows App can also configure display resolution, multiple monitors, clipboard behavior, audio, and device/folder redirection depending on platform support and policy. ## Connect from iPhone, iPad, or Android with Windows App Microsoft also provides Windows App on iOS, iPadOS, and Android/ChromeOS. The connection details remain the same: ```text PC name: Username: Administrator Password: ``` On iPhone or iPad: 1. install Windows App; 2. tap the add button; 3. add a **PC**; 4. enter the VPS IP address; 5. save the connection; 6. enter the Windows credentials when prompted. On Android/ChromeOS, add the remote PC in Windows App using the same IP and credentials. Mobile RDP is useful for emergency administration and quick checks. For long server-management sessions, a desktop client is usually more practical. ## Linux clients can use Remmina or FreeRDP Linux does not use a Microsoft Windows App client for this workflow. Common choices are **Remmina** and **FreeRDP**. On Ubuntu/Debian, Remmina can be installed with: ```bash sudo apt update sudo apt install remmina remmina-plugin-rdp ``` Then create an RDP profile with the server IP and `Administrator` credentials. FreeRDP can also connect from a terminal. Use its current client syntax for the version installed by your distribution and avoid options that globally disable certificate validation unless you are diagnosing a controlled test environment. Because Remmina and FreeRDP are third-party/open-source projects, use their current project documentation for distribution-specific package and certificate options. ## A first-time certificate warning is expected, but verify the server A fresh Windows Server commonly presents an RDP certificate that your client cannot validate through a public certificate authority, especially when you connect by raw IP address. Before accepting the prompt, confirm: - the IP matches the VM in your Raff dashboard; - you intentionally initiated the connection; - the warning is consistent with a first connection or known certificate change. Do not turn certificate validation off globally just to remove the prompt. If an established server suddenly presents a different certificate or fingerprint without an expected configuration change, investigate before continuing. ## Verify that the RDP session reached the correct Windows Server After login, open PowerShell and verify the operating system: ```powershell Get-ComputerInfo | Select-Object CsName, OsName, OsVersion, OsBuildNumber ``` Check the network configuration: ```powershell ipconfig ``` And confirm the Remote Desktop Services service is running: ```powershell Get-Service TermService ``` A healthy service state should report `Running`. These checks are especially useful when you manage several Windows VMs and want to verify that you connected to the intended server. :::cta Deploy Windows Now Need another Windows environment? Deploy a Raff Windows VM, then connect with the same RDP workflow after provisioning completes. ::: ## Keep Network Level Authentication enabled Microsoft recommends **Network Level Authentication (NLA)** for most environments. NLA requires authentication before the full remote session is created and reduces the resources exposed to unauthenticated users. If an old client cannot connect because the server requires NLA, update the client first. Disabling NLA should be a controlled compatibility exception with a recovery path, not the default troubleshooting step. ## Direct public RDP should be an administrative access path, not a team architecture Connecting directly to a public Windows VPS address is simple, but exposing Remote Desktop broadly to the internet increases the server's authentication attack surface. For a small admin-only deployment: - keep NLA enabled; - use strong unique credentials; - restrict RDP to trusted source IPs where practical; - keep Windows patched; - monitor failed sign-ins; - preserve a console/recovery path before changing firewall rules. For teams, changing source networks, or sensitive workloads, consider a VPN or **Remote Desktop Gateway** rather than relying on a broadly reachable direct RDP endpoint. See [RD Gateway vs Direct RDP](/windows-server/remote-desktop-gateway-vs-direct-rdp) for the architecture decision and [Configure Windows Firewall](/windows-server/configure-windows-firewall) for source restriction and rule scope. ## Administrative RDP is different from a multi-user RDS deployment A Windows Server VM can be administered through Remote Desktop without turning the server into a shared employee desktop. Use administrative RDP for: - server setup; - patching; - software installation; - troubleshooting; - occasional maintenance. If employees need separate Windows sessions or RemoteApp for daily work, plan **Remote Desktop Services (RDS) Session Host** and the correct Microsoft licensing model. The two built-in administrative connections are not employee desktop licenses. Use [Multi-User RDP vs RDS Session Host](/windows-server/multi-user-rdp-vs-rds) before onboarding daily users. ## Most RDP connection failures fit five checks When Remote Desktop cannot connect, troubleshoot in this order: 1. **VM state** — confirm the Windows VM is Running. 2. **IP address** — compare the address in your client with the dashboard. 3. **Credentials** — use `Administrator` or `.\Administrator` with the current password. 4. **Network path** — confirm your local network can reach TCP 3389. 5. **Server policy/firewall** — confirm RDP is enabled, allowed through Windows Firewall, and NLA/client compatibility is correct. On a Windows client, test TCP reachability: ```powershell Test-NetConnection 203.0.113.42 -Port 3389 ``` A successful `TcpTestSucceeded` proves that the TCP listener is reachable. It does **not** prove that credentials, NLA, RDS policy, UDP transport, or the desktop session itself will succeed. ## “Your credentials did not work” usually means account or cached-credential trouble Try this sequence: 1. Confirm Caps Lock and keyboard layout. 2. Enter the password manually rather than pasting it from an uncertain source. 3. Use `Administrator`. 4. If Windows is trying another account context, use `.\Administrator`. 5. Remove stale saved credentials from the client. 6. Reset the Raff VM password if the current password is unknown. Do not weaken CredSSP or NLA policy as the first response to a credential error. ## “Remote Desktop can't connect to the remote computer” usually means reachability Check: - the VM is powered on; - the public IP is correct; - your office/VPN/firewall is not blocking outbound RDP; - Windows Firewall still permits the intended connection; - RDP was not disabled inside Windows; - TCP 3389 is reachable from the client network. If a corporate network blocks RDP, test from another approved network to isolate whether the problem is local or server-side. If Windows Firewall rules changed immediately before the failure, use the documented recovery path rather than opening every port. The detailed safe workflow is in [Configure Windows Firewall](/windows-server/configure-windows-firewall). ## CredSSP errors should be fixed by updating both sides A message such as: ```text An authentication error has occurred. The function requested is not supported. ``` can appear when the client and server have incompatible CredSSP security-update states. The preferred fix is to update both the local client and Windows Server. Avoid old registry recipes that reduce CredSSP protection simply to make a connection succeed. ## Black screens and slow sessions are a separate performance problem If authentication succeeds but the session opens to a black screen, freezes, or becomes slow, the connection problem may have moved beyond basic login. Check: - Windows Update or first-boot work still running; - server CPU/RAM pressure; - client resolution and monitor count; - network latency or packet loss; - user-profile problems; - applications consuming server resources. For a systematic diagnosis, use [RDP Performance Tuning](/windows-server/rdp-performance-tuning). ## Clipboard and file redirection depend on client and server policy If copy/paste does not work, check that clipboard redirection is enabled in the client and not blocked by server or RDS policy. On a Windows session, restarting the clipboard process can help when the feature is enabled but stuck: ```powershell Stop-Process -Name rdpclip -Force Start-Process rdpclip.exe ``` For local-drive redirection in `mstsc`: 1. open **Show Options**; 2. select **Local Resources**; 3. select **More**; 4. enable only the drives or devices you need; 5. reconnect. For sensitive servers, redirect the minimum required local resources rather than exposing the entire client filesystem to the session. ## Secure the Windows VPS immediately after first login A successful RDP connection is the start of server administration, not the end of setup. After first login: 1. Run Windows Update. 2. Confirm the Administrator password is strong and unique. 3. Create attributable admin accounts if multiple people manage the VM. 4. Keep NLA enabled. 5. Review Windows Firewall and narrow RDP exposure where practical. 6. Do not expose SMB, SQL Server, WinRM, or other management ports broadly. 7. Enable backups or snapshots before installing business-critical software. 8. Monitor failed sign-ins and unexpected account activity. For the broader baseline, use the [Windows Server Hardening Checklist](/windows-server/windows-server-hardening-checklist). ## Tested on Raff > The original connection workflow was tested on a Raff Windows VM running Windows Server 2025 using **Remote Desktop Connection (`mstsc`) on Windows** and **Windows App on macOS**. The Raff dashboard screenshot and first-login workflow above are preserved from that earlier test. This September 2026 refresh revalidated the Microsoft client, NLA, and remote-access guidance against current Microsoft documentation; it does not claim a new live Raff connection test or a new dashboard screenshot. ## What's next - [RDP Performance Tuning](/windows-server/rdp-performance-tuning) — fix lag, latency, and session performance after login. - [Multi-User RDP vs RDS Session Host](/windows-server/multi-user-rdp-vs-rds) — decide when admin RDP is no longer enough. - [RD Gateway vs Direct RDP](/windows-server/remote-desktop-gateway-vs-direct-rdp) — choose a safer access architecture for teams. - [Configure Windows Firewall](/windows-server/configure-windows-firewall) — narrow RDP and other inbound rules safely. - [RDP VPS](/products/remote-desktop-vps) — deploy another Windows Server environment. ## Sources - Microsoft Learn — [Enable Remote Desktop](https://learn.microsoft.com/en-us/windows-server/remote/remote-desktop-services/remotepc/remote-desktop-allow-access) - Microsoft Learn — [Connect to Windows devices and apps with Windows App](https://learn.microsoft.com/en-us/windows-app/get-started-connect-devices-desktops-apps) - Microsoft Learn — [What is Windows App?](https://learn.microsoft.com/en-us/windows-app/overview) - Microsoft Learn — [Remote Desktop access from outside your network](https://learn.microsoft.com/en-us/windows-server/remote/remote-desktop-services/remotepc/remote-desktop-allow-outside-access) - Microsoft Learn — [`mstsc` command reference](https://learn.microsoft.com/en-us/windows-server/administration/windows-commands/mstsc) - Microsoft Learn — [Remote Desktop clients FAQ](https://learn.microsoft.com/en-us/windows-server/remote/remote-desktop-services/remotepc/remote-pc-connections-faq) - Remmina project documentation - FreeRDP project documentation - Sources revalidated: 2026-09-09 --- ### MetaTrader VPS Setup: Run MT4/MT5 EAs 24/7 on Windows URL: https://rafftechnologies.com/windows-server/metatrader-vps-setup Description: Set up MetaTrader 4 or MetaTrader 5 on a Windows VPS, move EAs and profiles safely, keep terminals running after RDP disconnect, troubleshoot connection issues, and choose the right VPS size. ## In short A **MetaTrader VPS** is a remote Windows environment that keeps MT4 or MT5 running even when your own computer is off. The practical setup is: deploy a Windows VPS, connect over RDP, install the broker's MetaTrader terminal, copy your EAs and profiles, verify the broker server, enable automated trading, then **disconnect from RDP without signing out** so the Windows session stays active. For one light terminal, 2 vCPU and 4 GB RAM is usually a sensible starting point. Multiple terminals, heavy indicators, or strategy testing need more headroom. If your EA depends on DLLs, multiple terminals, custom scripts, or Windows-level tools, a full Windows VPS is more flexible than MetaTrader's built-in Virtual Hosting. On Raff, a Windows VPS for MetaTrader starts at $13.99 for your first month, then $28.99 a month, with the Windows Server licence included. Raff Keep can install MetaTrader 4 and 5 for you and starts the terminals again after a restart. ## MetaTrader VPS vs MetaTrader Virtual Hosting MetaTrader users can choose between two different hosting models: | Option | Better fit | |---|---| | **Windows VPS** | Full RDP desktop, multiple MT4/MT5 terminals, custom files, DLL-dependent EAs, scripts, backup tools, broker-specific software | | **MetaTrader Virtual Hosting** | A simpler MetaTrader-native environment for migrating one terminal's EAs, indicators, charts, and signals without managing Windows | MetaTrader's own Virtual Hosting is integrated into the platform and is designed around migration from the local terminal. It is not a general-purpose Windows desktop. One important limitation: MetaQuotes documentation states that **DLL calls are not allowed in the virtual hosting environment**. If your EA requires trusted DLLs or other Windows-level dependencies, use a full Windows VPS instead. MetaQuotes also limits each rented terminal to one trading account. MQL5 hosting costs $15 a month, or $10 a month on a 12-month plan ([mql5.com](https://www.mql5.com/en/vps), checked 12 October 2026). It has no remote desktop, so you cannot install other software on it or run the Strategy Tester there. A useful decision rule is: ```text Need only MetaTrader-native EA/signal hosting → MetaTrader Virtual Hosting can be simpler Need full Windows control, RDP, multiple terminals, custom tooling, DLLs, or file automation → Windows VPS ``` ## Why run MT4 or MT5 on a Windows VPS? A Windows VPS gives MetaTrader a remote desktop that can remain online independently of your laptop. That helps when you need: - 24/7 EA availability; - MT4 or MT5 running while your own PC is off; - several terminals or broker accounts; - remote administration over RDP; - a consistent Windows environment; - central files, presets, templates, and logs; - controlled Windows updates and reboot windows; - access from another computer or mobile RDP client. A VPS does **not** guarantee trading profits, broker execution, low slippage, or a particular latency result. It only provides the infrastructure layer. ## What you need before you start, and how long setup takes Have these ready before you deploy: - your trading account number, password and the exact broker server name; - the MT4 or MT5 installer from your broker's client portal; - your EA files, `.set` presets and custom indicators; - any EA licence key, because some vendors bind a licence to one machine. A Raff Windows VPS is ready in about 55 seconds after you deploy it. Most of the remaining time is your own setup: install the terminal, copy your files, then check the first trades on a demo account. ## Step 1 — Choose the VPS around the MetaTrader workload MetaTrader itself is usually light, but the complete workload can grow quickly as you add terminals, charts, EAs, historical data, and backtesting. | Workload | Starting point | |---|---| | 1 MT4/MT5 terminal, light EA | 2 vCPU / 4 GB RAM | | 1–3 terminals, several charts | 2–4 vCPU / 4–8 GB RAM | | 3–6 terminals, multiple EAs | 4 vCPU / 8 GB RAM | | Many terminals or heavy indicators | 4–8 vCPU / 8–16 GB RAM | | Strategy testing / optimization | More CPU and RAM; benchmark the actual EA | These are planning ranges, not guarantees. EA code quality, indicator load, tick frequency, chart count, and tester jobs can change CPU use dramatically. For MetaTrader, it is usually better to leave headroom than to run the VM near 100% CPU or RAM during live automation. ### Shared or dedicated CPU for MT5? A typical Expert Advisor uses little CPU most of the time. It needs CPU when a new tick or bar arrives, often in bursts, for example around news. So the risk on a VPS is not the average load. The risk is a short CPU stall at that moment. - Leave headroom: choose a plan where normal CPU use stays well below 100%. - Keep optimisation off the live server. The MT5 Strategy Tester runs one testing agent per CPU core, so a backtest or an optimisation uses every core it can get. Run heavy optimisation on a larger plan or on your own PC. Raff Windows plans run on guaranteed AMD EPYC vCPU with NVMe storage. ## Step 2 — Connect to the Windows VPS over RDP After the VM is running, connect with Remote Desktop. Use: ```text Computer: VPS public IP Username: Administrator Password: your Windows VPS password ``` For the full first-login workflow, use [How to Connect to a Windows VPS via RDP](/windows-server/connect-to-windows-vps-via-rdp). After first login: 1. Run Windows Update. 2. Reboot if required. 3. Reconnect. 4. Confirm the server time and time zone. 5. Confirm internet access. 6. Save credentials in a password manager. Do not install trading software before the Windows Server is patched and stable. ## Step 3 — Install MT4 or MT5 from the broker or MetaQuotes Prefer the installer from your broker's official client portal when you are connecting a live account. Broker-provided packages often include the correct server list and connection settings. Use an official MetaQuotes download only when appropriate for your account. Avoid random third-party installers. After installation: 1. Open MetaTrader. 2. Log in to the trading account. 3. Select the exact broker server. 4. Confirm the connection indicator. 5. Check the **Journal** tab for login errors. 6. Verify the account number and server before enabling automation. If the account connects on your home PC but not on the VPS, the first thing to compare is the **broker server name**, not the VPS itself. ## Step 4 — Move an existing MT4/MT5 setup without breaking profiles or EAs If you already have MetaTrader configured on another computer, migrate the application data rather than rebuilding every chart manually. On the source MetaTrader terminal: ```text File → Open Data Folder ``` Important folders include: | Folder | Purpose | |---|---| | `MQL4` / `MQL5` | EAs, indicators, scripts | | `Experts` | Expert Advisor files | | `Indicators` | Custom indicators | | `Presets` | EA `.set` parameter files | | `Profiles` | Chart layouts | | `Templates` | Chart templates | | `Logs` | Terminal logs | | `Tester` | Strategy Tester data and caches | Safe migration sequence: 1. Close MetaTrader on both source and VPS. 2. Back up the source data folder. 3. Copy only the folders you actually need. 4. Start MetaTrader on the VPS. 5. Open the correct charts and profiles. 6. Verify every EA and indicator loads. 7. Re-enter vendor license details if the EA binds to a new machine. 8. Confirm symbols, timeframes, and broker suffixes match. Do not assume a copied profile proves the EA is operational. Check the **Experts** and **Journal** tabs after migration. ## Step 5 — Install and verify Expert Advisors For MT4: ```text MQL4 → Experts ``` For MT5: ```text MQL5 → Experts ``` After copying the EA: 1. Restart MetaTrader or refresh Navigator. 2. Open the required chart. 3. Attach the EA. 4. Load the correct preset if you use a `.set` file. 5. Confirm automated trading permission. 6. Check whether DLL or WebRequest access is required. 7. Read **Experts** and **Journal** for errors. Only enable DLL imports for software you trust. DLLs execute native code inside Windows and should be treated like any other executable dependency. ## Step 6 — Keep MetaTrader running after Remote Desktop disconnects This is the most important operational step. When you finish managing the VPS, **disconnect from RDP**. Do not sign out of Windows. Correct: ```text Close the RDP window or Disconnect the RDP session ``` Avoid: ```text Start → Sign out ``` or: ```cmd logoff ``` Signing out ends the Windows desktop session and normally closes GUI applications running in that session, including MetaTrader. After disconnecting, reconnect later and verify: - MetaTrader is still open; - account connection is active; - the EA is still attached; - Algo Trading / AutoTrading is enabled; - no repeated Journal or Experts errors appeared. ## Step 7 — Start MetaTrader again after planned reboots An RDP disconnect keeps the current user session alive, but a Windows reboot ends it. For a simple environment, place a MetaTrader shortcut in the Startup folder: ```text Win + R shell:startup ``` A more controlled option is Task Scheduler: ```text Trigger: When I log on Action: Start terminal.exe or terminal64.exe ``` Do not treat MetaTrader as a Windows service unless the software vendor explicitly supports that architecture. It is a desktop application. After every reboot: 1. Sign in. 2. Confirm MetaTrader launches. 3. Confirm broker connection. 4. Confirm EA state. 5. Check logs. On Raff, the Raff Keep **MetaTrader 4 and 5** setup does this for you. It installs MetaTrader 5, MetaTrader 4 or both on Windows Server 2025, gives each terminal its own folder, and starts each terminal again by itself after a restart. Check the terminal and the broker connection after each restart anyway. ## Step 8 — Monitor MT5 or MT4 from a phone A VPS does not require you to keep an RDP session open all day. For account monitoring, the cleaner approach is usually: - use the broker's official MT4/MT5 mobile app for positions and account status; - use RDP from a phone only when you need to administer the Windows terminal itself; - configure EA/vendor notifications where supported; - review Journal and Experts logs during scheduled checks. This reduces the temptation to leave a Remote Desktop session open continuously. ## Step 9 — Troubleshoot “No connection” on a MetaTrader VPS Do not assume every MetaTrader connectivity problem is a VPS outage. Check in this order: ### 1. VPS internet access Open a browser on the VPS and confirm normal internet connectivity. ### 2. Broker server selection Confirm the exact server name used by the account. ### 3. Account type Check whether the login is MT4 or MT5 and whether it is demo or live. ### 4. MetaTrader Journal Look for: - authorization failed; - no connection; - invalid account; - server unavailable; - network or proxy errors. ### 5. Broker status If other applications on the VPS work but MetaTrader cannot reach the broker, verify the broker's server status before changing Windows Firewall. The useful diagnostic split is: ```text No internet on VPS → infrastructure/network issue Internet works, broker server unreachable → broker/routing/terminal issue Broker connects, EA still fails → EA/configuration/permission issue ``` ## Step 10 — Troubleshoot an EA that works on your PC but not on the VPS Common causes include: - Algo Trading disabled; - EA-level trading permission disabled; - wrong chart or timeframe; - different symbol name or suffix; - missing indicator dependency; - missing DLL; - DLL permission disabled; - missing WebRequest domain; - vendor licence tied to the old machine; - missing `.set` preset; - Windows path differences; - broker account or server mismatch. Check: ```text Tools → Options → Expert Advisors ``` Then inspect **Experts** and **Journal**. If the EA is loaded but never sends a trade request, do not immediately resize the VPS. First rule out strategy conditions and permissions. ## Step 11 — Separate RDP performance from trading-platform connectivity A slow Remote Desktop session does not automatically mean MetaTrader is disconnected from the broker. RDP responsiveness depends on your client-to-VPS path. MetaTrader broker connectivity depends on the VPS-to-broker path. If RDP feels slow but MetaTrader shows a stable broker connection and normal logs, the trading terminal may still be operating correctly. For RDP troubleshooting, see [Remote Desktop Slow? Improve RDP Performance](/windows-server/rdp-performance-tuning). ## Step 12 — Back up the MetaTrader environment Back up the MetaTrader data folder before: - changing EA versions; - changing parameters; - moving to another VPS; - upgrading MetaTrader; - changing broker account; - cleaning profiles or templates; - making large Windows changes. Keep copies of: - `MQL4` or `MQL5`; - profiles; - templates; - presets; - vendor configuration files; - relevant logs; - screenshots or reports you rely on. Store an off-server copy. A backup stored only on the same VM does not protect against VM loss or accidental deletion. ## Step 13 — Secure the trading VPS Treat the VPS as a system containing financial-account credentials and executable trading code. Use: - strong unique Windows credentials; - Windows Firewall; - Windows Update; - trusted EA sources only; - no cracked EAs or indicators; - no public SMB shares; - restricted RDP access where practical; - backups and restore checks; - separate passwords for broker and VPS; - a password manager. If you can restrict RDP by trusted source IP or use a controlled access path, do so. ## Choosing latency for MetaTrader Latency should be measured against the broker's actual trade server, not against your own physical location. The number that matters is the VPS-to-broker path. Execution also depends on: - broker infrastructure; - liquidity routing; - account type; - spread; - slippage; - order type; - market volatility; - EA logic. A hosting provider cannot guarantee broker execution quality or trading results. For reference, Raff runs in us-east. Measured from a Raff us-east VPS on 11 September 2026, with 50 samples: 8.6 ms TCP median to a New York-area reference host (Linode, Newark, New Jersey) and about 77 ms to London reference hosts. If your broker offers a New York trade server, choose it. Your own number is the ping MetaTrader shows for your broker's server, in the bottom right corner of the terminal. ## How Raff fits MetaTrader VPS workloads Raff provides Windows VM infrastructure where traders can install MT4 or MT5, connect over RDP, run multiple terminals, manage files, and operate trusted EAs or indicators. Raff's role is the infrastructure layer, not the brokerage or trading-strategy layer. Raff does not provide: - broker services; - trading advice; - profitability guarantees; - EA certification; - account management; - broker execution guarantees. What a Raff forex VPS includes: - Windows Server 2019, 2022 or 2025 with the genuine Windows Server licence included in the price; - from $13.99 for your first month, then $28.99 a month (1 vCPU, 2 GB RAM, 50 GB NVMe); the first-month price is for your account's first server on monthly billing; - the 2 vCPU / 4 GB size from Step 1 at $37.99 a month ($22.99 for the first month), or from $26.66 a month billed yearly on the entry plan; - unmetered bandwidth, a 99.9% uptime SLA and a 14-day money-back guarantee; - Raff Keep **MetaTrader 4 and 5**, which installs the terminals and starts them again after a restart. See plans, terminal sizing and the latency method on the [Raff forex VPS for MT4 and MT5](/products/forex-vm) page. For other Windows workloads, size a [Raff Windows VM](/products/windows-vm) around the number of terminals, EAs, charts, and tester workload. :::cta Explore Forex VPS See forex VPS plans for MT4 and MT5 with the Windows licence included, then validate your EA on a demo account before live use. ::: ## Compatible with Raff This article documents a customer-managed MetaTrader architecture that is compatible with Raff Windows VMs. The current article does **not** make a fresh “Tested on Raff” claim because it does not include a complete new test environment, dated engineer validation, and original MetaTrader screenshot set required by Raff's Windows editorial standard. ## What's next - [Windows application hosting](/windows-server/windows-vps-for-business-software) — review the broader Windows application-hosting model when comparing persistent business workloads. - [How to Connect to a Windows VPS via RDP](/windows-server/connect-to-windows-vps-via-rdp) - [Remote Desktop Slow? Improve RDP Performance](/windows-server/rdp-performance-tuning) - [Windows Server 2019 vs 2022 vs 2025](/windows-server/windows-server-version-comparison) - [Configure Windows Firewall on a Windows VPS](/windows-server/configure-windows-firewall) - [Raff Windows VM](/products/windows-vm) - [Raff Forex VPS](/products/forex-vm) ## Sources - MetaTrader 5 Help — [Virtual Hosting](https://www.metatrader5.com/en/terminal/help/virtual_hosting) - MetaTrader 5 Help — [Migration to Virtual Hosting](https://www.metatrader5.com/en/terminal/help/virtual_hosting/virtual_hosting_migration) - MetaTrader 5 Help — [Expert Advisors and Custom Indicators](https://www.metatrader5.com/en/terminal/help/algotrading) - MetaTrader 5 Help — [Strategy Tester](https://www.metatrader5.com/en/terminal/help/algotrading/testing) - Microsoft Learn — [Remote Desktop Services overview](https://learn.microsoft.com/en-us/windows-server/remote/remote-desktop-services/overview) - MQL5: [Virtual hosting rules](https://www.mql5.com/en/vps/rules) - Raff: latency measured from a us-east VPS, 2026-09-11 (method on the [forex VPS page](/products/forex-vm)) - Sources verified: 2026-10-21 --- MetaTrader, MetaTrader 4, MetaTrader 5, MQL4, MQL5, and MetaQuotes are trademarks or products of MetaQuotes Ltd. Raff is not affiliated with or endorsed by MetaQuotes or any broker. This article is technical infrastructure documentation and is not financial advice. --- ## Marketplace ### Docker URL: https://marketplace.rafftechnologies.com/docker Tagline: Container-ready Ubuntu host, deployed in one click Description: Deploy a hardened Ubuntu 24.04 host with Docker Engine, Compose, and Buildx pre-installed. Run any container in minutes. #### Description ## What is the Docker 1-click VM? The Docker 1-click VM is a clean Ubuntu 24.04 host with the full Docker toolchain pre-installed and ready to use. Docker Engine, the Docker Compose v2 plugin, Buildx, and BuildKit are all configured on first boot, so you can `docker run`, `docker compose up`, or build multi-stage images the moment you SSH in. This image is the foundation, not a curated stack. It is meant for developers and teams who want a container-ready Linux host without spending the first hour after deploy installing Docker, configuring the daemon, opening firewall ports, and adding swap. Bring your own `docker-compose.yml`, your own custom images, or your own deployment automation. ## Why deploy Docker on Raff Cloud? - **Zero post-install setup** — Docker Engine, Compose v2, Buildx, and BuildKit are already running on first boot. - **Hardened by default** — UFW firewall and Fail2Ban are pre-configured. SSH is rate-limited against brute force out of the box. - **Tunable at deploy time** — The Raff dashboard exposes firewall ports, swap size, timezone, Fail2Ban, and auto-updates as toggles before the VM boots, so the host matches your workload without post-deploy config drift. - **Predictable cost** — Flat monthly VM pricing on bare-metal AMD EPYC. No per-container fees, no egress charges. - **Full root access** — Customize the Docker daemon, install additional runtimes, swap the storage driver, mount a separate volume for `/var/lib/docker`. Your VM, your rules. ## Use cases - Self-host any open-source app that ships a `docker-compose.yml` — databases, dashboards, monitoring stacks, internal tools. - Run a private staging environment for an application your team is building, with the same Docker primitives as production. - Build custom images on a fast EPYC host using Buildx and BuildKit, push to your registry of choice. #### Key Features - **Docker Engine 29.3** — Latest stable Docker daemon, pre-configured and running on boot - **Docker Compose v2** — Multi-container app deployment via the official Compose plugin - **Buildx and BuildKit** — Multi-platform image builds with cache mounts and secrets - **Ubuntu 24.04 LTS base** — Long-term support release, security updates until 2029 - **UFW firewall** — Pre-configured to allow SSH plus the ports you select at deploy time - **Fail2Ban** — SSH brute-force protection enabled by default on the host - **Configurable swap** — Pick a swap size at deploy time, or run swap-less for predictable performance - **Auto security updates** — Optional unattended upgrades for OS-level CVE patching #### Getting Started ## Getting Started 1. **Deploy the VM** — Click "Create Docker VM" in the Raff dashboard and pick a plan. In the App Configuration panel, set the firewall ports, swap, timezone, Fail2Ban, and auto-updates to match your workload. 2. **Connect via SSH** — `ssh root@` 3. **Verify the install** — Run `docker version` and `docker compose version` to confirm both are ready. 4. **Run your first container** — `docker run --rm hello-world` to smoke-test, then deploy your real workload. 5. **Open the firewall for your app** — Add your container's published port to UFW: `ufw allow 8080/tcp`. Or set it in the Raff dashboard at deploy time so it is open from the first boot. ## API Creation Deploy programmatically via the Raff CLI, public REST API, or Terraform. ### CLI ```bash raff vm create --template --plan s-2vcpu-4gb --region tr-ank-1 --name my-docker ``` ### REST ```bash curl -X POST https://api.rafftechnologies.com/v1/vms \ -H "Authorization: Bearer $RAFF_API_TOKEN" \ -H "Content-Type: application/json" \ -d '{"name":"my-docker","template_id":"","plan":"s-2vcpu-4gb","region":"tr-ank-1"}' ``` ### Terraform ```hcl resource "raff_vm" "docker" { name = "my-docker" template_id = "" plan = "s-2vcpu-4gb" region = "tr-ank-1" } ``` After provisioning, follow the steps above for first-time setup. #### FAQs **What is preinstalled on the Docker VM?** Ubuntu 24.04 LTS, Docker Engine 29.3, Docker Compose v2 plugin, Buildx, and BuildKit. UFW and Fail2Ban are configured and active. Nothing else — no preloaded containers, no web UI. **What plan do I need?** The 1 vCPU / 2 GB plan is fine for a few small containers or a single app. The 2 vCPU / 4 GB plan is the comfortable starting point for a multi-service Compose stack. Heavy workloads like databases, build runners, or media transcoding need 4 vCPU / 8 GB or more. **Does the VM include a web UI like Portainer?** No. This image is the bare Docker host. If you want a UI, install Portainer, Dockge, or Yacht yourself: `docker run -d -p 9443:9443 --restart=always -v /var/run/docker.sock:/var/run/docker.sock -v portainer_data:/data portainer/portainer-ce:latest`. **How do I open ports for my container?** Add the port to UFW with `ufw allow /tcp` after deploy, or pre-configure the allowed ports list in the Raff dashboard before the VM boots so the firewall opens them on first start. **Does Fail2Ban protect my containers?** No. Fail2Ban watches the host's SSH service to block brute-force attempts. Containers you run are not automatically monitored. If your workload exposes a public auth endpoint, add Fail2Ban filters for it inside the host or run a dedicated WAF/reverse proxy in front. **How do I update Docker?** Docker is installed from the official Docker apt repository. Run `apt update && apt upgrade docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin` to upgrade. If auto-updates are enabled at deploy time, security patches install automatically. **Where does Docker store data?** Container images, volumes, and BuildKit cache live in `/var/lib/docker` on the root disk. For workloads with significant data, attach an additional Raff volume and bind-mount it into your containers, or relocate `/var/lib/docker` to the larger volume. **Is this production-ready?** Yes for single-host workloads. For multi-host orchestration, high availability, or rolling deploys, consider a managed Kubernetes deployment instead. --- ### n8n URL: https://marketplace.rafftechnologies.com/n8n Tagline: Self-hosted workflow automation, deployed in one click Description: Deploy n8n workflow automation with one click. Self-hosted, extensible, and privacy-friendly with a visual editor. #### Description ## What is n8n? n8n is a fair-code workflow automation tool that connects APIs, services, and internal tools through a visual node-based editor. Workflows can mix pre-built integration nodes with custom JavaScript, so simple glue tasks and complex multi-step pipelines live in the same canvas. Because n8n runs entirely on your own VM, workflow definitions, credentials, and execution history stay on infrastructure you control. There is no third-party SaaS layer in the path between your data and your destinations — useful for teams handling regulated data, internal tooling, or anything where API keys should not leave the perimeter. ## Why deploy n8n on Raff Cloud? - **Self-hosted privacy** — Credentials and workflow data stay on your Raff VM. Nothing transits a third-party automation cloud. - **One-click deploy** — The image boots with n8n already running behind Nginx. Hit the IP and you are at the setup wizard. - **Hardened by default** — UFW firewall and Fail2Ban are pre-configured. SSH is rate-limited against brute force from the first boot. - **Tunable at deploy time** — The Raff dashboard exposes firewall ports, swap size, timezone, Fail2Ban, and auto-updates as toggles before the VM boots, so the host matches your workload without post-deploy config drift. - **Predictable cost** — Flat monthly VM pricing. No per-execution fees, no per-workflow tiers, no surprise overages. - **Full control** — Root SSH, custom nodes, custom environment variables, your choice of database backend. ## Use cases - Internal tooling that connects a CRM, billing system, and team chat to automate customer lifecycle events. - Data sync between two SaaS apps without writing and maintaining glue code. - AI pipelines that chain LLM calls with data sources for content generation, classification, or enrichment. #### Key Features - **Visual workflow editor** — Node-based canvas with branching, looping, and error handling - **400+ integration nodes** — Pre-built connectors for popular SaaS, databases, and developer tools - **Custom code nodes** — Drop in JavaScript when no node fits the job - **Webhook and schedule triggers** — Run workflows on incoming HTTP requests or on a cron - **AI-native nodes** — Built-in support for LLM calls, vector stores, and agent patterns - **Credential vault** — Encrypted credential storage scoped per workflow - **Execution history** — Inspect past runs, replay failures, and debug step by step - **REST API** — Manage workflows and trigger executions programmatically - **UFW firewall and Fail2Ban** — Pre-configured host hardening with SSH brute-force protection - **Configurable at deploy time** — Set firewall ports, swap, timezone, and auto-updates from the Raff dashboard before the VM boots #### Getting Started ## Getting Started 1. **Deploy the VM** — Click "Create n8n VM" in the Raff dashboard and pick a plan that meets the system requirements. 2. **Open the setup wizard** — Browse to `http://` and the n8n setup page loads automatically. 3. **Create the owner account** — Set the email and password for the first n8n admin user. 4. **Connect via SSH for advanced config** — `ssh root@` to edit environment variables, swap the SQLite backend for Postgres, or add a TLS certificate. 5. **Build your first workflow** — Drag a trigger node onto the canvas, chain in actions, and click Execute. ## API Creation Deploy programmatically via the Raff CLI, public REST API, or Terraform. ### CLI ```bash raff vm create --template --plan s-2vcpu-4gb --region tr-ank-1 --name my-n8n ``` ### REST ```bash curl -X POST https://api.rafftechnologies.com/v1/vms \ -H "Authorization: Bearer $RAFF_API_TOKEN" \ -H "Content-Type: application/json" \ -d '{"name":"my-n8n","template_id":"","plan":"s-2vcpu-4gb","region":"tr-ank-1"}' ``` ### Terraform ```hcl resource "raff_vm" "n8n" { name = "my-n8n" template_id = "" plan = "s-2vcpu-4gb" region = "tr-ank-1" } ``` After provisioning, follow the steps above for first-time setup. #### FAQs **Is n8n self-hosted on Raff?** Yes. The n8n Docker container runs on your Raff VM. Workflow definitions, credentials, and execution data live on the VM's disk. No third-party automation SaaS is in the path. **What plan do I need to start?** The 2 vCPU / 4 GB plan is the comfortable starting point for a small team. The 1 vCPU / 2 GB plan works for personal automations but can struggle once concurrent executions and webhook traffic pick up. **How do I update n8n?** SSH into the VM and run `docker pull n8nio/n8n:latest && docker restart n8n`. Workflows and credentials persist in the mounted Docker volume across upgrades. **Where is my data stored?** By default n8n uses an embedded SQLite database stored in a Docker volume on the VM. You can switch to PostgreSQL by editing the container's environment variables and pointing it at any Postgres instance you control. **Is this production-ready?** It is suitable for production internal tooling and team automations on the recommended plan. For high-throughput public webhook workloads, switch the database backend to PostgreSQL and put n8n behind your own TLS terminator. **How do I add HTTPS?** The default image serves n8n over HTTP on port 80 via Nginx. To enable HTTPS, point a domain at the VM and run certbot, or place the VM behind a Raff-managed load balancer with TLS. **Can I use custom nodes?** Yes. n8n supports community and custom nodes installed inside the container. Mount a node directory into the container or build a custom image with your additions baked in. **What license does n8n use?** n8n is fair-code under the Sustainable Use License. It is free to self-host and use internally, with restrictions on offering it as a hosted service to third parties. See n8n's license page for the full terms. **Is the VM secured by default?** Yes. UFW is active with only the ports n8n needs open, and Fail2Ban watches the host's SSH service for brute-force attempts. You can adjust allowed ports, Fail2Ban, swap, timezone, and auto-updates from the Raff dashboard before the VM boots. --- ## Release Notes ### v2.0: Managed Databases, Raff Apps, Functions & VPN URL: https://rafftechnologies.com/release-notes/v2.0 Status: live | Current build: 2.0.2 Last updated: 2026-08-25 Summary: Raff is now a complete cloud platform. Managed Databases with five engines, Raff Apps for running applications straight from your code, Raff Functions for on-demand compute, and private networking with VPN and peering. #### 2.0.2 (2026-08-25, patch) Kubernetes version upgrades, the Kubernetes API, CLI & Terraform, and multiple IPv4s per VM added: - Kubernetes version upgrades, in place. Upgrade a running cluster from the dashboard or the API: rolling, one node at a time, with the cluster API reachable throughout. Automatic patch upgrades in a maintenance window, or fully manual. - Kubernetes API, CLI, and Terraform. The full cluster lifecycle over the REST API, the new raff kubernetes CLI commands, and Terraform resources, with a complete documentation section. - Control-plane health, visible. etcd latency, component restarts, and API-server errors on every cluster. - Multiple public IPv4s per VM. Up to four addresses per VM; the first stays included, and reinstalling the OS keeps them all. - Two smaller VM plans. General-purpose 1 vCPU/1 GB and 1 vCPU/2 GB. changed: - Node removal drains first, always. Pods are moved before a node is removed, PodDisruptionBudgets honored; nothing is force-killed. - The autoscaler thinks like Kubernetes. Fit-checked scale-up, utilization-based scale-down with reschedule simulation. - The Nodes tab is organized by role. Gateway, control plane, workers, and storage, with kubelet health per node. - Complete HA upgrades. Upgrading to HA now doubles the gateway as well as the control plane. fixed: - Backups report what actually happened. Success the moment your restore point exists; no false failures, no duplicate copies. - Browser terminals connect reliably. A terminal service instance could silently lose its registry; it now reconnects automatically. - Site-to-site VPN tunnels survive key renewals. IPsec tunnels re-establish automatically after a rekey. - Renewal invoices are exact. No delayed and no duplicate renewal invoices. - Cluster deletion never loses track. A failed deletion shows as failed, with a working Retry. #### 2.0.1 (2026-08-04, patch) Managed Databases free tier, a rebuilt database console, and app preview environments added: - Managed Databases free tier. Choose the Free plan and run a real production-grade database at no cost: PostgreSQL, MySQL, or Valkey, one free database per account. No trial period, no expiry date. After seven days without a connection it pauses to save resources; one click starts it again with all your data exactly as you left it. We email you before it pauses, and your data is never deleted automatically. - Public database access without a VPC. Databases can now be reached over the internet through a protected shared entry point: your allowlist is enforced before any connection is accepted, with rate limits and per-database connection caps. A VPC is now optional when creating a database. - The database console, rebuilt. Live vitals on the fleet list: load, clients, and storage per database. On each database: query tabs, saved queries stored with the database and shared with your team, EXPLAIN, CSV export, run history, and new Users, Configuration, Performance, Extensions, and Backups tabs. - Database user management. Create, rotate, and delete scoped read-only or read-write users, and the Connect tab renders every connection string for exactly the user you pick. - Verifiable TLS. Download your database's CA certificate from the Connect tab; every connection snippet pins it. No more insecure flags. - Preview environments for Raff Apps. Every open pull request on a connected repository gets its own URL, rebuilt on each push and removed when the PR closes. Free, off by default, on per service. - The Apps console, rebuilt. Traffic, latency, and error rate on the fleet list, per-instance logs and shell, a service events timeline, real health checks, and service settings you can finally edit after creation. - A new release notes experience. One live page per version line, the page you are reading, with RSS, Atom, and JSON feeds. changed: - Database metrics measure only you. Health probes and platform sessions are now excluded from queries per second and client counts, so an idle database reads zero and a paused free database actually pauses. fixed: - Failed provisioning refunds card payments automatically. If provisioning fails after a successful card payment, the full amount is returned to your account balance, every time, for every product. - Renewals and usage charges settle exactly. Prorated renewals advance your billing period correctly, and monthly usage-based charges invoice reliably. Both verified on the August 1 billing run. - Database status tells the truth. A new database no longer flashes Degraded while its engine is still starting, a paused database is shown as paused, and backups no longer show running after they finished. - ClickHouse metrics show the right values. A parsing bug could shift readings onto the wrong fields; every value is now exact. - Valkey plan changes that grow storage now work. Storage expands online during the change. #### 2.0.0 (2026-07-28, major) Managed Databases, Raff Apps, Functions, VPN & Peering added: - Managed Databases. PostgreSQL, MySQL, Valkey, ClickHouse, and Kafka. High availability, automatic backups with restore, private networking, and per-database access control. - Raff Apps. Run applications without managing servers. Deploy from a container image, a template, a Dockerfile, docker-compose, or straight from GitHub. Automatic scaling, custom domains, logs, rollbacks, and one-click connections to your databases and buckets. - Raff Functions. Run code on demand. Write and edit directly in the browser, import your AWS Lambda functions in one click, and trigger on a schedule or on storage events. Spending caps are on by default, so a surprise bill is impossible. - VPN Gateway. Secure WireGuard access into your VPC for you and your team. Five devices, set up by scanning a QR code. - Site-to-Site VPN. Connect your office network or another cloud to your VPC over WireGuard or IPsec. Already carrying production traffic for customers. - VPC Peering. Route privately between two of your VPCs. No extra hardware, no configuration on your VMs. - Networking map. Your whole network on one interactive map: VMs, Kubernetes clusters, databases, apps, and functions, with filters and shareable views. changed: - Volumes moved to distributed storage. Block volumes now live on the same replicated storage cluster as VM disks, with higher capacity and durability. - Windows has its own plan family. Windows VMs run on dedicated plans built for Windows workloads. - Billing you can read. Every product shows up in your subscriptions with its real name, invoices name your coupon and balance instead of internal codes, and deleting any product refunds unused time automatically. - Images moved into Compute. Your images now live in a tab next to Backups, where you actually use them. fixed: - Discounts are exact everywhere. Checkout preview, charge, renewal, and refund now always agree. Coupons apply to the product you redeemed them for, and attached volumes and Windows licenses get their discount at checkout too. - Windows VMs with a Raff license deploy reliably. A scheduling bug could fail creation after payment. Payments were refunded automatically, and creation is now dependable. - Team members see everything they should. Invited members could hit errors in Kubernetes, VM tags, and Object Storage. All access now works regardless of role. - Invitations reach every user. Pending invitations now appear in the dashboard no matter how you signed in. - Purchases land in the right project. Volumes, reserved IPs, and buckets bought at checkout now follow the project you were working in. - Function metrics count every request. Short-lived traffic was invisible to the charts. Usage and metrics are now exact. --- ### v1.5: Managed Kubernetes, Compute & API URL: https://rafftechnologies.com/release-notes/v1.5 Status: maintained | Current build: 1.5.2 Last updated: 2026-07-21 Summary: Managed Kubernetes ships with a free control plane, the compute and VM experience is rebuilt, backups and snapshots share one free-storage pool, and the Raff API, CLI, and Terraform provider go live. #### 1.5.2 (2026-07-21, patch) Reinstall OS, billing, and refund accuracy fixed: - Reinstall OS keeps your public IP. Reinstalling a VM's OS no longer detaches and re-attaches the public IP. - Reinstall OS keeps your IPv6. The IPv6 address is preserved through the reinstall. - Pro-rata refunds are accurate. Refunds now credit to the hour instead of rounding to the start of the day. - Account deletion is safe. Deleting an account with an active subscription now tells you exactly what to clean up first. - Email changes propagate everywhere. Invoices and payment emails follow the new address. #### 1.5.1 (2026-06-30, patch) Kubernetes firewall enforcement and backup chains security: - Kubernetes firewall now actually enforces. Cluster firewalls were applied but not blocking: a default "allow all" rule was silently overriding the secure baseline. fixed: - Incremental backup chains no longer over-delete. Cleanup could delete the whole chain, including newer points that were still valid. - Snapshot rename and delete errors. Renaming or deleting a snapshot could fail with an internal error. - Long VM names no longer break dialogs. Create Snapshot and Backup/Snapshot dialogs overflowed for very long names. #### 1.5.0 (2026-06-18, minor) Managed Kubernetes, Compute rebuilt, API + CLI + Terraform added: - Managed Kubernetes. Free control plane, guided create wizard, node pools with autoscaling, dedicated storage nodes. - Public REST API (Beta), Raff CLI, and Terraform provider. Same API keys, same scoping. - Storage free tier. One shared free-storage pool per account across backups and snapshots. - Multiple backup schedules per VM and a dedicated VM Security tab. changed: - Compute, rebuilt. Live CPU and RAM on the list, redesigned Resources list, every VM detail tab polished. - Retention is now "keep N most recent" instead of days and weeks. - Persistent terminal sessions: browser terminals reconnect instead of dropping. --- ### v1.4: VPC Networking, Marketplace, Security & Audit Log URL: https://rafftechnologies.com/release-notes/v1.4 Status: maintained | Current build: 1.4.0 Last updated: 2026-04-08 Summary: Rebuilt VPC networking with gateways, port forwarding, and security groups. One-click app marketplace, CloudTrail-style audit logs, and major compute UX improvements. #### 1.4.0 (2026-04-08, minor) VPC gateways, port forwarding, marketplace, audit log added: - VPC gateways and port forwarding. Route public traffic into private subnets. - Security groups. Reusable, attachable rule sets. - App marketplace. One-click installs for common stacks. - Audit log. Every account action, who did it, and from where. changed: - Compute UX improvements across list, create, and detail. --- ### v1.3: S3 Object Storage, API Keys & Raff Learn URL: https://rafftechnologies.com/release-notes/v1.3 Status: maintained | Current build: 1.3.0 Last updated: 2026-03-18 Summary: S3-compatible object storage, expanded API key management with project and VM scoping, and Raff Learn for tutorials and guides. #### 1.3.0 (2026-03-18, minor) S3-compatible object storage and scoped API keys added: - Object Storage. S3-compatible buckets, presigned URLs, lifecycle rules. - API key management. New UI with project and VM scoping. - Raff Learn. Tutorials and guides in the dashboard. --- ### v1.2: Web Terminal, API Launch & Windows Templates URL: https://rafftechnologies.com/release-notes/v1.2 Status: maintained | Current build: 1.2.0 Last updated: 2026-03-09 Summary: Enterprise-grade web terminal, the first public API release with API keys, Windows Server Standard templates, and automatic invoices. #### 1.2.0 (2026-03-09, minor) Web terminal, first public API, Windows templates added: - Web terminal. Browser shell for every VM. - Public API with API keys. First release. - Windows Server Standard templates. changed: - Improved billing with automatic invoices; dozens of mobile fixes. --- ### v1.1: VPC, Reserved IPs & Subscription Billing URL: https://rafftechnologies.com/release-notes/v1.1 Status: maintained | Current build: 1.1.0 Last updated: 2026-02-03 Summary: A new beginning for Raff. Simple subscription billing replaces top-ups, VPC networking isolates your infrastructure, and Projects & Team Invites let you collaborate. #### 1.1.0 (2026-02-03, minor) Subscription billing, VPC, Reserved IPs, Projects added: - VPC networking. Private, isolated infrastructure. - Reserved IPs. Keep production addresses stable. - Projects & Team Invites. removed: - Balance top-ups, replaced by simple subscription billing. --- ### v1.0: The Foundation URL: https://rafftechnologies.com/release-notes/v1.0 Status: maintained | Current build: 1.0.0 Last updated: 2026-01-05 Summary: A complete rebuild of the Raff platform. Backend rewritten in Go, frontend and backend migrated from AWS, Render, and Vercel to Raff's own Kubernetes infrastructure. We run on Raff before you do. #### 1.0.0 (2026-01-05, minor) Platform rebuild on Raff's own infrastructure changed: - Backend rewritten in Go. - Migrated off AWS, Render, and Vercel onto Raff Kubernetes. --- ### v0.9: The Turning Point: Foundation & Growth URL: https://rafftechnologies.com/release-notes/v0.9 Status: archived | Current build: 0.9.0 Last updated: 2025-12-02 Summary: Service tier system, redesigned payment infrastructure, and the foundational work that positioned Raff as a complete platform. #### 0.9.0 (2025-12-02, minor) Service tiers and new payment infrastructure added: - Service tier system and redesigned payment infrastructure. --- ### v0.8: Dark Mode, VNC Console, Custom Images & Referrals URL: https://rafftechnologies.com/release-notes/v0.8 Status: archived | Current build: 0.8.2 Last updated: 2025-09-24 Summary: The line that shipped dark mode, browser-based VNC, custom image upload, referral rewards, and enterprise-grade DDoS protection. #### 0.8.2 (2025-09-24, patch) New website, custom images, VM reboot controls added: - Custom image upload up to 100 GB with automated processing. - VM reboot controls and mobile menu improvements. #### 0.8.1 (2025-09-02, patch) Referral rewards and DDoS protection added: - Referral and loyalty program, up to $365 in credits. security: - Enhanced password policies and enterprise-grade DDoS protection. #### 0.8.0 (2025-08-27, minor) Dark mode, VNC console, VM operations added: - Dark mode, browser-based VNC console, OS change and reset operations. --- ### v0.7: Advanced Billing, Storage Management (Volumes, Backups, Snapshots), Marketplace Templates & Enhanced Security URL: https://rafftechnologies.com/release-notes/v0.7 Status: archived | Current build: 0.7.3 Last updated: 2025-06-23 Summary: 0.7.0 introduces powerful Volumes for storage management and new data protection features like Backups & Snapshots. Benefit from enhanced billing & payments, secure your account with MFA, manage SSH keys for secure VM access, and experience various UI improvements across the platform. #### 0.7.3 (2025-06-23, patch) VM tags, priorities, and the mobile platform launch added: - Tag system for VMs. Group machines into environments like production, development, and staging, with grouped and list views. - Priority levels (1 to 9) to keep critical VMs front and center in the dashboard. - Full mobile compatibility. Manage VMs, billing, and account settings from any phone or tablet browser. changed: - Responsive design refinements across every section of the platform. - Improved password validation and clearer form feedback. - Clearer, more user-friendly privacy policy and terms of service. #### 0.7.2 (2025-06-16, patch) Analytics, phone verification, and auth polish added: - Phone verification with SMS consent for more secure account verification. - Centralized analytics and monitoring for better stability and faster issue resolution. changed: - Streamlined sign-in and sign-up UI, with improved Google and GitHub OAuth consent flows. - Template documentation redirects and a clearer template help menu. - Optimized payment banner and consistent branding across the app. #### 0.7.1 (2025-05-06, patch) Stripe, Google Pay / Apple Pay, and dual payment modes added: - Stripe payment flow with comprehensive validation and real-time webhook status updates. - Google Pay and Apple Pay support. - Dual payment modes. Automatic 3DS detection decides per card between manual payment and automatic end-of-period charging. - Welcome credit increased to $200, valid for 2 months. fixed: - Billing calculation problems on the UI side and numerous payment validation bugs. #### 0.7.0 (2025-04-22, minor) Volumes, backups, snapshots, MFA, and SSH keys added: - Volumes. Create, attach, detach, resize, and snapshot storage volumes, with mount instructions for Linux and Windows VMs. - Backups. Instant or scheduled backups with retention limits, restore, and reliable background processing. - Snapshots for VMs and images, with restore. - MFA and SSH key management for account and VM security. - PayTR payment provider and full payment method management. changed: - VM create, details, and table improved, with new Snapshots, Backups, and Volumes tabs on VM detail. - Cleaner Marketplace Templates UI with new template options. --- ### v0.6: Payment integration, new services and UI improvements. URL: https://rafftechnologies.com/release-notes/v0.6 Status: archived | Current build: 0.6.0 Last updated: 2025-02-20 Summary: This release brings major updates to servies, payment processing, UI improvements, and overall app stability. #### 0.6.0 (2025-02-20, minor) Payment integration, new services, and UI improvements added: - Payment processing integration with payment method management. - New service options and template improvements. changed: - UI improvements and stability fixes across the platform. --- ### v0.5: Our first production release! URL: https://rafftechnologies.com/release-notes/v0.5 Status: archived | Current build: 0.5.0 Last updated: 2025-02-09 Summary: This release marks the debut of Raff Technologies’ production-ready platform, featuring a robust support system and enhanced payment processing. #### 0.5.0 (2025-02-09, minor) Our first production release added: - Raff goes production. The first production-ready release of the platform. - A robust support system and enhanced payment processing. --- ## Documentation - Developer Docs: https://docs.rafftechnologies.com - API Reference: https://docs.rafftechnologies.com/api-reference/endpoints ## Contact - Website: https://rafftechnologies.com/contact-us - Email: info@rafftechnologies.com - Support: support@rafftechnologies.com