diff --git a/.env.example b/.env.example index 182884b..779ac4f 100644 --- a/.env.example +++ b/.env.example @@ -43,3 +43,19 @@ GS_PROPOSER_PRIVATE_KEY= # Sequencer address GS_SEQUENCER_ADDRESS= GS_SEQUENCER_PRIVATE_KEY= + +# DNS Configuration +L2_SYSTEM_SERVER_IP=11.22.33.44 +CLOUDFLARE_AUTH_EMAIL= +# 1. Log into Cloudflare dashboard +# 2. Go to "My Profile" (top right) +# 3. Scroll to "API Tokens" +# 4. View your "Global API Key" +CLOUDFLARE_API_KEY= +# 1. Log into Cloudflare dashboard +# 2. Select your domain +# 3. Look in the right sidebar - "Zone ID" is listed there +CLOUDFLARE_ZONE_ID= +CLOUDFLARE_DNS_SUBDOMAIN=tohma +CERTBOT_EMAIL=support@snapchain.dev +CERTBOT_DOMAIN_SUFFIX=tohma.snapchain.dev \ No newline at end of file diff --git a/Makefile b/Makefile index 54dc706..91c8f37 100644 --- a/Makefile +++ b/Makefile @@ -140,4 +140,8 @@ l2-explorer-ps: ## Show logs for the OP chain explorer l2-explorer-logs: docker compose -f docker/docker-compose-l2-explorer.yml logs -f -.PHONY: l2-explorer-logs \ No newline at end of file +.PHONY: l2-explorer-logs + +l2-proxy-setup: + @$(CURDIR)/scripts/l2/proxy-setup.sh +.PHONY: l2-proxy-setup diff --git a/configs/nginx/bridge.conf.template b/configs/nginx/bridge.conf.template new file mode 100644 index 0000000..2ee6f20 --- /dev/null +++ b/configs/nginx/bridge.conf.template @@ -0,0 +1,17 @@ + +server { + listen 443 ssl; + server_name bridge.${CERTBOT_DOMAIN_SUFFIX}; + + ssl_certificate /etc/letsencrypt/live/${CERTBOT_DOMAIN_SUFFIX}/fullchain.pem; + ssl_certificate_key /etc/letsencrypt/live/${CERTBOT_DOMAIN_SUFFIX}/privkey.pem; + + location / { + proxy_pass http://localhost:3002; # bridge UI port + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection 'upgrade'; + proxy_set_header Host $host; + proxy_cache_bypass $http_upgrade; + } +} \ No newline at end of file diff --git a/configs/nginx/l2-explorer.conf.template b/configs/nginx/l2-explorer.conf.template new file mode 100644 index 0000000..a5f182b --- /dev/null +++ b/configs/nginx/l2-explorer.conf.template @@ -0,0 +1,29 @@ +server { + listen 443 ssl; + server_name explorer.${CERTBOT_DOMAIN_SUFFIX}; + + ssl_certificate /etc/letsencrypt/live/${CERTBOT_DOMAIN_SUFFIX}/fullchain.pem; + ssl_certificate_key /etc/letsencrypt/live/${CERTBOT_DOMAIN_SUFFIX}/privkey.pem; + + location ~ ^/(api|socket|sitemap.xml|auth/auth0|auth/auth0/callback|auth/logout) { + proxy_pass http://localhost:8088; + 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 Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + } + + location / { + proxy_pass http://localhost:8088; + 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 Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + } +} \ No newline at end of file diff --git a/configs/nginx/l2-rpc.conf.template b/configs/nginx/l2-rpc.conf.template new file mode 100644 index 0000000..421921b --- /dev/null +++ b/configs/nginx/l2-rpc.conf.template @@ -0,0 +1,37 @@ +server { + listen 443 ssl; + server_name rpc.${CERTBOT_DOMAIN_SUFFIX}; + + ssl_certificate /etc/letsencrypt/live/${CERTBOT_DOMAIN_SUFFIX}/fullchain.pem; + ssl_certificate_key /etc/letsencrypt/live/${CERTBOT_DOMAIN_SUFFIX}/privkey.pem; + + location / { + proxy_pass http://localhost:9545; + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection 'upgrade'; + proxy_set_header Host $host; + proxy_cache_bypass $http_upgrade; + + # prevent duplicate headers by resetting existing ones + proxy_hide_header 'Access-Control-Allow-Origin'; + proxy_hide_header 'Access-Control-Allow-Methods'; + proxy_hide_header 'Access-Control-Allow-Headers'; + + if ($request_method = 'OPTIONS') { + add_header 'Access-Control-Allow-Origin' $http_origin always; + add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS' always; + add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range' always; + add_header 'Access-Control-Max-Age' 1728000 always; + add_header 'Content-Type' 'text/plain charset=UTF-8' always; + add_header 'Content-Length' 0 always; + return 204; + } + + # this line is needed to prevent CORS errors + add_header 'Access-Control-Allow-Origin' $http_origin always; + add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS' always; + add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range' always; + add_header 'Access-Control-Allow-Credentials' 'true' always; + } +} \ No newline at end of file diff --git a/docker/docker-compose-l2-explorer.yml b/docker/docker-compose-l2-explorer.yml index 5b4fdd5..0d8b60e 100644 --- a/docker/docker-compose-l2-explorer.yml +++ b/docker/docker-compose-l2-explorer.yml @@ -79,7 +79,7 @@ services: FRONT_PROXY_PASS: http://frontend:3000 STATS_PROXY_PASS: http://stats:8050/ ports: - - 80:80 + - 8088:80 - 8084:8080 smart-contract-verifier: diff --git a/optimism b/optimism index 7914128..32f912d 160000 --- a/optimism +++ b/optimism @@ -1 +1 @@ -Subproject commit 791412841429f901d6cf68d5e1de885072cbfc4f +Subproject commit 32f912d130b80293e91bdc4d5ffd7e462454a699 diff --git a/scripts/l2/l2-op-node-restart.sh b/scripts/l2/l2-op-node-restart.sh index 9e3d03e..4b36fd0 100755 --- a/scripts/l2/l2-op-node-restart.sh +++ b/scripts/l2/l2-op-node-restart.sh @@ -16,15 +16,20 @@ docker compose -f docker/docker-compose-l2.yml stop op-node post_deployment_setup_env_vars $(pwd)/.deploy/op-devnet-deployments-${L2_CHAIN_ID}.json $DEVNET_L2OO ROLLUP_CONFIG=$(pwd)/.deploy/rollup.json -# set babylonFinalityGadgetRpc in rollup.json -echo "Setting babylonFinalityGadgetRpc in rollup.json with value: $BBN_FINALITY_GADGET_RPC" -sed -i.bak 's|"babylonFinalityGadgetRpc":.*|"babylonFinalityGadgetRpc": "'"$BBN_FINALITY_GADGET_RPC"'"|' $ROLLUP_CONFIG +# set babylon_finality_gadget_rpc in rollup.json +if [ -z "$BBN_FINALITY_GADGET_RPC" ]; then + echo "Setting babylon_finality_gadget_rpc with empty value in rollup.json" +else + echo "Setting babylon_finality_gadget_rpc with value $BBN_FINALITY_GADGET_RPC in rollup.json" +fi + +sed -i.bak 's|"babylon_finality_gadget_rpc":.*|"babylon_finality_gadget_rpc": "'"$BBN_FINALITY_GADGET_RPC"'"|' $ROLLUP_CONFIG rm $ROLLUP_CONFIG.bak -# get the babylonFinalityGadgetRpc from rollup.json -FG_URL_IN_ROLLUP=$(jq -r '.babylonFinalityGadgetRpc' $ROLLUP_CONFIG) +# get the babylon_finality_gadget_rpc from rollup.json +FG_URL_IN_ROLLUP=$(jq -r '.babylon_finality_gadget_rpc' $ROLLUP_CONFIG) if [ "$FG_URL_IN_ROLLUP" != "$BBN_FINALITY_GADGET_RPC" ]; then - echo "babylonFinalityGadgetRpc in rollup.json ($FG_URL_IN_ROLLUP) is not equal to the value in .env ($BBN_FINALITY_GADGET_RPC)" + echo "ERROR: value mismatch - rollup.json: babylon_finality_gadget_rpc($FG_URL_IN_ROLLUP), .env: BBN_FINALITY_GADGET_RPC($BBN_FINALITY_GADGET_RPC)" exit 1 fi diff --git a/scripts/l2/proxy-setup.sh b/scripts/l2/proxy-setup.sh new file mode 100755 index 0000000..cdcdca0 --- /dev/null +++ b/scripts/l2/proxy-setup.sh @@ -0,0 +1,81 @@ +#!/bin/bash +set -euo pipefail + +set -a +source $(pwd)/.env +set +a + +# reference: https://developers.cloudflare.com/api/operations/dns-records-for-a-zone-batch-dns-records +create_dns_records() { + local names=("$@") + local records="" + + for name in "${names[@]}"; do + if [ -n "$records" ]; then + records="${records}," + fi + records="${records} + { + \"type\": \"A\", + \"name\": \"${name}.${CLOUDFLARE_DNS_SUBDOMAIN}\", + \"content\": \"$L2_SYSTEM_SERVER_IP\", + \"proxied\": false + }" + done + + curl --request POST \ + --url "https://api.cloudflare.com/client/v4/zones/$CLOUDFLARE_ZONE_ID/dns_records/batch" \ + --header "Content-Type: application/json" \ + --header "X-Auth-Email: $CLOUDFLARE_AUTH_EMAIL" \ + --header "X-Auth-Key: $CLOUDFLARE_API_KEY" \ + --data "{ + \"posts\": [${records}] + }" +} + +# 1. create the DNS records for the subdomains +# (RPC, Bridge, Explorer) +create_dns_records "rpc" "bridge" "explorer" + +# 2. obtain the SSL certificate for each subdomain +# the certs will be stored in /etc/letsencrypt/live/${CERTBOT_DOMAIN_SUFFIX} +# +# note that Certbot creates a single certificate that's valid for all those +# domains (called a SAN - Subject Alternative Names certificate) +# +# after running the command, you can verify by: +# sudo openssl x509 -in /etc/letsencrypt/live/${CERTBOT_DOMAIN_SUFFIX}/fullchain.pem -text | grep DNS: +# +# reference: https://eff-certbot.readthedocs.io/en/latest/using.html +certbot certonly --nginx --non-interactive --agree-tos -m ${CERTBOT_EMAIL} \ + --cert-name ${CERTBOT_DOMAIN_SUFFIX} \ + -d rpc.${CERTBOT_DOMAIN_SUFFIX} \ + -d bridge.${CERTBOT_DOMAIN_SUFFIX} \ + -d explorer.${CERTBOT_DOMAIN_SUFFIX} + +# 3. create the nginx config files for each subdomain +cp configs/nginx/l2-rpc.conf.template /etc/nginx/sites-available/l2-rpc.conf +cp configs/nginx/bridge.conf.template /etc/nginx/sites-available/bridge.conf +cp configs/nginx/l2-explorer.conf.template /etc/nginx/sites-available/l2-explorer.conf + +# 4. replace ${CERTBOT_DOMAIN_SUFFIX} in the nginx config files +sed -i 's/\${CERTBOT_DOMAIN_SUFFIX}/'"${CERTBOT_DOMAIN_SUFFIX}"'/g' /etc/nginx/sites-available/*.conf + +# 5. enable the nginx config files +mkdir -p /etc/nginx/sites-enabled +ln -sf /etc/nginx/sites-available/l2-rpc.conf /etc/nginx/sites-enabled/ +ln -sf /etc/nginx/sites-available/bridge.conf /etc/nginx/sites-enabled/ +ln -sf /etc/nginx/sites-available/l2-explorer.conf /etc/nginx/sites-enabled/ + +# 6. verify the nginx config files +nginx -t + +# 7. restart nginx +# +# after running this, you can check the status of nginx by: +# systemctl status nginx +# +# see logs +# journalctl -u nginx.service -f +systemctl start nginx +systemctl enable nginx \ No newline at end of file