diff --git a/deployment/data/nginx/app.conf.template b/deployment/data/nginx/app.conf.template index 177bfe54d..f9474e674 100644 --- a/deployment/data/nginx/app.conf.template +++ b/deployment/data/nginx/app.conf.template @@ -70,7 +70,7 @@ server { location / { proxy_http_version 1.1; proxy_buffering off; - proxy_pass http://${DOMAIN}; + proxy_pass http://localhost:80; } ssl_certificate /etc/letsencrypt/live/${DOMAIN}/fullchain.pem; diff --git a/deployment/data/nginx/app.conf.template.no-letsencrypt b/deployment/data/nginx/app.conf.template.no-letsencrypt new file mode 100644 index 000000000..85b1965e5 --- /dev/null +++ b/deployment/data/nginx/app.conf.template.no-letsencrypt @@ -0,0 +1,74 @@ +upstream api_server { + # fail_timeout=0 means we always retry an upstream even if it failed + # to return a good HTTP response + + # for UNIX domain socket setups + #server unix:/tmp/gunicorn.sock fail_timeout=0; + + # for a TCP configuration + # TODO: use gunicorn to manage multiple processes + server api_server:8080 fail_timeout=0; +} + +upstream web_server { + server web_server:3000 fail_timeout=0; +} + +server { + listen 80; + server_name ${DOMAIN}; + + client_max_body_size 500M; # Maximum upload size + + location ~ ^/api(.*)$ { + rewrite ^/api(/.*)$ $1 break; + + # misc headers + 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; + proxy_set_header Host $host; + + # need to use 1.1 to support chunked transfers + proxy_http_version 1.1; + proxy_buffering off; + + # we don't want nginx trying to do something clever with + # redirects, we set the Host: header above already. + proxy_redirect off; + proxy_pass http://api_server; + } + + location / { + # misc headers + 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; + proxy_set_header Host $host; + + proxy_http_version 1.1; + + # we don't want nginx trying to do something clever with + # redirects, we set the Host: header above already. + proxy_redirect off; + proxy_pass http://web_server; + } +} + +server { + listen 443 ssl; + server_name ${DOMAIN}; + + client_max_body_size 500M; # Maximum upload size + + location / { + proxy_http_version 1.1; + proxy_buffering off; + proxy_pass http://localhost:80; + } + + ssl_certificate /etc/nginx/sslcerts/${SSL_CERT_FILE_NAME}; + ssl_certificate_key /etc/nginx/sslcerts/${SSL_CERT_KEY_FILE_NAME}; +} diff --git a/deployment/docker_compose/docker-compose.prod-no-letsencrypt.yml b/deployment/docker_compose/docker-compose.prod-no-letsencrypt.yml new file mode 100644 index 000000000..44f454b31 --- /dev/null +++ b/deployment/docker_compose/docker-compose.prod-no-letsencrypt.yml @@ -0,0 +1,106 @@ +version: '3' +services: + api_server: + image: danswer/danswer-backend:latest + build: + context: ../../backend + dockerfile: Dockerfile + command: > + /bin/sh -c "alembic upgrade head && + echo \"Starting Danswer Api Server\" && + uvicorn danswer.main:app --host 0.0.0.0 --port 8080" + depends_on: + - relational_db + - document_index + restart: always + env_file: + - .env + environment: + - AUTH_TYPE=${AUTH_TYPE:-google_oauth} + - POSTGRES_HOST=relational_db + - VESPA_HOST=document_index + volumes: + - local_dynamic_storage:/home/storage + - file_connector_tmp_storage:/home/file_connector_storage + - model_cache_torch:/root/.cache/torch/ + - model_cache_nltk:/root/nltk_data/ + - model_cache_huggingface:/root/.cache/huggingface/ + background: + image: danswer/danswer-backend:latest + build: + context: ../../backend + dockerfile: Dockerfile + command: /usr/bin/supervisord + depends_on: + - relational_db + - document_index + restart: always + env_file: + - .env + environment: + - AUTH_TYPE=${AUTH_TYPE:-google_oauth} + - POSTGRES_HOST=relational_db + - VESPA_HOST=document_index + volumes: + - local_dynamic_storage:/home/storage + - file_connector_tmp_storage:/home/file_connector_storage + - model_cache_torch:/root/.cache/torch/ + - model_cache_nltk:/root/nltk_data/ + - model_cache_huggingface:/root/.cache/huggingface/ + web_server: + image: danswer/danswer-web-server:latest + build: + context: ../../web + dockerfile: Dockerfile + args: + - NEXT_PUBLIC_DISABLE_STREAMING=${NEXT_PUBLIC_DISABLE_STREAMING:-false} + depends_on: + - api_server + restart: always + env_file: + - .env + environment: + - INTERNAL_URL=http://api_server:8080 + relational_db: + image: postgres:15.2-alpine + restart: always + # POSTGRES_USER and POSTGRES_PASSWORD should be set in .env file + env_file: + - .env + volumes: + - db_volume:/var/lib/postgresql/data + document_index: + image: vespaengine/vespa:8 + restart: always + ports: + - "19071:19071" + - "8081:8081" + volumes: + - vespa_volume:/opt/vespa/var + nginx: + image: nginx:1.23.4-alpine + restart: always + # nginx will immediately crash with `nginx: [emerg] host not found in upstream` + # if api_server / web_server are not up + depends_on: + - api_server + - web_server + ports: + - "80:80" + - "443:443" + volumes: + - ../data/nginx:/etc/nginx/conf.d + - ../data/sslcerts:/etc/nginx/sslcerts + command: > + /bin/sh -c "envsubst '$$\{DOMAIN\} $$\{SSL_CERT_FILE_NAME\} $$\{SSL_CERT_KEY_FILE_NAME\}' < /etc/nginx/conf.d/app.conf.template.no-letsencrypt > /etc/nginx/conf.d/app.conf + && while :; do sleep 6h & wait $${!}; nginx -s reload; done & nginx -g \"daemon off;\"" + env_file: + - .env.nginx +volumes: + local_dynamic_storage: + file_connector_tmp_storage: # used to store files uploaded by the user temporarily while we are indexing them + db_volume: + vespa_volume: + model_cache_torch: + model_cache_nltk: + model_cache_huggingface: diff --git a/deployment/docker_compose/env.nginx.template b/deployment/docker_compose/env.nginx.template index 32e1b3e64..2fc2923a9 100644 --- a/deployment/docker_compose/env.nginx.template +++ b/deployment/docker_compose/env.nginx.template @@ -1,3 +1,11 @@ # DOMAIN is necessary for https setup, EMAIL is optional DOMAIN= EMAIL= + +# If using the `no-letsencrypt` setup, the below are required. +# They specify the path within /danswer/deployment/data/sslcerts directory +# where the certificate / certificate key can be found. You can either +# name your certificate / certificate key files to follow the convention +# below or adjust these to match your naming conventions. +SSL_CERT_FILE_NAME=ssl.cert +SSL_CERT_KEY_FILE_NAME=ssl.key