Skip to main content

Deployment Guide

Complete guide for deploying the QR Generator to cPanel/Apache hosting.


Deployment Overview

The QR Generator is a static web application that requires:

  • ✅ Web server (Apache/Nginx)
  • ✅ HTTPS (for camera access and PWA features)
  • ✅ URL rewriting (for SPA routing)
  • ❌ No Node.js runtime needed
  • ❌ No database required
  • ❌ No backend API

Prerequisites

Server Requirements

RequirementSpecification
Web ServerApache 2.4+ or Nginx
PHPNot required (static files only)
Node.jsNot required at runtime (only for building)
SSL CertificateRequired (Let's Encrypt recommended)
Disk Space~10MB for application files
Bandwidth~1MB per first-time visitor

Local Build Requirements

ToolVersionPurpose
Node.js18+Build tool
npm8+Package manager
GitAnyVersion control

Step 1: Build Production Files

On Your Local Machine

# Navigate to project directory
cd Z:\Repos\mini-qr

# Install dependencies (first time only)
npm install

# Build production files
npm run build

Build output:

dist/
├── .htaccess ← Created manually
├── index.html
├── manifest.webmanifest
├── sw.js
├── workbox-*.js
├── assets/
│ ├── index-[hash].js
│ ├── index-[hash].css
│ └── *.png/svg
├── app_icons/
├── batch_export_templates/
└── presets/

Build time: ~30-60 seconds


Step 2: Create .htaccess File

Create .htaccess in the dist/ folder with:

# Enable HTTPS redirect (after SSL is installed)
RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]

# Serve index.html for all routes (SPA routing)
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /

# Handle Authorization Header
RewriteCond %{HTTP:Authorization} .
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]

