diff --git a/self-hosting/docker-compose-self-hosted.yml b/self-hosting/docker-compose-self-hosted.yml index 8b4cc4f865..ce2e1e71be 100644 --- a/self-hosting/docker-compose-self-hosted.yml +++ b/self-hosting/docker-compose-self-hosted.yml @@ -1,4 +1,11 @@ services: + nginx: + image: nginx:stable + container_name: sni-router + network_mode: host + volumes: + - ./nginx.conf:/etc/nginx/nginx.conf:ro + restart: unless-stopped web: image: ghcr.io/forwardemail/forwardemail.net-selfhosted:latest container_name: web diff --git a/self-hosting/nginx.conf b/self-hosting/nginx.conf new file mode 100644 index 0000000000..8ba4080862 --- /dev/null +++ b/self-hosting/nginx.conf @@ -0,0 +1,53 @@ +worker_rlimit_nofile 65535; +worker_processes auto; + +events { + worker_connections 8192; + multi_accept on; +} + +# This stream block is acting as a pass-through proxy based on SNI. +# - Each upstream service (web, api, caldav, carddav) still handles TLS. +stream { + # Fail fast. This applies to all upstreams (web, api, caldav, carddav). + proxy_connect_timeout 5s; + + # Accommodate large headers/cookies in the initial response chunk + proxy_buffer_size 16k; + + # Enable TCP keepalive to detect dead connections and prevent timeouts + proxy_socket_keepalive on; + + map $ssl_preread_server_name $backend { + # carddav.example.com, caldav.example.com, api.example.com + ~^carddav\. carddav; + ~^caldav\. caldav; + ~^api\. api; + # example.com and any other hostname + default web; + } + + server { + listen 443; + listen [::]:443; + + ssl_preread on; # Use SNI information to route to correct backend + proxy_pass $backend; + } + + upstream web { + server 127.0.0.1:3000; + } + + upstream api { + server 127.0.0.1:4000; + } + + upstream caldav { + server 127.0.0.1:5000; + } + + upstream carddav { + server 127.0.0.1:6000; + } +} diff --git a/self-hosting/setup.sh b/self-hosting/setup.sh index 4561ccee51..dd4888da69 100755 --- a/self-hosting/setup.sh +++ b/self-hosting/setup.sh @@ -473,9 +473,9 @@ update_env_file() { update_default_env() { update_env_file NODE_ENV production update_env_file HTTP_PROTOCOL https - update_env_file SQLITE_HOST sqlite.{{DOMAIN}} + update_env_file WEB_URL https://{{DOMAIN}} update_env_file WEB_HOST {{DOMAIN}} - update_env_file WEB_PORT 443 + update_env_file SQLITE_HOST sqlite.{{DOMAIN}} update_env_file CALDAV_HOST caldav.{{DOMAIN}} update_env_file CARDDAV_HOST carddav.{{DOMAIN}} update_env_file API_HOST api.{{DOMAIN}}