Compare commits
1 Commits
main
...
whip/1339-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1d4abeac3e |
55
.github/workflows/pages.yml
vendored
Normal file
55
.github/workflows/pages.yml
vendored
Normal file
@@ -0,0 +1,55 @@
|
||||
name: Deploy Nexus Preview to Pages
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [main]
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
pages: write
|
||||
id-token: write
|
||||
|
||||
concurrency:
|
||||
group: "pages"
|
||||
cancel-in-progress: false
|
||||
|
||||
jobs:
|
||||
deploy:
|
||||
environment:
|
||||
name: github-pages
|
||||
url: ${{ steps.deployment.outputs.page_url }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Pages
|
||||
uses: actions/configure-pages@v5
|
||||
|
||||
- name: Prepare static assets
|
||||
run: |
|
||||
mkdir -p _site
|
||||
cp index.html _site/
|
||||
cp app.js _site/
|
||||
cp style.css _site/
|
||||
cp boot.js _site/
|
||||
cp gofai_worker.js _site/
|
||||
cp service-worker.js _site/
|
||||
cp manifest.json _site/
|
||||
cp robots.txt _site/
|
||||
cp help.html _site/
|
||||
cp portals.json _site/
|
||||
cp vision.json _site/
|
||||
cp -r nexus/ _site/nexus/
|
||||
cp -r icons/ _site/icons/ 2>/dev/null || true
|
||||
cp -r assets/ _site/assets/ 2>/dev/null || true
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-pages-artifact@v3
|
||||
with:
|
||||
path: '_site'
|
||||
|
||||
- name: Deploy to GitHub Pages
|
||||
id: deployment
|
||||
uses: actions/deploy-pages@v4
|
||||
27
Dockerfile.preview
Normal file
27
Dockerfile.preview
Normal file
@@ -0,0 +1,27 @@
|
||||
FROM nginx:alpine
|
||||
|
||||
# Remove default nginx config
|
||||
RUN rm /etc/nginx/conf.d/default.conf
|
||||
|
||||
# Copy our nginx config
|
||||
COPY preview/nginx.conf /etc/nginx/conf.d/default.conf
|
||||
|
||||
# Copy static frontend assets
|
||||
COPY index.html /usr/share/nginx/html/
|
||||
COPY app.js /usr/share/nginx/html/
|
||||
COPY style.css /usr/share/nginx/html/
|
||||
COPY boot.js /usr/share/nginx/html/
|
||||
COPY gofai_worker.js /usr/share/nginx/html/
|
||||
COPY service-worker.js /usr/share/nginx/html/
|
||||
COPY manifest.json /usr/share/nginx/html/
|
||||
COPY robots.txt /usr/share/nginx/html/
|
||||
COPY help.html /usr/share/nginx/html/
|
||||
COPY portals.json /usr/share/nginx/html/
|
||||
COPY vision.json /usr/share/nginx/html/
|
||||
|
||||
# Copy directories
|
||||
COPY nexus/ /usr/share/nginx/html/nexus/
|
||||
COPY icons/ /usr/share/nginx/html/icons/
|
||||
COPY assets/ /usr/share/nginx/html/assets/
|
||||
|
||||
EXPOSE 8080
|
||||
99
PREVIEW.md
Normal file
99
PREVIEW.md
Normal file
@@ -0,0 +1,99 @@
|
||||
# Nexus Preview Deployment
|
||||
|
||||
Deploy The Nexus to a proper URL so Three.js ES modules load correctly.
|
||||
|
||||
## Problem
|
||||
|
||||
When served via `file://` or raw Forge URL, ES module imports fail because:
|
||||
- Browsers block module imports from `file://` (CORS security)
|
||||
- Raw URLs don't set correct `Content-Type: application/javascript` headers
|
||||
- WebSocket connections can't be established without a proper HTTP server
|
||||
|
||||
## Quick Start
|
||||
|
||||
### Local Preview (Python, no Docker)
|
||||
|
||||
```bash
|
||||
./preview.sh # http://localhost:8080
|
||||
./preview.sh 3000 # http://localhost:3000
|
||||
```
|
||||
|
||||
### Docker Preview (nginx + WebSocket proxy)
|
||||
|
||||
```bash
|
||||
docker compose up -d nexus-preview
|
||||
# http://localhost:8080
|
||||
```
|
||||
|
||||
### Full Stack (preview + backend)
|
||||
|
||||
```bash
|
||||
docker compose up -d nexus-preview nexus-backend
|
||||
# http://localhost:8080 — static frontend
|
||||
# WebSocket proxied to nexus-backend:8765
|
||||
```
|
||||
|
||||
## Deployment Options
|
||||
|
||||
### 1. VPS (nginx)
|
||||
|
||||
Copy the static files to your VPS and serve with nginx:
|
||||
|
||||
```bash
|
||||
# On the VPS
|
||||
sudo mkdir -p /var/www/nexus
|
||||
sudo cp index.html app.js style.css boot.js gofai_worker.js /var/www/nexus/
|
||||
sudo cp -r nexus/ icons/ assets/ /var/www/nexus/
|
||||
|
||||
# Use preview/nginx.conf as your nginx site config
|
||||
sudo cp preview/nginx.conf /etc/nginx/sites-available/nexus
|
||||
sudo ln -s /etc/nginx/sites-available/nexus /etc/nginx/sites-enabled/
|
||||
sudo nginx -s reload
|
||||
```
|
||||
|
||||
### 2. GitHub Pages
|
||||
|
||||
Push to `main` and the `.github/workflows/pages.yml` workflow automatically
|
||||
deploys to GitHub Pages. Enable Pages in repo settings:
|
||||
- Source: GitHub Actions
|
||||
- Branch: main
|
||||
|
||||
### 3. Gitea Pages
|
||||
|
||||
If Gitea Pages is enabled on your Forge, the same static files work.
|
||||
Configure the pages source to serve from the repo root.
|
||||
|
||||
## Architecture
|
||||
|
||||
```
|
||||
User Browser
|
||||
│
|
||||
├── GET / ──────────────► nginx :8080 ──► index.html
|
||||
├── GET /app.js ────────► nginx :8080 ──► app.js (application/javascript)
|
||||
├── GET /style.css ─────► nginx :8080 ──► style.css (text/css)
|
||||
├── GET /nexus/... ─────► nginx :8080 ──► nexus/components/*.js
|
||||
│
|
||||
└── WS /api/world/ws ──► nginx :8080 ──► proxy ──► nexus-backend :8765
|
||||
```
|
||||
|
||||
## Files
|
||||
|
||||
| File | Purpose |
|
||||
|------|---------|
|
||||
| `Dockerfile.preview` | nginx-based preview container |
|
||||
| `preview/nginx.conf` | nginx config with correct MIME types + WS proxy |
|
||||
| `preview.sh` | Python one-liner preview server |
|
||||
| `docker-compose.yml` | Updated with nexus-preview + nexus-backend services |
|
||||
| `.github/workflows/pages.yml` | GitHub Pages deployment workflow |
|
||||
|
||||
## Verification
|
||||
|
||||
```bash
|
||||
# Check MIME types
|
||||
curl -sI http://localhost:8080/app.js | grep content-type
|
||||
# Should show: content-type: application/javascript
|
||||
|
||||
# Check WebSocket proxy
|
||||
curl -s -o /dev/null -w "%{http_code}" http://localhost:8080/api/world/ws
|
||||
# Should show: 101 (upgrade) or connection refused if backend not running
|
||||
```
|
||||
23
deploy.sh
23
deploy.sh
@@ -1,7 +1,9 @@
|
||||
#!/usr/bin/env bash
|
||||
# deploy.sh — spin up (or update) the Nexus staging environment
|
||||
# Usage: ./deploy.sh — rebuild and restart nexus-main (port 4200)
|
||||
# ./deploy.sh staging — rebuild and restart nexus-staging (port 4201)
|
||||
# deploy.sh — spin up (or update) the Nexus environment
|
||||
# Usage: ./deploy.sh — rebuild and restart nexus-main (port 8765)
|
||||
# ./deploy.sh staging — rebuild and restart nexus-staging (port 8766)
|
||||
# ./deploy.sh preview — deploy static preview (port 8080)
|
||||
# ./deploy.sh full — deploy preview + backend
|
||||
set -euo pipefail
|
||||
|
||||
SERVICE="${1:-nexus-main}"
|
||||
@@ -9,6 +11,21 @@ SERVICE="${1:-nexus-main}"
|
||||
case "$SERVICE" in
|
||||
staging) SERVICE="nexus-staging" ;;
|
||||
main) SERVICE="nexus-main" ;;
|
||||
preview)
|
||||
echo "==> Deploying Nexus preview on http://localhost:8080"
|
||||
docker compose build nexus-preview
|
||||
docker compose up -d --force-recreate nexus-preview
|
||||
echo "==> Preview available at http://localhost:8080"
|
||||
exit 0
|
||||
;;
|
||||
full)
|
||||
echo "==> Deploying full Nexus stack (preview + backend)"
|
||||
docker compose build nexus-preview nexus-backend
|
||||
docker compose up -d --force-recreate nexus-preview nexus-backend
|
||||
echo "==> Preview: http://localhost:8080"
|
||||
echo "==> Backend WebSocket: nexus-backend:8765"
|
||||
exit 0
|
||||
;;
|
||||
esac
|
||||
|
||||
echo "==> Deploying $SERVICE …"
|
||||
|
||||
@@ -7,9 +7,28 @@ services:
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "8765:8765"
|
||||
|
||||
nexus-staging:
|
||||
build: .
|
||||
container_name: nexus-staging
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "8766:8765"
|
||||
- "8766:8765"
|
||||
|
||||
nexus-backend:
|
||||
build: .
|
||||
container_name: nexus-backend
|
||||
restart: unless-stopped
|
||||
expose:
|
||||
- "8765"
|
||||
|
||||
nexus-preview:
|
||||
build:
|
||||
context: .
|
||||
dockerfile: Dockerfile.preview
|
||||
container_name: nexus-preview
|
||||
restart: unless-stopped
|
||||
ports:
|
||||
- "8080:8080"
|
||||
depends_on:
|
||||
- nexus-backend
|
||||
|
||||
58
preview.sh
Executable file
58
preview.sh
Executable file
@@ -0,0 +1,58 @@
|
||||
#!/usr/bin/env bash
|
||||
# preview.sh — One-command preview server for The Nexus
|
||||
# Serves static files with correct MIME types so ES modules work.
|
||||
#
|
||||
# Usage:
|
||||
# ./preview.sh — Start preview on http://localhost:8080
|
||||
# ./preview.sh 3000 — Start preview on http://localhost:3000
|
||||
# ./preview.sh docker — Use Docker/nginx instead
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
PORT="${1:-8080}"
|
||||
|
||||
if [ "$PORT" = "docker" ]; then
|
||||
echo "==> Starting Nexus preview via Docker/nginx..."
|
||||
docker compose up -d nexus-preview
|
||||
echo "==> Preview available at http://localhost:8080"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Check for python3
|
||||
if ! command -v python3 &> /dev/null; then
|
||||
echo "Error: python3 not found. Install Python 3.7+ or use './preview.sh docker'"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "==> Starting Nexus preview server on http://localhost:$PORT"
|
||||
echo "==> Press Ctrl+C to stop"
|
||||
echo ""
|
||||
|
||||
python3 -c "
|
||||
import http.server
|
||||
import socketserver
|
||||
import os
|
||||
|
||||
PORT = $PORT
|
||||
|
||||
class Handler(http.server.SimpleHTTPRequestHandler):
|
||||
def end_headers(self):
|
||||
# Ensure correct MIME types for ES modules
|
||||
self.send_header('Access-Control-Allow-Origin', '*')
|
||||
super().end_headers()
|
||||
|
||||
def guess_type(self, path):
|
||||
if path.endswith('.js'):
|
||||
return 'application/javascript'
|
||||
if path.endswith('.mjs'):
|
||||
return 'application/javascript'
|
||||
if path.endswith('.css'):
|
||||
return 'text/css'
|
||||
if path.endswith('.json'):
|
||||
return 'application/json'
|
||||
return super().guess_type(path)
|
||||
|
||||
with socketserver.TCPServer(('', PORT), Handler) as httpd:
|
||||
print(f'Serving at http://localhost:{PORT}')
|
||||
httpd.serve_forever()
|
||||
"
|
||||
57
preview/nginx.conf
Normal file
57
preview/nginx.conf
Normal file
@@ -0,0 +1,57 @@
|
||||
server {
|
||||
listen 8080;
|
||||
server_name _;
|
||||
|
||||
root /usr/share/nginx/html;
|
||||
index index.html;
|
||||
|
||||
# Serve static assets with correct MIME types
|
||||
location / {
|
||||
try_files $uri $uri/ /index.html;
|
||||
add_header X-Frame-Options "SAMEORIGIN" always;
|
||||
add_header X-Content-Type-Options "nosniff" always;
|
||||
}
|
||||
|
||||
# ES modules need correct Content-Type
|
||||
location ~* \.js$ {
|
||||
types { application/javascript js; }
|
||||
add_header Cache-Control "public, max-age=3600";
|
||||
}
|
||||
|
||||
location ~* \.css$ {
|
||||
types { text/css css; }
|
||||
add_header Cache-Control "public, max-age=3600";
|
||||
}
|
||||
|
||||
location ~* \.json$ {
|
||||
types { application/json json; }
|
||||
add_header Cache-Control "no-cache";
|
||||
}
|
||||
|
||||
# Proxy WebSocket to backend (app.js connects to /api/world/ws)
|
||||
location /api/world/ws {
|
||||
proxy_pass http://nexus-backend:8765;
|
||||
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_read_timeout 86400;
|
||||
}
|
||||
|
||||
# Direct WebSocket proxy (for server.py direct connections)
|
||||
location /ws {
|
||||
proxy_pass http://nexus-backend:8765;
|
||||
proxy_http_version 1.1;
|
||||
proxy_set_header Upgrade $http_upgrade;
|
||||
proxy_set_header Connection "upgrade";
|
||||
proxy_set_header Host $host;
|
||||
proxy_read_timeout 86400;
|
||||
}
|
||||
|
||||
# Health check
|
||||
location /health {
|
||||
return 200 '{"status":"ok","service":"nexus-preview"}';
|
||||
add_header Content-Type application/json;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user