Skip to main content

Overview

This guide covers deploying the Unity WebGL build of WPM Typing Tutor to production. The web version serves as the foundation for both direct browser access and the React Native mobile app (which loads the web version in a WebView).
Deployment Target: Static web hostingBuild Type: Unity WebGLTotal Size: ~21 MB (compressed)Requirements: Web server with compression support

Pre-Deployment Checklist

Before deploying, ensure you have:
1

Complete Unity Build

  • Unity WebGL build completed successfully
  • All .unityweb files present in Build/ folder
  • INTEGRADORA.json configuration file generated
  • UnityLoader.js included
  • index.html and template files ready
2

Test Locally

  • Game runs without errors locally
  • All levels and features work correctly
  • Loading screen displays properly
  • Performance is acceptable
3

Production Configuration

  • developmentBuild: false (recommended for production)
  • Compression enabled (Brotli or Gzip)
  • Code stripping enabled
  • Appropriate quality settings
4

Domain & Hosting Ready

  • Domain name configured (if applicable)
  • Hosting provider selected
  • SSL certificate available (HTTPS required)

Hosting Requirements

Server Requirements

Must Have:
  • Static file hosting
  • HTTPS support (SSL certificate)
  • MIME type configuration
  • Compression support (Gzip or Brotli)
  • CORS headers (if API integration)
  • Minimum 100 MB storage

MIME Types Configuration

Configure your web server to serve Unity WebGL files with correct MIME types:
nginx.conf
# Unity WebGL MIME types
types {
    application/octet-stream unityweb;
    application/wasm wasm;
    application/javascript js;
    application/json json;
    text/html html htm;
    text/css css;
}

# Enable compression for .unityweb files
gzip on;
gzip_types application/octet-stream application/wasm application/javascript;
.htaccess
# Unity WebGL MIME types
AddType application/octet-stream .unityweb
AddType application/wasm .wasm
AddType application/javascript .js

# Enable compression
AddOutputFilterByType DEFLATE application/octet-stream
AddOutputFilterByType DEFLATE application/wasm
AddOutputFilterByType DEFLATE application/javascript

Deployment Options

Best for: Easy deployment, automatic HTTPS, CDN, great free tier
1

Prepare Build

Organize your files:
project-root/
├── index.html
├── Build/
│   ├── INTEGRADORA.json
│   ├── INTEGRADORA.data.unityweb
│   ├── INTEGRADORA.wasm.code.unityweb
│   ├── INTEGRADORA.wasm.framework.unityweb
│   └── UnityLoader.js
└── TemplateData/
    ├── UnityProgress.js
    ├── favicon.ico
    └── mecanografia.jpg
2

Create netlify.toml

netlify.toml
[build]
  publish = "."

[[headers]]
  for = "/*"
  [headers.values]
    X-Frame-Options = "SAMEORIGIN"
    X-XSS-Protection = "1; mode=block"
    X-Content-Type-Options = "nosniff"

[[headers]]
  for = "/*.unityweb"
  [headers.values]
    Content-Type = "application/octet-stream"
    Content-Encoding = "gzip"

[[headers]]
  for = "/*.wasm"
  [headers.values]
    Content-Type = "application/wasm"
3

Deploy to Netlify

Option A: Drag & Drop
  1. Go to netlify.com
  2. Drag your project folder to deploy
Option B: Netlify CLI
# Install Netlify CLI
npm install -g netlify-cli

# Login
netlify login

# Deploy
netlify deploy --prod
Option C: Git Integration
  1. Push code to GitHub/GitLab
  2. Connect repository in Netlify
  3. Auto-deploy on push
4

Configure Custom Domain (Optional)

In Netlify dashboard:
  • Domain settings → Add custom domain
  • Update DNS records
  • SSL certificate auto-generated

Option 2: Vercel

Best for: Next.js integration, serverless functions, global CDN
1

Install Vercel CLI

npm install -g vercel
2

Create vercel.json

vercel.json
{
  "headers": [
    {
      "source": "/(.*)",
      "headers": [
        {
          "key": "X-Frame-Options",
          "value": "SAMEORIGIN"
        }
      ]
    },
    {
      "source": "/**/*.unityweb",
      "headers": [
        {
          "key": "Content-Type",
          "value": "application/octet-stream"
        },
        {
          "key": "Content-Encoding",
          "value": "gzip"
        }
      ]
    }
  ]
}
3