# Don't rewrite files or directories
RewriteCond %{REQUEST_FILENAME} -f [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^ - [L]

# Rewrite everything else to index.html
RewriteRule ^ index.html [L]
</IfModule>

# Security Headers
<IfModule mod_headers.c>
Header set X-Content-Type-Options "nosniff"
Header set X-XSS-Protection "1; mode=block"
Header set X-Frame-Options "SAMEORIGIN"
Header set Referrer-Policy "strict-origin-when-cross-origin"
</IfModule>

# Compression
<IfModule mod_deflate.c>
AddOutputFilterByType DEFLATE text/html
AddOutputFilterByType DEFLATE text/css
AddOutputFilterByType DEFLATE text/javascript
AddOutputFilterByType DEFLATE application/javascript
AddOutputFilterByType DEFLATE application/json
</IfModule>

# Browser caching for static assets
<IfModule mod_expires.c>
ExpiresActive On
ExpiresByType image/jpeg "access plus 1 year"
ExpiresByType image/png "access plus 1 year"
ExpiresByType image/svg+xml "access plus 1 year"
ExpiresByType text/css "access plus 1 month"
ExpiresByType application/javascript "access plus 1 month"

# Short cache for service worker
<Files "sw.js">
ExpiresDefault "access plus 0 seconds"
</Files>
</IfModule>

# Disable directory browsing
Options -Indexes

Step 3: Upload to cPanel

  1. Login to cPanel

    • URL: https://qr-generator.scottsdalemint.com:2083
    • Username: qrgenerator
  2. Navigate to File Manager

    • Click File Manager in cPanel
    • Go to public_html/ directory
  3. Clear Existing Files

    • Select all default files (index.html, cgi-bin, etc.)
    • Click Delete
  4. Upload Files

    • Click Upload button
    • Drag all files from dist/ folder
    • Or select files manually
    • Wait for upload to complete
  5. Verify Structure

    public_html/
    ├── .htaccess ← Must be present
    ├── index.html
    ├── manifest.webmanifest
    ├── sw.js
    ├── assets/
    ├── app_icons/
    ├── batch_export_templates/
    └── presets/

Method B: FTP/SFTP

# Using FileZilla or command line
sftp qrgenerator@your-server-ip

# Navigate to web root
cd public_html/

# Upload all files from dist/
put -r dist/* .

# Verify .htaccess uploaded
ls -la .htaccess

Method C: ZIP Upload (Fastest)

  1. Create ZIP locally

    • Select all contents of dist/ folder (NOT the dist folder itself)
    • Right-click → Send to → Compressed folder
    • Name: qr-generator.zip
  2. Upload ZIP to cPanel

    • File Manager → public_html/
    • Upload qr-generator.zip
  3. Extract

    • Right-click ZIP file → Extract
    • Extract to current directory
    • Delete ZIP file after extraction

Step 4: Configure Domain

Verify Domain Setup

  1. In cPanel → Domains
  2. Verify qr-generator.scottsdalemint.com points to:
    • Document Root: /home/qrgenerator/public_html

If Domain Not Set Up

  1. Add Domain

    • cPanel → Addon Domains
    • Domain: qr-generator.scottsdalemint.com
    • Document Root: /home/qrgenerator/public_html
    • Click Add Domain
  2. Wait for DNS Propagation (5-30 minutes)


Step 5: Install SSL Certificate

  1. In cPanel → SSL/TLS Status
  2. Select qr-generator.scottsdalemint.com
  3. Click Run AutoSSL
  4. Wait 2-5 minutes for certificate installation
  5. Verify: Visit https://qr-generator.scottsdalemint.com

Using Let's Encrypt

  1. In cPanel → Let's Encrypt SSL
  2. Select domain: qr-generator.scottsdalemint.com
  3. Click Issue
  4. Wait for confirmation

After SSL Installation

Uncomment HTTPS redirect in .htaccess:

RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]

Step 6: Verify File Permissions

Check Permissions

  1. In File Manager
  2. Right-click .htaccessPermissions
  3. Set to 644 (Owner: Read+Write, Group: Read, World: Read)

Correct Permissions

File TypePermissionNumeric
Directoriesdrwxr-xr-x755
Files-rw-r--r--644
.htaccess-rw-r--r--644

Fix permissions recursively:

# Via SSH (if available)
cd /home/qrgenerator/public_html
find . -type d -exec chmod 755 {} \;
find . -type f -exec chmod 644 {} \;

Step 7: Test Deployment

Basic Tests

  1. Visit Homepage

    • URL: https://qr-generator.scottsdalemint.com
    • Should load instantly
  2. Create QR Code

    • Enter text in Create tab
    • Verify QR code generates
    • Download PNG/JPG/SVG
  3. Scan QR Code

    • Click Scan tab
    • Test camera (allow permission)
    • Upload a QR code image
  4. Encryption

    • Enable encryption
    • Enter password
    • Verify green checkmark
    • Export encrypted QR
  5. Batch Export

    • Upload sample CSV
    • Preview rows
    • Export batch
  6. PWA Install

    • Look for install prompt
    • Install as app
    • Test offline (airplane mode)

Route Testing

Visit these URLs directly (should all load without 404):

  • https://qr-generator.scottsdalemint.com/
  • https://qr-generator.scottsdalemint.com/create
  • https://qr-generator.scottsdalemint.com/scan

If you see 404: .htaccess rewrite rules not working.

Browser Console Check

  1. Press F12 to open DevTools
  2. Check Console tab
  3. Should see no errors
  4. Look for: "Service Worker registered successfully"

Updating the Application

Update Workflow

  1. Build new version locally

    cd Z:\Repos\mini-qr
    npm run build
  2. Backup current deployment

    • In cPanel File Manager
    • Select all files in public_html/
    • Click Compress → Create ZIP
    • Download backup ZIP
  3. Upload new files

    • Upload new dist/ contents
    • Overwrite existing files
    • Preserve .htaccess (don't overwrite unless changed)
  4. Clear cache

    • Users: Hard refresh (Ctrl+F5)
    • Server: May need to clear cache
    • Service Worker will auto-update

Cache Busting

Automatic:

  • Vite generates unique hashes for JS/CSS files
  • index-[hash].js changes with each build
  • Old files can be deleted

Manual:

  • Edit index.html if needed
  • Update service worker sw.js version

Troubleshooting

Issue: 404 Not Found on Routes

Symptom: Direct URLs like /create show 404
Cause: .htaccess not working or missing
Solution:

  1. Verify .htaccess exists in public_html/
  2. Check file permissions (644)
  3. Verify mod_rewrite enabled (contact host)
  4. Check Apache error logs

Issue: Mixed Content Errors

Symptom: HTTPS site loading HTTP resources
Cause: External resources using http://
Solution:

  1. Ensure SSL installed and working
  2. Force HTTPS redirect in .htaccess
  3. Check browser console for specific resources

Issue: Service Worker Not Updating

Symptom: Old version still showing after update
Cause: Service Worker caching old files
Solution:

  1. Hard refresh: Ctrl+Shift+R (or Cmd+Shift+R)
  2. Clear browser cache
  3. Unregister service worker in DevTools
  4. Close all tabs and reopen

Issue: Camera Not Working

Symptom: "Camera access denied" or no camera detected
Cause: HTTPS not configured or permissions denied
Solution:

  1. Verify SSL certificate installed
  2. Check browser permissions (allow camera)
  3. Test in different browser
  4. Check browser console for errors

Issue: Large Bundle Size Warning

Symptom: Browser dev tools show large JS file
Cause: Expected — QR libraries are large
Solution:

  1. Enable Gzip compression (see .htaccess)
  2. Use browser caching headers
  3. Service worker caches everything after first load
  4. Normal behavior for this type of app

Performance Optimization

Already Implemented

  • ✅ Vite production build (minification, tree-shaking)
  • ✅ Gzip compression via .htaccess
  • ✅ Browser caching with long expiry
  • ✅ Service Worker with pre-caching
  • ✅ Lazy-loaded language files
  • ✅ Code splitting where possible

Additional Optimizations (Optional)

CDN:

  • Use Cloudflare for global CDN
  • Cache everything at edge
  • DDoS protection

HTTP/2:

  • Most cPanel servers support HTTP/2
  • Multiplexing improves load times
  • Check with host if not enabled

Image Optimization:

  • Preset logos already optimized
  • User-uploaded logos not optimized (client-side)
  • Consider WebP format for app icons

Security Checklist

  • ✅ HTTPS enforced
  • ✅ Security headers in .htaccess
  • ✅ Directory browsing disabled
  • ✅ No sensitive data exposed
  • ✅ No backend API endpoints
  • ✅ No database connections
  • ✅ Client-side encryption only
  • ✅ No user authentication required

Additional security:

  • Regular server updates
  • Strong cPanel password
  • Two-factor authentication on cPanel
  • Regular backups

Monitoring & Maintenance

What to Monitor

  • Uptime: Use UptimeRobot or similar
  • SSL expiry: Auto-renews with Let's Encrypt
  • Disk space: App uses ~10MB
  • Error logs: Check Apache error logs periodically

Maintenance Tasks

TaskFrequencyAction
Update appAs neededRebuild and redeploy
Check SSLMonthlyVerify auto-renewal working
Review logsWeeklyCheck for errors
Test featuresAfter updatesRun test checklist
BackupBefore updatesDownload current files

Rollback Procedure

If an update causes issues:

  1. Restore from backup

    • Upload backup ZIP to cPanel
    • Extract to public_html/
    • Overwrite problematic files
  2. Clear caches

    • Browser: Hard refresh
    • Server: May need to purge cache
    • CDN: Purge Cloudflare if applicable
  3. Verify rollback

    • Test all features
    • Check browser console
    • Monitor error logs

Support & Resources

Documentation

Hosting Support

  • cPanel documentation
  • Hosting provider support
  • Server administrator

Browser Issues

  • Chrome DevTools
  • Firefox Developer Tools
  • Safari Web Inspector
  • Browser vendor support forums

Next Steps