This guide explains how to deploy Redstring to both production and test environments on Google Cloud Run.
Redstring has two separate deployment environments:
- Production (
your-service-name): Live production environment athttps://redstring.io - Test (
redstring-test): Testing/development environment athttps://redstring-test-umk552kp4q-uc.a.run.app
Each environment uses its own GitHub App and OAuth credentials to ensure complete isolation.
./scripts/fast-deploy-prod.shWhat it does:
- Builds with production URLs (
https://redstring.io) - Uses production GitHub App (
redstring-semantic-sync) - Uses production OAuth credentials
- Deploys to
your-service-nameCloud Run service - Sets
NODE_ENV=productionandLOG_LEVEL=warn
./scripts/fast-deploy-test.shWhat it does:
- Builds with test URLs (
https://redstring-test-umk552kp4q-uc.a.run.app) - Uses test GitHub App (
redstring-semantic-sync-test) - Uses test OAuth credentials
- Deploys to
redstring-testCloud Run service - Sets
NODE_ENV=developmentandLOG_LEVEL=info
GitHub App:
- App ID:
YOUR_APP_ID - App Slug:
redstring-semantic-sync - Client ID:
YOUR_CLIENT_ID
OAuth:
- Client ID:
Ov23liYygPgJ9Tzcbvg6 - Callback:
https://redstring.io/oauth/callback
GCP Secrets Used:
github-app-id:latestgithub-app-client-id:latestgithub-app-client-secret:latestgithub-app-private-key:latestgithub-app-slug:latestgithub-client-id:latestgithub-client-secret:latest
GitHub App:
- App ID:
YOUR_APP_ID(same as prod, but different installation) - App Slug:
redstring-semantic-sync-test - Client ID:
YOUR_CLIENT_ID(same as prod)
OAuth:
- Client ID:
Ov23li1dnhS3KhBcHnup - Callback:
https://redstring-test-umk552kp4q-uc.a.run.app/oauth/callback
GCP Secrets Used:
github-app-id-test:latestgithub-app-client-id-test:latestgithub-app-client-secret-test:latestgithub-app-private-key-test:latestgithub-app-slug-test:latestgithub-client-id-test:latestgithub-client-secret-test:latest
The OAuth server automatically detects which environment it's running in:
function isLocalRequest(req) {
const host = (req.headers['x-forwarded-host'] || req.headers.host || '').toString().toLowerCase();
// Treat localhost AND redstring-test deployment as dev/test
return host.includes('localhost') ||
host.includes('127.0.0.1') ||
host.includes('redstring-test');
}Based on this detection:
- Test environment uses
*-testsecrets andredstring-semantic-sync-testapp slug - Production uses production secrets and
redstring-semantic-syncapp slug
-
Dockerfile Selection:
- Production:
deployment/docker/Dockerfile - Test:
deployment/docker/Dockerfile.test
- Production:
-
Build Arguments:
VITE_BRIDGE_URL: Base URL for API callsVITE_OAUTH_URL: OAuth server URL
-
Secret Injection:
- Secrets are mounted at runtime via Cloud Run
- No secrets are baked into the Docker image
┌─────────────────┐
│ npm run build │ ← Vite build with environment URLs
└────────┬────────┘
│
▼
┌─────────────────┐
│ Docker Build │ ← Package app + server code
└────────┬────────┘
│
▼
┌─────────────────┐
│ Push to GCR │ ← Google Container Registry
└────────┬────────┘
│
▼
┌─────────────────┐
│ Deploy to Run │ ← Cloud Run with environment secrets
└─────────────────┘
# Production
curl https://redstring.io/health
# Test
curl https://redstring-test-umk552kp4q-uc.a.run.app/health# Production
curl https://redstring.io/api/github/oauth/client-id
# Test
curl https://redstring-test-umk552kp4q-uc.a.run.app/api/github/oauth/client-id# Production (should return redstring-semantic-sync)
curl https://redstring.io/api/github/app/info
# Test (should return redstring-semantic-sync-test)
curl https://redstring-test-umk552kp4q-uc.a.run.app/api/github/app/infogcloud secrets list --project=your-project-id | grep github# Example: Update production OAuth client secret
echo -n "NEW_SECRET_VALUE" | gcloud secrets versions add github-client-secret \
--data-file=- \
--project=your-project-id# Example: View production GitHub App ID
gcloud secrets versions access latest \
--secret="github-app-id" \
--project=your-project-idSymptom: Test deployment redirects to production GitHub App
Solution: Verify the test deployment is using the correct secrets:
gcloud run services describe redstring-test \
--region=us-central1 \
--project=your-project-id \
--format="value(spec.template.spec.containers[0].env)"Symptom: After GitHub authentication, redirect fails
Solution: Verify the callback URLs are correctly configured in GitHub:
- Production:
https://redstring.io/oauth/callback - Test:
https://redstring-test-umk552kp4q-uc.a.run.app/oauth/callback
Symptom: Deployment uses old credentials
Solution: Cloud Run caches secret versions. Force a new deployment:
# For production
./scripts/fast-deploy-prod.sh
# For test
./scripts/fast-deploy-test.sh# Production logs
gcloud logging read 'resource.type=cloud_run_revision AND resource.labels.service_name=your-service-name' \
--limit=50 \
--project=your-project-id
# Test logs
gcloud logging read 'resource.type=cloud_run_revision AND resource.labels.service_name=redstring-test' \
--limit=50 \
--project=your-project-id# Production
gcloud run services describe your-service-name \
--region=us-central1 \
--project=your-project-id
# Test
gcloud run services describe redstring-test \
--region=us-central1 \
--project=your-project-id- Never commit private keys to the repository
- Always use GCP Secret Manager for sensitive data
- Rotate secrets regularly using versioned secrets
- Use test environment for development and testing
- Review logs for unauthorized access attempts
If a deployment fails, you can rollback to a previous revision:
# List revisions
gcloud run revisions list --service=your-service-name --region=us-central1
# Rollback to specific revision
gcloud run services update-traffic your-service-name \
--to-revisions=REVISION_NAME=100 \
--region=us-central1These scripts can be integrated into CI/CD pipelines:
# Example GitHub Actions workflow
deploy-test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: google-github-actions/setup-gcloud@v1
- run: ./scripts/fast-deploy-test.sh
deploy-prod:
needs: deploy-test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: google-github-actions/setup-gcloud@v1
- run: ./scripts/fast-deploy-prod.sh