pushcdn

Upload a file, get a public URL. A small Go CLI that publishes assets to a Google Cloud Storage bucket served through Cloud CDN.

Free and MIT licensed. macOS and Linux, amd64 and arm64.

What it is for

Files that need a stable public URL and nothing else.

A logo for an email signature, a resume PDF, an image shared in a chat. They all live in one public bucket behind a custom domain. pushcdn uploads them with sensible headers and prints the URL.

Upload

One or many files, optional destination folder or rename, content type inferred from the extension, progress bar on a terminal.

List with globs

Prefix match or server-side glob such as '*logo*', so listings stay fast on large buckets.

Delete with confirmation

pushcdn rm asks before deleting.

Cache headers

Defaults to public, max-age=3600. Override per upload with --cache-control.

No credentials to manage

Uses Application Default Credentials from gcloud. No token cache, no service account file.

Bucket included

The repository ships the Terraform for the public bucket.

Install

Homebrew

brew tap bcollard/push-to-cdn
brew install --cask push-to-cdn

Go

go install github.com/bcollard/push-to-cdn@latest

Binary

Download an archive from GitHub Releases and put pushcdn on your PATH.

Quick start

# one-time setup
gcloud auth application-default login
pushcdn config set bucket   cdn.runlocal.dev
pushcdn config set base-url https://cdn.runlocal.dev

# upload
pushcdn upload ~/Pictures/logo.png
# https://cdn.runlocal.dev/logo.png

# upload into a folder, or rename
pushcdn upload logo.png -d brand/
pushcdn upload logo.png -d brand/icon.png

# list, filter, delete, print URL
pushcdn ls
pushcdn ls '*logo*'
pushcdn rm old.png
pushcdn url logo.png

Configuration

Resolution order: environment variable, stored config, built-in default.

KeyEnvironment variableDescription
bucketPUSHCDN_BUCKETGCS bucket name
projectPUSHCDN_PROJECTGCP project ID (informational)
base-urlPUSHCDN_BASE_URLPublic URL prefix used when printing URLs

Stored in ~/.config/pushcdn/config.json with mode 0600.

FAQ

Are uploaded files private?
No. The bucket grants roles/storage.objectViewer to allUsers. Everything in it is public. Do not upload anything sensitive.
Can I use my own bucket and domain?
Yes. Set bucket and base-url. The Terraform in the repository creates the bucket. The load balancer and DNS are separate.
Why does the bucket name need domain verification?
GCS only allows dotted bucket names such as cdn.runlocal.dev after you verify domain ownership in Google Search Console. A hyphenated name such as cdn-runlocal-dev avoids that step.
How do I change an object that is already cached?
Cloud CDN honors Cache-Control. Upload with a short --cache-control value, or upload under a new name.