Files
NetworkCatsandClaude Opus 5.5 cd46024a46 Restrict HTTPS to Cloudflare with UFW on the host
The Vultr firewall now only opens 443 (and SSH); the host decides who may
use it. Docker-published ports bypass UFW's INPUT rules, so the new
firewall role routes Docker traffic through UFW's route rules via the
DOCKER-USER chain and allows Cloudflare's IPv4 ranges on 443 with
`ufw route allow`. ufw-cloudflare-sync keeps those rules in step with
https://www.cloudflare.com/ips-v4 daily via a systemd timer, refusing
to touch the rules if the list looks wrong.

The role runs on every deploy, before HAProxy starts, and fails the
deploy if the filtering is not in place, since HAProxy trusts
CF-Connecting-IP from anything that reaches it. The plain UFW allows
for 80/443 are dropped from the base role as they never applied to
Docker-published ports.

Rotating the deploy SSH key now rebuilds the instance, because Vultr
only installs SSH keys at creation.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-22 21:13:48 +08:00

3.1 KiB

Installation

Required GitHub Secrets

Go to Settings > Secrets and variables > Actions in your GitHub repository and add the following secrets.

If you are using environments, add them under the production environment (Settings > Environments > production).

Terraform State (S3-compatible backend)

Secret Description
TF_STATE_ACCESS_KEY Access key for the S3-compatible state backend (e.g. Cloudflare R2)
TF_STATE_SECRET_KEY Secret key for the S3-compatible state backend
TF_STATE_BUCKET Bucket name where Terraform state is stored
TF_STATE_ENDPOINT S3-compatible endpoint URL (e.g. https://<account_id>.r2.cloudflarestorage.com)

Infrastructure

Secret Description
VULTR_API_KEY Vultr API key for provisioning VPS and firewall resources
SSH_PUBLIC_KEY Public key deployed to the VPS for SSH access
SSH_PRIVATE_KEY Corresponding private key used by the pipeline to connect via SSH

Application

Secret Description
SITE_DOMAIN Production domain name (e.g. ip.nc.gy)
DB_UPDATE_URL URL to download the MMDB database from
IPV4_DOMAIN (Optional) IPv4-only domain for dual-stack detection (e.g. noipv6.org). Omit to disable.

TLS

Secret Description
ORIGIN_CERT Cloudflare Origin certificate (PEM) for TLS termination at HAProxy
ORIGIN_KEY Corresponding private key (PEM) for the Origin certificate
IPV4_ORIGIN_CERT (Optional) Cloudflare Origin certificate (PEM) for the IPv4-only domain. Required when IPV4_DOMAIN is set.
IPV4_ORIGIN_KEY (Optional) Corresponding private key (PEM) for the IPv4-only domain certificate. Required when IPV4_DOMAIN is set.

Docker Hub

Secret Description
DOCKERHUB_USERNAME Docker Hub username used for image push and pull
DOCKERHUB_TOKEN Docker Hub access token for authentication

Code Coverage with Codecov

  1. Sign up at codecov.io and add your repository.
  2. Copy the upload token from the Codecov repository settings page.
  3. Add a CODECOV_TOKEN secret to your GitHub repository under Settings > Secrets and variables > Actions.

Deploying

git tag v1.0.0
git push origin v1.0.0

This triggers the full pipeline. Monitor progress under the Actions tab in the repository.

Infrastructure Details

  • VPS: Vultr High Frequency (vhf-1c-1gb, 1 vCPU / 1 GB), Debian 13, region sjc (Silicon Valley)
  • Firewall: Vultr opens SSH and HTTPS; on the host, UFW limits HTTPS to Cloudflare's IPv4 ranges, refreshed daily by ufw-cloudflare-sync.timer (Docker-published ports are filtered via the DOCKER-USER chain)
  • Deployment: Blue-green with HAProxy traffic switching
  • First deploy: Automatically applies base OS hardening (UFW, fail2ban, sysctl tuning) and installs Docker
  • Subsequent deploys: The firewall rules are re-applied and the application container is updated via blue-green swap
  • Rotating the SSH key: Updating SSH_PUBLIC_KEY/SSH_PRIVATE_KEY rebuilds the instance on the next deploy (new IP; update DNS afterwards)