Deploy

vercel
Follow prompts to deploy. Vercel automatically:
  • Generates HTTPS certificate
  • Provides CDN distribution
  • Creates preview URLs

Option 3: GitHub Pages

Best for: Free hosting, GitHub integration, simple static sites
1

Prepare Repository

# Create or use existing repository
git init
git add .
git commit -m "Initial commit"
git branch -M main
git remote add origin https://github.com/username/wpm-typing-tutor.git
git push -u origin main
2

Create GitHub Actions Workflow

.github/workflows/deploy.yml
name: Deploy to GitHub Pages

on:
  push:
    branches: [main]

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      
      - name: Deploy to GitHub Pages
        uses: peaceiris/actions-gh-pages@v3
        with:
          github_token: ${{ secrets.GITHUB_TOKEN }}
          publish_dir: ./
3

Enable GitHub Pages

  1. Go to repository settings
  2. Pages → Source → Deploy from branch
  3. Select gh-pages branch
  4. Save
Site will be available at: https://username.github.io/wpm-typing-tutor/
4

Configure Custom Domain (Optional)

  1. Add CNAME file with your domain
  2. Update DNS records at your registrar
  3. Enable HTTPS in GitHub Pages settings

Option 4: Traditional Web Hosting (cPanel/FTP)

Best for: Existing hosting, full control, custom server configuration
1

Configure .htaccess

.htaccess
# Enable compression
<IfModule mod_deflate.c>
  AddOutputFilterByType DEFLATE text/html text/css application/javascript
  AddOutputFilterByType DEFLATE application/octet-stream
  AddOutputFilterByType DEFLATE application/wasm
</IfModule>

# MIME types
AddType application/octet-stream .unityweb
AddType application/wasm .wasm

# Cache control
<IfModule mod_expires.c>
  ExpiresActive On
  ExpiresByType application/octet-stream "access plus 1 year"
  ExpiresByType application/javascript "access plus 1 year"
  ExpiresByType text/css "access plus 1 year"
</IfModule>

# CORS (if needed)
<IfModule mod_headers.c>
  Header set Access-Control-Allow-Origin "*"
</IfModule>
2

Upload Files

Via FTP:
  1. Connect with FTP client (FileZilla, Cyberduck)
  2. Upload all files to public_html or www folder
  3. Ensure correct permissions (644 for files, 755 for folders)
Via cPanel:
  1. File Manager → public_html
  2. Upload zip file
  3. Extract files
3

Test Deployment

Visit your domain:
  • Check if game loads
  • Test all functionality
  • Verify HTTPS works
  • Check browser console for errors

Compression Configuration

Gzip Compression

Unity uses pre-compressed .unityweb files with Gzip:
server {
    # ... other config
    
    gzip on;
    gzip_vary on;
    gzip_types
        application/octet-stream
        application/wasm
        application/javascript
        text/css
        text/html;
    
    location ~ \.unityweb$ {
        gzip_static on;
        add_header Content-Encoding gzip;
        add_header Content-Type application/octet-stream;
    }
}

Brotli Compression

Brotli provides ~30% better compression than Gzip:
nginx - Brotli
server {
    # ... other config
    
    brotli on;
    brotli_types
        application/octet-stream
        application/wasm
        application/javascript
        text/css
        text/html;
    
    location ~ \.unityweb$ {
        brotli_static on;
        add_header Content-Encoding br;
        add_header Content-Type application/octet-stream;
    }
}
Ensure your Unity build uses the same compression method as your server configuration. Mismatched compression will cause loading errors.

Caching Strategy

Cache Headers

Optimize loading speed with proper caching:
nginx - Caching
location ~* \.(unityweb|wasm|js|css)$ {
    expires 1y;
    add_header Cache-Control "public, immutable";
}

location ~* \.(json)$ {
    expires 1d;
    add_header Cache-Control "public, must-revalidate";
}

location = /index.html {
    expires -1;
    add_header Cache-Control "no-cache, no-store, must-revalidate";
}
.htaccess - Caching
<IfModule mod_expires.c>
    ExpiresActive On
    
    # Cache Unity files for 1 year
    ExpiresByType application/octet-stream "access plus 1 year"
    ExpiresByType application/wasm "access plus 1 year"
    ExpiresByType application/javascript "access plus 1 year"
    ExpiresByType text/css "access plus 1 year"
    
    # Short cache for HTML
    ExpiresByType text/html "access plus 0 seconds"
