add nginx proxy as LB

This commit is contained in:
nitramiz 2019-06-13 09:01:23 -07:00
parent 92a6cbcd7f
commit 43bb58792d
No known key found for this signature in database
GPG key ID: 2352C35346C5D534
22 changed files with 744 additions and 358 deletions

View file

@ -2,7 +2,7 @@ variables:
GIT_SUBMODULE_STRATEGY: none
CI_DISPOSABLE_ENVIRONMENT: "true"
image: blockstream/gcloud-docker@sha256:2ab8222c44502282a614cdda4a9f1434d6f91e93888a39c56b82ebc52f6bd3b1
image: blockstream/gcloud-docker@sha256:e12152fa1daade1a1e3ff1c61ccc434fd99d7ad3627508fd2aa59f0f6b79910b
stages:
- build
- plan
@ -77,13 +77,14 @@ plan_satapi:
-var "zone=$ZONE"
-var "instance_type=$INSTANCE_TYPE"
-var "host=$HOST_STAGING"
-var "public_bucket_url=$PUBLIC_BUCKET_URL"
-var "letsencrypt_email=$LE_EMAIL"
-var "timeout=$TIMEOUT"
-var "prom_service_acct=$PROM_SA"
-var "opsgenie_key=$OPSGENIE_KEY"
-var "rpcuser=$RPCUSER"
-var "rpcpass=$RPCPASS"
-var "public_bucket_url=$PUBLIC_BUCKET_URL"
-var "letsencrypt_email=$LE_EMAIL"
-var "lb_svc_acct=$LB_SA_STAGING"
-input=false)
# This plan gets triggered only for miscellaneous branches/tags (i.e. tor, prometheus, etc), so make sure the branch/tag name starts with misc_
@ -134,7 +135,7 @@ deploy_misc:
-var "satellite_lb=$SATELLITE_LB"
-var "satellite_api_lb=$SATELLITE_API_LB"
-var "satellite_api_lb_staging=$SATELLITE_API_LB_STAGING"
-input=false -auto-approve)
-input=false -auto-approve)
# Tag with staging_v.* to deploy mainnet staging (e.g. staging_v0.1.1)
deploy_staging:
@ -152,13 +153,13 @@ deploy_staging:
-var "zone=$ZONE"
-var "instance_type=$INSTANCE_TYPE"
-var "host=$HOST_STAGING"
-var "public_bucket_url=$PUBLIC_BUCKET_URL"
-var "letsencrypt_email=$LE_EMAIL"
-var "timeout=$TIMEOUT"
-var "prom_service_acct=$PROM_SA"
-var "opsgenie_key=$OPSGENIE_KEY"
-var "rpcuser=$RPCUSER"
-var "rpcpass=$RPCPASS"
-var "public_bucket_url=$PUBLIC_BUCKET_URL"
-var "letsencrypt_email=$LE_EMAIL"
-input=false -auto-approve)
# Tag with production_v.* to deploy mainnet production (e.g. prod_v0.1.1)
@ -177,13 +178,13 @@ deploy_production:
-var "zone=$ZONE"
-var "instance_type=$INSTANCE_TYPE"
-var "host=$HOST"
-var "public_bucket_url=$PUBLIC_BUCKET_URL"
-var "letsencrypt_email=$LE_EMAIL"
-var "timeout=$TIMEOUT"
-var "prom_service_acct=$PROM_SA"
-var "opsgenie_key=$OPSGENIE_KEY"
-var "rpcuser=$RPCUSER"
-var "rpcpass=$RPCPASS"
-var "public_bucket_url=$PUBLIC_BUCKET_URL"
-var "letsencrypt_email=$LE_EMAIL"
-input=false -auto-approve)
# Tag with testnet_staging_v.* to deploy testnet staging (e.g. testnet_staging_v0.1.1)
@ -202,13 +203,14 @@ deploy_staging_testnet:
-var "zone=$ZONE"
-var "instance_type=$INSTANCE_TYPE"
-var "host=$HOST_STAGING"
-var "public_bucket_url=$PUBLIC_BUCKET_URL"
-var "letsencrypt_email=$LE_EMAIL"
-var "timeout=$TIMEOUT"
-var "prom_service_acct=$PROM_SA"
-var "opsgenie_key=$OPSGENIE_KEY"
-var "rpcuser=$RPCUSER"
-var "rpcpass=$RPCPASS"
-var "public_bucket_url=$PUBLIC_BUCKET_URL"
-var "letsencrypt_email=$LE_EMAIL"
-var "lb_svc_acct=$LB_SA_STAGING"
-input=false -auto-approve)
# Tag with production_v.* to deploy testnet production (e.g. testnet_prod_v0.1.1)
@ -226,22 +228,20 @@ deploy_production_testnet:
-var "region=$REGION"
-var "zone=$ZONE"
-var "instance_type=$INSTANCE_TYPE"
-var "host=$HOST"
-var "public_bucket_url=$PUBLIC_BUCKET_URL"
-var "letsencrypt_email=$LE_EMAIL"
-var "host=$HOST_STAGING"
-var "timeout=$TIMEOUT"
-var "prom_service_acct=$PROM_SA"
-var "opsgenie_key=$OPSGENIE_KEY"
-var "rpcuser=$RPCUSER"
-var "rpcpass=$RPCPASS"
-var "public_bucket_url=$PUBLIC_BUCKET_URL"
-var "letsencrypt_email=$LE_EMAIL"
-var "lb_svc_acct=$LB_SA"
-input=false -auto-approve)
# Pushing to this branch destroys the staging infrastructure
cleanup_staging:
stage: deploy
image:
name: hashicorp/terraform:light
entrypoint: [""]
only:
- cleanup_staging@satellite/ionosphere
script:
@ -249,6 +249,7 @@ cleanup_staging:
terraform workspace select staging &&
terraform destroy
-target module.blc.google_compute_instance_group_manager.blc
-target module.lb.google_compute_region_instance_group_manager.satapi-lb
-auto-approve)
- (cd terraform && terraform init -input=false &&
terraform workspace select testnet-staging &&

View file

@ -1,22 +1,19 @@
data "terraform_remote_state" "blc-mainnet" {
backend = "gcs"
backend = "gcs"
workspace = local.env
config = {
bucket = "tf-state-satellite-api"
prefix = "terraform/state"
bucket = "terraform-bs-source"
prefix = "satellite-api"
}
workspace = "prod"
}
data "terraform_remote_state" "blc-testnet" {
backend = "gcs"
backend = "gcs"
workspace = "testnet-${local.env}"
config = {
bucket = "tf-state-satellite-api"
prefix = "terraform/state"
bucket = "terraform-bs-source"
prefix = "satellite-api"
}
workspace = "testnet-prod"
}

View file

@ -27,10 +27,9 @@ module "blc-mainnet" {
ionosphere_docker = var.ionosphere_docker
ionosphere_sse_docker = var.ionosphere_sse_docker
node_exporter_docker = var.node_exporter_docker
certbot_docker = var.certbot_docker
net = "mainnet"
env = local.env
target_pool = google_compute_target_pool.blc-pool[0].self_link
lb_svc_acct = module.lb.lb_svc_acct
create_resources = local.create_mainnet
@ -38,14 +37,11 @@ module "blc-mainnet" {
region = var.region
zone = var.zone
instance_type = var.instance_type[0]
host = var.host
timeout = var.timeout
prom_service_acct = var.prom_service_acct
opsgenie_key = var.opsgenie_key
rpcuser = var.rpcuser
rpcpass = var.rpcpass
letsencrypt_email = var.letsencrypt_email
public_bucket_url = var.public_bucket_url
}
module "blc-testnet" {
@ -60,10 +56,8 @@ module "blc-testnet" {
ionosphere_docker = var.ionosphere_docker
ionosphere_sse_docker = var.ionosphere_sse_docker
node_exporter_docker = var.node_exporter_docker
certbot_docker = var.certbot_docker
net = "testnet"
env = local.env
target_pool = google_compute_target_pool.blc-pool[0].self_link
create_resources = local.create_testnet
@ -71,12 +65,36 @@ module "blc-testnet" {
region = var.region
zone = var.zone
instance_type = var.instance_type[0]
host = var.host
timeout = var.timeout
prom_service_acct = var.prom_service_acct
opsgenie_key = var.opsgenie_key
rpcuser = var.rpcuser
rpcpass = var.rpcpass
lb_svc_acct = var.lb_svc_acct
}
module "lb" {
source = "./modules/lb"
project = var.project
name = "satellite-api-lb"
network = "default"
certbot_docker = var.certbot_docker
node_exporter_docker = var.node_exporter_docker
env = local.env
internal_ip_mainnet = module.blc-mainnet.internal_ip
internal_ip_testnet = data.terraform_remote_state.blc-testnet.outputs.blc_internal_ip_testnet
target_pool = google_compute_target_pool.lb-pool[0].self_link
create_resources = local.create_mainnet
# CI vars
region = var.region
zone = var.zone
instance_type = var.instance_type[1]
host = var.host
timeout = var.timeout
prom_service_acct = var.prom_service_acct
letsencrypt_email = var.letsencrypt_email
public_bucket_url = var.public_bucket_url
}

View file

@ -1,4 +1,4 @@
certbot_dockerbootcmd:
bootcmd:
- blkid /dev/disk/by-id/google-data || mkfs.ext4 -L data /dev/disk/by-id/google-data
- mkdir -p /mnt/disks/data
mounts:
@ -28,239 +28,6 @@ write_files:
announce-addr=${announce_addr}
bind-addr=0.0.0.0
- path: /home/bs/default.conf
permissions: 0644
owner: root
content: |
log_format withtime '$remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent" '
'rt="$request_time" uct="$upstream_connect_time" uht="$upstream_header_time" urt="$upstream_response_time"';
server {
index index.php index.html index.htm index.nginx-debian.html;
access_log /var/log/nginx/access-def.log withtime;
error_log /var/log/nginx/error-def.log;
server_name ${host};
listen 80;
server_tokens off;
proxy_set_header X-Forwarded-For 0.0.0.0;
location /.well-known {
auth_basic off;
allow all; # Allow all to see content
proxy_pass ${public_bucket_url}/certs/.well-known;
}
location /healthz {
return 200;
}
location / {
return 301 https://$host$request_uri;
}
}
- path: /home/bs/space.conf
permissions: 0644
owner: root
content: |
log_format withtime '$remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent" '
'rt="$request_time" uct="$upstream_connect_time" uht="$upstream_header_time" urt="$upstream_response_time"';
server {
access_log /var/log/nginx/access.log withtime;
error_log /var/log/nginx/error.log;
server_name ${host};
listen 443 ssl default_server;
ssl_certificate /etc/nginx/certs/live/${host}/fullchain.pem;
ssl_certificate_key /etc/nginx/certs/live/${host}/privkey.pem;
ssl_prefer_server_ciphers on;
ssl_dhparam /etc/nginx/certs/certs/dhparam.pem;
root /usr/share/nginx/html/;
server_tokens off;
proxy_set_header X-Forwarded-For 0.0.0.0;
# Proxy to Satellite API
location = / {
rewrite ^ /index.html break;
}
location ${url_path}/ {
add_header 'Access-Control-Allow-Origin' '*' always;
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, DELETE' always;
add_header 'Access-Control-Allow-Headers' 'X-Auth-Token,DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range' always;
add_header 'X-XSS-Protection' '1; mode=block' always;
if ($request_uri ~* "^${url_path}/?$")
{
return 301 https://$host$request_uri;
}
if ($request_method = 'OPTIONS')
{
return 200;
}
proxy_pass http://0.0.0.0:9292/;
}
# Proxy to SSE container
location ${url_path}/subscribe/ {
chunked_transfer_encoding off;
proxy_buffering off;
proxy_request_buffering off;
proxy_cache off;
proxy_http_version 1.1;
proxy_pass http://0.0.0.0:4500/stream?channels=;
}
}
- path: /home/bs/index.html
permissions: 0644
owner: root
content: |
<html>
<body>
<title>Blockstream Satellite API</title>
<h3>This is our fancy default page. Here are some interesting places worth exploring:</h3>
<b>
<p>Learn more: <a href="https://blockstream.com/satellite-api-documentation/" target="_blank">Satellite API Docs</a></p>
<p>Contribute: <a href="https://github.com/blockstream/satellite-api" target="_blank">Satellite API Code</a></p>
</b>
<h4>If you're trying to use Tor, make sure you're using the right path. For example:</h4>
<p>http://btcspaceda7iejsrb7ihmi5si3hhssxxxdnqvvtyz6prv2m73j7lcoqd.onion/orders/pending</p>
</body>
</html>
- path: /etc/systemd/system/nginx.service
permissions: 0644
owner: root
content: |
[Unit]
Description=Nginx redirect
Wants=gcr-online.target
After=ionosphere.service
[Service]
Restart=always
RestartSec=3
Environment=HOME=/home/bs
ExecStartPre=/sbin/iptables -A INPUT -m tcp -p tcp --dport 80 -j ACCEPT
ExecStart=/usr/bin/docker run \
--network=host \
--pid=host \
--name=nginx \
--log-opt max-size=200m \
--log-opt max-file=3 \
-v /home/bs/default.conf:/etc/nginx/conf.d/default.conf:ro \
"nginx:latest"
ExecStop=/usr/bin/docker stop nginx
ExecStopPost=/usr/bin/docker rm nginx
ExecStopPost=/sbin/iptables -D INPUT -m tcp -p tcp --dport 80 -j ACCEPT
- path: /etc/systemd/system/nginx-tls.service
permissions: 0644
owner: root
content: |
[Unit]
Description=Nginx TLS proxy
Wants=gcr-online.target
After=nginx.service
[Service]
Restart=always
RestartSec=3
Environment=HOME=/home/bs
ExecStartPre=/sbin/iptables -A INPUT -m tcp -p tcp --dport 443 -j ACCEPT
ExecStart=/usr/bin/docker run \
--network=host \
--pid=host \
--name=nginx-tls \
--log-opt max-size=200m \
--log-opt max-file=3 \
-v /home/bs/space.conf:/etc/nginx/conf.d/default.conf:ro \
-v /home/bs/index.html:/usr/share/nginx/html/index.html:ro \
-v /home/bs/certs:/etc/nginx/certs:ro \
"nginx:latest"
ExecStop=/usr/bin/docker stop nginx-tls
ExecStopPost=/usr/bin/docker rm nginx-tls
ExecStopPost=/sbin/iptables -D INPUT -m tcp -p tcp --dport 443 -j ACCEPT
- path: /etc/systemd/system/cert-downloader.service
permissions: 0644
owner: root
content: |
[Unit]
Description=Run cert-downloader
Wants=gcr-online.target
After=nginx-tls.service
[Service]
Type=oneshot
RemainAfterExit=true
Environment=HOME=/home/bs
ExecStartPre=/usr/bin/docker-credential-gcr configure-docker
ExecStart=/usr/bin/docker run \
--name=cert-downloader \
--tmpfs /root \
--tmpfs /tmp \
--rm \
-v /home/bs/certs:/etc/letsencrypt:rw \
-e GCS_PUBLIC_BUCKET=${public_bucket} \
-e GCS_PRIVATE_BUCKET=${private_bucket} \
-e DOMAIN=${host} \
"${certbot_docker}" download
- path: /etc/systemd/system/cert-renewer.timer
permissions: 0644
owner: root
content: |
[Unit]
Description=Run full cert-renewer every 24 hours
[Timer]
OnUnitActiveSec=1d
Persistent=true
[Install]
WantedBy=timers.target
- path: /etc/systemd/system/cert-renewer.service
permissions: 0644
owner: root
content: |
[Unit]
Description=Run cert-renewer
Wants=gcr-online.target
After=gcr-online.target
[Service]
Type=oneshot
Environment=HOME=/home/bs
ExecStartPre=/usr/bin/docker-credential-gcr configure-docker
ExecStart=/usr/bin/docker run \
--name=cert-renewer \
--tmpfs /root \
--tmpfs /tmp \
--rm \
-v /home/bs/certs:/etc/letsencrypt:rw \
-e GCS_PUBLIC_BUCKET=${public_bucket} \
-e GCS_PRIVATE_BUCKET=${private_bucket} \
-e DOMAIN=${host} \
-e EMAIL=${letsencrypt_email} \
"${certbot_docker}" renew
ExecStartPost=-/usr/bin/systemctl restart nginx-tls
- path: /home/bs/check_containers.sh
permissions: 0744
@ -284,7 +51,7 @@ write_files:
"alias": "satapi-missing-containers",
"description":"Currently running '$${NUM_CONT}'/10: '$${RUNNING_CONT}'",
"tags": ["SatAPI","Critical"],
"entity":"satellite.blockstream.com/api",
"entity":"api.blockstream.space",
"priority":"P3"
}'
else
@ -439,7 +206,8 @@ write_files:
RestartSec=3
Environment=HOME=/home/bs
ExecStartPre=/usr/bin/docker pull ${ionosphere_docker}
ExecStartPre=/sbin/iptables -A INPUT -p tcp -s localhost --dport 9292 -j ACCEPT
ExecStartPre=/sbin/iptables -A INPUT -p tcp -s 10.138.0.0/16 --dport 9292 -j ACCEPT
ExecStopPost=/sbin/iptables -A INPUT -p tcp -s 10.138.0.0/16 --dport 4500 -j ACCEPT
ExecStartPre=/usr/bin/docker run \
--user root \
-v /mnt/disks/data/ionosphere:/data \
@ -460,7 +228,8 @@ write_files:
"${ionosphere_docker}"
ExecStop=/usr/bin/docker stop ionosphere
ExecStopPost=/usr/bin/docker rm ionosphere
ExecStopPost=/sbin/iptables -D INPUT -p tcp -s localhost --dport 9292 -j ACCEPT
ExecStopPost=/sbin/iptables -D INPUT -p tcp -s 10.138.0.0/16 --dport 9292 -j ACCEPT
ExecStopPost=/sbin/iptables -D INPUT -p tcp -s 10.138.0.0/16 --dport 4500 -j ACCEPT
- path: /etc/systemd/system/ionosphere-tx.service
permissions: 0644
@ -552,14 +321,6 @@ runcmd:
- systemctl enable ionosphere-sse.service
- systemctl start charge.service
- systemctl enable charge.service
- systemctl start nginx.service
- systemctl enable nginx.service
- systemctl start cert-renewer.timer
- systemctl enable cert-renewer.timer
- systemctl start cert-downloader.service
- systemctl enable cert-downloader.service
- systemctl start nginx-tls.service
- systemctl enable nginx-tls.service
- systemctl start node-exporter.service
- systemctl enable node-exporter.service
- systemctl start check-containers.timer

View file

@ -17,7 +17,6 @@ data "template_file" "blc" {
rpcuser = var.rpcuser
rpcpass = var.rpcpass
net = var.net
url_path = var.net == "testnet" ? "/testnet" : ""
bitcoin_cmd = "bitcoind ${var.net == "testnet" ? "-testnet" : ""} -printtoconsole"
lightning_cmd = "lightningd ${var.net == "testnet" ? "--testnet" : "--mainnet"} --conf=/root/.lightning/lightning.conf --plugin-dir=/usr/local/bin/plugins"
charge_cmd = "charged -d /data/charge.db -l /root/.lightning"
@ -26,17 +25,11 @@ data "template_file" "blc" {
bitcoin_docker = var.bitcoin_docker
lightning_docker = var.lightning_docker
charge_docker = var.charge_docker
certbot_docker = var.certbot_docker
redis_port = 6379
ionosphere_docker = var.ionosphere_docker
ionosphere_sse_docker = var.ionosphere_sse_docker
node_exporter_docker = var.node_exporter_docker
opsgenie_key = var.opsgenie_key
host = var.host
public_bucket_url = "${var.public_bucket_url}-${var.env}"
public_bucket = replace(google_storage_bucket.blc-public[count.index].url, "gs://", "")
private_bucket = replace(google_storage_bucket.blc-private[count.index].url, "gs://", "")
letsencrypt_email = var.letsencrypt_email
}
}
@ -50,4 +43,3 @@ data "template_cloudinit_config" "blc" {
content = data.template_file.blc[0].rendered
}
}

View file

@ -1,11 +1,12 @@
resource "google_compute_firewall" "blc" {
name = "${var.name}-${var.net}-fw-rule-${var.env}"
network = data.google_compute_network.blc.self_link
project = var.project
count = var.create_resources
allow {
protocol = "tcp"
ports = ["18333", "8333", "9735", "80", "443"]
ports = ["18333", "8333", "9735"]
}
target_service_accounts = [
@ -13,9 +14,30 @@ resource "google_compute_firewall" "blc" {
]
}
resource "google_compute_firewall" "api-internal" {
name = "${var.name}-${var.net}-lb-internal-fw-rule-${var.env}"
network = data.google_compute_network.blc.self_link
project = var.project
count = var.create_resources
allow {
protocol = "tcp"
ports = ["9292", "4500"]
}
source_service_accounts = [
var.lb_svc_acct,
]
target_service_accounts = [
google_service_account.blc[0].email,
]
}
resource "google_compute_firewall" "blc-prom" {
name = "${var.name}-${var.net}-prometheus-access-${var.env}"
network = data.google_compute_network.blc.self_link
project = var.project
count = var.create_resources
allow {

View file

@ -1,10 +1,22 @@
# Instance group
resource "google_compute_disk" "blc" {
name = "${var.name}-data-${var.net}-${var.env}"
type = "pd-standard"
image = data.google_compute_image.blc[0].self_link
zone = var.zone
count = var.create_resources
lifecycle {
prevent_destroy = true
ignore_changes = [image]
}
}
# Instance group & template
resource "google_compute_instance_group_manager" "blc" {
name = "${var.name}-ig-${var.net}-${var.env}"
target_pools = [var.target_pool]
project = var.project
provider = google-beta
count = var.create_resources
name = "${var.name}-ig-${var.net}-${var.env}"
project = var.project
provider = google-beta
count = var.create_resources
base_instance_name = "${var.name}-ig-${var.net}-${var.env}"
zone = var.zone
@ -24,20 +36,6 @@ resource "google_compute_instance_group_manager" "blc" {
}
}
resource "google_compute_disk" "blc" {
name = "${var.name}-data-${var.net}-${var.env}"
type = "pd-standard"
image = data.google_compute_image.blc[0].self_link
zone = var.zone
count = var.create_resources
lifecycle {
prevent_destroy = true
ignore_changes = [image]
}
}
# Instance template
resource "google_compute_instance_template" "blc" {
name_prefix = "${var.name}-${var.net}-${var.env}-tmpl-"
description = "This template is used to create ${var.name} ${var.net} ${var.env} instances."

View file

@ -1,13 +1,13 @@
# External and internal static IPs
resource "google_compute_address" "blc" {
name = "${var.name}-${var.net}-external-ip-${var.env}-${count.index}"
name = "${var.name}-${var.net}-external-ip-${var.env}"
project = var.project
region = var.region
count = var.create_resources
}
resource "google_compute_address" "blc-internal" {
name = "${var.name}-${var.net}-internal-ip-${var.env}-${count.index}"
name = "${var.name}-${var.net}-internal-ip-${var.env}"
address_type = "INTERNAL"
project = var.project
region = var.region

View file

@ -1,7 +1,7 @@
output "backend_service" {
value = element(
concat(google_compute_backend_service.blc.*.self_link, [""]),
0,
)
value = google_compute_backend_service.blc[0].self_link
}
output "internal_ip" {
value = google_compute_address.blc-internal[0].address
}

View file

@ -48,14 +48,6 @@ variable "net" {
type = string
}
variable "target_pool" {
type = string
}
variable "host" {
type = string
}
variable "timeout" {
type = string
}
@ -68,11 +60,7 @@ variable "prom_service_acct" {
type = string
}
variable "public_bucket_url" {
type = string
}
variable "letsencrypt_email" {
variable "lb_svc_acct" {
type = string
}
@ -98,8 +86,4 @@ variable "ionosphere_sse_docker" {
variable "node_exporter_docker" {
type = string
}
variable "certbot_docker" {
type = string
}
}

View file

@ -0,0 +1,343 @@
users:
- name: bs
uid: 2000
write_files:
- path: /home/bs/default.conf
permissions: 0644
owner: root
content: |
log_format withtime '$remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent" '
'rt="$request_time" uct="$upstream_connect_time" uht="$upstream_header_time" urt="$upstream_response_time"';
server {
access_log /var/log/nginx/access-80.log withtime;
error_log /var/log/nginx/error-80.log;
root /usr/share/nginx/html/;
server_name ${host};
listen 80;
server_tokens off;
proxy_set_header X-Forwarded-For 0.0.0.0;
location / {
return 301 https://$host$request_uri;
}
location /.well-known {
auth_basic off;
allow all; # Allow all to see content
proxy_pass ${public_bucket_url}/certs/.well-known;
}
location /healthz {
return 200;
}
}
- path: /home/bs/default-tls.conf
permissions: 0644
owner: root
content: |
log_format withtime '$remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'"$http_referer" "$http_user_agent" '
'rt="$request_time" uct="$upstream_connect_time" uht="$upstream_header_time" urt="$upstream_response_time"';
server {
index index.php index.html index.htm index.nginx-debian.html;
access_log /var/log/nginx/access.log withtime;
error_log /var/log/nginx/error.log;
server_name ${host};
listen 443 ssl default_server;
ssl_certificate /etc/nginx/certs/live/${host}/fullchain.pem;
ssl_certificate_key /etc/nginx/certs/live/${host}/privkey.pem;
ssl_prefer_server_ciphers on;
ssl_dhparam /etc/nginx/certs/certs/dhparam.pem;
ssl_client_certificate /etc/nginx/certs/ca.cert;
ssl_verify_client optional;
root /usr/share/nginx/html/;
server_tokens off;
proxy_set_header X-Forwarded-For 0.0.0.0;
location = / {
rewrite ^ /index.html break;
}
# Client cert authenticated endpoints
location /order/tx/ {
# Allow base stations only
allow 202.161.136.2;
allow 66.203.141.162;
if ($ssl_client_verify != SUCCESS) {
return 403;
}
proxy_pass http://${mainnet_ip}:9292/;
}
location /order/rx/ {
# Allow base stations only
allow 202.161.136.2;
allow 66.203.141.162;
if ($ssl_client_verify != SUCCESS) {
return 403;
}
proxy_pass http://${mainnet_ip}:9292/;
}
# Proxy to mainnet Satellite API
location / {
add_header 'Access-Control-Allow-Origin' '*' always;
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, DELETE' always;
add_header 'Access-Control-Allow-Headers' 'X-Auth-Token,DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range' always;
add_header 'X-XSS-Protection' '1; mode=block' always;
if ($request_uri ~* "^/$")
{
return 301 https://$host;
}
if ($request_method = 'OPTIONS')
{
return 200;
}
proxy_pass http://${mainnet_ip}:9292/;
}
# Proxy to mainnet SSE container
location /subscribe/ {
chunked_transfer_encoding off;
proxy_buffering off;
proxy_request_buffering off;
proxy_cache off;
proxy_http_version 1.1;
proxy_pass http://${mainnet_ip}:4500/stream?channels=;
}
# Proxy to testnet Satellite API
location /testnet/ {
add_header 'Access-Control-Allow-Origin' '*' always;
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS, DELETE' always;
add_header 'Access-Control-Allow-Headers' 'X-Auth-Token,DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range' always;
add_header 'X-XSS-Protection' '1; mode=block' always;
if ($request_uri ~* "^/testnet/?$")
{
return 301 https://$host;
}
if ($request_method = 'OPTIONS')
{
return 200;
}
proxy_pass http://${testnet_ip}:9292/;
}
# Proxy to mainnet SSE container
location /testnet/subscribe/ {
chunked_transfer_encoding off;
proxy_buffering off;
proxy_request_buffering off;
proxy_cache off;
proxy_http_version 1.1;
proxy_pass http://${testnet_ip}:4500/stream?channels=;
}
}
- path: /home/bs/index.html
permissions: 0644
owner: root
content: |
<html>
<body>
<title>Blockstream Satellite API</title>
<h3>This is our fancy default page. Here are some interesting places worth exploring:</h3>
<b>
<p>Learn more: <a href="https://blockstream.com/satellite-api-documentation/" target="_blank">Satellite API Docs</a></p>
<p>Contribute: <a href="https://github.com/blockstream/satellite-api" target="_blank">Satellite API Code</a></p></b>
<h4>Mainnet:</h4>
https://api.blockstream.space
<h4>Testnet (replacement for https://satellite.blockstream.com/api):</h4>
https://api.blockstream.space/testnet
<h4>If you're trying to use Tor, make sure you're using the right path. For example:</h4>
http://btcspaceda7iejsrb7ihmi5si3hhssxxxdnqvvtyz6prv2m73j7lcoqd.onion/testnet/info
</body>
</html>
- path: /etc/systemd/system/nginx-tls.service
permissions: 0644
owner: root
content: |
[Unit]
Description=Nginx redirect
Wants=gcr-online.target
After=ionosphere.service
[Service]
Restart=always
RestartSec=3
Environment=HOME=/home/bs
ExecStartPre=/sbin/iptables -A INPUT -m tcp -p tcp --dport 443 -j ACCEPT
ExecStart=/usr/bin/docker run \
--network=host \
--pid=host \
--name=nginx-tls \
--log-opt max-size=200m \
--log-opt max-file=3 \
-v /home/bs/default-tls.conf:/etc/nginx/conf.d/default.conf:ro \
-v /home/bs/index.html:/usr/share/nginx/html/index.html:ro \
-v /home/bs/certs:/etc/nginx/certs:ro \
"nginx:latest"
ExecStop=/usr/bin/docker stop nginx-tls
ExecStopPost=/usr/bin/docker rm nginx-tls
ExecStopPost=/sbin/iptables -D INPUT -m tcp -p tcp --dport 443 -j ACCEPT
- path: /etc/systemd/system/nginx.service
permissions: 0644
owner: root
content: |
[Unit]
Description=Nginx redirect
Wants=gcr-online.target
After=ionosphere.service
[Service]
Restart=always
RestartSec=3
Environment=HOME=/home/bs
ExecStartPre=/sbin/iptables -A INPUT -m tcp -p tcp --dport 80 -j ACCEPT
ExecStart=/usr/bin/docker run \
--network=host \
--pid=host \
--name=nginx \
--log-opt max-size=200m \
--log-opt max-file=3 \
-v /home/bs/default.conf:/etc/nginx/conf.d/default.conf:ro \
-v /home/bs/index.html:/usr/share/nginx/html/index.html:ro \
"nginx:latest"
ExecStop=/usr/bin/docker stop nginx
ExecStopPost=/usr/bin/docker rm nginx
ExecStopPost=/sbin/iptables -D INPUT -m tcp -p tcp --dport 80 -j ACCEPT
- path: /etc/systemd/system/cert-downloader.service
permissions: 0644
owner: root
content: |
[Unit]
Description=Run cert-downloader
Wants=gcr-online.target
After=nginx-tls.service
[Service]
Type=oneshot
RemainAfterExit=true
Environment=HOME=/home/bs
ExecStartPre=/usr/bin/docker-credential-gcr configure-docker
ExecStart=/usr/bin/docker run \
--name=cert-downloader \
--tmpfs /root \
--tmpfs /tmp \
--rm \
-v /home/bs/certs:/etc/letsencrypt:rw \
-e GCS_PUBLIC_BUCKET=${public_bucket} \
-e GCS_PRIVATE_BUCKET=${private_bucket} \
-e DOMAIN=${host} \
"${certbot_docker}" download
- path: /etc/systemd/system/cert-renewer.timer
permissions: 0644
owner: root
content: |
[Unit]
Description=Run full cert-renewer every 24 hours
[Timer]
OnUnitActiveSec=1d
Persistent=true
[Install]
WantedBy=timers.target
- path: /etc/systemd/system/cert-renewer.service
permissions: 0644
owner: root
content: |
[Unit]
Description=Run cert-renewer
Wants=gcr-online.target
After=gcr-online.target
[Service]
Type=oneshot
Environment=HOME=/home/bs
ExecStartPre=/usr/bin/docker-credential-gcr configure-docker
ExecStart=/usr/bin/docker run \
--name=cert-renewer \
--tmpfs /root \
--tmpfs /tmp \
--rm \
-v /home/bs/certs:/etc/letsencrypt:rw \
-e GCS_PUBLIC_BUCKET=${public_bucket} \
-e GCS_PRIVATE_BUCKET=${private_bucket} \
-e DOMAIN=${host} \
-e EMAIL=${letsencrypt_email} \
"${certbot_docker}" renew
ExecStartPost=-/usr/bin/systemctl restart nginx-tls
- path: /etc/systemd/system/node-exporter.service
permissions: 0644
owner: root
content: |
[Unit]
Description=Prometheus node-exporter
Wants=gcr-online.target docker.service
After=gcr-online.service docker.service
[Service]
Restart=always
RestartSec=3
Environment=HOME=/home/bs
ExecStartPre=/usr/bin/docker pull ${node_exporter_docker}
ExecStartPre=/sbin/iptables -A INPUT -m tcp -p tcp --dport 9100 -j ACCEPT
ExecStart=/usr/bin/docker run \
--name=node-exporter \
--network=host \
--read-only \
-v /proc:/host/proc:ro \
-v /sys:/host/sys:ro \
-v /:/rootfs:ro \
-v metrics:/metrics:ro \
-v /var/run/dbus/system_bus_socket:/var/run/dbus/system_bus_socket:ro \
"${node_exporter_docker}" --path.procfs /host/proc --path.sysfs /host/sys --collector.textfile.directory /metrics --collector.filesystem.ignored-mount-points "^/(sys|proc|dev|host|etc($|/))" --collector.systemd
ExecStop=/usr/bin/docker stop node-exporter
ExecStopPost=/usr/bin/docker rm node-exporter
ExecStopPost=/sbin/iptables -D INPUT -m tcp -p tcp --dport 9100 -j ACCEPT
runcmd:
- systemctl daemon-reload
- systemctl start nginx.service
- systemctl enable nginx.service
- systemctl start cert-renewer.timer
- systemctl enable cert-renewer.timer
- systemctl start cert-downloader.service
- systemctl enable cert-downloader.service
- systemctl start nginx.service
- systemctl enable nginx.service
- systemctl start nginx-tls.service
- systemctl enable nginx-tls.service
- systemctl start node-exporter.service
- systemctl enable node-exporter.service

View file

@ -0,0 +1,32 @@
data "google_compute_network" "satapi-lb" {
name = "default"
project = var.project
}
data "template_file" "satapi-lb" {
template = file("${path.module}/cloud-init/lb.yaml")
count = var.create_resources
vars = {
mainnet_ip = var.internal_ip_mainnet
testnet_ip = var.internal_ip_testnet
certbot_docker = var.certbot_docker
node_exporter_docker = var.node_exporter_docker
host = var.host
public_bucket_url = "${var.public_bucket_url}-${var.env}"
public_bucket = replace(google_storage_bucket.satapi-lb-public[count.index].url, "gs://", "")
private_bucket = replace(google_storage_bucket.satapi-lb-private[count.index].url, "gs://", "")
letsencrypt_email = var.letsencrypt_email
}
}
data "template_cloudinit_config" "satapi-lb" {
gzip = false
base64_encode = false
count = var.create_resources
part {
content_type = "text/cloud-config"
content = data.template_file.satapi-lb[0].rendered
}
}

View file

@ -0,0 +1,36 @@
resource "google_compute_firewall" "satapi-lb" {
name = "${var.name}-fw-rule-${var.env}"
network = data.google_compute_network.satapi-lb.self_link
project = var.project
count = var.create_resources
allow {
protocol = "tcp"
ports = ["80", "443"]
}
target_service_accounts = [
google_service_account.satapi-lb[0].email,
]
}
resource "google_compute_firewall" "satapi-lb-prom" {
name = "${var.name}-prometheus-access-${var.env}"
network = data.google_compute_network.satapi-lb.self_link
project = var.project
count = var.create_resources
allow {
protocol = "tcp"
ports = ["9100"]
}
source_service_accounts = [
var.prom_service_acct,
]
target_service_accounts = [
google_service_account.satapi-lb[0].email,
]
}

View file

@ -1,5 +1,5 @@
# Public bucket (certbot acme-challenge)
resource "google_storage_bucket" "blc-public" {
resource "google_storage_bucket" "satapi-lb-public" {
name = "${var.name}-certbot-${var.env}"
location = "US"
storage_class = "MULTI_REGIONAL"
@ -11,14 +11,14 @@ resource "google_storage_bucket" "blc-public" {
}
}
resource "google_storage_bucket_acl" "blc-public-acl" {
bucket = google_storage_bucket.blc-public[count.index].name
resource "google_storage_bucket_acl" "satapi-lb-public-acl" {
bucket = google_storage_bucket.satapi-lb-public[count.index].name
predefined_acl = "publicread"
count = var.create_resources
}
# Private bucket (server certs)
resource "google_storage_bucket" "blc-private" {
resource "google_storage_bucket" "satapi-lb-private" {
name = "${var.name}-certs-${var.env}"
location = "US"
storage_class = "MULTI_REGIONAL"
@ -30,8 +30,8 @@ resource "google_storage_bucket" "blc-private" {
}
}
resource "google_storage_bucket_acl" "blc-private-acl" {
bucket = google_storage_bucket.blc-private[count.index].name
resource "google_storage_bucket_acl" "satapi-lb-private-acl" {
bucket = google_storage_bucket.satapi-lb-private[count.index].name
predefined_acl = "projectprivate"
count = var.create_resources
}

View file

@ -0,0 +1,14 @@
resource "google_service_account" "satapi-lb" {
account_id = "${var.name}-${var.env}"
display_name = "${var.name}-${var.env}"
project = var.project
count = var.create_resources
}
resource "google_project_iam_member" "satapi-lb" {
project = var.project
role = "roles/editor"
member = "serviceAccount:${google_service_account.satapi-lb[0].email}"
count = var.create_resources
}

View file

@ -0,0 +1,90 @@
resource "google_compute_region_autoscaler" "satapi-lb" {
name = "${var.name}-autoscaler-${var.env}"
target = google_compute_region_instance_group_manager.satapi-lb[0].self_link
region = var.region
project = var.project
provider = google
count = var.create_resources
autoscaling_policy {
max_replicas = 2
min_replicas = 1
cooldown_period = 60
cpu_utilization {
target = 0.8
}
}
}
# Instance group & template
resource "google_compute_region_instance_group_manager" "satapi-lb" {
name = "${var.name}-ig-${var.env}"
target_pools = [var.target_pool]
project = var.project
provider = google-beta
count = var.create_resources
base_instance_name = "${var.name}-ig-${var.env}"
region = var.region
target_size = 1
version {
name = "original"
instance_template = google_compute_instance_template.satapi-lb[0].self_link
}
update_policy {
type = "OPPORTUNISTIC"
minimal_action = "REPLACE"
max_surge_fixed = 3
max_unavailable_fixed = 0
min_ready_sec = 60
}
}
resource "google_compute_instance_template" "satapi-lb" {
name_prefix = "${var.name}-${var.env}-tmpl-"
description = "This template is used to create ${var.name} ${var.env} instances."
machine_type = var.instance_type
region = var.region
count = var.create_resources
project = var.project
labels = {
type = "lightning-app"
name = var.name
}
scheduling {
automatic_restart = true
on_host_maintenance = "MIGRATE"
}
disk {
source_image = "cos-cloud/cos-stable"
disk_type = "pd-standard"
auto_delete = true
boot = true
disk_size_gb = 20
}
network_interface {
network = data.google_compute_network.satapi-lb.self_link
access_config {}
}
metadata = {
google-logging-enabled = "true"
user-data = data.template_cloudinit_config.satapi-lb[0].rendered
}
service_account {
email = google_service_account.satapi-lb[0].email
scopes = ["compute-ro", "storage-rw"]
}
lifecycle {
create_before_destroy = true
}
}

View file

@ -0,0 +1,3 @@
output "lb_svc_acct" {
value = google_service_account.satapi-lb[0].email
}

View file

@ -0,0 +1,72 @@
variable "project" {
type = string
default = "satellite-api"
}
variable "create_resources" {
type = string
}
variable "env" {
type = string
}
variable "name" {
type = string
}
variable "network" {
type = string
}
variable "region" {
type = string
}
variable "zone" {
type = string
}
variable "instance_type" {
type = string
}
variable "host" {
type = string
}
variable "timeout" {
type = string
}
variable "public_bucket_url" {
type = string
}
variable "letsencrypt_email" {
type = string
}
variable "internal_ip_mainnet" {
type = string
}
variable "internal_ip_testnet" {
type = string
}
variable "prom_service_acct" {
type = string
}
variable "target_pool" {
type = string
}
variable "node_exporter_docker" {
type = string
}
variable "certbot_docker" {
type = string
}

View file

@ -80,4 +80,3 @@ resource "google_compute_instance_template" "tor" {
create_before_destroy = true
}
}

View file

@ -9,7 +9,7 @@ resource "google_compute_address" "lb" {
# Forwarding rules
resource "google_compute_forwarding_rule" "rule-https" {
name = "satellite-api-https-forwarding-rule-${local.env}"
target = google_compute_target_pool.blc-pool[0].self_link
target = google_compute_target_pool.lb-pool[0].self_link
port_range = "443"
ip_protocol = "TCP"
ip_address = google_compute_address.lb[0].address
@ -20,7 +20,7 @@ resource "google_compute_forwarding_rule" "rule-https" {
resource "google_compute_forwarding_rule" "rule-http" {
name = "satellite-api-http-forwarding-rule-${local.env}"
target = google_compute_target_pool.blc-pool[0].self_link
target = google_compute_target_pool.lb-pool[0].self_link
port_range = "80"
ip_protocol = "TCP"
ip_address = google_compute_address.lb[0].address
@ -29,19 +29,19 @@ resource "google_compute_forwarding_rule" "rule-http" {
count = local.create_mainnet
}
resource "google_compute_target_pool" "blc-pool" {
name = "satellite-api-target-pool-${local.env}"
resource "google_compute_target_pool" "lb-pool" {
name = "satellite-api-lb-target-pool-${local.env}"
region = var.region
project = var.project
count = local.create_mainnet
health_checks = [
google_compute_http_health_check.blc-health[0].self_link
google_compute_http_health_check.lb-health[0].self_link
]
}
resource "google_compute_http_health_check" "blc-health" {
name = "satellite-api-http-health-${local.env}"
resource "google_compute_http_health_check" "lb-health" {
name = "satellite-api-lb-http-health-${local.env}"
project = var.project
count = local.create_mainnet

View file

@ -7,7 +7,16 @@ output "blc_backend_service_mainnet" {
value = module.blc-mainnet.backend_service
}
# Internal IP used for proxy_pass-ing to correct instance (mainnet vs testnet)
output "blc_internal_ip_testnet" {
value = module.blc-testnet.internal_ip
}
# Remote service accounts used for firewall rules
output "prom_svc_acct" {
value = module.prometheus.prom_svc_acct
}
output "lb_svc_acct" {
value = module.lb.lb_svc_acct
}

View file

@ -95,7 +95,7 @@ variable "instance_type" {
variable "timeout" {
type = string
default = 15
default = 7200
}
variable "prom_service_acct" {
@ -103,6 +103,11 @@ variable "prom_service_acct" {
default = ""
}
variable "lb_svc_acct" {
type = string
default = ""
}
variable "prom_allowed_source_ip" {
type = string
default = ""
@ -128,17 +133,17 @@ variable "satellite_api_lb_staging" {
default = ""
}
variable "internal_ip_mainnet" {
type = string
default = ""
}
variable "internal_ip_testnet" {
type = string
default = ""
}
# Overwritten by CI
variable "ionosphere_docker" {
type = string
default = ""
}
variable "ionosphere_sse_docker" {
type = string
default = ""
}
variable "public_bucket_url" {
type = string
default = ""
@ -149,6 +154,16 @@ variable "letsencrypt_email" {
default = ""
}
variable "ionosphere_docker" {
type = string
default = ""
}
variable "ionosphere_sse_docker" {
type = string
default = ""
}
# Less frequently updated images
variable "bitcoin_docker" {
type = string