docs(tinyauth): document .env file solution for "User not found" error

- Add Issue #5: "User not found" error resolved with .env file approach
- Update Configuration section to show .env as RECOMMENDED method
- Document $$ escaping requirement for bcrypt hashes in .env files
- Update credential management, troubleshooting, and backup sections
- Update status to "User authentication working with .env configuration"

The .env file approach eliminates YAML/shell parsing issues with special
characters in bcrypt hashes and represents Docker Compose best practice.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
2025-12-18 18:12:35 -07:00
parent c4962194e3
commit 7df2b1075e

View File

@@ -70,6 +70,16 @@ TinyAuth is a lightweight, self-hosted authentication service providing Single S
### Docker Compose
**✅ RECOMMENDED APPROACH**: Use `.env` file for credential storage
This method eliminates YAML/shell parsing issues with special characters in bcrypt hashes and represents Docker Compose best practice for credential management.
**File**: `/home/jramos/homelab/services/tinyauth/.env`
```bash
USERS=jramos:$$2y$$05$$CNW/Anbac0mD./ajAepRm.aUvpeAFtOWVrqSxge5wEKZK3yD1.tT.
```
**File**: `/home/jramos/homelab/services/tinyauth/docker-compose.yml`
```yaml
@@ -82,14 +92,23 @@ services:
- "8000:3000" # External:Internal (TinyAuth runs on port 3000 internally)
environment:
- APP_URL=https://tinyauth.apophisnetworking.net
- USERS='jramos:$2b$05$...' # Bcrypt-hashed password (MUST be single-quoted)
- USERS=${USERS} # References .env file variable
```
**Critical Configuration Notes**:
- **APP_URL**: MUST use the domain name, not an IP address (IP addresses trigger validation errors)
- **Port Mapping**: TinyAuth listens on port 3000 internally, exposed as 8000 externally
- **USERS Format**: `'username:bcrypt_hash'` - Single quotes prevent shell interpretation of special characters
- **USERS Format**: `username:bcrypt_hash` stored in `.env` file
- **Bcrypt Hash**: Generate with `htpasswd -nbB username password`, then extract hash portion
- **Double Dollar Signs**: In `.env` files, use `$$` to escape dollar signs in bcrypt hashes (e.g., `$$2y$$05$$...`)
- **.env File Security**: Set permissions with `chmod 600 .env` to restrict access
**Why .env File is Recommended**:
- ✅ Prevents YAML/shell parsing issues with special characters in bcrypt hashes
- ✅ Cleaner separation of secrets from configuration
- ✅ Easier to manage multiple users (just edit one variable)
- ✅ Avoids quoting complexity in docker-compose.yml
- ✅ Standard practice for Docker Compose credential management
### Nginx Proxy Manager Configuration
@@ -224,20 +243,20 @@ docker ps | grep tinyauth
**Root Cause**:
- TinyAuth v4 requires **bcrypt-hashed passwords**, not plaintext
- Initial configuration used `USERS=jramos:Nbkx4md007` (plaintext)
- Initial configuration used plaintext password storage
- TinyAuth compares bcrypt hash of input against stored hash - plaintext storage fails
**Solution**:
1. Generate bcrypt hash:
```bash
htpasswd -nbB jramos Nbkx4md007
htpasswd -nbB jramos YourPassword
# Output: jramos:$2b$05$AbCdEfGhIjKlMnOpQrStUvWxYz0123456789...
```
2. Update docker-compose.yml with **single-quoted hash**:
```yaml
- USERS='jramos:$2b$05$AbCdEfGhIjKlMnOpQrStUvWxYz0123456789...'
2. Store hash in `.env` file with `$$` escaping:
```bash
USERS=jramos:$$2y$$05$$AbCdEfGhIjKlMnOpQrStUvWxYz0123456789...
```
3. Restart container:
@@ -247,22 +266,79 @@ docker-compose down
docker-compose up -d
```
**Why Single Quotes Matter**:
- `$` has special meaning in shell/YAML double-quoted strings
- Single quotes prevent variable expansion and preserve the literal bcrypt hash
- Without quotes, the hash will be corrupted during environment variable parsing
**Why Bcrypt Hash is Required**:
- Security: Bcrypt is computationally expensive, resists brute force attacks
- Industry Standard: Modern password storage best practice
- One-way Hash: Even if .env is compromised, passwords cannot be reversed
**Validation**:
```bash
# Check environment variable is set correctly
# Check environment variable is set correctly inside container
docker exec tinyauth env | grep USERS
# Should show: USERS='jramos:$2b$05$...'
# Should show: USERS=jramos:$2y$05$... (single $ inside container)
# Test authentication
curl -u jramos:Nbkx4md007 http://192.168.2.10:8000/api/auth/nginx
curl -u jramos:YourPassword http://192.168.2.10:8000/api/auth/nginx
# Should return HTTP 200 on success
```
### Issue #5: "User not found" Error - Resolved with .env File Approach
**Symptoms**:
- Login page loaded correctly
- Valid credentials entered but TinyAuth returned "User not found"
- Logs showed: `WRN internal/service/auth_service.go:130 > Local user not found username=jramos`
- docker-compose.yml had USERS environment variable configured with bcrypt hash
**Root Cause**:
- YAML/shell parsing of bcrypt hashes with special characters (`$`) was inconsistent
- Even with single quotes in docker-compose.yml, the hash could be corrupted during environment variable expansion
- Different YAML parsers handle quoted strings with `$` symbols differently
- The quoted string approach created subtle parsing issues that prevented TinyAuth from recognizing the user
**Solution**:
1. Create `.env` file in `/home/jramos/homelab/services/tinyauth/`:
```bash
USERS=jramos:$$2y$$05$$CNW/Anbac0mD./ajAepRm.aUvpeAFtOWVrqSxge5wEKZK3yD1.tT.
```
2. Update docker-compose.yml to reference the variable:
```yaml
environment:
- USERS=${USERS}
```
3. Restart container:
```bash
cd /home/jramos/homelab/services/tinyauth
docker-compose down
docker-compose up -d
```
**Why This Works**:
- `.env` files use different escaping rules than YAML
- `$$` in `.env` files escapes to a single `$` in the environment variable
- Docker Compose reads .env files automatically and substitutes `${USERS}` with the file content
- Eliminates YAML parser ambiguity with special characters
- The `.env` approach is Docker Compose's intended method for managing credentials
**Validation**:
```bash
# Verify .env file exists and has correct format
cat /home/jramos/homelab/services/tinyauth/.env
# Should show: USERS=jramos:$$2y$$05$$...
# Verify environment variable is correct inside container
docker exec tinyauth env | grep USERS
# Should show: USERS=jramos:$2y$05$... (single $ inside container)
# Test authentication
curl -u jramos:YourPassword http://192.168.2.10:8000/api/auth/nginx
# Should return HTTP 200
```
**✅ This is now the RECOMMENDED configuration method** - see Configuration section above.
## Access & Credentials
### Login URL
@@ -276,22 +352,26 @@ curl -u jramos:Nbkx4md007 http://192.168.2.10:8000/api/auth/nginx
```bash
htpasswd -nbB newuser password123
```
2. Update docker-compose.yml USERS variable (comma-separated for multiple users):
```yaml
- USERS='jramos:$2b$05$...,alice:$2b$05$...,bob:$2b$05$...'
2. Update `.env` file with USERS variable (comma-separated for multiple users):
```bash
USERS=jramos:$$2y$$05$$...,alice:$$2y$$05$$...,bob:$$2y$$05$$...
```
**Remember**: Use `$$` (double dollar signs) to escape `$` in .env files
3. Restart container:
```bash
cd /home/jramos/homelab/services/tinyauth
docker-compose down && docker-compose up -d
```
**Changing Passwords**:
1. Generate new bcrypt hash with new password
2. Replace the hash in docker-compose.yml
2. Replace the hash in `.env` file (remember to use `$$` for escaping)
3. Restart container
**Security Note**: Credentials are stored in docker-compose.yml. For production use, consider:
- Environment variable injection from secrets management
**Security Note**: Credentials are stored in `.env` file. For production use, consider:
- Set file permissions: `chmod 600 .env`
- Environment variable injection from secrets management (Docker Secrets, Vault)
- Integration with LDAP/Active Directory
- Migration to more robust SSO (Authelia, Keycloak)
@@ -327,7 +407,10 @@ docker-compose restart
### Backup
```bash
# Backup docker-compose.yml (contains credentials)
# Backup .env file (contains credentials) - CRITICAL
cp .env .env.backup-$(date +%Y%m%d)
# Backup docker-compose.yml
cp docker-compose.yml docker-compose.yml.backup-$(date +%Y%m%d)
```
@@ -337,6 +420,7 @@ cp docker-compose.yml docker-compose.yml.backup-$(date +%Y%m%d)
docker pull ghcr.io/steveiliop56/tinyauth:v4
# Recreate container with new image
cd /home/jramos/homelab/services/tinyauth
docker-compose down
docker-compose pull
docker-compose up -d
@@ -357,21 +441,28 @@ docker logs nginx-proxy-manager | grep tinyauth
curl -I https://tinyauth.apophisnetworking.net
```
### Symptoms: "Invalid password" error
### Symptoms: "Invalid password" or "User not found" error
**Check**:
1. USERS environment variable uses bcrypt hash: `docker exec tinyauth env | grep USERS`
2. Hash is single-quoted in docker-compose.yml
3. Password hasn't changed since hash generation
4. Account isn't locked (wait 5 minutes after 5 failed attempts)
1. `.env` file exists in same directory as docker-compose.yml
2. USERS environment variable uses bcrypt hash with `$$` escaping in .env: `cat .env`
3. Hash is correctly loaded inside container: `docker exec tinyauth env | grep USERS`
4. Password hasn't changed since hash generation
5. Account isn't locked (wait 5 minutes after 5 failed attempts)
**Commands**:
```bash
# Verify hash format
# Verify .env file exists and has correct format
cat /home/jramos/homelab/services/tinyauth/.env
# Should show: USERS=jramos:$$2y$$05$$...
# Verify hash format inside container (single $, not double)
docker exec tinyauth env | grep USERS
# Should show: USERS=jramos:$2y$05$... (single $ inside container)
# Test authentication directly
curl -u jramos:Nbkx4md007 http://192.168.2.10:8000/api/auth/nginx
curl -u jramos:YourPassword http://192.168.2.10:8000/api/auth/nginx
# Should return HTTP 200 on success
```
### Symptoms: "IP addresses not allowed"
@@ -424,8 +515,8 @@ curl -u jramos:Nbkx4md007 http://192.168.2.10:8000/api/auth/nginx
✅ No database dependencies (reduces vulnerability vectors)
### Weaknesses & Mitigations
⚠️ **Credentials in docker-compose.yml**: Ensure file permissions restrict read access
- Mitigation: `chmod 600 docker-compose.yml`
⚠️ **Credentials in .env file**: Ensure file permissions restrict read access
- Mitigation: `chmod 600 .env`
- Future: Migrate to secrets management (Docker Secrets, Vault)
⚠️ **No MFA**: Single-factor authentication only
@@ -443,6 +534,7 @@ curl -u jramos:Nbkx4md007 http://192.168.2.10:8000/api/auth/nginx
### Recommended Hardening
1. **File Permissions**:
```bash
chmod 600 /home/jramos/homelab/services/tinyauth/.env
chmod 600 /home/jramos/homelab/services/tinyauth/docker-compose.yml
```
@@ -456,7 +548,7 @@ curl -u jramos:Nbkx4md007 http://192.168.2.10:8000/api/auth/nginx
4. **Log Monitoring**:
- Configure alerts for repeated authentication failures
- Forward logs to Loki (CT 101 - monitoring stack)
- Forward logs to Loki (VM 101 - monitoring stack)
## Future Enhancements
@@ -468,7 +560,7 @@ curl -u jramos:Nbkx4md007 http://192.168.2.10:8000/api/auth/nginx
### Medium-Term
- [ ] Extend authentication to Proxmox web UI (if supported by TinyAuth)
- [ ] Implement automated backup of docker-compose.yml to PBS
- [ ] Implement automated backup of .env to Proxmox Backup Server
- [ ] Explore TinyAuth API for programmatic user management
### Long-Term
@@ -489,4 +581,4 @@ curl -u jramos:Nbkx4md007 http://192.168.2.10:8000/api/auth/nginx
**Maintained by**: Homelab Infrastructure Team
**Last Updated**: 2025-12-18
**Status**: ✅ Operational - Protecting NetBox with SSO authentication
**Status**: ✅ Operational - User authentication working with .env configuration