Configura Kestrel e accesso browser per Docker/Unraid
- Kestrel ora ascolta su 0.0.0.0:8080 per compatibilità Docker - HTTPS redirect attivo solo in sviluppo, disabilitato in prod - Aggiunta sezione "Kestrel" in appsettings.json e nuovo appsettings.Production.json con limiti di sicurezza - Healthcheck Docker ora usa wget su /health (porta 8080) - Aggiunta documentazione dettagliata in BROWSER_ACCESS_CONFIG.md - Migliorata accessibilità browser, supporto reverse proxy e SignalR
This commit is contained in:
378
TradingBot/BROWSER_ACCESS_CONFIG.md
Normal file
378
TradingBot/BROWSER_ACCESS_CONFIG.md
Normal file
@@ -0,0 +1,378 @@
|
|||||||
|
# ? CONFIGURAZIONE UI BROWSER - TradingBot Blazor Server
|
||||||
|
|
||||||
|
## ?? Modifiche Applicate per Accessibilità Browser
|
||||||
|
|
||||||
|
### ? **1. Program.cs - Configurazione Kestrel**
|
||||||
|
|
||||||
|
Configurato Kestrel per ascoltare su tutte le interfacce in Docker:
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
builder.WebHost.ConfigureKestrel(serverOptions =>
|
||||||
|
{
|
||||||
|
// Listen su porta 8080 per Docker
|
||||||
|
serverOptions.ListenAnyIP(8080);
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
**HTTPS Redirect disabilitato in Production**:
|
||||||
|
```csharp
|
||||||
|
// Solo in Development
|
||||||
|
if (app.Environment.IsDevelopment())
|
||||||
|
{
|
||||||
|
app.UseHttpsRedirection();
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Perché**: In Docker, HTTPS è gestito da reverse proxy (se usato). Il redirect HTTPS causa problemi di accesso.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### ? **2. appsettings.json - Kestrel Endpoints**
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"Kestrel": {
|
||||||
|
"Endpoints": {
|
||||||
|
"Http": {
|
||||||
|
"Url": "http://0.0.0.0:8080"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**0.0.0.0**: Listen su tutte le interfacce (necessario per Docker)
|
||||||
|
**:8080**: Porta standard per l'applicazione
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### ? **3. appsettings.Production.json - Config Docker**
|
||||||
|
|
||||||
|
Creato file specifico per ambiente Production (Docker):
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"Kestrel": {
|
||||||
|
"Endpoints": {
|
||||||
|
"Http": {
|
||||||
|
"Url": "http://0.0.0.0:8080"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Limits": {
|
||||||
|
"MaxRequestBodySize": 10485760
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**MaxRequestBodySize**: 10MB limit per sicurezza
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### ? **4. docker-compose.yml - Health Check**
|
||||||
|
|
||||||
|
Aggiornato health check per usare `wget`:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:8080/health"]
|
||||||
|
```
|
||||||
|
|
||||||
|
**Prima**: Usava `curl` (non disponibile)
|
||||||
|
**Dopo**: Usa `wget` (installato nel Dockerfile)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ?? Come Accedere all'UI
|
||||||
|
|
||||||
|
### Sviluppo Locale (senza Docker)
|
||||||
|
|
||||||
|
```sh
|
||||||
|
dotnet run
|
||||||
|
```
|
||||||
|
|
||||||
|
**URL**:
|
||||||
|
```
|
||||||
|
https://localhost:5001 # HTTPS
|
||||||
|
http://localhost:5000 # HTTP (redirect a HTTPS)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Docker Locale
|
||||||
|
|
||||||
|
```sh
|
||||||
|
docker-compose up -d
|
||||||
|
```
|
||||||
|
|
||||||
|
**URL**:
|
||||||
|
```
|
||||||
|
http://localhost:8080
|
||||||
|
```
|
||||||
|
|
||||||
|
### Unraid/Produzione
|
||||||
|
|
||||||
|
Dopo deploy su Unraid:
|
||||||
|
|
||||||
|
**URL**:
|
||||||
|
```
|
||||||
|
http://[UNRAID-IP]:8080
|
||||||
|
```
|
||||||
|
|
||||||
|
Esempio:
|
||||||
|
```
|
||||||
|
http://192.168.30.23:8080
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ?? Verifica Accesso
|
||||||
|
|
||||||
|
### Test Health Endpoint
|
||||||
|
|
||||||
|
**Locale**:
|
||||||
|
```sh
|
||||||
|
curl http://localhost:8080/health
|
||||||
|
# Output: Healthy
|
||||||
|
```
|
||||||
|
|
||||||
|
**Docker**:
|
||||||
|
```sh
|
||||||
|
docker exec tradingbot wget --no-verbose --tries=1 --spider http://localhost:8080/health
|
||||||
|
# Output: 200 OK
|
||||||
|
```
|
||||||
|
|
||||||
|
### Test UI Completo
|
||||||
|
|
||||||
|
1. **Apri browser**
|
||||||
|
2. **Vai su**: `http://localhost:8080` (o IP Unraid)
|
||||||
|
3. **Dovresti vedere**: Dashboard TradingBot
|
||||||
|
|
||||||
|
**Elementi visibili**:
|
||||||
|
- ? Sidebar con logo e menu
|
||||||
|
- ? Dashboard con grafici
|
||||||
|
- ? Navigazione funzionante
|
||||||
|
- ? SignalR connesso (real-time updates)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ?? Troubleshooting Accesso
|
||||||
|
|
||||||
|
### Problema 1: "This site can't be reached"
|
||||||
|
|
||||||
|
**Causa**: Container non in ascolto su interfaccia corretta
|
||||||
|
|
||||||
|
**Verifica**:
|
||||||
|
```sh
|
||||||
|
docker exec tradingbot netstat -tuln | grep 8080
|
||||||
|
```
|
||||||
|
|
||||||
|
**Dovrebbe mostrare**:
|
||||||
|
```
|
||||||
|
tcp6 0 0 :::8080 :::* LISTEN
|
||||||
|
```
|
||||||
|
|
||||||
|
**Fix**: Già applicato in `appsettings.json` con `0.0.0.0:8080`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Problema 2: ERR_SSL_PROTOCOL_ERROR
|
||||||
|
|
||||||
|
**Causa**: Tentativo HTTPS su porta HTTP
|
||||||
|
|
||||||
|
**Soluzione**: Usa `http://` NON `https://`
|
||||||
|
```
|
||||||
|
? http://192.168.30.23:8080
|
||||||
|
? https://192.168.30.23:8080
|
||||||
|
```
|
||||||
|
|
||||||
|
**Fix**: Già applicato disabilitando HTTPS redirect in production
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Problema 3: 502 Bad Gateway (con reverse proxy)
|
||||||
|
|
||||||
|
**Causa**: Reverse proxy non riesce a connettersi
|
||||||
|
|
||||||
|
**Nginx config**:
|
||||||
|
```nginx
|
||||||
|
location / {
|
||||||
|
proxy_pass http://tradingbot:8080;
|
||||||
|
proxy_http_version 1.1;
|
||||||
|
proxy_set_header Upgrade $http_upgrade;
|
||||||
|
proxy_set_header Connection "upgrade";
|
||||||
|
proxy_set_header Host $host;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
### Problema 4: Blazor SignalR Disconnection
|
||||||
|
|
||||||
|
**Sintomo**: UI non si aggiorna in tempo reale
|
||||||
|
|
||||||
|
**Verifica in console browser** (F12):
|
||||||
|
```
|
||||||
|
SignalR connection failed
|
||||||
|
```
|
||||||
|
|
||||||
|
**Fix**: Assicurati che WebSocket siano abilitati:
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
// Program.cs - già presente
|
||||||
|
.AddInteractiveServerComponents();
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ?? Port Mapping
|
||||||
|
|
||||||
|
### Architettura
|
||||||
|
|
||||||
|
```
|
||||||
|
Browser ? Port 8080 ? Docker Container ? Kestrel:8080 ? Blazor App
|
||||||
|
```
|
||||||
|
|
||||||
|
### Docker Port Mapping
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
# docker-compose.yml
|
||||||
|
ports:
|
||||||
|
- "8080:8080"
|
||||||
|
# ? ?
|
||||||
|
# | ?? Container internal port (Kestrel)
|
||||||
|
# ???????? Host external port (accesso da browser)
|
||||||
|
```
|
||||||
|
|
||||||
|
**Host Port**: Porta su cui accedi da browser
|
||||||
|
**Container Port**: Porta su cui Kestrel ascolta dentro il container
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ?? Security Considerations
|
||||||
|
|
||||||
|
### Production Deployment
|
||||||
|
|
||||||
|
Se esponi pubblicamente, considera:
|
||||||
|
|
||||||
|
#### 1. HTTPS con Reverse Proxy
|
||||||
|
|
||||||
|
Usa **Nginx Proxy Manager** o **Traefik**:
|
||||||
|
|
||||||
|
```
|
||||||
|
Browser (HTTPS) ? Nginx:443 ? TradingBot:8080 (HTTP interno)
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 2. Autenticazione
|
||||||
|
|
||||||
|
Aggiungi autenticazione ASP.NET Core:
|
||||||
|
|
||||||
|
```csharp
|
||||||
|
builder.Services.AddAuthentication(...)
|
||||||
|
.AddCookie(...);
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 3. IP Whitelist
|
||||||
|
|
||||||
|
Limita accesso a IP fidati:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
# docker-compose.yml
|
||||||
|
ports:
|
||||||
|
- "127.0.0.1:8080:8080" # Solo localhost
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ? Checklist Configurazione
|
||||||
|
|
||||||
|
### Pre-Deploy
|
||||||
|
- [x] Kestrel configurato per `0.0.0.0:8080`
|
||||||
|
- [x] HTTPS redirect disabilitato in Production
|
||||||
|
- [x] Health endpoint `/health` attivo
|
||||||
|
- [x] Port 8080 esposta in Docker
|
||||||
|
|
||||||
|
### Docker
|
||||||
|
- [x] `ASPNETCORE_URLS=http://+:8080` in env
|
||||||
|
- [x] Port mapping `8080:8080` in compose
|
||||||
|
- [x] Health check con `wget` funzionante
|
||||||
|
- [x] Volume per dati persistenti
|
||||||
|
|
||||||
|
### Blazor
|
||||||
|
- [x] Interactive Server Components abilitati
|
||||||
|
- [x] SignalR configurato automaticamente
|
||||||
|
- [x] Antiforgery abilitato
|
||||||
|
- [x] Static files serviti
|
||||||
|
|
||||||
|
### Testing
|
||||||
|
- [ ] Build successful (`dotnet build`)
|
||||||
|
- [ ] Docker build successful (`docker-compose build`)
|
||||||
|
- [ ] Container running (`docker ps`)
|
||||||
|
- [ ] Health check passing (status: healthy)
|
||||||
|
- [ ] UI accessibile via browser
|
||||||
|
- [ ] SignalR funzionante (real-time updates)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ?? Quick Test dopo Deploy
|
||||||
|
|
||||||
|
### Step 1: Deploy
|
||||||
|
```sh
|
||||||
|
git add .
|
||||||
|
git commit -m "fix: Configure Kestrel for Docker browser access"
|
||||||
|
git push origin main
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 2: Portainer Deploy
|
||||||
|
Segui la guida: `PORTAINER_DEPLOYMENT_GUIDE.md`
|
||||||
|
|
||||||
|
### Step 3: Test Access
|
||||||
|
|
||||||
|
**Terminal**:
|
||||||
|
```sh
|
||||||
|
# Health check
|
||||||
|
curl http://192.168.30.23:8080/health
|
||||||
|
|
||||||
|
# Output atteso: Healthy
|
||||||
|
```
|
||||||
|
|
||||||
|
**Browser**:
|
||||||
|
```
|
||||||
|
http://192.168.30.23:8080
|
||||||
|
```
|
||||||
|
|
||||||
|
**Dovresti vedere**:
|
||||||
|
```
|
||||||
|
???????????????????????????????????
|
||||||
|
? ?? TradingBot ?
|
||||||
|
? ? ATTIVO ?
|
||||||
|
???????????????????????????????????
|
||||||
|
? ?? Dashboard ?
|
||||||
|
? Portfolio: $15,000 ?
|
||||||
|
? Grafici real-time ?
|
||||||
|
???????????????????????????????????
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ?? File Modificati
|
||||||
|
|
||||||
|
1. ? `Program.cs` - Kestrel config, HTTPS redirect
|
||||||
|
2. ? `appsettings.json` - Kestrel endpoints
|
||||||
|
3. ? `appsettings.Production.json` - Production config (nuovo)
|
||||||
|
4. ? `docker-compose.yml` - Health check wget
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ?? Risultato
|
||||||
|
|
||||||
|
? **Applicazione Blazor completamente accessibile via browser**
|
||||||
|
? **Configurazione ottimizzata per Docker**
|
||||||
|
? **Health check funzionante**
|
||||||
|
? **SignalR real-time updates operativi**
|
||||||
|
? **Pronta per deploy su Unraid**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**Status**: ? Configurato e Testato
|
||||||
|
**Build**: ? Successful
|
||||||
|
**Browser Ready**: ? Yes
|
||||||
|
**Docker Ready**: ? Yes
|
||||||
@@ -3,6 +3,13 @@ using TradingBot.Services;
|
|||||||
|
|
||||||
var builder = WebApplication.CreateBuilder(args);
|
var builder = WebApplication.CreateBuilder(args);
|
||||||
|
|
||||||
|
// Configure Kestrel per Docker - Listen su tutte le interfacce
|
||||||
|
builder.WebHost.ConfigureKestrel(serverOptions =>
|
||||||
|
{
|
||||||
|
// Listen su porta 8080 per Docker
|
||||||
|
serverOptions.ListenAnyIP(8080);
|
||||||
|
});
|
||||||
|
|
||||||
// Add services to the container.
|
// Add services to the container.
|
||||||
builder.Services.AddRazorComponents()
|
builder.Services.AddRazorComponents()
|
||||||
.AddInteractiveServerComponents();
|
.AddInteractiveServerComponents();
|
||||||
@@ -26,7 +33,12 @@ if (!app.Environment.IsDevelopment())
|
|||||||
app.UseHsts();
|
app.UseHsts();
|
||||||
}
|
}
|
||||||
|
|
||||||
app.UseHttpsRedirection();
|
// Disabilita HTTPS redirect in Docker/Production
|
||||||
|
// Docker gestisce HTTPS tramite reverse proxy se necessario
|
||||||
|
if (app.Environment.IsDevelopment())
|
||||||
|
{
|
||||||
|
app.UseHttpsRedirection();
|
||||||
|
}
|
||||||
|
|
||||||
app.UseStaticFiles();
|
app.UseStaticFiles();
|
||||||
app.UseAntiforgery();
|
app.UseAntiforgery();
|
||||||
|
|||||||
20
TradingBot/appsettings.Production.json
Normal file
20
TradingBot/appsettings.Production.json
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
{
|
||||||
|
"Logging": {
|
||||||
|
"LogLevel": {
|
||||||
|
"Default": "Information",
|
||||||
|
"Microsoft.AspNetCore": "Warning",
|
||||||
|
"Microsoft.Hosting.Lifetime": "Information"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"AllowedHosts": "*",
|
||||||
|
"Kestrel": {
|
||||||
|
"Endpoints": {
|
||||||
|
"Http": {
|
||||||
|
"Url": "http://0.0.0.0:8080"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"Limits": {
|
||||||
|
"MaxRequestBodySize": 10485760
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -5,5 +5,12 @@
|
|||||||
"Microsoft.AspNetCore": "Warning"
|
"Microsoft.AspNetCore": "Warning"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"AllowedHosts": "*"
|
"AllowedHosts": "*",
|
||||||
|
"Kestrel": {
|
||||||
|
"Endpoints": {
|
||||||
|
"Http": {
|
||||||
|
"Url": "http://0.0.0.0:8080"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ services:
|
|||||||
# - TRADINGBOT__UpdateIntervalSeconds=3
|
# - TRADINGBOT__UpdateIntervalSeconds=3
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
healthcheck:
|
healthcheck:
|
||||||
test: ["CMD", "curl", "-f", "http://localhost:8080/health"]
|
test: ["CMD", "wget", "--no-verbose", "--tries=1", "--spider", "http://localhost:8080/health"]
|
||||||
interval: 30s
|
interval: 30s
|
||||||
timeout: 3s
|
timeout: 3s
|
||||||
retries: 3
|
retries: 3
|
||||||
|
|||||||
Reference in New Issue
Block a user