Getting started
Headsign is a web application that can be deployed in various ways to suit different organizational needs and technical capabilities. This guide walks through the available deployment options, from simplest to most complex.
Prerequisites
Section titled “Prerequisites”Transit API Key
Section titled “Transit API Key”Regardless of deployment method, you’ll need an API key from Transit:
- Request a key from the Transit API page
- For testing or very limited use: The default free tier should be adequate
- For production deployments: You’ll need a paid tier API key
Transit partners: If your agency subscribes to Transit Royale or has other relationships with Transit, contact your account representative for API access information.
Display Hardware
Section titled “Display Hardware”You’ll need display hardware to show the Headsign interface. Options range from:
- Simple: Monitor connected to a PC or mini-PC
- Moderate: Raspberry Pi with display
- Advanced: Dedicated digital signage displays
Deployment Options
Section titled “Deployment Options”Option 1: One-Click Deployment (Railway) - Recommended for Most Users
Section titled “Option 1: One-Click Deployment (Railway) - Recommended for Most Users”Best for: Organizations comfortable with cloud PaaS platforms and looking for quickest setup
Railway provides a one-click deployment experience:
What happens when you click:
- You’ll be guided through creating a Railway account (if needed)
- You’ll configure your API key and settings for Headsign
- Railway creates a new project for Headsign
- Railway automatically deploys the latest Docker image for Headsign
- Your Headsign instance is live
Configuration:
- Custom domains can be added through Railway’s dashboard
- Environment variables can be updated anytime
- Multiple instances can be deployed for different displays
Costs: Railway charges based on usage. Check Railway’s pricing for current rates.
Demo instance: see it in action
Option 1B: One-Click Deployment (Render)
Section titled “Option 1B: One-Click Deployment (Render)”Best for: Organizations comfortable with cloud PaaS platforms and specifically familiar with Render
What happens when you click:
- You’ll be guided through creating a Render account (if needed)
- You’ll configure your API key and basic settings for Headsign
- Render creates a new project for Headsign
- Render automatically deploys the latest Docker image for Headsign as a Web Service
- Your Headsign instance is live
Configuration:
- Custom domains can be added through Render’s dashboard
- Environment variables can be updated anytime
- Multiple instances can be deployed for different displays
Option 2: Manual Cloud Platform Deployment
Section titled “Option 2: Manual Cloud Platform Deployment”Best for: Organizations preferring other PaaS providers or needing specific features
Headsign works with any Docker-compatible PaaS platform. Currently it has only been tested and deployed on Railway and has had test deployments on Render and should be supported by Fly.io.
- Railway - Recommended, full template support
- Render - Good alternative, straightforward setup with template support
- Fly.io - Global edge deployment, good for multi-location agencies
General Setup Steps
Section titled “General Setup Steps”- Create account on your chosen platform
- Create new service from Docker image
- Configure Docker image:
- Docker Hub:
jasonad123/headsign- Alternative: GitHub repository:
ghcr.io/jasonad123/headsign(this is also the only option for pre-release images)
- Alternative: GitHub repository:
- Tag:
latest(for stable) or specific version tag
- Docker Hub:
- Set environment variables:
Terminal window TRANSIT_API_KEY=your_api_key_hereSESSION_SECRET=any-long-secret-however-the-platform-generates-itPORT=8080NODE_ENV=production - Optional: Configure unattended setup
- Deploy and access your instance
Platform-Specific Guides
Section titled “Platform-Specific Guides”Render:
services: - type: web name: Headsign runtime: docker image: url: ghcr.io/jasonad123/headsign:latest envVars: - key: TRANSIT_API_KEY sync: false - key: SESSION_SECRET generateValue: true - key: ENABLE_SERVER_CACHE sync: false - key: PORT value: 8080 - key: NODE_ENV value: productionFly.io:
app = "your-headsign"
[env] PORT = "8080" NODE_ENV = "production"
[[services]] internal_port = 8080 protocol = "tcp"
[[services.ports]] port = 80 handlers = ["http"]
[[services.ports]] port = 443 handlers = ["tls", "http"]Option 3: Docker Deployment (VPS or On-Premise) - Recommended for Self-Hosted
Section titled “Option 3: Docker Deployment (VPS or On-Premise) - Recommended for Self-Hosted”Best for: Organizations with existing infrastructure, on-premise requirements, or cost optimization
Prerequisites
Section titled “Prerequisites”- Server/VM with Docker installed
- SSH or console access to the server
- Domain name (optional but recommended)
Installation Steps
Section titled “Installation Steps”-
Install Docker (if not already installed):
Terminal window # Follow instructions on https://docs.docker.com/engine/install/ to add the Docker repositories for your package manager# Once the repositories are added - install Docker according to the right method for your distro# Ubuntu/Debian basedsudo apt install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin# RHEL/Fedora basedsudo dnf install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin# Start the Docker servicesudo systemctl start docker# Test Dockersudo docker run hello-world -
Create environment file:
Terminal window # Create a directory for Headsignmkdir -p ~/headsigncd ~/headsign# Create .env filecat > .env << EOFTRANSIT_API_KEY=your_api_key_hereSESSION_SECRET=$(openssl rand -base64 32)PORT=8080NODE_ENV=productionEOF -
Pull and run the Docker image:
Terminal window # Pull the latest image from Docker Hubdocker pull jasonad123/headsign:latest# OR pull the latest image from GitHub# docker pull ghcr.io/jasonad123/headsign:latest# Run the containerdocker run -d \--name headsign \--restart unless-stopped \-p 8080:8080 \--env-file .env \jasonad123/headsign:latest -
Verify deployment:
Terminal window # Check container statusdocker ps# View logsdocker logs headsign -
Access your instance:
- Local:
http://localhost:8080 - Remote:
http://your-server-ip:8080
- Local:
Using Docker Compose (Recommended)
Section titled “Using Docker Compose (Recommended)”For easier management, use Docker Compose:
-
Create
compose.yaml:services:headsign:image: jasonad123/headsign:latestcontainer_name: headsignrestart: unless-stoppedports:- '8080:8080'environment:- TRANSIT_API_KEY=${TRANSIT_API_KEY}- SESSION_SECRET=${SESSION_SECRET}- PORT=8080- NODE_ENV=production# Optional: for unattended setup# - UNATTENDED_SETUP=true# - UNATTENDED_LOCATION=40.7240,-74.0002# - UNATTENDED_TITLE=Transit Display -
Deploy:
Terminal window # Startdocker compose up -d# View logsdocker compose logs -f# Stopdocker compose down# Update to latest versiondocker compose pulldocker compose up -d
Reverse Proxy Setup (Recommended for Production)
Section titled “Reverse Proxy Setup (Recommended for Production)”For SSL/TLS and custom domains, use a reverse proxy like Nginx or Caddy:
Caddy (easiest, automatic HTTPS):
headsign.youragency.com { reverse_proxy localhost:8080}Nginx:
server { listen 80; server_name headsign.youragency.com;
location / { proxy_pass http://localhost:8080; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection 'upgrade'; proxy_set_header Host $host; proxy_cache_bypass $http_upgrade; }}Reverse proxy alternatives
Section titled “Reverse proxy alternatives”Headsign has been tested to work behind both Cloudflare Tunnels and Tailscale (both natively and behind Tailscale Funnels). If your organization uses either of these programs, consider these as reverse proxy alternatives that don’t require opening ports.
Option 4: Direct Node.js Deployment (Development Only)
Section titled “Option 4: Direct Node.js Deployment (Development Only)”See Local deployment for more information.
Configuration
Section titled “Configuration”Unattended Setup
Section titled “Unattended Setup”Headsign supports automatic configuration on first launch, ideal for deploying multiple instances at once.
See the documentation for unattended setup for more information on available variables.
Caching
Section titled “Caching”Headsign also has built-in caching. Caching can be adjusted based on your Transit API subscription.
See the documentation for caching for more information on the caching setup.
Updating Your Deployment
Section titled “Updating Your Deployment”Railway
Section titled “Railway”Updates are automatic when new versions are tagged, or you can manually redeploy from the dashboard.
If you’re using the Railway template, the default settings will automatically update the Docker image at 7 AM UTC (3 AM EST, 12 AM PST).
PaaS Platforms
Section titled “PaaS Platforms”Most platforms support automatic updates or can be configured to pull the latest image on a schedule.
Docker Compose
Section titled “Docker Compose”docker compose pulldocker compose up -dDocker (Manual)
Section titled “Docker (Manual)”# Pull latest imagedocker pull jasonad123/headsign:latest
# Stop and remove old containerdocker stop headsigndocker rm headsign
# Start new container (using same command as initial deployment)docker run -d --name headsign --restart unless-stopped -p 8080:8080 --env-file .env jasonad123/headsign:latestMonitoring and Maintenance
Section titled “Monitoring and Maintenance”Health Checks
Section titled “Health Checks”Headsign exposes a health check endpoint at /health that returns:
{ "status": "healthy", "timestamp": "2025-12-18T16:00:00.000Z", "version": "1.3.0", "uptime": 3600, "environment": "production"}Use this for monitoring:
- Cloud platforms: Configure platform-specific health checks
- Self-hosted: Use monitoring tools like Uptime Kuma, Healthchecks.io
Docker (including Docker Compose):
# View logsdocker logs headsign
# Follow logs in real-timedocker logs -f headsign
# Last 100 linesdocker logs --tail 100 headsignDocker Compose:
docker compose logs -fResource requirements
Section titled “Resource requirements”Minimum:
- 512 MB RAM
- 1 CPU core
- 500 MB disk space
Recommended (for smooth operation):
- 1 GB RAM
- 2 CPU cores
- 1 GB disk space
Quick Checks
Section titled “Quick Checks”-
Container not starting:
Terminal window docker logs headsign -
API key issues:
- Verify API key is correct
- Check API quota/limits
- Ensure key has necessary permissions
-
Connection issues:
- Verify firewall allows traffic on port 8080
- Check security group settings (cloud deployments)
- Ensure port is not already in use
-
Display not updating:
- Check API key validity
- Verify location coordinates are correct
- Check browser console for errors
Support
Section titled “Support”- Issues: GitHub Issues
This documentation was prepared with assistance from agentic coding tools.