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.