Skip to main content

Deployment

Development (Docker Compose)

The default docker-compose.yml starts the full stack with SQLite and local file storage — no external dependencies required.

# Clone and start
git clone https://github.com/jchable/gpx-utility-analyzer.git
cd gpx-utility-analyzer
docker compose up --build

# Rebuild after code changes
docker compose up --build -d

Services started:

ContainerPortDescription
gpx-api5000ASP.NET Core Web API
gpx-client8081React frontend (nginx)
gpx-rustfs9000 / 9001RustFS S3 storage (optional)

The API auto-creates the SQLite database and runs migrations on startup.

Production (PostgreSQL + RustFS)

Use the prod overlay to add PostgreSQL:

docker compose -f docker-compose.yml -f docker-compose.prod.yml up --build -d

To also enable S3 object storage, add these environment variables to the api service:

- Storage__Type=s3
- Storage__S3__Endpoint=http://rustfs:9000
- Storage__S3__AccessKey=${RUSTFS_ACCESS_KEY}
- Storage__S3__SecretKey=${RUSTFS_SECRET_KEY}
- Storage__S3__BucketName=gpx-files

RustFS (S3-compatible storage)

The docker-compose.yml includes a rustfs service. To activate it:

  1. Uncomment the S3 env vars in the api service
  2. Optionally set credentials via a .env file:
RUSTFS_ACCESS_KEY=your-access-key
RUSTFS_SECRET_KEY=your-secret-key

Access the RustFS web console at http://localhost:9001 (default credentials: rustfsadmin / rustfsadmin).

Environment Variables

Required for Production

VariableDescription
Jwt__SecretJWT signing key (min 32 chars, keep secret)
AiProvider__ApiKeyAPI key for your AI provider

Database

VariableDefaultDescription
Database__Providersqlitesqlite or postgresql
Database__ConnectionStrings__SqliteData Source=/app/data/gpxanalyzer.dbSQLite path
Database__ConnectionStrings__PostgreSqlPostgreSQL connection string

Storage

VariableDefaultDescription
Storage__Typelocallocal or s3
Storage__GpxDirectory/app/data/gpxLocal GPX storage path
Storage__DemDirectory/app/data/demSRTM DEM cache path
Storage__S3__Endpointhttp://localhost:9000S3 endpoint URL
Storage__S3__AccessKeyrustfsadminS3 access key
Storage__S3__SecretKeyrustfsadminS3 secret key
Storage__S3__BucketNamegpx-filesS3 bucket name

Email

VariableDefaultDescription
Email__Typenoopnoop (logs only) or smtp
Email__Smtp__HostlocalhostSMTP server hostname
Email__Smtp__Port587SMTP port
Email__Smtp__UsernameSMTP username
Email__Smtp__PasswordSMTP password
Email__Smtp__Fromnoreply@gpx-analyzer.appSender address

AI Provider

VariableDefaultDescription
AiProvider__NamegeminiProvider: openai, anthropic, mistral, gemini, ollama, azure-openai
AiProvider__ApiKeyAPI key
AiProvider__ModelModel name (e.g., gemini-2.0-flash)
AiProvider__EndpointCustom endpoint URL (Azure, Ollama)

JWT

VariableDefaultDescription
Jwt__SecretDev defaultSigning key (≥32 chars)
Jwt__Issuergpx-analyzerJWT issuer claim
Jwt__Audiencegpx-analyzer-clientJWT audience claim
Jwt__AccessTokenExpirationMinutes60Access token lifetime
Jwt__RefreshTokenExpirationDays30Refresh token lifetime

Data Volumes

VolumeDescription
api-dataSQLite DB, local GPX files, DEM tiles
rustfs-dataRustFS object data
rustfs-logsRustFS logs

Re-deploy Checklist

After backend code changes:

# 1. Rebuild and restart
docker compose up --build -d

# 2. Verify API is healthy
curl -s http://localhost:5000/api/activities -H "Authorization: Bearer <token>"

# 3. Check logs if needed
docker logs gpx-api --tail 50
docker logs gpx-client --tail 20