feat(infra): add Jellyfin media server configuration and logging support
Add Jellyfin service to ansible inventory with hardware transcoding and Casdoor SSO configuration. Configure Alloy syslog listener to capture Jellyfin logs to Loki. Update documentation with new service mapping and S3 bucket credential retrieval instructions.
This commit is contained in:
@@ -75,6 +75,21 @@ loki.source.syslog "lobechat_logs" {
|
|||||||
forward_to = [loki.write.default.receiver]
|
forward_to = [loki.write.default.receiver]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Jellyfin Docker syslog
|
||||||
|
loki.source.syslog "jellyfin_logs" {
|
||||||
|
listener {
|
||||||
|
address = "127.0.0.1:{{ jellyfin_syslog_port }}"
|
||||||
|
protocol = "tcp"
|
||||||
|
syslog_format = "{{ syslog_format }}"
|
||||||
|
labels = {
|
||||||
|
job = "jellyfin",
|
||||||
|
hostname = "{{inventory_hostname}}",
|
||||||
|
environment = "{{deployment_environment}}",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
forward_to = [loki.write.default.receiver]
|
||||||
|
}
|
||||||
|
|
||||||
loki.source.syslog "searxng_logs" {
|
loki.source.syslog "searxng_logs" {
|
||||||
listener {
|
listener {
|
||||||
address = "127.0.0.1:{{searxng_syslog_port}}"
|
address = "127.0.0.1:{{searxng_syslog_port}}"
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ services:
|
|||||||
- anythingllm
|
- anythingllm
|
||||||
- docker
|
- docker
|
||||||
- gitea
|
- gitea
|
||||||
|
- jellyfin
|
||||||
- lobechat
|
- lobechat
|
||||||
- memcached
|
- memcached
|
||||||
- nextcloud
|
- nextcloud
|
||||||
@@ -237,3 +238,30 @@ searxng_oauth2_redirect_url: "https://searxng.ouranos.helu.ca/oauth2/callback"
|
|||||||
searxng_oauth2_client_id: "{{ vault_searxng_oauth_client_id }}"
|
searxng_oauth2_client_id: "{{ vault_searxng_oauth_client_id }}"
|
||||||
searxng_oauth2_client_secret: "{{ vault_searxng_oauth_client_secret }}"
|
searxng_oauth2_client_secret: "{{ vault_searxng_oauth_client_secret }}"
|
||||||
searxng_oauth2_cookie_secret: "{{ vault_searxng_oauth_cookie_secret }}"
|
searxng_oauth2_cookie_secret: "{{ vault_searxng_oauth_cookie_secret }}"
|
||||||
|
|
||||||
|
# Jellyfin Configuration
|
||||||
|
jellyfin_user: jellyfin
|
||||||
|
jellyfin_group: jellyfin
|
||||||
|
jellyfin_uid: 521
|
||||||
|
jellyfin_gid: 521
|
||||||
|
jellyfin_directory: /srv/jellyfin
|
||||||
|
jellyfin_port: 22086
|
||||||
|
jellyfin_syslog_port: 51426
|
||||||
|
|
||||||
|
# Storage paths
|
||||||
|
jellyfin_config_dir: /srv/jellyfin/config
|
||||||
|
jellyfin_cache_dir: /srv/jellyfin/cache
|
||||||
|
jellyfin_media_dir: /mnt/media
|
||||||
|
|
||||||
|
# Hardware transcoding (NVIDIA GPU passthrough)
|
||||||
|
jellyfin_enable_hwtranscode: true
|
||||||
|
|
||||||
|
# External access URL
|
||||||
|
jellyfin_published_server_url: "https://jellyfin.ouranos.helu.ca"
|
||||||
|
|
||||||
|
# SSO / OIDC Configuration (Casdoor)
|
||||||
|
jellyfin_sso_enabled: true
|
||||||
|
jellyfin_casdoor_client_id: "{{ vault_jellyfin_casdoor_client_id }}"
|
||||||
|
jellyfin_casdoor_client_secret: "{{ vault_jellyfin_casdoor_client_secret }}"
|
||||||
|
jellyfin_casdoor_issuer: "https://id.ouranos.helu.ca"
|
||||||
|
jellyfin_casdoor_redirect_uri: "https://jellyfin.ouranos.helu.ca/api/plugin/sso/callback"
|
||||||
|
|||||||
149
ansible/jellyfin/README.md
Normal file
149
ansible/jellyfin/README.md
Normal file
@@ -0,0 +1,149 @@
|
|||||||
|
---
|
||||||
|
# Jellyfin Deployment for Ouranos
|
||||||
|
|
||||||
|
Jellyfin media server deployed on Rosalind Incus container.
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
Jellyfin is an open-source media server for organizing, streaming, and managing media content. This deployment includes:
|
||||||
|
|
||||||
|
- Docker containerized deployment
|
||||||
|
- NVIDIA GPU passthrough for hardware-accelerated transcoding
|
||||||
|
- Prometheus metrics collection
|
||||||
|
- Syslog integration with Grafana Alloy
|
||||||
|
- Casdoor OIDC SSO support (via plugin)
|
||||||
|
|
||||||
|
## Deployment
|
||||||
|
|
||||||
|
### Prerequisites
|
||||||
|
|
||||||
|
1. Rosalind Incus container must be running with Docker installed
|
||||||
|
2. `/mnt/media` must be accessible from the Incus host
|
||||||
|
3. NVIDIA GPU must be passed through to the Rosalind container
|
||||||
|
4. Casdoor application must be configured for Jellyfin OIDC
|
||||||
|
|
||||||
|
### Installation
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# From ansible directory
|
||||||
|
cd /home/robert/git/ouranos/ansible
|
||||||
|
|
||||||
|
# Deploy Jellyfin to Rosalind
|
||||||
|
ansible-playbook jellyfin/deploy.yml --limit rosalind.incus
|
||||||
|
```
|
||||||
|
|
||||||
|
### Updating
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Update Jellyfin container
|
||||||
|
ansible-playbook jellyfin/deploy.yml --limit rosalind.incus
|
||||||
|
```
|
||||||
|
|
||||||
|
## Configuration
|
||||||
|
|
||||||
|
### Variables
|
||||||
|
|
||||||
|
| Variable | Description | Default |
|
||||||
|
|----------|-------------|---------|
|
||||||
|
| `jellyfin_user` | Service username | `jellyfin` |
|
||||||
|
| `jellyfin_group` | Service group name | `jellyfin` |
|
||||||
|
| `jellyfin_uid` | Service UID | `521` |
|
||||||
|
| `jellyfin_gid` | Service GID | `521` |
|
||||||
|
| `jellyfin_directory` | Base directory | `/srv/jellyfin` |
|
||||||
|
| `jellyfin_port` | HTTP port | `22086` |
|
||||||
|
| `jellyfin_syslog_port` | Syslog port | `51426` |
|
||||||
|
| `jellyfin_config_dir` | Config directory | `/srv/jellyfin/config` |
|
||||||
|
| `jellyfin_cache_dir` | Cache directory | `/srv/jellyfin/cache` |
|
||||||
|
| `jellyfin_media_dir` | Media bind mount | `/mnt/media` |
|
||||||
|
| `jellyfin_published_server_url` | External URL | `https://jellyfin.ouranos.helu.ca` |
|
||||||
|
|
||||||
|
### SSO Configuration
|
||||||
|
|
||||||
|
Jellyfin uses the `jellyfin-plugin-sso` community plugin for Casdoor OIDC authentication:
|
||||||
|
|
||||||
|
1. **Create Casdoor Application**:
|
||||||
|
- Application type: OIDC
|
||||||
|
- Callback URL: `https://jellyfin.ouranos.helu.ca/api/plugin/sso/callback`
|
||||||
|
- Enable PKCE
|
||||||
|
|
||||||
|
2. **Plugin Configuration**:
|
||||||
|
- Install manifest in `/config/plugins`
|
||||||
|
- Configure with Casdoor OIDC endpoints
|
||||||
|
|
||||||
|
3. **Casdoor Endpoints**:
|
||||||
|
- Authorization: `https://id.ouranos.helu.ca/oauth2/authorize`
|
||||||
|
- Token: `https://id.ouranos.helu.ca/oauth2/token`
|
||||||
|
- Userinfo: `https://id.ouranos.helu.ca/oauth2/userinfo`
|
||||||
|
|
||||||
|
## Monitoring
|
||||||
|
|
||||||
|
### Prometheus Metrics
|
||||||
|
|
||||||
|
Jellyfin exposes metrics at `http://localhost:8096/metrics`. These are collected by Prospero's Prometheus via:
|
||||||
|
|
||||||
|
- cAdvisor container metrics
|
||||||
|
- Process exporter
|
||||||
|
|
||||||
|
### Grafana Dashboard
|
||||||
|
|
||||||
|
Add a new data source in Grafana:
|
||||||
|
- Type: Prometheus
|
||||||
|
- URL: `http://prospero.incus:9090`
|
||||||
|
|
||||||
|
### Logs
|
||||||
|
|
||||||
|
View Jellyfin logs:
|
||||||
|
```bash
|
||||||
|
# Via Docker
|
||||||
|
docker logs -f jellyfin
|
||||||
|
|
||||||
|
# Via systemd
|
||||||
|
journalctl -u jellyfin -f
|
||||||
|
|
||||||
|
# Via Grafana Loki
|
||||||
|
https://loki.ouranos.helu.ca/explore?orgId=1&left=%5B%22now-1h%22,%22now%22,%22jellyfin%22,%7B%22job%22%3A%22jellyfin%22%7D%5D
|
||||||
|
```
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
### Container won't start
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Check Docker status
|
||||||
|
docker ps -a | grep jellyfin
|
||||||
|
|
||||||
|
# Check logs
|
||||||
|
docker logs jellyfin
|
||||||
|
|
||||||
|
# Verify GPU passthrough
|
||||||
|
ls -la /dev/dri/
|
||||||
|
```
|
||||||
|
|
||||||
|
### Transcoding fails
|
||||||
|
|
||||||
|
1. Verify GPU is accessible: `nvidia-smi`
|
||||||
|
2. Check container has device access: `docker inspect jellyfin | grep Devices`
|
||||||
|
3. Review logs for transcoding errors
|
||||||
|
|
||||||
|
### SSO not working
|
||||||
|
|
||||||
|
1. Verify plugin is installed in `/config/plugins`
|
||||||
|
2. Check Casdoor application configuration
|
||||||
|
3. Verify redirect URLs match exactly
|
||||||
|
4. Browser console for OAuth errors
|
||||||
|
|
||||||
|
## Files
|
||||||
|
|
||||||
|
| Path | Description |
|
||||||
|
|------|-------------|
|
||||||
|
| `/srv/jellyfin/docker-compose.yml` | Generated Docker Compose config |
|
||||||
|
| `/etc/systemd/system/jellyfin.service` | Systemd wrapper service |
|
||||||
|
| `/srv/jellyfin/config` | Jellyfin configuration |
|
||||||
|
| `/srv/jellyfin/cache` | Transcode cache |
|
||||||
|
| `/srv/jellyfin/logs` | Application logs (via syslog) |
|
||||||
|
|
||||||
|
## References
|
||||||
|
|
||||||
|
- [Jellyfin Official Docs](https://jellyfin.org/docs/)
|
||||||
|
- [Jellyfin Docker Image](https://hub.docker.com/r/jellyfin/jellyfin)
|
||||||
|
- [SSO Plugin GitHub](https://github.com/9p4/jellyfin-plugin-sso)
|
||||||
107
ansible/jellyfin/deploy.yml
Normal file
107
ansible/jellyfin/deploy.yml
Normal file
@@ -0,0 +1,107 @@
|
|||||||
|
---
|
||||||
|
- name: Deploy Jellyfin
|
||||||
|
hosts: ubuntu
|
||||||
|
become: true
|
||||||
|
vars:
|
||||||
|
ansible_python_interpreter: /usr/bin/python3
|
||||||
|
tasks:
|
||||||
|
- name: Check if host has jellyfin service
|
||||||
|
ansible.builtin.set_fact:
|
||||||
|
has_jellyfin: "{{ 'jellyfin' in services | default([]) }}"
|
||||||
|
|
||||||
|
- name: Skip hosts without jellyfin service
|
||||||
|
ansible.builtin.meta: end_host
|
||||||
|
when: not has_jellyfin
|
||||||
|
|
||||||
|
- name: Create jellyfin group
|
||||||
|
ansible.builtin.group:
|
||||||
|
name: "{{ jellyfin_group }}"
|
||||||
|
gid: "{{ jellyfin_gid }}"
|
||||||
|
|
||||||
|
- name: Create jellyfin user
|
||||||
|
ansible.builtin.user:
|
||||||
|
name: "{{ jellyfin_user }}"
|
||||||
|
comment: "Jellyfin service account"
|
||||||
|
group: "{{ jellyfin_group }}"
|
||||||
|
uid: "{{ jellyfin_uid }}"
|
||||||
|
home: "{{ jellyfin_directory }}"
|
||||||
|
system: true
|
||||||
|
shell: /bin/bash
|
||||||
|
|
||||||
|
- name: Add keeper_user to jellyfin group
|
||||||
|
ansible.builtin.user:
|
||||||
|
name: "{{ keeper_user }}"
|
||||||
|
groups: "{{ jellyfin_group }}"
|
||||||
|
append: true
|
||||||
|
|
||||||
|
- name: Create Jellyfin directories
|
||||||
|
ansible.builtin.file:
|
||||||
|
path: "{{ item }}"
|
||||||
|
owner: "{{ jellyfin_user }}"
|
||||||
|
group: "{{ jellyfin_group }}"
|
||||||
|
state: directory
|
||||||
|
mode: '0750'
|
||||||
|
loop:
|
||||||
|
- "{{ jellyfin_directory }}"
|
||||||
|
- "{{ jellyfin_config_dir }}"
|
||||||
|
- "{{ jellyfin_cache_dir }}"
|
||||||
|
|
||||||
|
- name: Check if Docker is installed
|
||||||
|
ansible.builtin.stat:
|
||||||
|
path: /var/run/docker.sock
|
||||||
|
register: docker_socket
|
||||||
|
|
||||||
|
- name: Deploy Docker Compose configuration
|
||||||
|
ansible.builtin.template:
|
||||||
|
src: docker-compose.yml.j2
|
||||||
|
dest: "{{ jellyfin_directory }}/docker-compose.yml"
|
||||||
|
owner: "{{ jellyfin_user }}"
|
||||||
|
group: "{{ jellyfin_group }}"
|
||||||
|
mode: '0644'
|
||||||
|
notify:
|
||||||
|
- Stop Jellyfin
|
||||||
|
- Pull Jellyfin image
|
||||||
|
- Start Jellyfin
|
||||||
|
|
||||||
|
- name: Create systemd service for Docker Compose
|
||||||
|
ansible.builtin.template:
|
||||||
|
src: jellyfin.service.j2
|
||||||
|
dest: /etc/systemd/system/jellyfin.service
|
||||||
|
mode: '0644'
|
||||||
|
notify:
|
||||||
|
- Reload systemd
|
||||||
|
- Enable Jellyfin
|
||||||
|
- Start Jellyfin
|
||||||
|
|
||||||
|
handlers:
|
||||||
|
- name: Reload systemd
|
||||||
|
ansible.builtin.systemd:
|
||||||
|
daemon_reload: true
|
||||||
|
|
||||||
|
- name: Stop Jellyfin
|
||||||
|
ansible.builtin.command:
|
||||||
|
cmd: "docker compose down"
|
||||||
|
chdir: "{{ jellyfin_directory }}"
|
||||||
|
become_user: "{{ jellyfin_user }}"
|
||||||
|
become: true
|
||||||
|
|
||||||
|
- name: Pull Jellyfin image
|
||||||
|
ansible.builtin.command:
|
||||||
|
cmd: "docker compose pull"
|
||||||
|
chdir: "{{ jellyfin_directory }}"
|
||||||
|
become_user: "{{ jellyfin_user }}"
|
||||||
|
become: true
|
||||||
|
|
||||||
|
- name: Start Jellyfin
|
||||||
|
ansible.builtin.command:
|
||||||
|
cmd: "docker compose up -d"
|
||||||
|
chdir: "{{ jellyfin_directory }}"
|
||||||
|
become_user: "{{ jellyfin_user }}"
|
||||||
|
become: true
|
||||||
|
|
||||||
|
- name: Enable Jellyfin
|
||||||
|
ansible.builtin.systemd:
|
||||||
|
name: jellyfin
|
||||||
|
enabled: true
|
||||||
|
state: started
|
||||||
|
daemon_reload: true
|
||||||
34
ansible/jellyfin/docker-compose.yml.j2
Normal file
34
ansible/jellyfin/docker-compose.yml.j2
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
---
|
||||||
|
services:
|
||||||
|
jellyfin:
|
||||||
|
image: jellyfin/jellyfin:latest
|
||||||
|
container_name: jellyfin
|
||||||
|
user: "{{ jellyfin_uid }}:{{ jellyfin_gid }}"
|
||||||
|
ports:
|
||||||
|
- "{{ jellyfin_port }}:8096/tcp"
|
||||||
|
- "7359:7359/udp"
|
||||||
|
volumes:
|
||||||
|
- "{{ jellyfin_config_dir }}:/config"
|
||||||
|
- "{{ jellyfin_cache_dir }}:/cache"
|
||||||
|
- "{{ jellyfin_media_dir }}:/media:ro"
|
||||||
|
restart: unless-stopped
|
||||||
|
devices:
|
||||||
|
- /dev/dri:/dev/dri
|
||||||
|
healthcheck:
|
||||||
|
test: ["CMD", "curl", "-f", "http://localhost:8096/dashboard"]
|
||||||
|
interval: 30s
|
||||||
|
timeout: 10s
|
||||||
|
retries: 3
|
||||||
|
start_period: 40s
|
||||||
|
logging:
|
||||||
|
driver: syslog
|
||||||
|
options:
|
||||||
|
syslog-address: "udp://prospero.incus:1514"
|
||||||
|
tag: "jellyfin"
|
||||||
|
environment:
|
||||||
|
- PUID={{ jellyfin_uid }}
|
||||||
|
- PGID={{ jellyfin_gid }}
|
||||||
|
- TZ=America/Toronto
|
||||||
|
- JELLYFIN_PublishedServerUrl={{ jellyfin_published_server_url }}
|
||||||
|
extra_hosts:
|
||||||
|
- "host.docker.internal:host-gateway"
|
||||||
18
ansible/jellyfin/jellyfin.service.j2
Normal file
18
ansible/jellyfin/jellyfin.service.j2
Normal file
@@ -0,0 +1,18 @@
|
|||||||
|
---
|
||||||
|
[Unit]
|
||||||
|
Description=Jellyfin Docker Compose Service
|
||||||
|
After=docker.service
|
||||||
|
Requires=docker.service
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=oneshot
|
||||||
|
RemainAfterExit=yes
|
||||||
|
WorkingDirectory={{ jellyfin_directory }}
|
||||||
|
User={{ jellyfin_user }}
|
||||||
|
ExecStart=/usr/bin/docker compose up -d
|
||||||
|
ExecStop=/usr/bin/docker compose down
|
||||||
|
Restart=on-failure
|
||||||
|
RestartSec=30
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=default.target
|
||||||
@@ -126,6 +126,7 @@ Witty and resourceful moon for PHP, Go, and Node.js runtimes.
|
|||||||
- LobeChat AI chat interface (port 22081)
|
- LobeChat AI chat interface (port 22081)
|
||||||
- Nextcloud file sharing and collaboration (port 22083)
|
- Nextcloud file sharing and collaboration (port 22083)
|
||||||
- AnythingLLM document AI workspace (port 22084)
|
- AnythingLLM document AI workspace (port 22084)
|
||||||
|
- Jellyfin media server (port 22086, NVIDIA transcoding, Casdoor SSO)
|
||||||
- Nextcloud data on dedicated Incus storage volume
|
- Nextcloud data on dedicated Incus storage volume
|
||||||
- Open WebUI LLM interface (port 22088, PostgreSQL backend on Portia
|
- Open WebUI LLM interface (port 22088, PostgreSQL backend on Portia
|
||||||
- Home Assistant (port 8123)
|
- Home Assistant (port 8123)
|
||||||
@@ -269,6 +270,7 @@ Titania provides TLS termination and reverse proxy for all services.
|
|||||||
| `grafana.ouranos.helu.ca` | prospero.incus:443 (SSL) | Grafana |
|
| `grafana.ouranos.helu.ca` | prospero.incus:443 (SSL) | Grafana |
|
||||||
| `hass.ouranos.helu.ca` | oberon.incus:8123 | Home Assistant |
|
| `hass.ouranos.helu.ca` | oberon.incus:8123 | Home Assistant |
|
||||||
| `id.ouranos.helu.ca` | titania.incus:22081 | Casdoor SSO |
|
| `id.ouranos.helu.ca` | titania.incus:22081 | Casdoor SSO |
|
||||||
|
| `jellyfin.ouranos.helu.ca` | rosalind.incus:22086 | Jellyfin |
|
||||||
| `icarlos.ouranos.helu.ca` | puck.incus:22681 | Icarlos (Django) |
|
| `icarlos.ouranos.helu.ca` | puck.incus:22681 | Icarlos (Django) |
|
||||||
| `jupyterlab.ouranos.helu.ca` | puck.incus:22071 | JupyterLab (OAuth2-Proxy) |
|
| `jupyterlab.ouranos.helu.ca` | puck.incus:22071 | JupyterLab (OAuth2-Proxy) |
|
||||||
| `kairos.ouranos.helu.ca` | puck.incus:22581 | Kairos (Django) |
|
| `kairos.ouranos.helu.ca` | puck.incus:22581 | Kairos (Django) |
|
||||||
@@ -449,13 +451,45 @@ ansible-vault encrypt new_secrets.yml
|
|||||||
|
|
||||||
Terraform provisions Incus S3 buckets for services requiring object storage:
|
Terraform provisions Incus S3 buckets for services requiring object storage:
|
||||||
|
|
||||||
| Service | Host | Purpose |
|
| Name | Description |
|
||||||
|---------|------|---------|
|
|---------------------|----------------------------------|
|
||||||
| **Casdoor** | Titania | User avatars and SSO resource storage |
|
| `casdoor` | Casdoor file storage bucket |
|
||||||
| **LobeChat** | Rosalind | File uploads and attachments |
|
| `daedalus` | Daedalus file storage bucket |
|
||||||
|
| `lobechat` | Lobechat file storage bucket |
|
||||||
|
| `mnemosyne-content` | Mnemosyne content storage bucket |
|
||||||
|
| `spelunker` | Spelunker file storage bucket |
|
||||||
|
|
||||||
> S3 credentials (access key, secret key, endpoint) are stored as sensitive Terraform outputs and managed in Ansible Vault with the `vault_*_s3_*` prefix.
|
> S3 credentials (access key, secret key, endpoint) are stored as sensitive Terraform outputs and managed in Ansible Vault with the `vault_*_s3_*` prefix.
|
||||||
|
|
||||||
|
### Retrieving S3 Bucket Credentials
|
||||||
|
|
||||||
|
The bucket credentials are declared as **sensitive** Terraform outputs, so a plain
|
||||||
|
`terraform output` will mask them. Use the `-json` (or `-raw`) flag to reveal the
|
||||||
|
values:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd terraform
|
||||||
|
|
||||||
|
# List all outputs (sensitive values shown as <sensitive>)
|
||||||
|
terraform output
|
||||||
|
|
||||||
|
# Show a specific bucket's credentials as JSON
|
||||||
|
terraform output -json casdoor_s3_credentials
|
||||||
|
terraform output -json daedalus_s3_credentials
|
||||||
|
terraform output -json lobechat_s3_credentials
|
||||||
|
terraform output -json mnemosyne_s3_credentials
|
||||||
|
terraform output -json spelunker_s3_credentials
|
||||||
|
|
||||||
|
# Extract a single field (e.g. access_key) with jq
|
||||||
|
terraform output -json casdoor_s3_credentials | jq -r .access_key
|
||||||
|
terraform output -json casdoor_s3_credentials | jq -r .secret_key
|
||||||
|
terraform output -json casdoor_s3_credentials | jq -r .endpoint
|
||||||
|
```
|
||||||
|
|
||||||
|
Each `*_s3_credentials` output contains `bucket`, `access_key`, `secret_key`, and
|
||||||
|
`endpoint`. Copy these into `inventory/group_vars/all/vault.yml` as
|
||||||
|
`vault_<service>_s3_access_key`, `vault_<service>_s3_secret_key`, etc.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## Ansible Automation
|
## Ansible Automation
|
||||||
@@ -498,6 +532,7 @@ Services with standalone deploy playbooks (not in `site.yml`):
|
|||||||
| `gitea_mcp/deploy.yml` | Miranda | Gitea MCP Server |
|
| `gitea_mcp/deploy.yml` | Miranda | Gitea MCP Server |
|
||||||
| `gitea_runner/deploy.yml` | Puck | Gitea CI/CD runner |
|
| `gitea_runner/deploy.yml` | Puck | Gitea CI/CD runner |
|
||||||
| `grafana_mcp/deploy.yml` | Miranda | Grafana MCP Server |
|
| `grafana_mcp/deploy.yml` | Miranda | Grafana MCP Server |
|
||||||
|
| `jellyfin/deploy.yml` | Rosalind | Jellyfin media server |
|
||||||
| `jupyterlab/deploy.yml` | Puck | JupyterLab + OAuth2-Proxy |
|
| `jupyterlab/deploy.yml` | Puck | JupyterLab + OAuth2-Proxy |
|
||||||
| `kernos/deploy.yml` | Caliban | Kernos MCP shell server |
|
| `kernos/deploy.yml` | Caliban | Kernos MCP shell server |
|
||||||
| `lobechat/deploy.yml` | Rosalind | LobeChat AI chat |
|
| `lobechat/deploy.yml` | Rosalind | LobeChat AI chat |
|
||||||
|
|||||||
Reference in New Issue
Block a user