Deployment¶
Deploy your gallery to production.
Recommended Workflow¶
Goldplated Photos is designed for a local development → deploy to server workflow:
┌─────────────────────────────────────────────────────────┐
│ LOCAL DEVELOPMENT │
│ │
│ ┌─────────────┐ ┌─────────────┐ │
│ │ Admin Panel │ ──────► │ Dev Server │ │
│ │ :4444 │ edits │ :4321 │ │
│ └─────────────┘ └─────────────┘ │
│ │
│ • Edit albums, upload photos via Admin Panel │
│ • Preview changes in Dev Server │
│ • All changes saved to src/content/albums/ │
└─────────────────────────────────────────────────────────┘
│
│ npm run deploy
▼
┌─────────────────────────────────────────────────────────┐
│ PRODUCTION SERVER │
│ │
│ • Builds site locally (npm run build) │
│ • Syncs content via rsync (--delete) │
│ • Restarts Node.js app via PM2 │
└─────────────────────────────────────────────────────────┘
Key Points
- Admin Panel is LOCAL ONLY - Never deployed to production
- Local content is source of truth - rsync uses
--deleteflag - Single command deployment -
npm run deployhandles everything
Quick Deploy¶
If you have SSH access configured and PM2 on your server:
This single command:
- Builds the production site locally
- Fixes paths for production server
- Syncs all files to remote via rsync
- Sets up symlinks on server
- Installs production dependencies
- Restarts PM2
Deploy Script Details¶
The npm run deploy command runs scripts/deploy.sh which performs:
Step 1: Build¶
Creates dist/ folder with optimized site.
Step 2: Fix Paths¶
Runs fix-server-paths.mjs to update paths for production.
Step 3: Sync Files¶
Uses rsync to transfer:
dist/client/- Static assetsdist/server/- Server codesrc/content/albums/- All albums (with --delete)public/- Hero images, card images, etc.package.json- Dependenciesecosystem.config.cjs- PM2 configuration
Step 4: Configure Remote¶
Creates symlinks on server for Apache to serve images directly.
Step 5: Install Dependencies¶
Step 6: Restart PM2¶
Deploy Configuration¶
Edit scripts/deploy.sh to configure your server:
Prerequisites¶
- SSH key access to server (no password prompt)
- PM2 installed on server
- Node.js 18+ on server
ecosystem.config.cjsfile in project root
Manual Deployment¶
If you prefer manual deployment or don't have rsync:
Build for Production¶
This creates a dist/ folder with:
dist/client/- Static assetsdist/server/- Node.js server code
Server Requirements¶
Since Goldplated Photos uses SSR for password protection, you need a Node.js server:
- Node.js 18+
- Persistent file system (for thumbnail cache)
- HTTPS recommended (for secure cookies)
Running in Production¶
Basic Start¶
With Environment Variables¶
With PM2 (Process Manager)¶
# Install PM2
npm install -g pm2
# Start with PM2
pm2 start dist/server/entry.mjs --name goldplated-photos
# Auto-restart on reboot
pm2 startup
pm2 save
Deployment Platforms¶
VPS / Dedicated Server¶
- Clone repository to server
- Install dependencies:
npm install - Build:
npm run build - Start with PM2 or systemd
- Configure reverse proxy (nginx/Caddy)
Docker¶
FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
RUN npm run build
EXPOSE 3000
ENV HOST=0.0.0.0
ENV PORT=3000
CMD ["node", "dist/server/entry.mjs"]
Vercel / Netlify¶
These platforms have limited SSR support. For full functionality:
- Use the Vercel/Netlify Astro adapter instead of Node
- Note: Some features may not work (in-memory rate limiting)
Reverse Proxy¶
Nginx¶
server {
listen 80;
server_name photos.example.com;
return 301 https://$server_name$request_uri;
}
server {
listen 443 ssl http2;
server_name photos.example.com;
ssl_certificate /path/to/cert.pem;
ssl_certificate_key /path/to/key.pem;
location / {
proxy_pass http://localhost:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection '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;
proxy_cache_bypass $http_upgrade;
}
# Cache static assets
location /_astro/ {
proxy_pass http://localhost:3000;
expires 1y;
add_header Cache-Control "public, immutable";
}
}
Caddy¶
Content Management Workflow¶
Adding New Albums¶
- Create album folder in
src/content/albums/ - Add
index.mdand photos - Rebuild:
npm run build - Restart server
Updating Existing Albums¶
For photo changes only (no code changes):
- Add/remove photos in album folder
- Delete cached thumbnails if needed:
rm -rf .meta/thumbnails - Rebuild:
npm run build - Restart server
Quick Preview¶
Preview runs the production build locally.
SSL Certificates¶
Let's Encrypt (Certbot)¶
# Install certbot
sudo apt install certbot python3-certbot-nginx
# Get certificate
sudo certbot --nginx -d photos.example.com
# Auto-renewal is configured automatically
Cloudflare¶
- Enable Cloudflare proxy for your domain
- Set SSL mode to "Full (strict)"
- Certificates managed automatically
Monitoring¶
PM2 Monitoring¶
Health Check Endpoint¶
Add a simple health check in your nginx config:
Backup Strategy¶
What to Backup¶
src/content/albums/- All your photos and metadata.meta/thumbnails/- Optional (can be regenerated)- Database/state - Not applicable (all file-based)
Backup Script¶
#!/bin/bash
BACKUP_DIR="/backups/goldplated-$(date +%Y%m%d)"
mkdir -p "$BACKUP_DIR"
# Backup albums
tar -czf "$BACKUP_DIR/albums.tar.gz" src/content/albums/
# Backup configuration
cp astro.config.mjs "$BACKUP_DIR/"
cp package.json "$BACKUP_DIR/"
Performance Tips¶
Thumbnail Pre-warming¶
Visit all albums once after deployment to generate thumbnails:
# Simple approach - visit each album page
curl http://localhost:3000/photos/2025/album1
curl http://localhost:3000/photos/2025/album2
CDN for Static Assets¶
Configure your CDN to cache /_astro/ paths with long TTLs.
Image Optimization¶
Before uploading, optimize source images:
Troubleshooting¶
Server Won't Start¶
- Check Node.js version:
node --version - Verify build completed:
ls dist/server/ - Check port availability:
lsof -i :3000
Thumbnails Not Generating¶
- Check
.meta/directory permissions - Verify Sharp is installed correctly
- Check server logs for errors
Password Protection Not Working¶
- Verify SSR is enabled in
astro.config.mjs - Check
album-accesscookie in browser - Ensure HTTPS for secure cookies in production
Related¶
- Admin Panel - Local content management
- Configuration - All options
- Architecture - Technical details