File size: 8,143 Bytes
4cef597 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 | #!/usr/bin/env bash
# LDV staging/production setup script
# Run as root or with sudo on a fresh Ubuntu/Debian server:
# sudo bash deploy/setup.sh
set -euo pipefail
# ── config ────────────────────────────────────────────────────────────────────
INSTALL_DIR="/opt/ldv"
APP_DIR="$INSTALL_DIR/ldv-backend"
DATA_DIR="$INSTALL_DIR/data"
BACKUP_DIR="/var/backups/ldv"
LOG_DIR="/var/log/ldv"
APP_USER="www-data"
REPO_URL="https://github.com/vadhh/cra.git"
ENV_FILE="$APP_DIR/.env"
SERVICE_NAME="ldv"
NGINX_SITE="ldv"
# ──────────────────────────────────────────────────────────────────────────────
RED='\033[0;31m'; GREEN='\033[0;32m'; YELLOW='\033[1;33m'; NC='\033[0m'
info() { echo -e "${GREEN}[ldv]${NC} $*"; }
warn() { echo -e "${YELLOW}[warn]${NC} $*"; }
die() { echo -e "${RED}[error]${NC} $*"; exit 1; }
[[ $EUID -eq 0 ]] || die "Run with sudo: sudo bash deploy/setup.sh"
# ── 1. system deps ────────────────────────────────────────────────────────────
info "Installing system dependencies..."
apt-get update -qq
apt-get install -y -qq python3 python3-pip libmagic1 rsync git nginx
# ── 2. clone or update ────────────────────────────────────────────────────────
if [[ -d "$INSTALL_DIR/.git" ]]; then
info "Repo already cloned — pulling latest..."
git -C "$INSTALL_DIR" pull
else
info "Cloning repo to $INSTALL_DIR..."
git clone "$REPO_URL" "$INSTALL_DIR"
fi
# ── 3. python deps ────────────────────────────────────────────────────────────
info "Installing Python dependencies..."
pip3 install -q -r "$APP_DIR/requirements.txt"
# ── 4. directories ────────────────────────────────────────────────────────────
info "Creating directories..."
mkdir -p "$DATA_DIR" "$BACKUP_DIR" "$LOG_DIR"
chown -R "$APP_USER:$APP_USER" "$DATA_DIR" "$BACKUP_DIR" "$LOG_DIR" "$INSTALL_DIR"
# ── 5. .env ───────────────────────────────────────────────────────────────────
if [[ -f "$ENV_FILE" ]]; then
warn ".env already exists at $ENV_FILE — skipping generation."
warn "Edit it manually if you need to change values."
else
info "Generating .env..."
SECRET_KEY=$(python3 -c "import secrets; print(secrets.token_hex(32))")
ENC_KEY=$(cd "$APP_DIR" && python3 manage.py gen-key)
read -rp "Admin email: " ADMIN_EMAIL
read -rsp "Admin password: " ADMIN_PASSWORD; echo
read -rp "Server domain or IP (e.g. 192.168.1.10 or app.example.com): " SERVER_HOST
read -rp "Backup rsync target (leave blank to skip, e.g. user@host:/backups/ldv): " BACKUP_REMOTE
cat > "$ENV_FILE" <<EOF
# Auto-generated by setup.sh — $(date -u +%Y-%m-%dT%H:%M:%SZ)
LDV_SECRET_KEY=$SECRET_KEY
LDV_ENCRYPTION_KEY=$ENC_KEY
LDV_PRODUCTION=1
LDV_COOKIE_SECURE=0
LDV_CORS_ORIGINS=http://$SERVER_HOST
LDV_DB_PATH=$DATA_DIR/sydeco.db
LDV_RETENTION_DAYS=30
LDV_BACKUP_DIR=$BACKUP_DIR
LDV_BACKUP_REMOTE=$BACKUP_REMOTE
LDV_BACKUP_KEEP_DAYS=30
LDV_MAX_UPLOAD_MB=10
LDV_DOWNLOAD_LINK_TTL=900
LDV_REMOTE_TRANSLATION=0
LDV_DEBUG=0
LDV_ADMIN_EMAIL=$ADMIN_EMAIL
LDV_ADMIN_PASSWORD=$ADMIN_PASSWORD
EOF
chmod 600 "$ENV_FILE"
chown "$APP_USER:$APP_USER" "$ENV_FILE"
info ".env written to $ENV_FILE"
fi
# ── 6. database init ──────────────────────────────────────────────────────────
info "Initialising database..."
(cd "$APP_DIR" && set -a && source "$ENV_FILE" && set +a && \
python3 -c "import database; database.init_db()" && \
python3 manage.py seed-admin 2>/dev/null || true)
info "Database ready."
# ── 7. systemd service ────────────────────────────────────────────────────────
info "Installing systemd service..."
GUNICORN_BIN=$(which gunicorn || echo "/usr/local/bin/gunicorn")
cat > /etc/systemd/system/${SERVICE_NAME}.service <<EOF
[Unit]
Description=LDV Contract Analyzer
After=network.target
[Service]
User=$APP_USER
WorkingDirectory=$APP_DIR
EnvironmentFile=$ENV_FILE
ExecStart=$GUNICORN_BIN -w 2 -b 127.0.0.1:5000 --timeout 120 \\
--access-logfile $LOG_DIR/access.log \\
--error-logfile $LOG_DIR/error.log \\
app:app
Restart=always
RestartSec=5
[Install]
WantedBy=multi-user.target
EOF
systemctl daemon-reload
systemctl enable "$SERVICE_NAME"
systemctl restart "$SERVICE_NAME"
info "Service $SERVICE_NAME started."
# ── 8. nginx ──────────────────────────────────────────────────────────────────
info "Configuring nginx..."
# read SERVER_HOST from .env if we skipped generation
SERVER_HOST=${SERVER_HOST:-$(grep LDV_CORS_ORIGINS "$ENV_FILE" | cut -d= -f2 | sed 's|https\?://||')}
cat > /etc/nginx/sites-available/$NGINX_SITE <<EOF
server {
listen 80;
server_name $SERVER_HOST;
client_max_body_size 15M;
location / {
proxy_pass http://127.0.0.1:5000;
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_read_timeout 120s;
}
}
EOF
ln -sf /etc/nginx/sites-available/$NGINX_SITE /etc/nginx/sites-enabled/$NGINX_SITE
rm -f /etc/nginx/sites-enabled/default
nginx -t
systemctl reload nginx
info "nginx configured."
# ── 9. backup cron ────────────────────────────────────────────────────────────
info "Installing backup cron..."
sed "s|/opt/ldv|$INSTALL_DIR|g" "$INSTALL_DIR/deploy/ldv-backup.cron" \
> /etc/cron.d/ldv-backup
chmod 644 /etc/cron.d/ldv-backup
info "Backup cron installed (runs nightly at 02:00)."
# ── 10. health check ─────────────────────────────────────────────────────────
info "Waiting for server to start..."
sleep 3
HTTP_STATUS=$(curl -s -o /dev/null -w "%{http_code}" http://127.0.0.1:5000/health)
if [[ "$HTTP_STATUS" == "200" ]]; then
info "Health check passed (HTTP 200)."
curl -s http://127.0.0.1:5000/health | python3 -m json.tool
else
warn "Health check returned HTTP $HTTP_STATUS — check logs:"
warn " journalctl -u $SERVICE_NAME -n 50"
fi
# ── done ──────────────────────────────────────────────────────────────────────
echo ""
echo -e "${GREEN}Setup complete.${NC}"
echo ""
echo " App running at : http://$SERVER_HOST"
echo " Logs : $LOG_DIR/"
echo " DB : $DATA_DIR/sydeco.db"
echo " Backups : $BACKUP_DIR/"
echo " Service : systemctl status $SERVICE_NAME"
echo ""
echo "Next steps:"
echo " 1. Follow docs/staging-runbook.md sections 7-12 to validate"
echo " 2. Set LDV_COOKIE_SECURE=1 in $ENV_FILE once you add HTTPS"
echo " (add HTTPS with: sudo apt install certbot python3-certbot-nginx)"
echo " (then run: sudo certbot --nginx -d $SERVER_HOST)"
|