CourtPin is a long-running background process and needs a host that keeps it alive 24/7. Regular shared web hosting (like Bluehost) is not suitable. Below are all supported options from simplest to most advanced.
| Method | Monthly cost | Technical level | Best for |
|---|---|---|---|
| Railway | Free to $5 | Beginner | Clubs with no local server hardware |
| Raspberry Pi | Free (hardware ~$50 one-time) | Beginner | Clubs wanting local hosting on cheap hardware |
| Docker | Free | Intermediate | Clubs with a NAS, home server, or existing Docker setup |
| Synology / QNAP NAS | Free | Beginner | Clubs with a NAS already running |
| VPS | $4–$6/mo | Intermediate | Cloud hosting with full control, no Railway dependency |
| Windows PC | Free | Beginner | Clubs with an always-on Windows PC at the facility |
Key advantage of local hosting (Pi, NAS, Docker, Windows): CourtPin runs on the same network as your UniFi console so no port forwarding is needed. Set UNIFI_HOST to the local IP directly (e.g. https://192.168.1.1:12445) and skip the entire UniFi networking setup.
Railway is a cloud platform that keeps CourtPin running with zero server management. It deploys automatically from GitHub on every push.
Prerequisites: A GitHub account and a Railway account (sign up with GitHub at railway.app).
- Create a new private repo on github.com named
courtpin - Upload all CourtPin files (do NOT upload your
.envfile — use Railway's Variables tab for credentials) - Commit
- Go to railway.app → New Project → Deploy from GitHub repo
- Select your
courtpinrepo - Railway starts a deployment — it will fail until you add variables. That is expected.
- Click your service → Variables → Raw Editor
- Paste the block from configuration.md and fill in your values
- Click Update Variables — Railway redeploys automatically
- Click your service → Settings → Networking → Generate Domain
- Bookmark
https://YOUR_RAILWAY_URL/adminon your phone
Click Deployments → latest → View Logs. You should see:
[INFO] CourtReserve <-> UniFi Access integration starting
[INFO] Fetched N reservation(s)
[INFO] Scheduler running — checking every minute.
Temporarily set NOTIFY_MINUTES_BEFORE=1440, create a test reservation in CourtReserve, and watch the logs. Change it back to 60 once confirmed working.
Any Raspberry Pi 3 or newer handles CourtPin easily. Any other always-on Linux machine works identically.
curl -fsSL https://deb.nodesource.com/setup_20.x | sudo -E bash -
sudo apt install -y nodejs
node --version # should show v20.x.x or latergit clone https://github.com/jchette/courtpin.git
cd courtpin
npm installcp env.example .env
nano .envSince the Pi is on the same local network as your UniFi console:
UNIFI_HOST=https://192.168.1.1:12445
No port forwarding needed. Save with Ctrl+O, exit with Ctrl+X.
npm start
# Press Ctrl+C to stop once confirmed workingnpm install -g pm2
pm2 start index.js --name courtpin
pm2 save
pm2 startup
# Run the command printed by pm2 startup to enable auto-start on rebootUseful PM2 commands:
pm2 status # check if running
pm2 logs courtpin # view live logs
pm2 restart courtpin # restart after editing .env
pm2 stop courtpin # stop the serviceDocker packages CourtPin into a self-contained image that runs identically on any machine. CourtPin includes a docker-compose.yml ready to use.
Since the Dockerfile is not included in the repo (to keep Railway deployments simple), create a Dockerfile in your project root with this content:
FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm install --omit=dev
COPY index.js ./
RUN mkdir -p /data
RUN addgroup -S courtpin && adduser -S courtpin -G courtpin
RUN chown -R courtpin:courtpin /app /data
USER courtpin
EXPOSE 3000
ENV NODE_ENV=production
ENV STATE_FILE=/data/state.json
CMD ["node", "index.js"]On Ubuntu / Raspberry Pi OS / Debian:
curl -fsSL https://get.docker.com | sh
sudo usermod -aG docker $USER
# Log out and back in for the group change to take effectOn other systems see docs.docker.com/get-docker.
# 1. Configure
cp env.example .env
nano .env # fill in your values
# 2. Start
docker compose up -d
# 3. View logs
docker compose logs -f
# 4. Stop
docker compose down
# 5. Restart after changing .env
docker compose down && docker compose up -dCourtPin automatically restarts on crash or reboot due to restart: unless-stopped in the compose file.
# Build
docker build -t courtpin .
# Run
docker run -d \
--name courtpin \
--restart unless-stopped \
--env-file .env \
-v courtpin_data:/data \
-p 3000:3000 \
courtpin
# View logs
docker logs -f courtpingit pull
docker compose down
docker compose up -d --buildIf your facility already has a NAS running, it can host CourtPin with no additional hardware.
- Open Package Center → install Container Manager
- Open Container Manager → Project → Create
- Paste the contents of
docker-compose.yml - Set environment variables in the UI or reference your
.envfile - Click Build then Start
Admin portal accessible at http://YOUR_NAS_IP:3000/admin on your local network.
- Open App Center → install Container Station
- Open Container Station → Create → Create Application
- Paste the contents of
docker-compose.yml - Set your environment variables
- Click Create
A virtual private server gives you cloud hosting with full control and no Railway dependency. The state file is stable across restarts and you can run other services on the same machine.
Recommended providers:
| Provider | Monthly cost | Notes |
|---|---|---|
| Hetzner | ~$4 | Best value, European data centers |
| DigitalOcean | $6 | Beginner friendly, excellent documentation |
| Vultr | $6 | Good global coverage |
| Linode (Akamai) | $5 | Reliable, long established |
Choose the smallest plan with 1 GB RAM — CourtPin uses very little memory.
- Create an Ubuntu 22.04 or 24.04 server
- SSH in:
ssh root@YOUR_SERVER_IP - Follow the same steps as Option 2 (Raspberry Pi) from Step 1 onward
Since a VPS is in the cloud you still need port forwarding or a Cloudflare Tunnel to reach your UniFi console. See unifi-setup.md.
If there is a Windows PC at the facility that is always powered on, it can run CourtPin.
- Go to nodejs.org and download the LTS installer
- Run the installer with default settings
- Open Command Prompt and verify:
node --version
- Go to your GitHub repo → Code → Download ZIP
- Extract to
C:\courtpin - Open Command Prompt:
cd C:\courtpin
npm install
copy env.example .env
notepad .envFill in all values and save.
npm startnpm install -g pm2
npm install -g pm2-windows-startup
pm2 start index.js --name courtpin
pm2 save
pm2-startup installUseful commands:
pm2 status
pm2 logs courtpin
pm2 restart courtpin