Deployment Guide
VozCraft is a static web application that can be deployed to any static hosting platform. This guide covers deployment to popular hosting services including GitHub Pages, Vercel, Netlify, and traditional web servers.
Prerequisites
Before deploying, ensure you have:
Build the application
This creates the dist/ directory with production-ready files.
Verify build output
Check that dist/ contains:
index.html
manifest.json
assets/ directory with JS bundles
Images (logo.png, logotipo.png)
Build size: The complete VozCraft build is typically 400-800 KB (150-200 KB gzipped), making it fast to deploy and serve.
Vercel Deployment
Vercel provides zero-configuration deployment with automatic builds and global CDN.
Method 1: Vercel CLI
Login to Vercel
Follow the authentication prompts.
Deploy
Vercel will:
Detect the project as a Vite application
Build automatically
Deploy to a preview URL
Deploy to production
Deploys to your production domain.
Method 2: Vercel Dashboard
Connect repository
Go to vercel.com
Click “Add New” → “Project”
Import your GitHub/GitLab/Bitbucket repository
Configure build settings
Vercel auto-detects Vite projects. Verify settings:
Framework Preset: Vite
Build Command: npm run build
Output Directory: dist
Install Command: npm install
Deploy
Click “Deploy” to start the build and deployment.
Vercel Configuration File
Create vercel.json for custom configuration: {
"buildCommand" : "npm run build" ,
"outputDirectory" : "dist" ,
"devCommand" : "npm run dev" ,
"installCommand" : "npm install" ,
"framework" : "vite" ,
"rewrites" : [
{ "source" : "/(.*)" , "destination" : "/index.html" }
],
"headers" : [
{
"source" : "/assets/(.*)" ,
"headers" : [
{
"key" : "Cache-Control" ,
"value" : "public, max-age=31536000, immutable"
}
]
},
{
"source" : "/(.*) \\ .(?:jpg|jpeg|png|gif|ico|svg)" ,
"headers" : [
{
"key" : "Cache-Control" ,
"value" : "public, max-age=86400, s-maxage=86400"
}
]
}
]
}
The rewrites rule ensures all routes serve index.html for SPA routing (if you add React Router later).
Vercel features:
✅ Automatic builds on git push
✅ Preview deployments for PRs
✅ Global CDN (Edge Network)
✅ Automatic HTTPS
✅ Zero configuration
✅ Free tier available
Netlify Deployment
Netlify offers similar features to Vercel with easy drag-and-drop deployment.
Method 1: Netlify CLI
Install Netlify CLI
npm install -g netlify-cli
Initialize site
Follow the prompts to create a new site or link existing one.
Method 2: Netlify Dashboard
Connect repository
Go to netlify.com
Click “Add new site” → “Import an existing project”
Connect your Git provider and select repository
Configure build
Set build configuration:
Base directory: (leave empty)
Build command: npm run build
Publish directory: dist
Deploy
Click “Deploy site” to start the build.
Method 3: Drag and Drop
Upload dist folder
Go to Netlify Dashboard
Drag and drop the dist/ folder onto the upload area
Netlify deploys instantly
Netlify Configuration File
Create netlify.toml for custom configuration: [ build ]
command = "npm run build"
publish = "dist"
[[ redirects ]]
from = "/*"
to = "/index.html"
status = 200
[[ headers ]]
for = "/assets/*"
[ headers . values ]
Cache-Control = "public, max-age=31536000, immutable"
[[ headers ]]
for = "/*.js"
[ headers . values ]
Cache-Control = "public, max-age=31536000, immutable"
[[ headers ]]
for = "/*.css"
[ headers . values ]
Cache-Control = "public, max-age=31536000, immutable"
[[ headers ]]
for = "/manifest.json"
[ headers . values ]
Content-Type = "application/manifest+json"
Cache-Control = "public, max-age=0, must-revalidate"
Netlify features:
✅ Automatic builds on git push
✅ Deploy previews for PRs
✅ Global CDN
✅ Automatic HTTPS
✅ Form handling
✅ Serverless functions
✅ Free tier available
GitHub Pages Deployment
Deploy VozCraft directly from your GitHub repository.
Method 1: GitHub Actions (Recommended)
Create .github/workflows/deploy.yml:
.github/workflows/deploy.yml
name : Deploy to GitHub Pages
on :
push :
branches :
- main
# Allow manual runs
workflow_dispatch :
permissions :
contents : read
pages : write
id-token : write
concurrency :
group : "pages"
cancel-in-progress : false
jobs :
build :
runs-on : ubuntu-latest
steps :
- name : Checkout
uses : actions/checkout@v4
- name : Setup Node
uses : actions/setup-node@v4
with :
node-version : '20'
cache : 'npm'
- name : Install dependencies
run : npm ci
- name : Build
run : npm run build
- name : Setup Pages
uses : actions/configure-pages@v4
- name : Upload artifact
uses : actions/upload-pages-artifact@v3
with :
path : './dist'
deploy :
environment :
name : github-pages
url : ${{ steps.deployment.outputs.page_url }}
runs-on : ubuntu-latest
needs : build
steps :
- name : Deploy to GitHub Pages
id : deployment
uses : actions/deploy-pages@v4
Enable GitHub Pages
Go to repository Settings → Pages
Source: “GitHub Actions”
Push workflow file
git add .github/workflows/deploy.yml
git commit -m "Add GitHub Pages deployment"
git push
Wait for deployment
GitHub Actions will automatically build and deploy. View progress: Actions tab in your repository
Access deployed site
Your site will be available at: https://username.github.io/vozcraft/
Base URL configuration: If deploying to a repository page (not user/org page), update vite.config.js: export default defineConfig ({
plugins: [ react ()] ,
base: '/vozcraft/' , // Replace with your repo name
})
This ensures assets load correctly from the subdirectory.
Method 2: gh-pages Package
Add deploy script
Update package.json: {
"scripts" : {
"build" : "vite build" ,
"predeploy" : "npm run build" ,
"deploy" : "gh-pages -d dist"
}
}
Deploy
This builds and pushes to the gh-pages branch.
Configure GitHub Pages
Go to Settings → Pages
Source: “Deploy from a branch”
Branch: gh-pages → / (root)
Save
Traditional Web Server Deployment
Nginx
Configuration for serving VozCraft on Nginx:
/etc/nginx/sites-available/vozcraft
server {
listen 80 ;
listen [::]:80;
server_name vozcraft.com www.vozcraft.com;
# Redirect to HTTPS
return 301 https://$ server_name $ request_uri ;
}
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
server_name vozcraft.com www.vozcraft.com;
# SSL configuration
ssl_certificate /etc/letsencrypt/live/vozcraft.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/vozcraft.com/privkey.pem;
# Document root
root /var/www/vozcraft/dist;
index index.html;
# Gzip compression
gzip on ;
gzip_vary on ;
gzip_min_length 1024 ;
gzip_types text/plain text/css text/xml text/javascript application/javascript application/xml+rss application/json;
# 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;
add_header Referrer-Policy "no-referrer-when-downgrade" always;
# Cache static assets
location /assets/ {
expires 1y;
add_header Cache-Control "public, immutable" ;
}
# Cache images
location ~* \.(jpg|jpeg|png|gif|ico|svg)$ {
expires 30d ;
add_header Cache-Control "public" ;
}
# No cache for index.html
location = /index.html {
add_header Cache-Control "no-cache, must-revalidate" ;
}
# SPA routing - serve index.html for all routes
location / {
try_files $ uri $ uri / /index.html;
}
}
Upload build files
scp -r dist/ * user@server:/var/www/vozcraft/dist/
Or use rsync: rsync -avz --delete dist/ user@server:/var/www/vozcraft/dist/
Configure Nginx
sudo nano /etc/nginx/sites-available/vozcraft
sudo ln -s /etc/nginx/sites-available/vozcraft /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx
Set up SSL (Let's Encrypt)
sudo apt install certbot python3-certbot-nginx
sudo certbot --nginx -d vozcraft.com -d www.vozcraft.com
Apache
Configuration for Apache web server:
/etc/apache2/sites-available/vozcraft.conf
< VirtualHost *:80 >
ServerName vozcraft.com
ServerAlias www.vozcraft.com
# Redirect to HTTPS
RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule ^ https://%{HTTP_HOST}%{REQUEST_URI} [L,R= 301 ]
</ VirtualHost >
< VirtualHost *:443 >
ServerName vozcraft.com
ServerAlias www.vozcraft.com
DocumentRoot /var/www/vozcraft/dist
# SSL configuration
SSLEngine on
SSLCertificateFile /etc/letsencrypt/live/vozcraft.com/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/vozcraft.com/privkey.pem
# Enable compression
< IfModule mod_deflate.c >
AddOutputFilterByType DEFLATE text/html text/plain text/xml text/css text/javascript application/javascript application/json
</ IfModule >
# Cache static assets
< Directory "/var/www/vozcraft/dist/assets" >
< IfModule mod_expires.c >
ExpiresActive On
ExpiresDefault "access plus 1 year"
</ IfModule >
</ Directory >
# SPA routing
< Directory "/var/www/vozcraft/dist" >
Options -Indexes +FollowSymLinks
AllowOverride All
Require all granted
RewriteEngine On
RewriteBase /
RewriteRule ^index\.html$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.html [L]
</ Directory >
</ VirtualHost >
Enable required modules
sudo a2enmod rewrite
sudo a2enmod ssl
sudo a2enmod expires
sudo a2enmod deflate
sudo a2enmod headers
Enable site
sudo a2ensite vozcraft
sudo apache2ctl configtest
sudo systemctl reload apache2
Cloud Storage Deployment
AWS S3 + CloudFront
Create S3 bucket
aws s3 mb s3://vozcraft-app
Enable static website hosting
aws s3 website s3://vozcraft-app/ \
--index-document index.html \
--error-document index.html
Upload build
aws s3 sync dist/ s3://vozcraft-app/ --delete
Set up CloudFront
Create CloudFront distribution
Origin: S3 bucket
Default root object: index.html
Custom error responses: 404 → /index.html (200)
Configure custom domain (optional)
Create SSL certificate in ACM
Add CNAME to CloudFront distribution
Update Route 53 DNS
Deployment Checklist
Pre-deployment checks
☐ Run npm run build successfully ☐ Test with npm run preview ☐ Verify all features work ☐ Check browser console for errors ☐ Test on mobile devices ☐ Run Lighthouse audit
Configuration
☐ Set correct base URL in vite.config.js ☐ Update environment variables if needed ☐ Configure caching headers ☐ Set up SSL/HTTPS ☐ Configure SPA routing fallback
Post-deployment
☐ Verify site loads correctly ☐ Test PWA installation ☐ Check all API features (speech synthesis, audio download) ☐ Verify analytics (if configured) ☐ Test from different browsers and devices ☐ Check performance metrics
CDN Configuration
Optimal cache headers for different file types:
# HTML - no cache (always fresh)
Cache-Control: no-cache, must- revalidate
# JavaScript/CSS with hash - cache forever
Cache-Control: public, max-age=31536000, immutable
# Images - cache for 30 days
Cache-Control: public, max-age= 2592000
# Manifest - short cache
Cache-Control: public, max-age= 3600
Compression
Enable gzip and Brotli compression:
# Nginx
gzip on ;
gzip_vary on ;
gzip_types text/plain text/css text/xml text/javascript application/javascript application/json;
# Brotli (requires module)
brotli on ;
brotli_types text/plain text/css text/xml text/javascript application/javascript application/json;
add_header X-Frame-Options "SAMEORIGIN" always;
add_header X-Content-Type-Options "nosniff" always;
add_header X-XSS-Protection "1; mode=block" always;
add_header Referrer-Policy "no-referrer-when-downgrade" always;
add_header Permissions-Policy "geolocation=(), microphone=(), camera=()" always;
Monitoring
Error Tracking
Integrate error tracking (optional):
import { StrictMode } from 'react'
import { createRoot } from 'react-dom/client'
import App from './App.jsx'
// Error tracking
window . addEventListener ( 'error' , ( event ) => {
console . error ( 'Global error:' , event . error );
// Send to error tracking service
});
window . addEventListener ( 'unhandledrejection' , ( event ) => {
console . error ( 'Unhandled promise rejection:' , event . reason );
// Send to error tracking service
});
createRoot ( document . getElementById ( 'root' )). render (
< StrictMode >
< App />
</ StrictMode > ,
)
Analytics
Add analytics tracking:
<!-- Google Analytics -->
< script async src = "https://www.googletagmanager.com/gtag/js?id=GA_MEASUREMENT_ID" ></ script >
< script >
window . dataLayer = window . dataLayer || [];
function gtag (){ dataLayer . push ( arguments );}
gtag ( 'js' , new Date ());
gtag ( 'config' , 'GA_MEASUREMENT_ID' );
</ script >
Rollback Strategy
Always maintain ability to rollback:
Vercel/Netlify
Automatic deployment history
Instant rollback via dashboard
Pin deployments to specific commits
Manual Deployments
# Tag releases
git tag v1.0.0
git push origin v1.0.0
# Keep previous builds
mv dist dist- $( date +%Y%m%d-%H%M%S )
npm run build
# Rollback if needed
rm -rf dist
mv dist-20260305-120000 dist
Common Deployment Issues
Cause: Server not configured for SPA routing.Solution: Configure fallback to index.html:location / {
try_files $ uri $ uri / /index.html;
}
Cause: Incorrect base URL.Solution: Update vite.config.js:base : '/correct-path/' , // or '/' for root
Cause: Missing CORS headers.Solution: Add CORS headers:add_header Access-Control-Allow-Origin "*" ;
Next Steps
PWA Setup Optimize PWA installation experience
Web Speech API Understand the core technology