diff --git a/.circleci/config.yml b/.circleci/config.yml index c6536af92b..b860f3f224 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -8,6 +8,12 @@ parameters: type: boolean default: false +executors: + default: + description: Node 16.18.1 + docker: + - image: cimg/node:16.18.1 + commands: restore-npm-cache: steps: @@ -32,11 +38,34 @@ commands: name: Dependencies command: npm ci --prefer-offline --cache ~/.cache/npm + build-nginx: + steps: + - run: + name: Build nginx + environment: + STACK: heroku-22 + ZLIB_VERSION: 1.2.13 + command: | + if [ ! -x /usr/local/bin/nginx ]; then + mkdir buildpack + mkdir build-nginx + cd build-nginx + sudo apt install --no-install-recommends -y libssl-dev + wget https://raw.githubusercontent.com/heroku/heroku-buildpack-nginx/main/scripts/build_nginx + chmod +x ./build_nginx + ./build_nginx . + cd ../buildpack + tar -xzvf /tmp/nginx-${STACK}.tgz + fi + - persist_to_workspace: + root: . + paths: + - buildpack/nginx + jobs: install-dependencies: executor: - name: node/default - tag: 16.15.1 + name: default resource_class: medium+ steps: - checkout @@ -48,10 +77,15 @@ jobs: - node_modules - save-npm-cache + install-nginx: + executor: + name: default + steps: + - build-nginx + test: executor: - name: node/default - tag: 16.15.1 + name: default resource_class: medium steps: - checkout @@ -74,36 +108,35 @@ jobs: path: coverage build: executor: - name: node/default - tag: 16.15.1 + name: default resource_class: medium+ steps: - checkout - attach_workspace: at: . + - run: + name: Install Ruby (erb) & nginx + command: | + sudo apt-get update -qq + sudo apt-get install --no-install-recommends -y ruby + sudo cp buildpack/nginx /usr/local/bin/nginx - run: name: Build command: npm run build - run: name: Require redirects file to be generated command: test -f config/nginx-redirects.conf - - run: - name: Install nginx & erb - command: | - sudo apt-get update -qq && - sudo apt-get install --no-install-recommends -y nginx ruby - run: name: Test nginx configuration command: | - PORT=3000 erb config/nginx.conf.erb > config/nginx.conf && - mkdir -p logs/nginx && - touch logs/nginx/access.log logs/nginx/error.log && - sudo nginx -p . -c config/nginx.conf -t + PORT=3000 erb config/nginx.conf.erb > config/nginx.conf + mkdir -p logs/nginx + nginx -p . -c config/nginx.conf -t - run: name: Start nginx command: | - mkdir -p logs/nginx && - sudo ./bin/start-nginx + mkdir -p logs/nginx + ./bin/start-nginx background: true - run: name: Wait for nginx @@ -135,9 +168,11 @@ workflows: unless: << pipeline.parameters.content-update >> jobs: - install-dependencies + - install-nginx - test: requires: - install-dependencies - build: requires: - install-dependencies + - install-nginx diff --git a/config/nginx.conf.erb b/config/nginx.conf.erb index 6e8faff7cf..06bc597d1a 100644 --- a/config/nginx.conf.erb +++ b/config/nginx.conf.erb @@ -36,6 +36,18 @@ http { map_hash_max_size 8192; map_hash_bucket_size 8192; + # Be as explicit as possible with our CORS origins. We can't use the + # `hostnames` directive as ably.com doesn't work with it + map $http_origin $cors_origin { + https://ably.com $http_origin; + https://www.ably.io $http_origin; + https://ably-dev.com $http_origin; + https://ik.imagekit.io $http_origin; + https://ably-docs.herokuapp.com $http_origin; + ~*https://website-[a-z0-9\-]*\.herokuapp\.com $http_origin; + ~*https://ably-docs-[a-z0-9\-]*\.herokuapp\.com $http_origin; + } + # Creates a map of redirects for us map $uri $redirected_url { default "none"; @@ -62,6 +74,39 @@ http { # Removes trailing slashes everywhere rewrite ^/(.*)/$ https://$host/$1 permanent; + location ~* \.json$ { + more_set_headers 'Access-Control-Allow-Origin: *'; + } + + # Optimize for pre-compiled assets scattered all over the place + location ~* \.(js|css|jpg|jpeg|gif|svg|png|woff|woff2)$ { + # expires 1y; + more_set_headers 'Cache-Control: public'; + gzip_static on; # to serve pre-gzipped version + + # Some browsers still send conditional-GET requests if there's a + # Last-Modified header or an ETag header even if they haven't + # reached the expiry date sent in the Expires header. + more_clear_headers 'Last-Modified'; + more_clear_headers 'ETag'; + + # This sets headers for our fonts to be served from any domain, and makes + # CDN access seamless. The wildcard is 'acceptable', because we restrict the + # type to font files only. + location ~* \.(woff|woff2)$ { + more_set_headers 'Access-Control-Allow-Origin: *'; + } + + # Set explicit allowed origin for svg that are requested by methods that need + # explicit headers like "fetch" + location ~* \.svg$ { + more_set_headers 'Access-Control-Allow-Origin: $cors_origin'; + } + + # Stop processing here and 404 if the asset/pack doesn't exist + break; + } + location / { try_files $uri $uri.html $uri/index.html @404; }