# Deployment Guide Complete setup for deploying the portfolio site with various web servers. ## Architecture Options ### Option A: Static Build (Recommended for Production) ``` Cloudflare → VPS (Apache/lighttpd/Caddy) → dist/ (static files) ``` ### Option B: Vite Dev Server (Development) ``` Cloudflare → VPS (Caddy) → Vite Dev Server (port 5173) ``` ## Quick Start: Static Build The simplest and most efficient approach: ```bash cd /opt/peters-portfolio-site git pull npm install npm run build # Now serve the dist/ folder with any web server ``` ## Option 1: Apache2 ### Install Apache ```bash sudo apt update sudo apt install apache2 sudo systemctl enable apache2 ``` ### Build and Deploy ```bash cd /opt/peters-portfolio-site npm install npm run build # Copy docs to dist for serving cp -r public/docs dist/ # Deploy to Apache sudo rm -rf /var/www/pwlmyers.org/* sudo cp -r dist/* /var/www/pwlmyers.org/ sudo chown -R www-data:www-data /var/www/pwlmyers.org ``` ### Apache Configuration Create `/etc/apache2/sites-available/pwlmyers.org.conf`: ```apache ServerName pwlmyers.org ServerAlias www.pwlmyers.org DocumentRoot /var/www/pwlmyers.org # Enable rewrite for SPA routing Options -Indexes +FollowSymLinks AllowOverride All Require all granted # Handle client-side routing RewriteEngine On RewriteBase / RewriteRule ^index\.html$ - [L] RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule . /index.html [L] # Enable compression AddOutputFilterByType DEFLATE text/html text/plain text/xml text/css AddOutputFilterByType DEFLATE application/javascript application/json # Cache static assets ExpiresActive On ExpiresByType image/png "access plus 1 month" ExpiresByType image/jpeg "access plus 1 month" ExpiresByType text/css "access plus 1 week" ExpiresByType application/javascript "access plus 1 week" ErrorLog ${APACHE_LOG_DIR}/pwlmyers-error.log CustomLog ${APACHE_LOG_DIR}/pwlmyers-access.log combined ``` Enable the site: ```bash sudo a2ensite pwlmyers.org.conf sudo a2enmod rewrite deflate expires headers sudo systemctl restart apache2 ``` ### SSL with Certbot ```bash sudo apt install certbot python3-certbot-apache sudo certbot --apache -d pwlmyers.org ``` ## Option 2: lighttpd ### Install lighttpd ```bash sudo apt update sudo apt install lighttpd sudo systemctl enable lighttpd ``` ### Build and Deploy ```bash cd /opt/peters-portfolio-site npm install npm run build cp -r public/docs dist/ sudo mkdir -p /var/www/pwlmyers.org sudo rm -rf /var/www/pwlmyers.org/* sudo cp -r dist/* /var/www/pwlmyers.org/ sudo chown -R www-data:www-data /var/www/pwlmyers.org ``` ### lighttpd Configuration Edit `/etc/lighttpd/lighttpd.conf` or create `/etc/lighttpd/conf-available/99-pwlmyers.conf`: ```lighttpd server.document-root = "/var/www/pwlmyers.org" server.port = 80 server.bind = "0.0.0.0" server.tag = "lighttpd" # Server name server.name = "pwlmyers.org" # Index file index-file.names = ( "index.html" ) # MIME types mimetype.assign = ( ".html" => "text/html", ".htm" => "text/html", ".css" => "text/css", ".js" => "application/javascript", ".json" => "application/json", ".png" => "image/png", ".jpg" => "image/jpeg", ".jpeg" => "image/jpeg", ".gif" => "image/gif", ".svg" => "image/svg+xml", ".ico" => "image/x-icon", ".pdf" => "application/pdf", ".pptx" => "application/vnd.openxmlformats-officedocument.presentationml.presentation", ".docx" => "application/vnd.openxmlformats-officedocument.wordprocessingml.document" ) # Enable mod_rewrite for SPA routing server.modules += ( "mod_rewrite" ) url.rewrite-if-not-file = ( "^/(.*)$" => "/index.html" ) # Enable compression server.modules += ( "mod_deflate" ) deflate.mimetypes = ( "text/html", "text/plain", "text/css", "application/javascript" ) deflate.allowed-encodings = ( "gzip", "deflate" ) # Security headers server.modules += ( "mod_setenv" ) setenv.add-response-header += ( "X-Frame-Options" => "SAMEORIGIN", "X-Content-Type-Options" => "nosniff", "X-XSS-Protection" => "1; mode=block", "Referrer-Policy" => "strict-origin-when-cross-origin" ) # Logging server.errorlog = "/var/log/lighttpd/error.log" accesslog.filename = "/var/log/lighttpd/access.log" # File upload limits (for large PPTX/PDF files) server.max-request-size = 104857600 # 100MB ``` Enable and restart: ```bash sudo lighty-enable-mod pwlmyers sudo systemctl restart lighttpd ``` ### SSL with Certbot ```bash sudo apt install certbot sudo certbot certonly --standalone -d pwlmyers.org ``` Then configure lighttpd for SSL (see certbot output for paths). ## Option 3: Caddy (Static Files) ### Build ```bash cd /opt/peters-portfolio-site npm install npm run build cp -r public/docs dist/ ``` ### Caddyfile ```caddy pwlmyers.org { root * /opt/peters-portfolio-site/dist file_server try_files {path} {path}/ /index.html # Handle docs directory handle /docs/* { uri strip_prefix /docs root * /opt/peters-portfolio-site/dist/docs file_server } log { output file /var/log/caddy/access.log } } ``` ## Option 4: Nginx ### Install Nginx ```bash sudo apt install nginx sudo systemctl enable nginx ``` ### Build ```bash cd /opt/peters-portfolio-site npm install npm run build cp -r public/docs dist/ ``` ### Nginx Configuration Create `/etc/nginx/sites-available/pwlmyers.org`: ```nginx server { listen 80; server_name pwlmyers.org www.pwlmyers.org; root /var/www/pwlmyers.org; index index.html; # Gzip compression gzip on; gzip_types text/plain text/css application/json application/javascript text/xml; # Cache static assets location ~* \.(jpg|jpeg|png|gif|ico|css|js|pdf)$ { expires 1M; add_header Cache-Control "public, immutable"; } # Serve docs correctly location /docs/ { alias /var/www/pwlmyers.org/docs/; autoindex off; } # SPA routing - serve index.html for all non-file routes location / { try_files $uri $uri/ /index.html; } # Security headers add_header X-Frame-Options "SAMEORIGIN" always; add_header X-Content-Type-Options "nosniff" always; add_header X-XSS-Protection "1; mode=block" always; # File upload size (for docs) client_max_body_size 100M; } ``` Enable: ```bash sudo ln -s /etc/nginx/sites-available/pwlmyers.org /etc/nginx/sites-enabled/ sudo rm /etc/nginx/sites-enabled/default # Remove default sudo nginx -t sudo systemctl restart nginx ``` ## Updating Static Build Create a deploy script `/opt/peters-portfolio-site/deploy.sh`: ```bash #!/bin/bash set -e cd /opt/peters-portfolio-site echo "Pulling latest changes..." git pull echo "Installing dependencies..." npm install echo "Building..." npm run build echo "Copying docs..." cp -r public/docs dist/ echo "Deploying to web server..." # For Apache: sudo rm -rf /var/www/pwlmyers.org/* sudo cp -r dist/* /var/www/pwlmyers.org/ sudo chown -R www-data:www-data /var/www/pwlmyers.org # For lighttpd: # sudo rm -rf /var/www/pwlmyers.org/* # sudo cp -r dist/* /var/www/pwlmyers.org/ # sudo chown -R www-data:www-data /var/www/pwlmyers.org # sudo systemctl restart lighttpd echo "Done!" ``` Make executable: ```bash chmod +x /opt/peters-portfolio-site/deploy.sh ``` ## Comparison | Server | RAM Usage | Ease of Config | SSL | Best For | |--------|-----------|----------------|-----|----------| | Apache | High | Medium | Certbot | Complex setups | | Nginx | Low | Medium | Certbot | High traffic | | lighttpd | Very Low | Easy | Manual | Resource constrained | | Caddy | Low | Very Easy | Auto | Simplicity | ## Troubleshooting ### 404 on refresh (SPA routing) Ensure rewrite rules are configured to serve `index.html` for non-file paths. ### Docs not downloading Check MIME types are configured for `.pptx`, `.docx`, `.pdf`. ### Permission denied ```bash sudo chown -R www-data:www-data /var/www/pwlmyers.org sudo chmod -R 755 /var/www/pwlmyers.org ``` ### Check logs ```bash # Apache sudo tail -f /var/log/apache2/pwlmyers-error.log # lighttpd sudo tail -f /var/log/lighttpd/error.log # Nginx sudo tail -f /var/log/nginx/error.log ``` ## Prerequisites All options require: - Domain pointing to VPS (A record) - Ports 80/443 open in Oracle Cloud security list - Node.js 20.19+ for building See [README.md](README.md) for development setup.