add simple Uberspace deployment option (simpler than Cloudflare)
Instead of the complex Cloudflare Worker setup with CORS proxy, you can now deploy both PWA and backend on Uberspace (~5€/month). Changes: - Add Express.js backend server (server/index.js) - Update ConfigService to support VITE_API_URL env variable - Make base path configurable via VITE_BASE_PATH - Add comprehensive Uberspace deployment guide - Add .env.production.example for configuration Deployment options: 1. Uberspace (recommended): Simple, all-in-one hosting 2. GitHub Pages + Cloudflare Workers: Free but complex setup Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
16
.env.production.example
Normal file
16
.env.production.example
Normal file
@@ -0,0 +1,16 @@
|
||||
# Backend URL (wo läuft dein Express Server?)
|
||||
# Uberspace / eigenes Backend
|
||||
VITE_API_URL=https://your-username.uber.space
|
||||
|
||||
# GitHub Pages (wenn du GitHub Pages nutzt, aber Uberspace Backend)
|
||||
# VITE_API_URL=https://your-username.uber.space
|
||||
|
||||
# Lokales Backend (für Development mit separatem Backend)
|
||||
# VITE_API_URL=http://localhost:3000
|
||||
|
||||
# Base Path (für URLs und Routing)
|
||||
# GitHub Pages deployment:
|
||||
# VITE_BASE_PATH=/whattoplay/
|
||||
|
||||
# Uberspace deployment (root):
|
||||
# VITE_BASE_PATH=/
|
||||
1
.gitignore
vendored
1
.gitignore
vendored
@@ -6,6 +6,7 @@ config.local.json
|
||||
*.local.json
|
||||
.env
|
||||
.env.*
|
||||
!.env.*.example
|
||||
*.secret.*
|
||||
*.key
|
||||
*.pem
|
||||
|
||||
150
UBERSPACE.md
Normal file
150
UBERSPACE.md
Normal file
@@ -0,0 +1,150 @@
|
||||
# Uberspace Deployment
|
||||
|
||||
Einfacheres Setup: Hoste sowohl PWA als auch Backend auf Uberspace.
|
||||
|
||||
## Voraussetzungen
|
||||
|
||||
- Uberspace Account (https://uberspace.de)
|
||||
- SSH Zugriff
|
||||
- Node.js (bereits auf Uberspace vorinstalliert)
|
||||
|
||||
## 1. Backend deployen
|
||||
|
||||
```bash
|
||||
# SSH auf deinen Uberspace
|
||||
ssh <username>@<servername>.uberspace.de
|
||||
|
||||
# Repository klonen
|
||||
cd ~
|
||||
git clone https://github.com/felixfoertsch/whattoplay.git
|
||||
cd whattoplay/server
|
||||
|
||||
# Dependencies installieren
|
||||
npm install
|
||||
|
||||
# Backend als Service einrichten
|
||||
uberspace web backend set / --http --port 3000
|
||||
```
|
||||
|
||||
### Backend als Daemon (automatischer Start)
|
||||
|
||||
Erstelle `~/etc/services.d/whattoplay-server.ini`:
|
||||
|
||||
```ini
|
||||
[program:whattoplay-server]
|
||||
directory=%(ENV_HOME)s/whattoplay/server
|
||||
command=node index.js
|
||||
autostart=yes
|
||||
autorestart=yes
|
||||
startsecs=60
|
||||
environment=PORT="3000"
|
||||
```
|
||||
|
||||
Starte den Service:
|
||||
```bash
|
||||
supervisorctl reread
|
||||
supervisorctl update
|
||||
supervisorctl start whattoplay-server
|
||||
supervisorctl status
|
||||
```
|
||||
|
||||
## 2. PWA deployen
|
||||
|
||||
```bash
|
||||
# Auf deinem lokalen Rechner
|
||||
# Build mit Uberspace URL als base
|
||||
npm run build
|
||||
|
||||
# Upload nach Uberspace
|
||||
rsync -avz dist/ <username>@<servername>.uberspace.de:~/html/
|
||||
|
||||
# Oder direkt auf Uberspace builden:
|
||||
cd ~/whattoplay
|
||||
npm install
|
||||
npm run build
|
||||
cp -r dist/* ~/html/
|
||||
```
|
||||
|
||||
## 3. Vite Config anpassen
|
||||
|
||||
Für Uberspace Deployment brauchst du keine spezielle `base`:
|
||||
|
||||
```typescript
|
||||
// vite.config.ts
|
||||
export default defineConfig({
|
||||
// base: "/whattoplay/", // <- entfernen für Uberspace
|
||||
plugins: [react()],
|
||||
// ...
|
||||
});
|
||||
```
|
||||
|
||||
## 4. App Config anpassen
|
||||
|
||||
Für Development kannst du die `.env` nutzen:
|
||||
|
||||
```bash
|
||||
# .env.development
|
||||
VITE_API_URL=http://localhost:3000
|
||||
|
||||
# .env.production
|
||||
VITE_API_URL=https://your-username.uber.space
|
||||
```
|
||||
|
||||
Dann in `ConfigService.ts`:
|
||||
|
||||
```typescript
|
||||
static getApiUrl(endpoint: string): string {
|
||||
const baseUrl = import.meta.env.VITE_API_URL || '';
|
||||
return `${baseUrl}${endpoint}`;
|
||||
}
|
||||
```
|
||||
|
||||
## 5. Domain einrichten (optional)
|
||||
|
||||
Falls du eine eigene Domain hast:
|
||||
|
||||
```bash
|
||||
uberspace web domain add your-domain.com
|
||||
```
|
||||
|
||||
Dann DNS Records setzen:
|
||||
```
|
||||
A @ <IP von uberspace>
|
||||
CNAME www <servername>.uberspace.de
|
||||
```
|
||||
|
||||
## Logs
|
||||
|
||||
```bash
|
||||
# Server logs
|
||||
supervisorctl tail whattoplay-server
|
||||
|
||||
# Webserver logs
|
||||
tail -f ~/logs/webserver/access_log
|
||||
```
|
||||
|
||||
## Updates deployen
|
||||
|
||||
```bash
|
||||
# Backend update
|
||||
cd ~/whattoplay
|
||||
git pull
|
||||
cd server
|
||||
npm install
|
||||
supervisorctl restart whattoplay-server
|
||||
|
||||
# PWA update
|
||||
cd ~/whattoplay
|
||||
npm install
|
||||
npm run build
|
||||
cp -r dist/* ~/html/
|
||||
```
|
||||
|
||||
## Kosten
|
||||
|
||||
Uberspace: ~5€/Monat (pay what you want, Minimum 1€)
|
||||
- Unbegrenzter Traffic
|
||||
- SSH Zugriff
|
||||
- Node.js, PHP, Python, Ruby Support
|
||||
- MySQL/PostgreSQL Datenbanken
|
||||
- Deutlich einfacher als Cloudflare Workers Setup
|
||||
58
server/index.js
Normal file
58
server/index.js
Normal file
@@ -0,0 +1,58 @@
|
||||
import express from 'express';
|
||||
import cors from 'cors';
|
||||
import fetch from 'node-fetch';
|
||||
|
||||
const app = express();
|
||||
const PORT = process.env.PORT || 3000;
|
||||
|
||||
// Enable CORS for your PWA
|
||||
app.use(cors({
|
||||
origin: process.env.ALLOWED_ORIGIN || '*'
|
||||
}));
|
||||
|
||||
app.use(express.json());
|
||||
|
||||
// Health check
|
||||
app.get('/health', (req, res) => {
|
||||
res.json({ status: 'ok' });
|
||||
});
|
||||
|
||||
// Proxy for Steam API - exactly like the worker
|
||||
app.all('/api/*', async (req, res) => {
|
||||
const path = req.url.replace('/api', '');
|
||||
const steamUrl = `https://store.steampowered.com${path}`;
|
||||
|
||||
console.log(`Proxying: ${req.method} ${steamUrl}`);
|
||||
|
||||
try {
|
||||
const response = await fetch(steamUrl, {
|
||||
method: req.method,
|
||||
headers: {
|
||||
'User-Agent': 'WhatToPlay/1.0',
|
||||
'Accept': 'application/json',
|
||||
...(req.body && { 'Content-Type': 'application/json' })
|
||||
},
|
||||
...(req.body && { body: JSON.stringify(req.body) })
|
||||
});
|
||||
|
||||
const contentType = response.headers.get('content-type');
|
||||
|
||||
if (contentType && contentType.includes('application/json')) {
|
||||
const data = await response.json();
|
||||
res.json(data);
|
||||
} else {
|
||||
const text = await response.text();
|
||||
res.send(text);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Proxy error:', error);
|
||||
res.status(500).json({
|
||||
error: 'Proxy error',
|
||||
message: error.message
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
app.listen(PORT, () => {
|
||||
console.log(`Server running on port ${PORT}`);
|
||||
});
|
||||
16
server/package.json
Normal file
16
server/package.json
Normal file
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"name": "whattoplay-server",
|
||||
"version": "1.0.0",
|
||||
"type": "module",
|
||||
"description": "Simple proxy server for WhatToPlay Steam API calls",
|
||||
"main": "index.js",
|
||||
"scripts": {
|
||||
"start": "node index.js",
|
||||
"dev": "node --watch index.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"express": "^4.18.2",
|
||||
"cors": "^2.8.5",
|
||||
"node-fetch": "^3.3.2"
|
||||
}
|
||||
}
|
||||
@@ -130,8 +130,10 @@ export class ConfigService {
|
||||
|
||||
/**
|
||||
* Get API URL for Steam refresh
|
||||
* Development: Use local Vite server
|
||||
* Production: Use Cloudflare Worker
|
||||
* Supports multiple deployment scenarios:
|
||||
* - Development: Vite dev server proxy
|
||||
* - Uberspace: Backend on same domain via VITE_API_URL
|
||||
* - Cloudflare Workers: User-configured Worker URL (fallback)
|
||||
*/
|
||||
static getApiUrl(endpoint: string, workerUrl?: string): string {
|
||||
// Development mode: Use Vite dev server middleware
|
||||
@@ -139,15 +141,22 @@ export class ConfigService {
|
||||
return endpoint;
|
||||
}
|
||||
|
||||
// Production mode: Use Cloudflare Worker
|
||||
if (!workerUrl) {
|
||||
throw new Error(
|
||||
"Worker URL not configured. Please set up your Cloudflare Worker in Settings.",
|
||||
);
|
||||
// Production: Check for backend URL from environment
|
||||
const backendUrl = import.meta.env.VITE_API_URL;
|
||||
if (backendUrl) {
|
||||
const baseUrl = backendUrl.replace(/\/$/, "");
|
||||
return `${baseUrl}${endpoint}`;
|
||||
}
|
||||
|
||||
// Ensure workerUrl doesn't have trailing slash
|
||||
const baseUrl = workerUrl.replace(/\/$/, "");
|
||||
return `${baseUrl}${endpoint}`;
|
||||
// Fallback: Cloudflare Worker (if configured)
|
||||
if (workerUrl) {
|
||||
const baseUrl = workerUrl.replace(/\/$/, "");
|
||||
return `${baseUrl}${endpoint}`;
|
||||
}
|
||||
|
||||
// No backend configured
|
||||
throw new Error(
|
||||
"Backend not configured. Please deploy the server or set up a Cloudflare Worker.",
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,7 +23,9 @@ const apiMiddlewarePlugin = {
|
||||
};
|
||||
|
||||
export default defineConfig({
|
||||
base: "/whattoplay/",
|
||||
// GitHub Pages: /whattoplay/
|
||||
// Uberspace: /
|
||||
base: process.env.VITE_BASE_PATH || "/whattoplay/",
|
||||
plugins: [react(), apiMiddlewarePlugin],
|
||||
server: {
|
||||
port: 5173,
|
||||
|
||||
Reference in New Issue
Block a user