diff --git a/.claude/settings.local.json b/.claude/settings.local.json index 89c157b..9a59536 100644 --- a/.claude/settings.local.json +++ b/.claude/settings.local.json @@ -22,7 +22,9 @@ "Bash(docker stats:*)", "Bash(time make:*)", "Bash(docker compose:*)", - "Bash(git add:*)" + "Bash(git add:*)", + "Bash(git commit:*)", + "Bash(git tag:*)" ], "deny": [] } diff --git a/.env.example b/.env.example index 72da45b..c94e3e9 100644 --- a/.env.example +++ b/.env.example @@ -39,4 +39,10 @@ GROUP_ID=20 VITE_API_BASE_URL=http://backend:3001/api VITE_AUTH0_DOMAIN=your-domain.auth0.com VITE_AUTH0_CLIENT_ID=your-client-id -VITE_AUTH0_AUDIENCE=https://api.motovaultpro.com \ No newline at end of file +VITE_AUTH0_AUDIENCE=https://api.motovaultpro.com + +# External Server Deployment +# Update these when deploying to external server with custom domain +FRONTEND_DOMAIN=motovaultpro.com +FRONTEND_PORT=3000 +# For API calls from external domain, update backend CORS settings \ No newline at end of file diff --git a/certs/.gitignore b/certs/.gitignore new file mode 100644 index 0000000..403f91b --- /dev/null +++ b/certs/.gitignore @@ -0,0 +1,9 @@ +# SSL Certificates - exclude from git for security +*.crt +*.key +*.pem +*.p12 +*.pfx + +# Keep directory structure +!.gitignore \ No newline at end of file diff --git a/docker-compose.yml b/docker-compose.yml index b76cf7f..5018d92 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -91,17 +91,23 @@ services: frontend: build: context: ./frontend - dockerfile: Dockerfile.dev + dockerfile: Dockerfile container_name: mvp-frontend environment: NODE_ENV: development VITE_API_BASE_URL: http://backend:3001/api + VITE_AUTH0_DOMAIN: ${VITE_AUTH0_DOMAIN:-motovaultpro.us.auth0.com} + VITE_AUTH0_CLIENT_ID: ${VITE_AUTH0_CLIENT_ID:-yspR8zdnSxmV8wFIghHynQ08iXAPoQJ3} + VITE_AUTH0_AUDIENCE: ${VITE_AUTH0_AUDIENCE:-https://api.motovaultpro.com} ports: - - "3000:3000" + - "0.0.0.0:3000:3000" # HTTP (redirects to HTTPS) + - "0.0.0.0:443:3443" # HTTPS + volumes: + - ./certs:/etc/nginx/certs:ro # Mount SSL certificates depends_on: - backend healthcheck: - test: ["CMD", "wget", "--quiet", "--tries=1", "--spider", "http://localhost:3000"] + test: ["CMD", "wget", "--quiet", "--tries=1", "--spider", "--no-check-certificate", "https://localhost:3443"] interval: 30s timeout: 10s retries: 3 diff --git a/frontend/Dockerfile b/frontend/Dockerfile index 4c3247d..95c927d 100644 --- a/frontend/Dockerfile +++ b/frontend/Dockerfile @@ -37,8 +37,8 @@ RUN touch /var/run/nginx.pid && \ USER frontend -# Expose port -EXPOSE 3000 +# Expose ports +EXPOSE 3000 3443 # Start nginx CMD ["nginx", "-g", "daemon off;"] \ No newline at end of file diff --git a/frontend/nginx.conf b/frontend/nginx.conf index 3dad573..12be541 100644 --- a/frontend/nginx.conf +++ b/frontend/nginx.conf @@ -9,9 +9,35 @@ http { sendfile on; keepalive_timeout 65; + # HTTP server - redirect to HTTPS server { listen 3000; - server_name localhost; + server_name motovaultpro.com *.motovaultpro.com localhost; + + # Redirect all HTTP traffic to HTTPS + return 301 https://$host:3443$request_uri; + } + + # HTTPS server + server { + listen 3443 ssl http2; + server_name motovaultpro.com *.motovaultpro.com localhost; + + # SSL certificate configuration + ssl_certificate /etc/nginx/certs/motovaultpro.com.crt; + ssl_certificate_key /etc/nginx/certs/motovaultpro.com.key; + + # Modern SSL configuration + ssl_protocols TLSv1.2 TLSv1.3; + ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA384; + ssl_prefer_server_ciphers off; + ssl_session_cache shared:SSL:10m; + ssl_session_timeout 10m; + + # Security headers + add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always; + add_header X-Frame-Options DENY always; + add_header X-Content-Type-Options nosniff always; root /usr/share/nginx/html; index index.html; @@ -28,6 +54,7 @@ http { 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-Port $server_port; } # Enable gzip compression diff --git a/frontend/src/core/auth/Auth0Provider.tsx b/frontend/src/core/auth/Auth0Provider.tsx index 4a323be..fd2e80e 100644 --- a/frontend/src/core/auth/Auth0Provider.tsx +++ b/frontend/src/core/auth/Auth0Provider.tsx @@ -18,6 +18,7 @@ export const Auth0Provider: React.FC = ({ children }) => { const clientId = import.meta.env.VITE_AUTH0_CLIENT_ID; const audience = import.meta.env.VITE_AUTH0_AUDIENCE; + const onRedirectCallback = (appState?: { returnTo?: string }) => { navigate(appState?.returnTo || '/dashboard'); }; diff --git a/frontend/vite.config.ts b/frontend/vite.config.ts index a0daf82..ce1699e 100644 --- a/frontend/vite.config.ts +++ b/frontend/vite.config.ts @@ -12,5 +12,10 @@ export default defineConfig({ server: { port: 3000, host: '0.0.0.0', // Allow external connections for container + allowedHosts: [ + 'localhost', + 'motovaultpro.com', + '.motovaultpro.com' + ], }, }); \ No newline at end of file