1
Your town
2
Contact
3
Setup needs
4
Review
Step 1 of 4
Tell us about your town
Basic information helps us make sure Pinpoint 311 is the right fit and that we can follow up with anything useful.
Please enter your municipality name
Please select a state
<1K5K10K25K 50K100K250K500K+
~10,000 residents
Helps us understand your existing setup.
Step 2 of 4
Who should we be in touch with?
We'll reach out with setup guidance and answer any questions. We don't share or sell your information.
Required
Required
Please enter a valid email address
Required
Step 3 of 4
A bit more about your setup
This helps us send you relevant deployment guidance and check if there's anything we can do to help.
Step 4 of 4
Review & submit
Double-check everything looks right, then submit. We'll be in touch within a couple of days.
After submitting, we'll send you the deployment link right away so you can get started. We'll follow up via email with setup guidance tailored to your situation.

Complete Setup Guide

Everything you need to go from zero to a fully running Pinpoint 311 deployment, step by step.

15–30 min basic · 45–60 min full production
Setup Guide
Get Running
Server, code, config, start & login · ~15 min
Make It Yours
Boundaries, services, branding & legal
Go Live
Domain, checklist & maintenance
Get Running
Server, code, config, start & login
Steps 1–5
1
Set Up Your Server
Get a server, SSH in, and install Docker

1a. Get a Server

You need a Linux server (Ubuntu recommended). Use any cloud provider — Oracle Cloud (free tier), AWS, Google Cloud, DigitalOcean, or an on-premise machine.

Minimum Specs Details
CPU 1 vCPU (2+ recommended for production)
RAM 1 GB minimum (2+ GB recommended)
Disk 20 GB+
OS Ubuntu 22.04 or 24.04 LTS recommended

1b. SSH Into Your Server

From your local machine, connect to the server using SSH:

# Replace with your server's IP address and key file ssh -i your-key.pem ubuntu@your-server-ip # Or if using password auth: ssh ubuntu@your-server-ip

💡 All remaining steps are run on the server, not your local machine.

1c. Install Docker & Docker Compose

First, check if Docker is already installed:

docker --version && docker compose version

If Docker is not installed, run these commands:

# Install Docker using the official convenience script curl -fsSL https://get.docker.com | sudo sh # Allow your user to run Docker without sudo sudo usermod -aG docker $USER # Log out and back in for group changes to take effect exit

SSH back in, then verify Docker is working:

docker --version docker compose version

💡 If Docker is already installed, skip this step entirely.

1d. Open Firewall Ports

Your cloud provider's firewall (security groups / network rules) must allow inbound traffic on these ports:

Port Protocol Purpose
22 TCP SSH access (already open if you can connect)
80 TCP HTTP — web traffic & Let's Encrypt certificate validation
443 TCP HTTPS — secure web traffic (auto-enabled with a domain)

Where to configure this depends on your cloud provider:

Provider Where to Open Ports
Oracle Cloud Networking → Virtual Cloud Networks → Security Lists → Add Ingress Rules
AWS EC2 → Security Groups → Edit Inbound Rules
Google Cloud VPC Network → Firewall → Create Firewall Rule
DigitalOcean Networking → Firewalls → Create Firewall

If your server also has a local firewall (e.g. ufw on Ubuntu), open the ports there too:

sudo ufw allow 22/tcp sudo ufw allow 80/tcp sudo ufw allow 443/tcp sudo ufw enable
⚠️
If port 80 or 443 is blocked, your site won't load and SSL certificates won't auto-provision. This is the most common setup issue — make sure both ports are open before running docker compose up.

Recommended (Optional)

Service Why
Google Cloud Maps, Vertex AI (Gemini), Translate, Secret Manager
Auth0 Account Staff SSO, MFA, passkeys — free tier
Custom Domain e.g. 311.yourtown.gov
SMTP Server Confirmation & status emails
2
Download the Latest Release
Get the stable release package from GitHub

On your server, download and extract the latest release:

# Auto-download the latest release VERSION=$(curl -s https://api.github.com/repos/Pinpoint-311/Pinpoint-311/releases/latest | grep '"tag_name"' | cut -d'"' -f4) curl -L "https://github.com/Pinpoint-311/Pinpoint-311/archive/refs/tags/${VERSION}.tar.gz" -o pinpoint.tar.gz tar -xzf pinpoint.tar.gz cd Pinpoint-311-${VERSION#v}

