From d499eac3025ae522b56f8baae8da664272233b48 Mon Sep 17 00:00:00 2001 From: David Merfield Date: Tue, 18 Mar 2025 18:33:57 +0100 Subject: [PATCH 1/5] Refactor --- .github/workflows/openresty.yml | 58 +++++++++++++++++++++++---------- 1 file changed, 40 insertions(+), 18 deletions(-) diff --git a/.github/workflows/openresty.yml b/.github/workflows/openresty.yml index 66d8148187f..544202d6182 100644 --- a/.github/workflows/openresty.yml +++ b/.github/workflows/openresty.yml @@ -14,7 +14,25 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@master + - uses: actions/checkout@v4 # Update to latest version + + # Cache npm dependencies + - name: Cache npm packages + uses: actions/cache@v4 + with: + path: ~/.npm + key: ${{ runner.os }}-npm-${{ hashFiles('**/package-lock.json') }} + restore-keys: | + ${{ runner.os }}-npm- + + # Cache luarocks + - name: Cache luarocks + uses: actions/cache@v4 + with: + path: ~/.luarocks + key: ${{ runner.os }}-luarocks-${{ hashFiles('**/*.rockspec') }} + restore-keys: | + ${{ runner.os }}-luarocks- - name: Install PCRE library run: sudo apt-get install -y libpcre3 libpcre3-dev @@ -28,7 +46,7 @@ jobs: with: withLuaPath: "/usr/local/openresty/luajit/" - - name: install auto-ssl + - name: Install auto-ssl run: | which luarocks sudo /home/runner/work/Blot/Blot/.luarocks/bin/luarocks install lua-resty-auto-ssl @@ -41,14 +59,20 @@ jobs: redis-version: 6.2.6 - name: Set up Node - uses: actions/setup-node@v2 + uses: actions/setup-node@v4 # Update to latest version with: node-version: 21.7.3 + cache: 'npm' # Enable built-in npm caching - name: Install Dependencies - run: npm install + run: npm ci # Use ci instead of install for more reliable builds + + - name: Create required directories + run: | + sudo mkdir -p /var/instance-ssd/logs + mkdir -p /home/runner/work/Blot/Blot/config/openresty/data/latest - - name: build openresty config + - name: Build openresty config env: NODE_PATH: /home/runner/work/Blot/Blot/app NODE_SERVER_IP: 127.0.0.1 @@ -64,25 +88,23 @@ jobs: node config/openresty/build-config.js --skip-confirmation cat config/openresty/data/latest/openresty.conf - # run this after building config since building config will overwrite the data directory - - name: generate self-signed SSL certs + - name: Generate self-signed SSL certs run: | - mkdir -p /home/runner/work/Blot/Blot/config/openresty/data/latest - openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout /home/runner/work/Blot/Blot/config/openresty/data/latest/selfsigned.key -out /home/runner/work/Blot/Blot/config/openresty/data/latest/selfsigned.crt -subj "/C=US/ST=Oregon/L=Portland/O=Company Name/OU=Org/CN=localhost" + openssl req -x509 -nodes -days 365 -newkey rsa:2048 \ + -keyout /home/runner/work/Blot/Blot/config/openresty/data/latest/selfsigned.key \ + -out /home/runner/work/Blot/Blot/config/openresty/data/latest/selfsigned.crt \ + -subj "/C=US/ST=Oregon/L=Portland/O=Company Name/OU=Org/CN=localhost" - - name: run openresty - run: | - sudo mkdir -p /var/instance-ssd/logs - sudo /usr/local/openresty/bin/openresty -c /home/runner/work/Blot/Blot/config/openresty/data/latest/openresty.conf + - name: Run openresty + run: sudo /usr/local/openresty/bin/openresty -c /home/runner/work/Blot/Blot/config/openresty/data/latest/openresty.conf - - name: check openresty is running on port 80 + - name: Verify openresty is running run: | - curl localhost:80 + curl -f localhost:80 || (sudo cat /var/instance-ssd/logs/* && exit 1) - - name: run openresty tests + - name: Run openresty tests env: NODE_PATH: /home/runner/work/Blot/Blot/app BLOT_OPENRESTY_TEST_USER: runner BLOT_OPENRESTY_TEST_GROUP: runner - run: | - node scripts/tests config/openresty + run: node scripts/tests config/openresty \ No newline at end of file From e1e7b5f18b74bd3440256830d29a24462e654608 Mon Sep 17 00:00:00 2001 From: David Merfield Date: Tue, 18 Mar 2025 18:35:44 +0100 Subject: [PATCH 2/5] Refactor --- .github/workflows/openresty.yml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.github/workflows/openresty.yml b/.github/workflows/openresty.yml index 544202d6182..0f88add529b 100644 --- a/.github/workflows/openresty.yml +++ b/.github/workflows/openresty.yml @@ -41,6 +41,15 @@ jobs: with: openrestyVersion: "1.21.4.2" configureFlags: "--with-pcre-jit --with-ipv6 --with-http_v2_module" + skipCache: true # Skip cache temporarily to test clean installation + + # Add verification step + - name: Verify OpenResty Installation + run: | + /usr/local/openresty/bin/openresty -v || true + ls -la /usr/local/openresty || true + echo "OpenResty installation directory contents:" + find /usr/local/openresty -type f -ls || true - uses: leafo/gh-actions-luarocks@v4 with: From 194fcee528b391f60c643f456267ca4f9600c6b0 Mon Sep 17 00:00:00 2001 From: David Merfield Date: Tue, 18 Mar 2025 18:37:16 +0100 Subject: [PATCH 3/5] Refactor --- .github/workflows/openresty.yml | 33 ++++++++++++++++++++++++++------- 1 file changed, 26 insertions(+), 7 deletions(-) diff --git a/.github/workflows/openresty.yml b/.github/workflows/openresty.yml index 0f88add529b..e290c1f129e 100644 --- a/.github/workflows/openresty.yml +++ b/.github/workflows/openresty.yml @@ -37,19 +37,38 @@ jobs: - name: Install PCRE library run: sudo apt-get install -y libpcre3 libpcre3-dev - - uses: leafo/gh-actions-openresty@v1 + # Debug: Show directory structure before cleanup + - name: Debug - Show initial directory structure + run: | + pwd + ls -la + ls -la ~/.openresty || echo "No ~/.openresty directory" + ls -la /usr/local/openresty || echo "No /usr/local/openresty directory" + + # Clear previous installation + - name: Clean previous installation + run: | + sudo rm -rf ~/.openresty /usr/local/openresty + sudo mkdir -p /usr/local/openresty + sudo chown -R $USER:$USER /usr/local/openresty + + # Install OpenResty without using cache + - name: Install OpenResty + uses: leafo/gh-actions-openresty@v1 with: openrestyVersion: "1.21.4.2" configureFlags: "--with-pcre-jit --with-ipv6 --with-http_v2_module" - skipCache: true # Skip cache temporarily to test clean installation + buildCache: false - # Add verification step - - name: Verify OpenResty Installation + # Debug: Verify installation + - name: Debug - Verify OpenResty installation run: | + echo "Directory structure after installation:" + ls -la /usr/local/openresty + echo "OpenResty version:" /usr/local/openresty/bin/openresty -v || true - ls -la /usr/local/openresty || true - echo "OpenResty installation directory contents:" - find /usr/local/openresty -type f -ls || true + echo "LuaJIT directory contents:" + ls -la /usr/local/openresty/luajit || true - uses: leafo/gh-actions-luarocks@v4 with: From 66954f09a23378dc9db8b57c18486cb1672870ec Mon Sep 17 00:00:00 2001 From: David Merfield Date: Wed, 19 Mar 2025 18:08:24 +0100 Subject: [PATCH 4/5] Updates dockerfile and entrypoint --- proxy/Dockerfile | 47 +- proxy/cacher.lua | 384 --------- proxy/entrypoint.sh | 41 +- proxy/nginx.conf | 1888 ------------------------------------------- 4 files changed, 69 insertions(+), 2291 deletions(-) delete mode 100644 proxy/cacher.lua delete mode 100644 proxy/nginx.conf diff --git a/proxy/Dockerfile b/proxy/Dockerfile index a96498d251d..136b9720bec 100644 --- a/proxy/Dockerfile +++ b/proxy/Dockerfile @@ -1,29 +1,44 @@ -FROM openresty/openresty:alpine +FROM openresty/openresty:alpine-fat -# Install dependencies -RUN apk add --no-cache git bash curl openssl build-base +# Install dependencies with specific versions +RUN apk add --no-cache bash openssl python3 py3-pip git && \ + apk add --no-cache py3-cryptography py3-openssl -# Install lua-resty-auto-ssl -RUN /usr/local/openresty/luajit/bin/luarocks install lua-resty-auto-ssl +# Install acme-nginx and create wrapper script +RUN pip3 install --no-cache-dir acme-nginx pyOpenSSL cryptography --break-system-packages && \ + echo '#!/usr/bin/env python3' > /usr/local/bin/acme-nginx && \ + echo 'from acme_nginx.client import main' >> /usr/local/bin/acme-nginx && \ + echo 'if __name__ == "__main__":' >> /usr/local/bin/acme-nginx && \ + echo ' main()' >> /usr/local/bin/acme-nginx && \ + chmod +x /usr/local/bin/acme-nginx + +# Verify acme-nginx installation +RUN acme-nginx --help + +# Create ec2-user with a fixed UID (1000) +RUN addgroup -S ec2-user && adduser -S -u 1000 -G ec2-user ec2-user + +# Install lua-resty-auto-ssl using pre-installed LuaRocks +RUN luarocks install lua-resty-auto-ssl # Create required directories for lua-resty-auto-ssl -RUN mkdir -p /etc/resty-auto-ssl/storage -RUN mkdir -p /etc/resty-auto-ssl/letsencrypt/conf -RUN mkdir -p /etc/openresty/conf.d +RUN mkdir -p /etc/resty-auto-ssl/storage \ + /etc/resty-auto-ssl/letsencrypt/conf \ + /etc/openresty/lua /etc/ssl/private + +# Set correct permissions RUN chmod 755 /etc/resty-auto-ssl -# Copy configuration files -COPY nginx.conf /usr/local/openresty/nginx/conf/nginx.conf -COPY ssl.conf /etc/openresty/conf.d/ -COPY generate-config.js /usr/local/bin/ -COPY entrypoint.sh /entrypoint.sh +# Copy pre-built configuration files +COPY data/openresty.conf /usr/local/openresty/nginx/conf/nginx.conf +COPY data/cacher.lua /etc/openresty/lua/cacher.lua -# Make scripts executable -RUN chmod +x /usr/local/bin/generate-config.js +# Copy entrypoint script +COPY entrypoint.sh /entrypoint.sh RUN chmod +x /entrypoint.sh # Expose ports EXPOSE 80 443 # Set entrypoint -ENTRYPOINT ["/entrypoint.sh"] \ No newline at end of file +ENTRYPOINT ["/entrypoint.sh"] diff --git a/proxy/cacher.lua b/proxy/cacher.lua deleted file mode 100644 index aea1da77164..00000000000 --- a/proxy/cacher.lua +++ /dev/null @@ -1,384 +0,0 @@ -local cacher = { - _VERSION = "cacher.lua 1.0.0", - _DESCRIPTION = "Purgable cache for OpenResty", - _URL = "", - _LICENSE = "" - } - -local function cacher_add (self, host, cache_key) - local shared_dictionary = self.shared_dictionary - local cache_key_hash = ngx.md5(cache_key) - ngx.log(ngx.NOTICE, "add hash=" .. cache_key_hash .. " host=" .. host .. " key=" .. cache_key) - shared_dictionary:rpush(host, cache_key_hash) -end - -local function cacher_inspect (self, ngx) - local cache_directory = self.cache_directory - local shared_dictionary = self.shared_dictionary - - if (cache_directory == nil) then - ngx.say("please set cache_directory") - ngx.exit(ngx.OK) - end - - if (shared_dictionary == nil) then - ngx.say("please set shared_dictionary") - ngx.exit(ngx.OK) - end - - -- the host is passed in ?host=example.com - local host = ngx.var.arg_host - - if (host == nil) then - ngx.say("please pass host to inspect as an argument") - ngx.exit(ngx.OK) - end - - ngx.log(ngx.NOTICE, "inspecting host: " .. host) - - local hash_list = {}; - local total_keys = shared_dictionary:llen(host) - - ngx.log(ngx.NOTICE, "found cache keys: " .. total_keys) - - local cache_key_hash = shared_dictionary:lpop(host) - - while cache_key_hash do - table.insert(hash_list, cache_key_hash) - cache_key_hash = shared_dictionary:lpop(host) - end - - -- reinstate the keys in the list - for _, hash in ipairs(hash_list) do - shared_dictionary:rpush(host, hash) - end - - -- append the list of cache keys to the message seperated by newlines - local message = table.concat(hash_list, "\n") - - ngx.say(message) - ngx.exit(ngx.OK) -end - --- this file will read the contents of the cache directory and store them in --- the lua shared dict shared_dictionary so we can purge them later - --- I'm not sure why we need to deduplicate the keys?-- -local function deduplicate_key_list_by_host (host, shared_dict) - - ngx.log(ngx.NOTICE, "deduplicate_key_list_by_host: " .. host) - - local deduplicated_key_list = {} - - -- we lpop from the list until we get nil - local cache_key_hash = shared_dict:lpop(host) - - while cache_key_hash do - - if (deduplicated_key_list[cache_key_hash] == nil) then - table.insert(deduplicated_key_list, cache_key_hash) - deduplicated_key_list[cache_key_hash] = true - else - ngx.log(ngx.NOTICE, "duplicate hash " .. cache_key_hash) - end - - cache_key_hash = shared_dict:lpop(host) - end - - -- reinsert the keys into the list - for _, cache_key_hash in ipairs(deduplicated_key_list) do - ngx.log(ngx.NOTICE, "reinserting " .. cache_key_hash) - shared_dict:rpush(host, cache_key_hash) - end -end - -local function extractHostFromCacheFile (ngx, cache_file_path) - - -- we need to read the first line of the cache file to get the host - -- the first line is in the format: - -- KEY: http://example.com/xyz/abc - local file = io.open(cache_file_path, "r") - local first_line = file:read() - - local number_of_lines_read = 1 - - -- keep reading the file until we get a line that contains "KEY: ", up to a max of 10 lines - while (first_line ~= nil and number_of_lines_read < 10 and string.match(first_line, "KEY: ") == nil) do - first_line = file:read() - end - - if (first_line == nil) then - return nil - end - - local key = string.match(first_line, "KEY: (.*)") - - if (key == nil) then - ngx.log(ngx.NOTICE, "key is nil") - return nil - end - - -- the protocol is included in the uri so we need to remove it - local uri_without_protocol = string.match(key, "://(.*)") - - if (uri_without_protocol == nil) then - return nil - end - - -- the host is the first part of the uri, up to question mark or slash or colon if there is one - local host = string.match(uri_without_protocol, "([^/?#:]+)") - - if (host == nil) then - return nil - end - - file:close() - - return host -end - --- returns a list of file or directory names in the given directory -local function readdirectory(directory) - local i, t, popen = 0, {}, io.popen - local pfile = popen('ls -a "'..directory..'"') - - -- we want to skip the lines that are . or .. - for filename in pfile:lines() do - if (filename ~= "." and filename ~= "..") then - i = i + 1 - ngx.log(ngx.NOTICE, "found file: " .. filename) - t[i] = filename - end - end - - pfile:close() - return t -end - - -local function cacher_rehydrate (self) - - -- we need to read the contents of the cache directory and store them in - -- the lua shared dict shared_dictionary so we can purge them later - local cache_directory = self.cache_directory - - -- local purged_files = purge_host(ngx.var.arg_host) - local shared_dictionary = self.shared_dictionary - - local message = '' - - ngx.log(ngx.NOTICE, "rehydrate: " .. cache_directory ) - - -- first we list all the top level directories in the cache directory - local top_level_directories = readdirectory(cache_directory) - - -- store a list of hosts - local hosts = {} - - -- then for each directory we list all the files in that directory - for _, top_level_directory in ipairs(top_level_directories) do - - local top_level_directory_path = cache_directory .. "/" .. top_level_directory - local second_level_directories = readdirectory(top_level_directory_path) - - for _, second_level_directory in ipairs(second_level_directories) do - local second_level_directory_path = top_level_directory_path .. "/" .. second_level_directory - local files = readdirectory(second_level_directory_path) - - for _, cache_key_hash in ipairs(files) do - local cache_file_path = top_level_directory .. "/" .. second_level_directory .. "/" .. cache_key_hash - local host = extractHostFromCacheFile(ngx, second_level_directory_path .. "/" .. cache_key_hash) - - - -- if the host was not parsed, log the file - if (host == nil) then - ngx.log(ngx.NOTICE, "rehydrate: failed to parse host: " .. cache_file_path) - message = message .. cache_file_path .. "\n" - else - -- add the host to the list of hosts - if (hosts[host] == nil) then - table.insert(hosts, host) - hosts[host] = true - end - - ngx.log(ngx.NOTICE, "rehydrate: adding FILE=" .. cache_key_hash .. " HOST=" .. host ) - shared_dictionary:rpush(host, cache_key_hash) - end - end - end - end - - for _, host in ipairs(hosts) do - deduplicate_key_list_by_host(host, shared_dictionary) - end - - ngx.log(ngx.NOTICE, "rehydrate: complete") - - if (message == '') then - message = "OK" - end - - return message -end - -local function cacher_purge (self, ngx) - - local cache_directory = self.cache_directory - local shared_dictionary = self.shared_dictionary - - local message = '' - - if (cache_directory == nil) then - ngx.say("please set cache_directory") - ngx.exit(ngx.OK) - end - - if (shared_dictionary == nil) then - ngx.say("please set shared_dictionary") - ngx.exit(ngx.OK) - end - - -- prevent an error if the args are nil - if (ngx.var.args == nil) then - ngx.say("please pass host to purge as an argument") - ngx.exit(ngx.OK) - end - - for host in string.gmatch(ngx.var.args, "host=([^&]+)") do - ngx.log(ngx.NOTICE, "purging host: " .. host) - local total_keys = purge_host(host, shared_dictionary, cache_directory) - message = message .. host .. ": " .. total_keys .. "\n" - end - - -- if message is empty then replace it with a message saying that no hosts were purged - if (message == '') then - message = "no hosts were purged" - end - - ngx.say(message) - ngx.exit(ngx.OK) -end - -function purge_host (host, shared_dictionary, cache_directory) - local total_keys = shared_dictionary:llen(host) - local cache_key_hash = shared_dictionary:lpop(host) - while cache_key_hash do - -- the cache file path is in the following format: $x/$y/$cache_key_hash - -- where x is the last character of the cache_key_hash - -- and y are the two characters before x - local x = cache_key_hash:sub(-1) - local y = cache_key_hash:sub(-3,-2) - local cached_file_path = cache_directory .. "/" .. x .. "/" .. y .. "/" .. cache_key_hash - local f = io.open(cached_file_path, "r") - - if f ~= nil then - io.close(f) - os.remove(cached_file_path) - end - - cache_key_hash = shared_dictionary:lpop(host) - end - - return total_keys -end - -function purge_lru_hosts (self) - -- returns all the keys in the dictionary, the least recently used at the very end of the list - local hosts = self.shared_dictionary:get_keys(0) - local maximum_hosts_to_purge = 500 - - -- we want to create a list of hosts that we can purge from the end of the list of hosts - local number_of_hosts_purged = 0 - - -- we want to purge the least recently used hosts first - for i = #hosts, 1, -1 do - local host = hosts[i] - purge_host(host, self.shared_dictionary, self.cache_directory) - number_of_hosts_purged = number_of_hosts_purged + 1 - if (number_of_hosts_purged >= maximum_hosts_to_purge) then - break - end - end -end - -function cacher_check_free_space (self, ngx) - local minimum_free_space = self.minimum_free_space - - -- if minimum_free_space is not nil then we need to check if we need to purge the lru hosts - if (minimum_free_space ~= nil) then - local free_space = self.shared_dictionary:free_space() - - if (free_space < minimum_free_space) then - ngx.log(ngx.NOTICE, "dictionary_free_space=" .. free_space .. " is less than " .. minimum_free_space .. ", purging lru hosts") - purge_lru_hosts(self) - ngx.log(ngx.NOTICE, "purge of lru hosts complete") - else - ngx.log(ngx.NOTICE, "dictionary_free_space=" .. free_space .. " is greater than " .. minimum_free_space .. ", no need to purge lru hosts") - end - end -end - -function cacher_monitor_free_space (self, ngx, monitor_interval) - - if (monitor_interval == nil) then - monitor_interval = 60 - end - - ngx.timer.every(monitor_interval, function (premature) - if premature then - return - end - - -- if both cache_directory and shared_dictionary are set then we can rehydrate - if (self.shared_dictionary ~= nil) then - local free_space = self.shared_dictionary:free_space() - - local capacity = self.shared_dictionary:capacity() - - -- calculate the memory usage in megabytes, rounded down - local usage = math.floor((capacity - free_space) / 1024 / 1024) - local free_space_mb = math.floor(free_space / 1024 / 1024) - - -- retrieve the disk usage of the cache directory - local cache_directory = self.cache_directory - local handle = io.popen("du -sh " .. cache_directory) - local output = handle:read('*a') - - if (output == nil) then - output = "n/a" - else - output = string.match(output, "([^\t]+)") - end - - handle:close() - ngx.log(ngx.NOTICE, "dictionary_usage=" .. usage .. "M disk_usage=" .. output .. " dictionary_free_space=" .. free_space_mb .. "M") - - cacher_check_free_space(self, ngx) - end - end, self) -end - ---- Create a new cacher instance. -function cacher.new() - - local function cacher_set(self, key, value) - self[key] = value - - -- if both cache_directory and shared_dictionary are set then we can rehydrate - if (self.cache_directory ~= nil and self.shared_dictionary ~= nil) then - cacher_rehydrate(self) - end - end - - return { - purge = cacher_purge, - set = cacher_set, - add = cacher_add, - inspect = cacher_inspect, - rehydrate = cacher_rehydrate, - monitor_free_space = cacher_monitor_free_space, - check_free_space = cacher_check_free_space - } -end - -return cacher \ No newline at end of file diff --git a/proxy/entrypoint.sh b/proxy/entrypoint.sh index ac4055f49e5..1abf9217b8e 100644 --- a/proxy/entrypoint.sh +++ b/proxy/entrypoint.sh @@ -1,8 +1,43 @@ #!/bin/bash set -e -# Generate OpenResty configuration using your JavaScript generator -node /usr/local/bin/generate-config.js +CERT_PATH="/etc/ssl/private/letsencrypt-domain.pem" +KEY_PATH="/etc/ssl/private/letsencrypt-domain.key" + +# Enable staging mode if USE_STAGING is set to "true" +STAGING_FLAG="" +if [[ "$USE_STAGING" == "true" ]]; then + echo "Using Let's Encrypt staging environment" + STAGING_FLAG="--staging" +fi + +# Ensure BLOT_HOST is set +echo "BLOT_HOST=$BLOT_HOST" + +# Check if AWS credentials are set +if [[ -n "$AWS_ACCESS_KEY_ID" && -n "$AWS_SECRET_ACCESS_KEY" && -n "$AWS_REGION" ]]; then + echo "AWS credentials detected. Using DNS challenge for wildcard certificate." + DNS_PROVIDER="--dns-provider route53" + DOMAIN="-d *.$BLOT_HOST" +else + echo "AWS credentials not found. Falling back to HTTP challenge for single-domain certificate." + DNS_PROVIDER="" + DOMAIN="-d $BLOT_HOST" +fi + +# Generate SSL certificate if not present +if [[ ! -f "$CERT_PATH" || ! -f "$KEY_PATH" ]]; then + echo "Generating SSL certificate for $DOMAIN..." + acme-nginx \ + $DNS_PROVIDER \ + $DOMAIN \ + -o "$CERT_PATH" \ + --domain-private-key "$KEY_PATH" \ + $STAGING_FLAG + echo "Certificate generated successfully." +else + echo "Certificate already exists. Skipping generation." +fi # Start OpenResty -exec /usr/local/openresty/bin/openresty -g "daemon off;" +exec /usr/local/openresty/bin/openresty -g "daemon off;" \ No newline at end of file diff --git a/proxy/nginx.conf b/proxy/nginx.conf deleted file mode 100644 index 0055d021c95..00000000000 --- a/proxy/nginx.conf +++ /dev/null @@ -1,1888 +0,0 @@ - - -# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -# !!!!!!!!!!! WARNING !!!!!!!!!!! -# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - -# Do not edit this file directly - -# This file was generated by ../build.js -# Please update the source files in ./conf and run ../build.js - -# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! -# !!!!!!!!!!! WARNING !!!!!!!!!!! -# !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! - -user ec2-user ec2-user; ## Default: nobody - -worker_processes 2; - -# Defines the scheduling priority for worker processes like it is done by the nice command: -# a negative number means higher priority. Allowed range normally varies from -20 to 20. -worker_priority -20; - -# Sets the limit of the maximum number of open files (RLIMIT_NOFILE) -# for worker processes -worker_rlimit_nofile 10000; - -events { - worker_connections 10000; - multi_accept on; -} -http { - - log_format access_log_format '[$time_local] $request_id $status $request_time $request_length:$bytes_sent $scheme://$host$request_uri cache=$sent_http_blot_cache'; - - error_log /var/instance-ssd/logs/error.log info; - access_log /var/instance-ssd/logs/access.log access_log_format; - - # Hide the nginx version in the server header - server_tokens off; - - # Added to set the content-type charset header - # for text files served by NGINX - charset utf-8; - - # Taken from - # https://github.com/h5bp/server-configs-nginx/blob/master/mime.types - - types { - - # Data interchange - - application/atom+xml atom; - application/json json map topojson; - application/ld+json jsonld; - application/rss+xml rss; - application/vnd.geo+json geojson; - application/xml rdf xml; - - - # JavaScript - - # Normalize to standard type. - # https://tools.ietf.org/html/rfc4329#section-7.2 - application/javascript js jsgzip; - - - # Manifest files - - application/manifest+json webmanifest; - application/x-web-app-manifest+json webapp; - text/cache-manifest appcache; - - - # Media files - - audio/midi mid midi kar; - audio/mp4 aac f4a f4b m4a; - audio/mpeg mp3; - audio/ogg oga ogg opus; - audio/x-realaudio ra; - audio/x-wav wav; - image/bmp bmp; - image/gif gif; - image/jpeg jpeg jpg; - image/jxr jxr hdp wdp; - image/png png; - image/svg+xml svg svggzip; - image/tiff tif tiff; - image/vnd.wap.wbmp wbmp; - image/webp webp; - image/x-jng jng; - video/3gpp 3gp 3gpp; - video/mp4 f4p f4v m4v mp4; - video/mpeg mpeg mpg; - video/ogg ogv; - video/quicktime mov; - video/webm webm; - video/x-flv flv; - video/x-mng mng; - video/x-ms-asf asf asx; - video/x-ms-wmv wmv; - video/x-msvideo avi; - - # Serving `.ico` image files with a different media type - # prevents Internet Explorer from displaying then as images: - # https://github.com/h5bp/html5-boilerplate/commit/37b5fec090d00f38de64b591bcddcb205aadf8ee - - image/x-icon cur ico; - - - # Microsoft Office - - application/msword doc; - application/vnd.ms-excel xls; - application/vnd.ms-powerpoint ppt; - application/vnd.openxmlformats-officedocument.wordprocessingml.document docx; - application/vnd.openxmlformats-officedocument.spreadsheetml.sheet xlsx; - application/vnd.openxmlformats-officedocument.presentationml.presentation pptx; - - - # Web fonts - - application/font-woff woff; - application/font-woff2 woff2; - application/vnd.ms-fontobject eot; - - # Browsers usually ignore the font media types and simply sniff - # the bytes to figure out the font type. - # https://mimesniff.spec.whatwg.org/#matching-a-font-type-pattern - # - # However, Blink and WebKit based browsers will show a warning - # in the console if the following font types are served with any - # other media types. - - application/x-font-ttf ttc ttf; - font/opentype otf; - - - # Other - - application/java-archive ear jar war; - application/mac-binhex40 hqx; - application/octet-stream bin deb dll dmg exe img iso msi msm msp safariextz; - application/pdf pdf; - application/postscript ai eps ps; - application/rtf rtf; - application/vnd.google-earth.kml+xml kml; - application/vnd.google-earth.kmz kmz; - application/vnd.wap.wmlc wmlc; - application/x-7z-compressed 7z; - application/x-bb-appworld bbaw; - application/x-bittorrent torrent; - application/x-chrome-extension crx; - application/x-cocoa cco; - application/x-java-archive-diff jardiff; - application/x-java-jnlp-file jnlp; - application/x-makeself run; - application/x-opera-extension oex; - application/x-perl pl pm; - application/x-pilot pdb prc; - application/x-rar-compressed rar; - application/x-redhat-package-manager rpm; - application/x-sea sea; - application/x-shockwave-flash swf; - application/x-stuffit sit; - application/x-tcl tcl tk; - application/x-x509-ca-cert crt der pem; - application/x-xpinstall xpi; - application/xhtml+xml xhtml; - application/xslt+xml xsl; - application/zip zip; - text/css css cssgzip; - text/csv csv; - text/html htm html shtml htmlgzip; - text/markdown md; - text/mathml mml; - text/plain txt; - text/vcard vcard vcf; - text/vnd.rim.location.xloc xloc; - text/vnd.sun.j2me.app-descriptor jad; - text/vnd.wap.wml wml; - text/vtt vtt; - text/x-component htc; - - } - - open_file_cache max=1000 inactive=3600s; - open_file_cache_valid 60s; - open_file_cache_min_uses 1; - open_file_cache_errors on; - - # do we get better performance if we disable this feature - # rather than resending the entire file? - # if_modified_since off; - - sendfile on; - sendfile_max_chunk 1m; - - tcp_nopush on; - tcp_nodelay on; - - gzip on; - gzip_types text/plain text/xml text/css - text/comma-separated-values - application/javascript - text/javascript application/x-javascript - application/atom+xml; - - lua_package_path '/home/ec2-user/openresty/?.lua;;'; - - # The "auto_ssl" shared dict should be defined with enough storage space to - # hold your certificate data. 1MB of storage holds certificates for - # approximately 100 separate domains. Note that this should not cause an - # error if there are too many domains, just that nginx will have to look - # up the certificate in the database which is slower. - # 100mb = 10,000 domains - lua_shared_dict auto_ssl 100m; - - # The "auto_ssl" shared dict is used to temporarily store various settings - # like the secret used by the hook server on port 8999. Do not change or omit. - lua_shared_dict auto_ssl_settings 64k; - - # A DNS resolver must be defined for OCSP stapling to function. - # - # This example uses Google's DNS server. You may want to use your system's - # default DNS servers, which can be found in /etc/resolv.conf. If your network - # is not IPv6 compatible, you may wish to disable IPv6 results by using the - # "ipv6=off" flag (like "resolver 8.8.8.8 ipv6=off"). - # https://github.com/auto-ssl/lua-resty-auto-ssl/issues/12#issuecomment-259402817 - # found by running cat /etc/resolv.conf and looking for the nameserver value - resolver 8.8.8.8 ipv6=off; - - # Internal server running on port 8999 for handling certificate tasks. - server { - - listen 127.0.0.1:8999; - - # Increase the body buffer size, to ensure the internal POSTs can always - # parse the full POST contents into memory. - client_body_buffer_size 128k; - client_max_body_size 128k; - - location / { - content_by_lua_block { - auto_ssl:hook_server() - } - } - } - - init_by_lua_block { - - cacher = (require "cacher").new() - cacher:set("cache_directory", "/var/instance-ssd/cache") - cacher:set("shared_dictionary", ngx.shared.cacher_dictionary) - cacher:set("minimum_free_space", 1024 * 1024 * 2) - - auto_ssl = (require "resty.auto-ssl").new() - - local redis = require "resty.redis" - - local redis_options = { host = "172.30.0.138", port = 6379 , prefix = "ssl" } - - local function get_redis_instance(redis_options) - - local instance = ngx.ctx.auto_ssl_redis_instance - - if instance then - return instance - end - - instance = redis:new() - - local ok, err - - if redis_options["socket"] then - ok, err = instance:connect(redis_options["socket"]) - else - ok, err = instance:connect(redis_options["host"], redis_options["port"]) - end - - if not ok then - return false, err - end - - if redis_options["auth"] then - ok, err = instance:auth(redis_options["auth"]) - if not ok then - return false, err - end - end - - ngx.ctx.auto_ssl_redis_instance = instance - return instance - end - - auto_ssl:set("redis", redis_options) - - -- Certificates are stored in redis - auto_ssl:set("storage_adapter", "resty.auto-ssl.storage_adapters.redis") - - -- This function determines whether the incoming domain - -- should automatically issue a new SSL certificate. - -- I need to set domain:blot.im to foo in the database so that - -- the allow_domain function works as expected even though - -- it's not technically a user's domain - - local function allow_domain(domain) - - local certstorage = auto_ssl.storage - - local fullchain_pem, privkey_pem = certstorage:get_cert(domain) - - -- If we have this cert in the memory cache - -- then return it without checking redis to save time - if fullchain_pem then - return true - end - - local redis_instance, instance_err = get_redis_instance(redis_options) - - if instance_err then - return nil, instance_err - end - - local res, err = redis_instance:get('domain:' .. domain) - - if res == ngx.null then - return false - end - - return true - end - - auto_ssl:set("allow_domain", allow_domain) - - auto_ssl:init() - } - - init_worker_by_lua_block { - auto_ssl:init_worker() - if ngx.worker.id() == 0 then - cacher:monitor_free_space(ngx) - end - } - # Make sure this directory exists - # It does not need to be owned by root - # https://serverfault.com/questions/1029358/nginx-keys-zone-size-persistence-and-maximum-number-of-files - # 1m = ~8000 items - # I believe the nginx memory cache does not need to be as large as cacher_dictionary because it can fall back - # to disk in an elegant way - proxy_cache_path /var/instance-ssd/cache levels=1:2 keys_zone=PROXY_CACHE:30m inactive=1y max_size=200g use_temp_path=off; - - lua_shared_dict cacher_dictionary 75m; - - upstream blot_node { - # Use least connections algorithm to better distribute load - least_conn; - # Activates the cache for connections to upstream servers. - keepalive 120; - - # We use the default fail_timeout=10s and max_fails=1 since - # there is a backup server which should never be marked as - # unavailable using the max_fails=0 directive - server 127.0.0.1:8089; # blot-container-green MASTER server - server 127.0.0.1:8088 backup max_fails=0; # blot-container-blue FAILOVER server - } - - upstream blot_blogs_node { - # Use least connections algorithm to better distribute load - least_conn; - # Activates the cache for connections to upstream servers. - keepalive 120; - - # We use the default fail_timeout=10s and max_fails=1 since - # there is a backup server which is never marked as unavailable - # We bias traffic to one container slightly so if there is a memory - # leak both containers do not go down close together - server 127.0.0.1:8090 weight=4; # blot-container-yellow - server 127.0.0.1:8091 weight=3; # blot-container-purple - server 127.0.0.1:8088 backup max_fails=0; # blot-container-blue FAILOVER server - } - - - upstream blot_stats { - server 127.0.0.1:19999; - } - # blot subdomains (e.g. david.blot.im) - server { - listen 80; - listen 443 ssl; - - http2 on; - - # match all subdomains of blot.im which do not start with preview- - # e.g. blog-on-david.blot.im - server_name "~^(?!preview-)[^.]+\.blot.im$"; - - # Check with the SSL evaluator tool - ssl_protocols TLSv1.2 TLSv1.3; - ssl_prefer_server_ciphers off; - ssl_ciphers "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384"; - - # Hopefully improves performance - # one megabyte can store about 4000 sessions - # 10m = 40,000 sessions - ssl_session_cache shared:SSL:10m; - ssl_session_timeout 1h; - ssl_session_tickets off; - - # Add OCSP stapling if your cert supports it - ssl_stapling on; - ssl_stapling_verify on; - - # The SSL certificate we use is generated by https://github.com/kshcherban/acme-nginx - # for the "*.blot.im" and "blot.im" domains. This allows us to do an infinite - # number of subdomains for previewing templates. The paths to these files are - # hardcoded in the source for kshcherban/acme-nginx. I wrote more about this - # process in notes/wildcard-ssl - ssl_certificate /etc/ssl/private/letsencrypt-domain.pem; - ssl_certificate_key /etc/ssl/private/letsencrypt-domain.key; - - set $upstream_server blot_blogs_node; - root /; - - # Match urls which start with /draft/stream/ - location /draft/stream/ { - proxy_pass http://blot_node; - proxy_read_timeout 24h; - proxy_send_timeout 24h; - proxy_connect_timeout 24h; - - # SSE-specific configurations - proxy_http_version 1.1; # SSE requires HTTP/1.1 - proxy_set_header Connection ''; # Disable keep-alive - proxy_buffering off; # Disable response buffering - proxy_cache off; # Ensure no caching - - # generic - 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_set_header X-Forwarded-Proto $scheme; - proxy_set_header X-Request-ID $request_id; - } - - # This is used to determine whether the server is handling - # requests, don't remove it unless you change monit.rc too! - location = /health { - return 200; - } - - # This is used to prevent people from accessing the git repositories in user folders - location ^~ /.git { - return 404; - } - - # return 404 immediately for all requests to URLs ending in .php, .asp, .aspx, .jsp, .php5, .php7, .php8 - location ~* \.(?:php[0-9]?|asp|aspx|jsp)$ { - return 404; - } - - # return 404 immediate for /.vscode/sftp.json - location = /.vscode/sftp.json { - return 404; - } - - location = /sftp-config.json { - return 404; - } - - location = /magento_version { - return 404; - } - - # return 404 immediately for all requests to URLs starting with /api/v1 - location ~* ^/api/v1 { - return 404; - } - - location ~* ^/api/collections/ { - return 404; - } - - location ~* ^/vendor/phpunit/ { - return 404; - } - - # return 404 for all URLS starting with /admin/controller/extension/extension - location ~* ^/admin/controller/extension/extension { - return 404; - } - - # return 404 immediately for all requests to URLs starting with /admin/.git/ - location ~* ^/admin/.git { - return 404; - } - - # return 404 immediately for all requests containing 'index.php/' or 'admin.php/' anywhere in their path - location ~* (?:index|admin)\.php/ { - return 404; - } - - # return 404 immediately for all requests to URLs ending in .env - location ~* \.env$ { - return 404; - } - - # return 404 immediately for all requests to URLs containing '/wp-admin/', '/wp-content/', '/wp-includes/' anywhere in their path - location ~* wp-(?:admin|content|includes|diambar|json|config) { - return 404; - } - - # bypass the cache for requests to /random - # todo: handle this with headers instead of a separate location block - location = /random { - add_header 'Blot-Server' 'us' always; - add_header 'Blot-Cache' $upstream_cache_status always; - add_header 'Blot-Upstream' $upstream_addr always; - - proxy_pass http://$upstream_server; - proxy_http_version 1.1; - - 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_set_header X-Forwarded-Proto $scheme; - proxy_set_header X-Request-ID $request_id; - proxy_set_header Upgrade $http_upgrade; - proxy_set_header Connection $http_connection; # Use $http_connection for better dynamic handling - # We let nginx handle the compression - proxy_set_header Accept-Encoding ""; - - gzip on; - gzip_types text/plain text/css application/json application/javascript application/x-javascript text/xml application/xml application/xml+rss text/javascript; - gzip_comp_level 6; - gzip_proxied any; - - # For larger responses (blog posts, content-heavy pages) - # Configured for 2MB total buffer size - proxy_buffers 32 64k; # 2MB total (32 * 64k = 2048k) - proxy_buffer_size 64k; - - proxy_redirect off; - - proxy_intercept_errors on; - error_page 500 502 503 504 429 /error-upstream-offline.html; - - # Enable retrying the next upstream on failure - # Important to limit the number of tries and possibly - # the timeout otherwise a single request which triggers an error could take down all the servers - # We do rolling deploys where one server is taken down at a time so this should allow - # a failover in that case. Expensive or bug-triggering requests should consistently failwhale - # You have to be careful that these error codes are only returned when the server is truly - # unavailable – I ran into a nasty bug where a request that should have lead to a 404 was return - # a 500 error code, and this config considered the upstream server bad! - proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504; - proxy_next_upstream_tries 1; - proxy_next_upstream_timeout 10s; - - # Fine-tune timeouts for better failover - proxy_connect_timeout 3s; # Time to establish a connection to the upstream - proxy_send_timeout 10s; # Time to send the request to the upstream - proxy_read_timeout 15s; # Time to read the response from the upstream - } - - # error page for when node server is unavailable - location = /error-upstream-offline.html { - root /home/ec2-user/openresty/html; - try_files /error-upstream-offline-blog.html =404; - } - - location / { - set $cache_key $scheme://$host$request_uri; - - open_file_cache off; - - proxy_cache PROXY_CACHE; - - # https://cassiomolin.com/2016/09/09/which-http-status-codes-are-cacheable/ - proxy_cache_valid 200 301 302 400 404 1y; - - # we want to cache everything, even if cache-control says not to - # it's important to ignore the vary header from upstream otherwise - # nginx will cache multiple copies of the same page - proxy_ignore_headers Cache-Control Expires Set-Cookie Vary; - - proxy_cache_key $cache_key; - proxy_cache_use_stale error timeout invalid_header updating http_500 http_502 http_503 http_504; - - add_header 'Blot-Server' 'us' always; - add_header 'Blot-Cache' $upstream_cache_status always; - add_header 'Blot-Upstream' $upstream_addr always; - - proxy_pass http://$upstream_server; - proxy_http_version 1.1; - - 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_set_header X-Forwarded-Proto $scheme; - proxy_set_header X-Request-ID $request_id; - proxy_set_header Upgrade $http_upgrade; - proxy_set_header Connection $http_connection; # Use $http_connection for better dynamic handling - # We let nginx handle the compression - proxy_set_header Accept-Encoding ""; - - gzip on; - gzip_types text/plain text/css application/json application/javascript application/x-javascript text/xml application/xml application/xml+rss text/javascript; - gzip_comp_level 6; - gzip_proxied any; - - # For larger responses (blog posts, content-heavy pages) - # Configured for 2MB total buffer size - proxy_buffers 32 64k; # 2MB total (32 * 64k = 2048k) - proxy_buffer_size 64k; - - proxy_redirect off; - - proxy_intercept_errors on; - error_page 500 502 503 504 429 /error-upstream-offline.html; - - # Enable retrying the next upstream on failure - # Important to limit the number of tries and possibly - # the timeout otherwise a single request which triggers an error could take down all the servers - # We do rolling deploys where one server is taken down at a time so this should allow - # a failover in that case. Expensive or bug-triggering requests should consistently failwhale - # You have to be careful that these error codes are only returned when the server is truly - # unavailable – I ran into a nasty bug where a request that should have lead to a 404 was return - # a 500 error code, and this config considered the upstream server bad! - proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504; - proxy_next_upstream_tries 1; - proxy_next_upstream_timeout 10s; - - # Fine-tune timeouts for better failover - proxy_connect_timeout 3s; # Time to establish a connection to the upstream - proxy_send_timeout 10s; # Time to send the request to the upstream - proxy_read_timeout 15s; # Time to read the response from the upstream - - # This registers a cached response in our dictionary of cached responses - # pass in the proxy_cache_key setting - log_by_lua_block { - if ngx.var.upstream_cache_status == "MISS" then - cacher:add(ngx.var.host, ngx.var.cache_key) - end - } } - - } - - # preview subdomains (e.g. preview-of-blog-on-david.blot.im) - # these skip the cache and are passed directly to node - server { - listen 80; - listen 443 ssl; - - http2 on; - - server_name "~^preview-[^.]+\.blot.im$"; - - # Check with the SSL evaluator tool - ssl_protocols TLSv1.2 TLSv1.3; - ssl_prefer_server_ciphers off; - ssl_ciphers "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384"; - - # Hopefully improves performance - # one megabyte can store about 4000 sessions - # 10m = 40,000 sessions - ssl_session_cache shared:SSL:10m; - ssl_session_timeout 1h; - ssl_session_tickets off; - - # Add OCSP stapling if your cert supports it - ssl_stapling on; - ssl_stapling_verify on; - - # The SSL certificate we use is generated by https://github.com/kshcherban/acme-nginx - # for the "*.blot.im" and "blot.im" domains. This allows us to do an infinite - # number of subdomains for previewing templates. The paths to these files are - # hardcoded in the source for kshcherban/acme-nginx. I wrote more about this - # process in notes/wildcard-ssl - ssl_certificate /etc/ssl/private/letsencrypt-domain.pem; - ssl_certificate_key /etc/ssl/private/letsencrypt-domain.key; - location / { - set $upstream_server blot_blogs_node; - add_header 'Blot-Server' 'us' always; - add_header 'Blot-Cache' $upstream_cache_status always; - add_header 'Blot-Upstream' $upstream_addr always; - - proxy_pass http://$upstream_server; - proxy_http_version 1.1; - - 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_set_header X-Forwarded-Proto $scheme; - proxy_set_header X-Request-ID $request_id; - proxy_set_header Upgrade $http_upgrade; - proxy_set_header Connection $http_connection; # Use $http_connection for better dynamic handling - # We let nginx handle the compression - proxy_set_header Accept-Encoding ""; - - gzip on; - gzip_types text/plain text/css application/json application/javascript application/x-javascript text/xml application/xml application/xml+rss text/javascript; - gzip_comp_level 6; - gzip_proxied any; - - # For larger responses (blog posts, content-heavy pages) - # Configured for 2MB total buffer size - proxy_buffers 32 64k; # 2MB total (32 * 64k = 2048k) - proxy_buffer_size 64k; - - proxy_redirect off; - - proxy_intercept_errors on; - error_page 500 502 503 504 429 /error-upstream-offline.html; - - # Enable retrying the next upstream on failure - # Important to limit the number of tries and possibly - # the timeout otherwise a single request which triggers an error could take down all the servers - # We do rolling deploys where one server is taken down at a time so this should allow - # a failover in that case. Expensive or bug-triggering requests should consistently failwhale - # You have to be careful that these error codes are only returned when the server is truly - # unavailable – I ran into a nasty bug where a request that should have lead to a 404 was return - # a 500 error code, and this config considered the upstream server bad! - proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504; - proxy_next_upstream_tries 1; - proxy_next_upstream_timeout 10s; - - # Fine-tune timeouts for better failover - proxy_connect_timeout 3s; # Time to establish a connection to the upstream - proxy_send_timeout 10s; # Time to send the request to the upstream - proxy_read_timeout 15s; # Time to read the response from the upstream - } - } - - # cdn subdomain (e.g. cdn.blot.im) - # these skip the cache and are passed directly to node - server { - listen 80; - listen 443 ssl; - - http2 on; - - server_name cdn.blot.im; - - # Check with the SSL evaluator tool - ssl_protocols TLSv1.2 TLSv1.3; - ssl_prefer_server_ciphers off; - ssl_ciphers "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384"; - - # Hopefully improves performance - # one megabyte can store about 4000 sessions - # 10m = 40,000 sessions - ssl_session_cache shared:SSL:10m; - ssl_session_timeout 1h; - ssl_session_tickets off; - - # Add OCSP stapling if your cert supports it - ssl_stapling on; - ssl_stapling_verify on; - - # The SSL certificate we use is generated by https://github.com/kshcherban/acme-nginx - # for the "*.blot.im" and "blot.im" domains. This allows us to do an infinite - # number of subdomains for previewing templates. The paths to these files are - # hardcoded in the source for kshcherban/acme-nginx. I wrote more about this - # process in notes/wildcard-ssl - ssl_certificate /etc/ssl/private/letsencrypt-domain.pem; - ssl_certificate_key /etc/ssl/private/letsencrypt-domain.key; - location / { - set $upstream_server blot_blogs_node; - add_header 'Blot-Server' 'us' always; - add_header 'Blot-Cache' $upstream_cache_status always; - add_header 'Blot-Upstream' $upstream_addr always; - - proxy_pass http://$upstream_server; - proxy_http_version 1.1; - - 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_set_header X-Forwarded-Proto $scheme; - proxy_set_header X-Request-ID $request_id; - proxy_set_header Upgrade $http_upgrade; - proxy_set_header Connection $http_connection; # Use $http_connection for better dynamic handling - # We let nginx handle the compression - proxy_set_header Accept-Encoding ""; - - gzip on; - gzip_types text/plain text/css application/json application/javascript application/x-javascript text/xml application/xml application/xml+rss text/javascript; - gzip_comp_level 6; - gzip_proxied any; - - # For larger responses (blog posts, content-heavy pages) - # Configured for 2MB total buffer size - proxy_buffers 32 64k; # 2MB total (32 * 64k = 2048k) - proxy_buffer_size 64k; - - proxy_redirect off; - - proxy_intercept_errors on; - error_page 500 502 503 504 429 /error-upstream-offline.html; - - # Enable retrying the next upstream on failure - # Important to limit the number of tries and possibly - # the timeout otherwise a single request which triggers an error could take down all the servers - # We do rolling deploys where one server is taken down at a time so this should allow - # a failover in that case. Expensive or bug-triggering requests should consistently failwhale - # You have to be careful that these error codes are only returned when the server is truly - # unavailable – I ran into a nasty bug where a request that should have lead to a 404 was return - # a 500 error code, and this config considered the upstream server bad! - proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504; - proxy_next_upstream_tries 1; - proxy_next_upstream_timeout 10s; - - # Fine-tune timeouts for better failover - proxy_connect_timeout 3s; # Time to establish a connection to the upstream - proxy_send_timeout 10s; # Time to send the request to the upstream - proxy_read_timeout 15s; # Time to read the response from the upstream - } - } - - # stats subdomain - # these skip the cache and are passed directly to node - server { - listen 80; - listen 443 ssl; - http2 on; - - server_name stats.blot.im; - - # Check with the SSL evaluator tool - ssl_protocols TLSv1.2 TLSv1.3; - ssl_prefer_server_ciphers off; - ssl_ciphers "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384"; - - # Hopefully improves performance - # one megabyte can store about 4000 sessions - # 10m = 40,000 sessions - ssl_session_cache shared:SSL:10m; - ssl_session_timeout 1h; - ssl_session_tickets off; - - # Add OCSP stapling if your cert supports it - ssl_stapling on; - ssl_stapling_verify on; - - # The SSL certificate we use is generated by https://github.com/kshcherban/acme-nginx - # for the "*.blot.im" and "blot.im" domains. This allows us to do an infinite - # number of subdomains for previewing templates. The paths to these files are - # hardcoded in the source for kshcherban/acme-nginx. I wrote more about this - # process in notes/wildcard-ssl - ssl_certificate /etc/ssl/private/letsencrypt-domain.pem; - ssl_certificate_key /etc/ssl/private/letsencrypt-domain.key; - auth_basic "Protected"; - auth_basic_user_file /home/ec2-user/netdataconfig/netdata/passwords; - - # Redirect root to /v3 to avoid annoying login window - location = / { - return 301 $scheme://$host/v3/; - } - - location / { - proxy_pass http://localhost:19999; - proxy_http_version 1.1; - 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_set_header X-Forwarded-Proto $scheme; - proxy_set_header Authorization $http_authorization; - - # WebSocket support - proxy_set_header Upgrade $http_upgrade; - proxy_set_header Connection "upgrade"; - - # Timeouts - proxy_connect_timeout 60s; - proxy_send_timeout 60s; - proxy_read_timeout 60s; - } - } - - - # blot.im - server { - listen 443 ssl; - - http2 on; - - server_name blot.im; - - # Check with the SSL evaluator tool - ssl_protocols TLSv1.2 TLSv1.3; - ssl_prefer_server_ciphers off; - ssl_ciphers "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384"; - - # Hopefully improves performance - # one megabyte can store about 4000 sessions - # 10m = 40,000 sessions - ssl_session_cache shared:SSL:10m; - ssl_session_timeout 1h; - ssl_session_tickets off; - - # Add OCSP stapling if your cert supports it - ssl_stapling on; - ssl_stapling_verify on; - - # The SSL certificate we use is generated by https://github.com/kshcherban/acme-nginx - # for the "*.blot.im" and "blot.im" domains. This allows us to do an infinite - # number of subdomains for previewing templates. The paths to these files are - # hardcoded in the source for kshcherban/acme-nginx. I wrote more about this - # process in notes/wildcard-ssl - ssl_certificate /etc/ssl/private/letsencrypt-domain.pem; - ssl_certificate_key /etc/ssl/private/letsencrypt-domain.key; - set $upstream_server blot_node; - - # Match /sites/{USERNAME}/status where {USERNAME} is dynamic - location ~ ^/sites/[^/]+/status$ { - proxy_pass http://blot_node; - proxy_read_timeout 24h; - proxy_send_timeout 24h; - proxy_connect_timeout 24h; - - # SSE-specific configurations - proxy_http_version 1.1; # SSE requires HTTP/1.1 - proxy_set_header Connection ''; # Disable keep-alive - proxy_buffering off; # Disable response buffering - proxy_cache off; # Ensure no caching - - # generic - 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_set_header X-Forwarded-Proto $scheme; - proxy_set_header X-Request-ID $request_id; - } - - location = /health { - return 200; - } - - # redirect for /cdn/XYZ to cdn.blot.im/XYZ - location ~ ^/cdn/(.*)$ { - return 301 https://cdn.blot.im/$1; - } - - # bypass cache - location = /redis-health { - add_header 'Blot-Server' 'us' always; - add_header 'Blot-Cache' $upstream_cache_status always; - add_header 'Blot-Upstream' $upstream_addr always; - - proxy_pass http://$upstream_server; - proxy_http_version 1.1; - - 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_set_header X-Forwarded-Proto $scheme; - proxy_set_header X-Request-ID $request_id; - proxy_set_header Upgrade $http_upgrade; - proxy_set_header Connection $http_connection; # Use $http_connection for better dynamic handling - # We let nginx handle the compression - proxy_set_header Accept-Encoding ""; - - gzip on; - gzip_types text/plain text/css application/json application/javascript application/x-javascript text/xml application/xml application/xml+rss text/javascript; - gzip_comp_level 6; - gzip_proxied any; - - # For larger responses (blog posts, content-heavy pages) - # Configured for 2MB total buffer size - proxy_buffers 32 64k; # 2MB total (32 * 64k = 2048k) - proxy_buffer_size 64k; - - proxy_redirect off; - - proxy_intercept_errors on; - error_page 500 502 503 504 429 /error-upstream-offline.html; - - # Enable retrying the next upstream on failure - # Important to limit the number of tries and possibly - # the timeout otherwise a single request which triggers an error could take down all the servers - # We do rolling deploys where one server is taken down at a time so this should allow - # a failover in that case. Expensive or bug-triggering requests should consistently failwhale - # You have to be careful that these error codes are only returned when the server is truly - # unavailable – I ran into a nasty bug where a request that should have lead to a 404 was return - # a 500 error code, and this config considered the upstream server bad! - proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504; - proxy_next_upstream_tries 1; - proxy_next_upstream_timeout 10s; - - # Fine-tune timeouts for better failover - proxy_connect_timeout 3s; # Time to establish a connection to the upstream - proxy_send_timeout 10s; # Time to send the request to the upstream - proxy_read_timeout 15s; # Time to read the response from the upstream - } - - # bypass cache - location /sites { - client_max_body_size 100M; - add_header 'Blot-Server' 'us' always; - add_header 'Blot-Cache' $upstream_cache_status always; - add_header 'Blot-Upstream' $upstream_addr always; - - proxy_pass http://$upstream_server; - proxy_http_version 1.1; - - 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_set_header X-Forwarded-Proto $scheme; - proxy_set_header X-Request-ID $request_id; - proxy_set_header Upgrade $http_upgrade; - proxy_set_header Connection $http_connection; # Use $http_connection for better dynamic handling - # We let nginx handle the compression - proxy_set_header Accept-Encoding ""; - - gzip on; - gzip_types text/plain text/css application/json application/javascript application/x-javascript text/xml application/xml application/xml+rss text/javascript; - gzip_comp_level 6; - gzip_proxied any; - - # For larger responses (blog posts, content-heavy pages) - # Configured for 2MB total buffer size - proxy_buffers 32 64k; # 2MB total (32 * 64k = 2048k) - proxy_buffer_size 64k; - - proxy_redirect off; - - proxy_intercept_errors on; - error_page 500 502 503 504 429 /error-upstream-offline.html; - - # Enable retrying the next upstream on failure - # Important to limit the number of tries and possibly - # the timeout otherwise a single request which triggers an error could take down all the servers - # We do rolling deploys where one server is taken down at a time so this should allow - # a failover in that case. Expensive or bug-triggering requests should consistently failwhale - # You have to be careful that these error codes are only returned when the server is truly - # unavailable – I ran into a nasty bug where a request that should have lead to a 404 was return - # a 500 error code, and this config considered the upstream server bad! - proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504; - proxy_next_upstream_tries 1; - proxy_next_upstream_timeout 10s; - - # Fine-tune timeouts for better failover - proxy_connect_timeout 3s; # Time to establish a connection to the upstream - proxy_send_timeout 10s; # Time to send the request to the upstream - proxy_read_timeout 15s; # Time to read the response from the upstream - } - - # bypass cache - location /dashboard { - client_max_body_size 100M; - add_header 'Blot-Server' 'us' always; - add_header 'Blot-Cache' $upstream_cache_status always; - add_header 'Blot-Upstream' $upstream_addr always; - - proxy_pass http://$upstream_server; - proxy_http_version 1.1; - - 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_set_header X-Forwarded-Proto $scheme; - proxy_set_header X-Request-ID $request_id; - proxy_set_header Upgrade $http_upgrade; - proxy_set_header Connection $http_connection; # Use $http_connection for better dynamic handling - # We let nginx handle the compression - proxy_set_header Accept-Encoding ""; - - gzip on; - gzip_types text/plain text/css application/json application/javascript application/x-javascript text/xml application/xml application/xml+rss text/javascript; - gzip_comp_level 6; - gzip_proxied any; - - # For larger responses (blog posts, content-heavy pages) - # Configured for 2MB total buffer size - proxy_buffers 32 64k; # 2MB total (32 * 64k = 2048k) - proxy_buffer_size 64k; - - proxy_redirect off; - - proxy_intercept_errors on; - error_page 500 502 503 504 429 /error-upstream-offline.html; - - # Enable retrying the next upstream on failure - # Important to limit the number of tries and possibly - # the timeout otherwise a single request which triggers an error could take down all the servers - # We do rolling deploys where one server is taken down at a time so this should allow - # a failover in that case. Expensive or bug-triggering requests should consistently failwhale - # You have to be careful that these error codes are only returned when the server is truly - # unavailable – I ran into a nasty bug where a request that should have lead to a 404 was return - # a 500 error code, and this config considered the upstream server bad! - proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504; - proxy_next_upstream_tries 1; - proxy_next_upstream_timeout 10s; - - # Fine-tune timeouts for better failover - proxy_connect_timeout 3s; # Time to establish a connection to the upstream - proxy_send_timeout 10s; # Time to send the request to the upstream - proxy_read_timeout 15s; # Time to read the response from the upstream - } - - # bypass cache - location /questions/ask { - add_header 'Blot-Server' 'us' always; - add_header 'Blot-Cache' $upstream_cache_status always; - add_header 'Blot-Upstream' $upstream_addr always; - - proxy_pass http://$upstream_server; - proxy_http_version 1.1; - - 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_set_header X-Forwarded-Proto $scheme; - proxy_set_header X-Request-ID $request_id; - proxy_set_header Upgrade $http_upgrade; - proxy_set_header Connection $http_connection; # Use $http_connection for better dynamic handling - # We let nginx handle the compression - proxy_set_header Accept-Encoding ""; - - gzip on; - gzip_types text/plain text/css application/json application/javascript application/x-javascript text/xml application/xml application/xml+rss text/javascript; - gzip_comp_level 6; - gzip_proxied any; - - # For larger responses (blog posts, content-heavy pages) - # Configured for 2MB total buffer size - proxy_buffers 32 64k; # 2MB total (32 * 64k = 2048k) - proxy_buffer_size 64k; - - proxy_redirect off; - - proxy_intercept_errors on; - error_page 500 502 503 504 429 /error-upstream-offline.html; - - # Enable retrying the next upstream on failure - # Important to limit the number of tries and possibly - # the timeout otherwise a single request which triggers an error could take down all the servers - # We do rolling deploys where one server is taken down at a time so this should allow - # a failover in that case. Expensive or bug-triggering requests should consistently failwhale - # You have to be careful that these error codes are only returned when the server is truly - # unavailable – I ran into a nasty bug where a request that should have lead to a 404 was return - # a 500 error code, and this config considered the upstream server bad! - proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504; - proxy_next_upstream_tries 1; - proxy_next_upstream_timeout 10s; - - # Fine-tune timeouts for better failover - proxy_connect_timeout 3s; # Time to establish a connection to the upstream - proxy_send_timeout 10s; # Time to send the request to the upstream - proxy_read_timeout 15s; # Time to read the response from the upstream - } - - location ~ ^/questions/[^/]+/edit$ { - add_header 'Blot-Server' 'us' always; - add_header 'Blot-Cache' $upstream_cache_status always; - add_header 'Blot-Upstream' $upstream_addr always; - - proxy_pass http://$upstream_server; - proxy_http_version 1.1; - - 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_set_header X-Forwarded-Proto $scheme; - proxy_set_header X-Request-ID $request_id; - proxy_set_header Upgrade $http_upgrade; - proxy_set_header Connection $http_connection; # Use $http_connection for better dynamic handling - # We let nginx handle the compression - proxy_set_header Accept-Encoding ""; - - gzip on; - gzip_types text/plain text/css application/json application/javascript application/x-javascript text/xml application/xml application/xml+rss text/javascript; - gzip_comp_level 6; - gzip_proxied any; - - # For larger responses (blog posts, content-heavy pages) - # Configured for 2MB total buffer size - proxy_buffers 32 64k; # 2MB total (32 * 64k = 2048k) - proxy_buffer_size 64k; - - proxy_redirect off; - - proxy_intercept_errors on; - error_page 500 502 503 504 429 /error-upstream-offline.html; - - # Enable retrying the next upstream on failure - # Important to limit the number of tries and possibly - # the timeout otherwise a single request which triggers an error could take down all the servers - # We do rolling deploys where one server is taken down at a time so this should allow - # a failover in that case. Expensive or bug-triggering requests should consistently failwhale - # You have to be careful that these error codes are only returned when the server is truly - # unavailable – I ran into a nasty bug where a request that should have lead to a 404 was return - # a 500 error code, and this config considered the upstream server bad! - proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504; - proxy_next_upstream_tries 1; - proxy_next_upstream_timeout 10s; - - # Fine-tune timeouts for better failover - proxy_connect_timeout 3s; # Time to establish a connection to the upstream - proxy_send_timeout 10s; # Time to send the request to the upstream - proxy_read_timeout 15s; # Time to read the response from the upstream - } - - location ~ ^/questions/[^/]+/new$ { - add_header 'Blot-Server' 'us' always; - add_header 'Blot-Cache' $upstream_cache_status always; - add_header 'Blot-Upstream' $upstream_addr always; - - proxy_pass http://$upstream_server; - proxy_http_version 1.1; - - 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_set_header X-Forwarded-Proto $scheme; - proxy_set_header X-Request-ID $request_id; - proxy_set_header Upgrade $http_upgrade; - proxy_set_header Connection $http_connection; # Use $http_connection for better dynamic handling - # We let nginx handle the compression - proxy_set_header Accept-Encoding ""; - - gzip on; - gzip_types text/plain text/css application/json application/javascript application/x-javascript text/xml application/xml application/xml+rss text/javascript; - gzip_comp_level 6; - gzip_proxied any; - - # For larger responses (blog posts, content-heavy pages) - # Configured for 2MB total buffer size - proxy_buffers 32 64k; # 2MB total (32 * 64k = 2048k) - proxy_buffer_size 64k; - - proxy_redirect off; - - proxy_intercept_errors on; - error_page 500 502 503 504 429 /error-upstream-offline.html; - - # Enable retrying the next upstream on failure - # Important to limit the number of tries and possibly - # the timeout otherwise a single request which triggers an error could take down all the servers - # We do rolling deploys where one server is taken down at a time so this should allow - # a failover in that case. Expensive or bug-triggering requests should consistently failwhale - # You have to be careful that these error codes are only returned when the server is truly - # unavailable – I ran into a nasty bug where a request that should have lead to a 404 was return - # a 500 error code, and this config considered the upstream server bad! - proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504; - proxy_next_upstream_tries 1; - proxy_next_upstream_timeout 10s; - - # Fine-tune timeouts for better failover - proxy_connect_timeout 3s; # Time to establish a connection to the upstream - proxy_send_timeout 10s; # Time to send the request to the upstream - proxy_read_timeout 15s; # Time to read the response from the upstream - } - - # git and icloud client need large bodies - location /clients/git { - client_max_body_size 1000M; - add_header 'Blot-Server' 'us' always; - add_header 'Blot-Cache' $upstream_cache_status always; - add_header 'Blot-Upstream' $upstream_addr always; - - proxy_pass http://$upstream_server; - proxy_http_version 1.1; - - 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_set_header X-Forwarded-Proto $scheme; - proxy_set_header X-Request-ID $request_id; - proxy_set_header Upgrade $http_upgrade; - proxy_set_header Connection $http_connection; # Use $http_connection for better dynamic handling - # We let nginx handle the compression - proxy_set_header Accept-Encoding ""; - - gzip on; - gzip_types text/plain text/css application/json application/javascript application/x-javascript text/xml application/xml application/xml+rss text/javascript; - gzip_comp_level 6; - gzip_proxied any; - - # For larger responses (blog posts, content-heavy pages) - # Configured for 2MB total buffer size - proxy_buffers 32 64k; # 2MB total (32 * 64k = 2048k) - proxy_buffer_size 64k; - - proxy_redirect off; - - proxy_intercept_errors on; - error_page 500 502 503 504 429 /error-upstream-offline.html; - - # Enable retrying the next upstream on failure - # Important to limit the number of tries and possibly - # the timeout otherwise a single request which triggers an error could take down all the servers - # We do rolling deploys where one server is taken down at a time so this should allow - # a failover in that case. Expensive or bug-triggering requests should consistently failwhale - # You have to be careful that these error codes are only returned when the server is truly - # unavailable – I ran into a nasty bug where a request that should have lead to a 404 was return - # a 500 error code, and this config considered the upstream server bad! - proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504; - proxy_next_upstream_tries 1; - proxy_next_upstream_timeout 10s; - - # Fine-tune timeouts for better failover - proxy_connect_timeout 3s; # Time to establish a connection to the upstream - proxy_send_timeout 10s; # Time to send the request to the upstream - proxy_read_timeout 15s; # Time to read the response from the upstream - } - - location /clients/icloud { - client_max_body_size 100M; - add_header 'Blot-Server' 'us' always; - add_header 'Blot-Cache' $upstream_cache_status always; - add_header 'Blot-Upstream' $upstream_addr always; - - proxy_pass http://$upstream_server; - proxy_http_version 1.1; - - 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_set_header X-Forwarded-Proto $scheme; - proxy_set_header X-Request-ID $request_id; - proxy_set_header Upgrade $http_upgrade; - proxy_set_header Connection $http_connection; # Use $http_connection for better dynamic handling - # We let nginx handle the compression - proxy_set_header Accept-Encoding ""; - - gzip on; - gzip_types text/plain text/css application/json application/javascript application/x-javascript text/xml application/xml application/xml+rss text/javascript; - gzip_comp_level 6; - gzip_proxied any; - - # For larger responses (blog posts, content-heavy pages) - # Configured for 2MB total buffer size - proxy_buffers 32 64k; # 2MB total (32 * 64k = 2048k) - proxy_buffer_size 64k; - - proxy_redirect off; - - proxy_intercept_errors on; - error_page 500 502 503 504 429 /error-upstream-offline.html; - - # Enable retrying the next upstream on failure - # Important to limit the number of tries and possibly - # the timeout otherwise a single request which triggers an error could take down all the servers - # We do rolling deploys where one server is taken down at a time so this should allow - # a failover in that case. Expensive or bug-triggering requests should consistently failwhale - # You have to be careful that these error codes are only returned when the server is truly - # unavailable – I ran into a nasty bug where a request that should have lead to a 404 was return - # a 500 error code, and this config considered the upstream server bad! - proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504; - proxy_next_upstream_tries 1; - proxy_next_upstream_timeout 10s; - - # Fine-tune timeouts for better failover - proxy_connect_timeout 3s; # Time to establish a connection to the upstream - proxy_send_timeout 10s; # Time to send the request to the upstream - proxy_read_timeout 15s; # Time to read the response from the upstream - } - - location /clients { - client_max_body_size 100M; - add_header 'Blot-Server' 'us' always; - add_header 'Blot-Cache' $upstream_cache_status always; - add_header 'Blot-Upstream' $upstream_addr always; - - proxy_pass http://$upstream_server; - proxy_http_version 1.1; - - 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_set_header X-Forwarded-Proto $scheme; - proxy_set_header X-Request-ID $request_id; - proxy_set_header Upgrade $http_upgrade; - proxy_set_header Connection $http_connection; # Use $http_connection for better dynamic handling - # We let nginx handle the compression - proxy_set_header Accept-Encoding ""; - - gzip on; - gzip_types text/plain text/css application/json application/javascript application/x-javascript text/xml application/xml application/xml+rss text/javascript; - gzip_comp_level 6; - gzip_proxied any; - - # For larger responses (blog posts, content-heavy pages) - # Configured for 2MB total buffer size - proxy_buffers 32 64k; # 2MB total (32 * 64k = 2048k) - proxy_buffer_size 64k; - - proxy_redirect off; - - proxy_intercept_errors on; - error_page 500 502 503 504 429 /error-upstream-offline.html; - - # Enable retrying the next upstream on failure - # Important to limit the number of tries and possibly - # the timeout otherwise a single request which triggers an error could take down all the servers - # We do rolling deploys where one server is taken down at a time so this should allow - # a failover in that case. Expensive or bug-triggering requests should consistently failwhale - # You have to be careful that these error codes are only returned when the server is truly - # unavailable – I ran into a nasty bug where a request that should have lead to a 404 was return - # a 500 error code, and this config considered the upstream server bad! - proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504; - proxy_next_upstream_tries 1; - proxy_next_upstream_timeout 10s; - - # Fine-tune timeouts for better failover - proxy_connect_timeout 3s; # Time to establish a connection to the upstream - proxy_send_timeout 10s; # Time to send the request to the upstream - proxy_read_timeout 15s; # Time to read the response from the upstream - } - - # error page for when node server is unavailable - location = /error-upstream-offline.html { - root /home/ec2-user/openresty/html; - try_files /error-upstream-offline-site.html =404; - } - - location / { - set $cache_key $scheme://$host$request_uri; - - open_file_cache off; - - proxy_cache PROXY_CACHE; - - # https://cassiomolin.com/2016/09/09/which-http-status-codes-are-cacheable/ - proxy_cache_valid 200 301 302 400 404 1y; - - # we want to cache everything, even if cache-control says not to - # it's important to ignore the vary header from upstream otherwise - # nginx will cache multiple copies of the same page - proxy_ignore_headers Cache-Control Expires Set-Cookie Vary; - - proxy_cache_key $cache_key; - proxy_cache_use_stale error timeout invalid_header updating http_500 http_502 http_503 http_504; - - add_header 'Blot-Server' 'us' always; - add_header 'Blot-Cache' $upstream_cache_status always; - add_header 'Blot-Upstream' $upstream_addr always; - - proxy_pass http://$upstream_server; - proxy_http_version 1.1; - - 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_set_header X-Forwarded-Proto $scheme; - proxy_set_header X-Request-ID $request_id; - proxy_set_header Upgrade $http_upgrade; - proxy_set_header Connection $http_connection; # Use $http_connection for better dynamic handling - # We let nginx handle the compression - proxy_set_header Accept-Encoding ""; - - gzip on; - gzip_types text/plain text/css application/json application/javascript application/x-javascript text/xml application/xml application/xml+rss text/javascript; - gzip_comp_level 6; - gzip_proxied any; - - # For larger responses (blog posts, content-heavy pages) - # Configured for 2MB total buffer size - proxy_buffers 32 64k; # 2MB total (32 * 64k = 2048k) - proxy_buffer_size 64k; - - proxy_redirect off; - - proxy_intercept_errors on; - error_page 500 502 503 504 429 /error-upstream-offline.html; - - # Enable retrying the next upstream on failure - # Important to limit the number of tries and possibly - # the timeout otherwise a single request which triggers an error could take down all the servers - # We do rolling deploys where one server is taken down at a time so this should allow - # a failover in that case. Expensive or bug-triggering requests should consistently failwhale - # You have to be careful that these error codes are only returned when the server is truly - # unavailable – I ran into a nasty bug where a request that should have lead to a 404 was return - # a 500 error code, and this config considered the upstream server bad! - proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504; - proxy_next_upstream_tries 1; - proxy_next_upstream_timeout 10s; - - # Fine-tune timeouts for better failover - proxy_connect_timeout 3s; # Time to establish a connection to the upstream - proxy_send_timeout 10s; # Time to send the request to the upstream - proxy_read_timeout 15s; # Time to read the response from the upstream - - # This registers a cached response in our dictionary of cached responses - # pass in the proxy_cache_key setting - log_by_lua_block { - if ngx.var.upstream_cache_status == "MISS" then - cacher:add(ngx.var.host, ngx.var.cache_key) - end - } } - - } - - # webhooks relay at webhooks.blot.im - server { - listen 443 ssl; - http2 on; - server_name webhooks.blot.im; - - # Dynamic handler for issuing or returning certs for SNI domains. - ssl_certificate_by_lua_block { - auto_ssl:ssl_certificate() - } - - # Endpoint used for performing domain verification with Let's Encrypt. - location /.well-known/acme-challenge/ { - content_by_lua_block { - auto_ssl:challenge_server() - } - } - - # You must still define a static ssl_certificate file for nginx to start. - # The SSL certificate we use is generated by https://github.com/kshcherban/acme-nginx - # for the "*.blot.im" and "blot.im" domains. This allows us to do an infinite - # number of subdomains for previewing templates. The paths to these files are - # hardcoded in the source for kshcherban/acme-nginx. I wrote more about this - # process in notes/wildcard-ssl - # Check with the SSL evaluator tool - ssl_protocols TLSv1.2 TLSv1.3; - ssl_prefer_server_ciphers off; - ssl_ciphers "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384"; - - # Hopefully improves performance - # one megabyte can store about 4000 sessions - # 10m = 40,000 sessions - ssl_session_cache shared:SSL:10m; - ssl_session_timeout 1h; - ssl_session_tickets off; - - # Add OCSP stapling if your cert supports it - ssl_stapling on; - ssl_stapling_verify on; - - # The SSL certificate we use is generated by https://github.com/kshcherban/acme-nginx - # for the "*.blot.im" and "blot.im" domains. This allows us to do an infinite - # number of subdomains for previewing templates. The paths to these files are - # hardcoded in the source for kshcherban/acme-nginx. I wrote more about this - # process in notes/wildcard-ssl - ssl_certificate /etc/ssl/private/letsencrypt-domain.pem; - ssl_certificate_key /etc/ssl/private/letsencrypt-domain.key; - location / { - # the icloud relay needs to handle large file uploads - client_max_body_size 100M; - - # IMPORTANT – we only send webhook relay requests to one - # upstream (the master node - blot-container-green) because - # it has an inmemory dictionary of connected clients – if - # you have multiple upstreams, it doesn't work – - # DO NOT replace with http://blot_node - proxy_pass http://127.0.0.1:8089; - - proxy_read_timeout 24h; - proxy_send_timeout 24h; - proxy_connect_timeout 24h; - - # SSE-specific configurations - proxy_http_version 1.1; # SSE requires HTTP/1.1 - proxy_set_header Connection ''; # Disable keep-alive - proxy_buffering off; # Disable response buffering - proxy_cache off; # Ensure no caching - - # generic - 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_set_header X-Forwarded-Proto $scheme; - proxy_set_header X-Request-ID $request_id; - } - } - - # custom domains - server { - listen 80 default_server; - listen 443 ssl default_server; - http2 on; - # Dynamic handler for issuing or returning certs for SNI domains. - ssl_certificate_by_lua_block { - auto_ssl:ssl_certificate() - } - - # Endpoint used for performing domain verification with Let's Encrypt. - location /.well-known/acme-challenge/ { - content_by_lua_block { - auto_ssl:challenge_server() - } - } - - # You must still define a static ssl_certificate file for nginx to start. - # The SSL certificate we use is generated by https://github.com/kshcherban/acme-nginx - # for the "*.blot.im" and "blot.im" domains. This allows us to do an infinite - # number of subdomains for previewing templates. The paths to these files are - # hardcoded in the source for kshcherban/acme-nginx. I wrote more about this - # process in notes/wildcard-ssl - # Check with the SSL evaluator tool - ssl_protocols TLSv1.2 TLSv1.3; - ssl_prefer_server_ciphers off; - ssl_ciphers "ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384"; - - # Hopefully improves performance - # one megabyte can store about 4000 sessions - # 10m = 40,000 sessions - ssl_session_cache shared:SSL:10m; - ssl_session_timeout 1h; - ssl_session_tickets off; - - # Add OCSP stapling if your cert supports it - ssl_stapling on; - ssl_stapling_verify on; - - # The SSL certificate we use is generated by https://github.com/kshcherban/acme-nginx - # for the "*.blot.im" and "blot.im" domains. This allows us to do an infinite - # number of subdomains for previewing templates. The paths to these files are - # hardcoded in the source for kshcherban/acme-nginx. I wrote more about this - # process in notes/wildcard-ssl - ssl_certificate /etc/ssl/private/letsencrypt-domain.pem; - ssl_certificate_key /etc/ssl/private/letsencrypt-domain.key; - set $upstream_server blot_blogs_node; - root /; - - # Match urls which start with /draft/stream/ - location /draft/stream/ { - proxy_pass http://blot_node; - proxy_read_timeout 24h; - proxy_send_timeout 24h; - proxy_connect_timeout 24h; - - # SSE-specific configurations - proxy_http_version 1.1; # SSE requires HTTP/1.1 - proxy_set_header Connection ''; # Disable keep-alive - proxy_buffering off; # Disable response buffering - proxy_cache off; # Ensure no caching - - # generic - 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_set_header X-Forwarded-Proto $scheme; - proxy_set_header X-Request-ID $request_id; - } - - # This is used to determine whether the server is handling - # requests, don't remove it unless you change monit.rc too! - location = /health { - return 200; - } - - # This is used to prevent people from accessing the git repositories in user folders - location ^~ /.git { - return 404; - } - - # return 404 immediately for all requests to URLs ending in .php, .asp, .aspx, .jsp, .php5, .php7, .php8 - location ~* \.(?:php[0-9]?|asp|aspx|jsp)$ { - return 404; - } - - # return 404 immediate for /.vscode/sftp.json - location = /.vscode/sftp.json { - return 404; - } - - location = /sftp-config.json { - return 404; - } - - location = /magento_version { - return 404; - } - - # return 404 immediately for all requests to URLs starting with /api/v1 - location ~* ^/api/v1 { - return 404; - } - - location ~* ^/api/collections/ { - return 404; - } - - location ~* ^/vendor/phpunit/ { - return 404; - } - - # return 404 for all URLS starting with /admin/controller/extension/extension - location ~* ^/admin/controller/extension/extension { - return 404; - } - - # return 404 immediately for all requests to URLs starting with /admin/.git/ - location ~* ^/admin/.git { - return 404; - } - - # return 404 immediately for all requests containing 'index.php/' or 'admin.php/' anywhere in their path - location ~* (?:index|admin)\.php/ { - return 404; - } - - # return 404 immediately for all requests to URLs ending in .env - location ~* \.env$ { - return 404; - } - - # return 404 immediately for all requests to URLs containing '/wp-admin/', '/wp-content/', '/wp-includes/' anywhere in their path - location ~* wp-(?:admin|content|includes|diambar|json|config) { - return 404; - } - - # bypass the cache for requests to /random - # todo: handle this with headers instead of a separate location block - location = /random { - add_header 'Blot-Server' 'us' always; - add_header 'Blot-Cache' $upstream_cache_status always; - add_header 'Blot-Upstream' $upstream_addr always; - - proxy_pass http://$upstream_server; - proxy_http_version 1.1; - - 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_set_header X-Forwarded-Proto $scheme; - proxy_set_header X-Request-ID $request_id; - proxy_set_header Upgrade $http_upgrade; - proxy_set_header Connection $http_connection; # Use $http_connection for better dynamic handling - # We let nginx handle the compression - proxy_set_header Accept-Encoding ""; - - gzip on; - gzip_types text/plain text/css application/json application/javascript application/x-javascript text/xml application/xml application/xml+rss text/javascript; - gzip_comp_level 6; - gzip_proxied any; - - # For larger responses (blog posts, content-heavy pages) - # Configured for 2MB total buffer size - proxy_buffers 32 64k; # 2MB total (32 * 64k = 2048k) - proxy_buffer_size 64k; - - proxy_redirect off; - - proxy_intercept_errors on; - error_page 500 502 503 504 429 /error-upstream-offline.html; - - # Enable retrying the next upstream on failure - # Important to limit the number of tries and possibly - # the timeout otherwise a single request which triggers an error could take down all the servers - # We do rolling deploys where one server is taken down at a time so this should allow - # a failover in that case. Expensive or bug-triggering requests should consistently failwhale - # You have to be careful that these error codes are only returned when the server is truly - # unavailable – I ran into a nasty bug where a request that should have lead to a 404 was return - # a 500 error code, and this config considered the upstream server bad! - proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504; - proxy_next_upstream_tries 1; - proxy_next_upstream_timeout 10s; - - # Fine-tune timeouts for better failover - proxy_connect_timeout 3s; # Time to establish a connection to the upstream - proxy_send_timeout 10s; # Time to send the request to the upstream - proxy_read_timeout 15s; # Time to read the response from the upstream - } - - # error page for when node server is unavailable - location = /error-upstream-offline.html { - root /home/ec2-user/openresty/html; - try_files /error-upstream-offline-blog.html =404; - } - - location / { - set $cache_key $scheme://$host$request_uri; - - open_file_cache off; - - proxy_cache PROXY_CACHE; - - # https://cassiomolin.com/2016/09/09/which-http-status-codes-are-cacheable/ - proxy_cache_valid 200 301 302 400 404 1y; - - # we want to cache everything, even if cache-control says not to - # it's important to ignore the vary header from upstream otherwise - # nginx will cache multiple copies of the same page - proxy_ignore_headers Cache-Control Expires Set-Cookie Vary; - - proxy_cache_key $cache_key; - proxy_cache_use_stale error timeout invalid_header updating http_500 http_502 http_503 http_504; - - add_header 'Blot-Server' 'us' always; - add_header 'Blot-Cache' $upstream_cache_status always; - add_header 'Blot-Upstream' $upstream_addr always; - - proxy_pass http://$upstream_server; - proxy_http_version 1.1; - - 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_set_header X-Forwarded-Proto $scheme; - proxy_set_header X-Request-ID $request_id; - proxy_set_header Upgrade $http_upgrade; - proxy_set_header Connection $http_connection; # Use $http_connection for better dynamic handling - # We let nginx handle the compression - proxy_set_header Accept-Encoding ""; - - gzip on; - gzip_types text/plain text/css application/json application/javascript application/x-javascript text/xml application/xml application/xml+rss text/javascript; - gzip_comp_level 6; - gzip_proxied any; - - # For larger responses (blog posts, content-heavy pages) - # Configured for 2MB total buffer size - proxy_buffers 32 64k; # 2MB total (32 * 64k = 2048k) - proxy_buffer_size 64k; - - proxy_redirect off; - - proxy_intercept_errors on; - error_page 500 502 503 504 429 /error-upstream-offline.html; - - # Enable retrying the next upstream on failure - # Important to limit the number of tries and possibly - # the timeout otherwise a single request which triggers an error could take down all the servers - # We do rolling deploys where one server is taken down at a time so this should allow - # a failover in that case. Expensive or bug-triggering requests should consistently failwhale - # You have to be careful that these error codes are only returned when the server is truly - # unavailable – I ran into a nasty bug where a request that should have lead to a 404 was return - # a 500 error code, and this config considered the upstream server bad! - proxy_next_upstream error timeout invalid_header http_500 http_502 http_503 http_504; - proxy_next_upstream_tries 1; - proxy_next_upstream_timeout 10s; - - # Fine-tune timeouts for better failover - proxy_connect_timeout 3s; # Time to establish a connection to the upstream - proxy_send_timeout 10s; # Time to send the request to the upstream - proxy_read_timeout 15s; # Time to read the response from the upstream - - # This registers a cached response in our dictionary of cached responses - # pass in the proxy_cache_key setting - log_by_lua_block { - if ngx.var.upstream_cache_status == "MISS" then - cacher:add(ngx.var.host, ngx.var.cache_key) - end - } } - - } - - # redirect blot.im over HTTP to HTTPS - server { - listen 80; - server_name blot.im; - return 301 https://$host$request_uri; - } - - # internal server for inspecting and purging the cache - server { - listen 127.0.0.1:80; - # needed by the node application running inside docker - # which doesn't have access to the host network - # this seems to cause errors for custom domains - # and overrides the default server - listen 172.30.0.122:8077; - - location = /inspect { - content_by_lua_block { - cacher:inspect(ngx) - } - } - - location = /rehydrate { - content_by_lua_block { - local message = cacher:rehydrate(ngx) - ngx.say(message) - } - } - - location = /purge { - content_by_lua_block { - cacher:purge(ngx) - } - } - - # otherwise, return 404 - location / { - return 404; - } - } -} \ No newline at end of file From b7ef65205928acb6d245c36dafcdf06d509e8766 Mon Sep 17 00:00:00 2001 From: David Merfield Date: Tue, 21 Oct 2025 11:06:16 +0200 Subject: [PATCH 5/5] Fail fast when BLOT_HOST is missing --- proxy/entrypoint.sh | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/proxy/entrypoint.sh b/proxy/entrypoint.sh index 1abf9217b8e..805229ac8eb 100644 --- a/proxy/entrypoint.sh +++ b/proxy/entrypoint.sh @@ -12,6 +12,11 @@ if [[ "$USE_STAGING" == "true" ]]; then fi # Ensure BLOT_HOST is set +if [[ -z "$BLOT_HOST" ]]; then + echo "Error: BLOT_HOST is not set. Please provide the domain via the BLOT_HOST environment variable." >&2 + exit 1 +fi + echo "BLOT_HOST=$BLOT_HOST" # Check if AWS credentials are set @@ -40,4 +45,4 @@ else fi # Start OpenResty -exec /usr/local/openresty/bin/openresty -g "daemon off;" \ No newline at end of file +exec /usr/local/openresty/bin/openresty -g "daemon off;"