Infrastructure

Server Management, Self-Hosting, and DevOps Basics


Your application is only as reliable as the servers it runs on. The most carefully tested Laravel codebase becomes worthless when a deployment corrupts the database, a disk fills up at 3am, or a certificate expires without anyone noticing. Web application infrastructure is the set of decisions and systems that prevent those failures.

Since 2005, we have provisioned and managed infrastructure for 50+ Laravel applications. Some of those systems have been running continuously for over a decade. The patterns described here come from that history: real failures, real fixes, and the operational discipline that keeps production systems alive.


The Constraint: Why Infrastructure Decisions Compound

Most development teams treat infrastructure as an afterthought. The application gets attention; the server gets whatever the default setup provides. This works until it does not.

A single misconfigured Nginx worker pool causes request queuing under load. A database running on the same disk as the application means a large import fills the volume and crashes both. An SSL certificate that renews manually gets forgotten and takes the site offline on a Saturday morning.

The compounding effect: Every infrastructure decision constrains future options. The hosting provider you choose determines your scaling options. Your deployment method determines your rollback speed. Your monitoring setup determines whether you find problems or your users do.

The constraint is this: infrastructure must be reproducible, observable, and recoverable. If you cannot rebuild a server from scratch in under an hour, you do not have infrastructure. You have a snowflake.


The Naive Approach: Manual Servers and Hope

The tutorial version of deployment looks like this: SSH into a server, run git pull, run composer install, run php artisan migrate, restart PHP-FPM. It works on the first deploy. It fails on the fiftieth.

The problems accumulate gradually. File permissions drift. Environment variables get edited directly on the server and never recorded anywhere. A failed migration leaves the database in a half-applied state. A composer install downloads a new dependency version that breaks the application, and there is no way to roll back without restoring a full backup.

No documentation: One developer configured the server months ago. Nobody else knows the Nginx configuration or which PHP extensions are installed.
No monitoring: Someone checks the site occasionally. Disk space is not tracked. Memory usage is not graphed. The first sign of trouble is a customer complaint.
No rollback: A failed deployment means restoring a full backup. Recovery time is measured in hours, not seconds.
No reproducibility: The server is a snowflake. Rebuilding it from scratch would take days of detective work.

The pattern extends to hosting decisions. A team starts on shared hosting because it is cheap. The application grows. Shared hosting throttles CPU during peak hours. The response is to upgrade to a bigger plan, then a VPS, then a managed platform, each migration requiring a full rebuild because nothing was documented or automated.


The Robust Pattern: Infrastructure as a Managed System

We treat web application infrastructure as code, not as a set of manual configurations. Every server we provision follows a repeatable process. Every deployment is atomic. Every failure mode has a documented recovery path.

The stack

Our standard Laravel infrastructure stack uses these components, each chosen for a specific reason and managed against a specific failure mode.

Ubuntu LTS on a VPS

Hetzner or DigitalOcean, depending on region and requirements. Long-term support releases provide security patches without breaking changes.

Laravel Forge for provisioning

Server provisioning, SSL management, and deployment orchestration. Handles PHP installation, Nginx configuration, and Let's Encrypt certificates.

Nginx + PHP-FPM

Nginx handles request routing and SSL termination. PHP-FPM manages application worker processes, with pool sizes calculated from available memory (each worker consumes roughly 30-50MB).

PostgreSQL + Redis

PostgreSQL on a separate volume or server for I/O isolation. Redis provides sub-millisecond reads for cache, session storage, and queue processing.

This is not a complex stack. It is deliberately simple. Fewer moving parts means fewer failure points, and every component has been battle-tested across hundreds of thousands of production hours.

Why Laravel Forge

We use Laravel Forge to provision and manage servers. Forge handles the tedious parts of server setup while still allowing SSH access for the remaining 10% that requires custom configuration. The alternative is maintaining Ansible playbooks or shell scripts for server provisioning. We have done both. Forge reduces the operational burden for the 90% case.

Forge also provides a deployment pipeline: pull code, install dependencies, run migrations, build assets, restart PHP-FPM. Each step is logged. Failures halt the pipeline before the application is affected.


Hosting Decisions: VPS, Cloud, and Managed Platforms

Choosing where to host a web application is a decision with long-term consequences. The wrong choice costs money, limits scaling options, or creates vendor dependency.

VPS hosting (our default)

For most Laravel applications serving under 50,000 daily users, a well-configured VPS is the correct choice. A single server with 4 vCPUs, 8GB RAM, and SSD storage handles more traffic than most businesses generate.

We default to Hetzner for European hosting. The cost difference is significant: a Hetzner CPX31 (4 vCPU, 8GB RAM, 160GB SSD) costs approximately €15/month. The equivalent DigitalOcean droplet costs $48/month. The equivalent AWS EC2 instance costs roughly $70/month before storage and data transfer. That price gap compounds over years.

VPS hosting also means you own your infrastructure. No platform lock-in, no proprietary APIs, no sudden pricing changes.

When to use cloud platforms

AWS, Google Cloud, and Azure make sense when you need specific managed services: object storage with CDN (S3 + CloudFront), managed database clusters with automated failover, or serverless compute for unpredictable workloads.

Cost warning: Cloud billing is notoriously difficult to predict. Egress charges, NAT gateway fees, and per-request pricing on managed services can triple the expected monthly cost. We have seen AWS bills double overnight because a misconfigured logging pipeline was writing gigabytes to CloudWatch.

