Services/Mealie
As of: 2026-07-05 — migrated from `services/MEALIE.md`
Mealie — Recipe Manager
Complete setup & operations guide for Mealie (recipe management app) with Authentik OAuth integration.
Overview
Mealie is a self-hosted recipe management app. We run it on Stronghold with:
- Authentik OAuth2 for user authentication
- Group-based access control (admin vs user roles)
- HTTPS via Cloudflare (cook.wilsoz.com)
- Persistent data storage in Docker volume
Current Users: marcus (admin via Authentik) Access: https://cook.wilsoz.com
Service Information
| Property | Value |
|---|---|
| URL | https://cook.wilsoz.com |
| Container name | mealie |
| Compose file | /library/mealie-app/docker-compose.yml
|
| Data volume | mealie-app_mealie-data:/app/data
|
| Internal port | 9000 |
| Host port | 9925 |
| Network | mealie-app_mealie (MTU 1280)
|
| Image | ghcr.io/mealie-recipes/mealie:latest
|
Initial Setup from Scratch
1. Create Directory & Files
<syntaxhighlight lang="bash"> mkdir -p /library/mealie-app cd /library/mealie-app </syntaxhighlight>
2. Create docker-compose.yml
<syntaxhighlight lang="yaml"> version: "3.8" services:
mealie:
image: ghcr.io/mealie-recipes/mealie:latest
container_name: mealie
restart: unless-stopped
env_file:
- .env
volumes:
- mealie-data:/app/data
ports:
- "9925:9000"
networks:
- mealie
volumes:
mealie-data:
networks:
mealie:
driver: bridge
driver_opts:
com.docker.network.driver.mtu: 1280
</syntaxhighlight>
3. Create .env File
<syntaxhighlight lang="bash">
- App Configuration
PUID=1000 PGID=1000 TZ=America/Chicago BASE_URL=https://cook.wilsoz.com ALLOW_SIGNUP=false
- OIDC Authentication (Authentik)
OIDC_AUTH_ENABLED=true OIDC_PROVIDER_NAME=Authentik OIDC_CONFIGURATION_URL=https://key.wilsoz.com/application/o/mealie/.well-known/openid-configuration OIDC_CLIENT_ID=3fUfT5FALoAqvWHzqiD0eLNYKd3fsyYjdUkEUVy5 OIDC_CLIENT_SECRET=D5IbtoxMgx6Kkmry296bXUz6G3NcvzT70wIBrr7RFu8 OIDC_SIGNUP_ENABLED=true OIDC_AUTO_REDIRECT=false OIDC_USER_GROUP=family-and-friends OIDC_ADMIN_GROUP=authentik Admins OIDC_GROUPS_CLAIM=groups OIDC_USER_CLAIM=email OIDC_NAME_CLAIM=name </syntaxhighlight>
4. Set Up Authentik OAuth Provider
Create OAuth2 Provider in Authentik
- Go to https://key.wilsoz.com/if/admin/
- Applications → Providers → Create OAuth2/OpenID Provider
- Fill in:
Name:** mealie-oauth Authorization flow:** (default-authentication-flow) Client type:** Confidential Redirect URIs:** (one per line)
```
https://cook.wilsoz.com/login
https://cook.wilsoz.com/login?direct=1
```
- Save — note the Client ID and Client Secret
Configure Provider: Signing Key
⚠️ CRITICAL: Assign the signing key or JWKS endpoint will return {} and OAuth will fail.
<syntaxhighlight lang="bash"> docker exec authentik-app_server_1 ak shell -c " from authentik.providers.oauth2.models import OAuth2Provider from authentik.crypto.models import CertificateKeyPair
p = OAuth2Provider.objects.get(name='mealie-oauth') jwt_key = CertificateKeyPair.objects.get(name='authentik Internal JWT Certificate') p.signing_key = jwt_key p.save() print('Assigned JWT Certificate signing key') " </syntaxhighlight>
Why JWT Certificate?
- Uses HS256 algorithm (Mealie's OIDC library supports it)
- Self-signed Certificate uses RS256 (rejected by Mealie)
Configure Provider: Property Mappings
Add OAuth scope property mappings:
<syntaxhighlight lang="bash"> docker exec authentik-app_server_1 ak shell -c " from authentik.providers.oauth2.models import OAuth2Provider from authentik.core.models import PropertyMapping
p = OAuth2Provider.objects.get(name='mealie-oauth') email_pm = PropertyMapping.objects.get(name='authentik default OAuth Mapping: OpenID \\'email\\) profile_pm = PropertyMapping.objects.get(name='authentik default OAuth Mapping: OpenID \\'profile\\) openid_pm = PropertyMapping.objects.get(name='authentik default OAuth Mapping: OpenID \\'openid\\)
p.property_mappings.add(email_pm, profile_pm, openid_pm) p.include_claims_in_id_token = True p.save() print('Added property mappings and enabled claims in ID token') " </syntaxhighlight>
Create Application in Authentik
- Go to Applications → Applications → Create
- Fill in:
Name:** Mealie Slug:** mealie Provider:** mealie-oauth (select from dropdown) Authorization flow:** default-authorization-flow
- Save
5. Start Mealie
<syntaxhighlight lang="bash"> cd /library/mealie-app docker compose up -d </syntaxhighlight>
Wait ~10 seconds for startup, then check:
<syntaxhighlight lang="bash"> docker logs mealie --tail=20
- Should show: "Application startup complete"
- And: "Enabled: True" under the OIDC section
</syntaxhighlight>
6. Configure VPS Nginx Proxy
On VPS, add server block to nginx config (or update if exists):
<syntaxhighlight lang="nginx"> server {
listen 443 ssl http2; server_name cook.wilsoz.com;
ssl_certificate /etc/letsencrypt/live/cook.wilsoz.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/cook.wilsoz.com/privkey.pem;
location / {
proxy_pass http://100.64.207.155:9925;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
}
} </syntaxhighlight>
Then:
<syntaxhighlight lang="bash"> sudo systemctl reload nginx </syntaxhighlight>
7. Create First Admin User (In-App)
- Navigate to https://cook.wilsoz.com
- You'll see the login page with "Authentik" button
- If Mealie is brand new with no users, it may show an initial setup screen
- Use Authentik to log in with an account in the authentik Admins group
- This account gets Mealie admin role automatically
Operations
Start/Stop/Restart
<syntaxhighlight lang="bash"> cd /library/mealie-app
- Start
docker compose up -d
- Stop
docker compose down
- Restart
docker compose restart mealie
- Full restart (clears cached config)
docker compose down && sleep 2 && docker compose up -d </syntaxhighlight>
View Logs
<syntaxhighlight lang="bash">
- Live logs
docker logs -f mealie
- Last 50 lines
docker logs mealie --tail=50
- Filter for errors
docker logs mealie 2>&1 | grep -i "error\|exception"
- Filter for OIDC
docker logs mealie 2>&1 | grep -i "oidc" </syntaxhighlight>
Reset Admin Password (Database)
If you lose the admin password:
<syntaxhighlight lang="bash"> docker exec mealie python3 -c " import sqlite3 import bcrypt
db = sqlite3.connect('/app/data/mealie.db') cursor = db.cursor()
- Set new password for marcus
new_password = 'TempPassword123456!' salt = bcrypt.gensalt(rounds=10) hashed = bcrypt.hashpw(new_password.encode('utf-8'), salt).decode('utf-8')
cursor.execute('UPDATE users SET password = ? WHERE username = ?', (hashed, 'marcus')) db.commit() print(f'Password reset to: {new_password}') db.close() " </syntaxhighlight>
Then log in and change it in Mealie settings.
Manage Users & Groups
Via Authentik:
- Users must be added to Authentik first
- Create/manage groups: Directory → Groups
- Add users to groups for role assignment
Via Mealie:
- Settings → Users — shows Mealie users (created on first OAuth login)
- User roles are determined by Authentik group membership:
authentik Admins** → Mealie admin family-and-friends** → Mealie user
Configuration Reference
Environment Variables (.env)
| Variable | Purpose | Example |
|---|---|---|
BASE_URL
|
External URL for Mealie | https://cook.wilsoz.com
|
ALLOW_SIGNUP
|
Allow registration without OIDC | false
|
OIDC_AUTH_ENABLED
|
Enable OAuth login | true
|
OIDC_CLIENT_ID
|
Authentik provider client ID | (from Authentik) |
OIDC_CLIENT_SECRET
|
Authentik provider secret | (from Authentik) |
OIDC_CONFIGURATION_URL
|
OIDC discovery endpoint | https://key.wilsoz.com/application/o/mealie/.well-known/openid-configuration
|
OIDC_USER_GROUP
|
Authentik group for regular users | family-and-friends
|
OIDC_ADMIN_GROUP
|
Authentik group for admins | authentik Admins
|
OIDC_GROUPS_CLAIM
|
OIDC claim name for groups | groups
|
OIDC_SIGNUP_ENABLED
|
Auto-create users on first OIDC login | true
|
OIDC_AUTO_REDIRECT
|
Skip login page, go straight to Authentik | false
|
TZ
|
Timezone | America/Chicago
|
PUID / PGID
|
Linux user/group for file permissions | 1000
|
Data & Backups
Data Location
<syntaxhighlight lang="text"> /library/mealie-app/mealie-data:/app/data
Contents: - mealie.db (SQLite database — all recipes, users, settings) - recipes/ (recipe files) - users/ (user data) - backups/ (exported recipe backups) - templates/ (custom templates) - groups/ (group/household data) </syntaxhighlight>
Backup Procedure
<syntaxhighlight lang="bash">
- Backup the entire data volume
docker run --rm \
-v mealie-app_mealie-data:/data \ -v /home/mnw/backups:/backup \ ubuntu tar czf /backup/mealie-$(date +%Y%m%d).tar.gz /data
- List backups
ls -lh /home/mnw/backups/mealie-*.tar.gz </syntaxhighlight>
Restore from Backup
<syntaxhighlight lang="bash">
- Stop Mealie
cd /library/mealie-app && docker compose down
- Restore data
docker run --rm \
-v mealie-app_mealie-data:/data \ -v /home/mnw/backups:/backup \ ubuntu bash -c "rm -rf /data/* && tar xzf /backup/mealie-20260513.tar.gz -C /data"
- Restart
docker compose up -d </syntaxhighlight>
Troubleshooting
Login Issues
"Something went wrong" on OAuth callback
Symptoms:
- Authentik login succeeds, but Mealie shows error when redirected back
Common causes & fixes:
| Error | Cause | Fix |
|---|---|---|
KeyError: 'keys'
|
JWKS endpoint returns {}
|
Assign signing key to OAuth provider (see Setup step 4) |
UnsupportedAlgorithmError: RS256 not allowed
|
Wrong signing key algorithm | Use "authentik Internal JWT Certificate" (HS256), not "Self-signed Certificate" (RS256) |
invalid_client: Client authentication failed
|
Client secret mismatch | Verify OIDC_CLIENT_SECRET in .env matches Authentik provider
|
HTTP 500 at /api/auth/oauth/callback
|
Mealie can't reach Authentik's token endpoint | Check network connectivity, SSL certificates, DNS |
Debug steps:
<syntaxhighlight lang="bash">
- Check OIDC config is loaded
docker logs mealie | grep -i "oidc\|enabled"
- Test discovery endpoint
docker exec mealie curl -s "https://key.wilsoz.com/application/o/mealie/.well-known/openid-configuration" -k | jq .
- Check JWKS endpoint has keys
docker exec mealie curl -s "https://key.wilsoz.com/application/o/mealie/jwks/" -k | jq '.keys | length'
- View OAuth errors
docker logs mealie --tail=100 | grep -i "oauth\|error\|exception" | tail -20 </syntaxhighlight>
"OIDC not appearing on login page"
- Verify
OIDC_AUTH_ENABLED=truein.env - Restart container:
docker compose down && docker compose up -d - Check logs for startup errors
"Redirect URI mismatch" error
- Ensure Authentik provider redirect URIs match exactly:
- Verify
BASE_URL=https://cook.wilsoz.comin.env - No trailing slashes or port numbers
User not getting admin role
- Confirm user is in authentik Admins group (Directory → Groups)
- Log out and log back in (roles are assigned at login time)
- Check Mealie Settings → Users to see assigned role
Performance
Slow startup
Mealie can take 30-60 seconds on first start or after upgrade. Check:
<syntaxhighlight lang="bash"> docker logs mealie | tail -20
- Look for "Application startup complete"
</syntaxhighlight>
High memory usage
Default image is fine for small recipe collections. For very large:
- Monitor:
docker stats mealie - Limit: Add
mem_limit: 2gto compose file if needed
Network Issues
Can't access https://cook.wilsoz.com
- Check VPS nginx config (see Setup step 6)
- Verify SSL cert is valid:
curl -I https://cook.wilsoz.com - Check Mealie is running:
docker ps | grep mealie - Check port:
netstat -tlnp | grep 9925
Mealie can't reach Authentik (key.wilsoz.com)
From Mealie container:
<syntaxhighlight lang="bash"> docker exec mealie curl -v https://key.wilsoz.com/api/v3/ -k
- Should return 401 (not accessible, but shouldn't timeout)
docker exec mealie ping -c 1 key.wilsoz.com
- Should succeed
</syntaxhighlight>
Security Notes
- OIDC_CLIENT_SECRET: Store securely in
.env, never commit to git - Database:
/app/data/mealie.dbcontains all user data — protect with filesystem permissions - Backups: Backup volume includes full database — encrypt backups if stored externally
- User signup:
ALLOW_SIGNUP=falsemeans only Authentik users can access (good) - Groups: Ensure only trusted users are in
authentik Adminsgroup
Links & References
- Mealie Docs: https://nightly.mealie.io/
- Mealie GitHub: https://github.com/mealie-recipes/mealie
- Authentik OIDC: https://goauthentik.io/docs/providers/oauth2
- Mealie OIDC Integration Guide: https://integrations.goauthentik.io/documentation/mealie/
Related Services
- Authentik (auth):
/library/authentik-app/— OAuth provider - Nginx (proxy): VPS
/etc/nginx/sites-available/— external access - Backups:
/home/mnw/backups/— data snapshots