</IfModule>

<IfModule mod_headers.c>
    <FilesMatch "\.(unityweb|wasm|js|css)$">
        Header set Cache-Control "max-age=31536000, public, immutable"
    </FilesMatch>
    
    <FilesMatch "\.html$">
        Header set Cache-Control "no-cache, no-store, must-revalidate"
    </FilesMatch>
</IfModule>

CDN Integration

Cloudflare Setup

1

Add Site to Cloudflare

  1. Sign up at cloudflare.com
  2. Add your domain
  3. Update nameservers at your registrar
2

Configure Settings

Speed → Optimization
  • Auto Minify: Enable for CSS, JS, HTML
  • Brotli: Enabled
  • Early Hints: Enabled
Caching → Configuration
  • Caching Level: Standard
  • Browser Cache TTL: 1 year
3

Create Page Rules

Rule 1: *.unityweb
- Cache Level: Cache Everything
- Edge Cache TTL: 1 year
- Browser Cache TTL: 1 year

Rule 2: index.html
- Cache Level: Bypass
4

Enable HTTP/2

Cloudflare automatically enables HTTP/2 for better parallel loading.

Custom CDN Configuration

For other CDN providers (AWS CloudFront, Azure CDN, etc.):
CloudFront Behavior
{
  "PathPattern": "*.unityweb",
  "Compress": true,
  "MinTTL": 31536000,
  "DefaultTTL": 31536000,
  "MaxTTL": 31536000,
  "ViewerProtocolPolicy": "redirect-to-https"
}

Security Configuration

HTTPS Enforcement

HTTPS is required for Unity WebGL features like SharedArrayBuffer and certain browser APIs.
nginx - Force HTTPS
server {
    listen 80;
    server_name yourdomain.com;
    return 301 https://$server_name$request_uri;
}

server {
    listen 443 ssl http2;
    server_name yourdomain.com;
    
    ssl_certificate /path/to/cert.pem;
    ssl_certificate_key /path/to/key.pem;
    
    # ... rest of config
}
.htaccess - Force HTTPS
RewriteEngine On
RewriteCond %{HTTPS} off
RewriteRule ^(.*)$ https://%{HTTP_HOST}%{REQUEST_URI} [L,R=301]

Security Headers

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 "strict-origin-when-cross-origin" always;
add_header Permissions-Policy "gamepad=*, keyboard-map=*" always;

CORS Configuration (If Needed)

If mobile app loads from different domain:
CORS for Mobile App
add_header Access-Control-Allow-Origin "https://your-mobile-app-domain.com";
add_header Access-Control-Allow-Methods "GET, OPTIONS";
add_header Access-Control-Allow-Headers "Content-Type";

Environment-Specific Configuration

Development vs Production

config.dev.js
const CONFIG = {
  API_URL: 'http://localhost:3001',
  DEBUG: true,
  ANALYTICS: false,
  SENTRY: false,
  UNITY_BUILD: 'Build/INTEGRADORA.json'
};

Build Script

Automate deployment preparation:
deploy.sh
#!/bin/bash

# Build script for WPM Typing Tutor

echo "🚀 Starting deployment build..."

# Clean previous build
rm -rf dist/
mkdir dist/

# Copy Unity build files
cp -r Build/ dist/Build/
cp -r TemplateData/ dist/TemplateData/
cp index.html dist/
cp netlify.toml dist/ # or vercel.json, .htaccess, etc.

# Minify HTML/CSS/JS (optional)
if command -v html-minifier &> /dev/null; then
  html-minifier --collapse-whitespace --remove-comments \
    dist/index.html -o dist/index.html
fi

# Validate build
if [ ! -f "dist/Build/INTEGRADORA.json" ]; then
  echo "❌ Error: Unity build files not found!"
  exit 1
fi

echo "✅ Build complete! Ready to deploy."
echo "📦 Build size:"
du -sh dist/
Make executable:
chmod +x deploy.sh
./deploy.sh

Post-Deployment

Verification Checklist

