Host Operations

Run your own instance of the UHRP Storage Server

Read as Markdown

You don’t need to deploy your own server to start using UHRP—our public instance (https://nanostore.babbage.systems) already works with the StorageUploader, StorageDownloader, and React components. Follow the steps below only if you want to run and manage a self‑hosted UHRP Storage Server (e.g., for custom pricing, data residency, or full control over upgrades)

UHRP Storage Server – Deployment Guide

This guide walks you through deploying UHRP Storage Server on Google Cloud Platform (GCP) with continuous delivery via GitHub Actions. When you finish, you’ll have:

  • A single‑region Cloud Storage bucket that stores all UHRP data.

  • A Cloud Run service that handles uploads, billing, and API requests.

  • A Cloud Run service that handles the broadcasting and advertising of your UHRP data.

  • An HTTP Load Balancer that fronts both the bucket (static files) and Cloud Run (dynamic API) behind a custom HTTPS domain.

  • A GitHub Actions workflow (deploy.yaml) that rebuilds and redeploys automatically whenever you push to the master or production branch.

Security note The IAM roles in this tutorial are intentionally permissive to minimise friction. Feel free to tighten them once everything works.


Prerequisites

GCP Project with billing Create a new Project on Google Cloud Platform that you have owner or editor access and is funded

GitHub account & repo You will fork/clone and push the code to your own repository.

Domain name Optional but recommended for the HTTPS front‑end (e.g. storage.example.com).

gcloud CLI Only required for the few shell commands shown below. Everything else uses the Cloud Console UI.


1 Get the code into your GitHub

  1. Fork the original repository or clone and push:

    1git clone https://github.com/bsv-blockchain/storage-server.git
    2cd storage-server
    3git remote remove origin
    4git remote add origin <your‑github‑repo‑url.git>
    5git push origin master   # or production for your mainnet branch
    Copied!
  2. Verify that your repo contains .github/workflows/deploy.yaml. All future pushes to master or production will trigger this workflow.


2 Google Cloud setup (Console UI)

2.1 Create a single‑region bucket

  1. Storage > Buckets > Create bucket.

  2. Name  <unique‑bucket‑name> (e.g. my‑uhrp‑bucket).

  3. Region  Select a single region (e.g. us‑west1).

  4. Storage class  Choose Autoclass.
    GCS will now shift each object between Standard and Nearline automatically, giving you the lowest possible storage cost when access patterns change.

  5. Data protection  Turn the extras off:

    • Soft delete policy  Unchecked → We don’t keep 7‑day recovery copies; deletes are immediate.

    • Object versioning  Unchecked

    • Retention  Unchecked

  6. Access control Default; make sure Public access prevention is Off.

  7. Create

  8. Apply CORS rules: Run these commands from a terminal in the root of your cloned storage‑server repository (e.g., your local shell or Cloud Shell).

    1gcloud auth login
    2gcloud config set project <id>
    3gsutil cors set bucket-cors-config.json gs://<your-bucket-name>
    Copied!

bucket-cors-config.json is provided in the repo root; edit it if you need to restrict origins.

2.2 Enable required APIs

Open APIs & Services > Library, search each API, click Enable. Open APIs & Services > Library, search each API, click Enable:

APIWhy it’s needed
Cloud Run Admin APICreate, update, and route traffic to the Cloud Run service.
Cloud Functions APIDeploys the notifier function used for on‑chain events.
Cloud Logging APICaptures structured logs from Cloud Run and the load balancer.
Cloud Pub/Sub APIDelivers bucket‑create events (and other messages) to the notifier.
Eventarc APIConnects Cloud Storage events to Cloud Run/Functions reliably.
Artifact Registry APIHosts container images built by GitHub Actions.
Cloud Build APIBuilds the Docker image inside GCP when you deploy from source.
Service Usage APILets other services (and the GitHub SA) enable additional APIs programmatically.
Cloud Resource Manager APIAllows IAM policy updates at the project level.
Identity and Access Management (IAM) APIGrants and tests roles for service accounts.
Compute Engine APIBacks load balancer & VPC resources under the hood.

It can take a minute or two for each API to flip to Enabled.

2.3 Initial IAM policy bindings (required for Eventarc)

Run these two commands before assigning roles to service accounts. They give Eventarc and Pub/Sub the bucket/project access they need.

1gcloud storage buckets add-iam-policy-binding gs://<your-bucket-name> \
2  --member=serviceAccount:service-$(gcloud projects describe <your-project-name> --format="value(projectNumber)")@gcp-sa-eventarc.iam.gserviceaccount.com \
3  --role=roles/storage.legacyBucketReader
4
5gcloud projects add-iam-policy-binding <your-project-name> \
6  --member=serviceAccount:service-$(gcloud projects describe <your-project-name> --format="value(projectNumber)")@gs-project-accounts.iam.gserviceaccount.com \
7  --role=roles/pubsub.publisher
Copied!

Replace <your-bucket-name> / <your-project-name> with your bucket & project.

2.4 Service accounts and roles

2.4.1 GitHub Actions deployer service account

  • Create IAM & Admin > Service accounts > Create → uhrp-github-deployer.

  • Grant roles:

    • Cloud Run Admin

    • Cloud Functions Admin

    • Cloud Build Editor

    • Artifact Registry Administrator

    • Storage Object Admin

    • Service Account User

  • Keys tab > Add key > JSON – download and keep safe. You’ll paste this into a GitHub secret.

2.4.2 Default Compute Engine service account

  • Find it at IAM & Admin > IAM (email ends with compute@developer.gserviceaccount.com).

  • Give it all of these roles:

    • Artifact Registry Administrator

    • Cloud Run Admin

    • Eventarc Admin

    • Logs Writer

    • Service Account Admin

    • Service Account User

    • Storage Object Admin

This SA becomes the runtime identity for Cloud Run, so the bucket permissions propagate automatically.


3 Add GitHub repository secrets

The examples below use the STAGING_ prefix. For a production deployment create the same secrets with PROD_ instead and push to the production branch.

SecretWhat it's forExample
STAGING_ADMIN_TOKENBearer token granting admin API calls (e.g., content migration)super‑secret‑admin‑token
STAGING_BSV_NETWORKWhich Bitcoin SV network the server talks totestnet or mainnet
STAGING_GCP_BUCKET_NAMEThe Cloud Storage bucket you createdmy-uhrp-bucket
STAGING_GOOGLE_PROJECT_IDYour GCP project IDmy‑gcp‑project
STAGING_GCR_HOSTContainer registry host (gcr.io, us.gcr.io, or Artifact Registry host)us.gcr.io
STAGING_GCR_IMAGE_NAMERepository/image name for the containeruhrp/uhrp-storage
STAGING_GCP_STORAGE_CREDSRaw JSON for the runtime service account that Cloud Run uses to access the bucket{ "type": "service_account", ... }
STAGING_GCR_PUSH_KEYBase64‑encoded JSON of the deployer service‑account key (used by the Action to push the image)ewogICJ0eXBlIjogInNlcnZpY2VfYWNjb3VudCIsIC4uLn0=
STAGING_HOSTING_DOMAINPublic HTTPS domain for your load balancerstorage.example.com
STAGING_HTTP_PORTPort your app listens on inside the container3104
STAGING_MIN_HOSTING_MINUTESMinimum retention billed per upload15
STAGING_NODE_ENVNode environment string passed to the appstaging or production
STAGING_PRICE_PER_GB_MOMonthly price (USD) per GB stored0.03
STAGING_SERVER_PRIVATE_KEY32‑byte hex private key used to sign on‑chain ops58d23bd395c55041c65d415357b524fc2f07802c58d23bd395c55041c65d4153
STAGING_WALLET_STORAGE_URLURL of the Toolbox Wallet storage serverhttps://staging-storage.babbage.systems

Add them in GitHub Settings > Secrets and variables > Actions.


4 Understand the GitHub Actions workflow

deploy.yaml will:

  1. Authenticate to GCP using STAGING_GCR_PUSH_KEY and STAGING_GOOGLE_PROJECT_ID.

  2. Build & push the Docker image <GCR_HOST>/<PROJECT>/<IMAGE_NAME>:branch‑sha.

  3. Generate a service.<branch>.yaml manifest with all environment variables.

  4. Deploy/replace the Cloud Run service in the bucket’s region.

  5. Deploy the notifier Cloud Function.

Every push to master triggers the staging deployment. A push to production does the same but reads the PROD_* secrets.


5 Trigger the first deployment

  1. Commit any change and push to master.

  2. Watch GitHub > Actions → Deployment run. Green check = success.

  3. In GCP Cloud Run > Services, verify a new service appears in your chosen region. Click its URL to confirm the server responds.

  4. The initial deploy is private, so you may see 403 Forbidden. Grant public invoke rights:

    1gcloud run services add-iam-policy-binding <SERVICE_NAME> \
    2  --region <REGION> \
    3  --platform managed \
    4  --member="allUsers" \
    5  --role="roles/run.invoker"
    Copied!

Replace <SERVICE_NAME> with the Cloud Run service name and <REGION> with your region (e.g., us‑west1). After a minute, loading the service URL should return a JSON status instead of 403.


6 Create an HTTPS load balancer

6.1 Frontend configuration

SettingValue
ProtocolHTTPS
IP versionIPv4
IP addressCreate a new static IP (e.g., staging-uhrp-ingress-ip)
Port443
CertificateCreate new → Google‑managed (enter STAGING_HOSTING_DOMAIN, e.g., storage.example.com)
RedirectEnable HTTP → HTTPS redirect

6.2 Backend configuration

6.2.1 Backend Service → Cloud Run

FieldValue
Backend typeServerless network endpoint group (SNEG)
Serverless network endpoint groupsCreate new
Cloud Run regionSame region as your bucket
Cloud Run serviceSelect the service deployed by GitHub Actions (the main storage service, not the notifier)
Cloud CDNDisabled
Security policyDefault

Save to create the backend service (e.g., uhrp-backend-service).

6.2.2 Backend bucket → Cloud Storage

FieldValue
BucketYour previously created bucket
Cloud CDNEnabled (leave defaults)

6.3 Host & path rules

Add a rule that routes CDN requests to the bucket and everything else to Cloud Run:

HostPathBackend
*/cdn/*Backend bucket

6.4 Create and test

Click Create and wait a few minutes. Then:

  1. Create an A record pointing your hosting domain to the load‑balancer IP (This may take a few hours).

  2. Wait for DNS propagation. The Google‑managed certificate will turn Active automatically.

  3. Test: Go to https://uhrp-ui.bapp.dev/ and test uploading and downloading with your hosting domain.

Everything is now live, secure, and fronted by a global HTTPS load balancer.


7 Next steps & hardening

  • Restrict Cloud Run to accept traffic only from the load balancer’s identity instead of allUsers.

  • Replace broad roles with narrower ones (e.g., Storage Object Viewer instead of Admin). Be sure to update the bucket IAM accordingly.

  • Set up monitoring & alerts in Cloud Monitoring.


© 2025 – Feel free to adapt, improve, and PR!

Was this page helpful?