💡 Or download directly from the Releases page — click the latest version and download "Source code (tar.gz)".

3
Configure Environment Variables
Set your database password and secret key
# 1. Generate a secure 32-byte secret key first openssl rand -hex 32 # 2. Copy the config file and edit it cp .env.example .env nano .env
🔒
Your .env file never leaves your server. This ensures your API keys and Resident Data stay securely within your own infrastructure.
⚠️
Crucial DNS Step: If you are using a custom domain (e.g., 311.yourcity.gov), you MUST point your DNS A-Record to this server's IP address before moving to Step 4. If you set DOMAIN below but the DNS is not pointed, the server will fail to start and throw SSL Protocol errors.

Required variables

Variable What to set
DOMAIN Your domain (e.g., 311.yourcity.gov), or localhost for local testing
DB_PASSWORD A strong, unique database password
SECRET_KEY Paste the secure key you generated above
ADMIN_EMAIL Your admin contact email
💡
Most API keys can be configured later via the Admin Console. You only need DB_PASSWORD, SECRET_KEY, and DOMAIN to start.
4
Start the System
Build and launch all services

Build & Start (recommended)

docker compose up --build -d

Verify

docker compose ps

You should see backend, frontend, db, redis, caddy, and worker — all Up or healthy.

Access points

Portal URL
Resident Portal http://localhost/
Staff Dashboard http://localhost/staff
Admin Console http://localhost/admin
Research Lab http://localhost/research
API Docs http://localhost/api/docs
5
Log In to Admin Console
One-click admin access for initial setup

After the containers start, you need to log into the Admin Console to configure your system.

Option A: Browser (Recommended)

  1. Open http://your-server-ip/login in your browser
  2. You'll see a "Welcome to Pinpoint 311" card with an "Enter Admin Console" button
  3. Click the button — you'll be automatically logged in as admin

💡 If your browser shows an SSL error, use port 8000 instead: http://your-server-ip:8000/login

Option B: Terminal

Alternatively, run this on the server:

curl -X POST http://localhost:8000/api/auth/bootstrap

Copy the login_url from the JSON response and open it in your browser.

⚠️
Bootstrap access is one-time only — once you configure Auth0 (Step 6), the button disappears and all logins go through SSO.
💡
If the login page doesn't load, containers may still be starting: docker compose ps — all services should show "healthy".
Connect Services
Auth0, AI, Maps, staff, email & SMS
Steps 6–11
6
Configure Auth0 (SSO)
Zero-password staff authentication with MFA

1. Create an Auth0 account

