Compare commits
2 Commits
846ab74f87
...
bfd6f22f0e
| Author | SHA1 | Date | |
|---|---|---|---|
| bfd6f22f0e | |||
| 89b43180fc |
307
docs/vaultwarden-sso-status.md
Normal file
307
docs/vaultwarden-sso-status.md
Normal file
@@ -0,0 +1,307 @@
|
||||
# Vaultwarden SSO Feature Status and Configuration
|
||||
|
||||
**Document Date:** December 21, 2025
|
||||
**Last Updated:** December 21, 2025
|
||||
**Status:** SSO Configured, Waiting for Stable Release
|
||||
|
||||
---
|
||||
|
||||
## Executive Summary
|
||||
|
||||
Vaultwarden has been successfully deployed with **SSO integration pre-configured** for Authentik. However, SSO functionality is currently **only available in testing images** and not yet in the stable release. This document explains the current state, our decision to wait for stable, and how to activate SSO when it becomes available.
|
||||
|
||||
## Current Deployment Status
|
||||
|
||||
### What's Working
|
||||
- ✅ Vaultwarden deployed successfully at `https://vault.jnss.me`
|
||||
- ✅ PostgreSQL backend via Unix socket
|
||||
- ✅ Admin panel accessible and working
|
||||
- ✅ Email/password authentication working
|
||||
- ✅ SMTP notifications configured
|
||||
- ✅ All SSO environment variables correctly configured
|
||||
- ✅ Authentik OAuth2 provider created and ready
|
||||
|
||||
### What's Not Working (By Design)
|
||||
- ❌ SSO login option not appearing on login page
|
||||
- ❌ "Use single sign-on" button missing
|
||||
|
||||
**Reason:** Using stable image (`vaultwarden/server:latest` v1.34.3) which does not include SSO code.
|
||||
|
||||
## Investigation Summary (Dec 21, 2025)
|
||||
|
||||
### Problem Reported
|
||||
User deployed Vaultwarden with `vaultwarden_sso_enabled: true` and configured Authentik integration following official guides, but no SSO option appeared on the login page.
|
||||
|
||||
### Root Cause Identified
|
||||
After investigation including:
|
||||
- Service status check (healthy, running normally)
|
||||
- Environment variable verification (all SSO vars present and correct)
|
||||
- Configuration review (matches Authentik integration guide perfectly)
|
||||
- API endpoint inspection (`/api/config` returns `"sso":""`)
|
||||
- Official documentation review
|
||||
|
||||
**Finding:** SSO feature is only compiled into `vaultwarden/server:testing` images, not stable releases.
|
||||
|
||||
### Evidence
|
||||
|
||||
From [Vaultwarden Official Wiki](https://github.com/dani-garcia/vaultwarden/wiki):
|
||||
|
||||
> **Testing features**
|
||||
>
|
||||
> Features available in the `testing` docker image:
|
||||
> - Single Sign-On (SSO), see [Documentation](https://github.com/dani-garcia/vaultwarden/wiki/Enabling-SSO-support-using-OpenId-Connect)
|
||||
|
||||
From [SSO Documentation Page](https://github.com/dani-garcia/vaultwarden/wiki/Enabling-SSO-support-using-OpenId-Connect):
|
||||
|
||||
> ⚠️ **Important**
|
||||
>
|
||||
> ‼️ ‼️ ‼️
|
||||
> SSO is currently only available in the `:testing` tagged images!
|
||||
> The current stable `v1.34.3` **does not** contain the SSO feature.
|
||||
> ‼️ ‼️ ‼️
|
||||
|
||||
### API Response Analysis
|
||||
|
||||
```bash
|
||||
# API config endpoint shows SSO not available
|
||||
curl -s http://127.0.0.1:8080/api/config | grep -o '"sso":"[^"]*"'
|
||||
# Returns: "sso":"" ← Empty = feature not compiled in
|
||||
|
||||
# Environment variables are set correctly
|
||||
podman exec vaultwarden env | grep -i sso
|
||||
SSO_ENABLED=true
|
||||
SSO_ONLY=false
|
||||
SSO_CLIENT_ID=DDOQXdwFn6pi4FtSvo7PK5b63pRzyD552xapTZGr
|
||||
SSO_CLIENT_SECRET=02D308Sle2w2NPsi7UaXb3bvKKK4punFDT2LiVqKpzvEFqgPpyLysA8Z5yS4g8t4LYmsI9txLE02l5MtWP5R2RBavLhYHjNFHcwEmvYB94bOJw45YmgiGePaW4NHKcfY
|
||||
SSO_AUTHORITY=https://auth.jnss.me/application/o/vaultwarden/
|
||||
SSO_SCOPES="openid email profile offline_access"
|
||||
# ... etc (all correct)
|
||||
```
|
||||
|
||||
**Conclusion:** Environment configured correctly, feature simply not available in stable release.
|
||||
|
||||
## Decision: Wait for Stable Release
|
||||
|
||||
### Rationale
|
||||
|
||||
**Why NOT switch to testing image:**
|
||||
1. **Production stability** - This is a password manager handling sensitive credentials
|
||||
2. **Testing images are volatile** - Frequent updates, potential bugs
|
||||
3. **No ETA for stable** - SSO marked as "testing feature" indefinitely
|
||||
4. **Current auth works fine** - Email/password login is secure and functional
|
||||
5. **Configuration is ready** - When SSO reaches stable, it will work immediately
|
||||
|
||||
**Why keep SSO configured:**
|
||||
1. **Future-ready** - No additional work needed when SSO stabilizes
|
||||
2. **No harm** - Environment variables are ignored by stable image
|
||||
3. **Documentation** - Clear record of SSO setup for future reference
|
||||
4. **Authentik provider ready** - Already created and configured
|
||||
|
||||
### Alternatives Considered
|
||||
|
||||
| Option | Pros | Cons | Decision |
|
||||
|--------|------|------|----------|
|
||||
| Use `testing` image | SSO available now | Unstable, potential data loss, frequent breaking changes | ❌ Rejected |
|
||||
| Wait for stable | Stable, reliable, secure | No SSO until unknown future date | ✅ **Selected** |
|
||||
| Remove SSO config | Cleaner config | Requires reconfiguration later | ❌ Rejected |
|
||||
| Dual deployment | Test SSO separately | Resource waste, complexity | ❌ Rejected |
|
||||
|
||||
## Current Configuration
|
||||
|
||||
### Ansible Role Variables
|
||||
|
||||
Location: `roles/vaultwarden/defaults/main.yml`
|
||||
|
||||
```yaml
|
||||
# Container version (stable, no SSO)
|
||||
vaultwarden_version: "latest"
|
||||
|
||||
# SSO enabled (ready for when feature reaches stable)
|
||||
vaultwarden_sso_enabled: true
|
||||
vaultwarden_sso_only: false
|
||||
vaultwarden_sso_client_id: "{{ vault_vaultwarden_sso_client_id }}"
|
||||
vaultwarden_sso_client_secret: "{{ vault_vaultwarden_sso_client_secret }}"
|
||||
vaultwarden_sso_authority: "https://auth.jnss.me/application/o/vaultwarden/"
|
||||
vaultwarden_sso_scopes: "openid email profile offline_access"
|
||||
vaultwarden_sso_signups_match_email: true
|
||||
vaultwarden_sso_allow_unknown_email_verification: false
|
||||
vaultwarden_sso_client_cache_expiration: 0
|
||||
```
|
||||
|
||||
### Vault Variables (Encrypted)
|
||||
|
||||
Location: `group_vars/homelab/vault.yml`
|
||||
|
||||
```yaml
|
||||
# SSO credentials from Authentik
|
||||
vault_vaultwarden_sso_client_id: "DDOQXdwFn6pi4FtSvo7PK5b63pRzyD552xapTZGr"
|
||||
vault_vaultwarden_sso_client_secret: "02D308Sle2w2NPsi7UaXb3bvKKK4punFDT2LiVqKpzvEFqgPpyLysA8Z5yS4g8t4LYmsI9txLE02l5MtWP5R2RBavLhYHjNFHcwEmvYB94bOJw45YmgiGePaW4NHKcfY"
|
||||
```
|
||||
|
||||
### Authentik Provider Configuration
|
||||
|
||||
**Provider Details:**
|
||||
- **Name:** Vaultwarden
|
||||
- **Type:** OAuth2/OpenID Connect Provider
|
||||
- **Client Type:** Confidential
|
||||
- **Client ID:** `DDOQXdwFn6pi4FtSvo7PK5b63pRzyD552xapTZGr`
|
||||
- **Application Slug:** `vaultwarden`
|
||||
- **Redirect URI:** `https://vault.jnss.me/identity/connect/oidc-signin`
|
||||
|
||||
**Scopes Configured:**
|
||||
- ✅ `authentik default OAuth Mapping: OpenID 'openid'`
|
||||
- ✅ `authentik default OAuth Mapping: OpenID 'email'`
|
||||
- ✅ `authentik default OAuth Mapping: OpenID 'profile'`
|
||||
- ✅ `authentik default OAuth Mapping: OpenID 'offline_access'`
|
||||
|
||||
**Token Settings:**
|
||||
- Access token validity: > 5 minutes
|
||||
- Refresh token enabled via `offline_access` scope
|
||||
|
||||
**Authority URL:** `https://auth.jnss.me/application/o/vaultwarden/`
|
||||
|
||||
### Deployed Environment (VPS)
|
||||
|
||||
```bash
|
||||
# Deployed environment file
|
||||
Location: /opt/vaultwarden/.env
|
||||
|
||||
# All SSO variables present and correct
|
||||
SSO_ENABLED=true
|
||||
SSO_AUTHORITY=https://auth.jnss.me/application/o/vaultwarden/
|
||||
SSO_SCOPES="openid email profile offline_access"
|
||||
# ... etc
|
||||
```
|
||||
|
||||
## How to Activate SSO (Future)
|
||||
|
||||
When Vaultwarden SSO reaches stable release:
|
||||
|
||||
### Automatic Activation (Recommended)
|
||||
|
||||
1. **Monitor Vaultwarden releases** for SSO in stable:
|
||||
- Watch: https://github.com/dani-garcia/vaultwarden/releases
|
||||
- Look for: SSO feature in stable image changelog
|
||||
|
||||
2. **Update container** (standard maintenance):
|
||||
```bash
|
||||
ansible-playbook rick-infra.yml --tags vaultwarden --ask-vault-pass
|
||||
```
|
||||
|
||||
3. **Verify SSO is available**:
|
||||
```bash
|
||||
ssh root@69.62.119.31 "curl -s http://127.0.0.1:8080/api/config | grep sso"
|
||||
# Should return: "sso":"https://vault.jnss.me" or similar
|
||||
```
|
||||
|
||||
4. **Test SSO**:
|
||||
- Navigate to: https://vault.jnss.me
|
||||
- Log out if logged in
|
||||
- Enter verified email address
|
||||
- Click "Use single sign-on" button
|
||||
- Should redirect to Authentik login
|
||||
|
||||
**No configuration changes needed** - Everything is already set up correctly.
|
||||
|
||||
### Manual Testing (Use Testing Image)
|
||||
|
||||
If you want to test SSO before stable release:
|
||||
|
||||
1. **Backup current deployment**:
|
||||
```bash
|
||||
ansible-playbook playbooks/backup-vaultwarden.yml # Create if needed
|
||||
```
|
||||
|
||||
2. **Change to testing image** in `roles/vaultwarden/defaults/main.yml`:
|
||||
```yaml
|
||||
vaultwarden_version: "testing"
|
||||
```
|
||||
|
||||
3. **Deploy**:
|
||||
```bash
|
||||
ansible-playbook rick-infra.yml --tags vaultwarden --ask-vault-pass
|
||||
```
|
||||
|
||||
4. **Test SSO** (same as above)
|
||||
|
||||
5. **Revert to stable** when testing complete:
|
||||
```yaml
|
||||
vaultwarden_version: "latest"
|
||||
```
|
||||
|
||||
**Warning:** Testing images may contain bugs, data corruption risks, or breaking changes. Not recommended for production password manager.
|
||||
|
||||
## Verification Commands
|
||||
|
||||
### Check Current Image Version
|
||||
```bash
|
||||
ssh root@69.62.119.31 "podman inspect vaultwarden --format '{{.ImageName}}'"
|
||||
# Expected: docker.io/vaultwarden/server:latest
|
||||
```
|
||||
|
||||
### Check SSO API Status
|
||||
```bash
|
||||
ssh root@69.62.119.31 "curl -s http://127.0.0.1:8080/api/config | grep -o '\"sso\":\"[^\"]*\"'"
|
||||
# Current: "sso":"" (empty = not available)
|
||||
# Future: "sso":"https://vault.jnss.me" (URL = available)
|
||||
```
|
||||
|
||||
### Check SSO Environment Variables
|
||||
```bash
|
||||
ssh root@69.62.119.31 "podman exec vaultwarden env | grep -i sso | sort"
|
||||
# Should show all SSO_* variables configured correctly
|
||||
```
|
||||
|
||||
### Check Vaultwarden Version
|
||||
```bash
|
||||
ssh root@69.62.119.31 "podman exec vaultwarden /vaultwarden --version"
|
||||
# Current: Vaultwarden 1.34.3
|
||||
```
|
||||
|
||||
## Documentation Updates
|
||||
|
||||
The following files have been updated to document this finding:
|
||||
|
||||
1. **`roles/vaultwarden/README.md`**
|
||||
- Added warning banner in SSO configuration section
|
||||
- Updated troubleshooting section with SSO status checks
|
||||
- Documented stable vs testing image behavior
|
||||
|
||||
2. **`roles/vaultwarden/VAULT_VARIABLES.md`**
|
||||
- Added SSO feature status warning
|
||||
- Documented that credentials are ready but inactive
|
||||
|
||||
3. **`roles/vaultwarden/defaults/main.yml`**
|
||||
- Added comments explaining SSO availability
|
||||
|
||||
4. **`docs/vaultwarden-sso-status.md`** (this document)
|
||||
- Complete investigation findings
|
||||
- Configuration reference
|
||||
- Activation procedures
|
||||
|
||||
## Timeline
|
||||
|
||||
- **2025-07-30:** Vaultwarden v1.34.3 released (current stable)
|
||||
- **2025-12-21:** Vaultwarden deployed with SSO pre-configured
|
||||
- **2025-12-21:** Investigation completed, SSO status documented
|
||||
- **TBD:** SSO feature reaches stable release (no ETA)
|
||||
- **Future:** Automatic SSO activation on next deployment
|
||||
|
||||
## Related Documentation
|
||||
|
||||
- [Vaultwarden Official Wiki](https://github.com/dani-garcia/vaultwarden/wiki)
|
||||
- [SSO Documentation](https://github.com/dani-garcia/vaultwarden/wiki/Enabling-SSO-support-using-OpenId-Connect)
|
||||
- [Authentik Integration Guide](https://integrations.goauthentik.io/security/vaultwarden/)
|
||||
- [Vaultwarden Testing Features](https://github.com/dani-garcia/vaultwarden/wiki#testing-features)
|
||||
|
||||
## Contact
|
||||
|
||||
For questions about this deployment:
|
||||
- Infrastructure repo: `/home/fitz/rick-infra`
|
||||
- Role location: `roles/vaultwarden/`
|
||||
- Service: `vault.jnss.me`
|
||||
- Host: `arch-vps` (69.62.119.31)
|
||||
|
||||
---
|
||||
|
||||
**Status:** SSO configured and ready, waiting for upstream stable release. No action required.
|
||||
@@ -65,7 +65,8 @@ nextcloud_db_password: "{{ vault_nextcloud_db_password }}"
|
||||
nextcloud_valkey_db: 2 # Authentik uses 1
|
||||
|
||||
# Admin configuration
|
||||
nextcloud_admin_user: "admin"
|
||||
nextcloud_admin_user: "joakim"
|
||||
nextcloud_admin_email: "joakim@jnss.me"
|
||||
nextcloud_admin_password: "{{ vault_nextcloud_admin_password }}"
|
||||
|
||||
# Service configuration
|
||||
|
||||
@@ -63,15 +63,6 @@
|
||||
changed_when: container_remove.rc == 0
|
||||
failed_when: false
|
||||
|
||||
- name: Remove nextcloud images
|
||||
command: podman rmi -f {{ item }}
|
||||
loop:
|
||||
- docker.io/library/nextcloud:stable-fpm
|
||||
- docker.io/library/nextcloud
|
||||
register: image_remove
|
||||
changed_when: image_remove.rc == 0
|
||||
failed_when: false
|
||||
|
||||
# ============================================
|
||||
# Remove Systemd Units
|
||||
# ============================================
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
# - Nextcloud cloud storage
|
||||
# - Authentik SSO/authentication
|
||||
# - Gitea git hosting
|
||||
# - Vaultwarden password manager
|
||||
#
|
||||
# Usage:
|
||||
# ansible-playbook playbooks/homelab.yml
|
||||
@@ -30,8 +31,13 @@
|
||||
# name: gitea
|
||||
# tags: ['gitea', 'git', 'development']
|
||||
|
||||
- name: Deploy Nextcloud
|
||||
include_role:
|
||||
name: nextcloud
|
||||
tags: ['nextcloud', 'cloud', 'storage']
|
||||
# - name: Deploy Nextcloud
|
||||
# include_role:
|
||||
# name: nextcloud
|
||||
# tags: ['nextcloud', 'cloud', 'storage']
|
||||
|
||||
- name: Deploy Vaultwarden
|
||||
include_role:
|
||||
name: vaultwarden
|
||||
tags: ['vaultwarden', 'vault', 'password-manager', 'security']
|
||||
|
||||
|
||||
@@ -52,9 +52,17 @@ See `defaults/main.yml` for all configurable variables.
|
||||
Define these in your `host_vars/` with `ansible-vault`:
|
||||
|
||||
```yaml
|
||||
# Core credentials (required)
|
||||
vault_nextcloud_db_password: "secure-database-password"
|
||||
vault_nextcloud_admin_password: "secure-admin-password"
|
||||
vault_valkey_password: "secure-valkey-password"
|
||||
|
||||
# Email credentials (optional - only if email enabled)
|
||||
vault_nextcloud_smtp_password: "secure-smtp-password"
|
||||
|
||||
# OIDC credentials (optional - only if OIDC enabled)
|
||||
vault_nextcloud_oidc_client_id: "nextcloud-client-id-from-authentik"
|
||||
vault_nextcloud_oidc_client_secret: "nextcloud-client-secret-from-authentik"
|
||||
```
|
||||
|
||||
### Key Variables
|
||||
@@ -91,27 +99,449 @@ This role uses a **two-phase deployment** approach to work correctly with the Ne
|
||||
6. Container runs `occ maintenance:install` with PostgreSQL
|
||||
7. Installation creates `config.php` with database credentials
|
||||
|
||||
### Phase 2: Custom Configuration (automatic)
|
||||
### Phase 2: Configuration via OCC Script (automatic)
|
||||
8. Ansible waits for `occ status` to report `installed: true`
|
||||
9. Ansible deploys custom `redis.config.php` (overwrites default)
|
||||
10. Container restart applies custom configuration
|
||||
9. Ansible deploys and runs configuration script inside container
|
||||
10. Script configures system settings via OCC commands:
|
||||
- Redis caching (without sessions)
|
||||
- Maintenance window and phone region
|
||||
- Database optimizations (indices, bigint, mimetypes)
|
||||
|
||||
**Why this order?**
|
||||
|
||||
The Nextcloud container's entrypoint uses `version.php` as a marker to determine if installation is needed. If you deploy any files into `/opt/nextcloud/config/` before the container starts, the initialization process fails:
|
||||
The Nextcloud container's entrypoint uses `version.php` as a marker to determine if installation is needed. We must wait for the container's auto-installation to complete before running configuration commands:
|
||||
|
||||
- Container copies files including `version.php`
|
||||
- Entrypoint sees `version.php` exists → assumes already installed
|
||||
- Skips running `occ maintenance:install`
|
||||
- Result: Empty `config.php`, 503 errors
|
||||
- Container must complete first-time setup (copy files, run `occ maintenance:install`)
|
||||
- OCC commands require a fully initialized Nextcloud installation
|
||||
- Running configuration after installation avoids conflicts with the entrypoint script
|
||||
|
||||
By deploying custom configs **after** installation completes, we:
|
||||
- ✅ Allow the container's auto-installation to run properly
|
||||
- ✅ Override specific configs (like Redis) after the fact
|
||||
- ✅ Maintain idempotency (subsequent runs just update configs)
|
||||
**Configuration Method:**
|
||||
|
||||
This role uses **OCC commands via a script** rather than config files because:
|
||||
- ✅ **Explicit and verifiable** - Run `occ config:list system` to see exact state
|
||||
- ✅ **No file conflicts** - Avoids issues with Docker image's built-in config files
|
||||
- ✅ **Fully idempotent** - Safe to re-run during updates
|
||||
- ✅ **Single source of truth** - All configuration in one script template
|
||||
|
||||
See the official [Nextcloud Docker documentation](https://github.com/nextcloud/docker#auto-configuration-via-environment-variables) for more details on the auto-configuration process.
|
||||
|
||||
## Installed Apps
|
||||
|
||||
This role automatically installs and enables the following apps:
|
||||
|
||||
- **user_oidc** - OpenID Connect authentication backend for SSO integration
|
||||
- **calendar** - Calendar and scheduling application (CalDAV)
|
||||
- **contacts** - Contact management application (CardDAV)
|
||||
|
||||
To customize the app list, override these variables in your `host_vars`:
|
||||
|
||||
```yaml
|
||||
nextcloud_apps_install:
|
||||
- user_oidc
|
||||
- calendar
|
||||
- contacts
|
||||
- tasks # Add more apps as needed
|
||||
- deck
|
||||
- mail
|
||||
|
||||
```
|
||||
|
||||
## OIDC/SSO Integration
|
||||
|
||||
### Prerequisites
|
||||
|
||||
Before enabling OIDC, you must create an OIDC application/provider in your identity provider (e.g., Authentik):
|
||||
|
||||
**For Authentik:**
|
||||
|
||||
1. Navigate to **Applications → Providers**
|
||||
2. Click **Create** → **OAuth2/OpenID Provider**
|
||||
3. Configure:
|
||||
- **Name**: `Nextcloud`
|
||||
- **Authorization flow**: `default-authentication-flow` (or your preferred flow)
|
||||
- **Client type**: `Confidential`
|
||||
- **Client ID**: Generate or specify (save this)
|
||||
- **Client Secret**: Generate or specify (save this)
|
||||
- **Redirect URIs**: `https://cloud.jnss.me/apps/user_oidc/code`
|
||||
- **Signing Key**: Select your signing certificate
|
||||
- **Scopes**: Add `openid`, `profile`, `email`
|
||||
|
||||
4. Create **Application**:
|
||||
- Navigate to **Applications → Applications**
|
||||
- Click **Create**
|
||||
- **Name**: `Nextcloud`
|
||||
- **Slug**: `nextcloud`
|
||||
- **Provider**: Select the provider created above
|
||||
- **Launch URL**: `https://cloud.jnss.me`
|
||||
|
||||
5. Note the **Discovery URL**: `https://auth.jnss.me/application/o/nextcloud/.well-known/openid-configuration`
|
||||
|
||||
### Configuration
|
||||
|
||||
Enable OIDC in your `host_vars/arch-vps/main.yml`:
|
||||
|
||||
```yaml
|
||||
# OIDC Configuration
|
||||
nextcloud_oidc_enabled: true
|
||||
nextcloud_oidc_provider_id: "authentik" # Provider identifier (slug)
|
||||
nextcloud_oidc_provider_name: "Authentik SSO" # Display name on login button
|
||||
nextcloud_oidc_discovery_url: "https://auth.jnss.me/application/o/nextcloud/.well-known/openid-configuration"
|
||||
|
||||
# Security settings (recommended defaults)
|
||||
nextcloud_oidc_unique_uid: true # Prevents account takeover between providers
|
||||
nextcloud_oidc_check_bearer: false
|
||||
nextcloud_oidc_send_id_token_hint: true
|
||||
|
||||
# Attribute mappings (defaults work for most providers)
|
||||
nextcloud_oidc_mapping_display_name: "name"
|
||||
nextcloud_oidc_mapping_email: "email"
|
||||
nextcloud_oidc_mapping_uid: "preferred_username" # Or "sub" for UUID
|
||||
|
||||
# Optional: Enable single login (auto-redirect to SSO)
|
||||
nextcloud_oidc_single_login: false # Set to true to force SSO login
|
||||
```
|
||||
|
||||
Add credentials to your vault file `host_vars/arch-vps/vault.yml`:
|
||||
|
||||
```yaml
|
||||
vault_nextcloud_oidc_client_id: "nextcloud-client-id-from-authentik"
|
||||
vault_nextcloud_oidc_client_secret: "nextcloud-client-secret-from-authentik"
|
||||
```
|
||||
|
||||
### OIDC Scopes
|
||||
|
||||
The following scopes are requested from your OIDC provider by default:
|
||||
|
||||
```yaml
|
||||
nextcloud_oidc_scope: "email profile nextcloud openid"
|
||||
```
|
||||
|
||||
**Standard scopes:**
|
||||
- `openid` - Required for OpenID Connect (contains no claims itself)
|
||||
- `email` - User's email address (`email` and `email_verified` claims)
|
||||
- `profile` - User's profile information (`name`, `given_name`, `preferred_username`, `picture`, etc.)
|
||||
|
||||
**Custom scope for Authentik:**
|
||||
- `nextcloud` - Custom scope mapping you create in Authentik (contains `groups`, `quota`, `user_id`)
|
||||
|
||||
#### Creating the Nextcloud Scope Mapping in Authentik
|
||||
|
||||
The `nextcloud` scope must be created as a custom property mapping in Authentik:
|
||||
|
||||
1. Log in to Authentik as administrator
|
||||
2. Navigate to **Customization** → **Property mappings** → **Create**
|
||||
3. Select type: **Scope mapping**
|
||||
4. Configure:
|
||||
- **Name**: `Nextcloud Profile`
|
||||
- **Scope name**: `nextcloud`
|
||||
- **Expression**:
|
||||
|
||||
```python
|
||||
# Extract all groups the user is a member of
|
||||
groups = [group.name for group in user.ak_groups.all()]
|
||||
|
||||
# In Nextcloud, administrators must be members of a fixed group called "admin"
|
||||
# If a user is an admin in authentik, ensure that "admin" is appended to their group list
|
||||
if user.is_superuser and "admin" not in groups:
|
||||
groups.append("admin")
|
||||
|
||||
return {
|
||||
"name": request.user.name,
|
||||
"groups": groups,
|
||||
# Set a quota by using the "nextcloud_quota" property in the user's attributes
|
||||
"quota": user.group_attributes().get("nextcloud_quota", None),
|
||||
# To connect an existing Nextcloud user, set "nextcloud_user_id" to the Nextcloud username
|
||||
"user_id": user.attributes.get("nextcloud_user_id", str(user.uuid)),
|
||||
}
|
||||
```
|
||||
|
||||
5. Click **Finish**
|
||||
6. Navigate to your Nextcloud provider → **Advanced protocol settings**
|
||||
7. Add `Nextcloud Profile` to **Scopes** (in addition to the default scopes)
|
||||
|
||||
### Group Provisioning and Synchronization
|
||||
|
||||
Automatically sync user group membership from Authentik to Nextcloud.
|
||||
|
||||
**Default configuration:**
|
||||
|
||||
```yaml
|
||||
nextcloud_oidc_group_provisioning: true # Auto-create groups from Authentik
|
||||
nextcloud_oidc_mapping_groups: "groups" # Claim containing group list
|
||||
```
|
||||
|
||||
**How it works:**
|
||||
|
||||
1. User logs in via OIDC
|
||||
2. Authentik sends group membership in the `groups` claim (from the custom scope)
|
||||
3. Nextcloud automatically:
|
||||
- Creates groups that don't exist in Nextcloud
|
||||
- Adds user to those groups
|
||||
- Removes user from groups they're no longer member of in Authentik
|
||||
|
||||
**Example: Making a user an admin**
|
||||
|
||||
Nextcloud requires admins to be in a group literally named `admin`. The custom scope mapping (above) automatically adds `"admin"` to the groups list for Authentik superusers.
|
||||
|
||||
Alternatively, manually create a group in Authentik called `admin` and add users to it.
|
||||
|
||||
**Quota management:**
|
||||
|
||||
Set storage quotas by adding the `nextcloud_quota` attribute to Authentik groups or users:
|
||||
|
||||
1. In Authentik, navigate to **Directory** → **Groups** → select your group
|
||||
2. Under **Attributes**, add:
|
||||
```json
|
||||
{
|
||||
"nextcloud_quota": "15 GB"
|
||||
}
|
||||
```
|
||||
3. Users in this group will have a 15 GB quota in Nextcloud
|
||||
4. If not set, quota is unlimited
|
||||
|
||||
### Complete Authentik Setup Guide
|
||||
|
||||
Follow these steps to set up OIDC authentication with Authentik:
|
||||
|
||||
**Step 1: Create the Custom Scope Mapping**
|
||||
|
||||
See [Creating the Nextcloud Scope Mapping in Authentik](#creating-the-nextcloud-scope-mapping-in-authentik) above.
|
||||
|
||||
**Step 2: Create the OAuth2/OpenID Provider**
|
||||
|
||||
1. In Authentik, navigate to **Applications** → **Providers**
|
||||
2. Click **Create** → **OAuth2/OpenID Provider**
|
||||
3. Configure:
|
||||
- **Name**: `Nextcloud`
|
||||
- **Authorization flow**: `default-authentication-flow` (or your preferred flow)
|
||||
- **Client type**: `Confidential`
|
||||
- **Client ID**: Generate or specify (save this for later)
|
||||
- **Client Secret**: Generate or specify (save this for later)
|
||||
- **Redirect URIs**: `https://cloud.jnss.me/apps/user_oidc/code`
|
||||
- **Signing Key**: Select your signing certificate
|
||||
- Under **Advanced protocol settings**:
|
||||
- **Scopes**: Add `openid`, `email`, `profile`, and `Nextcloud Profile` (the custom scope created in Step 1)
|
||||
- **Subject mode**: `Based on the User's UUID` (or `Based on the User's username` if you prefer usernames)
|
||||
|
||||
**Step 3: Create the Application**
|
||||
|
||||
1. Navigate to **Applications** → **Applications**
|
||||
2. Click **Create**
|
||||
3. Configure:
|
||||
- **Name**: `Nextcloud`
|
||||
- **Slug**: `nextcloud`
|
||||
- **Provider**: Select the provider created in Step 2
|
||||
- **Launch URL**: `https://cloud.jnss.me` (optional)
|
||||
|
||||
**Step 4: Note the Discovery URL**
|
||||
|
||||
The discovery URL follows this pattern:
|
||||
```
|
||||
https://auth.jnss.me/application/o/<slug>/.well-known/openid-configuration
|
||||
```
|
||||
|
||||
For the application slug `nextcloud`, it will be:
|
||||
```
|
||||
https://auth.jnss.me/application/o/nextcloud/.well-known/openid-configuration
|
||||
```
|
||||
|
||||
**Step 5: Configure Nextcloud Role Variables**
|
||||
|
||||
In your `host_vars/arch-vps/main.yml`:
|
||||
|
||||
```yaml
|
||||
nextcloud_oidc_enabled: true
|
||||
nextcloud_oidc_provider_id: "authentik"
|
||||
nextcloud_oidc_provider_name: "Authentik"
|
||||
nextcloud_oidc_discovery_url: "https://auth.jnss.me/application/o/nextcloud/.well-known/openid-configuration"
|
||||
nextcloud_oidc_scope: "email profile nextcloud openid"
|
||||
nextcloud_oidc_mapping_uid: "preferred_username" # Or "sub" for UUID-based IDs
|
||||
nextcloud_oidc_mapping_display_name: "name"
|
||||
nextcloud_oidc_mapping_email: "email"
|
||||
nextcloud_oidc_mapping_groups: "groups"
|
||||
nextcloud_oidc_mapping_quota: "quota"
|
||||
nextcloud_oidc_group_provisioning: true
|
||||
```
|
||||
|
||||
In your `host_vars/arch-vps/vault.yml`:
|
||||
|
||||
```yaml
|
||||
vault_nextcloud_oidc_client_id: "nextcloud" # Client ID from Authentik
|
||||
vault_nextcloud_oidc_client_secret: "very-long-secret-from-authentik" # Client Secret from Authentik
|
||||
```
|
||||
|
||||
**Step 6: Deploy and Test**
|
||||
|
||||
Run the Nextcloud playbook:
|
||||
```bash
|
||||
ansible-playbook -i inventory/hosts.yml site.yml --tags nextcloud --ask-vault-pass
|
||||
```
|
||||
|
||||
### Supported OIDC Providers
|
||||
|
||||
The `user_oidc` app supports any **OpenID Connect 1.0** compliant provider:
|
||||
|
||||
- **Authentik** (recommended for self-hosted)
|
||||
- **Keycloak**
|
||||
- **Auth0**
|
||||
- **Okta**
|
||||
- **Azure AD / Microsoft Entra ID**
|
||||
- **Google Identity Platform**
|
||||
- **GitHub** (via OIDC)
|
||||
- **GitLab**
|
||||
- **Authelia**
|
||||
- **Kanidm**
|
||||
- Any other OIDC 1.0 compliant provider
|
||||
|
||||
The `nextcloud_oidc_provider_id` is just an identifier slug - you can use any value like `authentik`, `keycloak`, `auth0`, `mycompany-sso`, etc.
|
||||
|
||||
### Verification
|
||||
|
||||
After deployment:
|
||||
|
||||
1. **Check provider configuration:**
|
||||
```bash
|
||||
podman exec --user www-data nextcloud php occ user_oidc:provider
|
||||
podman exec --user www-data nextcloud php occ user_oidc:provider authentik
|
||||
```
|
||||
|
||||
2. **Test login:**
|
||||
- Visit `https://cloud.jnss.me`
|
||||
- You should see a "Log in with Authentik SSO" button
|
||||
- Click it to test SSO flow
|
||||
- User account should be auto-created on first login
|
||||
|
||||
3. **Check user mapping:**
|
||||
```bash
|
||||
podman exec --user www-data nextcloud php occ user:list
|
||||
```
|
||||
|
||||
### Troubleshooting OIDC
|
||||
|
||||
**Login button doesn't appear:**
|
||||
```bash
|
||||
# Check if user_oidc app is enabled
|
||||
podman exec --user www-data nextcloud php occ app:list | grep user_oidc
|
||||
|
||||
# Enable if needed
|
||||
podman exec --user www-data nextcloud php occ app:enable user_oidc
|
||||
```
|
||||
|
||||
**Discovery URL errors:**
|
||||
```bash
|
||||
# Test discovery URL is accessible from container
|
||||
podman exec nextcloud curl -k https://auth.jnss.me/application/o/nextcloud/.well-known/openid-configuration
|
||||
```
|
||||
|
||||
**JWKS cache issues:**
|
||||
```bash
|
||||
# Clear JWKS cache
|
||||
podman exec --user www-data nextcloud php occ user_oidc:provider authentik \
|
||||
--clientid='your-client-id'
|
||||
```
|
||||
|
||||
## Email Configuration
|
||||
|
||||
Configure Nextcloud to send emails for password resets, notifications, and sharing.
|
||||
|
||||
### Configuration
|
||||
|
||||
Enable email in your `host_vars/arch-vps/main.yml`:
|
||||
|
||||
```yaml
|
||||
# Email Configuration
|
||||
nextcloud_email_enabled: true
|
||||
nextcloud_smtp_host: "smtp.fastmail.com"
|
||||
nextcloud_smtp_port: 587
|
||||
nextcloud_smtp_secure: "tls" # tls, ssl, or empty
|
||||
nextcloud_smtp_username: "nextcloud@jnss.me"
|
||||
nextcloud_mail_from_address: "nextcloud"
|
||||
nextcloud_mail_domain: "jnss.me"
|
||||
|
||||
# Set admin user's email address
|
||||
nextcloud_admin_email: "admin@jnss.me"
|
||||
```
|
||||
|
||||
Add SMTP password to vault `host_vars/arch-vps/vault.yml`:
|
||||
|
||||
```yaml
|
||||
vault_nextcloud_smtp_password: "your-smtp-app-password"
|
||||
```
|
||||
|
||||
### Common SMTP Providers
|
||||
|
||||
**Fastmail:**
|
||||
```yaml
|
||||
nextcloud_smtp_host: "smtp.fastmail.com"
|
||||
nextcloud_smtp_port: 587
|
||||
nextcloud_smtp_secure: "tls"
|
||||
```
|
||||
|
||||
**Gmail (App Password required):**
|
||||
```yaml
|
||||
nextcloud_smtp_host: "smtp.gmail.com"
|
||||
nextcloud_smtp_port: 587
|
||||
nextcloud_smtp_secure: "tls"
|
||||
```
|
||||
|
||||
**Office 365:**
|
||||
```yaml
|
||||
nextcloud_smtp_host: "smtp.office365.com"
|
||||
nextcloud_smtp_port: 587
|
||||
nextcloud_smtp_secure: "tls"
|
||||
```
|
||||
|
||||
**SMTP2GO:**
|
||||
```yaml
|
||||
nextcloud_smtp_host: "mail.smtp2go.com"
|
||||
nextcloud_smtp_port: 587
|
||||
nextcloud_smtp_secure: "tls"
|
||||
```
|
||||
|
||||
### Verification
|
||||
|
||||
After deployment:
|
||||
|
||||
1. **Check SMTP configuration:**
|
||||
```bash
|
||||
podman exec --user www-data nextcloud php occ config:list system | grep mail
|
||||
```
|
||||
|
||||
2. **Check admin email:**
|
||||
```bash
|
||||
podman exec --user www-data nextcloud php occ user:setting admin settings email
|
||||
```
|
||||
|
||||
3. **Send test email via Web UI:**
|
||||
- Log in as admin
|
||||
- Settings → Administration → Basic settings
|
||||
- Scroll to "Email server"
|
||||
- Click "Send email" button
|
||||
- Check recipient inbox
|
||||
|
||||
### Troubleshooting Email
|
||||
|
||||
**Test SMTP connection from container:**
|
||||
```bash
|
||||
# Install swaks if needed (for testing)
|
||||
podman exec nextcloud apk add --no-cache swaks
|
||||
|
||||
# Test SMTP connection
|
||||
podman exec nextcloud swaks \
|
||||
--to recipient@example.com \
|
||||
--from nextcloud@jnss.me \
|
||||
--server smtp.fastmail.com:587 \
|
||||
--auth LOGIN \
|
||||
--auth-user nextcloud@jnss.me \
|
||||
--auth-password 'your-password' \
|
||||
--tls
|
||||
```
|
||||
|
||||
**Check Nextcloud logs:**
|
||||
```bash
|
||||
podman exec --user www-data nextcloud php occ log:watch
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
### Include in Playbook
|
||||
@@ -250,7 +680,7 @@ This role uses a **split caching strategy** for optimal performance and stabilit
|
||||
- `memcache.local`: APCu (in-memory opcode cache)
|
||||
- `memcache.distributed`: Redis (shared cache, file locking)
|
||||
- `memcache.locking`: Redis (transactional file locking)
|
||||
- Configuration: Via custom `redis.config.php` template
|
||||
- Configuration: Via OCC commands in configuration script
|
||||
|
||||
**Why not Redis sessions?**
|
||||
|
||||
@@ -262,7 +692,7 @@ The official Nextcloud Docker image enables Redis session handling when `REDIS_H
|
||||
4. **Worker exhaustion**: Limited FPM workers (default 5) all become blocked
|
||||
5. **Cascading failure**: New requests queue, timeouts accumulate, locks orphan
|
||||
|
||||
This role disables Redis sessions by **not setting** `REDIS_HOST` in the environment, while still providing Redis caching via a custom `redis.config.php` that is deployed independently.
|
||||
This role disables Redis sessions by **not setting** `REDIS_HOST` in the environment, while still providing Redis caching via OCC configuration commands.
|
||||
|
||||
**If you need Redis sessions** (e.g., multi-server setup with session sharing), you must:
|
||||
1. Enable `REDIS_HOST` in `nextcloud.env.j2`
|
||||
|
||||
@@ -1,22 +1,104 @@
|
||||
# Nextcloud Role - Required Vault Variables
|
||||
# Nextcloud Role - Vault Variables
|
||||
|
||||
This role requires the following encrypted variables to be defined in your vault file (typically `host_vars/<hostname>/vault.yml`).
|
||||
This document describes all vault-encrypted variables used by the Nextcloud role.
|
||||
|
||||
## Required Variables
|
||||
|
||||
Add these to your encrypted vault file:
|
||||
These variables **must** be defined in your vault file for the role to function:
|
||||
|
||||
```yaml
|
||||
# Nextcloud database password
|
||||
# =================================================================
|
||||
# Core Credentials (REQUIRED)
|
||||
# =================================================================
|
||||
|
||||
# PostgreSQL database password for Nextcloud user
|
||||
vault_nextcloud_db_password: "CHANGE_ME_secure_database_password"
|
||||
|
||||
# Nextcloud admin account password
|
||||
# Nextcloud admin user password
|
||||
vault_nextcloud_admin_password: "CHANGE_ME_secure_admin_password"
|
||||
|
||||
# Valkey/Redis password (shared infrastructure)
|
||||
# Valkey (Redis) password for caching (shared infrastructure)
|
||||
vault_valkey_password: "CHANGE_ME_secure_valkey_password"
|
||||
```
|
||||
|
||||
## Optional Variables
|
||||
|
||||
These variables are only required if you enable the corresponding features:
|
||||
|
||||
### Email/SMTP Configuration
|
||||
|
||||
Only required if `nextcloud_email_enabled: true`:
|
||||
|
||||
```yaml
|
||||
# =================================================================
|
||||
# Email/SMTP Credentials (OPTIONAL)
|
||||
# =================================================================
|
||||
|
||||
# SMTP server password for sending emails
|
||||
# Used with nextcloud_smtp_username for authentication
|
||||
vault_nextcloud_smtp_password: "your-smtp-password-or-app-password"
|
||||
```
|
||||
|
||||
**Example for Gmail:**
|
||||
- Use an [App Password](https://support.google.com/accounts/answer/185833)
|
||||
- Do NOT use your main Google account password
|
||||
|
||||
**Example for Fastmail:**
|
||||
- Use an [App Password](https://www.fastmail.help/hc/en-us/articles/360058752854)
|
||||
|
||||
### OIDC/SSO Configuration
|
||||
|
||||
Only required if `nextcloud_oidc_enabled: true`:
|
||||
|
||||
```yaml
|
||||
# =================================================================
|
||||
# OIDC/SSO Credentials (OPTIONAL)
|
||||
# =================================================================
|
||||
|
||||
# OAuth2/OIDC Client ID from your identity provider
|
||||
vault_nextcloud_oidc_client_id: "nextcloud"
|
||||
|
||||
# OAuth2/OIDC Client Secret from your identity provider
|
||||
# IMPORTANT: Keep this secret! Anyone with this can impersonate your app
|
||||
vault_nextcloud_oidc_client_secret: "very-long-random-secret-from-authentik"
|
||||
```
|
||||
|
||||
## Complete Vault File Example
|
||||
|
||||
Here's a complete example of a vault file with all possible variables:
|
||||
|
||||
```yaml
|
||||
---
|
||||
# =================================================================
|
||||
# Example Vault File
|
||||
# =================================================================
|
||||
# File: host_vars/arch-vps/vault.yml
|
||||
# Encrypted with: ansible-vault encrypt host_vars/arch-vps/vault.yml
|
||||
|
||||
# Caddy TLS
|
||||
vault_caddy_tls_email: "admin@jnss.me"
|
||||
vault_cloudflare_api_token: "your-cloudflare-token"
|
||||
|
||||
# Authentik
|
||||
vault_authentik_db_password: "authentik-db-password"
|
||||
vault_authentik_secret_key: "authentik-secret-key"
|
||||
vault_authentik_admin_password: "authentik-admin-password"
|
||||
|
||||
# Valkey (shared infrastructure)
|
||||
vault_valkey_password: "V4lk3y!P@ssw0rd#R3d1s"
|
||||
|
||||
# Nextcloud - Core (always required)
|
||||
vault_nextcloud_db_password: "XkN8vQ2mP9wR5tY7uI0oP3sA6dF8gH1j"
|
||||
vault_nextcloud_admin_password: "AdminP@ssw0rd!SecureAndL0ng"
|
||||
|
||||
# Nextcloud - Email (optional)
|
||||
vault_nextcloud_smtp_password: "fastmail-app-password-xyz123"
|
||||
|
||||
# Nextcloud - OIDC (optional)
|
||||
vault_nextcloud_oidc_client_id: "nextcloud"
|
||||
vault_nextcloud_oidc_client_secret: "aksk_authentik_secret_very_long_random_string"
|
||||
```
|
||||
|
||||
## Creating/Editing Vault File
|
||||
|
||||
### First Time Setup
|
||||
@@ -37,6 +119,13 @@ ansible-vault edit host_vars/arch-vps/vault.yml
|
||||
# Add the Nextcloud variables, then save and exit
|
||||
```
|
||||
|
||||
### View Vault Contents
|
||||
|
||||
```bash
|
||||
# View vault file contents
|
||||
ansible-vault view host_vars/arch-vps/vault.yml
|
||||
```
|
||||
|
||||
### Password Generation
|
||||
|
||||
Generate secure passwords:
|
||||
@@ -49,39 +138,26 @@ openssl rand -base64 32
|
||||
pwgen -s 32 1
|
||||
```
|
||||
|
||||
## Example Vault File
|
||||
## Running Playbooks with Vault
|
||||
|
||||
Your `host_vars/arch-vps/vault.yml` should include:
|
||||
|
||||
```yaml
|
||||
---
|
||||
# Caddy TLS
|
||||
vault_caddy_tls_email: "admin@jnss.me"
|
||||
vault_cloudflare_api_token: "your-cloudflare-token"
|
||||
|
||||
# Authentik
|
||||
vault_authentik_db_password: "authentik-db-password"
|
||||
vault_authentik_secret_key: "authentik-secret-key"
|
||||
vault_authentik_admin_password: "authentik-admin-password"
|
||||
|
||||
# Nextcloud (ADD THESE)
|
||||
vault_nextcloud_db_password: "generated-password-1"
|
||||
vault_nextcloud_admin_password: "generated-password-2"
|
||||
|
||||
# Valkey (shared infrastructure)
|
||||
vault_valkey_password: "valkey-password"
|
||||
```
|
||||
|
||||
## Deployment
|
||||
|
||||
When deploying, you'll need to provide the vault password:
|
||||
### Interactive Password Prompt
|
||||
|
||||
```bash
|
||||
# Deploy with vault password prompt
|
||||
ansible-playbook -i inventory/hosts.yml site.yml --tags nextcloud --ask-vault-pass
|
||||
ansible-playbook -i inventory/hosts.yml site.yml --ask-vault-pass
|
||||
```
|
||||
|
||||
# Or use a password file
|
||||
ansible-playbook -i inventory/hosts.yml site.yml --tags nextcloud --vault-password-file ~/.vault_pass
|
||||
### Using a Password File
|
||||
|
||||
```bash
|
||||
# Create password file (DO NOT COMMIT THIS!)
|
||||
echo 'your-vault-password' > .vault_pass
|
||||
chmod 600 .vault_pass
|
||||
|
||||
# Add to .gitignore
|
||||
echo '.vault_pass' >> .gitignore
|
||||
|
||||
# Run playbook
|
||||
ansible-playbook -i inventory/hosts.yml site.yml --vault-password-file .vault_pass
|
||||
```
|
||||
|
||||
## Security Notes
|
||||
@@ -92,6 +168,29 @@ ansible-playbook -i inventory/hosts.yml site.yml --tags nextcloud --vault-passwo
|
||||
- Store vault password securely (password manager, encrypted file, etc.)
|
||||
- Consider using `ansible-vault rekey` to change vault password periodically
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### "Vault password incorrect"
|
||||
|
||||
**Problem:** Wrong vault password entered
|
||||
|
||||
**Solution:** Verify you're using the correct vault password
|
||||
|
||||
### "vault_nextcloud_db_password is undefined"
|
||||
|
||||
**Problem:** Variable not defined in vault file or vault file not loaded
|
||||
|
||||
**Solution:**
|
||||
1. Verify variable exists in vault file:
|
||||
```bash
|
||||
ansible-vault view host_vars/arch-vps/vault.yml | grep vault_nextcloud
|
||||
```
|
||||
|
||||
2. Ensure you're using `--ask-vault-pass`:
|
||||
```bash
|
||||
ansible-playbook -i inventory/hosts.yml site.yml --ask-vault-pass
|
||||
```
|
||||
|
||||
## Verification
|
||||
|
||||
Check that variables are properly encrypted:
|
||||
@@ -103,3 +202,8 @@ cat host_vars/arch-vps/vault.yml
|
||||
# Decrypt and view (requires password)
|
||||
ansible-vault view host_vars/arch-vps/vault.yml
|
||||
```
|
||||
|
||||
## Reference
|
||||
|
||||
- [Ansible Vault Documentation](https://docs.ansible.com/ansible/latest/user_guide/vault.html)
|
||||
- [Best Practices for Variables and Vaults](https://docs.ansible.com/ansible/latest/user_guide/playbooks_best_practices.html#variables-and-vaults)
|
||||
|
||||
@@ -15,7 +15,6 @@ nextcloud_home: /opt/nextcloud
|
||||
nextcloud_html_dir: "{{ nextcloud_home }}/html"
|
||||
nextcloud_data_dir: "{{ nextcloud_home }}/data"
|
||||
nextcloud_config_dir: "{{ nextcloud_home }}/config"
|
||||
nextcloud_custom_apps_dir: "{{ nextcloud_home }}/custom_apps"
|
||||
|
||||
# Container configuration (FPM variant)
|
||||
nextcloud_version: "stable-fpm"
|
||||
@@ -52,6 +51,7 @@ nextcloud_domain: "cloud.jnss.me"
|
||||
|
||||
# Admin user (auto-configured on first run)
|
||||
nextcloud_admin_user: "admin"
|
||||
nextcloud_admin_email: "admin@jnss.me"
|
||||
nextcloud_admin_password: "{{ vault_nextcloud_admin_password }}"
|
||||
|
||||
# Trusted domains (space-separated)
|
||||
@@ -75,12 +75,79 @@ nextcloud_background_jobs_mode: "cron" # Options: ajax, webcron, cron
|
||||
nextcloud_cron_interval: "5min" # How often cron runs (systemd timer)
|
||||
|
||||
# =================================================================
|
||||
# Maintenance Configuration
|
||||
# Nextcloud System Configuration
|
||||
# =================================================================
|
||||
|
||||
nextcloud_maintenance_window_start: 4 # Start hour (UTC) for maintenance window
|
||||
nextcloud_default_phone_region: "NO" # Default phone region code (ISO 3166-1 alpha-2)
|
||||
|
||||
# =================================================================
|
||||
# Apps Configuration
|
||||
# =================================================================
|
||||
|
||||
# Apps to install and enable
|
||||
nextcloud_apps_install:
|
||||
- user_oidc
|
||||
- calendar
|
||||
- contacts
|
||||
|
||||
# =================================================================
|
||||
# Email/SMTP Configuration (Optional)
|
||||
# =================================================================
|
||||
|
||||
nextcloud_email_enabled: true # Master switch - set to true to enable SMTP
|
||||
|
||||
# SMTP Server Configuration
|
||||
nextcloud_smtp_mode: "smtp" # smtp, sendmail, qmail
|
||||
nextcloud_smtp_host: "smtp.titan.email" # e.g., smtp.gmail.com, smtp.fastmail.com
|
||||
nextcloud_smtp_port: 587 # 587 for TLS, 465 for SSL, 25 for plain
|
||||
nextcloud_smtp_secure: "tls" # tls, ssl, or empty string for no encryption
|
||||
nextcloud_smtp_auth: true # Enable SMTP authentication
|
||||
nextcloud_smtp_authtype: "PLAIN" # LOGIN or PLAIN
|
||||
nextcloud_smtp_username: "hello@jnss.me" # SMTP username
|
||||
nextcloud_smtp_password: "{{ vault_nextcloud_smtp_password | default('') }}"
|
||||
|
||||
# Email Addressing
|
||||
nextcloud_mail_from_address: "hello" # Local part only (before @)
|
||||
nextcloud_mail_domain: "jnss.me" # Domain part (after @)
|
||||
|
||||
# Admin User Email (set at line 55 in Core Configuration section)
|
||||
|
||||
# =================================================================
|
||||
# OIDC/SSO Configuration (Optional)
|
||||
# =================================================================
|
||||
|
||||
nextcloud_oidc_enabled: true # Master switch - set to true to enable OIDC
|
||||
|
||||
# Provider Configuration
|
||||
nextcloud_oidc_provider_id: "authentik" # Provider identifier (slug)
|
||||
nextcloud_oidc_provider_name: "Authentik" # Display name (shown on login button)
|
||||
nextcloud_oidc_client_id: "{{ vault_nextcloud_oidc_client_id | default('') }}"
|
||||
nextcloud_oidc_client_secret: "{{ vault_nextcloud_oidc_client_secret | default('') }}"
|
||||
nextcloud_oidc_discovery_url: "https://auth.jnss.me/application/o/nextcloud/.well-known/openid-configuration" # Full discovery URL, e.g., https://auth.example.com/application/o/nextcloud/.well-known/openid-configuration
|
||||
|
||||
# Scopes (based on Authentik integration guide)
|
||||
# The 'nextcloud' scope is a custom scope you must create in Authentik
|
||||
nextcloud_oidc_scope: "email profile nextcloud openid"
|
||||
|
||||
# Provider Options
|
||||
nextcloud_oidc_unique_uid: false # Hash provider+user ID to prevent account takeover (recommended: true)
|
||||
nextcloud_oidc_check_bearer: false # Check bearer tokens for API/WebDAV calls
|
||||
nextcloud_oidc_send_id_token_hint: true # Send ID token hint during logout
|
||||
|
||||
# Attribute Mappings (based on Authentik integration guide)
|
||||
nextcloud_oidc_mapping_display_name: "name" # Claim for display name
|
||||
nextcloud_oidc_mapping_email: "email" # Claim for email
|
||||
nextcloud_oidc_mapping_quota: "quota" # Claim for quota (from Authentik property mapping)
|
||||
nextcloud_oidc_mapping_uid: "preferred_username" # Claim for user ID
|
||||
nextcloud_oidc_mapping_groups: "groups" # Claim for groups (from Authentik property mapping)
|
||||
|
||||
# Group Provisioning (based on Authentik integration guide)
|
||||
nextcloud_oidc_group_provisioning: true # Auto-create groups from OIDC provider
|
||||
|
||||
# Single Login Option
|
||||
nextcloud_oidc_single_login: true # If true and only one provider, auto-redirect to SSO
|
||||
|
||||
# =================================================================
|
||||
# Caddy Integration
|
||||
# =================================================================
|
||||
|
||||
36
roles/nextcloud/tasks/configure.yml
Normal file
36
roles/nextcloud/tasks/configure.yml
Normal file
@@ -0,0 +1,36 @@
|
||||
---
|
||||
# =================================================================
|
||||
# Nextcloud Configuration via Script
|
||||
# =================================================================
|
||||
# Rick-Infra - Nextcloud Role
|
||||
#
|
||||
# Deploys and runs a configuration script inside the Nextcloud
|
||||
# container to set system configuration via OCC commands.
|
||||
|
||||
- name: Deploy Nextcloud configuration script
|
||||
template:
|
||||
src: configure-nextcloud.sh.j2
|
||||
dest: "{{ nextcloud_config_dir }}/configure.sh"
|
||||
mode: '0755'
|
||||
tags: [config, nextcloud-config]
|
||||
|
||||
- name: Run Nextcloud configuration script
|
||||
command: podman exec --user www-data nextcloud bash /var/www/html/config/configure.sh
|
||||
register: nc_config_result
|
||||
changed_when: false # Script output doesn't indicate changes reliably
|
||||
failed_when: nc_config_result.rc != 0
|
||||
tags: [config, nextcloud-config]
|
||||
|
||||
- name: Display configuration script output
|
||||
debug:
|
||||
msg: "{{ nc_config_result.stdout_lines }}"
|
||||
when: nc_config_result.stdout | length > 0
|
||||
tags: [config, nextcloud-config]
|
||||
|
||||
- name: Display configuration script errors
|
||||
debug:
|
||||
msg: "{{ nc_config_result.stderr_lines }}"
|
||||
when:
|
||||
- nc_config_result.stderr | length > 0
|
||||
- nc_config_result.rc != 0
|
||||
tags: [config, nextcloud-config]
|
||||
@@ -40,7 +40,6 @@
|
||||
- "{{ nextcloud_html_dir }}"
|
||||
- "{{ nextcloud_data_dir }}"
|
||||
- "{{ nextcloud_config_dir }}"
|
||||
- "{{ nextcloud_custom_apps_dir }}"
|
||||
tags: [setup, directories]
|
||||
|
||||
- name: Deploy environment configuration
|
||||
@@ -52,12 +51,9 @@
|
||||
notify: restart nextcloud
|
||||
tags: [config]
|
||||
|
||||
# NOTE: Custom Redis config is deployed AFTER installation completes (see below)
|
||||
# to avoid interfering with the container's first-time initialization process
|
||||
|
||||
# NOTE: redis-session-override.ini is NOT deployed because we use file-based sessions
|
||||
# (not Redis sessions). If you enable REDIS_HOST in the future, you'll need to add
|
||||
# proper session lock configuration.
|
||||
# NOTE: Nextcloud is configured via OCC commands in a script after installation
|
||||
# completes. This avoids interfering with the container's initialization process
|
||||
# and provides a clean, explicit configuration approach.
|
||||
|
||||
- name: Create Quadlet systemd directory (system scope)
|
||||
file:
|
||||
@@ -130,13 +126,9 @@
|
||||
changed_when: false
|
||||
tags: [verification]
|
||||
|
||||
- name: Deploy custom Redis caching configuration (post-installation)
|
||||
template:
|
||||
src: redis.config.php.j2
|
||||
dest: "{{ nextcloud_config_dir }}/redis.config.php"
|
||||
mode: '0644'
|
||||
notify: restart nextcloud
|
||||
tags: [config, redis]
|
||||
- name: Configure Nextcloud via OCC script
|
||||
include_tasks: configure.yml
|
||||
tags: [config, configure]
|
||||
|
||||
- name: Truncate nextcloud.log to prevent bloat
|
||||
shell: |
|
||||
@@ -149,10 +141,6 @@
|
||||
include_tasks: cron.yml
|
||||
tags: [cron, background-jobs]
|
||||
|
||||
- name: Optimize database and apply configuration
|
||||
include_tasks: optimization.yml
|
||||
tags: [optimization, database]
|
||||
|
||||
- name: Display Nextcloud deployment status
|
||||
debug:
|
||||
msg: |
|
||||
@@ -167,7 +155,8 @@
|
||||
⚙️ Configuration:
|
||||
- Redis caching enabled (application-level cache & file locking)
|
||||
- PHP sessions use file-based storage (not Redis)
|
||||
- Custom redis.config.php deployed post-installation
|
||||
- Database optimizations applied
|
||||
- Configuration via OCC commands
|
||||
|
||||
🚀 Ready for file storage and collaboration!
|
||||
|
||||
|
||||
@@ -1,64 +0,0 @@
|
||||
---
|
||||
# =================================================================
|
||||
# Nextcloud Database Optimization
|
||||
# =================================================================
|
||||
# Rick-Infra - Nextcloud Role
|
||||
#
|
||||
# Performs database maintenance tasks to optimize performance
|
||||
# and resolve setup warnings about missing indices and migrations
|
||||
|
||||
- name: Add missing database indices
|
||||
command: >
|
||||
podman exec --user www-data nextcloud
|
||||
php occ db:add-missing-indices
|
||||
register: nextcloud_indices
|
||||
changed_when: "'indices added' in nextcloud_indices.stdout or 'Check indices' in nextcloud_indices.stdout"
|
||||
failed_when:
|
||||
- nextcloud_indices.rc != 0
|
||||
- "'already exists' not in nextcloud_indices.stderr"
|
||||
|
||||
- name: Convert filecache bigint columns
|
||||
command: >
|
||||
podman exec --user www-data nextcloud
|
||||
php occ db:convert-filecache-bigint --no-interaction
|
||||
register: nextcloud_bigint
|
||||
changed_when: "'converted' in nextcloud_bigint.stdout"
|
||||
failed_when:
|
||||
- nextcloud_bigint.rc != 0
|
||||
- "'already' not in nextcloud_bigint.stdout"
|
||||
timeout: 300 # 5 minutes for large databases
|
||||
|
||||
- name: Update mimetype database mappings
|
||||
command: >
|
||||
podman exec --user www-data nextcloud
|
||||
php occ maintenance:repair --include-expensive
|
||||
register: nextcloud_repair
|
||||
changed_when: "'updated' in nextcloud_repair.stdout or 'repaired' in nextcloud_repair.stdout"
|
||||
failed_when: nextcloud_repair.rc != 0
|
||||
timeout: 600 # 10 minutes for expensive repairs
|
||||
|
||||
- name: Configure maintenance window
|
||||
command: >
|
||||
podman exec --user www-data nextcloud
|
||||
php occ config:system:set maintenance_window_start --value={{ nextcloud_maintenance_window_start }} --type=integer
|
||||
register: nextcloud_maintenance_window
|
||||
changed_when: "'set' in nextcloud_maintenance_window.stdout"
|
||||
failed_when: nextcloud_maintenance_window.rc != 0
|
||||
|
||||
- name: Configure default phone region
|
||||
command: >
|
||||
podman exec --user www-data nextcloud
|
||||
php occ config:system:set default_phone_region --value={{ nextcloud_default_phone_region }}
|
||||
register: nextcloud_phone_region
|
||||
changed_when: "'set' in nextcloud_phone_region.stdout"
|
||||
failed_when: nextcloud_phone_region.rc != 0
|
||||
|
||||
- name: Display optimization results
|
||||
debug:
|
||||
msg: |
|
||||
Database optimization complete:
|
||||
- Indices: {{ 'Added' if 'indices added' in nextcloud_indices.stdout else 'Already optimized' }}
|
||||
- BigInt: {{ 'Converted' if 'converted' in nextcloud_bigint.stdout else 'Already converted' }}
|
||||
- Mimetypes: {{ 'Updated' if 'updated' in nextcloud_repair.stdout else 'Up to date' }}
|
||||
- Maintenance window: {{ nextcloud_maintenance_window_start }}:00 UTC
|
||||
- Phone region: {{ nextcloud_default_phone_region }}
|
||||
189
roles/nextcloud/templates/configure-nextcloud.sh.j2
Normal file
189
roles/nextcloud/templates/configure-nextcloud.sh.j2
Normal file
@@ -0,0 +1,189 @@
|
||||
#!/bin/bash
|
||||
# =================================================================
|
||||
# Nextcloud Configuration Script
|
||||
# =================================================================
|
||||
# Rick-Infra - Nextcloud Role
|
||||
#
|
||||
# This script configures Nextcloud via OCC commands after initial
|
||||
# installation. It is generated from Ansible variables and runs
|
||||
# inside the Nextcloud container.
|
||||
#
|
||||
# Generated by: roles/nextcloud/templates/configure-nextcloud.sh.j2
|
||||
# Managed by: Ansible
|
||||
|
||||
set +e # Continue on errors, report at end
|
||||
ERRORS=0
|
||||
|
||||
# Helper function for OCC
|
||||
occ() {
|
||||
php /var/www/html/occ "$@" 2>&1
|
||||
}
|
||||
|
||||
# Track errors
|
||||
check_error() {
|
||||
if [ $? -ne 0 ]; then
|
||||
ERRORS=$((ERRORS + 1))
|
||||
echo "ERROR: $1" >&2
|
||||
fi
|
||||
}
|
||||
|
||||
# =================================================================
|
||||
# Redis Caching Configuration
|
||||
# =================================================================
|
||||
# Configure Redis for application-level caching and file locking
|
||||
# WITHOUT enabling Redis sessions (which can cause performance issues)
|
||||
|
||||
occ config:system:set memcache.distributed --value='\OC\Memcache\Redis' --quiet
|
||||
check_error "Failed to set memcache.distributed"
|
||||
|
||||
occ config:system:set memcache.locking --value='\OC\Memcache\Redis' --quiet
|
||||
check_error "Failed to set memcache.locking"
|
||||
|
||||
occ config:system:set redis host --value='{{ valkey_unix_socket_path }}' --quiet
|
||||
check_error "Failed to set redis.host"
|
||||
|
||||
occ config:system:set redis password --value='{{ valkey_password }}' --quiet
|
||||
check_error "Failed to set redis.password"
|
||||
|
||||
occ config:system:set redis dbindex --value={{ nextcloud_valkey_db }} --type=integer --quiet
|
||||
check_error "Failed to set redis.dbindex"
|
||||
|
||||
# =================================================================
|
||||
# Maintenance Configuration
|
||||
# =================================================================
|
||||
|
||||
occ config:system:set maintenance_window_start --value={{ nextcloud_maintenance_window_start }} --type=integer --quiet
|
||||
check_error "Failed to set maintenance_window_start"
|
||||
|
||||
occ config:system:set default_phone_region --value='{{ nextcloud_default_phone_region }}' --quiet
|
||||
check_error "Failed to set default_phone_region"
|
||||
|
||||
# =================================================================
|
||||
# Database Optimization
|
||||
# =================================================================
|
||||
|
||||
# Add missing database indices
|
||||
occ db:add-missing-indices --quiet
|
||||
check_error "Failed to add missing database indices"
|
||||
|
||||
# Convert filecache to bigint
|
||||
occ db:convert-filecache-bigint --no-interaction --quiet
|
||||
check_error "Failed to convert filecache to bigint"
|
||||
|
||||
# Update mimetype database mappings
|
||||
occ maintenance:repair --include-expensive --quiet
|
||||
check_error "Failed to run maintenance:repair"
|
||||
|
||||
# =================================================================
|
||||
# App Installation and Enablement
|
||||
# =================================================================
|
||||
# Install apps first, then enable them. This must happen before
|
||||
# app-specific configuration (e.g., OIDC provider setup)
|
||||
|
||||
{% if nextcloud_apps_install is defined and nextcloud_apps_install | length > 0 %}
|
||||
# Install apps
|
||||
{% for app in nextcloud_apps_install %}
|
||||
occ app:install {{ app }} --quiet 2>&1 | grep -v "already installed" || true
|
||||
check_error "Failed to install app: {{ app }}"
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
# =================================================================
|
||||
# Email/SMTP Configuration
|
||||
# =================================================================
|
||||
{% if nextcloud_email_enabled | default(false) %}
|
||||
# Configure SMTP mode
|
||||
occ config:system:set mail_smtpmode --value={{ nextcloud_smtp_mode }} --quiet
|
||||
check_error "Failed to set mail_smtpmode"
|
||||
|
||||
# Configure SMTP server
|
||||
occ config:system:set mail_smtphost --value='{{ nextcloud_smtp_host }}' --quiet
|
||||
check_error "Failed to set mail_smtphost"
|
||||
|
||||
occ config:system:set mail_smtpport --value={{ nextcloud_smtp_port }} --type=integer --quiet
|
||||
check_error "Failed to set mail_smtpport"
|
||||
|
||||
{% if nextcloud_smtp_secure %}
|
||||
occ config:system:set mail_smtpsecure --value={{ nextcloud_smtp_secure }} --quiet
|
||||
check_error "Failed to set mail_smtpsecure"
|
||||
{% endif %}
|
||||
|
||||
{% if nextcloud_smtp_auth %}
|
||||
# Configure SMTP authentication
|
||||
occ config:system:set mail_smtpauth --value=1 --type=integer --quiet
|
||||
check_error "Failed to set mail_smtpauth"
|
||||
|
||||
occ config:system:set mail_smtpauthtype --value={{ nextcloud_smtp_authtype }} --quiet
|
||||
check_error "Failed to set mail_smtpauthtype"
|
||||
|
||||
occ config:system:set mail_smtpname --value='{{ nextcloud_smtp_username }}' --quiet
|
||||
check_error "Failed to set mail_smtpname"
|
||||
|
||||
occ config:system:set mail_smtppassword --value='{{ nextcloud_smtp_password }}' --quiet
|
||||
check_error "Failed to set mail_smtppassword"
|
||||
{% endif %}
|
||||
|
||||
# Configure email addressing
|
||||
occ config:system:set mail_from_address --value='{{ nextcloud_mail_from_address }}' --quiet
|
||||
check_error "Failed to set mail_from_address"
|
||||
|
||||
occ config:system:set mail_domain --value='{{ nextcloud_mail_domain }}' --quiet
|
||||
check_error "Failed to set mail_domain"
|
||||
{% endif %}
|
||||
|
||||
# Set admin user email address
|
||||
{% if nextcloud_admin_email %}
|
||||
occ user:setting {{ nextcloud_admin_user }} settings email '{{ nextcloud_admin_email }}' --quiet
|
||||
check_error "Failed to set admin user email"
|
||||
{% endif %}
|
||||
|
||||
# =================================================================
|
||||
# OIDC/SSO Provider Configuration
|
||||
# =================================================================
|
||||
{% if nextcloud_oidc_enabled | default(false) %}
|
||||
# Configure OIDC provider (creates if doesn't exist, updates if exists)
|
||||
occ user_oidc:provider {{ nextcloud_oidc_provider_id }} \
|
||||
--clientid='{{ nextcloud_oidc_client_id }}' \
|
||||
--clientsecret='{{ nextcloud_oidc_client_secret }}' \
|
||||
--discoveryuri='{{ nextcloud_oidc_discovery_url }}' \
|
||||
--scope='{{ nextcloud_oidc_scope }}' \
|
||||
--unique-uid={{ '1' if nextcloud_oidc_unique_uid else '0' }} \
|
||||
--check-bearer={{ '1' if nextcloud_oidc_check_bearer else '0' }} \
|
||||
--send-id-token-hint={{ '1' if nextcloud_oidc_send_id_token_hint else '0' }} \
|
||||
{% if nextcloud_oidc_mapping_display_name %}
|
||||
--mapping-display-name='{{ nextcloud_oidc_mapping_display_name }}' \
|
||||
{% endif %}
|
||||
{% if nextcloud_oidc_mapping_email %}
|
||||
--mapping-email='{{ nextcloud_oidc_mapping_email }}' \
|
||||
{% endif %}
|
||||
{% if nextcloud_oidc_mapping_quota %}
|
||||
--mapping-quota='{{ nextcloud_oidc_mapping_quota }}' \
|
||||
{% endif %}
|
||||
{% if nextcloud_oidc_mapping_uid %}
|
||||
--mapping-uid='{{ nextcloud_oidc_mapping_uid }}' \
|
||||
{% endif %}
|
||||
{% if nextcloud_oidc_mapping_groups %}
|
||||
--mapping-groups='{{ nextcloud_oidc_mapping_groups }}' \
|
||||
{% endif %}
|
||||
--group-provisioning={{ '1' if nextcloud_oidc_group_provisioning else '0' }} \
|
||||
--quiet 2>&1 | grep -v "already exists" || true
|
||||
check_error "Failed to configure OIDC provider: {{ nextcloud_oidc_provider_id }}"
|
||||
|
||||
{% if nextcloud_oidc_single_login %}
|
||||
# Enable single login (auto-redirect to SSO if only one provider)
|
||||
occ config:app:set user_oidc allow_multiple_user_backends --value=0 --quiet
|
||||
check_error "Failed to enable single login mode"
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
# =================================================================
|
||||
# Exit Status
|
||||
# =================================================================
|
||||
|
||||
if [ $ERRORS -gt 0 ]; then
|
||||
echo "Configuration completed with $ERRORS error(s)" >&2
|
||||
exit 1
|
||||
else
|
||||
echo "Nextcloud configuration completed successfully"
|
||||
exit 0
|
||||
fi
|
||||
@@ -1,32 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* Nextcloud Additional Configuration
|
||||
* Rick-Infra - Nextcloud Role
|
||||
*
|
||||
* This file provides additional configuration for Nextcloud
|
||||
* that complements the main config.php file.
|
||||
*
|
||||
* Applied via: php occ config:system:set
|
||||
*/
|
||||
|
||||
$CONFIG = array(
|
||||
/**
|
||||
* Maintenance Window
|
||||
*
|
||||
* Defines a maintenance window during which resource-intensive
|
||||
* operations (like database updates) can be performed.
|
||||
*
|
||||
* Format: Hour (0-23, UTC)
|
||||
*/
|
||||
'maintenance_window_start' => {{ nextcloud_maintenance_window_start }},
|
||||
|
||||
/**
|
||||
* Default Phone Region
|
||||
*
|
||||
* Sets the default country code for phone number validation.
|
||||
* Used when users enter phone numbers without country prefix.
|
||||
*
|
||||
* Format: ISO 3166-1 alpha-2 country code
|
||||
*/
|
||||
'default_phone_region' => '{{ nextcloud_default_phone_region }}',
|
||||
);
|
||||
@@ -23,9 +23,6 @@ Volume={{ nextcloud_data_dir }}:/var/www/html/data:Z
|
||||
# Configuration (private - contains secrets)
|
||||
Volume={{ nextcloud_config_dir }}:/var/www/html/config:Z
|
||||
|
||||
# Custom apps (world-readable)
|
||||
Volume={{ nextcloud_custom_apps_dir }}:/var/www/html/custom_apps:Z
|
||||
|
||||
# Infrastructure sockets (mounted with world-readable permissions on host)
|
||||
Volume={{ postgresql_unix_socket_directories }}:{{ postgresql_unix_socket_directories }}:Z
|
||||
Volume={{ valkey_unix_socket_path | dirname }}:{{ valkey_unix_socket_path | dirname }}:Z
|
||||
|
||||
@@ -1,34 +0,0 @@
|
||||
<?php
|
||||
/**
|
||||
* Redis/Valkey Caching Configuration for Nextcloud
|
||||
*
|
||||
* This file provides Redis caching for Nextcloud application-level operations
|
||||
* (distributed cache, file locking) WITHOUT enabling Redis for PHP sessions.
|
||||
*
|
||||
* IMPORTANT: This overrides the default /usr/src/nextcloud/config/redis.config.php
|
||||
* which checks for REDIS_HOST environment variable. We deploy this custom version
|
||||
* to enable Redis caching while keeping PHP sessions file-based for stability.
|
||||
*
|
||||
* Why not use REDIS_HOST env var?
|
||||
* - Setting REDIS_HOST enables BOTH Redis sessions AND Redis caching
|
||||
* - Redis session handling can cause severe performance issues:
|
||||
* * Session lock contention under high concurrency
|
||||
* * Infinite lock retries blocking FPM workers
|
||||
* * Timeout orphaning leaving locks unreleased
|
||||
* * Worker pool exhaustion causing cascading failures
|
||||
*
|
||||
* This configuration provides the benefits of Redis caching (fast distributed
|
||||
* cache, reliable file locking) while avoiding the pitfalls of Redis sessions.
|
||||
*
|
||||
* Managed by: Ansible Nextcloud role
|
||||
* Template: roles/nextcloud/templates/redis.config.php.j2
|
||||
*/
|
||||
|
||||
$CONFIG = array(
|
||||
'memcache.distributed' => '\OC\Memcache\Redis',
|
||||
'memcache.locking' => '\OC\Memcache\Redis',
|
||||
'redis' => array(
|
||||
'host' => '{{ valkey_unix_socket_path }}',
|
||||
'password' => '{{ valkey_password }}',
|
||||
),
|
||||
);
|
||||
331
roles/vaultwarden/README.md
Normal file
331
roles/vaultwarden/README.md
Normal file
@@ -0,0 +1,331 @@
|
||||
# Vaultwarden Password Manager Role
|
||||
|
||||
Self-contained Vaultwarden (Bitwarden-compatible) password manager deployment using Podman and PostgreSQL.
|
||||
|
||||
## Overview
|
||||
|
||||
This role deploys Vaultwarden as a Podman Quadlet container with:
|
||||
- **PostgreSQL backend** via Unix socket (777 permissions)
|
||||
- **Caddy reverse proxy** with HTTPS and WebSocket support
|
||||
- **SSO integration** ready (Authentik OpenID Connect)
|
||||
- **SMTP support** for email notifications (optional)
|
||||
- **Admin panel** for management
|
||||
|
||||
## Architecture
|
||||
|
||||
```
|
||||
Internet → Caddy (HTTPS) → Vaultwarden Container → PostgreSQL (Unix socket)
|
||||
↓
|
||||
/data volume
|
||||
```
|
||||
|
||||
### Components
|
||||
|
||||
- **Container Image**: `vaultwarden/server:latest` (Docker Hub)
|
||||
- **User**: System user `vaultwarden` (non-root)
|
||||
- **Port**: 8080 (localhost only)
|
||||
- **Domain**: `vault.jnss.me`
|
||||
- **Database**: PostgreSQL via Unix socket at `/var/run/postgresql`
|
||||
- **Data**: `/opt/vaultwarden/data`
|
||||
|
||||
## Dependencies
|
||||
|
||||
**Managed Hosts:**
|
||||
- `postgresql` role (provides database and Unix socket)
|
||||
- `caddy` role (provides reverse proxy)
|
||||
|
||||
**Control Node:**
|
||||
- `argon2` command-line tool (automatically installed if not present)
|
||||
- Used to hash the admin token securely on the control node
|
||||
- Available in most package managers: `pacman -S argon2`, `apt install argon2`, etc.
|
||||
|
||||
## Configuration
|
||||
|
||||
### Required Variables
|
||||
|
||||
Must be defined in vault (e.g., `group_vars/homelab/vault.yml`):
|
||||
|
||||
```yaml
|
||||
# Database password
|
||||
vault_vaultwarden_db_password: "secure-database-password"
|
||||
|
||||
# Admin token (plain text - will be hashed automatically during deployment)
|
||||
vault_vaultwarden_admin_token: "your-secure-admin-token"
|
||||
|
||||
# SMTP password (if using email)
|
||||
vault_vaultwarden_smtp_password: "smtp-password" # optional
|
||||
|
||||
# SSO credentials (if using Authentik integration)
|
||||
vault_vaultwarden_sso_client_id: "vaultwarden" # optional
|
||||
vault_vaultwarden_sso_client_secret: "sso-secret" # optional
|
||||
```
|
||||
|
||||
### Optional Variables
|
||||
|
||||
Override in `group_vars` or `host_vars`:
|
||||
|
||||
```yaml
|
||||
# Domain
|
||||
vaultwarden_domain: "vault.jnss.me"
|
||||
|
||||
# Container version
|
||||
vaultwarden_version: "latest"
|
||||
|
||||
# Registration controls
|
||||
vaultwarden_signups_allowed: false # Disable open registration
|
||||
vaultwarden_invitations_allowed: true # Allow existing users to invite
|
||||
|
||||
# SMTP Configuration
|
||||
vaultwarden_smtp_enabled: true
|
||||
vaultwarden_smtp_host: "smtp.example.com"
|
||||
vaultwarden_smtp_port: 587
|
||||
vaultwarden_smtp_from: "vault@jnss.me"
|
||||
vaultwarden_smtp_username: "smtp-user"
|
||||
|
||||
# SSO Configuration (Authentik)
|
||||
vaultwarden_sso_enabled: true
|
||||
vaultwarden_sso_authority: "https://auth.jnss.me"
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
### Deploy Vaultwarden
|
||||
|
||||
```bash
|
||||
# Full deployment
|
||||
ansible-playbook rick-infra.yml --tags vaultwarden
|
||||
|
||||
# Or via site.yml
|
||||
ansible-playbook site.yml --tags vaultwarden -l homelab
|
||||
```
|
||||
|
||||
### Access Admin Panel
|
||||
|
||||
1. Set admin token in vault file (plain text):
|
||||
```yaml
|
||||
# Generate a secure token
|
||||
vault_vaultwarden_admin_token: "$(openssl rand -base64 32)"
|
||||
```
|
||||
|
||||
2. The role automatically hashes the token during deployment:
|
||||
- Hashing occurs on the **control node** using `argon2` CLI
|
||||
- Uses OWASP recommended settings (19MiB memory, 2 iterations, 1 thread)
|
||||
- Idempotent: same token always produces the same hash
|
||||
- The `argon2` package is automatically installed if not present
|
||||
|
||||
3. Access: `https://vault.jnss.me/admin` (use the plain text token from step 1)
|
||||
|
||||
### Configure SSO (Authentik Integration)
|
||||
|
||||
> ⚠️ **IMPORTANT: SSO Feature Status (as of December 2025)**
|
||||
>
|
||||
> SSO is currently **only available in `vaultwarden/server:testing` images**.
|
||||
> The stable release (v1.34.3) does **NOT** include SSO functionality.
|
||||
>
|
||||
> **Current Deployment Status:**
|
||||
> - This role is configured with SSO settings ready for when SSO reaches stable release
|
||||
> - Using `vaultwarden_version: "latest"` (stable) - SSO will not appear
|
||||
> - To test SSO now: Set `vaultwarden_version: "testing"` (not recommended for production)
|
||||
> - To wait for stable: Keep current configuration, SSO will activate automatically when available
|
||||
>
|
||||
> **References:**
|
||||
> - [Vaultwarden Wiki - SSO Documentation](https://github.com/dani-garcia/vaultwarden/wiki/Enabling-SSO-support-using-OpenId-Connect)
|
||||
> - [Vaultwarden Testing Features](https://github.com/dani-garcia/vaultwarden/wiki#testing-features)
|
||||
>
|
||||
> **Decision:** This deployment keeps SSO configured but uses stable image until SSO feature is production-ready.
|
||||
|
||||
Following the [Authentik integration guide](https://integrations.goauthentik.io/security/vaultwarden/):
|
||||
|
||||
1. **In Authentik**: Create OAuth2/OpenID Provider
|
||||
- **Name**: `Vaultwarden`
|
||||
- **Client Type**: `Confidential`
|
||||
- **Redirect URIs**: `https://vault.jnss.me/identity/connect/oidc-signin` (must be strict/exact match)
|
||||
- **Scopes**: Under "Advanced protocol settings", ensure these scope mappings are selected:
|
||||
- `authentik default OAuth Mapping: OpenID 'openid'`
|
||||
- `authentik default OAuth Mapping: OpenID 'email'`
|
||||
- `authentik default OAuth Mapping: OpenID 'profile'`
|
||||
- `authentik default OAuth Mapping: OpenID 'offline_access'` ⚠️ **Required**
|
||||
- **Access token validity**: Set to more than 5 minutes
|
||||
- **Note the Client ID, Client Secret, and application slug** (from URL or provider settings)
|
||||
|
||||
2. **Update Vault Variables**:
|
||||
```yaml
|
||||
vault_vaultwarden_sso_client_id: "<client-id-from-authentik>"
|
||||
vault_vaultwarden_sso_client_secret: "<client-secret-from-authentik>"
|
||||
```
|
||||
|
||||
3. **Enable SSO and set authority** in `group_vars/homelab/main.yml`:
|
||||
```yaml
|
||||
vaultwarden_sso_enabled: true
|
||||
# Replace 'vaultwarden' with your actual application slug
|
||||
vaultwarden_sso_authority: "https://auth.jnss.me/application/o/vaultwarden/"
|
||||
```
|
||||
|
||||
4. **Optional: SSO-Only Mode** (disable password login):
|
||||
```yaml
|
||||
vaultwarden_sso_only: true # Requires SSO, disables email+password
|
||||
```
|
||||
|
||||
5. **Redeploy**:
|
||||
```bash
|
||||
ansible-playbook rick-infra.yml --tags vaultwarden
|
||||
```
|
||||
|
||||
6. **Test**: Log out, enter a verified email on login page, click "Use single sign-on"
|
||||
- **Note**: With `vaultwarden_version: "latest"`, SSO button will not appear (feature not in stable yet)
|
||||
|
||||
## Security Considerations
|
||||
|
||||
### Database Access
|
||||
|
||||
- Uses PostgreSQL Unix socket with **777 permissions**
|
||||
- Security maintained via password authentication (scram-sha-256)
|
||||
- See: `docs/socket-permissions-architecture.md`
|
||||
|
||||
### Admin Token
|
||||
|
||||
- **Never commit plain admin token to git**
|
||||
- Use Ansible Vault for `vault_vaultwarden_admin_token`
|
||||
- Rotate periodically via admin panel
|
||||
|
||||
### User Registration
|
||||
|
||||
- Default: **Disabled** (`vaultwarden_signups_allowed: false`)
|
||||
- Users must be invited by existing users or created via admin panel
|
||||
- Prevents unauthorized account creation
|
||||
|
||||
## Maintenance
|
||||
|
||||
### Backup
|
||||
|
||||
Backup the following:
|
||||
|
||||
```bash
|
||||
# Database backup (via PostgreSQL role)
|
||||
sudo -u postgres pg_dump vaultwarden > vaultwarden-backup.sql
|
||||
|
||||
# Data directory (attachments, icons, etc.)
|
||||
tar -czf vaultwarden-data-backup.tar.gz /opt/vaultwarden/data
|
||||
```
|
||||
|
||||
### Update Container
|
||||
|
||||
```bash
|
||||
# Pull new image and restart
|
||||
ansible-playbook rick-infra.yml --tags vaultwarden
|
||||
```
|
||||
|
||||
### View Logs
|
||||
|
||||
```bash
|
||||
# Service logs
|
||||
journalctl -u vaultwarden -f
|
||||
|
||||
# Container logs
|
||||
podman logs vaultwarden -f
|
||||
```
|
||||
|
||||
### Restart Service
|
||||
|
||||
```bash
|
||||
systemctl restart vaultwarden
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Container won't start
|
||||
|
||||
```bash
|
||||
# Check container status
|
||||
systemctl status vaultwarden
|
||||
|
||||
# Check container directly
|
||||
podman ps -a
|
||||
podman logs vaultwarden
|
||||
|
||||
# Verify database connectivity
|
||||
sudo -u vaultwarden psql -h /var/run/postgresql -U vaultwarden -d vaultwarden -c "SELECT 1;"
|
||||
```
|
||||
|
||||
### Database connection errors
|
||||
|
||||
1. Verify PostgreSQL is running: `systemctl status postgresql`
|
||||
2. Check socket exists: `ls -la /var/run/postgresql/.s.PGSQL.5432`
|
||||
3. Verify socket permissions: Should be `srwxrwxrwx` (777)
|
||||
4. Test connection as vaultwarden user (see above)
|
||||
|
||||
### Can't access admin panel
|
||||
|
||||
1. Verify admin token is set in vault file (plain text)
|
||||
2. Check that the token was hashed successfully during deployment
|
||||
3. Ensure you're using the plain text token to log in
|
||||
4. Redeploy to regenerate hash if needed
|
||||
|
||||
### SSO not appearing / not working
|
||||
|
||||
**Most Common Issue: Using Stable Image**
|
||||
|
||||
SSO is only available in testing images. Check your deployment:
|
||||
|
||||
```bash
|
||||
# Check current image version
|
||||
podman inspect vaultwarden --format '{{.ImageName}}'
|
||||
|
||||
# Check API config for SSO support
|
||||
curl -s http://127.0.0.1:8080/api/config | grep -o '"sso":"[^"]*"'
|
||||
# Empty string "" = SSO not available in this image
|
||||
# URL present = SSO is available
|
||||
```
|
||||
|
||||
**If using `vaultwarden_version: "latest"`**: SSO will not appear (feature not in stable yet)
|
||||
- **To test SSO**: Set `vaultwarden_version: "testing"` in role defaults or group/host vars
|
||||
- **For production**: Wait for SSO to reach stable release (recommended)
|
||||
|
||||
**If using `vaultwarden_version: "testing"` and SSO still not working**:
|
||||
|
||||
1. Verify Authentik provider configuration:
|
||||
- Check that `offline_access` scope mapping is added
|
||||
- Verify redirect URI matches exactly: `https://vault.jnss.me/identity/connect/oidc-signin`
|
||||
- Ensure access token validity is > 5 minutes
|
||||
2. Verify SSO authority URL includes full path with slug:
|
||||
- Should be: `https://auth.jnss.me/application/o/<your-slug>/`
|
||||
- Not just: `https://auth.jnss.me`
|
||||
3. Check client ID and secret in vault match Authentik
|
||||
4. Verify all required scopes: `openid email profile offline_access`
|
||||
5. Check Vaultwarden logs for SSO-related errors:
|
||||
```bash
|
||||
podman logs vaultwarden 2>&1 | grep -i sso
|
||||
```
|
||||
6. Test SSO flow: Log out, enter verified email, click "Use single sign-on"
|
||||
|
||||
## File Structure
|
||||
|
||||
```
|
||||
roles/vaultwarden/
|
||||
├── defaults/
|
||||
│ └── main.yml # Default variables
|
||||
├── handlers/
|
||||
│ └── main.yml # Service restart handlers
|
||||
├── meta/
|
||||
│ └── main.yml # Role dependencies
|
||||
├── tasks/
|
||||
│ ├── main.yml # Main orchestration
|
||||
│ ├── user.yml # User and directory setup
|
||||
│ └── database.yml # PostgreSQL setup
|
||||
├── templates/
|
||||
│ ├── vaultwarden.container # Quadlet container definition
|
||||
│ ├── vaultwarden.env.j2 # Environment configuration
|
||||
│ └── vaultwarden.caddy.j2 # Caddy reverse proxy config
|
||||
└── README.md # This file
|
||||
```
|
||||
|
||||
## References
|
||||
|
||||
- [Vaultwarden Documentation](https://github.com/dani-garcia/vaultwarden/wiki)
|
||||
- [PostgreSQL Backend Guide](https://github.com/dani-garcia/vaultwarden/wiki/Using-the-PostgreSQL-Backend)
|
||||
- [SSO Configuration](https://github.com/dani-garcia/vaultwarden/wiki/Enabling-SSO-support-using-OpenId-Connect)
|
||||
- [Socket Permissions Architecture](../../docs/socket-permissions-architecture.md)
|
||||
|
||||
## License
|
||||
|
||||
MIT
|
||||
171
roles/vaultwarden/VAULT_VARIABLES.md
Normal file
171
roles/vaultwarden/VAULT_VARIABLES.md
Normal file
@@ -0,0 +1,171 @@
|
||||
# Vaultwarden Role - Required Vault Variables
|
||||
|
||||
This document lists all vault-encrypted variables required by the Vaultwarden role.
|
||||
|
||||
## Required Variables
|
||||
|
||||
These variables **must** be defined in your vault file (e.g., `group_vars/homelab/vault.yml`):
|
||||
|
||||
### Database Credentials
|
||||
|
||||
```yaml
|
||||
# PostgreSQL database password for vaultwarden user
|
||||
vault_vaultwarden_db_password: "your-secure-database-password-here"
|
||||
```
|
||||
|
||||
**Generation**:
|
||||
```bash
|
||||
openssl rand -base64 32
|
||||
```
|
||||
|
||||
### Admin Panel Access
|
||||
|
||||
```yaml
|
||||
# Plain text admin token (will be hashed during deployment)
|
||||
vault_vaultwarden_admin_token: "your-secret-admin-token"
|
||||
```
|
||||
|
||||
**Generation**:
|
||||
```bash
|
||||
# Generate a secure random token
|
||||
openssl rand -base64 32
|
||||
```
|
||||
|
||||
**Important**:
|
||||
- Store as **plain text** in vault (the role will hash it automatically)
|
||||
- Use the same token to access `/admin` panel
|
||||
- The token is automatically hashed on the **control node** using argon2id
|
||||
- Hashing uses OWASP recommended settings (m=19456, t=2, p=1)
|
||||
- Hashing is **idempotent**: same token always produces same hash
|
||||
- The `argon2` package is automatically installed if not present on control node
|
||||
- Never commit the vault file unencrypted to git
|
||||
|
||||
## Optional Variables
|
||||
|
||||
These variables are only needed if you enable specific features:
|
||||
|
||||
### SMTP Configuration
|
||||
|
||||
Required if `vaultwarden_smtp_enabled: true`:
|
||||
|
||||
```yaml
|
||||
# SMTP password for sending emails
|
||||
vault_vaultwarden_smtp_password: "smtp-password-here"
|
||||
```
|
||||
|
||||
### SSO Integration (Authentik)
|
||||
|
||||
> ⚠️ **SSO Feature Status (December 2025)**
|
||||
>
|
||||
> SSO is only available in `vaultwarden/server:testing` images (not in stable yet).
|
||||
> This role is configured with SSO ready for when it reaches stable release.
|
||||
>
|
||||
> Current deployment uses `vaultwarden_version: "latest"` (stable) - SSO credentials
|
||||
> below are configured but SSO will not appear until feature reaches stable.
|
||||
|
||||
Required if `vaultwarden_sso_enabled: true`:
|
||||
|
||||
```yaml
|
||||
# OAuth2 Client ID from Authentik
|
||||
vault_vaultwarden_sso_client_id: "your-client-id-here"
|
||||
|
||||
# OAuth2 Client Secret from Authentik
|
||||
vault_vaultwarden_sso_client_secret: "your-client-secret-here"
|
||||
```
|
||||
|
||||
**Setup** (following [Authentik integration guide](https://integrations.goauthentik.io/security/vaultwarden/)):
|
||||
1. Create OAuth2/OpenID Provider in Authentik:
|
||||
- Redirect URI: `https://vault.jnss.me/identity/connect/oidc-signin` (exact match)
|
||||
- Add scope mappings: `openid`, `email`, `profile`, `offline_access` (required)
|
||||
- Access token validity: > 5 minutes
|
||||
- Note the **application slug** from the provider URL
|
||||
2. Copy Client ID and Secret from Authentik
|
||||
3. Add credentials to vault file
|
||||
4. Set the SSO authority URL in role configuration:
|
||||
```yaml
|
||||
vaultwarden_sso_enabled: true
|
||||
vaultwarden_sso_authority: "https://auth.jnss.me/application/o/<your-slug>/"
|
||||
```
|
||||
5. Deploy the role
|
||||
6. **Wait for SSO to reach stable**, or use `vaultwarden_version: "testing"` to test now
|
||||
|
||||
**Important**:
|
||||
- The SSO authority must include the full path with application slug
|
||||
- The `offline_access` scope mapping is **required** for Vaultwarden SSO
|
||||
- Access token must be valid for more than 5 minutes
|
||||
- SSO is configured and ready but will activate when stable release includes it
|
||||
|
||||
## Example Vault File
|
||||
|
||||
```yaml
|
||||
---
|
||||
# group_vars/homelab/vault.yml (encrypted with ansible-vault)
|
||||
|
||||
# Vaultwarden - Database
|
||||
vault_vaultwarden_db_password: "xK9mP2nR5tY8wQ3vZ7cB6sA4dF1gH0jL"
|
||||
|
||||
# Vaultwarden - Admin Panel (plain text, will be hashed automatically)
|
||||
vault_vaultwarden_admin_token: "MySecureAdminToken123!"
|
||||
|
||||
# Vaultwarden - SMTP (optional)
|
||||
vault_vaultwarden_smtp_password: "smtp-app-password-here"
|
||||
|
||||
# Vaultwarden - SSO (optional)
|
||||
vault_vaultwarden_sso_client_id: "vaultwarden"
|
||||
vault_vaultwarden_sso_client_secret: "sso-secret-from-authentik"
|
||||
```
|
||||
|
||||
## Vault File Management
|
||||
|
||||
### Encrypt Vault File
|
||||
|
||||
```bash
|
||||
ansible-vault encrypt group_vars/homelab/vault.yml
|
||||
```
|
||||
|
||||
### Edit Vault File
|
||||
|
||||
```bash
|
||||
ansible-vault edit group_vars/homelab/vault.yml
|
||||
```
|
||||
|
||||
### Decrypt Vault File (temporary)
|
||||
|
||||
```bash
|
||||
ansible-vault decrypt group_vars/homelab/vault.yml
|
||||
# Make changes
|
||||
ansible-vault encrypt group_vars/homelab/vault.yml
|
||||
```
|
||||
|
||||
## Security Best Practices
|
||||
|
||||
1. **Never commit unencrypted vault files**
|
||||
2. **Use strong passwords** (32+ characters for database, admin token)
|
||||
3. **Rotate credentials periodically** (especially admin token)
|
||||
4. **Limit vault password access** (use password manager)
|
||||
5. **Use separate passwords** for different services
|
||||
6. **Back up vault password** (secure location, not in git)
|
||||
|
||||
## Verifying Variables
|
||||
|
||||
Test if variables are properly loaded:
|
||||
|
||||
```bash
|
||||
ansible -m debug -a "var=vault_vaultwarden_db_password" homelab --ask-vault-pass
|
||||
```
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Variable not found error
|
||||
|
||||
- Ensure vault file is in correct location: `group_vars/homelab/vault.yml`
|
||||
- Verify file is encrypted: `file group_vars/homelab/vault.yml`
|
||||
- Check variable name matches exactly (case-sensitive)
|
||||
- Provide vault password with `--ask-vault-pass`
|
||||
|
||||
### Admin token not working
|
||||
|
||||
- Verify the plain text token in vault matches what you're entering
|
||||
- Check for extra whitespace in vault file
|
||||
- Ensure the token was hashed successfully during deployment (check ansible output)
|
||||
- Try redeploying the role to regenerate the hash
|
||||
109
roles/vaultwarden/defaults/main.yml
Normal file
109
roles/vaultwarden/defaults/main.yml
Normal file
@@ -0,0 +1,109 @@
|
||||
---
|
||||
# =================================================================
|
||||
# Vaultwarden Password Manager Role - Default Variables
|
||||
# =================================================================
|
||||
# Self-contained Vaultwarden deployment with Podman and PostgreSQL
|
||||
|
||||
# =================================================================
|
||||
# Service Configuration
|
||||
# =================================================================
|
||||
|
||||
# Service user and directories
|
||||
vaultwarden_user: vaultwarden
|
||||
vaultwarden_group: vaultwarden
|
||||
vaultwarden_home: /opt/vaultwarden
|
||||
vaultwarden_data_dir: "{{ vaultwarden_home }}/data"
|
||||
|
||||
# Container configuration
|
||||
# NOTE: SSO feature is only available in "testing" tag (as of Dec 2025)
|
||||
# Using "latest" (stable) means SSO will not appear even if configured
|
||||
# SSO settings below are configured and ready for when feature reaches stable
|
||||
vaultwarden_version: "latest"
|
||||
vaultwarden_image: "vaultwarden/server"
|
||||
|
||||
# Service management
|
||||
vaultwarden_service_enabled: true
|
||||
vaultwarden_service_state: "started"
|
||||
|
||||
# =================================================================
|
||||
# Database Configuration (Self-managed)
|
||||
# =================================================================
|
||||
|
||||
vaultwarden_db_name: "vaultwarden"
|
||||
vaultwarden_db_user: "vaultwarden"
|
||||
vaultwarden_db_password: "{{ vault_vaultwarden_db_password }}"
|
||||
|
||||
# =================================================================
|
||||
# Network Configuration
|
||||
# =================================================================
|
||||
|
||||
vaultwarden_domain: "vault.jnss.me"
|
||||
vaultwarden_http_port: 8080
|
||||
|
||||
# =================================================================
|
||||
# Vaultwarden Core Configuration
|
||||
# =================================================================
|
||||
|
||||
# Admin panel access token (plain text, will be hashed during deployment)
|
||||
vaultwarden_admin_token_plain: "{{ vault_vaultwarden_admin_token }}"
|
||||
|
||||
# Registration and invitation controls
|
||||
vaultwarden_signups_allowed: false # Disable open registration
|
||||
vaultwarden_invitations_allowed: true # Allow existing users to invite
|
||||
vaultwarden_show_password_hint: false # Don't show password hints
|
||||
|
||||
# WebSocket support for live sync
|
||||
vaultwarden_websocket_enabled: true
|
||||
|
||||
# =================================================================
|
||||
# Email Configuration (Optional)
|
||||
# =================================================================
|
||||
|
||||
vaultwarden_smtp_enabled: true
|
||||
vaultwarden_smtp_host: "smtp.titan.email"
|
||||
vaultwarden_smtp_port: 587
|
||||
vaultwarden_smtp_from: "hello@jnss.me"
|
||||
vaultwarden_smtp_username: "hello@jnss.me"
|
||||
vaultwarden_smtp_password: "{{ vault_vaultwarden_smtp_password | default('') }}"
|
||||
vaultwarden_smtp_security: "starttls" # Options: starttls, force_tls, off
|
||||
|
||||
# =================================================================
|
||||
# SSO Configuration (Optional - Authentik Integration)
|
||||
# =================================================================
|
||||
|
||||
vaultwarden_sso_enabled: false
|
||||
|
||||
# SSO Provider Configuration (Authentik)
|
||||
vaultwarden_sso_client_id: "{{ vault_vaultwarden_sso_client_id | default('') }}"
|
||||
vaultwarden_sso_client_secret: "{{ vault_vaultwarden_sso_client_secret | default('') }}"
|
||||
# Authority must include full path with application slug
|
||||
vaultwarden_sso_authority: "https://{{ authentik_domain }}/application/o/vaultwarden/"
|
||||
vaultwarden_sso_scopes: "openid email profile offline_access"
|
||||
|
||||
# Additional SSO settings (per Authentik integration guide)
|
||||
vaultwarden_sso_only: false # Set to true to disable email+password login and require SSO
|
||||
vaultwarden_sso_signups_match_email: true # Match first SSO login to existing account by email
|
||||
vaultwarden_sso_allow_unknown_email_verification: false
|
||||
vaultwarden_sso_client_cache_expiration: 0
|
||||
|
||||
# Domain whitelist for SSO signups (comma-separated domains, empty = all)
|
||||
vaultwarden_sso_signups_domains_whitelist: ""
|
||||
|
||||
# =================================================================
|
||||
# Caddy Integration
|
||||
# =================================================================
|
||||
|
||||
# Caddy configuration (assumes caddy role provides these variables)
|
||||
caddy_sites_enabled_dir: "/etc/caddy/sites-enabled"
|
||||
caddy_log_dir: "/var/log/caddy"
|
||||
caddy_user: "caddy"
|
||||
|
||||
# =================================================================
|
||||
# Infrastructure Dependencies (Read-only)
|
||||
# =================================================================
|
||||
|
||||
# PostgreSQL socket configuration (managed by postgresql role)
|
||||
postgresql_unix_socket_directories: "/var/run/postgresql"
|
||||
postgresql_client_group: "postgres-clients"
|
||||
postgresql_port: 5432
|
||||
postgresql_unix_socket_enabled: true
|
||||
16
roles/vaultwarden/handlers/main.yml
Normal file
16
roles/vaultwarden/handlers/main.yml
Normal file
@@ -0,0 +1,16 @@
|
||||
---
|
||||
# Vaultwarden Password Manager - Service Handlers
|
||||
|
||||
- name: reload systemd
|
||||
systemd:
|
||||
daemon_reload: true
|
||||
|
||||
- name: restart vaultwarden
|
||||
systemd:
|
||||
name: vaultwarden
|
||||
state: restarted
|
||||
|
||||
- name: reload caddy
|
||||
systemd:
|
||||
name: caddy
|
||||
state: reloaded
|
||||
25
roles/vaultwarden/meta/main.yml
Normal file
25
roles/vaultwarden/meta/main.yml
Normal file
@@ -0,0 +1,25 @@
|
||||
---
|
||||
# Vaultwarden Password Manager - Role Metadata
|
||||
|
||||
dependencies:
|
||||
- role: postgresql
|
||||
- role: caddy
|
||||
|
||||
galaxy_info:
|
||||
author: Rick Infrastructure Team
|
||||
description: Vaultwarden password manager deployment with PostgreSQL and Caddy
|
||||
license: MIT
|
||||
min_ansible_version: "2.14"
|
||||
|
||||
platforms:
|
||||
- name: ArchLinux
|
||||
versions:
|
||||
- all
|
||||
|
||||
galaxy_tags:
|
||||
- vaultwarden
|
||||
- bitwarden
|
||||
- password-manager
|
||||
- security
|
||||
- postgresql
|
||||
- podman
|
||||
51
roles/vaultwarden/tasks/database.yml
Normal file
51
roles/vaultwarden/tasks/database.yml
Normal file
@@ -0,0 +1,51 @@
|
||||
---
|
||||
# Database setup for Vaultwarden - PostgreSQL via Unix Socket
|
||||
|
||||
- name: Test PostgreSQL socket connectivity
|
||||
postgresql_ping:
|
||||
login_unix_socket: "{{ postgresql_unix_socket_directories }}"
|
||||
login_user: "{{ vaultwarden_user }}"
|
||||
become: true
|
||||
become_user: "{{ vaultwarden_user }}"
|
||||
|
||||
- name: Create Vaultwarden database user via socket
|
||||
postgresql_user:
|
||||
name: "{{ vaultwarden_db_user }}"
|
||||
password: "{{ vaultwarden_db_password }}"
|
||||
login_unix_socket: "{{ postgresql_unix_socket_directories }}"
|
||||
login_user: postgres
|
||||
become: true
|
||||
become_user: postgres
|
||||
|
||||
- name: Create Vaultwarden database via socket
|
||||
postgresql_db:
|
||||
name: "{{ vaultwarden_db_name }}"
|
||||
owner: "{{ vaultwarden_db_user }}"
|
||||
encoding: UTF8
|
||||
template: template0
|
||||
login_unix_socket: "{{ postgresql_unix_socket_directories }}"
|
||||
login_user: postgres
|
||||
become: true
|
||||
become_user: postgres
|
||||
|
||||
- name: Grant Vaultwarden database privileges
|
||||
postgresql_privs:
|
||||
db: "{{ vaultwarden_db_name }}"
|
||||
privs: ALL
|
||||
type: database
|
||||
role: "{{ vaultwarden_db_user }}"
|
||||
login_unix_socket: "{{ postgresql_unix_socket_directories }}"
|
||||
login_user: postgres
|
||||
become: true
|
||||
become_user: postgres
|
||||
|
||||
- name: Display database setup status
|
||||
debug:
|
||||
msg: |
|
||||
Vaultwarden database setup complete!
|
||||
|
||||
Database: {{ vaultwarden_db_name }}
|
||||
User: {{ vaultwarden_db_user }}
|
||||
Connection: Unix socket ({{ postgresql_unix_socket_directories }})
|
||||
|
||||
Ready for Vaultwarden container deployment
|
||||
57
roles/vaultwarden/tasks/hash_admin_token.yml
Normal file
57
roles/vaultwarden/tasks/hash_admin_token.yml
Normal file
@@ -0,0 +1,57 @@
|
||||
---
|
||||
# Hash admin token on Ansible control node using argon2
|
||||
|
||||
- name: Check if argon2 is available on control node
|
||||
command: which argon2
|
||||
register: argon2_check
|
||||
delegate_to: localhost
|
||||
become: false
|
||||
changed_when: false
|
||||
failed_when: false
|
||||
|
||||
- name: Install argon2 on control node if not present
|
||||
package:
|
||||
name: argon2
|
||||
state: present
|
||||
delegate_to: localhost
|
||||
become: false
|
||||
when: argon2_check.rc != 0
|
||||
run_once: true
|
||||
|
||||
- name: Generate deterministic salt from domain
|
||||
set_fact:
|
||||
vaultwarden_salt_source: "{{ vaultwarden_domain }}-{{ vaultwarden_sso_authority }}"
|
||||
no_log: true
|
||||
|
||||
- name: Create base64-encoded salt for argon2
|
||||
shell: echo -n "{{ vaultwarden_salt_source }}" | sha256sum | cut -d' ' -f1 | head -c 22
|
||||
register: admin_token_salt
|
||||
delegate_to: localhost
|
||||
become: false
|
||||
changed_when: false
|
||||
no_log: true
|
||||
|
||||
- name: Hash admin token using argon2 (OWASP preset)
|
||||
shell: echo -n "{{ vaultwarden_admin_token_plain }}" | argon2 "{{ admin_token_salt.stdout }}" -id -t 2 -k 19456 -p 1 -e
|
||||
register: admin_token_hash_result
|
||||
delegate_to: localhost
|
||||
become: false
|
||||
changed_when: false
|
||||
no_log: true
|
||||
|
||||
- name: Extract hashed admin token
|
||||
set_fact:
|
||||
vaultwarden_admin_token_hashed: "{{ admin_token_hash_result.stdout | trim }}"
|
||||
no_log: true
|
||||
|
||||
- name: Display token hash status
|
||||
debug:
|
||||
msg: |
|
||||
Admin token hashed successfully on control node
|
||||
|
||||
Hash algorithm: argon2id
|
||||
Preset: OWASP (m=19456, t=2, p=1)
|
||||
Format: PHC string (Vaultwarden compatible)
|
||||
Idempotent: Same token always produces same hash
|
||||
|
||||
The hashed token will be used in the environment configuration
|
||||
108
roles/vaultwarden/tasks/main.yml
Normal file
108
roles/vaultwarden/tasks/main.yml
Normal file
@@ -0,0 +1,108 @@
|
||||
---
|
||||
# Vaultwarden Password Manager Role - Main Tasks
|
||||
# Self-contained deployment with Podman and Unix sockets
|
||||
|
||||
- name: Setup vaultwarden user and directories
|
||||
include_tasks: user.yml
|
||||
tags: [user, setup]
|
||||
|
||||
- name: Setup database access and permissions
|
||||
include_tasks: database.yml
|
||||
tags: [database, setup]
|
||||
|
||||
- name: Pull vaultwarden container image
|
||||
containers.podman.podman_image:
|
||||
name: "{{ vaultwarden_image }}:{{ vaultwarden_version }}"
|
||||
state: present
|
||||
tags: [containers, image-pull]
|
||||
|
||||
- name: Hash admin token on host
|
||||
include_tasks: hash_admin_token.yml
|
||||
tags: [config, admin-token]
|
||||
|
||||
- name: Deploy environment configuration
|
||||
template:
|
||||
src: vaultwarden.env.j2
|
||||
dest: "{{ vaultwarden_home }}/.env"
|
||||
owner: "{{ vaultwarden_user }}"
|
||||
group: "{{ vaultwarden_group }}"
|
||||
mode: '0600'
|
||||
backup: true
|
||||
notify:
|
||||
- restart vaultwarden
|
||||
tags: [config]
|
||||
|
||||
- name: Create Quadlet systemd directory
|
||||
file:
|
||||
path: /etc/containers/systemd
|
||||
state: directory
|
||||
mode: '0755'
|
||||
|
||||
- name: Deploy Quadlet container file
|
||||
template:
|
||||
src: vaultwarden.container
|
||||
dest: /etc/containers/systemd/vaultwarden.container
|
||||
mode: '0644'
|
||||
notify:
|
||||
- reload systemd
|
||||
- restart vaultwarden
|
||||
tags: [containers, deployment]
|
||||
|
||||
- name: Deploy Caddy configuration
|
||||
template:
|
||||
src: vaultwarden.caddy.j2
|
||||
dest: "{{ caddy_sites_enabled_dir }}/vaultwarden.caddy"
|
||||
owner: root
|
||||
group: "{{ caddy_user }}"
|
||||
mode: '0644'
|
||||
backup: true
|
||||
notify: reload caddy
|
||||
tags: [caddy, reverse-proxy]
|
||||
|
||||
- name: Ensure PostgreSQL is running
|
||||
systemd:
|
||||
name: postgresql
|
||||
state: started
|
||||
|
||||
- name: Wait for PostgreSQL socket to be ready
|
||||
wait_for:
|
||||
path: "{{ postgresql_unix_socket_directories }}/.s.PGSQL.{{ postgresql_port }}"
|
||||
timeout: 30
|
||||
when: postgresql_unix_socket_enabled
|
||||
|
||||
- name: Enable and start Vaultwarden service (system scope)
|
||||
systemd:
|
||||
name: vaultwarden
|
||||
enabled: "{{ vaultwarden_service_enabled }}"
|
||||
state: "{{ vaultwarden_service_state }}"
|
||||
daemon_reload: true
|
||||
tags: [containers, service]
|
||||
|
||||
- name: Wait for Vaultwarden to be ready
|
||||
uri:
|
||||
url: "http://127.0.0.1:{{ vaultwarden_http_port }}/"
|
||||
method: GET
|
||||
status_code: [200, 302]
|
||||
timeout: 30
|
||||
retries: 10
|
||||
delay: 15
|
||||
register: vaultwarden_health_check
|
||||
tags: [verification, health-check]
|
||||
|
||||
- name: Display Vaultwarden deployment status
|
||||
debug:
|
||||
msg: |
|
||||
Vaultwarden Password Manager deployed successfully!
|
||||
|
||||
Domain: {{ vaultwarden_domain }}
|
||||
Database: {{ vaultwarden_db_name }} (Unix socket)
|
||||
Container: {{ vaultwarden_image }}:{{ vaultwarden_version }}
|
||||
Admin Panel: https://{{ vaultwarden_domain }}/admin
|
||||
|
||||
Ready for user registration and password management!
|
||||
|
||||
Next Steps:
|
||||
- Access https://{{ vaultwarden_domain }}/admin with your admin token
|
||||
- Configure additional settings (SMTP, SSO, etc.)
|
||||
- Invite users or create accounts
|
||||
tags: [verification]
|
||||
28
roles/vaultwarden/tasks/user.yml
Normal file
28
roles/vaultwarden/tasks/user.yml
Normal file
@@ -0,0 +1,28 @@
|
||||
---
|
||||
# Vaultwarden User Management - Service-Specific User Setup
|
||||
|
||||
- name: Create vaultwarden group
|
||||
group:
|
||||
name: "{{ vaultwarden_group }}"
|
||||
system: true
|
||||
|
||||
- name: Create vaultwarden user
|
||||
user:
|
||||
name: "{{ vaultwarden_user }}"
|
||||
group: "{{ vaultwarden_group }}"
|
||||
system: true
|
||||
shell: /bin/bash
|
||||
home: "{{ vaultwarden_home }}"
|
||||
create_home: true
|
||||
comment: "Vaultwarden password manager service"
|
||||
|
||||
- name: Create vaultwarden directories
|
||||
file:
|
||||
path: "{{ item }}"
|
||||
state: directory
|
||||
owner: "{{ vaultwarden_user }}"
|
||||
group: "{{ vaultwarden_group }}"
|
||||
mode: '0755'
|
||||
loop:
|
||||
- "{{ vaultwarden_home }}"
|
||||
- "{{ vaultwarden_data_dir }}"
|
||||
35
roles/vaultwarden/templates/vaultwarden.caddy.j2
Normal file
35
roles/vaultwarden/templates/vaultwarden.caddy.j2
Normal file
@@ -0,0 +1,35 @@
|
||||
# Vaultwarden Password Manager
|
||||
{{ vaultwarden_domain }} {
|
||||
# Notifications endpoint (WebSocket for live sync)
|
||||
@websocket {
|
||||
path /notifications/hub
|
||||
}
|
||||
reverse_proxy @websocket http://127.0.0.1:{{ vaultwarden_http_port }} {
|
||||
header_up Upgrade {http.request.header.Upgrade}
|
||||
header_up Connection {http.request.header.Connection}
|
||||
}
|
||||
|
||||
# Regular HTTP traffic
|
||||
reverse_proxy http://127.0.0.1:{{ vaultwarden_http_port }} {
|
||||
header_up Host {host}
|
||||
header_up X-Real-IP {remote_host}
|
||||
header_up X-Forwarded-Proto https
|
||||
header_up X-Forwarded-For {remote_host}
|
||||
}
|
||||
|
||||
# Security headers
|
||||
header {
|
||||
X-Frame-Options SAMEORIGIN
|
||||
X-Content-Type-Options nosniff
|
||||
X-XSS-Protection "1; mode=block"
|
||||
Referrer-Policy strict-origin-when-cross-origin
|
||||
Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
|
||||
}
|
||||
|
||||
# Logging
|
||||
log {
|
||||
output file {{ caddy_log_dir }}/vaultwarden.log
|
||||
level INFO
|
||||
format json
|
||||
}
|
||||
}
|
||||
26
roles/vaultwarden/templates/vaultwarden.container
Normal file
26
roles/vaultwarden/templates/vaultwarden.container
Normal file
@@ -0,0 +1,26 @@
|
||||
[Unit]
|
||||
Description=Vaultwarden Password Manager Container
|
||||
After=network-online.target postgresql.service
|
||||
Wants=network-online.target
|
||||
|
||||
[Container]
|
||||
ContainerName=vaultwarden
|
||||
Image={{ vaultwarden_image }}:{{ vaultwarden_version }}
|
||||
EnvironmentFile={{ vaultwarden_home }}/.env
|
||||
|
||||
# Volume mounts
|
||||
# Application data (includes database, attachments, sends, icons, etc.)
|
||||
Volume={{ vaultwarden_data_dir }}:/data:Z
|
||||
|
||||
# Infrastructure socket (PostgreSQL access with 777 permissions on host)
|
||||
Volume={{ postgresql_unix_socket_directories }}:{{ postgresql_unix_socket_directories }}:Z
|
||||
|
||||
# Expose HTTP port to localhost only (Caddy will reverse proxy)
|
||||
PublishPort=127.0.0.1:{{ vaultwarden_http_port }}:80
|
||||
|
||||
[Service]
|
||||
Restart=always
|
||||
TimeoutStartSec=300
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
73
roles/vaultwarden/templates/vaultwarden.env.j2
Normal file
73
roles/vaultwarden/templates/vaultwarden.env.j2
Normal file
@@ -0,0 +1,73 @@
|
||||
# Vaultwarden Environment Configuration
|
||||
# Generated by Ansible - DO NOT EDIT MANUALLY
|
||||
|
||||
# =================================================================
|
||||
# Database Configuration (PostgreSQL via Unix Socket)
|
||||
# =================================================================
|
||||
DATABASE_URL=postgresql://{{ vaultwarden_db_user }}:{{ vaultwarden_db_password }}@/{{ vaultwarden_db_name }}?host={{ postgresql_unix_socket_directories }}
|
||||
|
||||
# =================================================================
|
||||
# Domain Configuration
|
||||
# =================================================================
|
||||
DOMAIN=https://{{ vaultwarden_domain }}
|
||||
|
||||
# =================================================================
|
||||
# Admin Configuration
|
||||
# =================================================================
|
||||
ADMIN_TOKEN={{ vaultwarden_admin_token_hashed }}
|
||||
|
||||
# =================================================================
|
||||
# Registration and Invitation Controls
|
||||
# =================================================================
|
||||
SIGNUPS_ALLOWED={{ vaultwarden_signups_allowed | lower }}
|
||||
INVITATIONS_ALLOWED={{ vaultwarden_invitations_allowed | lower }}
|
||||
SHOW_PASSWORD_HINT={{ vaultwarden_show_password_hint | lower }}
|
||||
|
||||
# =================================================================
|
||||
# WebSocket Configuration (for live sync)
|
||||
# =================================================================
|
||||
WEBSOCKET_ENABLED={{ vaultwarden_websocket_enabled | lower }}
|
||||
|
||||
# =================================================================
|
||||
# SMTP Configuration (Optional)
|
||||
# =================================================================
|
||||
{% if vaultwarden_smtp_enabled %}
|
||||
SMTP_HOST={{ vaultwarden_smtp_host }}
|
||||
SMTP_PORT={{ vaultwarden_smtp_port }}
|
||||
SMTP_FROM={{ vaultwarden_smtp_from }}
|
||||
SMTP_SECURITY={{ vaultwarden_smtp_security }}
|
||||
{% if vaultwarden_smtp_username %}
|
||||
SMTP_USERNAME={{ vaultwarden_smtp_username }}
|
||||
SMTP_PASSWORD={{ vaultwarden_smtp_password }}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
# =================================================================
|
||||
# SSO Configuration (Optional - Authentik Integration)
|
||||
# =================================================================
|
||||
{% if vaultwarden_sso_enabled %}
|
||||
SSO_ENABLED=true
|
||||
SSO_ONLY={{ vaultwarden_sso_only | lower }}
|
||||
SSO_CLIENT_ID={{ vaultwarden_sso_client_id }}
|
||||
SSO_CLIENT_SECRET={{ vaultwarden_sso_client_secret }}
|
||||
SSO_AUTHORITY={{ vaultwarden_sso_authority }}
|
||||
SSO_SCOPES="{{ vaultwarden_sso_scopes }}"
|
||||
SSO_SIGNUPS_MATCH_EMAIL={{ vaultwarden_sso_signups_match_email | lower }}
|
||||
SSO_ALLOW_UNKNOWN_EMAIL_VERIFICATION={{ vaultwarden_sso_allow_unknown_email_verification | lower }}
|
||||
SSO_CLIENT_CACHE_EXPIRATION={{ vaultwarden_sso_client_cache_expiration }}
|
||||
{% if vaultwarden_sso_signups_domains_whitelist %}
|
||||
SSO_SIGNUPS_DOMAINS_WHITELIST={{ vaultwarden_sso_signups_domains_whitelist }}
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
|
||||
# =================================================================
|
||||
# Security and Performance
|
||||
# =================================================================
|
||||
# Disable user registration via email (use admin panel or invitations)
|
||||
SIGNUPS_VERIFY=false
|
||||
|
||||
# Log level (trace, debug, info, warn, error, off)
|
||||
LOG_LEVEL=info
|
||||
|
||||
# Rocket configuration
|
||||
ROCKET_WORKERS=10
|
||||
Reference in New Issue
Block a user