prepare-deployment.sh 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440
  1. #!/bin/bash
  2. # Gooneral Wheelchair - Linux/macOS Deployment Preparation Script
  3. # Usage: ./prepare-deployment.sh yourdomain.com [server-host] [server-user]
  4. set -e # Exit on any error
  5. # Colors for output
  6. RED='\033[0;31m'
  7. GREEN='\033[0;32m'
  8. YELLOW='\033[1;33m'
  9. BLUE='\033[0;34m'
  10. CYAN='\033[0;36m'
  11. NC='\033[0m' # No Color
  12. # Parse arguments
  13. DOMAIN="$1"
  14. SERVER_HOST="$2"
  15. SERVER_USER="${3:-root}"
  16. if [ -z "$DOMAIN" ]; then
  17. echo -e "${RED}❌ Error: Domain name is required${NC}"
  18. echo ""
  19. echo "Usage:"
  20. echo " $0 yourdomain.com # Create deployment package"
  21. echo " $0 yourdomain.com server-ip # Deploy directly to server"
  22. echo " $0 yourdomain.com server-ip username # Deploy with custom user"
  23. exit 1
  24. fi
  25. echo -e "${GREEN}🚀 Preparing Gooneral Wheelchair for deployment...${NC}"
  26. echo -e "${CYAN}📁 Domain: $DOMAIN${NC}"
  27. # Generate secure session secret
  28. SESSION_SECRET=$(openssl rand -base64 64 | tr -d "=+/" | cut -c1-64)
  29. # Build the frontend
  30. echo -e "${YELLOW}🏗️ Building frontend...${NC}"
  31. npm run build
  32. if [ $? -ne 0 ]; then
  33. echo -e "${RED}❌ Frontend build failed!${NC}"
  34. exit 1
  35. fi
  36. # Create deployment directory
  37. DEPLOY_DIR="./deployment-ready"
  38. if [ -d "$DEPLOY_DIR" ]; then
  39. rm -rf "$DEPLOY_DIR"
  40. fi
  41. mkdir -p "$DEPLOY_DIR"
  42. echo -e "${YELLOW}📦 Packaging files...${NC}"
  43. # Copy built frontend
  44. cp -r ./dist "$DEPLOY_DIR/"
  45. # Copy backend files
  46. BACKEND_DIR="$DEPLOY_DIR/backend"
  47. mkdir -p "$BACKEND_DIR"
  48. BACKEND_FILES=(
  49. "server.js"
  50. "start-production.js"
  51. "package.json"
  52. "auth.js"
  53. "themes.js"
  54. )
  55. for file in "${BACKEND_FILES[@]}"; do
  56. if [ -f "./backend/$file" ]; then
  57. cp "./backend/$file" "$BACKEND_DIR/"
  58. fi
  59. done
  60. # Copy public directory if it exists
  61. if [ -d "./public" ]; then
  62. cp -r ./public "$DEPLOY_DIR/"
  63. fi
  64. # Create production environment file
  65. cat > "$BACKEND_DIR/.env.production" << EOF
  66. # Production Environment Variables - Generated $(date)
  67. # Server Configuration
  68. NODE_ENV=production
  69. PORT=3001
  70. # IMPORTANT: This session secret was auto-generated
  71. # Keep this secret and secure!
  72. SESSION_SECRET=$SESSION_SECRET
  73. # CORS Configuration
  74. FRONTEND_URL=https://$DOMAIN
  75. # Database/Storage paths (relative to backend directory)
  76. POSTS_DIR=../public/posts
  77. THEMES_FILE=./themes.json
  78. SESSIONS_DIR=./sessions
  79. # Security Settings
  80. COOKIE_SECURE=true
  81. COOKIE_SAME_SITE=strict
  82. EOF
  83. # Create Caddyfile with the actual domain
  84. cat > "$DEPLOY_DIR/Caddyfile" << EOF
  85. # Caddy configuration for $DOMAIN
  86. $DOMAIN {
  87. # Enable automatic HTTPS
  88. # Caddy will automatically get and renew SSL certificates
  89. # Serve the React frontend (static files)
  90. root * dist
  91. # Try to serve static files first, then fallback to index.html for SPA routing
  92. try_files {path} /index.html
  93. # API routes - proxy to backend
  94. handle /api/* {
  95. reverse_proxy localhost:3001
  96. }
  97. # Health check endpoint
  98. handle /health {
  99. reverse_proxy localhost:3001
  100. }
  101. # Serve static files with proper headers
  102. header /assets/* {
  103. Cache-Control "public, max-age=31536000, immutable"
  104. }
  105. # Security headers
  106. header {
  107. # Enable HSTS
  108. Strict-Transport-Security "max-age=63072000; includeSubDomains; preload"
  109. # Prevent clickjacking
  110. X-Frame-Options "DENY"
  111. # Prevent MIME type sniffing
  112. X-Content-Type-Options "nosniff"
  113. # XSS protection
  114. X-XSS-Protection "1; mode=block"
  115. # Referrer policy
  116. Referrer-Policy "strict-origin-when-cross-origin"
  117. # Content Security Policy (adjust as needed)
  118. Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' data:;"
  119. }
  120. # Gzip compression
  121. encode gzip
  122. # Logging
  123. log {
  124. output file /var/log/caddy/gooneral-wheelchair.log
  125. format json
  126. }
  127. }
  128. EOF
  129. # Create systemd service file
  130. cat > "$DEPLOY_DIR/gooneral-wheelchair.service" << EOF
  131. [Unit]
  132. Description=Gooneral Wheelchair CMS Backend
  133. After=network.target
  134. [Service]
  135. Type=simple
  136. User=gooneral
  137. WorkingDirectory=/opt/gooneral-wheelchair/backend
  138. Environment=NODE_ENV=production
  139. ExecStart=/usr/bin/node start-production.js
  140. Restart=always
  141. RestartSec=10
  142. StandardOutput=syslog
  143. StandardError=syslog
  144. SyslogIdentifier=gooneral-wheelchair
  145. [Install]
  146. WantedBy=multi-user.target
  147. EOF
  148. # Create the server deployment script
  149. cat > "$DEPLOY_DIR/deploy.sh" << 'EOF'
  150. #!/bin/bash
  151. # Gooneral Wheelchair - Automated Server Deployment Script
  152. # This script will fully set up your CMS on the server
  153. set -e # Exit on any error
  154. # Colors for output
  155. RED='\033[0;31m'
  156. GREEN='\033[0;32m'
  157. YELLOW='\033[1;33m'
  158. BLUE='\033[0;34m'
  159. NC='\033[0m'
  160. echo -e "${GREEN}🚀 Starting automated deployment of Gooneral Wheelchair CMS...${NC}"
  161. # Check if running as root
  162. if [[ $EUID -eq 0 ]]; then
  163. echo -e "${RED}❌ Please run this script as a regular user with sudo privileges, not as root${NC}"
  164. exit 1
  165. fi
  166. # Check if required commands exist
  167. for cmd in node npm caddy systemctl; do
  168. if ! command -v $cmd &> /dev/null; then
  169. echo -e "${RED}❌ Required command '$cmd' not found. Please install it first.${NC}"
  170. exit 1
  171. fi
  172. done
  173. echo -e "${GREEN}✅ Prerequisites check passed${NC}"
  174. # Generate random password for admin user
  175. ADMIN_PASSWORD=$(openssl rand -base64 32 | tr -d "=+/" | cut -c1-16)
  176. # Create application directory
  177. echo -e "${YELLOW}📁 Setting up application directory...${NC}"
  178. sudo mkdir -p /opt/gooneral-wheelchair
  179. sudo chown $USER:$USER /opt/gooneral-wheelchair
  180. # Copy files
  181. echo -e "${YELLOW}📦 Installing application files...${NC}"
  182. cp -r dist /opt/gooneral-wheelchair/
  183. cp -r backend /opt/gooneral-wheelchair/
  184. cp -r public /opt/gooneral-wheelchair/ 2>/dev/null || mkdir -p /opt/gooneral-wheelchair/public/posts
  185. # Install backend dependencies
  186. echo -e "${YELLOW}📥 Installing backend dependencies...${NC}"
  187. cd /opt/gooneral-wheelchair/backend
  188. npm install --production --silent
  189. # Create required directories
  190. mkdir -p sessions
  191. mkdir -p ../public/posts
  192. # Set up system user for security
  193. echo -e "${YELLOW}👤 Setting up system user...${NC}"
  194. if ! id "gooneral" &>/dev/null; then
  195. sudo useradd --system --shell /bin/false --home /opt/gooneral-wheelchair gooneral
  196. fi
  197. # Set proper ownership
  198. sudo chown -R gooneral:gooneral /opt/gooneral-wheelchair
  199. # Make start script executable
  200. chmod +x start-production.js
  201. # Install and start systemd service
  202. echo -e "${YELLOW}⚙️ Setting up systemd service...${NC}"
  203. sudo cp ../gooneral-wheelchair.service /etc/systemd/system/
  204. sudo systemctl daemon-reload
  205. sudo systemctl enable gooneral-wheelchair
  206. sudo systemctl start gooneral-wheelchair
  207. # Give the service a moment to start
  208. sleep 3
  209. if sudo systemctl is-active --quiet gooneral-wheelchair; then
  210. echo -e "${GREEN}✅ Backend service started successfully${NC}"
  211. else
  212. echo -e "${RED}❌ Backend service failed to start. Checking logs...${NC}"
  213. sudo systemctl status gooneral-wheelchair
  214. exit 1
  215. fi
  216. # Set up Caddy
  217. echo -e "${YELLOW}🌐 Configuring Caddy...${NC}"
  218. sudo cp Caddyfile /etc/caddy/Caddyfile
  219. # Test Caddy configuration
  220. if sudo caddy validate --config /etc/caddy/Caddyfile; then
  221. echo -e "${GREEN}✅ Caddy configuration is valid${NC}"
  222. sudo systemctl reload caddy
  223. else
  224. echo -e "${RED}❌ Caddy configuration is invalid${NC}"
  225. exit 1
  226. fi
  227. # Create admin user
  228. echo -e "${YELLOW}👨‍💼 Creating admin user...${NC}"
  229. cd /opt/gooneral-wheelchair/backend
  230. node -e "
  231. const bcrypt = require('bcryptjs');
  232. const fs = require('fs');
  233. const path = require('path');
  234. const username = 'admin';
  235. const password = '$ADMIN_PASSWORD';
  236. const hashedPassword = bcrypt.hashSync(password, 10);
  237. const usersFile = path.join(__dirname, 'users.json');
  238. const users = [
  239. {
  240. id: 1,
  241. username: username,
  242. password: hashedPassword,
  243. role: 'admin'
  244. }
  245. ];
  246. fs.writeFileSync(usersFile, JSON.stringify(users, null, 2));
  247. console.log('Admin user created successfully');
  248. "
  249. # Set proper ownership again after creating files
  250. sudo chown -R gooneral:gooneral /opt/gooneral-wheelchair
  251. # Extract domain from Caddyfile
  252. DOMAIN=$(grep -E '^[a-zA-Z0-9.-]+\.[a-zA-Z]{2,} {' Caddyfile | head -1 | cut -d' ' -f1)
  253. # Final status check
  254. echo ""
  255. echo -e "${GREEN}🎉 Deployment completed successfully!${NC}"
  256. echo ""
  257. echo "==================== IMPORTANT ===================="
  258. echo -e "${BLUE}🔐 Your admin credentials:${NC}"
  259. echo " Username: admin"
  260. echo " Password: $ADMIN_PASSWORD"
  261. echo ""
  262. echo -e "${RED}⚠️ SAVE THESE CREDENTIALS SECURELY!${NC}"
  263. echo -e "${RED}⚠️ Change the password after first login!${NC}"
  264. echo "==================== IMPORTANT ===================="
  265. echo ""
  266. echo -e "${CYAN}🌐 Your blog is now available at: https://$DOMAIN${NC}"
  267. echo -e "${CYAN}🔧 Admin panel: https://$DOMAIN/admin${NC}"
  268. echo ""
  269. echo -e "${YELLOW}📊 Service status:${NC}"
  270. sudo systemctl status gooneral-wheelchair --no-pager
  271. echo ""
  272. sudo systemctl status caddy --no-pager
  273. echo ""
  274. echo -e "${YELLOW}📝 To view logs:${NC}"
  275. echo " Backend: sudo journalctl -u gooneral-wheelchair -f"
  276. echo " Caddy: sudo journalctl -u caddy -f"
  277. echo ""
  278. echo -e "${GREEN}✅ Deployment complete!${NC}"
  279. EOF
  280. chmod +x "$DEPLOY_DIR/deploy.sh"
  281. # Create README
  282. cat > "$DEPLOY_DIR/README.md" << EOF
  283. # Gooneral Wheelchair - Deployment Package
  284. ## Quick Deployment
  285. 1. Upload this entire directory to your server
  286. 2. Run the deployment script: \`./deploy.sh\`
  287. 3. Access your blog at https://$DOMAIN
  288. ## What's Included
  289. - Built frontend in \`dist/\`
  290. - Backend application in \`backend/\`
  291. - Auto-configured Caddyfile for $DOMAIN
  292. - Systemd service configuration
  293. - Automated deployment script
  294. ## Generated Configuration
  295. - **Domain**: $DOMAIN
  296. - **Session Secret**: Auto-generated (64 characters)
  297. - **Admin User**: Will be created automatically
  298. - **SSL**: Automatic via Caddy + Let's Encrypt
  299. ## After Deployment
  300. The script will output your admin credentials. Save them securely!
  301. Access your blog:
  302. - **Blog**: https://$DOMAIN
  303. - **Admin**: https://$DOMAIN/admin
  304. ## Manual Steps (if needed)
  305. If the automated script doesn't work, see DEPLOYMENT.md for manual instructions.
  306. EOF
  307. # Copy the detailed deployment guide
  308. cp ./DEPLOYMENT.md "$DEPLOY_DIR/" 2>/dev/null || echo "Note: DEPLOYMENT.md not found, skipping..."
  309. # Upload and deploy if server specified
  310. if [ -n "$SERVER_HOST" ]; then
  311. echo -e "${YELLOW}📤 Uploading to server...${NC}"
  312. # Create tarball
  313. TAR_FILE="gooneral-wheelchair-deployment.tar.gz"
  314. tar -czf "$TAR_FILE" -C "$DEPLOY_DIR" .
  315. echo -e "${YELLOW}🚀 Deploying to $SERVER_HOST...${NC}"
  316. # Upload and execute deployment
  317. scp "$TAR_FILE" "${SERVER_USER}@${SERVER_HOST}:~/"
  318. ssh "${SERVER_USER}@${SERVER_HOST}" "
  319. mkdir -p gooneral-wheelchair-deploy
  320. cd gooneral-wheelchair-deploy
  321. tar -xzf ../$TAR_FILE
  322. chmod +x deploy.sh
  323. ./deploy.sh
  324. "
  325. # Clean up local tarball
  326. rm "$TAR_FILE"
  327. echo -e "${GREEN}✅ Remote deployment completed!${NC}"
  328. else
  329. echo ""
  330. echo -e "${GREEN}🎉 Deployment package ready!${NC}"
  331. echo -e "${CYAN}📁 Location: $DEPLOY_DIR${NC}"
  332. echo ""
  333. echo -e "${YELLOW}Next steps:${NC}"
  334. echo "1. Upload the '$DEPLOY_DIR' folder to your server"
  335. echo "2. SSH to your server and run: ./deploy.sh"
  336. echo "3. Access your blog at https://$DOMAIN"
  337. echo ""
  338. echo -e "${BLUE}💡 Or run this again with server details for automatic deployment:${NC}"
  339. echo "./prepare-deployment.sh $DOMAIN your.server.ip username"
  340. fi
  341. # Save deployment info
  342. cat > "$DEPLOY_DIR/deployment-info.json" << EOF
  343. {
  344. "domain": "$DOMAIN",
  345. "sessionSecret": "$SESSION_SECRET",
  346. "deploymentTime": "$(date -Iseconds)",
  347. "deploymentPath": "$DEPLOY_DIR"
  348. }
  349. EOF
  350. echo ""
  351. echo -e "${GREEN}✅ Session secret generated and saved securely in deployment package${NC}"
  352. echo -e "${RED}🔐 Keep your deployment files secure - they contain sensitive configuration!${NC}"