Deployment Guide

Deployment is the last mile that turns code into a running service — and the most error-prone step. Whether you install LNMP by hand or orchestrate with Docker Compose, the resources below help you move from "it runs" to "stable and production-ready."

AI Prompt Template

Help me deploy a production server.
- Site Type: [Static/PHP/Node.js/Python]
- Server OS: [Ubuntu/CentOS/Debian]
- Database: [MySQL/PostgreSQL/SQLite]
- HTTPS: [Yes/No]

Output: server init, Nginx config, runtime installation, database setup, SSL cert.

LNMP One-Click Deployment

On a fresh Ubuntu server, one command installs Nginx, MySQL, and PHP:

apt update && apt install -y nginx mysql-server php-fpm php-mysql
apt install -y certbot python3-certbot-nginx

After installation, run the security initializer: mysql_secure_installation to set the root password and remove anonymous users and the test database.

Nginx Site Configuration

server {
    listen 443 ssl http2;
    server_name yourdomain.com;
    root /var/www/yourdomain;
    ssl_certificate /etc/letsencrypt/live/yourdomain.com/fullchain.pem;
    ssl_certificate_key /etc/letsencrypt/live/yourdomain.com/privkey.pem;
    location / { try_files $uri $uri/ /index.php?$query_string; }
    location ~ \.php$ { fastcgi_pass unix:/var/run/php/php8.1-fpm.sock; }
    location ~* \.(jpg|png|ico|css|js)$ { expires 30d; }
}

Docker Compose for LAMP Stack

version: '3.8'
services:
  web:
    image: nginx:alpine
    ports: ["80:80", "443:443"]
    volumes: ["./site:/usr/share/nginx/html"]
  db:
    image: mariadb:10
    environment:
      MYSQL_ROOT_PASSWORD: ${DB_PASSWORD}
    volumes: ["db_data:/var/lib/mysql"]
volumes: {db_data:}

Inject passwords through .env; never hard-code MYSQL_ROOT_PASSWORD in the compose file.

SSL Certificate with Certbot

apt install certbot python3-certbot-nginx -y
certbot --nginx -d example.com -d www.example.com
certbot renew --dry-run

Deployment Is More Than Uploading Files

"It works on my machine" — these words haunt every ops engineer. The differences between local and production environments cause some of the hardest-to-diagnose production issues.

The goal of deployment isn't "put code on a server." It's "create a predictable, repeatable runtime environment."

Environment Management Principles

1. Consistency

Minimize differences between dev, staging, and production. A single minor version difference in PHP can change function behavior.

Do this: Define your local environment with Docker Compose or Vagrant so anyone can be running in 10 minutes.

2. Configuration Separation

Code and configuration are different things. Database passwords and API keys don't belong in repositories.

project/
├── .env.example        # committed, contains all keys as templates
├── .env                # gitignored, actual values
├── config/
│   ├── app.php
│   └── database.php    # reads from .env

3. Rollback Capability

Every deployment should be rollbackable within 5 minutes. If yours isn't, you're gambling.

Deployment Strategy Comparison

Strategy Downtime Complexity Use Case
Direct replace Yes Low Personal projects, low traffic
Blue-green No Medium Business sites, production
Rolling update No Medium Multi-instance clusters
Canary No High High-traffic critical services

For small to medium sites, blue-green is the sweet spot: maintain two environments, deploy to green, validate, switch traffic. If something goes wrong, switch back to blue. One caveat: blue-green needs double the machine resources. If the budget is tight, a fallback that still hits the 5-minute rollback goal is to keep the previous build artifacts around and script a one-command rollback.

Backup Reality Check

Backups are only as valuable as your ability to restore from them.

Data Type Frequency Retention Restore Drill
Database Daily full + hourly incremental 30 days Monthly
File assets Daily snapshot 7 days Quarterly
Config files Every change Git history forever Not needed

Critical advice: Don't wait for a disaster to test your backups. Run a monthly restore drill on a clean server and verify data integrity. You might be surprised how many backups fail to restore.

SSL Reality

Let's Encrypt certificates are sufficient for most sites. Configure auto-renewal with Certbot, set up monitoring to verify renewal succeeded, and check certificate status monthly. This prevents the panicked "our cert expired!" discovery a year later.

Pre-Launch Checklist

Deploying is not the same as being ready for traffic. Go through this list before cutting over, and you will avoid most "launch-day incidents":

  • Firewall only exposes the necessary ports (80/443/SSH); SSH uses key-based login
  • Database password is not the default, and the DB only accepts internal connections
  • Site directory permissions are tightened; upload directories cannot execute PHP
  • HTTPS is live site-wide with HTTP redirecting to HTTPS
  • Log rotation is configured so logs do not fill the disk
  • Backup scripts have run end-to-end, and one restore drill has been completed

When Deployment Goes Wrong

However solid your process, there will be a moment when a release breaks the API or the page goes blank. What saves you is not improvisation but a plan: first roll back to the previous version so the business recovers, then debug slowly — do not edit code on the server while production is failing. Rollback requires that both code directories and database schema can be reverted quickly, which is exactly why configuration separation and rollback capability must be in place before the incident, not on the day of it.

If your team is small, consider a control panel or a CI/CD tool to turn deployment into a repeatable pipeline and remove the human error that comes with manual steps.