This is a completely optional web interface for the EphemeralMail Backend API.
You don't need this frontend to use EphemeralMail! The backend API works perfectly with:
Required:
The backend MUST be running before you can use this frontend!
This guide helps you avoid the common pitfalls we encountered during deployment.
Step 1: Deploy the Backend First
# On your VPS - Deploy the backend API first
git clone https://github.com/tacssuki/EphemeralMail.git
cd EphemeralMail
sudo ./deploy.sh yourdomain.com
Step 2: Deploy the Frontend
# On your VPS - Deploy this frontend
git clone https://github.com/tacssuki/EphemeralMail-svelte.git
cd EphemeralMail-svelte
# Configure for production
cp .env.example .env
nano .env
Step 3: Configure Environment
# .env file
VITE_API_URL=https://yourdomain.com
โ ๏ธ CRITICAL: Make sure VITE_API_URL
does NOT end with /api
- just your domain!
Step 4: Build and Deploy
# Install dependencies
npm install
# Build for production
npm run build
# Create deployment directory
sudo mkdir -p /opt/ephemeral-mail-frontend
sudo cp -r dist/* /opt/ephemeral-mail-frontend/
sudo chown -R www-data:www-data /opt/ephemeral-mail-frontend
# Install PM2 for serving
sudo npm install -g pm2 serve
# Start serving the frontend
pm2 serve /opt/ephemeral-mail-frontend 3000 --name "ephemeral-mail-frontend" --spa
pm2 startup
pm2 save
Step 5: Configure Nginx
Add to your Nginx configuration:
server {
listen 443 ssl;
server_name yourdomain.com;
# SSL configuration (already set up by backend deploy.sh)
ssl_certificate /etc/letsencrypt/live/yourdomain.com/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/yourdomain.com/privkey.pem;
# API routes (backend)
location /api/ {
proxy_pass http://localhost:4444/;
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;
}
# Frontend (serves from root)
location / {
proxy_pass http://localhost:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}
}
Step 6: Test and Verify
# Reload Nginx
sudo nginx -t && sudo systemctl reload nginx
# Test the frontend
curl -I https://yourdomain.com
# Should return 200 OK
# Test API through frontend
curl -I https://yourdomain.com/api/health
# Should return 200 OK
# Check PM2 status
pm2 status
Step 1: Start Backend
# In terminal 1 - Start the backend
cd /path/to/EphemeralMail
npm run dev
# Backend runs on http://localhost:4444
Step 2: Start Frontend
# In terminal 2 - Start the frontend
cd /path/to/EphemeralMail-svelte
npm install
# Configure for local development (optional)
cp .env.example .env
# Edit .env if your backend runs on different port
# Start development server
npm run dev
# Frontend runs on http://localhost:4173
Step 3: Visit and Test
Create a .env
file:
# API Configuration
VITE_API_URL=https://yourdomain.com
# Development alternatives:
# VITE_API_URL=http://localhost:4444
# VITE_API_URL=https://api.yourdomain.com
Important Notes:
VITE_API_URL=https://yourdomain.com
VITE_API_URL=https://yourdomain.com/api
VITE_API_URL=https://yourdomain.com/api/
The frontend automatically appends /api
to the base URL.
Ensure your backend's .env
includes your frontend domain:
# In your backend's .env file
ALLOWED_ORIGINS=https://yourdomain.com,http://localhost:4173,http://localhost:3000
๐๏ธ Left Panel: Email Addresses (320px)
๐ฅ Middle Panel: Email Inbox (320px)
๐ Right Panel: Email Viewer (Remaining space)
# Test frontend loading
curl -I https://yourdomain.com
# Should return: 200 OK
# Test that it serves the app
curl https://yourdomain.com | grep "EphemeralMail"
# Should find the app title
# Test API through the same domain
curl https://yourdomain.com/api/health
# Should return: {"status": "healthy", ...}
# Test CORS by checking response headers
curl -I -H "Origin: https://yourdomain.com" https://yourdomain.com/api/health
# Should include: Access-Control-Allow-Origin: https://yourdomain.com
Manual test email:
# Replace with your generated email address
echo "Subject: Test Email
This is a test email from the deployment." | sendmail [email protected]
npm run dev # Start development server (port 4173)
npm run dev:3000 # Start development server (port 3000)
npm run dev:5173 # Start development server (port 5173)
npm run build # Build for production
npm run preview # Preview production build locally
# 1. Install dependencies
npm install
# 2. Configure environment
cp .env.example .env
# Edit .env with your settings
# 3. Build for production
npm run build
# Creates optimized files in dist/
# 4. Test production build locally
npm run preview
# Serves on http://localhost:4173
# 5. Deploy to server
# Copy dist/ contents to your web server
Use the included deployment script:
#!/bin/bash
DOMAIN=${1:-localhost}
FRONTEND_DIR="/opt/ephemeral-mail-frontend"
echo "๐จ Deploying EphemeralMail Frontend..."
echo "๐ Domain: $DOMAIN"
# Clone or update repository
if [ -d "$FRONTEND_DIR" ]; then
echo "๐ฆ Updating existing installation..."
cd $FRONTEND_DIR
git pull
else
echo "๐ฆ Fresh installation..."
git clone https://github.com/tacssuki/EphemeralMail-svelte.git $FRONTEND_DIR
cd $FRONTEND_DIR
fi
# Install dependencies
npm install
# Configure environment
echo "VITE_API_URL=https://$DOMAIN" > .env
# Build for production
npm run build
# Set up serving with PM2
sudo npm install -g pm2 serve
pm2 delete ephemeral-mail-frontend 2>/dev/null || true
pm2 serve dist 3000 --name "ephemeral-mail-frontend" --spa
pm2 startup
pm2 save
echo "โ
Frontend deployed successfully!"
echo "๐ Configure Nginx to proxy / to http://localhost:3000"
echo "๐ Frontend will be available at: https://$DOMAIN"
Usage:
chmod +x deploy.sh
sudo ./deploy.sh yourdomain.com
1. Frontend loads but can't connect to API
# Check API URL configuration
cat .env
# Should show: VITE_API_URL=https://yourdomain.com (no /api at the end)
# Check if API is accessible
curl https://yourdomain.com/api/health
# Check browser network tab for CORS errors
# Open browser dev tools โ Network tab โ look for red entries
2. CORS errors in browser console
# Check backend CORS configuration
ssh your-vps
cd /opt/ephemeral-mail
grep ALLOWED_ORIGINS .env
# Should include your frontend domain
# Update backend CORS
echo "ALLOWED_ORIGINS=https://yourdomain.com,http://localhost:4173" >> .env
pm2 restart ephemeral-mail
3. Frontend not loading (404 errors)
# Check if frontend service is running
pm2 status
# Check if PM2 is serving files correctly
curl -I http://localhost:3000
# Should return 200 OK
# Check Nginx configuration
sudo nginx -t
sudo systemctl reload nginx
4. Build errors
# Clear cache and reinstall
rm -rf node_modules package-lock.json
npm install
# Check Node.js version
node --version
# Should be 18+
# Build with verbose output
npm run build -- --verbose
5. API calls return wrong URLs
# Check built files for localhost references
grep -r "localhost" dist/
# Should not find any localhost references in production build
# Rebuild after fixing .env
rm -rf dist/
npm run build
Enable debug mode by adding to your .env
:
VITE_DEBUG=true
This will:
For Netlify:
# Build command
npm run build
# Publish directory
dist
# Environment variables (in Netlify dashboard)
VITE_API_URL=https://yourdomain.com
For Vercel:
# Build command
npm run build
# Output directory
dist
# Environment variables (in Vercel dashboard)
VITE_API_URL=https://yourdomain.com
<VirtualHost *:443>
ServerName yourdomain.com
DocumentRoot /opt/ephemeral-mail-frontend
# SSL configuration
SSLEngine on
SSLCertificateFile /etc/letsencrypt/live/yourdomain.com/fullchain.pem
SSLCertificateKeyFile /etc/letsencrypt/live/yourdomain.com/privkey.pem
# API proxy
ProxyPreserveHost On
ProxyPass /api/ http://localhost:4444/
ProxyPassReverse /api/ http://localhost:4444/
# Frontend (SPA routing)
<Directory "/opt/ephemeral-mail-frontend">
RewriteEngine On
RewriteBase /
RewriteRule ^index\.html$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.html [L]
</Directory>
</VirtualHost>
The frontend is built with security in mind:
<!-- Automatically included in production builds -->
<meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; connect-src 'self' https://yourdomain.com;">
VITE_*
variables are safe for frontend useVITE_*
variablesThe production build is already optimized:
Nginx Caching:
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ {
expires 1y;
add_header Cache-Control "public, immutable";
}
location /index.html {
add_header Cache-Control "no-cache";
}
Gzip Compression:
gzip on;
gzip_types text/plain text/css application/json application/javascript text/xml application/xml;
The frontend includes PWA features:
Users can install the app by:
# Prerequisites: Node.js 18+, running EphemeralMail backend
# Clone and install
git clone https://github.com/tacssuki/EphemeralMail-svelte.git
cd EphemeralMail-svelte
npm install
# Configure for local development
cp .env.example .env
# Edit .env if needed (default works with standard backend setup)
# Start development server
npm run dev
# Open http://localhost:4173
src/
โโโ lib/
โ โโโ api.js # API service for backend communication
โ โโโ EmailApp.svelte # Main 3-panel layout component
โ โโโ Dialog.svelte # Reusable dialog component
โ โโโ dialogStore.js # Dialog state management
โ โโโ storage.js # Local storage utilities
โโโ App.svelte # Root application component
โโโ main.js # Application entry point
โโโ app.css # Global styles and Tailwind imports
public/
โโโ eemail.png # App logo
โโโ manifest.json # PWA manifest
Configuration files:
โโโ vite.config.js # Vite build configuration
โโโ tailwind.config.js # Tailwind CSS configuration
โโโ postcss.config.js # PostCSS configuration
โโโ svelte.config.js # Svelte configuration
Add a new component:
<!-- src/lib/NewComponent.svelte -->
<script>
export let prop1;
export let prop2 = 'default';
// Component logic here
</script>
<div class="p-4 bg-white dark:bg-gray-800 rounded-lg">
<h2 class="text-lg font-semibold">{prop1}</h2>
<p class="text-gray-600 dark:text-gray-300">{prop2}</p>
</div>
Extend the API service:
// src/lib/api.js
export async function newApiFunction(param) {
try {
const response = await fetch(`${API_BASE_URL}/api/new-endpoint`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ param }),
});
return await response.json();
} catch (error) {
console.error('API Error:', error);
throw error;
}
}
git checkout -b feature/amazing-feature
git commit -m 'Add amazing feature'
git push origin feature/amazing-feature
MIT License - see LICENSE file for details.
https://yourdomain.com/api/health
# Check frontend build
npm run build 2>&1 | tee build.log
# Check API connectivity
curl -v https://yourdomain.com/api/health
# Check CORS headers
curl -I -H "Origin: https://yourdomain.com" https://yourdomain.com/api/health
# Check PM2 services
pm2 status
pm2 logs ephemeral-mail-frontend
# Check Nginx configuration
sudo nginx -t
โญ Star this repo if you find it useful!
๐ Backend API | Report Issues | Discussions