diff --git a/hosting/docker-compose.yaml b/hosting/docker-compose.yaml index 709eeeaf83..c8d003474d 100644 --- a/hosting/docker-compose.yaml +++ b/hosting/docker-compose.yaml @@ -82,7 +82,7 @@ services: restart: always image: nginx:latest volumes: - - ./proxy/nginx.conf:/etc/envoy/envoy.yaml + - ./proxy/nginx.conf:/etc/nginx/nginx.conf ports: - "${MAIN_PORT}:10000" depends_on: diff --git a/hosting/envoy.dev.yaml.hbs b/hosting/envoy.dev.yaml.hbs deleted file mode 100644 index 59363fab5e..0000000000 --- a/hosting/envoy.dev.yaml.hbs +++ /dev/null @@ -1,149 +0,0 @@ -static_resources: - listeners: - - name: main_listener - address: - socket_address: { address: 0.0.0.0, port_value: 10000 } - filter_chains: - - filters: - - name: envoy.filters.network.http_connection_manager - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager - stat_prefix: ingress - codec_type: auto - route_config: - name: local_route - virtual_hosts: - - name: local_services - domains: ["*"] - routes: - # special case to redirect specifically the route path - # to the builder, if this were a prefix then it would break minio - - match: { path: "/" } - redirect: { path_redirect: "/builder/" } - - - match: { prefix: "/db/" } - route: - cluster: couchdb-service - prefix_rewrite: "/" - - - match: { prefix: "/api/system/" } - route: - cluster: worker-dev - - - match: { prefix: "/api/admin/" } - route: - cluster: worker-dev - - - match: { prefix: "/api/global/" } - route: - cluster: worker-dev - - - match: { prefix: "/api/" } - route: - cluster: server-dev - timeout: 120s - - - match: { prefix: "/app_" } - route: - cluster: server-dev - - - match: { prefix: "/app/" } - route: - cluster: server-dev - prefix_rewrite: "/" - - # the below three cases are needed to make sure - # all traffic prefixed for the builder is passed through - # correctly. - - match: { path: "/" } - route: - cluster: builder-dev - - - match: { prefix: "/builder/" } - route: - cluster: builder-dev - - - match: { prefix: "/builder" } - route: - cluster: builder-dev - prefix_rewrite: "/builder/" - - # minio is on the default route because this works - # best, minio + AWS SDK doesn't handle path proxy - - match: { prefix: "/" } - route: - cluster: minio-service - - http_filters: - - name: envoy.filters.http.router - - clusters: - - name: minio-service - connect_timeout: 0.25s - type: strict_dns - lb_policy: round_robin - load_assignment: - cluster_name: minio-service - endpoints: - - lb_endpoints: - - endpoint: - address: - socket_address: - address: minio-service - port_value: 9000 - - - name: couchdb-service - connect_timeout: 0.25s - type: strict_dns - lb_policy: round_robin - load_assignment: - cluster_name: couchdb-service - endpoints: - - lb_endpoints: - - endpoint: - address: - socket_address: - address: couchdb-service - port_value: 5984 - - - name: server-dev - connect_timeout: 0.25s - type: strict_dns - lb_policy: round_robin - load_assignment: - cluster_name: server-dev - endpoints: - - lb_endpoints: - - endpoint: - address: - socket_address: - address: {{ address }} - port_value: 4001 - - - name: builder-dev - connect_timeout: 15s - type: strict_dns - lb_policy: round_robin - load_assignment: - cluster_name: builder-dev - endpoints: - - lb_endpoints: - - endpoint: - address: - socket_address: - address: {{ address }} - port_value: 3000 - - - name: worker-dev - connect_timeout: 0.25s - type: strict_dns - lb_policy: round_robin - load_assignment: - cluster_name: worker-dev - endpoints: - - lb_endpoints: - - endpoint: - address: - socket_address: - address: {{ address }} - port_value: 4002 diff --git a/hosting/hosting.properties b/hosting/hosting.properties deleted file mode 100644 index c8e2f5c606..0000000000 --- a/hosting/hosting.properties +++ /dev/null @@ -1,21 +0,0 @@ -# Use the main port in the builder for your self hosting URL, e.g. localhost:10000 -MAIN_PORT=10000 - -# This section contains all secrets pertaining to the system -# These should be updated -JWT_SECRET=testsecret -MINIO_ACCESS_KEY=budibase -MINIO_SECRET_KEY=budibase -COUCH_DB_PASSWORD=budibase -COUCH_DB_USER=budibase -REDIS_PASSWORD=budibase -INTERNAL_API_KEY=budibase - -# This section contains variables that do not need to be altered under normal circumstances -APP_PORT=4002 -WORKER_PORT=4003 -MINIO_PORT=4004 -COUCH_DB_PORT=4005 -REDIS_PORT=6379 -WATCHTOWER_PORT=6161 -BUDIBASE_ENVIRONMENT=PRODUCTION diff --git a/hosting/kubernetes/envoy/Dockerfile b/hosting/kubernetes/envoy/Dockerfile deleted file mode 100644 index 96334fa723..0000000000 --- a/hosting/kubernetes/envoy/Dockerfile +++ /dev/null @@ -1,4 +0,0 @@ -FROM envoyproxy/envoy:v1.16-latest -COPY envoy.yaml /etc/envoy/envoy.yaml -RUN chmod go+r /etc/envoy/envoy.yaml - diff --git a/hosting/kubernetes/envoy/envoy.yaml b/hosting/kubernetes/envoy/envoy.yaml deleted file mode 100644 index bab1f25c02..0000000000 --- a/hosting/kubernetes/envoy/envoy.yaml +++ /dev/null @@ -1,146 +0,0 @@ -static_resources: - listeners: - - name: main_listener - address: - socket_address: { address: 0.0.0.0, port_value: 10000 } - filter_chains: - - filters: - - name: envoy.filters.network.http_connection_manager - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager - stat_prefix: ingress - codec_type: auto - route_config: - name: local_route - virtual_hosts: - - name: local_services - domains: ["*"] - routes: - - match: { prefix: "/app/" } - route: - cluster: app-service - prefix_rewrite: "/" - - - match: { prefix: "/builder/" } - route: - cluster: app-service - - - match: { prefix: "/builder" } - route: - cluster: app-service - - - match: { prefix: "/app_" } - route: - cluster: app-service - - # special cases for worker admin (deprecated), global and system API - - match: { prefix: "/api/global/" } - route: - cluster: worker-service - - - match: { prefix: "/api/admin/" } - route: - cluster: worker-service - - - match: { prefix: "/api/system/" } - route: - cluster: worker-service - - - match: { path: "/" } - route: - cluster: app-service - - - match: - safe_regex: - google_re2: {} - regex: "/api/.*/export" - route: - timeout: 0s - cluster: app-service - - - match: { path: "/api/deploy" } - route: - timeout: 60s - cluster: app-service - - # special case for when API requests are made, can just forward, not to minio - - match: { prefix: "/api/" } - route: - cluster: app-service - - - match: { prefix: "/worker/" } - route: - cluster: worker-service - prefix_rewrite: "/" - - - match: { prefix: "/db/" } - route: - cluster: couchdb-service - prefix_rewrite: "/" - - # minio is on the default route because this works - # best, minio + AWS SDK doesn't handle path proxy - - match: { prefix: "/" } - route: - cluster: minio-service - - http_filters: - - name: envoy.filters.http.router - - clusters: - - name: app-service - connect_timeout: 0.25s - type: strict_dns - lb_policy: round_robin - load_assignment: - cluster_name: app-service - endpoints: - - lb_endpoints: - - endpoint: - address: - socket_address: - address: app-service.budibase.svc.cluster.local - port_value: 4002 - - - name: minio-service - connect_timeout: 0.25s - type: strict_dns - lb_policy: round_robin - load_assignment: - cluster_name: minio-service - endpoints: - - lb_endpoints: - - endpoint: - address: - socket_address: - address: minio-service.budibase.svc.cluster.local - port_value: 9000 - - - name: worker-service - connect_timeout: 0.25s - type: strict_dns - lb_policy: round_robin - load_assignment: - cluster_name: worker-service - endpoints: - - lb_endpoints: - - endpoint: - address: - socket_address: - address: worker-service.budibase.svc.cluster.local - port_value: 4001 - - - name: couchdb-service - connect_timeout: 0.25s - type: strict_dns - lb_policy: round_robin - load_assignment: - cluster_name: couchdb-service - endpoints: - - lb_endpoints: - - endpoint: - address: - socket_address: - address: budibase-prod-svc-couchdb - port_value: 5984 - diff --git a/hosting/kubernetes/nginx/Dockerfile b/hosting/kubernetes/nginx/Dockerfile index 189a71288f..754f9f9be3 100644 --- a/hosting/kubernetes/nginx/Dockerfile +++ b/hosting/kubernetes/nginx/Dockerfile @@ -1,3 +1,2 @@ -# FROM envoyproxy/envoy:v1.16-latest -# COPY envoy.yaml /etc/envoy/envoy.yaml -# RUN chmod go+r /etc/envoy/envoy.yaml +FROM nginx:latest +COPY nginx.conf /etc/nginx/nginx.conf diff --git a/hosting/kubernetes/nginx/nginx.conf b/hosting/kubernetes/nginx/nginx.conf index bab1f25c02..14c9b5aa44 100644 --- a/hosting/kubernetes/nginx/nginx.conf +++ b/hosting/kubernetes/nginx/nginx.conf @@ -1,146 +1,113 @@ -static_resources: - listeners: - - name: main_listener - address: - socket_address: { address: 0.0.0.0, port_value: 10000 } - filter_chains: - - filters: - - name: envoy.filters.network.http_connection_manager - typed_config: - "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager - stat_prefix: ingress - codec_type: auto - route_config: - name: local_route - virtual_hosts: - - name: local_services - domains: ["*"] - routes: - - match: { prefix: "/app/" } - route: - cluster: app-service - prefix_rewrite: "/" +user nginx; +error_log /var/log/nginx/error.log debug; +pid /var/run/nginx.pid; +worker_processes auto; +worker_rlimit_nofile 33282; - - match: { prefix: "/builder/" } - route: - cluster: app-service +events { + worker_connections 1024; +} - - match: { prefix: "/builder" } - route: - cluster: app-service +http { + limit_req_zone $binary_remote_addr zone=ratelimit:10m rate=10r/s; + include /etc/nginx/mime.types; + default_type application/octet-stream; - - match: { prefix: "/app_" } - route: - cluster: app-service - # special cases for worker admin (deprecated), global and system API - - match: { prefix: "/api/global/" } - route: - cluster: worker-service + log_format main '$remote_addr - $remote_user [$time_local] "$request" ' + '$status $body_bytes_sent "$http_referer" ' + '"$http_user_agent" "$http_x_forwarded_for"'; + + map $http_upgrade $connection_upgrade { + default "upgrade"; + } - - match: { prefix: "/api/admin/" } - route: - cluster: worker-service + server { + listen 10000 default_server; + server_name _; + client_max_body_size 1000m; + ignore_invalid_headers off; + proxy_buffering off; - - match: { prefix: "/api/system/" } - route: - cluster: worker-service + # Security Headers + add_header X-Frame-Options SAMEORIGIN always; + add_header X-Content-Type-Options nosniff always; + add_header X-XSS-Protection "1; mode=block" always; + add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' 'unsafe-eval' https://cdn.budi.live https://js.intercomcdn.com https://widget.intercom.io; style-src 'self' 'unsafe-inline' https://cdn.jsdelivr.net https://fonts.googleapis.com https://rsms.me; object-src 'none'; base-uri 'self'; connect-src 'self' https://api-iam.intercom.io https://app.posthog.com wss://nexus-websocket-a.intercom.io; font-src 'self' https://cdn.jsdelivr.net https://fonts.gstatic.com https://rsms.me; frame-src 'self'; img-src https: data:; manifest-src 'self'; media-src 'self'; worker-src 'none';" always; - - match: { path: "/" } - route: - cluster: app-service + location /app { + proxy_pass http://app-service:4002; + rewrite ^/app/(.*)$ /$1 break; + } - - match: - safe_regex: - google_re2: {} - regex: "/api/.*/export" - route: - timeout: 0s - cluster: app-service + location = / { + proxy_pass http://app-service.budibase.svc.cluster.local:4002; + } - - match: { path: "/api/deploy" } - route: - timeout: 60s - cluster: app-service + location /builder/ { + proxy_http_version 1.1; + proxy_set_header Connection $connection_upgrade; + proxy_set_header Upgrade $http_upgrade; + 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_pass http://app-service.budibase.svc.cluster.local:4002; + } - # special case for when API requests are made, can just forward, not to minio - - match: { prefix: "/api/" } - route: - cluster: app-service + location ^/(builder|app_) { + proxy_pass http://app-service.budibase.svc.cluster.local:4002; + } - - match: { prefix: "/worker/" } - route: - cluster: worker-service - prefix_rewrite: "/" + location ~ ^/api/(system|admin|global)/ { + proxy_pass http://worker-service.budibase.svc.cluster.local:4003; + } - - match: { prefix: "/db/" } - route: - cluster: couchdb-service - prefix_rewrite: "/" + location /worker/ { + proxy_pass http://worker-service.budibase.svc.cluster.local:4003; + rewrite ^/worker/(.*)$ /$1 break; + } - # minio is on the default route because this works - # best, minio + AWS SDK doesn't handle path proxy - - match: { prefix: "/" } - route: - cluster: minio-service + location /api/ { + # calls to the API are rate limited with bursting + limit_req zone=ratelimit burst=10 nodelay; - http_filters: - - name: envoy.filters.http.router + # 120s timeout on API requests + proxy_read_timeout 120s; + proxy_connect_timeout 120s; + proxy_send_timeout 120s; - clusters: - - name: app-service - connect_timeout: 0.25s - type: strict_dns - lb_policy: round_robin - load_assignment: - cluster_name: app-service - endpoints: - - lb_endpoints: - - endpoint: - address: - socket_address: - address: app-service.budibase.svc.cluster.local - port_value: 4002 + proxy_http_version 1.1; + proxy_set_header Connection $connection_upgrade; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Host $host; + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; - - name: minio-service - connect_timeout: 0.25s - type: strict_dns - lb_policy: round_robin - load_assignment: - cluster_name: minio-service - endpoints: - - lb_endpoints: - - endpoint: - address: - socket_address: - address: minio-service.budibase.svc.cluster.local - port_value: 9000 + proxy_pass http://app-service.budibase.svc.cluster.local:4002; + } - - name: worker-service - connect_timeout: 0.25s - type: strict_dns - lb_policy: round_robin - load_assignment: - cluster_name: worker-service - endpoints: - - lb_endpoints: - - endpoint: - address: - socket_address: - address: worker-service.budibase.svc.cluster.local - port_value: 4001 + location /db/ { + proxy_pass http://budibase-prod-svc-couchdb:5984; + rewrite ^/db/(.*)$ /$1 break; + } - - name: couchdb-service - connect_timeout: 0.25s - type: strict_dns - lb_policy: round_robin - load_assignment: - cluster_name: couchdb-service - endpoints: - - lb_endpoints: - - endpoint: - address: - socket_address: - address: budibase-prod-svc-couchdb - port_value: 5984 + location / { + 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 Host $http_host; + proxy_connect_timeout 300; + proxy_http_version 1.1; + proxy_set_header Connection ""; + chunked_transfer_encoding off; + proxy_pass http://minio-service.budibase.svc.cluster.local:9000; + } + + client_header_timeout 60; + client_body_timeout 60; + keepalive_timeout 60; + gzip on; + gzip_comp_level 4; + } +} \ No newline at end of file diff --git a/hosting/nginx.dev.conf.hbs b/hosting/nginx.dev.conf.hbs index b07d3c10d2..51b55cd49b 100644 --- a/hosting/nginx.dev.conf.hbs +++ b/hosting/nginx.dev.conf.hbs @@ -23,11 +23,9 @@ http { server { listen 10000 default_server; server_name _; - - location = / { - absolute_redirect off; - return 301 /builder; - } + client_max_body_size 1000m; + ignore_invalid_headers off; + proxy_buffering off; location /db/ { proxy_pass http://couchdb-service:5984; @@ -71,6 +69,16 @@ http { } location / { + 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 Host $http_host; + + proxy_connect_timeout 300; + proxy_http_version 1.1; + proxy_set_header Connection ""; + chunked_transfer_encoding off; + proxy_pass http://minio-service:9000; } diff --git a/hosting/proxy/nginx.conf b/hosting/proxy/nginx.conf index 2d644911f7..1f7f0f6e6e 100644 --- a/hosting/proxy/nginx.conf +++ b/hosting/proxy/nginx.conf @@ -9,9 +9,11 @@ events { } http { + limit_req_zone $binary_remote_addr zone=ratelimit:10m rate=10r/s; include /etc/nginx/mime.types; default_type application/octet-stream; + log_format main '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" "$http_x_forwarded_for"'; @@ -23,6 +25,20 @@ http { server { listen 10000 default_server; server_name _; + client_max_body_size 1000m; + ignore_invalid_headers off; + proxy_buffering off; + + # Security Headers + add_header X-Frame-Options SAMEORIGIN always; + add_header X-Content-Type-Options nosniff always; + add_header X-XSS-Protection "1; mode=block" always; + add_header Content-Security-Policy "default-src 'self'; script-src 'unsafe-inline' 'unsafe-eval' 'self' https://cdn.budi.live https://js.intercomcdn.com https://widget.intercom.io; style-src 'self' 'unsafe-inline' https://cdn.jsdelivr.net https://fonts.googleapis.com https://rsms.me; object-src 'none'; base-uri 'self'; connect-src 'self' https://api-iam.intercom.io https://app.posthog.com wss://nexus-websocket-a.intercom.io; font-src 'self' https://cdn.jsdelivr.net https://fonts.gstatic.com https://rsms.me; frame-src 'self'; img-src https: data:; manifest-src 'self'; media-src 'self'; worker-src 'none';" always; + + location /app { + proxy_pass http://app-service:4002; + rewrite ^/app/(.*)$ /$1 break; + } location = / { proxy_pass http://app-service:4002; @@ -33,14 +49,16 @@ http { } location /builder/ { + proxy_http_version 1.1; + proxy_set_header Connection $connection_upgrade; + proxy_set_header Upgrade $http_upgrade; + 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_pass http://app-service:4002; } - location /builder { - proxy_pass http://app-service:4002; - } - - location /app_ { + location ^/(builder|app_) { proxy_pass http://app-service:4002; } @@ -48,31 +66,52 @@ http { proxy_pass http://worker-service:4003; } - location /api/ { - proxy_read_timeout 120s; - proxy_connect_timeout 120s; - proxy_send_timeout 120s; - proxy_pass http://app-service:4002; - } - location /worker/ { proxy_pass http://worker-service:4003; rewrite ^/worker/(.*)$ /$1 break; } + location /api/ { + # calls to the API are rate limited with bursting + limit_req zone=ratelimit burst=10 nodelay; + + # 120s timeout on API requests + proxy_read_timeout 120s; + proxy_connect_timeout 120s; + proxy_send_timeout 120s; + + proxy_http_version 1.1; + proxy_set_header Connection $connection_upgrade; + proxy_set_header Upgrade $http_upgrade; + 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_pass http://app-service:4002; + } + location /db/ { proxy_pass http://couchdb-service:5984; rewrite ^/db/(.*)$ /$1 break; } location / { + 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 Host $http_host; + + proxy_connect_timeout 300; + proxy_http_version 1.1; + proxy_set_header Connection ""; + chunked_transfer_encoding off; proxy_pass http://minio-service:9000; } client_header_timeout 60; client_body_timeout 60; keepalive_timeout 60; - gzip off; + gzip on; gzip_comp_level 4; } } \ No newline at end of file diff --git a/hosting/scripts/airgapped/airgappedDockerBuild.js b/hosting/scripts/airgapped/airgappedDockerBuild.js index 5be19fdeb8..3892a35ee6 100755 --- a/hosting/scripts/airgapped/airgappedDockerBuild.js +++ b/hosting/scripts/airgapped/airgappedDockerBuild.js @@ -15,8 +15,7 @@ const IMAGES = { const FILES = { COMPOSE: "docker-compose.yaml", - ENVOY: "envoy.yaml", - PROPERTIES: "hosting.properties" + NGINX: "nginx.conf" } const OUTPUT_DIR = path.join(__dirname, "../", "bb-airgapped") diff --git a/packages/builder/cypress/setup.js b/packages/builder/cypress/setup.js index 7657303853..022b134e2f 100644 --- a/packages/builder/cypress/setup.js +++ b/packages/builder/cypress/setup.js @@ -18,7 +18,7 @@ process.env.COUCH_URL = `leveldb://${tmpdir}/.data/` process.env.SELF_HOSTED = 1 process.env.WORKER_URL = "http://localhost:10002/" process.env.APPS_URL = `http://localhost:${MAIN_PORT}/` -process.env.MINIO_URL = `http://localhost:${MAIN_PORT}/` +process.env.MINIO_URL = `http://localhost:${MAIN_PORT}/minio` process.env.MINIO_ACCESS_KEY = "budibase" process.env.MINIO_SECRET_KEY = "budibase" process.env.COUCH_DB_USER = "budibase" diff --git a/packages/cli/.gitignore b/packages/cli/.gitignore index c47f898f26..c38adcf17a 100644 --- a/packages/cli/.gitignore +++ b/packages/cli/.gitignore @@ -1,6 +1,5 @@ node_modules/ docker-compose.yaml envoy.yaml -hosting.properties build/ docker-error.log diff --git a/packages/server/scripts/likeCypress.ts b/packages/server/scripts/likeCypress.ts index 625b4386e1..299552d9b5 100644 --- a/packages/server/scripts/likeCypress.ts +++ b/packages/server/scripts/likeCypress.ts @@ -17,7 +17,7 @@ process.env.JWT_SECRET = "budibase" process.env.COUCH_URL = `leveldb://${tmpdir}/.data/` process.env.SELF_HOSTED = "1" process.env.WORKER_URL = `http://localhost:${WORKER_PORT}/` -process.env.MINIO_URL = `http://localhost:${MAIN_PORT}/` +process.env.MINIO_URL = `http://localhost:${MAIN_PORT}/minio` process.env.MINIO_ACCESS_KEY = "budibase" process.env.MINIO_SECRET_KEY = "budibase" process.env.COUCH_DB_USER = "budibase"