diff --git a/backend/Dockerfile b/backend/Dockerfile index 70393d6..e578d79 100644 --- a/backend/Dockerfile +++ b/backend/Dockerfile @@ -2,25 +2,20 @@ FROM mcr.microsoft.com/dotnet/sdk:9.0 AS build WORKDIR /app -# Copiar archivos de proyecto y restaurar dependencias primero para aprovechar el caché de Docker COPY backend/src/Titulares.Api/Titulares.Api.csproj backend/src/Titulares.Api/ RUN dotnet restore backend/src/Titulares.Api/Titulares.Api.csproj -# Copiar el resto del código fuente del backend COPY backend/src/ ./backend/src/ -# Publicar la aplicación en modo Release RUN dotnet publish backend/src/Titulares.Api/Titulares.Api.csproj -c Release -o /app/publish # --- Etapa 2: Imagen Final (Final) --- FROM mcr.microsoft.com/dotnet/aspnet:9.0 WORKDIR /app -# Copiar solo los artefactos compilados desde la etapa de build COPY --from=build /app/publish . -# Exponer el puerto interno que ASP.NET Core usará por defecto en Docker EXPOSE 8080 - -# Comando para iniciar la aplicación +# Añade esta línea para asegurar que Kestrel escuche en el puerto 8080 +ENV ASPNETCORE_URLS=http://+:8080 ENTRYPOINT ["dotnet", "Titulares.Api.dll"] \ No newline at end of file diff --git a/backend/src/Titulares.Api/Program.cs b/backend/src/Titulares.Api/Program.cs index 560ab0c..2dfcb26 100644 --- a/backend/src/Titulares.Api/Program.cs +++ b/backend/src/Titulares.Api/Program.cs @@ -4,6 +4,7 @@ using Titulares.Api.Hubs; using Titulares.Api.Models; using Titulares.Api.Services; using Titulares.Api.Workers; +using Microsoft.AspNetCore.HttpOverrides; var builder = WebApplication.CreateBuilder(args); @@ -23,19 +24,27 @@ builder.Services.AddScoped(); builder.Services.AddSingleton(); builder.Services.AddSingleton(); -// Añadimos la política de CORS +var frontendUrl = "http://192.168.5.128:8905"; + builder.Services.AddCors(options => { - options.AddPolicy("AllowReactApp", builder => + options.AddPolicy("AllowReactApp", policyBuilder => { - //builder.WithOrigins("http://localhost:5173") - builder.AllowAnyOrigin() - .AllowAnyHeader() - .AllowAnyMethod() - .AllowCredentials(); + policyBuilder.WithOrigins(frontendUrl) + .AllowAnyHeader() + .AllowAnyMethod() + .AllowCredentials(); }); }); +builder.Services.Configure(options => +{ + options.ForwardedHeaders = + ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto; + options.KnownNetworks.Clear(); + options.KnownProxies.Clear(); +}); + builder.Services.AddSignalR(); builder.Services.AddHostedService(); @@ -47,6 +56,16 @@ builder.Services.AddAuthorization(); // ========================== var app = builder.Build(); +// DEBE IR ANTES DE UseRouting, UseCors, UseAuthorization, etc. +app.UseForwardedHeaders(); + +// Configure the HTTP request pipeline. +if (app.Environment.IsDevelopment()) +{ + app.UseSwagger(); + app.UseSwaggerUI(); +} + // 3. Configurar el pipeline de peticiones HTTP. // ============================================ @@ -72,5 +91,4 @@ app.UseAuthorization(); app.MapControllers(); app.MapHub("/titularesHub"); - app.Run(); \ No newline at end of file diff --git a/backend/src/Titulares.Api/appsettings.json b/backend/src/Titulares.Api/appsettings.json index 39ce038..eec17d7 100644 --- a/backend/src/Titulares.Api/appsettings.json +++ b/backend/src/Titulares.Api/appsettings.json @@ -7,6 +7,6 @@ }, "AllowedHosts": "*", "ConnectionStrings": { - "DefaultConnection": "Server=db-sqlserver;Database=TitularesDB;User Id=titularesApi;Password=PTP847Titulares;Trusted_Connection=True;TrustServerCertificate=True;" + "DefaultConnection": "Server=db-sqlserver;Database=TitularesDB;User Id=titularesApi;Password=PTP847Titulares;TrustServerCertificate=True;" } } \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml index d6dec4c..7b9e929 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -17,6 +17,8 @@ services: build: context: ./frontend dockerfile: Dockerfile + args: + - VITE_API_BASE_URL=http://192.168.5.128:8905 container_name: titulares-frontend restart: unless-stopped expose: diff --git a/frontend/.env b/frontend/.env new file mode 100644 index 0000000..0c74d82 --- /dev/null +++ b/frontend/.env @@ -0,0 +1 @@ +VITE_API_BASE_URL=http://192.168.5.128:8905 \ No newline at end of file diff --git a/frontend/proxy/nginx.conf b/frontend/proxy/nginx.conf index bcd0459..40a4e58 100644 --- a/frontend/proxy/nginx.conf +++ b/frontend/proxy/nginx.conf @@ -1,21 +1,37 @@ +# /frontend/proxy/nginx.conf + server { listen 80; + server_name localhost; - # Pasa todas las peticiones a la API al servicio del backend - location /api/ { - proxy_pass http://titulares-api:8080/api/; - 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; - } - - # Pasa el resto de las peticiones al servicio del frontend location / { proxy_pass http://titulares-frontend:80; 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_set_header X-Forwarded-Host $host; + } + + location /api/ { + proxy_pass http://titulares-api:8080; + 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_set_header X-Forwarded-Host $host; + } + + location /titularesHub/ { + proxy_pass http://titulares-api:8080; + 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; + 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_set_header X-Forwarded-Host $host; } } \ No newline at end of file diff --git a/frontend/src/hooks/useSignalR.ts b/frontend/src/hooks/useSignalR.ts index e81d889..9e46e48 100644 --- a/frontend/src/hooks/useSignalR.ts +++ b/frontend/src/hooks/useSignalR.ts @@ -3,8 +3,10 @@ import { useEffect, useRef, useState } from 'react'; import * as signalR from '@microsoft/signalr'; +// Construye la URL completa del Hub +const HUB_URL = `${import.meta.env.VITE_API_BASE_URL}/titularesHub`; //const HUB_URL = 'http://localhost:5174/titularesHub'; -const HUB_URL = '/titularesHub'; + // Definimos un tipo para el estado de la conexión para más claridad export type ConnectionStatus = 'Connecting' | 'Connected' | 'Disconnected' | 'Reconnecting'; diff --git a/frontend/src/services/apiService.ts b/frontend/src/services/apiService.ts index 554fd0b..f7b808a 100644 --- a/frontend/src/services/apiService.ts +++ b/frontend/src/services/apiService.ts @@ -4,7 +4,7 @@ import axios from 'axios'; import type { Configuracion, Titular } from '../types'; //const API_URL = 'http://localhost:5174/api'; -const API_URL = '/api'; +const API_URL = `${import.meta.env.VITE_API_BASE_URL}/api`; const apiClient = axios.create({ baseURL: API_URL, diff --git a/frontend/vite.config.ts b/frontend/vite.config.ts index 8b0f57b..8ddcfc6 100644 --- a/frontend/vite.config.ts +++ b/frontend/vite.config.ts @@ -1,7 +1,22 @@ import { defineConfig } from 'vite' import react from '@vitejs/plugin-react' -// https://vite.dev/config/ +// https://vitejs.dev/config/ export default defineConfig({ plugins: [react()], -}) + server: { + proxy: { + // Redirige cualquier petición que empiece con '/api' al backend + '/api': { + target: 'http://localhost:5174', // <-- Usa el puerto HTTP del backend + changeOrigin: true, + }, + // Redirige cualquier petición a '/titularesHub' al backend (para SignalR) + '/titularesHub': { + target: 'http://localhost:5174', // <-- Usa el mismo puerto + ws: true, // <-- Habilita el proxy para WebSockets (crucial para SignalR) + changeOrigin: true, + } + } + } +}) \ No newline at end of file