TeamGlimpse Deployment Guide

This guide covers deploying TeamGlimpse on Linux.

Architecture Overview

  • Backend: Rust binary running as a systemd service on port 8080
  • Frontend: Static files served by nginx
  • Database: PostgreSQL (one control database + per-organization databases created at runtime)
                    ┌─────────────────┐
                    │     nginx       │
                    │   (port 80/443) │
                    └────────┬────────┘
                             │
              ┌──────────────┴──────────────┐
              │                             │
              ▼                             ▼
     ┌────────────────┐          ┌──────────────────┐
     │ /api/* proxy   │          │ /* static files  │
     │ to backend     │          │ SPA routing      │
     └───────┬────────┘          └──────────────────┘
             │                            │
             ▼                            ▼
    ┌─────────────────┐         ┌──────────────────┐
    │  teamglimpse  │         │ /var/www/        │
    │  (port 8080)    │         │ teamglimpse/   │
    └────────┬────────┘         └──────────────────┘
             │
             ▼
    ┌─────────────────┐
    │   PostgreSQL    │
    │  (port 5432)    │
    └─────────────────┘

Single-instance deployment

TeamGlimpse is designed to run as a single backend process. Several subsystems keep state in process memory and are not shared across replicas:

  • Job queue runner and live status stream — the in-memory broadcast registry (JobRegistry) that powers the GET /jobs/:id/stream SSE endpoint lives in the process that started the job. A second replica would deliver only the initial database snapshot, then close the stream, and cancel requests routed there would update the row without emitting a live event.
  • Background scheduler — periodic data-fetch jobs are scheduled in-process. Running two replicas would run every scheduled job twice.
  • LLM rate-limit tracker — the per-provider concurrency and rate-limit state is in process memory; replicas would not coordinate.

Run a single backend instance. To scale, increase resources on the host rather than adding replicas. Horizontal scale would require a shared pub/sub backbone (e.g. Redis, NATS, or Postgres LISTEN/NOTIFY), scheduler leader election, and a shared rate-limit store — none of which are present today.

Migrating from ActivityPulse

TeamGlimpse was called ActivityPulse up to version 0.9.6. New versions are published only under the new name, so an existing ActivityPulse install is moved over once. The move keeps the data, the logins, the port and the address; only the names on the machine change (directories, the service, the database and its user, the Docker image and volume).

Run the command for the way ActivityPulse was installed. Each one stops ActivityPulse, moves it, and starts TeamGlimpse; the application is offline in between.

Installed withCommand
Dockercurl -fsSL https://github.com/TeamGlimpse/teamglimpse-release/releases/latest/download/migrate-to-teamglimpse.sh | sudo bash
Debian packagecurl -fsSL https://github.com/TeamGlimpse/teamglimpse-release/releases/latest/download/install-deb.sh | sudo bash
tar.gz bundlecurl -fsSL https://github.com/TeamGlimpse/teamglimpse-release/releases/latest/download/install-tarball.sh | sudo bash

If a step fails, the old names are put back and ActivityPulse is started again.

Docker

  • The script expects the install in /opt/activitypulse. For a Compose directory elsewhere, add --from: ... | sudo bash -s -- --from /path/to/directory.
  • The database volume is copied, not moved. The old volume is kept as a fallback and the script prints the command that deletes it once you are satisfied.
  • The machine needs free disk space for a second copy of the database.
  • Changes made by hand to the old docker-compose.yml are not carried over. The old directory is kept as /opt/activitypulse.migrated-<date>; apply them to /opt/teamglimpse/docker-compose.yml.
  • Do not start the new docker-compose.yml from the release page in an old Compose directory: it uses a new, empty database volume.

Debian package and tar.gz bundle

  • A dump of all databases is written to /var/backups/teamglimpse-migration-<date>.sql.gz before anything is renamed.
  • The configuration moves to /etc/teamglimpse/teamglimpse.conf (package) or /opt/teamglimpse/teamglimpse.conf (bundle). Settings named ACTIVITYPULSE_EMAIL_... are renamed to TEAMGLIMPSE_EMAIL_....
  • The nginx site is carried over under the name teamglimpse, with your host names and certificates.
  • The service is now teamglimpse: sudo systemctl status teamglimpse, sudo journalctl -u teamglimpse -f.
  • A database on another server, or one whose user or name you chose yourself, is not renamed; its DATABASE_URL is carried over as it is.
  • When installing the package by hand (sudo apt install ./teamglimpse_<version>_amd64.deb) instead of with the command above, finish with sudo dpkg --purge activitypulse.

Prerequisites

Ubuntu Server Requirements

  • Ubuntu 22.04 LTS or newer
  • Minimum 2 GB RAM
  • 20 GB disk space
  • Root or sudo access

Required Software

Install the following packages:

sudo apt update
sudo apt install -y nginx postgresql postgresql-client

Installation via Debian Package

The easiest way to install TeamGlimpse on Debian/Ubuntu is using the .deb package. It handles all setup automatically: dependencies, system user, database initialization, nginx configuration, and the systemd service.

Quick Install

curl -fsSL https://github.com/TeamGlimpse/teamglimpse-release/releases/latest/download/install-deb.sh | sudo bash

This downloads and installs the latest .deb package with all dependencies (nginx, PostgreSQL). The package post-install script handles database initialization, JWT secret generation, and service startup. The script is non-interactive and safe to inspect before running.

If TeamGlimpse is already installed, the script prints the current version and upgrade instructions, then exits without making changes.

Manual Install

1. Install the Package

sudo apt install ./teamglimpse_1.0.0_amd64.deb

apt will install the required dependencies (nginx, postgresql, postgresql-client) and then run the post-install script, which:

  • Creates the teamglimpse system user
  • Initializes the PostgreSQL database and user
  • Generates a random JWT secret
  • Enables and activates the nginx site (removing the default site if present)
  • Enables and starts the teamglimpse systemd service

2. Configure the Application

Review and update the configuration file:

sudo nano /etc/teamglimpse/teamglimpse.conf

At minimum verify:

  • DATABASE_URL — set automatically during install, confirm it is correct
  • JWT_SECRET — generated automatically; replace if you prefer your own value
  • APP_URL — auto-detected from hostname; update to your actual domain if using DNS or TLS (required for SSO)

3. Start the Service

sudo systemctl restart teamglimpse
sudo systemctl status teamglimpse

Updating via Debian Package

To upgrade to a newer version, install the new package the same way:

sudo apt install ./teamglimpse_1.1.0_amd64.deb

The post-install script will automatically run any pending database migrations and restart the service. Your existing configuration in /etc/teamglimpse/teamglimpse.conf is preserved.

Uninstalling the Debian Package

1. Remove the package:

sudo apt remove teamglimpse

This stops the systemd service, removes the binary, frontend files, and nginx configuration. The configuration file at /etc/teamglimpse/teamglimpse.conf is kept in case you reinstall later.

To also remove the configuration file:

sudo apt purge teamglimpse

2. (Optional) Remove the PostgreSQL database:

The package does not drop the database on removal. Because TeamGlimpse creates a separate database for each organization, you must drop all of them before removing the user.

Drop the control database and all organization databases owned by teamglimpse:

# Drop all databases owned by the teamglimpse user
sudo -u postgres psql -tAc \
  "SELECT datname FROM pg_database WHERE datdba = (SELECT oid FROM pg_roles WHERE rolname = 'teamglimpse');" \
  | while read -r db; do
      sudo -u postgres psql -c "DROP DATABASE IF EXISTS \"$db\";"
    done

# Now drop the user
sudo -u postgres psql -c "DROP USER IF EXISTS teamglimpse;"

This permanently deletes all data. If you want to keep a backup, run export-db.sh first.

3. (Optional) Remove nginx:

If nginx was installed only for TeamGlimpse and is not used by other applications:

sudo apt purge nginx nginx-common
sudo apt autoremove

This removes nginx, its configuration files, and any dependencies that are no longer needed.

4. (Optional) Remove PostgreSQL:

If PostgreSQL was installed only for TeamGlimpse and is not used by other applications:

sudo apt purge postgresql postgresql-client
sudo apt autoremove

Warning: This removes the PostgreSQL server and all databases on the system, not just the TeamGlimpse database. Only do this if no other applications depend on PostgreSQL.


Deployment via Docker

Quick Install

curl -fsSL https://github.com/TeamGlimpse/teamglimpse-release/releases/latest/download/install-docker.sh | sudo bash

This sets up TeamGlimpse in /opt/teamglimpse with auto-generated credentials. Requires Docker with the Compose plugin. The script is non-interactive and safe to inspect before running.

If TeamGlimpse is already installed, the script prints update instructions and exits without making changes.

Manual Docker Setup

Docker is the easiest way to run TeamGlimpse when you don’t want to manage system dependencies directly. A single docker compose command starts the application and a PostgreSQL database.

The Docker container runs as a non-root user (teamglimpse) for improved security. Inside the container, nginx listens on port 8080 and the backend on port 8081 — both unprivileged ports. The HTTP_PORT variable (default 8080) controls which port is exposed on the host. To serve on port 80 or 443, place a reverse proxy (e.g. host nginx or Caddy with TLS) in front of the container.

Prerequisites

  • Docker Engine 24+ and Docker Compose v2

1. Get the Docker Image

Option A — Pull from GitHub Container Registry (recommended)

docker pull ghcr.io/teamglimpse/teamglimpse:latest

To pin to a specific version:

docker pull ghcr.io/teamglimpse/teamglimpse:0.6.0

Option B — Load from a downloaded archive

If you have a teamglimpse-<version>-docker.tar.gz file:

docker load -i teamglimpse-0.6.0-docker.tar.gz

2. Get the Compose File

Download docker-compose.yml from the releases page or copy it directly:

curl -fsSL https://github.com/TeamGlimpse/teamglimpse-release/releases/latest/download/docker-compose.yml \
  -o docker-compose.yml

The released docker-compose.yml is preconfigured to pull ghcr.io/teamglimpse/teamglimpse:latest. If you loaded the image from a downloaded archive instead, edit the image: line in docker-compose.yml to match the local tag (e.g. teamglimpse:0.6.0).

3. Generate Credentials

Run the setup script once to create a .env file with randomly generated credentials:

./docker-setup.sh

This creates a .env file next to docker-setup.sh with a strong random POSTGRES_PASSWORD and JWT_SECRET, plus an APP_URL guessed from the host name. The script will not overwrite an existing .env, so it is safe to re-run.

Manual setup (optional): If you prefer to set credentials yourself, create .env manually:

POSTGRES_PASSWORD=$(openssl rand -base64 24 | tr -d '/+=' | head -c 32)
JWT_SECRET=$(openssl rand -base64 64 | tr -d '\n')
# HTTP_PORT=8080
# JWT_EXPIRY_HOURS=24
# RUST_LOG=info
# APP_URL=http://localhost:8080
VariableRequiredDefaultDescription
POSTGRES_PASSWORDYes—PostgreSQL password
JWT_SECRETYes—JWT signing secret (auto-generated if missing, but not persistent)
HTTP_PORTNo8080Host port for HTTP (mapped to container port 8080)
JWT_EXPIRY_HOURSNo24Token expiry in hours
RUST_LOGNoinfoLog level (info, debug, warn)
APP_URLNoAuto-detectedBase URL of the instance (e.g. http://host:8080). Required for SSO.

ORG_POOL_CACHE_SIZE (maximum number of organization database connection pools kept open at once, default 32) is not read from .env by the bundled Compose file — Compose only substitutes the variables named in the environment: block. To change it under Docker, add a line to the teamglimpse service in docker-compose.yml:

    environment:
      ORG_POOL_CACHE_SIZE: "${ORG_POOL_CACHE_SIZE:-32}"

then set ORG_POOL_CACHE_SIZE in .env and recreate the container. Raise it only alongside PostgreSQL’s max_connections. See Configuring TeamGlimpse.

4. Start the Stack

docker compose --env-file .env up -d

TeamGlimpse will be available at http://localhost:8080 (or the port set by HTTP_PORT).

On first start the application automatically initializes the database schema before accepting connections.

Viewing Logs

Run these commands from the directory containing docker-compose.yml (e.g. /opt/teamglimpse):

# Follow all logs
docker compose logs -f

# Backend only
docker compose logs -f teamglimpse

Updating

If using GHCR:

docker pull ghcr.io/teamglimpse/teamglimpse:latest
docker compose up -d

If using a downloaded archive:

docker load -i teamglimpse-1.1.0-docker.tar.gz
docker compose up -d

The database and configuration in .env are preserved between updates.

One-time check: data volume name

TeamGlimpse stores its database in a Docker volume named teamglimpse_pgdata. Releases before this fix derived the volume name from the deployment directory, so some installs ended up with a different name (commonly docker_pgdata, or infra_pgdata on very old installs). Starting the new version against a renamed volume would create a fresh, empty database and leave your data stranded in the old volume.

Run this check once, before the first update to this version:

docker volume ls --format '{{.Name}}' | grep '_pgdata$'

If the only line is teamglimpse_pgdata, nothing to do — continue updating normally. Installs done with the install-docker.sh script (in /opt/teamglimpse) are always already on teamglimpse_pgdata.

If you see a different name (e.g. docker_pgdata), copy the data into the canonical volume while the stack is stopped:

docker compose stop

# Replace docker_pgdata with the name reported by the check above.
docker volume create teamglimpse_pgdata
docker run --rm -v docker_pgdata:/from -v teamglimpse_pgdata:/to \
  alpine cp -a /from/. /to/

docker compose up -d

cp -a preserves the file ownership and permissions that PostgreSQL requires. After confirming your data is present in the running app, remove the old volume:

docker volume rm docker_pgdata

Uninstalling

To completely remove the Docker deployment, stop the containers, remove them along with the data volume, and delete the install directory.

1. Stop and remove containers and volumes:

cd /opt/teamglimpse
docker compose --env-file .env down -v

The -v flag removes the pgdata volume containing all database data. This permanently deletes all data. If you want to keep a backup, run export-db.sh first (see Backup below).

To stop and remove containers but keep the data volume for later use:

docker compose --env-file .env down

2. Remove the install directory:

sudo rm -rf /opt/teamglimpse

3. (Optional) Remove the Docker image:

docker rmi ghcr.io/teamglimpse/teamglimpse:latest
docker rmi postgres:16

4. (Optional) Remove orphaned volumes:

If you ran down without -v and later decide to delete the data:

docker volume rm teamglimpse_pgdata

Persistent Data

PostgreSQL data is stored in the teamglimpse_pgdata Docker volume and survives container restarts and image updates. The volume name is fixed, so it stays the same regardless of where the deployment directory lives.

The volume is managed by Docker and its location on the host filesystem is determined by the Docker storage driver. You can inspect the exact path with:

docker volume inspect teamglimpse_pgdata

The Mountpoint field shows the host directory (typically under /var/lib/docker/volumes/). Do not modify files in this directory directly — use the backup and restore procedures below.

Backup (Export)

TeamGlimpse uses a multi-database architecture: one control database plus a separate database for each organization. The bundled export-db.sh script handles this automatically — it discovers all organization databases, dumps each one, and packages everything into a single archive with a manifest.

Where the scripts live: export-db.sh and import-db.sh ship in the release tarball under infra/, which is the path used in the examples below. In a source checkout of the repository they live in scripts/ instead — adjust the paths accordingly.

DATABASE_URL="postgres://teamglimpse:yourpassword@localhost:5432/teamglimpse" \
  ./infra/export-db.sh

This produces a file like teamglimpse-export-20260320-143000.tar.bz2. To specify a custom output path:

DATABASE_URL="..." ./infra/export-db.sh -o /backups/teamglimpse-backup.tar.bz2

Docker users: The script runs on the host and connects to PostgreSQL over the network. Ensure the database port is reachable. If you have not published the PostgreSQL port, you can either:

  • Temporarily add a ports mapping to the postgres service and recreate the container, or
  • Run the export from inside the postgres container:
docker compose exec postgres \
  pg_dumpall -U teamglimpse > teamglimpse-backup.sql

Note that pg_dumpall produces a single SQL file (not the structured archive format), which cannot be used with import-db.sh. For full export/import compatibility, use the scripts with a reachable DATABASE_URL.

Restore (Import)

The import-db.sh script restores an export archive. It reads the manifest, drops existing databases, and recreates everything from the archive.

WARNING: Import destroys all existing data in the target databases.

DATABASE_URL="postgres://teamglimpse:yourpassword@localhost:5432/teamglimpse" \
  ./infra/import-db.sh teamglimpse-export-20260320-143000.tar.bz2

The script will show a summary and ask for confirmation before proceeding. To skip the confirmation prompt (useful for scripted restores):

DATABASE_URL="..." ./infra/import-db.sh -y export.tar.bz2

Migrating to Another Host

  1. On the old server — export the database:
DATABASE_URL="postgres://teamglimpse:oldpass@localhost:5432/teamglimpse" \
  ./infra/export-db.sh -o teamglimpse-migration.tar.bz2
  1. Copy files to the new server:
scp teamglimpse-migration.tar.bz2 .env docker-compose.yml infra/import-db.sh \
  newserver:/path/to/teamglimpse/
  1. On the new server — start the stack and import:
# Start the stack (the entrypoint initializes an empty database)
docker compose up -d

# Import the backup (replace credentials with those from the new .env)
DATABASE_URL="postgres://teamglimpse:newpass@localhost:5432/teamglimpse" \
  ./infra/import-db.sh teamglimpse-migration.tar.bz2

Migrating Between Docker and Bare-Metal

The export/import scripts work against any reachable PostgreSQL instance — Docker or bare-metal. Just point DATABASE_URL at the appropriate server.

Docker → bare-metal:

# Export from Docker PostgreSQL
DATABASE_URL="postgres://teamglimpse:pass@localhost:5432/teamglimpse" \
  ./infra/export-db.sh -o migration.tar.bz2

# Import into bare-metal PostgreSQL
DATABASE_URL="postgres://teamglimpse:pass@localhost:5432/teamglimpse" \
  ./infra/import-db.sh migration.tar.bz2

Bare-metal → Docker:

# Export from bare-metal PostgreSQL
DATABASE_URL="postgres://teamglimpse:pass@localhost:5432/teamglimpse" \
  ./infra/export-db.sh -o migration.tar.bz2

# Import into Docker PostgreSQL (ensure the postgres container port is reachable)
DATABASE_URL="postgres://teamglimpse:dockerpass@localhost:5432/teamglimpse" \
  ./infra/import-db.sh migration.tar.bz2

Note: After migrating, verify that the DATABASE_URL and POSTGRES_PASSWORD in your target environment match the credentials of the target PostgreSQL instance. The import script connects using the DATABASE_URL you provide — it does not carry over credentials from the source.


Installation from a tar.gz bundle

Quick Install

curl -fsSL https://github.com/TeamGlimpse/teamglimpse-release/releases/latest/download/install-tarball.sh | sudo bash

This downloads the latest release tarball and performs a full bare-metal installation: installs dependencies (nginx, PostgreSQL) if missing, initializes the database with auto-generated credentials, deploys the backend binary, frontend files, nginx configuration, and systemd service. The script is non-interactive and safe to inspect before running.

If TeamGlimpse is already installed, the script prints upgrade instructions and exits without making changes.

Manual Install

1. Extract Release

# Create a temporary directory for extraction
cd /tmp

# Extract the release
tar -xzf teamglimpse-v1.0.0-linux-amd64.tar.gz

# Navigate to the release directory
cd teamglimpse-v1.0.0

2. Database Setup

Create the PostgreSQL database and user:

sudo -u postgres psql
-- Create user (CREATEDB is required because TeamGlimpse creates per-organization databases)
CREATE USER teamglimpse WITH ENCRYPTED PASSWORD 'your_secure_password' CREATEDB;

-- Create database
CREATE DATABASE teamglimpse OWNER teamglimpse;

-- Grant privileges
GRANT ALL PRIVILEGES ON DATABASE teamglimpse TO teamglimpse;

-- Connect to the database
\c teamglimpse

-- Enable required extensions
CREATE EXTENSION IF NOT EXISTS "pgcrypto";

\q

Initialize the schema using the provided SQL:

PGPASSWORD=<your_secure_password> psql -h localhost -p 5432 -U teamglimpse -d teamglimpse -f infra/init.sql

3. Run the Deployment Script

For first-time installation:

sudo ./infra/deploy.sh

The script will:

  • Create the teamglimpse system user
  • Install the backend binary to /opt/teamglimpse/
  • Install frontend files to /var/www/teamglimpse/
  • Set up systemd service
  • Configure nginx

Important: If nginx still shows the default “Welcome to nginx!” page after deployment, disable the default site — it conflicts because both listen on port 80 with server_name _:

sudo rm /etc/nginx/sites-enabled/default
sudo systemctl reload nginx

4. Configure the Application

Edit the configuration file:

sudo nano /opt/teamglimpse/teamglimpse.conf

At minimum, update:

  • DATABASE_URL - PostgreSQL connection string
  • JWT_SECRET - Generate a secure random string
  • APP_URL - Auto-detected from hostname; update to your actual domain if using DNS or TLS (required for SSO)
# Generate a secure JWT secret
openssl rand -base64 64 | tr -d '\n'

5. Start the Service

sudo systemctl restart teamglimpse
sudo systemctl status teamglimpse

6. Configure Domain (Optional)

If you have a domain name:

  1. Update nginx configuration:
   sudo nano /etc/nginx/sites-available/teamglimpse

Change server_name _; to your domain:

   server_name example.com www.example.com;
  1. Reload nginx:
   sudo systemctl reload nginx
  1. Set up SSL with Let’s Encrypt:
   sudo apt install certbot python3-certbot-nginx
   sudo certbot --nginx -d example.com -d www.example.com

Updating

To update to a new version, download the new release tarball, then:

1. Run Update

sudo ./infra/deploy.sh --update

The --update flag:

  • Skips user/directory creation
  • Preserves existing teamglimpse.conf configuration
  • Only updates binaries and frontend files

2. Database Migrations

No separate step is needed: deploy.sh --update runs infra/migrations/run_migration.sh --all before it installs the new binaries, and aborts the update if a migration fails.

Do not apply migration .sql files by hand with psql. TeamGlimpse stores each organization in its own database, and run_migration.sh is what discovers those databases and applies every pending migration to the control database and each organization database, recording what it applied. Running a single file against the control database alone leaves the organization databases behind.

To run migrations on their own (for example after restoring a backup), invoke the script directly from the extracted release:

sudo DATABASE_URL="postgres://teamglimpse:yourpassword@localhost:5432/teamglimpse" \
  ./infra/migrations/run_migration.sh --all

Uninstalling

1. Stop and disable the service:

sudo systemctl stop teamglimpse
sudo systemctl disable teamglimpse

2. Remove installed files:

# Remove the systemd unit file
sudo rm /etc/systemd/system/teamglimpse.service
sudo systemctl daemon-reload

# Remove the backend binary and configuration
sudo rm -rf /opt/teamglimpse

# Remove the frontend files
sudo rm -rf /var/www/teamglimpse

# Remove the nginx site configuration
sudo rm /etc/nginx/sites-enabled/teamglimpse
sudo rm /etc/nginx/sites-available/teamglimpse
sudo systemctl reload nginx

3. (Optional) Remove the system user:

sudo userdel teamglimpse

4. (Optional) Remove the PostgreSQL database:

Because TeamGlimpse creates a separate database for each organization, you must drop all of them before removing the user.

# Drop all databases owned by the teamglimpse user
sudo -u postgres psql -tAc \
  "SELECT datname FROM pg_database WHERE datdba = (SELECT oid FROM pg_roles WHERE rolname = 'teamglimpse');" \
  | while read -r db; do
      sudo -u postgres psql -c "DROP DATABASE IF EXISTS \"$db\";"
    done

# Now drop the user
sudo -u postgres psql -c "DROP USER IF EXISTS teamglimpse;"

This permanently deletes all data. If you want to keep a backup, run export-db.sh first (see Backup).

5. (Optional) Remove nginx:

If nginx was installed only for TeamGlimpse and is not used by other applications:

sudo apt purge nginx nginx-common
sudo apt autoremove

6. (Optional) Remove PostgreSQL:

If PostgreSQL was installed only for TeamGlimpse and is not used by other applications:

sudo apt purge postgresql postgresql-client
sudo apt autoremove

Warning: This removes the PostgreSQL server and all databases on the system, not just the TeamGlimpse database. Only do this if no other applications depend on PostgreSQL.


TLS/HTTPS with Let’s Encrypt

Serving TeamGlimpse over HTTPS is strongly recommended for any public-facing deployment. Certbot automates certificate issuance and renewal via Let’s Encrypt.

Prerequisites

  • A domain name pointed at your server (DNS A record)
  • Port 80 open (required for the HTTP-01 ACME challenge)
  • TeamGlimpse already running and reachable at http://your-domain.com

1. Install Certbot

sudo apt install -y certbot python3-certbot-nginx

2. Obtain a Certificate

sudo certbot --nginx -d example.com -d www.example.com

Certbot will:

  1. Verify domain ownership via an HTTP challenge
  2. Issue a certificate signed by Let’s Encrypt
  3. Automatically update the nginx configuration to enable HTTPS and redirect HTTP → HTTPS

When prompted, choose Redirect to enforce HTTPS for all traffic.

3. Verify Automatic Renewal

Certbot installs a systemd timer (or cron job) that renews certificates before they expire. Test it with:

sudo certbot renew --dry-run

A successful dry-run means certificates will renew automatically.

4. Update APP_URL

After enabling HTTPS, update APP_URL in your configuration file to use https://:

# Debian package
sudo nano /etc/teamglimpse/teamglimpse.conf

# Tarball
sudo nano /opt/teamglimpse/teamglimpse.conf

Change APP_URL=http://example.com to APP_URL=https://example.com, then restart the service:

sudo systemctl restart teamglimpse

This ensures invitation links and SSO redirects use the correct protocol.

5. Check Certificate Status

sudo certbot certificates

Firewall

Make sure port 443 is open in addition to port 80:

sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
sudo ufw enable

Port 80 must remain open — Certbot needs it for renewal challenges.

Troubleshooting

Certificate issuance fails: Confirm the domain resolves to your server’s public IP and that port 80 is reachable from the internet.

nginx fails to reload after renewal: Check sudo nginx -t for configuration errors, then sudo systemctl reload nginx.

Certificate expires unexpectedly: Verify the Certbot timer is active: sudo systemctl status certbot.timer.


Troubleshooting

Permission Denied to Create Database

If the logs show permission denied to create database, the PostgreSQL user is missing the CREATEDB privilege. TeamGlimpse creates a separate database for each organization, so this privilege is required.

Fix:

sudo -u postgres psql -c "ALTER USER teamglimpse CREATEDB;"
sudo systemctl restart teamglimpse

Port Already in Use

The installer and deployment scripts pre-flight check that the backend port (default 8080) is free before starting the service. If something else is already bound to that port, the install or upgrade aborts with a message like:

[ERROR] Port 8080 is already in use:
[ERROR]   LISTEN 0  4096  0.0.0.0:8080  0.0.0.0:*  users:(("some-process",pid=1234,fd=3))

Identify the offending process:

sudo ss -tlnp 'sport = :8080'

Then either:

  1. Stop the conflicting service and re-run the installer (Debian: sudo dpkg --configure teamglimpse; tarball: sudo ./infra/deploy.sh).
  2. Run TeamGlimpse on a different port — set PORT=<n> in /etc/teamglimpse/teamglimpse.conf (Debian package) or /opt/teamglimpse/teamglimpse.conf (tarball), update the upstream teamglimpse_backend block in /etc/nginx/sites-available/teamglimpse to match, then restart:
   sudo systemctl restart teamglimpse
   sudo systemctl reload nginx

For Docker deployments, set HTTP_PORT in .env (or pass it to install-docker.sh) — the installer’s port check uses that value.

Service Won’t Start

Check the logs:

sudo journalctl -u teamglimpse -f

Common issues:

  • Database connection failed: Verify DATABASE_URL in teamglimpse.conf
  • Port already in use: Check if another service is using port 8080
  • Permission denied: Ensure proper ownership of /opt/teamglimpse

Nginx Returns 502 Bad Gateway

The backend service isn’t running or isn’t responding:

# Check if backend is running
sudo systemctl status teamglimpse

# Check if port 8080 is listening
ss -tlnp | grep 8080

# Check nginx error logs
sudo tail -f /var/log/nginx/teamglimpse_error.log

Frontend Shows Blank Page

  1. Check that files exist:
   ls -la /var/www/teamglimpse/
  1. Check nginx configuration:
   sudo nginx -t
  1. Check browser console for JavaScript errors

Checking Service Health

# Service status
sudo systemctl status teamglimpse

# Recent logs
sudo journalctl -u teamglimpse -n 50

# Test API endpoint
curl http://localhost:8080/health

Security Recommendations

  1. Firewall: Only expose ports 80 and 443
   sudo ufw allow 80/tcp
   sudo ufw allow 443/tcp
   sudo ufw enable
  1. SSL/TLS: Always use HTTPS in production with Let’s Encrypt

  2. Database: Use a strong password and restrict access to localhost

  3. JWT Secret: Use a cryptographically secure random string (minimum 64 characters)

  4. Updates: Regularly update Ubuntu packages

   sudo apt update && sudo apt upgrade

Directory Structure Reference

/opt/teamglimpse/
├── teamglimpse-backend   # Main binary
└── teamglimpse.conf      # Environment configuration

/var/www/teamglimpse/
├── index.html              # Frontend entry point
├── assets/                 # JS/CSS bundles
└── ...                     # Other static files

/etc/nginx/sites-available/
└── teamglimpse           # Nginx configuration

/etc/systemd/system/
└── teamglimpse.service   # Systemd unit

Support

  • Check service logs: sudo journalctl -u teamglimpse -f
  • Check nginx logs: sudo tail -f /var/log/nginx/teamglimpse_error.log
  • Check PostgreSQL logs: sudo tail -f /var/log/postgresql/postgresql-*-main.log