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:
@@ -70,6 +70,16 @@ TinyAuth is a lightweight, self-hosted authentication service providing Single S
|
|||||||
|
|
||||||
### Docker Compose
|
### 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`
|
**File**: `/home/jramos/homelab/services/tinyauth/docker-compose.yml`
|
||||||
|
|
||||||
```yaml
|
```yaml
|
||||||
@@ -82,14 +92,23 @@ services:
|
|||||||
- "8000:3000" # External:Internal (TinyAuth runs on port 3000 internally)
|
- "8000:3000" # External:Internal (TinyAuth runs on port 3000 internally)
|
||||||
environment:
|
environment:
|
||||||
- APP_URL=https://tinyauth.apophisnetworking.net
|
- 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**:
|
**Critical Configuration Notes**:
|
||||||
- **APP_URL**: MUST use the domain name, not an IP address (IP addresses trigger validation errors)
|
- **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
|
- **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
|
- **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
|
### Nginx Proxy Manager Configuration
|
||||||
|
|
||||||
@@ -224,20 +243,20 @@ docker ps | grep tinyauth
|
|||||||
|
|
||||||
**Root Cause**:
|
**Root Cause**:
|
||||||
- TinyAuth v4 requires **bcrypt-hashed passwords**, not plaintext
|
- 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
|
- TinyAuth compares bcrypt hash of input against stored hash - plaintext storage fails
|
||||||
|
|
||||||
**Solution**:
|
**Solution**:
|
||||||
|
|
||||||
1. Generate bcrypt hash:
|
1. Generate bcrypt hash:
|
||||||
```bash
|
```bash
|
||||||
htpasswd -nbB jramos Nbkx4md007
|
htpasswd -nbB jramos YourPassword
|
||||||
# Output: jramos:$2b$05$AbCdEfGhIjKlMnOpQrStUvWxYz0123456789...
|
# Output: jramos:$2b$05$AbCdEfGhIjKlMnOpQrStUvWxYz0123456789...
|
||||||
```
|
```
|
||||||
|
|
||||||
2. Update docker-compose.yml with **single-quoted hash**:
|
2. Store hash in `.env` file with `$$` escaping:
|
||||||
```yaml
|
```bash
|
||||||
- USERS='jramos:$2b$05$AbCdEfGhIjKlMnOpQrStUvWxYz0123456789...'
|
USERS=jramos:$$2y$$05$$AbCdEfGhIjKlMnOpQrStUvWxYz0123456789...
|
||||||
```
|
```
|
||||||
|
|
||||||
3. Restart container:
|
3. Restart container:
|
||||||
@@ -247,22 +266,79 @@ docker-compose down
|
|||||||
docker-compose up -d
|
docker-compose up -d
|
||||||
```
|
```
|
||||||
|
|
||||||
**Why Single Quotes Matter**:
|
**Why Bcrypt Hash is Required**:
|
||||||
- `$` has special meaning in shell/YAML double-quoted strings
|
- Security: Bcrypt is computationally expensive, resists brute force attacks
|
||||||
- Single quotes prevent variable expansion and preserve the literal bcrypt hash
|
- Industry Standard: Modern password storage best practice
|
||||||
- Without quotes, the hash will be corrupted during environment variable parsing
|
- One-way Hash: Even if .env is compromised, passwords cannot be reversed
|
||||||
|
|
||||||
**Validation**:
|
**Validation**:
|
||||||
```bash
|
```bash
|
||||||
# Check environment variable is set correctly
|
# Check environment variable is set correctly inside container
|
||||||
docker exec tinyauth env | grep USERS
|
docker exec tinyauth env | grep USERS
|
||||||
# Should show: USERS='jramos:$2b$05$...'
|
# Should show: USERS=jramos:$2y$05$... (single $ inside container)
|
||||||
|
|
||||||
# Test authentication
|
# 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
|
# 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
|
## Access & Credentials
|
||||||
|
|
||||||
### Login URL
|
### Login URL
|
||||||
@@ -276,22 +352,26 @@ curl -u jramos:Nbkx4md007 http://192.168.2.10:8000/api/auth/nginx
|
|||||||
```bash
|
```bash
|
||||||
htpasswd -nbB newuser password123
|
htpasswd -nbB newuser password123
|
||||||
```
|
```
|
||||||
2. Update docker-compose.yml USERS variable (comma-separated for multiple users):
|
2. Update `.env` file with USERS variable (comma-separated for multiple users):
|
||||||
```yaml
|
```bash
|
||||||
- USERS='jramos:$2b$05$...,alice:$2b$05$...,bob:$2b$05$...'
|
USERS=jramos:$$2y$$05$$...,alice:$$2y$$05$$...,bob:$$2y$$05$$...
|
||||||
```
|
```
|
||||||
|
**Remember**: Use `$$` (double dollar signs) to escape `$` in .env files
|
||||||
|
|
||||||
3. Restart container:
|
3. Restart container:
|
||||||
```bash
|
```bash
|
||||||
|
cd /home/jramos/homelab/services/tinyauth
|
||||||
docker-compose down && docker-compose up -d
|
docker-compose down && docker-compose up -d
|
||||||
```
|
```
|
||||||
|
|
||||||
**Changing Passwords**:
|
**Changing Passwords**:
|
||||||
1. Generate new bcrypt hash with new password
|
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
|
3. Restart container
|
||||||
|
|
||||||
**Security Note**: Credentials are stored in docker-compose.yml. For production use, consider:
|
**Security Note**: Credentials are stored in `.env` file. For production use, consider:
|
||||||
- Environment variable injection from secrets management
|
- Set file permissions: `chmod 600 .env`
|
||||||
|
- Environment variable injection from secrets management (Docker Secrets, Vault)
|
||||||
- Integration with LDAP/Active Directory
|
- Integration with LDAP/Active Directory
|
||||||
- Migration to more robust SSO (Authelia, Keycloak)
|
- Migration to more robust SSO (Authelia, Keycloak)
|
||||||
|
|
||||||
@@ -327,7 +407,10 @@ docker-compose restart
|
|||||||
|
|
||||||
### Backup
|
### Backup
|
||||||
```bash
|
```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)
|
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
|
docker pull ghcr.io/steveiliop56/tinyauth:v4
|
||||||
|
|
||||||
# Recreate container with new image
|
# Recreate container with new image
|
||||||
|
cd /home/jramos/homelab/services/tinyauth
|
||||||
docker-compose down
|
docker-compose down
|
||||||
docker-compose pull
|
docker-compose pull
|
||||||
docker-compose up -d
|
docker-compose up -d
|
||||||
@@ -357,21 +441,28 @@ docker logs nginx-proxy-manager | grep tinyauth
|
|||||||
curl -I https://tinyauth.apophisnetworking.net
|
curl -I https://tinyauth.apophisnetworking.net
|
||||||
```
|
```
|
||||||
|
|
||||||
### Symptoms: "Invalid password" error
|
### Symptoms: "Invalid password" or "User not found" error
|
||||||
|
|
||||||
**Check**:
|
**Check**:
|
||||||
1. USERS environment variable uses bcrypt hash: `docker exec tinyauth env | grep USERS`
|
1. `.env` file exists in same directory as docker-compose.yml
|
||||||
2. Hash is single-quoted in docker-compose.yml
|
2. USERS environment variable uses bcrypt hash with `$$` escaping in .env: `cat .env`
|
||||||
3. Password hasn't changed since hash generation
|
3. Hash is correctly loaded inside container: `docker exec tinyauth env | grep USERS`
|
||||||
4. Account isn't locked (wait 5 minutes after 5 failed attempts)
|
4. Password hasn't changed since hash generation
|
||||||
|
5. Account isn't locked (wait 5 minutes after 5 failed attempts)
|
||||||
|
|
||||||
**Commands**:
|
**Commands**:
|
||||||
```bash
|
```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
|
docker exec tinyauth env | grep USERS
|
||||||
|
# Should show: USERS=jramos:$2y$05$... (single $ inside container)
|
||||||
|
|
||||||
# Test authentication directly
|
# 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"
|
### 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)
|
✅ No database dependencies (reduces vulnerability vectors)
|
||||||
|
|
||||||
### Weaknesses & Mitigations
|
### Weaknesses & Mitigations
|
||||||
⚠️ **Credentials in docker-compose.yml**: Ensure file permissions restrict read access
|
⚠️ **Credentials in .env file**: Ensure file permissions restrict read access
|
||||||
- Mitigation: `chmod 600 docker-compose.yml`
|
- Mitigation: `chmod 600 .env`
|
||||||
- Future: Migrate to secrets management (Docker Secrets, Vault)
|
- Future: Migrate to secrets management (Docker Secrets, Vault)
|
||||||
|
|
||||||
⚠️ **No MFA**: Single-factor authentication only
|
⚠️ **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
|
### Recommended Hardening
|
||||||
1. **File Permissions**:
|
1. **File Permissions**:
|
||||||
```bash
|
```bash
|
||||||
|
chmod 600 /home/jramos/homelab/services/tinyauth/.env
|
||||||
chmod 600 /home/jramos/homelab/services/tinyauth/docker-compose.yml
|
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**:
|
4. **Log Monitoring**:
|
||||||
- Configure alerts for repeated authentication failures
|
- Configure alerts for repeated authentication failures
|
||||||
- Forward logs to Loki (CT 101 - monitoring stack)
|
- Forward logs to Loki (VM 101 - monitoring stack)
|
||||||
|
|
||||||
## Future Enhancements
|
## Future Enhancements
|
||||||
|
|
||||||
@@ -468,7 +560,7 @@ curl -u jramos:Nbkx4md007 http://192.168.2.10:8000/api/auth/nginx
|
|||||||
|
|
||||||
### Medium-Term
|
### Medium-Term
|
||||||
- [ ] Extend authentication to Proxmox web UI (if supported by TinyAuth)
|
- [ ] 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
|
- [ ] Explore TinyAuth API for programmatic user management
|
||||||
|
|
||||||
### Long-Term
|
### Long-Term
|
||||||
@@ -489,4 +581,4 @@ curl -u jramos:Nbkx4md007 http://192.168.2.10:8000/api/auth/nginx
|
|||||||
|
|
||||||
**Maintained by**: Homelab Infrastructure Team
|
**Maintained by**: Homelab Infrastructure Team
|
||||||
**Last Updated**: 2025-12-18
|
**Last Updated**: 2025-12-18
|
||||||
**Status**: ✅ Operational - Protecting NetBox with SSO authentication
|
**Status**: ✅ Operational - User authentication working with .env configuration
|
||||||
|
|||||||
Reference in New Issue
Block a user