Our rule: start with a VPS. Move specific services to cloud platforms when you have a concrete requirement that a VPS cannot satisfy. Do not start on AWS because it feels professional. Start on a VPS because it is simple, fast, and cheap.

Managed application platforms

Laravel Vapor, Railway, and similar platforms abstract away server management entirely. These platforms suit applications with highly variable traffic or teams with no infrastructure expertise. The cost per request is higher, but the operational burden is near zero. The limitation is control: when something goes wrong at the platform level, you wait for their support team.


Zero-Downtime Deployments

Every production deployment we run follows the atomic deployment pattern. A deployment pipeline is not a luxury. It is the difference between a five-second rollback and a two-hour recovery.

1

Create a new release directory

Clone or pull the latest code into a fresh directory on the server. Install Composer dependencies with --no-dev --optimize-autoloader.

2

Run migrations and build assets

Run database migrations with a pre-flight check. Build frontend assets if required. Run a health check against the new release.

3

Swap the symlink

Point the current symlink at the new release directory. This is atomic. The application serves the old release until the exact moment the symlink changes.

4

Reload and clean up

Graceful PHP-FPM restart (no dropped connections). Purge old releases, keeping the last five for rollback. Rollback means pointing the symlink at a previous directory: a one-second operation.

The naive approach (running git pull in the live directory) means the application serves partially-updated code during deployment. A request hitting the server mid-pull might load old controllers with new views. This causes errors that are difficult to reproduce and diagnose.


Monitoring and Alerting

Monitoring without alerting is data collection. Alerting without monitoring is guesswork. We configure both.

Metric Alert Threshold Why It Matters
HTTP 5xx rate Above 1% Application errors affecting users
Response time (p95) Above 500ms Performance degradation under load
Disk usage 80% warning, 90% critical Most common infrastructure failure
Memory Below 500MB free Process starvation and OOM kills
SSL certificate expiry 14 days before expiry Auto-renewal can fail silently
Queue depth Above configured threshold Background work is backing up

Lessons from production

Certain monitoring lessons only come from experience. These are the ones that have saved us repeatedly.

Disk full is the most common failure. Log files, failed job output, and temporary upload files fill disks silently. Automated log rotation and disk monitoring prevent this.
Memory leaks in queue workers cause gradual degradation. Workers should restart after a fixed number of jobs (--max-jobs=1000).
Certificate auto-renewal fails silently when the HTTP challenge cannot reach the server (firewall rules, CDN configuration). Test renewal manually after any networking change.
DNS propagation takes up to 48 hours. Plan DNS changes well ahead of any deadline.

Backup Strategy

We follow the 3-2-1 rule: three copies of data, on two different storage types, with one copy off-site.

Database backups

Automated daily PostgreSQL dumps, stored locally and replicated to off-site object storage. Point-in-time recovery enabled for production databases.

Uploaded files

Synced to off-site storage nightly. Large media files stored directly in object storage (S3 or equivalent) rather than on the application server.

Server configuration

Managed through Forge. A new server can be provisioned from scratch in under 30 minutes.

The critical discipline is testing restores. A backup that has never been restored is a hope, not a backup. We test database restores monthly and document the recovery time. If a full restore takes longer than the business can tolerate, we adjust the strategy.


Scaling: Vertical First, Then Horizontal

Premature scaling wastes money and adds operational complexity. Most Laravel applications never need horizontal scaling. Vertical scaling (upgrading the server) is simpler, cheaper, and sufficient for the vast majority of workloads.

Vertical scaling

A single well-configured server handles more traffic than most teams expect. Nginx serves static assets from memory. Redis eliminates repeated database queries. PHP-FPM worker tuning ensures available memory is used efficiently. When a server is genuinely under-resourced, the fix is straightforward: increase RAM, add CPU cores, switch to faster storage.

When horizontal scaling is necessary

Horizontal scaling becomes necessary when a single server cannot handle the requirements regardless of size, or when you need geographic distribution for latency reasons. It requires architectural changes that are best planned before they are needed.

Sessions in Redis (not the filesystem)
File uploads in object storage (not the local disk)
Load balancer distributing traffic across application servers
Database connection pooling to prevent connection exhaustion
Centralised logging so you can debug across multiple servers

The decision rule: if your monthly hosting cost is under £500 and you are not experiencing performance problems, you do not need horizontal scaling. Invest that engineering time in application-level optimisation instead: query optimisation, caching strategies, and efficient background job processing.


Infrastructure as an Asset

Web application infrastructure is not a cost centre. It is an operational asset that determines uptime, deployment speed, and recovery capability.

  • Deployments happen multiple times per day Atomic deploys with one-second rollback. No stress, no downtime, no maintenance windows.
  • Failures are detected before users notice Continuous monitoring with targeted alerts. Problems found in minutes, not days.
  • Recovery follows a documented procedure Tested backups, rehearsed restores, known recovery times. No panicked improvisation.
  • Provider independence Standard Linux servers on standard infrastructure. Move providers in a day, not a quarter.

This is closely related to the question of owning versus renting your systems. Infrastructure decisions also affect your security and operational posture. Every component in the stack is a potential attack surface. Fewer components, kept current and monitored, means a smaller surface to defend.


Get Your Infrastructure Right

Since 2005, we have built and managed infrastructure for businesses that depend on their web applications daily. The first conversation is free and comes with no obligation.

Book a discovery call →
Graphic Swish