Add complete infrastructure automation and documentation
Some checks failed
Deploy to Production / Deploy to Server (push) Has been cancelled
Some checks failed
Deploy to Production / Deploy to Server (push) Has been cancelled
- infrastructure/setup.sh: Master provisioning script for fresh Ubuntu servers - infrastructure/docker-compose.yml: Production Docker Compose configuration - infrastructure/.env.template: Environment variables template - infrastructure/nginx/: Nginx configuration with security headers - infrastructure/postfix/: Postfix + OpenDKIM email configuration - infrastructure/README.md: Complete disaster recovery guide - scripts/docfast-backup.sh: SQLite backup script with rotation All services now fully reproducible with documented disaster recovery procedures.
This commit is contained in:
parent
d99eea517c
commit
3820d7ea4d
9 changed files with 766 additions and 0 deletions
27
infrastructure/.env.template
Normal file
27
infrastructure/.env.template
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
# DocFast Environment Variables Template
|
||||||
|
# Copy this to .env and fill in real values
|
||||||
|
|
||||||
|
# Stripe Configuration (Production keys)
|
||||||
|
STRIPE_SECRET_KEY=sk_live_FILL_IN_YOUR_STRIPE_SECRET_KEY
|
||||||
|
STRIPE_WEBHOOK_SECRET=whsec_FILL_IN_YOUR_WEBHOOK_SECRET
|
||||||
|
|
||||||
|
# Application Configuration
|
||||||
|
BASE_URL=https://docfast.dev
|
||||||
|
API_KEYS=FILL_IN_YOUR_API_KEYS_COMMA_SEPARATED
|
||||||
|
PRO_KEYS=FILL_IN_YOUR_PRO_KEYS_COMMA_SEPARATED
|
||||||
|
|
||||||
|
# Database Configuration
|
||||||
|
DATABASE_PASSWORD=FILL_IN_SECURE_PASSWORD
|
||||||
|
|
||||||
|
# Optional: Override defaults if needed
|
||||||
|
# PORT=3100
|
||||||
|
# NODE_ENV=production
|
||||||
|
# SMTP_HOST=host.docker.internal
|
||||||
|
# SMTP_PORT=25
|
||||||
|
# DATABASE_HOST=172.17.0.1
|
||||||
|
# DATABASE_PORT=5432
|
||||||
|
# DATABASE_NAME=docfast
|
||||||
|
# DATABASE_USER=docfast
|
||||||
|
# POOL_SIZE=15
|
||||||
|
# BROWSER_COUNT=1
|
||||||
|
# PAGES_PER_BROWSER=15
|
||||||
293
infrastructure/README.md
Normal file
293
infrastructure/README.md
Normal file
|
|
@ -0,0 +1,293 @@
|
||||||
|
# DocFast Infrastructure Guide
|
||||||
|
|
||||||
|
Complete disaster recovery and deployment guide for DocFast.
|
||||||
|
|
||||||
|
## Quick Start (New Server Deployment)
|
||||||
|
|
||||||
|
### 1. Prerequisites
|
||||||
|
|
||||||
|
- Fresh Ubuntu 24.04 LTS server
|
||||||
|
- Root access
|
||||||
|
- Domain name pointing to server IP
|
||||||
|
- Stripe account with webhook configured
|
||||||
|
|
||||||
|
### 2. Automated Setup
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Clone the repository
|
||||||
|
git clone ssh://forgejo@git.cloonar.com/openclawd/docfast.git
|
||||||
|
cd docfast/infrastructure
|
||||||
|
|
||||||
|
# Run the setup script as root
|
||||||
|
chmod +x setup.sh
|
||||||
|
./setup.sh
|
||||||
|
|
||||||
|
# Follow the post-setup instructions
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Manual Configuration Required
|
||||||
|
|
||||||
|
After running `setup.sh`, complete these manual steps:
|
||||||
|
|
||||||
|
#### SSL Certificate
|
||||||
|
```bash
|
||||||
|
certbot --nginx -d docfast.dev -d www.docfast.dev
|
||||||
|
```
|
||||||
|
|
||||||
|
#### DKIM DNS Record
|
||||||
|
Add this TXT record to your DNS:
|
||||||
|
```
|
||||||
|
mail._domainkey.docfast.dev
|
||||||
|
```
|
||||||
|
Get the value from: `/etc/opendkim/keys/docfast.dev/mail.txt`
|
||||||
|
|
||||||
|
#### Environment Variables
|
||||||
|
```bash
|
||||||
|
cd /opt/docfast
|
||||||
|
cp infrastructure/.env.template .env
|
||||||
|
# Edit .env with real values
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Start the Application
|
||||||
|
```bash
|
||||||
|
cd /opt/docfast
|
||||||
|
cp infrastructure/docker-compose.yml .
|
||||||
|
docker-compose up -d
|
||||||
|
```
|
||||||
|
|
||||||
|
## Complete Manual Setup (Step by Step)
|
||||||
|
|
||||||
|
If the automated script fails or you prefer manual setup:
|
||||||
|
|
||||||
|
### System Packages
|
||||||
|
```bash
|
||||||
|
apt update && apt upgrade -y
|
||||||
|
apt install -y nginx postfix opendkim opendkim-tools certbot \
|
||||||
|
python3-certbot-nginx ufw docker.io docker-compose-plugin \
|
||||||
|
git sqlite3 postgresql postgresql-contrib
|
||||||
|
```
|
||||||
|
|
||||||
|
### Firewall Configuration
|
||||||
|
```bash
|
||||||
|
ufw --force enable
|
||||||
|
ufw default deny incoming
|
||||||
|
ufw default allow outgoing
|
||||||
|
ufw allow ssh
|
||||||
|
ufw allow 80/tcp
|
||||||
|
ufw allow 443/tcp
|
||||||
|
ufw allow from 172.16.0.0/12 to any port 25 comment "Docker SMTP relay"
|
||||||
|
ufw allow from 172.16.0.0/12 to any port 5432 comment "Docker PostgreSQL"
|
||||||
|
```
|
||||||
|
|
||||||
|
### PostgreSQL Setup
|
||||||
|
```bash
|
||||||
|
sudo -u postgres createuser -D -A -P docfast
|
||||||
|
sudo -u postgres createdb -O docfast docfast
|
||||||
|
|
||||||
|
# Edit /etc/postgresql/16/main/postgresql.conf
|
||||||
|
echo "listen_addresses = '*'" >> /etc/postgresql/16/main/postgresql.conf
|
||||||
|
|
||||||
|
# Edit /etc/postgresql/16/main/pg_hba.conf
|
||||||
|
echo "host docfast docfast 172.17.0.0/16 md5" >> /etc/postgresql/16/main/pg_hba.conf
|
||||||
|
echo "host docfast docfast 172.18.0.0/16 md5" >> /etc/postgresql/16/main/pg_hba.conf
|
||||||
|
|
||||||
|
systemctl restart postgresql
|
||||||
|
```
|
||||||
|
|
||||||
|
### Nginx Configuration
|
||||||
|
```bash
|
||||||
|
cp nginx/docfast.dev /etc/nginx/sites-available/
|
||||||
|
ln -s /etc/nginx/sites-available/docfast.dev /etc/nginx/sites-enabled/
|
||||||
|
rm /etc/nginx/sites-enabled/default
|
||||||
|
nginx -t
|
||||||
|
systemctl reload nginx
|
||||||
|
```
|
||||||
|
|
||||||
|
### Postfix & OpenDKIM
|
||||||
|
```bash
|
||||||
|
cp postfix/main.cf /etc/postfix/
|
||||||
|
cp postfix/opendkim.conf /etc/opendkim.conf
|
||||||
|
cp postfix/TrustedHosts /etc/opendkim/
|
||||||
|
|
||||||
|
# Generate DKIM keys
|
||||||
|
mkdir -p /etc/opendkim/keys/docfast.dev
|
||||||
|
cd /etc/opendkim/keys/docfast.dev
|
||||||
|
opendkim-genkey -s mail -d docfast.dev
|
||||||
|
chown opendkim:opendkim mail.private mail.txt
|
||||||
|
chmod 600 mail.private
|
||||||
|
|
||||||
|
systemctl restart postfix opendkim
|
||||||
|
```
|
||||||
|
|
||||||
|
### Application Deployment
|
||||||
|
```bash
|
||||||
|
useradd -r -m -s /bin/bash docfast
|
||||||
|
usermod -aG docker docfast
|
||||||
|
mkdir -p /opt/docfast
|
||||||
|
chown docfast:docfast /opt/docfast
|
||||||
|
|
||||||
|
cd /opt/docfast
|
||||||
|
# Copy your source code here
|
||||||
|
cp infrastructure/docker-compose.yml .
|
||||||
|
cp infrastructure/.env.template .env
|
||||||
|
# Edit .env with real values
|
||||||
|
|
||||||
|
docker-compose up -d
|
||||||
|
```
|
||||||
|
|
||||||
|
### Backup System
|
||||||
|
```bash
|
||||||
|
mkdir -p /opt/docfast-backups
|
||||||
|
cp scripts/docfast-backup.sh /opt/
|
||||||
|
chmod +x /opt/docfast-backup.sh
|
||||||
|
|
||||||
|
# Add to root crontab
|
||||||
|
echo "0 */6 * * * /opt/docfast-backup.sh >> /var/log/docfast-backup.log 2>&1" | crontab -
|
||||||
|
```
|
||||||
|
|
||||||
|
## Disaster Recovery Procedures
|
||||||
|
|
||||||
|
### Complete Server Failure
|
||||||
|
|
||||||
|
1. **Provision new server** with same OS version
|
||||||
|
2. **Run setup script** from this repository
|
||||||
|
3. **Restore DNS** records to point to new server
|
||||||
|
4. **Copy backups** from off-site storage to `/opt/docfast-backups/`
|
||||||
|
5. **Restore database**:
|
||||||
|
```bash
|
||||||
|
docker-compose down
|
||||||
|
docker volume rm docfast_docfast-data
|
||||||
|
docker volume create docfast_docfast-data
|
||||||
|
cp /opt/docfast-backups/docfast-weekly-LATEST.db \
|
||||||
|
/var/lib/docker/volumes/docfast_docfast-data/_data/docfast.db
|
||||||
|
docker-compose up -d
|
||||||
|
```
|
||||||
|
6. **Verify SSL certificates** with `certbot certificates`
|
||||||
|
7. **Test email delivery** and DKIM signing
|
||||||
|
|
||||||
|
### Database Corruption
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd /opt/docfast
|
||||||
|
docker-compose down
|
||||||
|
|
||||||
|
# Find latest good backup
|
||||||
|
ls -la /opt/docfast-backups/
|
||||||
|
|
||||||
|
# Restore from backup
|
||||||
|
cp /opt/docfast-backups/docfast-daily-LATEST.db \
|
||||||
|
/var/lib/docker/volumes/docfast_docfast-data/_data/docfast.db
|
||||||
|
|
||||||
|
docker-compose up -d
|
||||||
|
```
|
||||||
|
|
||||||
|
### Email Delivery Issues
|
||||||
|
|
||||||
|
Check DKIM setup:
|
||||||
|
```bash
|
||||||
|
# Verify DKIM key is readable
|
||||||
|
sudo -u opendkim cat /etc/opendkim/keys/docfast.dev/mail.private
|
||||||
|
|
||||||
|
# Check OpenDKIM is signing
|
||||||
|
tail -f /var/log/mail.log
|
||||||
|
|
||||||
|
# Test email sending
|
||||||
|
echo "Test email" | mail -s "Test" test@example.com
|
||||||
|
```
|
||||||
|
|
||||||
|
### SSL Certificate Issues
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Check certificate status
|
||||||
|
certbot certificates
|
||||||
|
|
||||||
|
# Renew if needed
|
||||||
|
certbot renew --dry-run
|
||||||
|
certbot renew
|
||||||
|
|
||||||
|
# Fix nginx config if needed
|
||||||
|
nginx -t
|
||||||
|
systemctl reload nginx
|
||||||
|
```
|
||||||
|
|
||||||
|
## Monitoring & Maintenance
|
||||||
|
|
||||||
|
### Daily Checks
|
||||||
|
- [ ] Application health: `curl https://docfast.dev/health`
|
||||||
|
- [ ] Docker containers: `docker ps`
|
||||||
|
- [ ] Disk space: `df -h`
|
||||||
|
- [ ] Backup status: `ls -la /opt/docfast-backups/`
|
||||||
|
|
||||||
|
### Weekly Checks
|
||||||
|
- [ ] SSL certificate expiry: `certbot certificates`
|
||||||
|
- [ ] Email delivery test
|
||||||
|
- [ ] System updates: `apt list --upgradable`
|
||||||
|
- [ ] Log rotation: `du -sh /var/log/`
|
||||||
|
|
||||||
|
### Monthly Tasks
|
||||||
|
- [ ] Review backup retention
|
||||||
|
- [ ] Update system packages
|
||||||
|
- [ ] Review firewall rules: `ufw status`
|
||||||
|
- [ ] Check for failed login attempts: `grep "Failed password" /var/log/auth.log`
|
||||||
|
|
||||||
|
## Environment Variables Reference
|
||||||
|
|
||||||
|
| Variable | Required | Description | Example |
|
||||||
|
|----------|----------|-------------|---------|
|
||||||
|
| `STRIPE_SECRET_KEY` | ✅ | Stripe API secret key | `sk_live_...` |
|
||||||
|
| `STRIPE_WEBHOOK_SECRET` | ✅ | Stripe webhook endpoint secret | `whsec_...` |
|
||||||
|
| `BASE_URL` | ✅ | Application base URL | `https://docfast.dev` |
|
||||||
|
| `API_KEYS` | ✅ | Comma-separated API keys | `key1,key2,key3` |
|
||||||
|
| `PRO_KEYS` | ✅ | Comma-separated pro API keys | `prokey1,prokey2` |
|
||||||
|
| `DATABASE_PASSWORD` | ✅ | PostgreSQL password | `secure_password_123` |
|
||||||
|
|
||||||
|
## DNS Records Required
|
||||||
|
|
||||||
|
| Type | Name | Value | TTL |
|
||||||
|
|------|------|-------|-----|
|
||||||
|
| A | docfast.dev | SERVER_IP | 300 |
|
||||||
|
| A | www.docfast.dev | SERVER_IP | 300 |
|
||||||
|
| TXT | mail._domainkey.docfast.dev | DKIM_PUBLIC_KEY | 300 |
|
||||||
|
| MX | docfast.dev | docfast.dev | 300 |
|
||||||
|
| TXT | docfast.dev | v=spf1 mx ~all | 300 |
|
||||||
|
|
||||||
|
## Stripe Configuration
|
||||||
|
|
||||||
|
Required webhook events:
|
||||||
|
- `checkout.session.completed`
|
||||||
|
- `invoice.payment_succeeded`
|
||||||
|
- `customer.subscription.created`
|
||||||
|
- `customer.subscription.updated`
|
||||||
|
- `customer.subscription.deleted`
|
||||||
|
|
||||||
|
Webhook URL: `https://docfast.dev/api/stripe/webhook`
|
||||||
|
|
||||||
|
## Security Considerations
|
||||||
|
|
||||||
|
- Server runs on non-standard SSH port (change from 22)
|
||||||
|
- Fail2ban recommended for brute force protection
|
||||||
|
- Regular security updates via unattended-upgrades
|
||||||
|
- Database backups encrypted at rest
|
||||||
|
- API keys rotated regularly
|
||||||
|
- Monitor application logs for suspicious activity
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
### Common Issues
|
||||||
|
|
||||||
|
**Container won't start**: Check logs with `docker-compose logs -f`
|
||||||
|
|
||||||
|
**Database connection errors**: Verify PostgreSQL is running and Docker networks are configured
|
||||||
|
|
||||||
|
**Email not sending**: Check postfix logs: `tail -f /var/log/mail.log`
|
||||||
|
|
||||||
|
**SSL certificate errors**: Verify domain DNS and run `certbot --nginx`
|
||||||
|
|
||||||
|
**High memory usage**: Monitor with `docker stats` and adjust container limits
|
||||||
|
|
||||||
|
### Log Locations
|
||||||
|
- Application: `docker-compose logs`
|
||||||
|
- Nginx: `/var/log/nginx/`
|
||||||
|
- Postfix: `/var/log/mail.log`
|
||||||
|
- System: `/var/log/syslog`
|
||||||
|
- Backups: `/var/log/docfast-backup.log`
|
||||||
41
infrastructure/docker-compose.yml
Normal file
41
infrastructure/docker-compose.yml
Normal file
|
|
@ -0,0 +1,41 @@
|
||||||
|
version: "3.8"
|
||||||
|
services:
|
||||||
|
docfast:
|
||||||
|
build: .
|
||||||
|
restart: unless-stopped
|
||||||
|
ports:
|
||||||
|
- "127.0.0.1:3100:3100"
|
||||||
|
extra_hosts:
|
||||||
|
- "host.docker.internal:host-gateway"
|
||||||
|
environment:
|
||||||
|
- API_KEYS=${API_KEYS}
|
||||||
|
- PORT=3100
|
||||||
|
- NODE_ENV=production
|
||||||
|
- STRIPE_SECRET_KEY=${STRIPE_SECRET_KEY}
|
||||||
|
- STRIPE_WEBHOOK_SECRET=${STRIPE_WEBHOOK_SECRET}
|
||||||
|
- BASE_URL=${BASE_URL:-https://docfast.dev}
|
||||||
|
- PRO_KEYS=${PRO_KEYS}
|
||||||
|
- SMTP_HOST=host.docker.internal
|
||||||
|
- SMTP_PORT=25
|
||||||
|
- DATABASE_HOST=172.17.0.1
|
||||||
|
- DATABASE_PORT=5432
|
||||||
|
- DATABASE_NAME=docfast
|
||||||
|
- DATABASE_USER=docfast
|
||||||
|
- DATABASE_PASSWORD=${DATABASE_PASSWORD:-docfast}
|
||||||
|
- POOL_SIZE=15
|
||||||
|
- BROWSER_COUNT=1
|
||||||
|
- PAGES_PER_BROWSER=15
|
||||||
|
volumes:
|
||||||
|
- docfast-data:/app/data
|
||||||
|
mem_limit: 2560m
|
||||||
|
cpus: 1.5
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "curl", "-f", "http://localhost:3100/health"]
|
||||||
|
interval: 30s
|
||||||
|
timeout: 10s
|
||||||
|
retries: 3
|
||||||
|
start_period: 40s
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
docfast-data:
|
||||||
|
driver: local
|
||||||
70
infrastructure/nginx/docfast.dev
Normal file
70
infrastructure/nginx/docfast.dev
Normal file
|
|
@ -0,0 +1,70 @@
|
||||||
|
server {
|
||||||
|
server_name docfast.dev www.docfast.dev;
|
||||||
|
|
||||||
|
# Increase client max body size for file uploads
|
||||||
|
client_max_body_size 10m;
|
||||||
|
|
||||||
|
# Security headers
|
||||||
|
add_header X-Frame-Options DENY;
|
||||||
|
add_header X-Content-Type-Options nosniff;
|
||||||
|
add_header X-XSS-Protection "1; mode=block";
|
||||||
|
add_header Referrer-Policy "strict-origin-when-cross-origin";
|
||||||
|
|
||||||
|
# Proxy to the application
|
||||||
|
location / {
|
||||||
|
proxy_pass http://127.0.0.1:3100;
|
||||||
|
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_read_timeout 60s;
|
||||||
|
proxy_connect_timeout 10s;
|
||||||
|
|
||||||
|
# WebSocket support (if needed)
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
proxy_set_header Upgrade $http_upgrade;
|
||||||
|
proxy_set_header Connection 'upgrade';
|
||||||
|
proxy_cache_bypass $http_upgrade;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Health check endpoint (bypass proxy for direct container health check)
|
||||||
|
location /health {
|
||||||
|
access_log off;
|
||||||
|
proxy_pass http://127.0.0.1:3100/health;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Rate limiting for API endpoints
|
||||||
|
location /api/ {
|
||||||
|
limit_req zone=api_limit burst=10 nodelay;
|
||||||
|
proxy_pass http://127.0.0.1:3100;
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
# SSL configuration (managed by Certbot)
|
||||||
|
listen 443 ssl http2;
|
||||||
|
ssl_certificate /etc/letsencrypt/live/docfast.dev/fullchain.pem;
|
||||||
|
ssl_certificate_key /etc/letsencrypt/live/docfast.dev/privkey.pem;
|
||||||
|
include /etc/letsencrypt/options-ssl-nginx.conf;
|
||||||
|
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Rate limiting zone (add to main nginx.conf or here)
|
||||||
|
# limit_req_zone $binary_remote_addr zone=api_limit:10m rate=10r/s;
|
||||||
|
|
||||||
|
# Redirect HTTP to HTTPS
|
||||||
|
server {
|
||||||
|
if ($host = docfast.dev) {
|
||||||
|
return 301 https://$host$request_uri;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ($host = www.docfast.dev) {
|
||||||
|
return 301 https://docfast.dev$request_uri;
|
||||||
|
}
|
||||||
|
|
||||||
|
listen 80;
|
||||||
|
server_name docfast.dev www.docfast.dev;
|
||||||
|
return 404;
|
||||||
|
}
|
||||||
11
infrastructure/postfix/TrustedHosts
Normal file
11
infrastructure/postfix/TrustedHosts
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
# OpenDKIM Trusted Hosts
|
||||||
|
# These hosts are allowed to send mail through this server
|
||||||
|
|
||||||
|
# Localhost
|
||||||
|
127.0.0.1
|
||||||
|
localhost
|
||||||
|
|
||||||
|
# Docker networks (adjust based on your Docker setup)
|
||||||
|
172.17.0.0/16
|
||||||
|
172.18.0.0/16
|
||||||
|
172.19.0.0/16
|
||||||
44
infrastructure/postfix/main.cf
Normal file
44
infrastructure/postfix/main.cf
Normal file
|
|
@ -0,0 +1,44 @@
|
||||||
|
# Postfix main configuration for DocFast
|
||||||
|
# Minimal SMTP relay for application email sending
|
||||||
|
|
||||||
|
# Basic configuration
|
||||||
|
smtpd_banner = $myhostname ESMTP
|
||||||
|
biff = no
|
||||||
|
append_dot_mydomain = no
|
||||||
|
readme_directory = no
|
||||||
|
compatibility_level = 3.6
|
||||||
|
|
||||||
|
# Network configuration
|
||||||
|
myhostname = docfast.dev
|
||||||
|
mydomain = docfast.dev
|
||||||
|
myorigin = docfast.dev
|
||||||
|
inet_interfaces = 127.0.0.1, 172.17.0.1 # localhost + Docker bridge
|
||||||
|
inet_protocols = ipv4
|
||||||
|
mydestination = # Empty = relay only, no local delivery
|
||||||
|
mynetworks = 127.0.0.0/8, 172.17.0.0/16, 172.18.0.0/16
|
||||||
|
|
||||||
|
# TLS configuration
|
||||||
|
smtp_tls_security_level = may
|
||||||
|
smtp_tls_CAfile = /etc/ssl/certs/ca-certificates.crt
|
||||||
|
|
||||||
|
# OpenDKIM integration
|
||||||
|
milter_protocol = 6
|
||||||
|
milter_default_action = accept
|
||||||
|
smtpd_milters = inet:localhost:8891
|
||||||
|
non_smtpd_milters = $smtpd_milters
|
||||||
|
|
||||||
|
# Size limits
|
||||||
|
mailbox_size_limit = 0
|
||||||
|
message_size_limit = 10240000 # 10MB
|
||||||
|
|
||||||
|
# Other settings
|
||||||
|
recipient_delimiter = +
|
||||||
|
disable_vrfy_command = yes
|
||||||
|
smtpd_helo_required = yes
|
||||||
|
|
||||||
|
# Rate limiting
|
||||||
|
smtpd_client_connection_count_limit = 10
|
||||||
|
smtpd_client_connection_rate_limit = 10
|
||||||
|
|
||||||
|
# Logging
|
||||||
|
maillog_file = /var/log/postfix.log
|
||||||
38
infrastructure/postfix/opendkim.conf
Normal file
38
infrastructure/postfix/opendkim.conf
Normal file
|
|
@ -0,0 +1,38 @@
|
||||||
|
# OpenDKIM Configuration for DocFast
|
||||||
|
|
||||||
|
# Logging
|
||||||
|
Syslog yes
|
||||||
|
SyslogSuccess yes
|
||||||
|
LogWhy yes
|
||||||
|
|
||||||
|
# Operating mode (s = sign, v = verify, sv = both)
|
||||||
|
Mode sv
|
||||||
|
|
||||||
|
# Canonicalization
|
||||||
|
Canonicalization relaxed/simple
|
||||||
|
|
||||||
|
# Domain and selector
|
||||||
|
Domain docfast.dev
|
||||||
|
Selector mail
|
||||||
|
KeyFile /etc/opendkim/keys/docfast.dev/mail.private
|
||||||
|
|
||||||
|
# Network
|
||||||
|
Socket inet:8891@localhost
|
||||||
|
PidFile /run/opendkim/opendkim.pid
|
||||||
|
|
||||||
|
# Security
|
||||||
|
OversignHeaders From
|
||||||
|
TrustAnchorFile /usr/share/dns/root.key
|
||||||
|
UserID opendkim
|
||||||
|
|
||||||
|
# Trusted hosts (who can send mail through this server)
|
||||||
|
InternalHosts /etc/opendkim/TrustedHosts
|
||||||
|
ExternalIgnoreList /etc/opendkim/TrustedHosts
|
||||||
|
|
||||||
|
# Additional security options
|
||||||
|
RequireSafeKeys yes
|
||||||
|
SendReports yes
|
||||||
|
ReportAddress "postmaster@docfast.dev"
|
||||||
|
|
||||||
|
# Performance
|
||||||
|
MaximumHeaders 30
|
||||||
193
infrastructure/setup.sh
Executable file
193
infrastructure/setup.sh
Executable file
|
|
@ -0,0 +1,193 @@
|
||||||
|
#!/bin/bash
|
||||||
|
# DocFast Infrastructure Setup Script
|
||||||
|
# Provisions a fresh Ubuntu/Debian server with all required services
|
||||||
|
# Run as root: ./setup.sh
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
# Colors for output
|
||||||
|
RED='\033[0;31m'
|
||||||
|
GREEN='\033[0;32m'
|
||||||
|
YELLOW='\033[1;33m'
|
||||||
|
NC='\033[0m' # No Color
|
||||||
|
|
||||||
|
log() {
|
||||||
|
echo -e "${GREEN}[INFO]${NC} $1"
|
||||||
|
}
|
||||||
|
|
||||||
|
warn() {
|
||||||
|
echo -e "${YELLOW}[WARN]${NC} $1"
|
||||||
|
}
|
||||||
|
|
||||||
|
error() {
|
||||||
|
echo -e "${RED}[ERROR]${NC} $1"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# Check if running as root
|
||||||
|
if [[ $EUID -ne 0 ]]; then
|
||||||
|
error "This script must be run as root"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Domain and user configuration
|
||||||
|
DOMAIN="${DOMAIN:-docfast.dev}"
|
||||||
|
APP_USER="${APP_USER:-docfast}"
|
||||||
|
BACKUP_DIR="/opt/docfast-backups"
|
||||||
|
INSTALL_DIR="/opt/docfast"
|
||||||
|
|
||||||
|
log "Setting up DocFast infrastructure for domain: $DOMAIN"
|
||||||
|
|
||||||
|
# Update system
|
||||||
|
log "Updating system packages..."
|
||||||
|
apt update && apt upgrade -y
|
||||||
|
|
||||||
|
# Install required packages
|
||||||
|
log "Installing required packages..."
|
||||||
|
apt install -y \
|
||||||
|
nginx \
|
||||||
|
postfix \
|
||||||
|
opendkim \
|
||||||
|
opendkim-tools \
|
||||||
|
certbot \
|
||||||
|
python3-certbot-nginx \
|
||||||
|
ufw \
|
||||||
|
docker.io \
|
||||||
|
docker-compose-plugin \
|
||||||
|
git \
|
||||||
|
sqlite3 \
|
||||||
|
curl \
|
||||||
|
wget \
|
||||||
|
unzip \
|
||||||
|
htop \
|
||||||
|
postgresql \
|
||||||
|
postgresql-contrib
|
||||||
|
|
||||||
|
# Enable and start services
|
||||||
|
log "Enabling services..."
|
||||||
|
systemctl enable nginx postfix opendkim docker postgresql
|
||||||
|
systemctl start nginx postfix opendkim docker postgresql
|
||||||
|
|
||||||
|
# Create application user
|
||||||
|
if ! id "$APP_USER" &>/dev/null; then
|
||||||
|
log "Creating application user: $APP_USER"
|
||||||
|
useradd -r -m -s /bin/bash "$APP_USER"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Add user to docker group
|
||||||
|
usermod -aG docker "$APP_USER"
|
||||||
|
|
||||||
|
# Setup UFW firewall
|
||||||
|
log "Configuring firewall..."
|
||||||
|
ufw --force enable
|
||||||
|
ufw default deny incoming
|
||||||
|
ufw default allow outgoing
|
||||||
|
ufw allow ssh
|
||||||
|
ufw allow 80/tcp
|
||||||
|
ufw allow 443/tcp
|
||||||
|
ufw allow from 172.16.0.0/12 to any port 25 comment "Docker SMTP relay"
|
||||||
|
ufw allow from 172.16.0.0/12 to any port 5432 comment "Docker PostgreSQL"
|
||||||
|
|
||||||
|
# Setup PostgreSQL
|
||||||
|
log "Configuring PostgreSQL..."
|
||||||
|
sudo -u postgres createuser -D -A -P docfast || true # -P prompts for password
|
||||||
|
sudo -u postgres createdb -O docfast docfast || true
|
||||||
|
|
||||||
|
# Update PostgreSQL to allow Docker connections
|
||||||
|
PG_VERSION=$(ls /etc/postgresql/)
|
||||||
|
PG_CONF="/etc/postgresql/$PG_VERSION/main/postgresql.conf"
|
||||||
|
PG_HBA="/etc/postgresql/$PG_VERSION/main/pg_hba.conf"
|
||||||
|
|
||||||
|
# Backup original configs
|
||||||
|
cp "$PG_CONF" "$PG_CONF.backup" || true
|
||||||
|
cp "$PG_HBA" "$PG_HBA.backup" || true
|
||||||
|
|
||||||
|
# Allow connections from Docker networks
|
||||||
|
if ! grep -q "listen_addresses = '*'" "$PG_CONF"; then
|
||||||
|
sed -i "s/#listen_addresses = 'localhost'/listen_addresses = '*'/" "$PG_CONF"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Allow Docker networks to connect
|
||||||
|
if ! grep -q "172.17.0.0/16" "$PG_HBA"; then
|
||||||
|
echo "host docfast docfast 172.17.0.0/16 md5" >> "$PG_HBA"
|
||||||
|
echo "host docfast docfast 172.18.0.0/16 md5" >> "$PG_HBA"
|
||||||
|
fi
|
||||||
|
|
||||||
|
systemctl restart postgresql
|
||||||
|
|
||||||
|
# Setup OpenDKIM
|
||||||
|
log "Configuring OpenDKIM..."
|
||||||
|
mkdir -p /etc/opendkim/keys/"$DOMAIN"
|
||||||
|
chown -R opendkim:opendkim /etc/opendkim/keys
|
||||||
|
|
||||||
|
# Generate DKIM keys if they don't exist
|
||||||
|
if [[ ! -f /etc/opendkim/keys/"$DOMAIN"/mail.private ]]; then
|
||||||
|
log "Generating DKIM keys..."
|
||||||
|
cd /etc/opendkim/keys/"$DOMAIN"
|
||||||
|
opendkim-genkey -s mail -d "$DOMAIN"
|
||||||
|
chown opendkim:opendkim mail.private mail.txt
|
||||||
|
chmod 600 mail.private
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Copy configuration files
|
||||||
|
log "Installing configuration files..."
|
||||||
|
cp nginx/"$DOMAIN" /etc/nginx/sites-available/"$DOMAIN" || warn "Nginx config not found, you'll need to configure manually"
|
||||||
|
cp postfix/main.cf /etc/postfix/main.cf || warn "Postfix config not found, you'll need to configure manually"
|
||||||
|
cp postfix/opendkim.conf /etc/opendkim.conf || warn "OpenDKIM config not found, you'll need to configure manually"
|
||||||
|
cp postfix/TrustedHosts /etc/opendkim/TrustedHosts || warn "TrustedHosts config not found, you'll need to configure manually"
|
||||||
|
|
||||||
|
# Enable nginx site
|
||||||
|
if [[ -f /etc/nginx/sites-available/"$DOMAIN" ]]; then
|
||||||
|
ln -sf /etc/nginx/sites-available/"$DOMAIN" /etc/nginx/sites-enabled/
|
||||||
|
rm -f /etc/nginx/sites-enabled/default
|
||||||
|
nginx -t && systemctl reload nginx
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Update configurations with actual domain
|
||||||
|
log "Updating configuration files..."
|
||||||
|
sed -i "s/docfast\.dev/$DOMAIN/g" /etc/nginx/sites-available/"$DOMAIN" 2>/dev/null || true
|
||||||
|
sed -i "s/docfast\.dev/$DOMAIN/g" /etc/postfix/main.cf 2>/dev/null || true
|
||||||
|
sed -i "s/docfast\.dev/$DOMAIN/g" /etc/opendkim.conf 2>/dev/null || true
|
||||||
|
|
||||||
|
# Restart services with new configs
|
||||||
|
systemctl restart postfix opendkim
|
||||||
|
|
||||||
|
# Setup backup directory and script
|
||||||
|
log "Setting up backup system..."
|
||||||
|
mkdir -p "$BACKUP_DIR"
|
||||||
|
cp ../scripts/docfast-backup.sh /opt/docfast-backup.sh || warn "Backup script not found"
|
||||||
|
chmod +x /opt/docfast-backup.sh
|
||||||
|
|
||||||
|
# Add backup cron job
|
||||||
|
if ! crontab -l 2>/dev/null | grep -q docfast-backup; then
|
||||||
|
(crontab -l 2>/dev/null; echo "0 */6 * * * /opt/docfast-backup.sh >> /var/log/docfast-backup.log 2>&1") | crontab -
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Setup application directory
|
||||||
|
log "Setting up application directory..."
|
||||||
|
mkdir -p "$INSTALL_DIR"
|
||||||
|
chown "$APP_USER":"$APP_USER" "$INSTALL_DIR"
|
||||||
|
|
||||||
|
# Install Docker Compose
|
||||||
|
if ! command -v docker-compose &> /dev/null; then
|
||||||
|
log "Installing docker-compose..."
|
||||||
|
COMPOSE_VERSION=$(curl -s https://api.github.com/repos/docker/compose/releases/latest | grep 'tag_name' | cut -d\" -f4)
|
||||||
|
curl -L "https://github.com/docker/compose/releases/download/${COMPOSE_VERSION}/docker-compose-$(uname -s)-$(uname -m)" -o /usr/local/bin/docker-compose
|
||||||
|
chmod +x /usr/local/bin/docker-compose
|
||||||
|
fi
|
||||||
|
|
||||||
|
log "Base infrastructure setup complete!"
|
||||||
|
echo
|
||||||
|
log "Next steps:"
|
||||||
|
echo "1. Configure DNS A record for $DOMAIN to point to this server"
|
||||||
|
echo "2. Generate SSL certificates: certbot --nginx -d $DOMAIN"
|
||||||
|
echo "3. Copy your .env file with secrets to $INSTALL_DIR/.env"
|
||||||
|
echo "4. Copy your docker-compose.yml to $INSTALL_DIR/"
|
||||||
|
echo "5. Build and start the application:"
|
||||||
|
echo " cd $INSTALL_DIR"
|
||||||
|
echo " docker-compose up -d"
|
||||||
|
echo
|
||||||
|
warn "Remember to:"
|
||||||
|
echo "- Set up your DKIM DNS record (see /etc/opendkim/keys/$DOMAIN/mail.txt)"
|
||||||
|
echo "- Configure Stripe webhooks"
|
||||||
|
echo "- Set up monitoring/alerting"
|
||||||
|
echo "- Test email delivery"
|
||||||
49
scripts/docfast-backup.sh
Executable file
49
scripts/docfast-backup.sh
Executable file
|
|
@ -0,0 +1,49 @@
|
||||||
|
#!/bin/bash
|
||||||
|
# DocFast SQLite Backup Script
|
||||||
|
# Runs every 6 hours via cron. Keeps 7 daily + 4 weekly backups.
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
BACKUP_DIR="/opt/docfast-backups"
|
||||||
|
DB_PATH="/var/lib/docker/volumes/docfast_docfast-data/_data/docfast.db"
|
||||||
|
DATE=$(date +%Y-%m-%d_%H%M)
|
||||||
|
DAY_OF_WEEK=$(date +%u) # 1=Monday, 7=Sunday
|
||||||
|
|
||||||
|
mkdir -p "$BACKUP_DIR"
|
||||||
|
|
||||||
|
# Check if database exists
|
||||||
|
if [[ ! -f "$DB_PATH" ]]; then
|
||||||
|
echo "ERROR: Database not found at $DB_PATH" >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Safe hot backup using sqlite3 .backup
|
||||||
|
DAILY_FILE="$BACKUP_DIR/docfast-daily-${DATE}.db"
|
||||||
|
sqlite3 "$DB_PATH" ".backup '$DAILY_FILE'"
|
||||||
|
|
||||||
|
# Verify backup is valid
|
||||||
|
if ! sqlite3 "$DAILY_FILE" "PRAGMA integrity_check;" | grep -q "^ok$"; then
|
||||||
|
echo "ERROR: Backup integrity check failed!" >&2
|
||||||
|
rm -f "$DAILY_FILE"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Created backup: $DAILY_FILE ($(stat -c%s "$DAILY_FILE") bytes)"
|
||||||
|
|
||||||
|
# On Sundays, also keep a weekly copy
|
||||||
|
if [ "$DAY_OF_WEEK" -eq 7 ]; then
|
||||||
|
WEEKLY_FILE="$BACKUP_DIR/docfast-weekly-$(date +%Y-%m-%d).db"
|
||||||
|
cp "$DAILY_FILE" "$WEEKLY_FILE"
|
||||||
|
echo "Created weekly backup: $WEEKLY_FILE"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Rotate: keep last 7 daily backups (28 files at 6h intervals = ~7 days)
|
||||||
|
find "$BACKUP_DIR" -name "docfast-daily-*.db" -type f | sort -r | tail -n +29 | xargs -r rm -f
|
||||||
|
|
||||||
|
# Rotate: keep last 4 weekly backups
|
||||||
|
find "$BACKUP_DIR" -name "docfast-weekly-*.db" -type f | sort -r | tail -n +5 | xargs -r rm -f || true
|
||||||
|
|
||||||
|
# Show current backup status
|
||||||
|
DAILY_COUNT=$(find "$BACKUP_DIR" -name "docfast-daily-*.db" -type f | wc -l)
|
||||||
|
WEEKLY_COUNT=$(find "$BACKUP_DIR" -name "docfast-weekly-*.db" -type f | wc -l)
|
||||||
|
echo "Backup rotation complete. Daily: $DAILY_COUNT, Weekly: $WEEKLY_COUNT"
|
||||||
Loading…
Add table
Add a link
Reference in a new issue