Go to auth0.com and create a free account (or use your organization's existing tenant). The free tier supports up to 7,000 active users.

2. Create an application

  • In the Auth0 Dashboard, go to Applications → Create Application
  • Choose Regular Web Application
  • In the app's Settings tab, copy the Domain, Client ID, and Client Secret

3. Configure callback URLs

Setting Value
Allowed Callback URLs https://311.yourtown.gov/api/auth/callback
Allowed Logout URLs https://311.yourtown.gov/staff
Allowed Web Origins https://311.yourtown.gov
⚠️
Common Issue: The callback URL must exactly match your domain with /api/auth/callback appended. A single typo here will cause staff logins to fail silently.

4. Enable MFA (recommended)

In the Auth0 Dashboard, go to Security → Multi-factor Auth and enable MFA. Staff will be prompted to set up a second factor on their first login.

5. Social login (optional)

Under Authentication → Social, add Google and Microsoft connections so staff can log in with their existing work accounts.

6. Enter credentials in Admin Console

Go to Setup & Integration → Auth0, enter your Auth0 Domain, Client ID, and Client Secret, and save.

🔒
Once Auth0 is configured, bootstrap access is automatically disabled. All staff logins use Auth0 SSO with passkey support.
7
Google Cloud (AI, KMS & Secrets)
Vertex AI, Translation, KMS encryption & Secret Manager

1. Create or select a GCP project

Go to console.cloud.google.com and create a new project or select an existing one. Note your Project ID (not the project name).

💡
Billing must be enabled on your GCP project even if you stay within the free tier. Most API usage for a single municipality will fall within Google's generous free quotas.

2. Enable APIs

Go to APIs & Services → Library and enable all four:

API What it powers
Cloud KMS API PII encryption at rest (HSM-backed, FIPS 140-2)
Cloud Translation API Multi-language support (109 languages)
Vertex AI API AI request analysis, priority scoring, photo assessment, duplicate detection
Secret Manager API Enterprise secrets vault for production credentials

3. Create KMS Key Ring & Key

Navigate to Security → Key Management:

  • Create Key Ring — name it (e.g., pinpoint311) and select a location (e.g., us-central1)
  • Create Key inside the ring (e.g., pii-encryption), purpose: Symmetric encrypt/decrypt
  • Optional: Set automatic rotation (e.g., every 90 days). After rotation, use the Re-encrypt All PII Data button in Admin Console to migrate historical data

4. Create a Service Account

Go to IAM & Admin → Service Accounts → Create. Grant it these roles:

Role Purpose
Cloud KMS CryptoKey Encrypter/Decrypter Encrypt/decrypt PII data
Cloud Translation API User Translate submissions
Vertex AI User AI-powered analysis
Secret Manager Admin Manage secrets vault

5. Download the JSON key

On the Service Account page, go to Keys → Add Key → Create new key → JSON. Download and keep this file secure — it's your master credential.

6. Enter in Admin Console

Go to Setup & Integration → Google Cloud:

  • Enter your Project ID, KMS Location, Key Ring, and Key ID
  • Upload or paste your Service Account JSON key
  • Click Save GCP Settings

7. Migrate Secrets (optional)

Click Migrate to Secret Manager to vault all API credentials (Maps key, SMTP password, Twilio token, etc.) into GCP.

⚠️
Two bootstrap keys (GCP_SERVICE_ACCOUNT_JSON and GOOGLE_CLOUD_PROJECT) always stay in the local DB — they're the master keys needed to access Secret Manager itself.
8
Configure Google Maps
Location picker, boundary maps, address autocomplete

1. Create an API key

2. Restrict the key

Restriction Value
API restrictions Maps JavaScript, Places, Geocoding
Website restrictions https://311.yourtown.gov/*

3. Enter in Admin Console

Go to Setup & Integration → Google Maps and paste your API key. If you activated Secret Manager in Step 7, this key is automatically vaulted into GCP.

4. Enable 3D buildings (optional)

For 45° tilt, rotation, and 3D buildings on the map:

  • Go to Google Cloud Console → Maps → Map Management
  • Create a Map ID with map type: Vector
  • Enter the Map ID in Admin Console → Google Maps → Map ID
💡
No extra cost — same Dynamic Maps pricing ($7 per 1,000 loads, $200/month free credit from Google). Most municipalities never exceed the free tier.
9
Add Staff Users
Invite team members and assign roles

In the Admin Console, go to Staff Management and add your team:

Role Access Level Best For
Admin Full Admin Console + all operations IT staff, department heads
Staff View, manage, and resolve requests Field workers, dispatchers
Researcher Privacy-preserved analytics only Analysts, council members

Staff log in via Auth0 SSO — no passwords stored in the system.

🔐
Staff PII (names, emails, phone numbers) is now encrypted with Google KMS since Step 7 was configured. All personal data is protected at rest.
10
Email Notifications
SMTP for submission confirmations & status updates

Choose your SMTP provider

Provider Host Port Username
Gmail smtp.gmail.com 587 Your Gmail address
SendGrid smtp.sendgrid.net 587 apikey (literal)
Org relay Your server's SMTP host Varies Varies
⚠️
Gmail users: You must enable 2FA on your Google account first, then generate an App Password under Security → App Passwords. Use the app password as your SMTP password.

Enter the host, port, from address, username, and password in Admin Console → Setup & Integration → Email (SMTP) and click Save SMTP Settings.

✉️
All notification emails automatically include your municipality's branding (logo, colors, name) — set those up in Step 14.
11
SMS Notifications (Optional)
Twilio or custom HTTP API for text alerts

Option A: Twilio (recommended)

  • Create an account at twilio.com
  • Note your Account SID and Auth Token from the Console Dashboard
  • Go to Phone Numbers → Manage → Buy a number — get a number with SMS capability
  • In Admin Console → SMS Notifications, select "Twilio" and enter your credentials

Option B: Custom HTTP API

If you have an existing SMS gateway, select "Custom HTTP API" and provide your endpoint URL. Pinpoint sends a POST request with:

{ "to": "+1234567890", "message": "Your request #123 has been updated..." }
💡
SMS is fully optional. Email notifications cover all the same status updates. SMS adds real-time text alerts for residents who opt in.
Make It Yours
Boundaries, services, branding & legal
Steps 12–14
12
Municipality Boundaries
GeoJSON service area

Requests outside the boundary are automatically rejected. Get your file from:

Upload in Setup & Integration → Municipality Boundaries.

13
Services & Departments
Categories, routing, custom questions

In Admin Console → Services, create categories (Pothole, Streetlight, etc.):

Setting Description
Routing Township Handled, Third-Party, or Road-Based
Department Which team handles it
Questions Follow-up questions per service
💡
Road-Based routing splits jurisdiction per street — all configured without code.
14
Branding & Legal
Logo, colors, privacy policy, terms of service

Branding

In Admin Console → Branding:

  • Municipality Name — headers, emails, portal
  • Logo — nav, emails, portal
  • Primary & Secondary Colors
  • Font

Auto-applied to Resident Portal, all emails, SMS, and Staff Dashboard.

Legal Documents

In Branding → Legal Documents:

  • Privacy Policy — data collection, retention, rights
  • Terms of Service — includes non-emergency disclaimer
  • Accessibility — WCAG 2.1 AA, Section 508

All support Markdown formatting. Sensible defaults included.

Go Live
Domain, checklist & maintenance
Steps 15–16
15
Custom Domain
Auto HTTPS via Let's Encrypt

1. Point DNS

Type Name Value
A 311.yourtown.gov Your server IP

2. Update .env

DOMAIN=311.yourtown.gov

3. Restart Caddy

docker compose restart caddy

Caddy auto-provisions SSL and redirects HTTP → HTTPS.

16
Go-Live Checklist & Maintenance
Launch verification, backups, updates

Pre-Launch Checklist

Item
Secure DB_PASSWORD and SECRET_KEY (not defaults)
Auth0 configured, bootstrap disabled
Google Maps key working
Municipality boundary uploaded
At least one service category
At least one department with staff
SMTP email configured and tested
Branding set (logo, name, colors)
Legal documents reviewed
Custom domain with HTTPS
Full lifecycle test: submit → staff → resolve → email

Automatic Updates (Optional)

# Enable docker compose up -d watchtower # Disable docker compose stop watchtower # Status docker compose ps watchtower
💡
Works perfectly without Watchtower. Use for hands-off updates, or disable for manual control.

Database Backups

Automated (recommended): Configure S3-compatible storage in Admin Console → Setup & Integration → Database Backups:

Field Description
S3 Bucket Your bucket name (AWS S3, Oracle Object Storage, MinIO, etc.)
Access Key IAM access key with s3:PutObject, s3:GetObject permissions
Secret Key Corresponding secret key
Encryption Key Passphrase for AES-256 backup encryption — store this securely
Endpoint Optional: Custom endpoint for Oracle/MinIO (leave blank for AWS)
⚠️
Privacy note: Backups contain a full database snapshot including resident PII. Without the encryption key, backups are unreadable. Keep this key in a separate, secure location.

Manual: Take a one-off backup any time:

docker compose exec db pg_dump -U township township_db > backup_$(date +%Y%m%d).sql

Manual Updates

# Download the new release VERSION=v1.1.6 # Replace with latest version curl -L "https://github.com/Pinpoint-311/Pinpoint-311/archive/refs/tags/${VERSION}.tar.gz" | tar -xz # Copy your .env into the new version cp .env Pinpoint-311-${VERSION#v}/ cd Pinpoint-311-${VERSION#v} # Rebuild and restart docker compose up --build -d

Database Migrations

Migrations run automatically on startup. To run manually:

docker compose exec backend alembic upgrade head

View Logs

docker compose logs -f backend

Record Retention

State Period
Texas 10 years
NJ, PA, WI 7 years
NY, MI, WA, CT 6 years
CA, FL, most 5 years (default)
GA, MA 3 years

Need help? We're here for you.

GitHub Repository → Report an Issue Donate (tax-deductible)

© 2024–2026 Pinpoint 311 · MIT License · Fiscally sponsored by Hack Club 501(c)(3)

Setup Assistant

👋 Hi! I'm the Pinpoint 311 setup assistant. I can help you with deployment, configuration, Docker, Auth0, Google Cloud, and anything else in the setup guide. What can I help with?