Promote returning students, assign officers, and clear last season's data after an automatic SQLite backup, with Docker volume path docs fixed for /app/Data. Co-authored-by: Cursor <cursoragent@cursor.com>
8.4 KiB
Docker Deployment Guide
Authentication Configuration for Production
The application supports two methods for configuring authentication credentials in Docker:
Option 1: Volume-Mounted JSON File (Recommended)
This approach allows you to edit credentials without rebuilding the container.
Steps:
-
Generate Password Hashes (on your development machine):
# Run the app locally and navigate to: https://localhost:<port>/dev/hash-password?password=YourPassword -
Create
auth-secrets.jsonon your Docker host:cp auth-secrets.example.json auth-secrets.json -
Edit
auth-secrets.jsonand replace the placeholder hashes:{ "Authentication": { "Users": [ { "Email": "admin@example.com", "PasswordHash": "$2a$11$actual.hash.here", "Role": "Administrator", "DisplayName": "Administrator" } ] } } -
Mount the file in Docker Compose:
volumes: - ./auth-secrets.json:/app/secrets/auth-secrets.json:ro -
Update credentials: Simply edit
auth-secrets.jsonon the host and restart the container:docker-compose restart webapp
Security Note: Set proper file permissions on the host:
chmod 600 auth-secrets.json
Option 2: Environment Variables
This approach is useful for container orchestration platforms (Kubernetes, Docker Swarm, etc.).
Docker Compose Example:
environment:
- TSA_Authentication__Users__0__Email=admin@example.com
- TSA_Authentication__Users__0__PasswordHash=$2a$11$hash...
- TSA_Authentication__Users__0__Role=Administrator
- TSA_Authentication__Users__0__DisplayName=Administrator
- TSA_Authentication__Users__1__Email=advisor@example.com
- TSA_Authentication__Users__1__PasswordHash=$2a$11$hash...
- TSA_Authentication__Users__1__Role=Advisor
- TSA_Authentication__Users__1__DisplayName=Chapter Advisor
Docker Run Example:
docker run -d \
-p 8080:8080 \
-e ASPNETCORE_ENVIRONMENT=Production \
-e TSA_Authentication__Users__0__Email=admin@example.com \
-e TSA_Authentication__Users__0__PasswordHash='$2a$11$hash...' \
-e TSA_Authentication__Users__0__Role=Administrator \
-e TSA_Authentication__Users__0__DisplayName=Administrator \
tsa-chapter-organizer:latest
Kubernetes Secret Example:
apiVersion: v1
kind: Secret
metadata:
name: tsa-auth-secrets
type: Opaque
stringData:
TSA_Authentication__Users__0__Email: "admin@example.com"
TSA_Authentication__Users__0__PasswordHash: "$2a$11$hash..."
TSA_Authentication__Users__0__Role: "Administrator"
TSA_Authentication__Users__0__DisplayName: "Administrator"
Building and Running
Publish to Docker Registry (Recommended)
Use the provided PowerShell script to build and publish the Docker image:
.\publish-docker.ps1
Options:
-Tag "v1.0.0"- Specify a custom tag (default: "latest")-Registry "docker-registry.kolpacksoftware.com"- Specify registry URL-ImageName "tsa-chapter-organizer"- Specify image name-BuildConfiguration "Release"- Specify build configuration
Examples:
# Publish with default settings (latest tag)
.\publish-docker.ps1
# Publish with a version tag
.\publish-docker.ps1 -Tag "v1.0.0"
# Publish with custom registry
.\publish-docker.ps1 -Tag "latest" -Registry "my-registry.com"
Build the Docker Image (Manual)
If you prefer to build manually:
cd WebApp
docker build -t tsa-chapter-organizer:latest .
Or from the root directory:
docker build -f WebApp/Dockerfile -t tsa-chapter-organizer:latest .
Run with Docker Compose
# Copy and customize the example
cp docker-compose.example.yml docker-compose.yml
# Edit auth-secrets.json with your credentials
cp auth-secrets.example.json auth-secrets.json
# (Edit the file and replace hashes)
# Start the container
docker-compose up -d
# View logs
docker-compose logs -f webapp
Access the Application
- HTTP:
http://localhost:8080 - HTTPS:
https://localhost:8081(if configured)
Data Persistence (SQLite + Backups)
The app stores its SQLite database and runtime config under Data/ (capital D) relative to the content root:
| Path in container | Purpose |
|---|---|
/app/Data/app.db |
Live SQLite database |
/app/Data/appsettings.json |
Chapter settings overrides (e.g. CompetitionYear) |
/app/Data/backups/pre-rollover-*.db |
Automatic backups created by New Year Rollover |
Docker volume mount must use capital Data:
volumes:
- ./data:/app/Data
On Linux, ./data:/app/data is a different path and will not persist the database or rollover backups. After a correct mount, host files appear under ./data/ (for example ./data/app.db and ./data/backups/).
Ensure the container user can write to the mounted directory (the image runs as a non-root APP_UID). If directory creation for backups/ fails, year rollover aborts before changing data.
For the rollover workflow itself, see docs/instructions/year-rollover.md.
Managing Users
Adding a New User
With Volume-Mounted File:
- Edit
auth-secrets.jsonon the host - Add new user entry to the
Usersarray - Restart the container:
docker-compose restart webapp
With Environment Variables:
- Add new environment variables (increment the index number)
- Recreate the container:
docker-compose up -d
Changing a Password
- Generate new hash using the dev endpoint (on local dev machine)
- Update the
PasswordHashvalue in your configuration - Restart/recreate the container
Removing a User
- Remove the user entry from your configuration
- Restart/recreate the container
Security Considerations
-
File Permissions:
chmod 600 auth-secrets.json chown root:root auth-secrets.json -
Never Commit Secrets: Add to
.gitignore:auth-secrets.json docker-compose.yml -
Use HTTPS in Production: Configure SSL/TLS certificates
-
Backup Credentials: Store encrypted backups of
auth-secrets.json -
Password Rotation: Periodically regenerate password hashes
-
Monitor Access: Review application logs for failed login attempts:
docker-compose logs webapp | grep "Failed login"
Troubleshooting
Container Won't Start
Check logs:
docker-compose logs webapp
Can't Login
-
Verify
auth-secrets.jsonis properly mounted:docker exec tsa-app ls -la /app/secrets/ -
Check if the file is being loaded:
docker-compose logs webapp | grep "secrets" -
Verify JSON syntax:
cat auth-secrets.json | jq .
Forgot Admin Password
- Generate a new password hash locally
- Update
auth-secrets.jsonon the host - Restart the container
Example: Complete Setup
# 1. Generate password hashes locally
# Navigate to: https://localhost:5001/dev/hash-password?password=MySecurePass123
# 2. Create secrets file
cat > auth-secrets.json <<EOF
{
"Authentication": {
"Users": [
{
"Email": "admin@myschool.edu",
"PasswordHash": "$2a$11$paste_hash_here",
"Role": "Administrator",
"DisplayName": "TSA Admin"
}
]
}
}
EOF
# 3. Set permissions
chmod 600 auth-secrets.json
# 4. Create docker-compose.yml
cp docker-compose.example.yml docker-compose.yml
# 5. Start the application
docker-compose up -d
# 6. Check it's running
docker-compose ps
curl http://localhost:8080
# 7. Login
# Navigate to http://localhost:8080/login
# Use: admin@myschool.edu / MySecurePass123
Production Deployment Checklist
- Generated secure password hashes
- Created
auth-secrets.jsonwith production credentials - Set file permissions to 600
- Configured HTTPS/SSL certificates
- Updated
ASPNETCORE_URLSfor production domain - Configured volume for database persistence as
./data:/app/Data(capital D) - Verified
app.dbappears on the host under./data/after first run - Removed development endpoints (already done in code)
- Set up log monitoring
- Confirmed year-rollover backups write to
./data/backups/(seedocs/instructions/year-rollover.md) - Tested login with all user roles
- Tested rate limiting (5 failed attempts)
- Documented admin password securely
- Added
auth-secrets.jsonto.gitignore