Skip to content

Latest commit

 

History

3 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 

Repository files navigation

Readeck on Cloud Run

Deploy Readeck (read-it-later / bookmark manager) on Google Cloud Run with persistent storage using a Cloud Storage bucket.

This repository provides a simple script to deploy a personal instance with minimal setup.


Overview

This setup runs Readeck in a single Cloud Run instance and stores data in a mounted Cloud Storage bucket.

Key characteristics:

  • Stateless container (Cloud Run)
  • Persistent storage via mounted bucket
  • SQLite database
  • Single instance to avoid concurrency issues
  • Least-privilege service account, secret held in Secret Manager

Why this setup

This deployment is designed for personal use:

  • Simple to deploy (single script)
  • No database to manage (SQLite)
  • Very low cost

Cost considerations

For light usage (a few requests per day):

  • Cloud Run: often free (within free tier)
  • Cloud Storage: a few cents per month
  • Artifact Registry: negligible
  • Secret Manager: free (one active secret version, free tier covers six)

👉 In practice, this setup typically costs ~0–1€/month for personal usage.

Note that Cloud Run and Cloud Storage free tiers are counted per billing account, not per project, so they are shared with anything else you host.

Trade-offs:

  • Not scalable (single instance)
  • Not suitable for teams or heavy traffic

Architecture

Cloud Run
  └─ Readeck container  (runs as readeck-sa)
        ├─ /readeck (mounted bucket)
        └─ READECK_SECRET_KEY (from Secret Manager)

Artifact Registry
  └─ Docker image (mirrored from Codeberg, version-pinned)

Cloud Storage
  └─ SQLite database + files

Secret Manager
  └─ readeck-secret-key

Requirements

  • Google Cloud project, with billing enabled
  • gcloud CLI installed and authenticated
  • crane or Docker, to mirror the image into your project

Readeck is only published on the Codeberg container registry, which Cloud Run cannot pull from. The image therefore has to be copied into your own Artifact Registry. crane is the lighter option since it needs no daemon:

brew install crane

The script uses crane if present and falls back to Docker otherwise.


Deployment

1. Clone the repository

git clone https://github.com/arenier/readeck-run.git
cd readeck-run

2. Configure

Set your environment variables:

export PROJECT_ID="your-project-id"
export REGION="europe-west1"
export READECK_VERSION="0.22.3"   # optional, defaults to the pinned version

PROJECT_ID and REGION fall back to your gcloud configuration if unset.

3. Run

chmod +x deploy.sh
./deploy.sh

What the script does

  • Enables the required Google Cloud APIs
  • Creates an Artifact Registry repository
  • Mirrors the pinned Readeck image from Codeberg into your project
  • Creates a Cloud Storage bucket, with uniform bucket-level access and public access prevention
  • Creates a dedicated service account, granted access to that bucket only
  • Generates READECK_SECRET_KEY in Secret Manager on first run, and reuses it afterwards
  • Deploys the Cloud Run service

Every step is guarded, so the script is idempotent: running it again against an existing deployment updates the service without recreating the bucket, the service account or the secret.


Access

After deployment, a URL is displayed in the terminal.

Open it in your browser and create your account. Do this promptly — the service is deployed with --allow-unauthenticated, so until an account exists anyone reaching the URL could create the first one.


Update

Readeck releases roughly monthly. To upgrade, bump the pinned version and run the script again:

export READECK_VERSION="0.23.0"
./deploy.sh

The script mirrors the new image and deploys it. Your data and your secret key are left untouched.

Do not replace READECK_SECRET_KEY on an existing install. Readeck derives other keys from it, so changing it invalidates API tokens, application passwords and share links. The script creates it once and never regenerates it.


Security notes

A few deliberate choices, worth knowing if you adapt this script:

  • Dedicated service account. Without --service-account, Cloud Run falls back to the default Compute service account, which holds roles/editor on the entire project. Readeck fetches arbitrary URLs by design, so a container compromise would otherwise reach every resource you own. The service account here is granted roles/storage.objectAdmin on its own bucket and nothing else.
  • Secret in Secret Manager, not an environment variable. A plaintext env var is readable by anyone with roles/run.viewer on the project, and it is not audit-logged. The secret key signs sessions and CSRF tokens, so it is worth protecting.
  • Bucket hardening. --uniform-bucket-level-access makes IAM the only access path by disabling per-object ACLs; --public-access-prevention makes it impossible to grant the bucket to allUsers, even by accident.
  • Version pinning. Deploying :latest means you cannot tell which version is running, and a new upstream push would silently change your deployment.
  • IAM propagation. A freshly created service account is not immediately usable in IAM bindings. The script retries for up to two minutes rather than failing on a race.

The service itself is public (--allow-unauthenticated), relying on Readeck's own authentication. If you want network-level filtering or rate limiting, that requires putting an external HTTPS load balancer and Cloud Armor in front, which adds a fixed monthly cost well above the rest of this setup.


Limitations

  • SQLite is stored on a mounted bucket (not a full POSIX filesystem)
  • Only one instance is allowed (max-instances=1), which is required for SQLite over gcsfuse
  • During a deployment, the new and old revisions may briefly overlap, so avoid deploying while the app is in use
  • Not designed for high traffic or team usage

Production setup

For a more robust setup, consider:

  • Using PostgreSQL (Cloud SQL)
  • Removing the single-instance limitation
  • Setting a billing budget alert, since the service is publicly reachable

License

MIT


Credits

Inspired by https://github.com/daniefdz/actual-run

About

No description, website, or topics provided.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages