ProPresenter Lyrics Export

Logo

Extract and export worship song lyrics from ProPresenter 7

View the Project on GitHub adamswbrown/propresenterlyricexport

Web Proxy Setup Guide (Manual)

← Back to Home User Guide Proxy App Guide (GUI)

Prefer a GUI? The Web Proxy App is a macOS menu bar application that manages the web server and tunnel for you — no terminal required. This guide covers the manual, terminal-based setup.

Access ProPresenter Lyrics Export from any device — phone, tablet, or remote computer — through a secure web interface exposed via Cloudflare Tunnel.

Table of Contents

  1. Overview
  2. Prerequisites
  3. Step 1: Google OAuth Setup
  4. Step 2: Install Cloudflare Tunnel
  5. Step 3: Create a Tunnel
  6. Step 4: Configure Environment
  7. Step 5: Build and Start the Server
  8. Step 6: Add Users
  9. Running as a Service
  10. Quick Start (Testing Only)
  11. Troubleshooting
  12. Security Notes
  13. Environment Variable Reference

Overview

The web proxy lets remote users access your ProPresenter installation through a browser. The architecture is:

User's browser  →  Cloudflare Tunnel  →  Web proxy (your machine)  →  ProPresenter API

Key features:


Prerequisites


Step 1: Google OAuth Setup

Google OAuth lets your users sign in with their Google account. Only emails you approve can access the app.

1a. Create a Google Cloud Project

  1. Go to console.cloud.google.com
  2. Click the project selector dropdown (top navigation bar)
  3. Click New Project
  4. Enter a name (e.g., “ProPresenter Web”) and click Create
  5. Select the new project from the dropdown
  1. Navigate to Google Auth Platform > Overview > Get Started
    • (Or the older path: APIs & Services > OAuth consent screen)
  2. Set User type:
    • Internal — if all your users are on the same Google Workspace domain (simplest)
    • External — if your users have personal Gmail accounts
  3. Fill in the required fields:
Field What to enter
App name ProPresenter Web (or your preferred name)
User support email Your email address
Developer contact email Your email address
  1. Click Save and Continue

1c. Add Scopes

  1. Click Add or Remove Scopes
  2. Add these three scopes:
    • openid
    • .../auth/userinfo.email
    • .../auth/userinfo.profile
  3. Click Update, then Save and Continue

These are all non-sensitive scopes — no Google verification is required, even for production use.

1d. Create OAuth Credentials

  1. Navigate to Google Auth Platform > Clients > Create Client
    • (Or: APIs & Services > Credentials > Create Credentials > OAuth client ID)
  2. Set Application type to Web application
  3. Enter a name (e.g., “ProPresenter Web Client”)
  4. Under Authorized redirect URIs, click Add URI and enter:
    https://YOUR-DOMAIN.example.com/auth/google/callback
    

    Replace YOUR-DOMAIN.example.com with your actual tunnel hostname (configured in Step 3).

  5. Click Create

1e. Copy Credentials

A dialog shows your Client ID and Client Secret.

Copy both values immediately — the Client Secret is only visible at creation time (since June 2025). You can also click Download JSON to save them.

Store these values securely. You’ll use them as environment variables in Step 4.

Testing vs Production Mode

For a self-hosted app using only openid, email, and profile scopes:


Step 2: Install Cloudflare Tunnel

Cloudflare Tunnel (cloudflared) creates a secure outbound connection from your machine to Cloudflare’s edge. No port-forwarding required.

macOS

brew install cloudflared

Windows

winget install --id Cloudflare.cloudflared

Linux (Debian/Ubuntu)

# Add Cloudflare GPG key and repository
sudo mkdir -p --mode=0755 /usr/share/keyrings
curl -fsSL https://pkg.cloudflare.com/cloudflare-main.gpg \
  | sudo tee /usr/share/keyrings/cloudflare-main.gpg >/dev/null

echo "deb [signed-by=/usr/share/keyrings/cloudflare-main.gpg] https://pkg.cloudflare.com/cloudflared any main" \
  | sudo tee /etc/apt/sources.list.d/cloudflared.list

sudo apt-get update && sudo apt-get install cloudflared

Linux (RHEL/CentOS)

curl -fsSl https://pkg.cloudflare.com/cloudflared.repo \
  | sudo tee /etc/yum.repos.d/cloudflared.repo

sudo yum update && sudo yum install cloudflared

Verify

cloudflared --version

Step 3: Create a Tunnel

3a. Authenticate

cloudflared tunnel login

This opens your browser. Select the Cloudflare zone (domain) to authorize. A certificate is saved to ~/.cloudflared/cert.pem.

3b. Create a Named Tunnel

cloudflared tunnel create propresenter-web

Note the tunnel UUID printed (e.g., 6ff42ae2-765d-4adf-8112-31c55c1551ef). A credentials file is created at ~/.cloudflared/<UUID>.json.

3c. Route DNS

cloudflared tunnel route dns propresenter-web pp.standrewsbangor.church

Replace pp.example.com with your desired hostname. This creates a CNAME record in Cloudflare DNS.

3d. Create Config File

Create ~/.cloudflared/config.yml:

tunnel: <TUNNEL-UUID>
credentials-file: /home/<USER>/.cloudflared/<TUNNEL-UUID>.json

ingress:
  - hostname: pp.example.com
    service: http://localhost:3100
  - service: http_status:404

Replace <TUNNEL-UUID> with your actual UUID and <USER> with your system username.

3e. Validate

cloudflared tunnel ingress validate

Step 4: Configure Environment

Create a .env file or export these variables before starting the server:

# Required — Google OAuth credentials (from Step 1e)
export GOOGLE_CLIENT_ID="123456789-abcdef.apps.googleusercontent.com"
export GOOGLE_CLIENT_SECRET="GOCSPX-xxxxxxxxxxxxxxxx"

# Required — your tunnel's public URL
export TUNNEL_URL="https://pp.example.com"

# Optional — ProPresenter connection (defaults shown)
export PROPRESENTER_HOST="192.168.68.58"
export PROPRESENTER_PORT="61166"

# Optional — server settings (defaults shown)
export WEB_PORT="3100"
export WEB_HOST="0.0.0.0"
export LOG_RETENTION_DAYS="14"

Step 5: Build and Start the Server

# 1. Install dependencies
npm ci

# 2. Build the server and web UI
npm run build
npm run web:build:ui

# 3. Start the server
npm run web:start

The startup banner shows connection details, auth status, and paths:

  ProPresenter Lyrics Export — Web Proxy
  ======================================
  Server:  http://0.0.0.0:3100
  Health:  http://0.0.0.0:3100/health

  Tunnel:  https://pp.example.com
  Tunnel config: OK

  Google OAuth: ENABLED
  Callback URL: https://pp.example.com/auth/google/callback
  Allowed users: (none — add emails to allowlist)

  Bearer token: a1b2c3d4-e5f6-...
  (fallback auth for API access / SSE)

  Sessions:  /home/user/.propresenter-words/sessions
  Logs:      /home/user/.propresenter-words/logs

Start the tunnel (separate terminal)

cloudflared tunnel run propresenter-web

Or run both together:

npm run web:start:tunnel

Step 6: Add Users

Only emails in the allowlist can sign in. Add the first user (yourself) via CLI:

# Add yourself as an admin
npm start -- users add you@gmail.com --admin

# Add other users
npm start -- users add colleague@gmail.com

# List all users
npm start -- users list

Once signed in as an admin, you can also manage users from the web UI via the Users button.


Running as a Service

For persistent operation (survives reboots), install cloudflared as a system service.

Linux (systemd)

# Install cloudflared as a service
sudo cloudflared --config /home/<USER>/.cloudflared/config.yml service install
sudo systemctl enable cloudflared
sudo systemctl start cloudflared

For the web proxy itself, create a systemd unit:

# /etc/systemd/system/propresenter-web.service
[Unit]
Description=ProPresenter Lyrics Export Web Proxy
After=network.target

