Security hardening, cost control and migrations
WAF, DDoS protection and security headers, patch policy, least-privilege access, rightsizing and egress savings, and moving a live site between hosts.
Edge protection and headers
# security headers that are safe for most sites
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Referrer-Policy "strict-origin-when-cross-origin" always;
add_header Permissions-Policy "geolocation=(), microphone=(), camera=()" always;
add_header Content-Security-Policy "default-src 'self'; img-src 'self' data: https:; object-src 'none'; base-uri 'self'; frame-ancestors 'self'" always;
# rate limit the endpoints that get abused
limit_req_zone $binary_remote_addr zone=login:10m rate=5r/m;
location = /login {
limit_req zone=login burst=5 nodelay;
proxy_pass http://app;
}| Control | Protects against | Do not rely on it for |
|---|---|---|
| WAF (managed rules) | Known exploit patterns | Business logic abuse |
| WAF (custom rules) | Specific abusive patterns you observe | Anything you have not tested |
| DDoS absorption | Volumetric floods | Application-layer attacks that look like users |
| Rate limiting | Credential stuffing and scraping | Distributed attacks from many addresses |
| Security headers | Clickjacking, MIME sniffing, referrer leakage | Server-side vulnerabilities |
| Bot scoring | Automated abuse | Blocking real users - test before enforcing |
- Roll out a CSP in report-only mode first. A strict policy applied blind breaks inline scripts and third-party widgets, and the users find out before you do.
- Rate limit by the cheapest key that is correct - IP plus route, not IP alone, or one office behind a NAT gets blocked.
- Block only what you can explain. Aggressive rules that block legitimate clients are a self-inflicted outage by a different name.
Access and patch policy
- No shared accounts. Every human has their own identity, and production access is granted per person and revoked on departure.
- Hardware-key two-factor for the provider console, the repository and the DNS provider. These three control everything else.
- Least privilege for service accounts: one role per service, scoped to the resources it needs, with no wildcard policies.
- No long-lived keys where an instance identity or a short-lived token is available.
- Patch on a schedule: OS security updates monthly, application dependencies weekly, with an emergency path for a critical advisory.
- Log every administrative action and keep the log where the administrator cannot edit it.
# automated dependency and OS patching signals
npm audit --omit=dev --audit-level=high
docker scout cves registry.example/app:latest
# unattended security upgrades on a Debian-based host
# /etc/apt/apt.conf.d/20auto-upgrades
# APT::Periodic::Update-Package-Lists "1";
# APT::Periodic::Unattended-Upgrade "1";The security control that fails most often is not a missing WAF rule, it is an unpatched dependency or a former employee's still-active key. Put a calendar entry on the patch cycle and an audit of active keys next to it.
Cost control and migrations
| Cost lever | Typical saving | Risk |
|---|---|---|
| Right-size instances | 20-40 percent on over-provisioned compute | Under-provisioning at peak |
| Move static assets to a CDN | Large on egress | Cache invalidation mistakes |
| Compress and convert images | Large on egress | Quality regressions |
| Shorten log retention | Modest but easy | Less history when debugging |
| Delete unattached volumes and old snapshots | Surprisingly large | Deleting something still needed |
| Reserved capacity or commitments | 20-40 percent on steady baseline | A lock-in if usage changes |
| Turn off non-production overnight | Large for staging | Nobody can test when they want to |
| Reduce third-party API calls | Varies | Feature or quality loss |
Migrating a live site between hosts
1. inventory every record, every cron job, every certificate, every integration
2. lower TTLs 48 hours before any DNS change
3. provision the new environment and deploy the same artefact
4. copy data with a documented cutover point or continuous replication
5. test against the new environment by host header, not by the public name
6. cut over DNS, or the load balancer, in one change
7. verify resolution, TLS, email, payments, login, and the slowest page
8. keep the old running and unmodified for a week
9. clean up after the window, and only after a written sign-off- Test the new host with the Host header pointing at it before any public change. You want to discover certificate and absolute-URL problems while nobody is affected.
- Move the data with a defined freeze or a replication lag target. "Copy it and then copy the delta" without a checkpoint loses writes.
- After the switch, keep the previous environment serving for a week. It is the fastest rollback you will ever have.
⚠️
Never delete the old environment or its data on the day of a migration. The most expensive mistake in this whole area is cleaning up early - the old host and its backups cost a rounding error for a week, and deleting them removes every rollback path you have.
FAQ
Do I need a WAF?
If you run a login form, a payment flow or anything an attacker can automate, yes - a managed ruleset is cheap insurance. It does not replace fixing application vulnerabilities.
How long should a migration take?
The cutover is minutes. The safe window around it is days: lower TTLs before, test the new host directly, keep the old one afterwards, and only then clean up.
Related
Choosing a host: cost, lock-in and support Custom domains and TLS
Last refreshed 2026-09-18.