This guide covers deploying the Math2Visual frontend in production as a static React application.
The Math2Visual frontend is a React application built with Vite that produces static files for production deployment. The production build can be served using:
- Static file servers (serve, http-server)
- Web servers (Nginx, Apache)
- CDN/Cloud hosting (Vercel, Netlify, AWS S3 + CloudFront)
- Node.js 18+
- npm or yarn
- Math2Visual backend running and accessible
- Web server (Nginx recommended) or static file server
Important: Before building for production, ensure the development proxy security setting is removed from vite.config.ts:
// frontend/vite.config.ts - REMOVE THIS LINE BEFORE PRODUCTION BUILD
secure: false, // TODO: remove this when the backend is deployedThe secure: false setting in Vite's proxy configuration disables SSL certificate validation, which is useful during development but poses a security risk in production. This setting should only be present during local development and must be removed when building for production deployments with proper SSL certificates.
cd frontend/
# Install dependencies (if not already done)
npm install
# Set production backend URL (optional, if different from default)
export VITE_BACKEND_URL=https://your-backend-url.com
# Build for production
npm run buildThe build process will:
- Compile TypeScript to JavaScript
- Optimize and minify code
- Bundle assets
- Generate production-ready files in the
dist/directory
# Preview the production build locally
npm run previewThis starts Vite's preview server on http://localhost:4173 (default port) to test the production build before deployment.
# Install serve globally
npm install -g serve
# Serve the production build
serve -s dist -l 3000
# With custom port
serve -s dist -l 8080
# With HTTPS (requires certificates)
serve -s dist -l 3000 --ssl-cert cert.pem --ssl-key key.pem# Install http-server globally
npm install -g http-server
# Serve the production build
http-server dist -p 3000
# With CORS enabled (if needed)
http-server dist -p 3000 --cors
# With HTTPS
http-server dist -p 3000 -S -C cert.pem -K key.pem# Using serve
npx serve -s dist -l 3000
# Using http-server
npx http-server dist -p 3000Create or update /etc/nginx/sites-available/math2visual-frontend:
server {
listen 80;
server_name your-domain.com;
root /path/to/math2visual/frontend/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/x-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;
# Serve static files
location / {
try_files $uri $uri/ /index.html;
}
# Cache static assets
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
expires 1y;
add_header Cache-Control "public, immutable";
}
# Proxy API requests to backend
location /api {
proxy_pass http://127.0.0.1:5000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_cache_bypass $http_upgrade;
# Timeout settings for ML processing
proxy_connect_timeout 60s;
proxy_send_timeout 120s;
proxy_read_timeout 120s;
}
}# Create symbolic link
sudo ln -s /etc/nginx/sites-available/math2visual-frontend /etc/nginx/sites-enabled/
# Test configuration
sudo nginx -t
# Reload Nginx
sudo systemctl reload nginx# Install certbot
sudo apt install certbot python3-certbot-nginx
# Obtain SSL certificate
sudo certbot --nginx -d your-domain.com
# Auto-renewal is set up automaticallyCreate or update /etc/apache2/sites-available/math2visual-frontend.conf:
<VirtualHost *:80>
ServerName your-domain.com
DocumentRoot /path/to/math2visual/frontend/dist
<Directory /path/to/math2visual/frontend/dist>
Options -Indexes +FollowSymLinks
AllowOverride All
Require all granted
# Enable URL rewriting for React Router
RewriteEngine On
RewriteBase /
RewriteRule ^index\.html$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.html [L]
</Directory>
# Proxy API requests to backend
ProxyPreserveHost On
ProxyPass /api http://127.0.0.1:5000/api
ProxyPassReverse /api http://127.0.0.1:5000/api
</VirtualHost># Enable the site
sudo a2ensite math2visual-frontend.conf
# Enable required modules
sudo a2enmod rewrite proxy proxy_http
# Test configuration
sudo apache2ctl configtest
# Restart Apache
sudo systemctl restart apache2# Install Vercel CLI
npm install -g vercel
# Deploy
cd frontend/
vercel
# Or connect your GitHub repository to Vercel dashboardCreate vercel.json in the frontend directory:
{
"buildCommand": "npm run build",
"outputDirectory": "dist",
"rewrites": [
{ "source": "/(.*)", "destination": "/index.html" }
]
}Create netlify.toml in the frontend directory:
[build]
command = "npm run build"
publish = "dist"
[[redirects]]
from = "/*"
to = "/index.html"
status = 200Deploy via Netlify CLI or connect your Git repository.
The frontend uses environment variables that must be set before building:
# Backend URL for production (required if different from default)
VITE_BACKEND_URL=https://api.your-domain.com
# Build with environment variable
VITE_BACKEND_URL=https://api.your-domain.com npm run buildImportant: Environment variables prefixed with VITE_ are embedded at build time. Changes require a rebuild.
The frontend needs to know where the backend API is located. There are two ways to configure this:
-
Build-time configuration (recommended):
VITE_BACKEND_URL=https://api.your-domain.com npm run build
-
Runtime configuration (requires code changes): Update
src/config/api.tsto read from a configuration file or environment-specific settings.
The frontend expects the backend to be accessible at:
- Development:
http://localhost:5000(via Vite proxy) - Production: Configured via
VITE_BACKEND_URLorsrc/config/api.ts
For running with a static file server as a system service:
Create /etc/systemd/system/math2visual-frontend.service:
[Unit]
Description=Math2Visual Frontend
After=network.target
[Service]
Type=simple
User=www-data
Group=www-data
WorkingDirectory=/path/to/math2visual/frontend
ExecStart=/usr/bin/npx serve -s dist -l 3000
Restart=always
RestartSec=3
[Install]
WantedBy=multi-user.targetEnable and start:
sudo systemctl enable math2visual-frontend
sudo systemctl start math2visual-frontend
sudo systemctl status math2visual-frontendAdd to your web server configuration:
# Nginx
add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval'; style-src 'self' 'unsafe-inline'; img-src 'self' data: https:; font-src 'self' data:;" always;Always use HTTPS in production:
- Use Let's Encrypt for free SSL certificates
- Configure automatic renewal
- Redirect HTTP to HTTPS
# Secure file permissions
chmod 755 /path/to/math2visual/frontend/dist
chmod 644 /path/to/math2visual/frontend/dist/*The Vite build process automatically:
- Minifies JavaScript and CSS
- Tree-shakes unused code
- Code-splits for optimal loading
- Optimizes images and assets
Configure your web server to cache static assets:
# Nginx - Cache static assets for 1 year
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg|woff|woff2|ttf|eot)$ {
expires 1y;
add_header Cache-Control "public, immutable";
}
# Don't cache HTML (always get latest)
location ~* \.html$ {
expires -1;
add_header Cache-Control "no-cache, no-store, must-revalidate";
}Enable gzip/brotli compression in your web server for better performance.
# Check if frontend is serving correctly
curl http://your-domain.com
# Check API connectivity
curl http://your-domain.com/api/system/status# Nginx access logs
tail -f /var/log/nginx/access.log
# Nginx error logs
tail -f /var/log/nginx/error.log
# Systemd service logs
journalctl -u math2visual-frontend -f-
404 Errors on Refresh
- Ensure your web server is configured to serve
index.htmlfor all routes - Check URL rewriting rules
- Ensure your web server is configured to serve
-
API Connection Failed
- Verify
VITE_BACKEND_URLwas set during build - Check backend is running and accessible
- Verify CORS settings on backend
- Check proxy configuration in web server
- Verify
-
Build Errors
# Clear cache and rebuild rm -rf node_modules dist npm install npm run build -
Static Assets Not Loading
- Check file permissions
- Verify base path configuration
- Check web server root directory setting
-
CORS Errors
- Ensure backend has CORS enabled
- Check proxy configuration
- Verify API endpoint URLs
For debugging production issues:
# Build with source maps
npm run build -- --sourcemap
# Check build output
ls -la dist/
# Test locally with preview
npm run preview-
Pull latest changes
git pull origin main
-
Update dependencies (if needed)
npm install
-
Rebuild
npm run build
-
Deploy
- Copy
dist/to web server - Or restart service/systemd service
- Or trigger CI/CD pipeline
- Copy
For zero-downtime deployments:
- Build new version in a separate directory
- Test the new build
- Switch web server root to new directory
- Reload web server
- Keep old version as backup
name: Deploy Frontend
on:
push:
branches: [main]
jobs:
build-and-deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: '18'
- run: cd frontend && npm install
- run: cd frontend && npm run build
env:
VITE_BACKEND_URL: ${{ secrets.BACKEND_URL }}
- name: Deploy to server
uses: appleboy/scp-action@master
with:
host: ${{ secrets.HOST }}
username: ${{ secrets.USERNAME }}
key: ${{ secrets.SSH_KEY }}
source: "frontend/dist/*"
target: "/var/www/math2visual-frontend"- Always use HTTPS in production
- Set proper environment variables before building
- Test the production build locally before deploying
- Use a reverse proxy (Nginx/Apache) for better performance
- Enable compression (gzip/brotli)
- Configure caching for static assets
- Monitor logs for errors and performance
- Keep dependencies updated regularly
- Use CI/CD for automated deployments
- Backup your deployment configuration