[Service]
Type=simple
User=<USER>
WorkingDirectory=/path/to/propresenterlyricexport
ExecStart=/usr/bin/node dist/server/index.js
Restart=on-failure
RestartSec=5
Environment=GOOGLE_CLIENT_ID=your-client-id
Environment=GOOGLE_CLIENT_SECRET=your-client-secret
Environment=TUNNEL_URL=https://pp.example.com
Environment=NODE_ENV=production

[Install]
WantedBy=multi-user.target
sudo systemctl enable propresenter-web
sudo systemctl start propresenter-web

macOS (launchd)

# Install cloudflared as a service
sudo cloudflared service install

For the web proxy, create a launchd plist at ~/Library/LaunchAgents/com.propresenter.web.plist or use a process manager like pm2.

Windows

cloudflared.exe service install
sc start cloudflared

For the web proxy, use a tool like NSSM or run as a scheduled task on login.


Quick Start (Testing Only)

For quick testing without a Cloudflare account or domain:

# Terminal 1: Start the web server
npm run web:start

# Terminal 2: Quick tunnel (random URL)
cloudflared tunnel --url http://localhost:3100

This gives you a temporary *.trycloudflare.com URL. Limitations:

Use the bearer token (printed on server start) to authenticate — paste it on the login page.


Troubleshooting

“Google OAuth: NOT CONFIGURED”

The server didn’t find GOOGLE_CLIENT_ID and GOOGLE_CLIENT_SECRET. Make sure they’re exported in your environment before starting the server.

“redirect_uri_mismatch” error on Google sign-in

The redirect URI in Google Cloud Console must match exactly:

https://pp.example.com/auth/google/callback

Sessions lost on restart

This shouldn’t happen with the file-based session store. Check that ~/.propresenter-words/sessions/ exists and is writable.

When behind a tunnel, cookies require secure: true. Make sure:

Tunnel not reachable

# Test tunnel health
curl https://pp.example.com/health?check=tunnel

# Check cloudflared is running
cloudflared tunnel info propresenter-web

Logs

Request logs are written to ~/.propresenter-words/logs/ as daily JSON-lines files:

# View today's log
cat ~/.propresenter-words/logs/web-$(date +%Y-%m-%d).log | head -20

# Watch live
tail -f ~/.propresenter-words/logs/web-$(date +%Y-%m-%d).log

Logs are automatically pruned after 14 days (configurable via LOG_RETENTION_DAYS).


Security Notes

HTTPS

All traffic between users and your server is encrypted end-to-end by Cloudflare Tunnel. You don’t need to configure TLS certificates — Cloudflare handles this automatically.

The connection flow:

Browser ←—HTTPS—→ Cloudflare Edge ←—encrypted tunnel—→ cloudflared ←—HTTP—→ localhost:3100

Authentication Layers

  1. Google OAuth — primary auth for browser users. Only allowlisted emails can sign in.
  2. Bearer token — fallback for API access and SSE connections. Auto-generated, printed on startup.
  3. Session cookieshttpOnly, secure, sameSite=lax, 6-hour expiry.

Data Storage

All configuration is stored locally at ~/.propresenter-words/:

File Contents
web-auth.json Bearer token + session secret (chmod 600)
web-users.json Email allowlist + admin list
sessions/ Session files (auto-pruned)
logs/ Request logs (auto-pruned after 14 days)
aliases.json Song alias mappings

Rate Limiting

Auth endpoints are rate-limited to 20 attempts per 15 minutes per IP (uses CF-Connecting-IP when behind Cloudflare).


Environment Variable Reference

Variable Required Default Description
GOOGLE_CLIENT_ID For OAuth Google OAuth client ID
GOOGLE_CLIENT_SECRET For OAuth Google OAuth client secret
TUNNEL_URL For production Public tunnel URL (e.g., https://pp.example.com)
WEB_PORT No 3100 Server listen port
WEB_HOST No 0.0.0.0 Server listen host
PROPRESENTER_HOST No 127.0.0.1 ProPresenter host
PROPRESENTER_PORT No 1025 ProPresenter API port
CORS_ORIGIN No * Comma-separated allowed origins
NODE_ENV No Set to production for secure cookies without TUNNEL_URL
LOG_RETENTION_DAYS No 14 Days to keep log files