After deployment, verify:
  • Game loads without errors
  • Loading progress bar displays correctly
  • Initial load time < 10 seconds on fast connection
  • Assets download properly
  • No 404 errors in console
  • All game levels work
  • Keyboard input responsive
  • Score calculation accurate
  • Leaderboard updates (if applicable)
  • Audio plays correctly
  • Works in Chrome
  • Works in Firefox
  • Works in Safari
  • Works in Edge
  • Proper error messages on unsupported browsers
  • HTTPS enabled
  • Security headers present
  • Compression enabled
  • Caching configured
  • CDN working (if applicable)
  • React Native app can load game
  • Touch input works
  • Performance acceptable on mobile
  • No CORS errors

Performance Testing

# Test with curl
curl -I https://yourdomain.com

# Check compression
curl -H "Accept-Encoding: gzip" -I https://yourdomain.com/Build/INTEGRADORA.data.unityweb

# Check response time
curl -w "@curl-format.txt" -o /dev/null -s https://yourdomain.com
Create curl-format.txt:
time_namelookup:  %{time_namelookup}s
time_connect:  %{time_connect}s
time_appconnect:  %{time_appconnect}s
time_starttransfer:  %{time_starttransfer}s
time_total:  %{time_total}s

Monitoring & Analytics

Basic Analytics

Integrate Google Analytics or similar:
index.html
<!-- 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');
  
  // Track game events
  function trackGameEvent(action, label, value) {
    gtag('event', action, {
      'event_category': 'Game',
      'event_label': label,
      'value': value
    });
  }
</script>

Error Tracking

Integrate Sentry for error monitoring:
Error Tracking
<script src="https://browser.sentry-cdn.com/7.x.x/bundle.min.js"></script>
<script>
  Sentry.init({
    dsn: 'YOUR_SENTRY_DSN',
    environment: 'production',
    beforeSend(event) {
      // Filter out Unity internal errors if needed
      return event;
    }
  });
</script>

Troubleshooting Deployment Issues

Common causes:
  • Incorrect file paths
  • Missing .unityweb files
  • MIME type not configured
  • Compression mismatch
Debug steps:
  1. Open browser console (F12)
  2. Check for 404 errors
  3. Verify file paths in INTEGRADORA.json
  4. Test without compression
  5. Check server error logs
Solutions:
  • Enable compression (Brotli preferred)
  • Use CDN
  • Enable HTTP/2
  • Optimize Unity build (code stripping)
  • Reduce asset quality
  • Check server bandwidth
When this happens:
  • Loading from different domain
  • Mobile app integration
  • API calls
Solution:
add_header Access-Control-Allow-Origin "*";
Solutions:
  • Use Let’s Encrypt (free)
  • Use hosting provider’s SSL
  • Check certificate expiration
  • Verify domain matches certificate

Continuous Deployment

GitHub Actions

Automate deployment on git push:
.github/workflows/deploy.yml
name: Deploy to Production

on:
  push:
    branches: [main]

jobs:
  deploy:
    runs-on: ubuntu-latest
    
    steps:
      - uses: actions/checkout@v3
      
      - name: Deploy to Netlify
        uses: netlify/actions/cli@master
        with:
          args: deploy --prod --dir=.
        env:
          NETLIFY_AUTH_TOKEN: ${{ secrets.NETLIFY_AUTH_TOKEN }}
          NETLIFY_SITE_ID: ${{ secrets.NETLIFY_SITE_ID }}

GitLab CI/CD

.gitlab-ci.yml
stages:
  - deploy

deploy_production:
  stage: deploy
  script:
    - npm install -g netlify-cli
    - netlify deploy --prod --dir=.
  only:
    - main
  environment:
    name: production
    url: https://yourdomain.com

Hosting Cost Comparison

ProviderFree TierPaid PlansBest For
Netlify100GB bandwidth/monthFrom $19/moEasy deployment, auto-SSL
Vercel100GB bandwidth/monthFrom $20/moNext.js, serverless
GitHub PagesUnlimited (soft limit)Free onlySimple static sites
Cloudflare PagesUnlimited bandwidthFreeBest free option
AWS S3 + CloudFront50GB free (1st year)Pay per useLarge scale
DigitalOceanNo free tierFrom $4/moFull control
For WPM Typing Tutor’s ~21MB build size and expected traffic, the free tiers of Netlify, Vercel, or Cloudflare Pages should be sufficient.

Next Steps

Unity Setup

Review Unity WebGL build configuration

React Native App

Configure mobile app to load deployed game

Platform Guide

User guide for web platform

Unity Setup

Unity project configuration

Build docs developers (and LLMs) love