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
| Requirement | Specification |
|---|---|
| Web Server | Apache 2.4+ or Nginx |
| PHP | Not required (static files only) |
| Node.js | Not required at runtime (only for building) |
| SSL Certificate | Required (Let's Encrypt recommended) |
| Disk Space | ~10MB for application files |
| Bandwidth | ~1MB per first-time visitor |
Local Build Requirements
| Tool | Version | Purpose |
|---|---|---|
| Node.js | 18+ | Build tool |
| npm | 8+ | Package manager |
| Git | Any | Version 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
Method A: File Manager (Recommended)
-
Login to cPanel
- URL:
https://qr-generator.scottsdalemint.com:2083 - Username:
qrgenerator
- URL:
-
Navigate to File Manager
- Click File Manager in cPanel
- Go to
public_html/directory
-
Clear Existing Files
- Select all default files (index.html, cgi-bin, etc.)
- Click Delete
-
Upload Files
- Click Upload button
- Drag all files from
dist/folder - Or select files manually
- Wait for upload to complete
-
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)
-
Create ZIP locally
- Select all contents of
dist/folder (NOT the dist folder itself) - Right-click → Send to → Compressed folder
- Name:
qr-generator.zip
- Select all contents of
-
Upload ZIP to cPanel
- File Manager →
public_html/ - Upload
qr-generator.zip
- File Manager →
-
Extract
- Right-click ZIP file → Extract
- Extract to current directory
- Delete ZIP file after extraction
Step 4: Configure Domain
Verify Domain Setup
- In cPanel → Domains
- Verify
qr-generator.scottsdalemint.compoints to:- Document Root:
/home/qrgenerator/public_html
- Document Root:
If Domain Not Set Up
-
Add Domain
- cPanel → Addon Domains
- Domain:
qr-generator.scottsdalemint.com - Document Root:
/home/qrgenerator/public_html - Click Add Domain
-
Wait for DNS Propagation (5-30 minutes)
Step 5: Install SSL Certificate
Using AutoSSL (Recommended)
- In cPanel → SSL/TLS Status
- Select
qr-generator.scottsdalemint.com - Click Run AutoSSL
- Wait 2-5 minutes for certificate installation
- Verify: Visit
https://qr-generator.scottsdalemint.com
Using Let's Encrypt
- In cPanel → Let's Encrypt SSL
- Select domain:
qr-generator.scottsdalemint.com - Click Issue
- 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
- In File Manager
- Right-click
.htaccess→ Permissions - Set to
644(Owner: Read+Write, Group: Read, World: Read)
Correct Permissions
| File Type | Permission | Numeric |
|---|---|---|
| Directories | drwxr-xr-x | 755 |
| 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
-
✅ Visit Homepage
- URL:
https://qr-generator.scottsdalemint.com - Should load instantly
- URL:
-
✅ Create QR Code
- Enter text in Create tab
- Verify QR code generates
- Download PNG/JPG/SVG
-
✅ Scan QR Code
- Click Scan tab
- Test camera (allow permission)
- Upload a QR code image
-
✅ Encryption
- Enable encryption
- Enter password
- Verify green checkmark
- Export encrypted QR
-
✅ Batch Export
- Upload sample CSV
- Preview rows
- Export batch
-
✅ 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/createhttps://qr-generator.scottsdalemint.com/scan
If you see 404: .htaccess rewrite rules not working.
Browser Console Check
- Press
F12to open DevTools - Check Console tab
- Should see no errors
- Look for: "Service Worker registered successfully"
Updating the Application
Update Workflow
-
Build new version locally
cd Z:\Repos\mini-qr
npm run build -
Backup current deployment
- In cPanel File Manager
- Select all files in
public_html/ - Click Compress → Create ZIP
- Download backup ZIP
-
Upload new files
- Upload new
dist/contents - Overwrite existing files
- Preserve
.htaccess(don't overwrite unless changed)
- Upload new
-
Clear cache
- Users: Hard refresh (
Ctrl+F5) - Server: May need to clear cache
- Service Worker will auto-update
- Users: Hard refresh (
Cache Busting
Automatic:
- Vite generates unique hashes for JS/CSS files
index-[hash].jschanges with each build- Old files can be deleted
Manual:
- Edit
index.htmlif needed - Update service worker
sw.jsversion
Troubleshooting
Issue: 404 Not Found on Routes
Symptom: Direct URLs like /create show 404
Cause: .htaccess not working or missing
Solution:
- Verify
.htaccessexists inpublic_html/ - Check file permissions (644)
- Verify
mod_rewriteenabled (contact host) - Check Apache error logs
Issue: Mixed Content Errors
Symptom: HTTPS site loading HTTP resources
Cause: External resources using http://
Solution:
- Ensure SSL installed and working
- Force HTTPS redirect in
.htaccess - 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:
- Hard refresh:
Ctrl+Shift+R(orCmd+Shift+R) - Clear browser cache
- Unregister service worker in DevTools
- 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:
- Verify SSL certificate installed
- Check browser permissions (allow camera)
- Test in different browser
- 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:
- Enable Gzip compression (see
.htaccess) - Use browser caching headers
- Service worker caches everything after first load
- 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
| Task | Frequency | Action |
|---|---|---|
| Update app | As needed | Rebuild and redeploy |
| Check SSL | Monthly | Verify auto-renewal working |
| Review logs | Weekly | Check for errors |
| Test features | After updates | Run test checklist |
| Backup | Before updates | Download current files |
Rollback Procedure
If an update causes issues:
-
Restore from backup
- Upload backup ZIP to cPanel
- Extract to
public_html/ - Overwrite problematic files
-
Clear caches
- Browser: Hard refresh
- Server: May need to purge cache
- CDN: Purge Cloudflare if applicable
-
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