initial commit

This commit is contained in:
hiperman
2026-01-30 15:07:31 -05:00
commit 7844cc4416
83 changed files with 3802 additions and 0 deletions
+3
View File
@@ -0,0 +1,3 @@
[submodule "roles/docker_compose_app"]
path = roles/docker_compose_app
url = ssh://git@ssh.git.jaroszew.ski:2222/ansible/ansible-role-docker-compose-app.git
+222
View File
@@ -0,0 +1,222 @@
# Ansible Collection - patrickj.docker_apps
A comprehensive Ansible collection for deploying and managing Docker Compose applications with enterprise-grade features including backup/restore, health checks, and automated updates.
## Overview
A curated collection of Docker Compose roles for self-hosted applications. Each role leverages the `docker_compose_app` base to provide standardized deployment, configuration management, backup procedures, and lifecycle operations across diverse containerized services.
Consult the [role development documentation](https://git.jaroszew.ski/ansible/ansible-role-docker-compose-app/src/branch/main/README.md) for guidance on creating custom roles, variable conventions, and integration patterns.
## Features
- **🏗️ Template-based deployment** with Jinja2 templating
- **🔄 Backup & restore system** (store backups on the Ansible controller + remote host)
- **🏥 Health checks** and deployment verification
- **🏷️ Tag-based execution** for selective operations
- **📦 Multiple deployment modes** (template, file, or inline content)
- **🔧 Flexible directory management**
- **⚙️ Configurable retention policies**
- **🔄 Container update automation**
## Installation
### From Git Repository
```bash
ansible-galaxy collection install https://git.jaroszew.ski/ansible/ansible-collection-docker-apps.git
```
### From Local Development
```bash
# From the collection directory
ansible-galaxy collection install .
# Or specify path
ansible-galaxy collection install /path/to/patrickj/docker_apps
```
## Quick Start
### 1. Basic Deployment
Create a playbook using the collection roles:
```yaml
---
- name: Deploy media server applications
hosts: localhost
become: yes
vars:
host_root_path: /opt/docker
app_timezone: "America/New_York"
roles:
- patrickj.docker_apps.open-webui
- patrickj.docker_apps.audiobookshelf
- patrickj.docker_apps.paperless-ngx
```
### 2. Run the Deployment
```bash
# Full deployment
ansible-playbook deploy.yml
# Setup only (directories, templates - no containers)
ansible-playbook --tags setup deploy.yml
# Deploy specific apps
ansible-playbook deploy.yml --limit jellyfin
```
## Available Roles
### Media Applications
- **`jellyfin`** - Media server for movies, TV shows, music
- **`audiobookshelf`** - Audiobook and podcast server
- **`navidrome`** - Music streaming server
### Utilities & Monitoring
- **`uptime-kuma`** - Uptime monitoring
- **`speedtest-tracker`** - Internet speed monitoring
- **`glance`** - Dashboard
- **`grafana`** - Data visualization
- **`influxdb`** - Time series database
### Productivity
- **`paperless-ngx`** - Document management
- **`mealie`** - Recipe manager
- **`linkwarden`** - Bookmark manager
- **`immich`** - Photo management
- **`gitea`** - Git repository server
### Web Services
- **`open-webui`** - Web interface for LLMs
- **`redlib`** - Alternative Reddit frontend
- **`calibre-web`** - eBook server
I'll be adding more roles as I incorporate them into my homelab.
## Usage Examples
### Tag-Based Operations
```bash
# Setup applications (do not start containers)
ansible-playbook --tags setup playbook.yml
# Full deployment (setup + start containers)
ansible-playbook --tags deploy playbook.yml
# Backup applications
ansible-playbook --tags backup playbook.yml
# Restore from backup then deploy
ansible-playbook --tags restore,deploy playbook.yml
# Update container images
ansible-playbook --tags update playbook.yml
# Backup and update
ansible-playbook --tags backup,update playbook.yml
# Health check only
ansible-playbook --tags healthcheck playbook.yml
```
## Configuration
### Global Variables
Set these variables in your playbook or inventory:
```yaml
# Required
host_root_path: /opt/docker # Base directory for all apps
# Optional
app_timezone: "UTC" # Container timezone
app_restart_policy: unless-stopped # Docker restart policy
backup_path: /opt/backups # Backup storage location
```
### Per-Application Variables
Each application role accepts specific configuration. See individual role documentation in `roles/<app_name>/README.md`.
Common patterns:
```yaml
app_name: custom-instance-name # Override default name
{app}_http_port: 8080 # Custom port
{app}_config_path: /custom/path # Override paths
```
## Backup & Restore
### Automated Backups
```bash
# Create backups for all deployed applications
ansible-playbook --tags backup site.yml
# Schedule daily backups (cron)
0 2 * * * ansible-playbook --tags backup /path/to/playbook.yml
```
### Restore Operations
```bash
# Restore latest backup
ansible-playbook --tags restore playbook.yml
# Full restore workflow (setup + restore + deploy)
ansible-playbook --tags setup,restore,deploy playbook.yml
# Restore specific archive
ansible-playbook --tags restore playbook.yml \
-e app_restore_archive=/path/to/backup.tar.gz
```
## Requirements
- **Ansible**: >= 2.14
- **Docker**: >= 20.10
- **Docker Compose**: >= 2.0
- **Python**: >= 3.8
## Dependencies
The collection automatically handles dependencies:
```yaml
collections:
- community.docker # For Docker Compose operations
```
## Development
### Adding New Applications
1. Create role directory: `roles/new-app/`
2. Follow the template structure from existing roles
3. Configure meta dependency on `docker_compose_app`
4. Add to documentation
### Testing
```bash
# Test role syntax
ansible-playbook --syntax-check playbook.yml
# Test specific role
ansible-playbook --tags setup --check playbook.yml
```
## License
MIT
## Author
Patrick Jaroszewski
+22
View File
@@ -0,0 +1,22 @@
---
namespace: patrickj
name: docker_apps
version: 1.0.0
readme: README.md
authors:
- Patrick Jaroszewski
description: Ansible collection for deploying Docker Compose applications
license:
- MIT
tags:
- docker
- compose
- containers
- selfhosted
- homelab
dependencies:
"community.docker": ">=1.10.0"
repository: https://git.jaroszew.ski/ansible/ansible-collection-docker-apps
documentation: https://git.jaroszew.ski/ansible/ansible-collection-docker-apps/README.md
homepage: https://git.jaroszew.ski/ansible/ansible-collection-docker-apps
issues: https://git.jaroszew.ski/ansible/ansible-collection-docker-apps/issues
+34
View File
@@ -0,0 +1,34 @@
# Audiobookshelf
Deploy Audiobookshelf audiobook and podcast server using Docker Compose.
## Description
Audiobookshelf is a self-hosted audiobook and podcast server with mobile apps, chapter support, and progress tracking.
## Variables
### Required
| Variable | Description |
|----------|-------------|
| `audiobookshelf_libraries` | List of media library mappings with `host_path` and `container_path` |
### Optional
| Variable | Default | Description |
|----------|---------|-------------|
| `audiobookshelf_http_port` | `13378` | Web interface port |
| `audiobookshelf_config_path` | `{{ app_dir }}/config` | Configuration storage |
| `audiobookshelf_metadata_path` | `{{ app_dir }}/metadata` | Metadata cache storage |
| `audiobookshelf_container_version` | `latest` | Audiobookshelf Docker image tag |
## Example
```yaml
- role: patrickj.docker_apps.audiobookshelf
vars:
audiobookshelf_libraries:
- host_path: /storage/audiobooks
container_path: /audiobooks
```
+14
View File
@@ -0,0 +1,14 @@
---
app_role_name: audiobookshelf
app_name: audiobookshelf
# Container configuration
audiobookshelf_container_name: "{{ app_name | default('audiobookshelf') }}"
audiobookshelf_container_version: latest
audiobookshelf_restart_policy: "{{ app_restart_policy }}"
audiobookshelf_http_port: 13378
# Volume paths
audiobookshelf_config_path: "{{ app_dir }}/config"
audiobookshelf_metadata_path: "{{ app_dir }}/metadata"
+16
View File
@@ -0,0 +1,16 @@
---
galaxy_info:
author: Patrick Jaroszewski
description: Deploy Audiobookshelf with Docker Compose
license: MIT
dependencies:
- role: patrickj.docker_apps.docker_compose_app
vars:
app_role_name: audiobookshelf
app_subdirectories:
- "{{ audiobookshelf_config_path }}"
- "{{ audiobookshelf_metadata_path }}"
app_backup_subdirectories:
- "{{ audiobookshelf_config_path }}"
- "{{ audiobookshelf_metadata_path }}"
@@ -0,0 +1,14 @@
---
services:
audiobookshelf:
image: "ghcr.io/advplyr/audiobookshelf:{{ audiobookshelf_container_version }}"
container_name: "{{ audiobookshelf_container_name }}"
restart: "{{ audiobookshelf_restart_policy }}"
ports:
- "{{ audiobookshelf_http_port }}:80"
volumes:
- "{{ audiobookshelf_config_path }}:/config"
- "{{ audiobookshelf_metadata_path }}:/metadata"
{% for item in audiobookshelf_libraries %}
- "{{ item.host_path }}:{{ item.container_path }}"
{% endfor %}
+36
View File
@@ -0,0 +1,36 @@
# Calibre-Web
Deploy Calibre-Web ebook server using Docker Compose.
## Description
Calibre-Web is a web app providing a clean interface for browsing, reading and downloading eBooks from a Calibre database.
## Variables
### Required
| Variable | Description |
|----------|-------------|
| `calibre_web_library_path` | Path to existing Calibre library directory |
### Optional
| Variable | Default | Description |
|----------|---------|-------------|
| `calibre_web_http_port` | `8083` | Web interface port |
| `calibre_web_config_path` | `{{ app_dir }}/config` | Configuration storage |
| `calibre_web_container_version` | `latest` | Calibre-Web Docker image tag |
| `calibre_web_uid` | `{{ app_uid }}` | User ID for file permissions |
| `calibre_web_gid` | `{{ app_gid }}` | Group ID for file permissions |
| `calibre_web_timezone` | `{{ app_timezone }}` | Container timezone |
| `calibre_web_docker_mods` | `linuxserver/mods:universal-calibre` | Adds ebook conversion capability (x86-64 only) |
| `calibre_web_oauth_relax` | `1` | Allows Google OAuth to work. Set to `0` to disable |
## Example
```yaml
- role: patrickj.docker_apps.calibre-web
vars:
calibre_web_library_path: /storage/ebooks/calibre-library
```
+22
View File
@@ -0,0 +1,22 @@
---
app_name: calibre-web
# Container configuration
calibre_web_container_name: "{{ app_name | default('calibre-web') }}"
calibre_web_container_version: latest
calibre_web_restart_policy: "{{ app_restart_policy }}"
calibre_web_uid: "{{ app_uid }}"
calibre_web_gid: "{{ app_gid }}"
# Network configuration
calibre_web_http_port: 8083
# Volume paths
calibre_web_config_path: "{{ app_dir }}/config"
calibre_web_library_path: "{{ app_dir }}/library"
# App-specific configuration
calibre_web_timezone: "{{ app_timezone | default('Etc/UTC') }}"
calibre_web_docker_mods: "linuxserver/mods:universal-calibre"
calibre_web_oauth_relax: "1"
+15
View File
@@ -0,0 +1,15 @@
---
galaxy_info:
author: Patrick Jaroszewski
description: Deploy Calibre-Web with Docker Compose
license: MIT
dependencies:
- role: patrickj.docker_apps.docker_compose_app
vars:
app_role_name: calibre-web
app_subdirectories:
- "{{ calibre_web_config_path }}"
- "{{ calibre_web_books_path }}"
app_backup_subdirectories:
- "{{ calibre_web_config_path }}"
@@ -0,0 +1,17 @@
---
services:
calibre-web:
image: "lscr.io/linuxserver/calibre-web:{{ calibre_web_container_version }}"
container_name: "{{ calibre_web_container_name }}"
restart: "{{ calibre_web_restart_policy }}"
ports:
- "{{ calibre_web_http_port }}:8083"
environment:
- PUID={{ calibre_web_uid }}
- PGID={{ calibre_web_gid }}
- TZ={{ calibre_web_timezone }}
- DOCKER_MODS={{ calibre_web_docker_mods }}
- OAUTHLIB_RELAX_TOKEN_SCOPE={{ calibre_web_oauth_relax }}
volumes:
- "{{ calibre_web_config_path }}:/config"
- "{{ calibre_web_library_path }}:/books"
+3
View File
@@ -0,0 +1,3 @@
# ---> Ansible
*.retry
+18
View File
@@ -0,0 +1,18 @@
MIT License
Copyright (c) 2025 ansible
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and
associated documentation files (the "Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the
following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial
portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO
EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
USE OR OTHER DEALINGS IN THE SOFTWARE.
+512
View File
@@ -0,0 +1,512 @@
# Ansible Role: gitea
This Ansible role automates the deployment of Gitea - a self-hosted Git service, using Docker Compose. It provides a comprehensive setup with support for runners, fail2ban integration, and extensive configuration options. This role uses the centralized `docker_compose_app` role for standardized deployment, backup/restore, and health checks.
## Features
- **Standardized deployment** - Uses `docker_compose_app` for consistent deployment patterns
- **Docker-based deployment** - Runs Gitea in a rootless container for enhanced security
- **Complete security configuration** - Password policies, 2FA, fail2ban integration, etc.
- **Enterprise backup/restore** - Dual storage system with configurable retention policies
- **Health monitoring** - Automated health checks and deployment verification
- **Gitea Actions support** - Supports creating multiple runners running in rootless containers using DinD (Docker-in-Docker)
- **User management** - Automated user creation and removal
- **Extensible** - Extra config variables for any Gitea setting not explicitly defined
## Requirements
- Docker and Docker Compose installed (handled by `geerlingguy.docker` dependency)
- jmespath Python library (install with: `pip install jmespath`)
## Sample Usage in a Playbook
The following playbook was tested on the latest Debian 12, it should work on Ubuntu as well.
```yaml
# Installs Docker and Compose if not available
- name: Install Gitea using Docker Compose
hosts: git.example.com
become: yes
roles:
- role: gitea
vars:
# The default vars assume you are running a reverse proxy that handles HTTPS
app_name: gitea-prod
gitea_fqdn: 'git.example.com'
gitea_root_url: 'https://git.example.com'
gitea_protocol: http
gitea_http_listen: '0.0.0.0'
```
## Backup and Restore
This role uses the standardized backup/restore system from `docker_compose_app`, providing dual storage (controller + remote host) with configurable retention policies.
### Creating a Backup
```yaml
- name: Create Gitea backup
hosts: git.example.com
become: yes
roles:
- role: gitea
vars:
app_name: gitea-prod
app_backup: true
app_backup_retention_days_controller: 90
app_backup_retention_days_remote: 7
```
### Restoring from Backup
Restore from latest backup:
```yaml
- name: Restore Gitea from latest backup
hosts: git.example.com
become: yes
roles:
- role: gitea
vars:
app_name: gitea-prod
app_restore: true
app_restore_source: controller # or 'remote'
```
Restore from specific archive:
```yaml
- name: Restore Gitea from specific backup
hosts: git.example.com
become: yes
roles:
- role: gitea
vars:
app_name: gitea-prod
app_restore: true
app_restore_source: controller
app_restore_archive: /path/to/gitea-20240315-120000.tar.gz
```
> [!WARNING]
> Restore operations will **completely replace** all existing Gitea data.
# Variables
## Standardized Variables
This role uses the standardized `docker_compose_app` pattern. Core variables include:
| Variable Name | Default Value | Description |
|---------------|---------------|-------------|
| `app_name` | Required | Unique application instance name |
| `app_dir` | `{{ host_root_path }}/{{ app_name }}` | Application directory |
| `app_uid` | `{{ ansible_facts.user_uid }}` | File ownership UID |
| `app_gid` | `{{ ansible_facts.user_gid }}` | File ownership GID |
| `app_permission_mode` | `"0640"` | File permission mode |
| `app_restart_policy` | `"unless-stopped"` | Docker restart policy |
| `app_subdirectories` | `['data', 'config', 'log']` | Directories created in app_dir |
## Container Configuration
| Variable Name | Default Value | Description |
|---------------|---------------|-------------|
| `gitea_container_name` | `{{ app_name \| default('gitea') }}` | Docker container name for the Gitea service |
| `gitea_container_version` | `latest-rootless` | Docker image tag for the Gitea container (e.g., `latest-rootless`, `1.21.5-rootless`) |
| `gitea_restart_policy` | `{{ app_restart_policy }}` | Container restart policy (unless-stopped, always, on-failure, no) |
| `gitea_http_port` | `3000` | Host port that maps to Gitea's web interface |
| `gitea_ssh_port` | `2222` | Host port that maps to Gitea's SSH server |
| `gitea_data_path` | `{{ app_dir }}/data` | Full path to Gitea data directory on the host |
| `gitea_config_path` | `{{ app_dir }}/config` | Full path to Gitea configuration directory on the host |
| `gitea_log_path` | `{{ app_dir }}/log` | Full path to Gitea log directory on the host |
## Initial User Setup
| Variable Name | Option | Description |
|---------------|---------------|-------------|
| `gitea_users` | `[]` | List of user objects to create or remove in Gitea |
| | `username` | Login username for the Gitea user |
| | `email` | Email address for the Gitea user |
| | `password` | Password for the user (should be encrypted with Ansible Vault) |
| | `must_change_password` | If `true`, user must change password on first login |
| | `admin` | If `true`, user is created with administrator privileges |
| | `state` | Set to `present` to create user or `absent` to delete user |
## Backup and Restore
Backup and restore functionality is provided by the `docker_compose_app` role. Use the standard backup/restore variables:
| Variable Name | Default Value | Description |
|---------------|---------------|-------------|
| `app_backup` | `false` | Enable backup functionality |
| `app_backup_subdirectories` | `['data', 'config']` | Directories to backup (relative to app_dir) |
| `app_restore` | `false` | Enable restore functionality |
| `app_restore_source` | `controller` | Restore source (`controller` or `remote`) |
| `app_restore_archive` | - | Specific archive file to restore (overrides latest) |
| `app_backup_retention_days_controller` | `90` | Controller backup retention in days |
| `app_backup_retention_days_remote` | `7` | Remote backup retention in days |
## Runners Configuration
| Variable Name | Default Value | Description |
|---------------|---------------|-------------|
| `gitea_runner_global_registration_token` | `""` | Global registration token that applies to all runners (can be found in Gitea admin settings) |
| `gitea_runner_image` | `gitea/act_runner` | Docker image for Gitea Actions runners |
| `gitea_runner_container_version` | `latest-dind-rootless` | Docker image tag for runner containers |
| `gitea_runner_restart_policy` | `{{ gitea_restart_policy }}` | Container restart policy for runners |
| `gitea_runners` | `{}` | Dictionary of Gitea Actions runner configurations |
### Runner Configuration Options
Each runner in the `gitea_runners` dictionary supports these options:
| Option | Description |
|--------|-------------|
| `name` | Unique name identifier for the runner |
| `data_mount` | Path relative to app_dir for persistent runner data storage |
| `config_file_mount` | Path relative to app_dir for runner configuration files |
| `cache_enabled` | If `true`, enables action cache functionality (for `actions/cache` support) |
| `cache_port` | Port number on the host for accessing the runner's cache service (must be unique per runner) |
| `registration_token` | Runner-specific registration token (optional if `gitea_runner_global_registration_token` is set) |
## Fail2Ban Security
| Variable Name | Default Value | Description |
|---------------|---------------|-------------|
| `gitea_fail2ban_enabled` | `false` | Enable fail2ban protection to automatically ban IPs after failed login attempts |
| `gitea_fail2ban_jail_maxretry` | `10` | Number of failed login attempts before an IP is banned |
| `gitea_fail2ban_jail_findtime` | `3600` | Time window in seconds during which failed attempts are counted |
| `gitea_fail2ban_jail_bantime` | `900` | Duration in seconds that an IP remains banned |
| `gitea_fail2ban_jail_action` | `iptables-allports[chain="FORWARD"]` | Fail2ban action/rule to execute when banning an IP |
## Overall Configuration
| Variable Name | Default Value | Description |
|---------------|---------------|-------------|
| `gitea_app_name` | `Gitea` | Application name displayed throughout the Gitea interface |
| `gitea_user` | `gitea` | System username that runs the Gitea process inside the container |
| `gitea_run_mode` | `prod` | Application run mode: `prod` (production), `dev` (development), or `test` |
| `gitea_fqdn` | `localhost` | Fully qualified domain name for accessing the Gitea instance |
## Server Configuration
| Variable Name | Default Value | Description |
|---------------|---------------|-------------|
| `gitea_protocol` | `http` | Protocol for the root URL: `http` or `https` |
| `gitea_http_domain` | `{{ gitea_fqdn }}` | Domain name used in HTTP headers and clone URLs |
| `gitea_root_url` | `{{ gitea_protocol }}://{{ gitea_fqdn }}` | Full public URL where Gitea is accessible |
| `gitea_http_listen` | `127.0.0.1` | IP address the HTTP server binds to; use `0.0.0.0` to allow external access |
| `gitea_internal_http_port` | `3000` | Port number Gitea listens on inside the container |
| `gitea_internal_ssh_port` | `2222` | Port number SSH server listens on inside the container |
| `gitea_ssh_listen` | `0.0.0.0` | IP address the SSH server binds to |
| `gitea_ssh_domain` | `{{ gitea_http_domain }}` | Domain name shown in SSH clone URLs |
| `gitea_start_ssh` | `true` | Enable or disable the built-in SSH server |
| `gitea_landing_page` | `home` | Default page for non-authenticated users: `home`, `explore`, `organizations`, or `login` |
| `gitea_server_extra_config` | `{}` | Dictionary of additional server configuration options not covered above |
## Security Configuration
| Variable Name | Default Value | Description |
|---------------|---------------|-------------|
| `gitea_secret_key` | | Secret key used for encrypting cookies and tokens (generate with `gitea generate secret SECRET_KEY`) |
| `gitea_internal_token` | | Token used for internal API authentication (generate with `gitea generate secret INTERNAL_TOKEN`) |
| `gitea_install_lock` | `false` | If `true`, prevents the installation wizard from running |
| `gitea_disable_git_hooks` | `true` | If `true`, disables custom Git hooks for security |
| `gitea_disable_webhooks` | `false` | If `true`, disables all webhook functionality |
| `gitea_reverse_proxy_limit` | `1` | Number of reverse proxy hops to trust for obtaining the real client IP |
| `gitea_reverse_proxy_trusted_proxies` | `127.0.0.0/8,::1/128` | Comma-separated list of trusted proxy IP addresses or CIDR ranges |
| `gitea_password_complexity` | `off` | Password requirements: `off`, or comma-separated list of `lower`, `upper`, `digit`, `spec` |
| `gitea_password_min_length` | `8` | Minimum number of characters required for passwords |
| `gitea_password_check_pwn` | `false` | If `true`, checks passwords against the HaveIBeenPwned breach database |
| `gitea_2fa` | | Two-factor authentication setting; set to `enforced` to require 2FA for all users |
| `gitea_login_remember_days` | `31` | Number of days to keep users logged in when they select "Remember Me" |
| `gitea_cookie_remember_name` | `gitea_incredible` | Name of the cookie used for "Remember Me" functionality |
| `gitea_security_extra_config` | `{}` | Dictionary of additional security configuration options |
## Service Configuration
| Variable Name | Default Value | Description |
|---------------|---------------|-------------|
| `gitea_disable_registration` | `false` | If `true`, disables new user registration entirely |
| `gitea_register_email_confirm` | `false` | If `true`, requires email verification to complete registration |
| `gitea_register_manual_confirm` | `false` | If `true`, requires admin approval for new registrations |
| `gitea_require_signin_view` | `false` | If `true`, requires users to sign in to view any content |
| `gitea_enable_notify_mail` | `false` | If `true`, enables email notifications for events |
| `gitea_enable_captcha` | `false` | If `true`, shows CAPTCHA on registration form |
| `gitea_captcha_type` | `image` | Type of CAPTCHA to use: `image`, `recaptcha`, `hcaptcha`, or `mcaptcha` |
| `gitea_show_registration_button` | `true` | If `true`, displays registration button on login page |
| `gitea_default_keep_email_private` | `false` | If `true`, new users have email privacy enabled by default |
| `gitea_default_allow_create_organization` | `true` | If `true`, new users can create organizations |
| `gitea_default_user_is_restricted` | `false` | If `true`, new users are created with restricted permissions |
| `gitea_default_user_visibility` | `public` | Default visibility for new user profiles: `public`, `limited`, or `private` |
| `gitea_default_org_visibility` | `public` | Default visibility for new organizations: `public`, `limited`, or `private` |
| `gitea_default_org_member_visible` | `false` | If `true`, organization members are visible by default |
| `gitea_allow_only_internal_registration` | `false` | If `true`, only allows registration via internal authentication |
| `gitea_allow_only_external_registration` | `false` | If `true`, only allows registration via external authentication sources |
| `gitea_email_domain_allowlist` | | Comma-separated list of allowed email domains for registration |
| `gitea_email_domain_blocklist` | | Comma-separated list of blocked email domains for registration |
| `gitea_no_reply_address` | | No-reply email address used for system-generated emails |
| `gitea_enable_user_heatmap` | `true` | If `true`, displays user activity heatmap on profiles |
| `gitea_enable_timetracking` | `true` | If `true`, enables time tracking features for issues |
| `gitea_auto_watch_new_repos` | `true` | If `true`, users automatically watch repositories they create |
| `gitea_auto_watch_on_changes` | `false` | If `true`, users automatically watch repositories they contribute to |
| `gitea_show_milestones_dashboard_page` | `true` | If `true`, shows milestones on the dashboard page |
| `gitea_service_extra_config` | `{}` | Dictionary of additional service configuration options |
## Repository Configuration
| Variable Name | Default Value | Description |
|---------------|---------------|-------------|
| `gitea_repo_force_private` | `false` | If `true`, forces all new repositories to be private |
| `gitea_repo_default_private` | `last` | Default visibility for new repositories: `public`, `private`, or `last` (uses last selection) |
| `gitea_repo_default_push_create_private` | `true` | If `true`, repositories created via push are private by default |
| `gitea_repo_preferred_licenses` | `Apache License 2.0,MIT License` | Comma-separated list of license names to show at the top when creating repositories |
| `gitea_repo_disable_http_git` | `false` | If `true`, disables HTTP(S) Git operations (clone, push, pull) |
| `gitea_repo_disable_migrations` | `false` | If `true`, disables repository migration feature |
| `gitea_repo_disable_stars` | `false` | If `true`, disables the ability to star repositories |
| `gitea_repo_default_branch` | `main` | Default branch name for new repositories |
| `gitea_repository_extra_config` | `{}` | Dictionary of additional repository configuration options |
## CORS Configuration
| Variable Name | Default Value | Description |
|---------------|---------------|-------------|
| `gitea_cors_enabled` | `false` | Enable Cross-Origin Resource Sharing (CORS) headers |
| `gitea_cors_allowed_domains` | `*` | Domains allowed to make cross-origin requests; `*` allows all |
| `gitea_cors_allowed_methods` | `GET,HEAD,POST,PUT,PATCH,DELETE,OPTIONS` | HTTP methods allowed for cross-origin requests |
| `gitea_cors_max_age` | `10m` | Duration to cache preflight CORS request results |
| `gitea_cors_allowed_credentials` | `false` | If `true`, allows credentials (cookies, auth headers) in cross-origin requests |
| `gitea_cors_headers` | `Content-Type,User-Agent` | Custom headers allowed in cross-origin requests |
| `gitea_cors_x_frame_options` | `SAMEORIGIN` | X-Frame-Options header value: `SAMEORIGIN`, `DENY`, or `ALLOW-FROM uri` |
## UI Configuration
| Variable Name | Default Value | Description |
|---------------|---------------|-------------|
| `gitea_ui_default_theme` | `gitea-auto` | Default theme for the UI; `gitea-auto` switches based on system preference |
| `gitea_ui_themes` | | Comma-separated list of themes to make available; if empty, all themes are available |
| `gitea_ui_show_user_email` | `true` | If `true`, displays user email addresses in the UI (respects privacy settings) |
| `gitea_ui_show_full_name` | `false` | If `true`, displays full names instead of usernames where applicable |
| `gitea_ui_extra_config` | `{}` | Dictionary of additional UI configuration options |
## UI Meta Configuration
| Variable Name | Default Value | Description |
|---------------|---------------|-------------|
| `gitea_ui_meta_author` | `Gitea - Git with a cup of tea` | Content for the HTML meta author tag |
| `gitea_ui_meta_description` | `Gitea (Git with a cup of tea) is a painless self-hosted Git service written in Go` | Content for the HTML meta description tag (used by search engines) |
| `gitea_ui_meta_keywords` | `go,git,self-hosted,gitea` | Comma-separated keywords for the HTML meta keywords tag |
## Indexer Configuration
| Variable Name | Default Value | Description |
|---------------|---------------|-------------|
| `gitea_issue_indexer_type` | `bleve` | Issue search indexer engine: `bleve` (built-in), `db` (database), `elasticsearch`, or `meilisearch` |
| `gitea_issue_indexer_connection_string` | | Connection string for external indexer (required for `elasticsearch` or `meilisearch`) |
| `gitea_issue_indexer_name` | `gitea_issues` | Index name used in external indexer services |
| `gitea_issue_indexer_path` | `indexers/issues.bleve` | File path for bleve index storage (relative to Gitea data directory) |
| `gitea_repo_indexer_enabled` | `false` | Enable code search functionality (WARNING: requires significant disk space, ~6x repository size) |
| `gitea_repo_indexer_repo_types` | `sources,forks,mirrors,templates` | Types of repositories to include in code search index |
| `gitea_repo_indexer_type` | `bleve` | Code search indexer engine: `bleve` (built-in) or `elasticsearch` |
| `gitea_repo_indexer_path` | `indexers/repos.bleve` | File path for bleve code index storage (relative to Gitea data directory) |
| `gitea_repo_indexer_connection_string` | | Connection string for elasticsearch code indexer |
| `gitea_repo_indexer_name` | `gitea_codes` | Index name for code search in elasticsearch |
| `gitea_repo_indexer_include` | | Glob patterns for files to include in code search (e.g., `**.txt,**.md`); empty includes all |
| `gitea_repo_indexer_exclude` | | Glob patterns for files to exclude from code search (takes precedence over includes) |
| `gitea_repo_indexer_exclude_vendored` | `true` | If `true`, excludes vendored/third-party code from indexing |
| `gitea_repo_indexer_max_file_size` | `1048576` | Maximum file size in bytes to index (default 1 MiB); larger files are skipped |
| `gitea_indexer_startup_timeout` | `30s` | Maximum time to wait for indexer initialization; `-1` disables timeout |
| `gitea_indexer_extra_config` | `{}` | Dictionary of additional indexer configuration options |
## Packages Configuration
| Variable Name | Default Value | Description |
|---------------|---------------|-------------|
| `gitea_packages_enabled` | `true` | Enable package registry functionality (for npm, Maven, Docker, etc.) |
| `gitea_packages_extra_config` | `{}` | Dictionary of additional package registry configuration options |
## Actions Configuration
| Variable Name | Default Value | Description |
|---------------|---------------|-------------|
| `gitea_actions_enabled` | `false` | Enable Gitea Actions (CI/CD pipeline functionality) |
| `gitea_actions_default_actions_url` | `github` | Default URL for Actions marketplace; `github`, `self`, or custom URL |
| `gitea_actions_extra_config` | `{}` | Dictionary of additional Actions configuration options |
## Logging Configuration
| Variable Name | Default Value | Description |
|---------------|---------------|-------------|
| `gitea_log_root_path` | | Root directory for log files; required if `gitea_log_mode` is `file` or for fail2ban integration |
| `gitea_log_mode` | `console` | Log output destination: `console`, `file`, `conn` (network), or `smtp` (email) |
| `gitea_log_level` | `Info` | Logging verbosity level: `Trace`, `Debug`, `Info`, `Warn`, `Error`, or `Critical` |
| `gitea_enable_ssh_log` | `false` | If `true`, enables detailed logging for SSH operations |
| `gitea_log_extra_config` | `{}` | Dictionary of additional logging configuration options |
## Mailer Configuration
| Variable Name | Default Value | Description |
|---------------|---------------|-------------|
| `gitea_mailer_enabled` | `false` | Enable email functionality for notifications and registration |
| `gitea_mailer_protocol` | | Mail protocol: `smtp`, `smtps`, `smtp+starttls`, `smtp+unix`, `sendmail`, or `dummy` (logs only) |
| `gitea_mailer_smtp_addr` | | Hostname or IP address of the SMTP server |
| `gitea_mailer_smtp_port` | | Port number for the SMTP server (typically 25, 465, or 587) |
| `gitea_mailer_user` | | Username for SMTP authentication |
| `gitea_mailer_password` | | Password for SMTP authentication (should be encrypted with Ansible Vault) |
| `gitea_mailer_from` | `noreply@{{ gitea_http_domain }}` | Email address used as the sender for all outgoing emails |
| `gitea_mailer_subject_prefix` | | Text prepended to all email subject lines |
| `gitea_mailer_send_as_plain_text` | `false` | If `true`, sends emails as plain text instead of HTML |
| `gitea_mailer_extra_config` | `{}` | Dictionary of additional mailer configuration options |
## Mirror Configuration
| Variable Name | Default Value | Description |
|---------------|---------------|-------------|
| `gitea_mirror_enabled` | `true` | Enable repository mirroring functionality |
| `gitea_mirror_disable_new_pull` | `false` | If `true`, prevents creation of new pull mirrors (mirroring from external repos) |
| `gitea_mirror_disable_new_push` | `false` | If `true`, prevents creation of new push mirrors (mirroring to external repos) |
| `gitea_mirror_default_interval` | `8h` | Default synchronization interval for new mirrors |
| `gitea_mirror_min_interval` | `10m` | Minimum allowed interval between mirror synchronizations |
| `gitea_mirror_extra_config` | `{}` | Dictionary of additional mirror configuration options |
## Metrics Configuration
| Variable Name | Default Value | Description |
|---------------|---------------|-------------|
| `gitea_metrics_enabled` | `false` | Enable Prometheus metrics endpoint at `/metrics` |
| `gitea_metrics_token` | | Authentication token required to access the metrics endpoint |
| `gitea_metrics_extra_config` | `{}` | Dictionary of additional metrics configuration options |
## API Configuration
| Variable Name | Default Value | Description |
|---------------|---------------|-------------|
| `gitea_api_enable_swagger` | `true` | Enable Swagger UI for API documentation at `/api/swagger` |
| `gitea_api_max_response_items` | `50` | Maximum number of items returned in a single API response page |
| `gitea_api_default_paging_num` | `30` | Default number of items per page for API responses |
| `gitea_api_extra_config` | `{}` | Dictionary of additional API configuration options |
## OAuth2 Configuration
| Variable Name | Default Value | Description |
|---------------|---------------|-------------|
| `gitea_oauth2_enabled` | `true` | Enable OAuth2 provider functionality (allows other apps to use Gitea for authentication) |
| `gitea_oauth2_access_token_expiration_time` | `3600` | OAuth2 access token lifetime in seconds (default 1 hour) |
| `gitea_oauth2_refresh_token_expiration_time` | `730` | OAuth2 refresh token lifetime in hours (default ~30 days) |
| `gitea_oauth2_jwt_signing_algorithm` | `RS256` | Algorithm used to sign JWT tokens: `RS256`, `RS384`, `RS512`, `ES256`, `ES384`, or `ES512` |
| `gitea_oauth2_jwt_secret` | | Secret key for signing JWT tokens (auto-generated if not provided) |
| `gitea_oauth2_extra_config` | `{}` | Dictionary of additional OAuth2 configuration options |
## Other Configuration
| Variable Name | Default Value | Description |
|---------------|---------------|-------------|
| `gitea_show_footer_version` | `true` | If `true`, displays Gitea version number in the page footer |
| `gitea_show_footer_template_load_time` | `true` | If `true`, displays page generation time in the footer |
| `gitea_enable_sitemap` | `true` | If `true`, generates XML sitemap at `/sitemap.xml` for search engines |
| `gitea_enable_feed` | `true` | If `true`, enables RSS and Atom feeds for repositories and users |
| `gitea_other_extra_config` | `{}` | Dictionary of additional miscellaneous configuration options |
## Additional Configuration
> [!NOTE]
> Not all variables that Gitea supports have been implemented yet. Read the following secion to add additional configuration options.
| Variable Name | Default Value | Description |
|---------------|---------------|-------------|
| `gitea_extra_config` | `{}` | Dictionary of any additional environment variables to pass to Gitea; consult the [Gitea configuration cheat sheet](https://docs.gitea.com/administration/config-cheat-sheet) for available options |
### Example: Using `gitea_extra_config`
```yaml
gitea_extra_config:
GITEA__webhook__ALLOWED_HOST_LIST: "external"
GITEA__webhook__SKIP_TLS_VERIFY: "false"
GITEA__cron__ENABLED: "true"
```
## Understanding Extra Configuration Variables
Many configuration sections include an `*_extra_config` variable (e.g., `gitea_server_extra_config`, `gitea_security_extra_config`, etc.). These variables allow you to add additional Gitea configuration options that aren't explicitly defined as separate variables in this role.
### How Extra Config Variables Work
Each `*_extra_config` variable is a dictionary that gets merged into the corresponding section of the Gitea configuration. The role converts these dictionaries into the appropriate environment variable format that Gitea expects.
### Naming Convention
Gitea uses environment variables with a specific naming pattern:
```
GITEA__<section>__<key>
```
When you use an `*_extra_config` variable, the role automatically handles the section name for you. You only need to provide the key-value pairs.
### Available Extra Config Variables
| Variable | Maps to Gitea Section |
|----------|----------------------|
| `gitea_server_extra_config` | `[server]` |
| `gitea_security_extra_config` | `[security]` |
| `gitea_service_extra_config` | `[service]` |
| `gitea_repository_extra_config` | `[repository]` |
| `gitea_ui_extra_config` | `[ui]` |
| `gitea_indexer_extra_config` | `[indexer]` |
| `gitea_packages_extra_config` | `[packages]` |
| `gitea_actions_extra_config` | `[actions]` |
| `gitea_log_extra_config` | `[log]` |
| `gitea_mailer_extra_config` | `[mailer]` |
| `gitea_mirror_extra_config` | `[mirror]` |
| `gitea_metrics_extra_config` | `[metrics]` |
| `gitea_api_extra_config` | `[api]` |
| `gitea_oauth2_extra_config` | `[oauth2]` |
| `gitea_other_extra_config` | `[other]` |
### Examples
#### Adding Server Configuration
```yaml
gitea_server_extra_config:
OFFLINE_MODE: true
DISABLE_ROUTER_LOG: false
ENABLE_GZIP: true
```
This translates to these environment variables:
```
GITEA__server__OFFLINE_MODE=true
GITEA__server__DISABLE_ROUTER_LOG=false
GITEA__server__ENABLE_GZIP=true
```
#### Using gitea_extra_config for Any Section
If you need to configure a section that doesn't have a dedicated `*_extra_config` variable, or want to set options across multiple sections, use `gitea_extra_config`:
```yaml
gitea_extra_config:
# Webhook configuration
GITEA__webhook__ALLOWED_HOST_LIST: "external"
GITEA__webhook__SKIP_TLS_VERIFY: "false"
# Cron configuration
GITEA__cron__ENABLED: "true"
GITEA__cron_DOT_update_checker__ENABLED: "false"
# Git configuration
GITEA__git__DISABLE_DIFF_HIGHLIGHT: "false"
GITEA__git__timeout__DEFAULT: "360"
```
### Finding Available Options
For a complete list of available configuration options, refer to the official [Gitea Configuration Cheat Sheet](https://docs.gitea.com/administration/config-cheat-sheet).
### Important Notes
1. **Values**: All values in `*_extra_config` dictionaries should be strings, numbers, or booleans.
2. **Priority**: Variables defined in `*_extra_config` can override the explicitly defined role variables if they conflict.
3. **Validation**: The role does not validate extra configuration options. Ensure you're using valid Gitea configuration keys by consulting the official documentation.
# License
MIT License
+253
View File
@@ -0,0 +1,253 @@
---
app_name: gitea
# User configuration. Note that if using rootless, the uid and gid must be 1000
gitea_uid: 1000
gitea_gid: 1000
# Container configuration
gitea_container_name: "{{ app_name | default('gitea') }}"
gitea_container_version: latest-rootless
gitea_restart_policy: "{{ app_restart_policy }}"
# Network configuration
gitea_http_port: 3000
gitea_ssh_port: 2222
# Volume paths
gitea_data_path: "{{ app_dir }}/data"
gitea_config_path: "{{ app_dir }}/config"
gitea_log_path: "{{ app_dir }}/log"
gitea_users: []
# gitea_users:
# - username: someuser
# email: user@example.com
# password: somepass # Should be a vault secret
# admin: true
# must_change_password: true
# state: present # `absent` if you want to delete this user
gitea_runners: []
# - name: <runner-name>
# data_mount: ./runners/main_runner
# registration_token: <token>
# cache_enabled: true
# cache_port: <port> # Use a unique port
gitea_runner_global_registration_token: ""
gitea_runner_image: gitea/act_runner
gitea_runner_container_version: latest-dind-rootless
gitea_runner_restart_policy: "{{ gitea_restart_policy }}"
# Fail2Ban vars
gitea_fail2ban_enabled: false
gitea_fail2ban_jail_maxretry: 10
gitea_fail2ban_jail_findtime: 3600
gitea_fail2ban_jail_bantime: 900
gitea_fail2ban_jail_action: 'iptables-allports[chain="FORWARD"]'
# App-specific configuration
# Overall (DEFAULT)
# -> https://docs.gitea.io/en-us/config-cheat-sheet/#overall-default
gitea_app_name: "Gitea"
gitea_user: "gitea"
gitea_run_mode: "prod"
gitea_fqdn: "localhost"
# Repository Configuration
# ->
gitea_repo_force_private: false
gitea_repo_default_private: 'last'
gitea_repo_default_push_create_private: true
gitea_repo_preferred_licenses: 'Apache License 2.0,MIT License'
gitea_repo_disable_http_git: false
gitea_repo_disable_migrations: false
gitea_repo_disable_stars: false
gitea_repo_default_branch: 'main'
gitea_repository_extra_config: {}
# CORS Configuration
# ->
gitea_cors_enabled: false
gitea_cors_allowed_domains: '*'
gitea_cors_allowed_methods: 'GET,HEAD,POST,PUT,PATCH,DELETE,OPTIONS'
gitea_cors_max_age: '10m'
gitea_cors_allowed_credentials: false
gitea_cors_headers: 'Content-Type,User-Agent'
gitea_cors_x_frame_options: 'SAMEORIGIN'
# UI Configuration
# ->
gitea_ui_default_theme: "gitea-auto"
gitea_ui_themes: ""
gitea_ui_show_user_email: true
gitea_ui_show_full_name: false
gitea_ui_extra_config: {}
# UI Meta Configuration
# ->
gitea_ui_meta_author: 'Gitea - Git with a cup of tea'
gitea_ui_meta_description: 'Gitea (Git with a cup of tea) is a painless self-hosted Git service written in Go'
gitea_ui_meta_keywords: 'go,git,self-hosted,gitea'
# Server (server)
# -> https://docs.gitea.io/en-us/config-cheat-sheet/#server-server
gitea_protocol: "http"
gitea_http_domain: "{{ gitea_fqdn }}"
gitea_root_url: "{{ gitea_protocol }}://{{ gitea_fqdn }}"
gitea_http_listen: "127.0.0.1"
gitea_internal_http_port: 3000
gitea_internal_ssh_port: 2222
gitea_ssh_listen: "0.0.0.0"
gitea_start_ssh: true
gitea_ssh_domain: "{{ gitea_http_domain }}"
gitea_landing_page: 'home'
gitea_server_extra_config: {}
# Security (security)
# -> https://docs.gitea.io/en-us/config-cheat-sheet/#security-security
gitea_secret_key: ""
gitea_internal_token: ""
gitea_install_lock: false
gitea_disable_git_hooks: true
gitea_disable_webhooks: false
gitea_reverse_proxy_limit: 1
gitea_reverse_proxy_trusted_proxies: "127.0.0.0/8,::1/128"
gitea_password_complexity: "off"
gitea_password_min_length: 8
gitea_password_check_pwn: false
gitea_2fa: ""
gitea_login_remember_days: 31
gitea_cookie_remember_name: "gitea_incredible"
gitea_security_extra_config: {}
# Service (service)
# -> https://docs.gitea.io/en-us/config-cheat-sheet/#service-service
gitea_disable_registration: false
gitea_register_email_confirm: false
gitea_register_manual_confirm: false
gitea_require_signin_view: false
gitea_enable_notify_mail: false
gitea_enable_captcha: false
gitea_require_captcha_for_login: false
gitea_captcha_type: image
gitea_show_registration_button: true
gitea_default_keep_email_private: false
gitea_default_allow_create_organization: true
gitea_default_user_is_restricted: false
gitea_default_user_visibility: public
gitea_default_org_visibility: public
gitea_default_org_member_visible: false
gitea_allow_only_internal_registration: false
gitea_allow_only_external_registration: false
gitea_email_domain_allowlist: ""
gitea_email_domain_blocklist: ""
gitea_no_reply_address: ""
gitea_enable_user_heatmap: true
gitea_enable_timetracking: true
gitea_auto_watch_new_repos: true
gitea_auto_watch_on_changes: false
gitea_show_milestones_dashboard_page: true
gitea_service_extra_config: {}
# Indexer (indexer)
# -> https://docs.gitea.com/administration/config-cheat-sheet#indexer-indexer
gitea_issue_indexer_type: 'bleve'
gitea_issue_indexer_connection_string: ''
gitea_issue_indexer_name: 'gitea_issues'
gitea_issue_indexer_path: 'indexers/issues.bleve'
gitea_repo_indexer_enabled: false
gitea_repo_indexer_repo_types: 'sources,forks,mirrors,templates'
gitea_repo_indexer_type: 'bleve'
gitea_repo_indexer_path: 'indexers/repos.bleve'
gitea_repo_indexer_connection_string: ''
gitea_repo_indexer_name: 'gitea_codes'
gitea_repo_indexer_include: ''
gitea_repo_indexer_exclude: ''
gitea_repo_indexer_exclude_vendored: true
gitea_repo_indexer_max_file_size: 1048576
gitea_indexer_startup_timeout: '30s'
gitea_indexer_extra_config: {}
# Packages (packages)
# -> https://docs.gitea.io/en-us/config-cheat-sheet/#packages-packages
gitea_packages_enabled: true
gitea_packages_extra_config: {}
# Actions (actions)
# -> https://docs.gitea.io/en-us/config-cheat-sheet/#actions-actions
gitea_actions_enabled: false
gitea_actions_default_actions_url: github
gitea_actions_extra_config: {}
# Log (log)
# -> https://docs.gitea.com/next/administration/config-cheat-sheet#log-log
gitea_log_root_path: ""
gitea_log_mode: console
gitea_log_level: Info
gitea_enable_ssh_log: false
gitea_log_extra_config: {}
# Mailer (mailer)
# -> https://docs.gitea.io/en-us/config-cheat-sheet/#mailer-mailer
gitea_mailer_enabled: false
gitea_mailer_protocol: "" # smtp, smtps, smtp+starttls, smtp+unix, sendmail, dummy
gitea_mailer_smtp_addr: ""
gitea_mailer_smtp_port: ""
gitea_mailer_user: ""
gitea_mailer_password: ""
gitea_mailer_from: "noreply@{{ gitea_http_domain }}"
gitea_mailer_subject_prefix: ""
gitea_mailer_send_as_plain_text: false
gitea_mailer_extra_config: {}
# Mirror (mirror)
# -> https://docs.gitea.io/en-us/config-cheat-sheet/#mirror-mirror
gitea_mirror_enabled: true
gitea_mirror_disable_new_pull: false
gitea_mirror_disable_new_push: false
gitea_mirror_default_interval: 8h
gitea_mirror_min_interval: 10m
gitea_mirror_extra_config: {}
# Other (other)
# -> https://docs.gitea.io/en-us/config-cheat-sheet/#other-other
gitea_show_footer_version: true
gitea_show_footer_template_load_time: true
gitea_enable_sitemap: true
gitea_enable_feed: true
gitea_other_extra_config: {}
# Metrics (metrics)
# -> https://docs.gitea.io/en-us/config-cheat-sheet/#metrics-metrics
gitea_metrics_enabled: false
gitea_metrics_token: ""
gitea_metrics_extra_config: {}
# API (api)
# -> https://docs.gitea.io/en-us/config-cheat-sheet/#api-api
gitea_api_enable_swagger: true
gitea_api_max_response_items: 50
gitea_api_default_paging_num: 30
gitea_api_extra_config: {}
# OAuth2 (oauth2)
# -> https://docs.gitea.io/en-us/config-cheat-sheet/#oauth2-oauth2
gitea_oauth2_enabled: true
gitea_oauth2_access_token_expiration_time: 3600
gitea_oauth2_refresh_token_expiration_time: 730
gitea_oauth2_jwt_signing_algorithm: RS256
gitea_oauth2_jwt_secret: ""
gitea_oauth2_extra_config: {}
# A dictionary of additional environment variables
# Read the cheat sheet before adding configurations https://docs.gitea.com/administration/config-cheat-sheet
gitea_extra_config: {}
# ENV_VAR_KEY: value
+6
View File
@@ -0,0 +1,6 @@
---
- name: "Restart fail2ban"
become: true
ansible.builtin.service:
name: fail2ban
state: restarted
+2
View File
@@ -0,0 +1,2 @@
install_date: Tue Dec 2 19:10:42 2025
version: ''
+40
View File
@@ -0,0 +1,40 @@
---
galaxy_info:
app_role_name: gitea
author: Patrick Jaroszewski
description: Ansible role to configure and deploy Gitea in Docker, with optional support for runners.
license: MIT License
min_ansible_version: 2.11
platforms:
- name: Debian
versions: all
- name: Ubuntu
version: all
galaxy_tags:
- gitea
- act_runner
- git
- gitserver
- selfhosted
dependencies:
- role: patrickj.docker_apps.docker_compose_app
vars:
app_role_name: gitea
app_compose_validate: false
app_compose_start: false
app_uid: "{{ gitea_uid }}"
app_gid: "{{ gitea_gid }}"
app_extra_templates:
- src: env.j2
dest: "{{ app_dir }}/.env"
# Directory structure
app_subdirectories:
- "{{ gitea_data_path }}"
- "{{ gitea_config_path }}"
- "{{ gitea_log_path }}"
# Backup configuration
app_backup_subdirectories:
- "{{ gitea_data_path }}"
- "{{ gitea_config_path }}"
+24
View File
@@ -0,0 +1,24 @@
---
- name: Get host IP
ansible.builtin.set_fact:
gitea_host_ip: "{{ ansible_default_ipv4.address }}"
- name: Create data directories for runners
ansible.builtin.file:
path: "{{ app_dir }}/{{ item.data_mount }}"
state: directory
mode: "{{ app_permission_mode }}"
owner: "{{ app_uid }}"
group: "{{ app_gid }}"
loop: "{{ gitea_runners }}"
- name: Create configuration files for each runner
ansible.builtin.template:
src: actions/config.yaml.j2
dest: "{{ app_dir }}/{{ item.config_file_mount }}"
mode: "{{ app_permission_mode }}"
owner: "{{ app_uid }}"
group: "{{ app_gid }}"
loop: "{{ gitea_runners }}"
+17
View File
@@ -0,0 +1,17 @@
---
- name: Deploy optional fail2ban rules
ansible.builtin.include_tasks: setup-fail2ban.yaml
when: gitea_fail2ban_enabled | bool
- name: Generate Gitea configuration files
ansible.builtin.include_tasks: generate-config.yaml
- name: Create or remove Gitea users
ansible.builtin.include_tasks: manage_users.yaml
when: gitea_users | length > 0
- name: Start Docker Compose stack after configuration
ansible.builtin.include_tasks: "{{ app_roles_path }}/docker_compose_app/tasks/manage_compose.yaml"
vars:
app_compose_start: true
+58
View File
@@ -0,0 +1,58 @@
---
- name: Get list of users
community.docker.docker_container_exec:
container: "{{ gitea_container_name }}"
command: /bin/bash -c "gitea admin user list"
register: user_list
failed_when: false
changed_when: false
when: gitea_users | length > 0
- name: Extract existing usernames
ansible.builtin.set_fact:
gitea_existing_users: "{{ user_list.stdout_lines[1:] | map('regex_replace', '^\\d+\\s+(\\S+)\\s+.*$', '\\1') | list | default([]) }}"
when:
- gitea_users | length > 0
- user_list.stdout_lines | default([]) | length > 1
- name: Create Gitea users
community.docker.docker_container_exec:
container: "{{ gitea_container_name }}"
command: >
/bin/bash -c "gitea admin user create
--username {{ user.username }}
--email {{ user.email }}
--password {{ user.password }}
--must-change-password={{ user.must_change_password | default(false) }}
--admin={{ user.admin | default(false) }}"
register: _gitea_user_result
failed_when:
- '"successfully created" not in _gitea_user_result.stdout'
changed_when:
- '"successfully created!" in _gitea_user_result.stdout'
when:
- user.username not in gitea_existing_users | default([]) and user.state | default('present') == 'present'
loop: "{{ gitea_users }}"
loop_control:
label: "user={{ user.username }}"
loop_var: user
# no_log: true # Avoid logging passwords
- name: Remove gitea users
community.docker.docker_container_exec:
container: "{{ gitea_container_name }}"
command: >
/bin/bash -c "gitea admin user delete
--username {{ user.username }}
--email {{ user.email }}"
register: _gitea_user_del_result
failed_when:
- '"error" in _gitea_user_del_result.stdout'
changed_when: "user.username in gitea_existing_users"
when: "user.username in gitea_existing_users | default([]) and user.state | default('present') == 'absent'"
loop: "{{ gitea_users }}"
loop_control:
label: "user={{ user.username }}"
loop_var: user
+39
View File
@@ -0,0 +1,39 @@
---
- name: Gather installed packages for checks later on
ansible.builtin.package_facts:
manager: "auto"
- name: Warn if fail2ban is not installed
ansible.builtin.fail:
msg: "the package fail2ban is not installed. no fail2ban filters deployed."
when: "'fail2ban' not in ansible_facts.packages"
failed_when: false
- name: Install fail2ban filter
become: true
ansible.builtin.template:
src: fail2ban/filter.conf.j2
dest: /etc/fail2ban/filter.d/gitea.local
owner: root
group: root
mode: "0444"
notify: "Restart fail2ban"
when: "'fail2ban' in ansible_facts.packages"
- name: Install fail2ban jail for logins over HTTP(S)
become: true
vars:
gitea_fail2ban_filter: gitea
gitea_fail2ban_port: "http,https,{{ gitea_ssh_port }}"
gitea_fail2ban_jail_name: gitea-docker
ansible.builtin.template:
src: fail2ban/jail.conf.j2
dest: /etc/fail2ban/jail.d/gitea.local
owner: root
group: root
mode: "0444"
notify: "Restart fail2ban"
when: "'fail2ban' in ansible_facts.packages"
@@ -0,0 +1,111 @@
# Example configuration file, it's safe to copy this as the default config file without any modification.
# https://gitea.com/gitea/act_runner/src/branch/main/internal/pkg/config/config.example.yaml
# You don't have to copy this file to your instance,
# just run `./act_runner generate-config > config.yaml` to generate a config file.
log:
# The level of logging, can be trace, debug, info, warn, error, fatal
level: info
runner:
# Where to store the registration result.
file: .runner
# Execute how many tasks concurrently at the same time.
capacity: 1
# Extra environment variables to run jobs.
envs:
# A_TEST_ENV_NAME_1: a_test_env_value_1
# A_TEST_ENV_NAME_2: a_test_env_value_2
# Extra environment variables to run jobs from a file.
# It will be ignored if it's empty or the file doesn't exist.
env_file: .env
# The timeout for a job to be finished.
# Please note that the Gitea instance also has a timeout (3h by default) for the job.
# So the job could be stopped by the Gitea instance if its timeout is shorter than this.
timeout: 3h
# The timeout for the runner to wait for running jobs to finish when shutting down.
# Any running jobs that haven't finished after this timeout will be cancelled.
shutdown_timeout: 0s
# Whether skip verifying the TLS certificate of the Gitea instance.
insecure: false
# The timeout for fetching the job from the Gitea instance.
fetch_timeout: 5s
# The interval for fetching the job from the Gitea instance.
fetch_interval: 2s
# The github_mirror of a runner is used to specify the mirror address of the github that pulls the action repository.
# It works when something like `uses: actions/checkout@v4` is used and DEFAULT_ACTIONS_URL is set to github,
# and github_mirror is not empty. In this case,
# it replaces https://github.com with the value here, which is useful for some special network environments.
github_mirror: ''
# The labels of a runner are used to determine which jobs the runner can run, and how to run them.
# Like: "macos-arm64:host" or "ubuntu-latest:docker://docker.gitea.com/runner-images:ubuntu-latest"
# Find more images provided by Gitea at https://gitea.com/gitea/runner-images .
# If it's empty when registering, it will ask for inputting labels.
# If it's empty when execute `daemon`, will use labels in `.runner` file.
labels:
- "ubuntu-latest:docker://docker.gitea.com/runner-images:ubuntu-latest"
- "ubuntu-24.04:docker://docker.gitea.com/runner-images:ubuntu-24.04"
- "ubuntu-22.04:docker://docker.gitea.com/runner-images:ubuntu-22.04"
cache:
# Enable cache server to use actions/cache.
enabled: {{ item.cache_enabled | bool | lower }}
# The directory to store the cache data.
# If it's empty, the cache data will be stored in $HOME/.cache/actcache.
dir: ""
# The host of the cache server.
# It's not for the address to listen, but the address to connect from job containers.
# So 0.0.0.0 is a bad choice, leave it empty to detect automatically.
host: {{ gitea_host_ip }}
# The port of the cache server.
# 0 means to use a random available port.
port: {{ item.cache_port }}
# The external cache server URL. Valid only when enable is true.
# If it's specified, act_runner will use this URL as the ACTIONS_CACHE_URL rather than start a server by itself.
# The URL should generally end with "/".
external_server: ""
container:
# Specifies the network to which the container will connect.
# Could be host, bridge or the name of a custom network.
# If it's empty, act_runner will create a network automatically.
network: ""
# Whether to use privileged mode or not when launching task containers (privileged mode is required for Docker-in-Docker).
privileged: false
# Any other options to be used when the container is started (e.g., --add-host=my.gitea.url:host-gateway).
options:
# The parent directory of a job's working directory.
# NOTE: There is no need to add the first '/' of the path as act_runner will add it automatically.
# If the path starts with '/', the '/' will be trimmed.
# For example, if the parent directory is /path/to/my/dir, workdir_parent should be path/to/my/dir
# If it's empty, /workspace will be used.
workdir_parent:
# Volumes (including bind mounts) can be mounted to containers. Glob syntax is supported, see https://github.com/gobwas/glob
# You can specify multiple volumes. If the sequence is empty, no volumes can be mounted.
# For example, if you only allow containers to mount the `data` volume and all the json files in `/src`, you should change the config to:
# valid_volumes:
# - data
# - /src/*.json
# If you want to allow any volume, please use the following configuration:
# valid_volumes:
# - '**'
valid_volumes: []
# Overrides the docker client host with the specified one.
# If it's empty, act_runner will find an available docker host automatically.
# If it's "-", act_runner will find an available docker host automatically, but the docker host won't be mounted to the job containers and service containers.
# If it's not empty or "-", the specified docker host will be used. An error will be returned if it doesn't work.
docker_host: ""
# Pull docker image(s) even if already present
force_pull: true
# Rebuild docker image(s) even if already present
force_rebuild: false
# Always require a reachable docker daemon, even if not required by act_runner
require_docker: false
# Timeout to wait for the docker daemon to be reachable, if docker is required by require_docker or act_runner
docker_timeout: 0s
host:
# The parent directory of a job's working directory.
# If it's empty, $HOME/.cache/act/ will be used.
workdir_parent:
+42
View File
@@ -0,0 +1,42 @@
---
services:
gitea:
image: docker.gitea.com/gitea:{{ gitea_container_version }}
container_name: "{{ gitea_container_name }}"
restart: "{{ gitea_restart_policy }}"
environment:
- USER_UID={{ app_uid }}
- USER_GID={{ app_gid }}
env_file:
- .env
volumes:
- "{{ gitea_data_path }}:/var/lib/gitea"
- "{{ gitea_config_path }}:/etc/gitea"
- "{{ gitea_log_path }}:/var/log/gitea"
- "/etc/timezone:/etc/timezone:ro"
- "/etc/localtime:/etc/localtime:ro"
ports:
- "127.0.0.1:{{ gitea_http_port }}:3000"
- "0.0.0.0:{{ gitea_ssh_port }}:2222"
{% for runner in gitea_runners %}
{{ runner.name }}:
image: "{{ gitea_runner_image }}:{{ gitea_runner_container_version }}"
container_name: "{{ app_name }}-{{ runner.name }}"
restart: "{{ gitea_runner_restart_policy }}"
privileged: true
depends_on:
- "{{ gitea_container_name }}"
volumes:
- {{ runner.config_file_mount }}:/config.yaml
- {{ runner.data_mount }}:/data
{% if runner.cache_enabled %}
ports:
- 127.0.0.1:{{ runner.cache_port }}:{{ runner.cache_port }}
{% endif %}
environment:
CONFIG_FILE: /config.yaml
GITEA_RUNNER_NAME: {{ runner.name }}
GITEA_INSTANCE_URL: {{ gitea_root_url }}
DOCKER_HOST: "unix:///var/run/user/{{ app_uid }}/docker.sock"
GITEA_RUNNER_REGISTRATION_TOKEN: {{ gitea_runner_global_registration_token | default(runner.registration_token) | default('') }}
{% endfor %}
+429
View File
@@ -0,0 +1,429 @@
# ============================================
# Default Configuration
# ============================================
GITEA__DEFAULT__APP_NAME={{ gitea_app_name }}
GITEA__DEFAULT__RUN_MODE={{ gitea_run_mode }}
GITEA__DEFAULT__RUN_USER={{ gitea_user }}
# ============================================
# Server Configuration
# ============================================
GITEA__server__PROTOCOL={{ gitea_protocol }}
GITEA__server__DOMAIN={{ gitea_http_domain }}
GITEA__server__ROOT_URL={{ gitea_root_url }}
GITEA__server__HTTP_ADDR={{ gitea_http_listen }}
GITEA__server__HTTP_PORT={{ gitea_internal_http_port }}
GITEA__server__SSH_PORT={{ gitea_internal_ssh_port }}
GITEA__server__SSH_LISTEN_HOST={{ gitea_ssh_listen }}
GITEA__server__START_SSH_SERVER={{ gitea_start_ssh | bool | lower }}
GITEA__server__SSH_DOMAIN={{ gitea_ssh_domain }}
GITEA__server__LANDING_PAGE={{ gitea_landing_page }}
{% if gitea_server_extra_config %}
# Additional Server Configuration
{% for item in gitea_server_extra_config | dict2items %}
GITEA__server__{{ item.key }}={{ item.value }}
{% endfor %}
{% endif %}
# ============================================
# Service Configuration
# ============================================
GITEA__service__DISABLE_REGISTRATION={{ gitea_disable_registration | bool | lower }}
GITEA__service__REGISTER_EMAIL_CONFIRM={{ gitea_register_email_confirm | bool | lower }}
GITEA__service__REGISTER_MANUAL_CONFIRM={{ gitea_register_manual_confirm | bool | lower }}
GITEA__service__REQUIRE_SIGNIN_VIEW={{ gitea_require_signin_view | bool | lower }}
GITEA__service__ENABLE_NOTIFY_MAIL={{ gitea_enable_notify_mail | bool | lower }}
GITEA__service__ENABLE_CAPTCHA={{ gitea_enable_captcha | bool | lower }}
{% if gitea_enable_captcha %}
GITEA__service__REQUIRE_CAPTCHA_FOR_LOGIN={{ gitea_require_captcha_for_login }}
GITEA__service__CAPTCHA_TYPE={{ gitea_captcha_type }}
{% endif %}
GITEA__service__SHOW_REGISTRATION_BUTTON={{ gitea_show_registration_button | bool | lower }}
GITEA__service__DEFAULT_KEEP_EMAIL_PRIVATE={{ gitea_default_keep_email_private | bool | lower }}
GITEA__service__DEFAULT_ALLOW_CREATE_ORGANIZATION={{ gitea_default_allow_create_organization | bool | lower }}
GITEA__service__DEFAULT_USER_IS_RESTRICTED={{ gitea_default_user_is_restricted | bool | lower }}
GITEA__service__DEFAULT_USER_VISIBILITY={{ gitea_default_user_visibility }}
GITEA__service__DEFAULT_ORG_VISIBILITY={{ gitea_default_org_visibility }}
GITEA__service__DEFAULT_ORG_MEMBER_VISIBLE={{ gitea_default_org_member_visible | bool | lower }}
GITEA__service__ALLOW_ONLY_INTERNAL_REGISTRATION={{ gitea_allow_only_internal_registration | bool | lower }}
GITEA__service__ALLOW_ONLY_EXTERNAL_REGISTRATION={{ gitea_allow_only_external_registration | bool | lower }}
{% if gitea_email_domain_allowlist %}
GITEA__service__EMAIL_DOMAIN_ALLOWLIST={{ gitea_email_domain_allowlist }}
{% endif %}
{% if gitea_email_domain_blocklist %}
GITEA__service__EMAIL_DOMAIN_BLOCKLIST={{ gitea_email_domain_blocklist }}
{% endif %}
{% if gitea_no_reply_address %}
GITEA__service__NO_REPLY_ADDRESS={{ gitea_no_reply_address }}
{% endif %}
GITEA__service__ENABLE_USER_HEATMAP={{ gitea_enable_user_heatmap | bool | lower }}
GITEA__service__ENABLE_TIMETRACKING={{ gitea_enable_timetracking | bool | lower }}
GITEA__service__AUTO_WATCH_NEW_REPOS={{ gitea_auto_watch_new_repos | bool | lower }}
GITEA__service__AUTO_WATCH_ON_CHANGES={{ gitea_auto_watch_on_changes | bool | lower }}
GITEA__service__SHOW_MILESTONES_DASHBOARD_PAGE={{ gitea_show_milestones_dashboard_page | bool | lower }}
{% if gitea_service_extra_config %}
# Additional Service Configuration
{% for item in gitea_service_extra_config | dict2items %}
{% if item.value is boolean %}
GITEA__service__{{ item.key }}={{ item.value | bool | lower }}
{% else %}
GITEA__service__{{ item.key }}={{ item.value }}
{% endif %}
{% endfor %}
{% endif %}
# ============================================
# Security Configuration
# ============================================
{% if gitea_secret_key %}
GITEA__security__SECRET_KEY={{ gitea_secret_key }}
{% endif %}
{% if gitea_internal_token %}
GITEA__security__INTERNAL_TOKEN={{ gitea_internal_token }}
{% endif %}
GITEA__security__INSTALL_LOCK={{ gitea_install_lock | bool | lower }}
GITEA__security__DISABLE_GIT_HOOKS={{ gitea_disable_git_hooks | bool | lower }}
GITEA__security__DISABLE_WEBHOOKS={{ gitea_disable_webhooks | bool | lower }}
GITEA__security__PASSWORD_COMPLEXITY={{ gitea_password_complexity }}
GITEA__security__PASSWORD_MIN_LENGTH={{ gitea_password_min_length }}
GITEA__security__PASSWORD_CHECK_PWN={{ gitea_password_check_pwn | bool | lower }}
{% if gitea_2fa %}
GITEA__security__TWO_FACTOR_AUTH={{ gitea_2fa }}
{% endif %}
GITEA__security__LOGIN_REMEMBER_DAYS={{ gitea_login_remember_days }}
GITEA__security__COOKIE_REMEMBER_NAME={{ gitea_cookie_remember_name }}
{% if gitea_security_extra_config %}
# Additional Security Configuration
{% for item in gitea_security_extra_config | dict2items %}
GITEA__security__{{ item.key }}={{ item.value if item.value is not boolean else (item.value | bool | lower) }}
{% endfor %}
{% endif %}
# ============================================
# Repository Configuration
# ============================================
GITEA__repository__FORCE_PRIVATE={{ gitea_repo_force_private }}
GITEA__repository__DEFAULT_PRIVATE={{ gitea_repo_default_private }}
GITEA__repository__DEFAULT_PUSH_CREATE_PRIVATE={{ gitea_repo_default_push_create_private }}
GITEA__repository__PREFERRED_LICENSES={{ gitea_repo_preferred_licenses }}
GITEA__repository__DISABLE_HTTP_GIT={{ gitea_repo_disable_http_git }}
GITEA__repository__DEFAULT_BRANCH={{ gitea_repo_default_branch }}
GITEA__repository__DISABLE_STARS={{ gitea_repo_disable_stars }}
GITEA__repository__DISABLE_MIGRATIONS={{ gitea_repo_disable_migrations }}
{% if gitea_repository_extra_config %}
# Additional Repository Configuration
{% for item in gitea_repository_extra_config | dict2items %}
{% if item.value is boolean %}
GITEA__repository__{{ item.key }}={{ item.value | bool | lower }}
{% else %}
GITEA__repository__{{ item.key }}={{ item.value }}
{% endif %}
{% endfor %}
{% endif %}
# ============================================
# CORS Configuration
# ============================================
GITEA__cors__ENABLED={{ gitea_cors_enabled }}
GITEA__cors__ALLOW_DOMAIN={{ gitea_cors_allowed_domains }}
GITEA__cors__METHODS={{ gitea_cors_allowed_methods }}
GITEA__cors__MAX_AGE={{ gitea_cors_max_age }}
GITEA__cors__ALLOW_CREDENTIALS={{ gitea_cors_allowed_credentials | bool | lower }}
GITEA__cors__HEADERS={{ gitea_cors_headers }}
GITEA__cors__X_FRAME_OPTIONS={{ gitea_cors_x_frame_options }}
# ============================================
# UI Configuration
# ============================================
GITEA__ui__DEFAULT_THEME={{ gitea_ui_default_theme }}
GITEA__ui__THEMES={{ gitea_ui_themes }}
GITEA__ui__SHOW_USER_EMAIL={{ gitea_ui_show_user_email }}
GITEA__ui__DEFAULT_SHOW_FULL_NAME={{ gitea_ui_show_full_name }}
{% if gitea_ui_extra_config %}
# Additional UI Configuration
{% for item in gitea_ui_extra_config | dict2items %}
{% if item.value is boolean %}
GITEA__ui__{{ item.key }}={{ item.value | bool | lower }}
{% else %}
GITEA__ui__{{ item.key }}={{ item.value }}
{% endif %}
{% endfor %}
{% endif %}
# ============================================
# UI.meta Configuration
# ============================================
GITEA__ui.meta__AUTHOR={{ gitea_ui_meta_author }}
GITEA__ui.meta__DESCRIPTION={{ gitea_ui_meta_description }}
GITEA__ui.meta__KEYWORDS={{ gitea_ui_meta_keywords }}
# ============================================
# Indexer Configuration
# ============================================
# Issue Indexer
GITEA__indexer__ISSUE_INDEXER_TYPE={{ gitea_issue_indexer_type }}
{% if gitea_issue_indexer_type in ['elasticsearch', 'meilisearch'] and gitea_issue_indexer_connection_string %}
GITEA__indexer__ISSUE_INDEXER_CONN_STR={{ gitea_issue_indexer_connection_string }}
{% endif %}
{% if gitea_issue_indexer_type in ['elasticsearch', 'meilisearch'] and gitea_issue_indexer_name %}
GITEA__indexer__ISSUE_INDEXER_NAME={{ gitea_issue_indexer_name }}
{% endif %}
{% if gitea_issue_indexer_type == 'bleve' and gitea_issue_indexer_path %}
GITEA__indexer__ISSUE_INDEXER_PATH={{ gitea_issue_indexer_path }}
{% endif %}
# Repository Indexer
GITEA__indexer__REPO_INDEXER_ENABLED={{ gitea_repo_indexer_enabled | bool | lower }}
{% if gitea_repo_indexer_enabled %}
{% if gitea_repo_indexer_repo_types %}
GITEA__indexer__REPO_INDEXER_REPO_TYPES={{ gitea_repo_indexer_repo_types }}
{% endif %}
GITEA__indexer__REPO_INDEXER_TYPE={{ gitea_repo_indexer_type }}
{% if gitea_repo_indexer_type == 'bleve' and gitea_repo_indexer_path %}
GITEA__indexer__REPO_INDEXER_PATH={{ gitea_repo_indexer_path }}
{% endif %}
{% if gitea_repo_indexer_type == 'elasticsearch' and gitea_repo_indexer_connection_string %}
GITEA__indexer__REPO_INDEXER_CONN_STR={{ gitea_repo_indexer_connection_string }}
{% endif %}
{% if gitea_repo_indexer_type == 'elasticsearch' and gitea_repo_indexer_name %}
GITEA__indexer__REPO_INDEXER_NAME={{ gitea_repo_indexer_name }}
{% endif %}
{% if gitea_repo_indexer_include %}
GITEA__indexer__REPO_INDEXER_INCLUDE={{ gitea_repo_indexer_include }}
{% endif %}
{% if gitea_repo_indexer_exclude %}
GITEA__indexer__REPO_INDEXER_EXCLUDE={{ gitea_repo_indexer_exclude }}
{% endif %}
GITEA__indexer__REPO_INDEXER_EXCLUDE_VENDORED={{ gitea_repo_indexer_exclude_vendored | bool | lower }}
GITEA__indexer__MAX_FILE_SIZE={{ gitea_repo_indexer_max_file_size }}
{% endif %}
{% if gitea_indexer_startup_timeout %}
GITEA__indexer__STARTUP_TIMEOUT={{ gitea_indexer_startup_timeout }}
{% endif %}
{% if gitea_indexer_extra_config %}
# Additional Indexer Configuration
{% for item in gitea_indexer_extra_config | dict2items %}
{% if item.value is boolean %}
GITEA__indexer__{{ item.key }}={{ item.value | bool | lower }}
{% else %}
GITEA__indexer__{{ item.key }}={{ item.value }}
{% endif %}
{% endfor %}
{% endif %}
# ============================================
# Packages Configuration
# ============================================
GITEA__packages__ENABLED={{ gitea_packages_enabled | bool | lower }}
{% if gitea_packages_extra_config %}
# Additional Packages Configuration
{% for item in gitea_packages_extra_config | dict2items %}
GITEA__packages__{{ item.key }}={{ item.value if item.value is not boolean else (item.value | bool | lower) }}
{% endfor %}
{% endif %}
# ============================================
# Actions Configuration
# ============================================
GITEA__actions__ENABLED={{ gitea_actions_enabled | bool | lower }}
{% if gitea_actions_enabled %}
GITEA__actions__DEFAULT_ACTIONS_URL={{ gitea_actions_default_actions_url }}
{% endif %}
{% if gitea_runner_global_registration_token %}
GITEA_RUNNER_REGISTRATION_TOKEN={{ gitea_runner_global_registration_token }}
{% endif %}
{% if gitea_actions_extra_config %}
# Additional Actions Configuration
{% for item in gitea_actions_extra_config | dict2items %}
GITEA__actions__{{ item.key }}={{ item.value if item.value is not boolean else (item.value | bool | lower) }}
{% endfor %}
{% endif %}
# ============================================
# Log Configuration
# ============================================
{% if gitea_log_root_path %}
GITEA__log__ROOT_PATH={{ gitea_log_root_path }}
{% endif %}
GITEA__log__MODE={{ gitea_log_mode }}
GITEA__log__LEVEL={{ gitea_log_level }}
{% if gitea_log_extra_config %}
# Additional Log Configuration
{% for item in gitea_log_extra_config | dict2items %}
{% if item.value is boolean %}
GITEA__log__{{ item.key }}={{ item.value | bool | lower }}
{% else %}
GITEA__log__{{ item.key }}={{ item.value }}
{% endif %}
{% endfor %}
{% endif %}
# ============================================
# Mailer Configuration
# ============================================
GITEA__mailer__ENABLED={{ gitea_mailer_enabled | bool | lower }}
{% if gitea_mailer_enabled %}
{% if gitea_mailer_protocol %}
GITEA__mailer__PROTOCOL={{ gitea_mailer_protocol }}
{% endif %}
{% if gitea_mailer_smtp_addr %}
GITEA__mailer__SMTP_ADDR={{ gitea_mailer_smtp_addr }}
{% endif %}
{% if gitea_mailer_smtp_port %}
GITEA__mailer__SMTP_PORT={{ gitea_mailer_smtp_port }}
{% endif %}
{% if gitea_mailer_user %}
GITEA__mailer__USER={{ gitea_mailer_user }}
{% endif %}
{% if gitea_mailer_password %}
GITEA__mailer__PASSWD={{ gitea_mailer_password }}
{% endif %}
{% if gitea_mailer_from %}
GITEA__mailer__FROM={{ gitea_mailer_from }}
{% endif %}
{% if gitea_mailer_subject_prefix %}
GITEA__mailer__SUBJECT_PREFIX={{ gitea_mailer_subject_prefix }}
{% endif %}
GITEA__mailer__SEND_AS_PLAIN_TEXT={{ gitea_mailer_send_as_plain_text | bool | lower }}
{% endif %}
{% if gitea_mailer_extra_config %}
# Additional Mailer Configuration
{% for item in gitea_mailer_extra_config | dict2items %}
{% if item.value is boolean %}
GITEA__mailer__{{ item.key }}={{ item.value | bool | lower }}
{% else %}
GITEA__mailer__{{ item.key }}={{ item.value }}
{% endif %}
{% endfor %}
{% endif %}
# ============================================
# Mirror Configuration
# ============================================
GITEA__mirror__ENABLED={{ gitea_mirror_enabled | bool | lower }}
GITEA__mirror__DISABLE_NEW_PULL={{ gitea_mirror_disable_new_pull | bool | lower }}
GITEA__mirror__DISABLE_NEW_PUSH={{ gitea_mirror_disable_new_push | bool | lower }}
GITEA__mirror__DEFAULT_INTERVAL={{ gitea_mirror_default_interval }}
GITEA__mirror__MIN_INTERVAL={{ gitea_mirror_min_interval }}
{% if gitea_mirror_extra_config %}
# Additional Mirror Configuration
{% for item in gitea_mirror_extra_config | dict2items %}
{% if item.value is boolean %}
GITEA__mirror__{{ item.key }}={{ item.value | bool | lower }}
{% else %}
GITEA__mirror__{{ item.key }}={{ item.value }}
{% endif %}
{% endfor %}
{% endif %}
# ============================================
# Metrics Configuration
# ============================================
GITEA__metrics__ENABLED={{ gitea_metrics_enabled | bool | lower }}
{% if gitea_metrics_enabled and gitea_metrics_token %}
GITEA__metrics__TOKEN={{ gitea_metrics_token }}
{% endif %}
{% if gitea_metrics_extra_config %}
# Additional Metrics Configuration
{% for item in gitea_metrics_extra_config | dict2items %}
{% if item.value is boolean %}
GITEA__metrics__{{ item.key }}={{ item.value | bool | lower }}
{% else %}
GITEA__metrics__{{ item.key }}={{ item.value }}
{% endif %}
{% endfor %}
{% endif %}
# ============================================
# API Configuration
# ============================================
GITEA__api__ENABLE_SWAGGER={{ gitea_api_enable_swagger | bool | lower }}
GITEA__api__MAX_RESPONSE_ITEMS={{ gitea_api_max_response_items }}
GITEA__api__DEFAULT_PAGING_NUM={{ gitea_api_default_paging_num }}
{% if gitea_api_extra_config %}
# Additional API Configuration
{% for item in gitea_api_extra_config | dict2items %}
{% if item.value is boolean %}
GITEA__api__{{ item.key }}={{ item.value | bool | lower }}
{% else %}
GITEA__api__{{ item.key }}={{ item.value }}
{% endif %}
{% endfor %}
{% endif %}
# ============================================
# OAuth2 Configuration
# ============================================
GITEA__oauth2__ENABLED={{ gitea_oauth2_enabled | bool | lower }}
{% if gitea_oauth2_enabled %}
GITEA__oauth2__ACCESS_TOKEN_EXPIRATION_TIME={{ gitea_oauth2_access_token_expiration_time }}
GITEA__oauth2__REFRESH_TOKEN_EXPIRATION_TIME={{ gitea_oauth2_refresh_token_expiration_time }}
GITEA__oauth2__JWT_SIGNING_ALGORITHM={{ gitea_oauth2_jwt_signing_algorithm }}
{% if gitea_oauth2_jwt_secret %}
GITEA__oauth2__JWT_SECRET={{ gitea_oauth2_jwt_secret }}
{% endif %}
{% endif %}
{% if gitea_oauth2_extra_config %}
# Additional OAuth2 Configuration
{% for item in gitea_oauth2_extra_config | dict2items %}
{% if item.value is boolean %}
GITEA__oauth2__{{ item.key }}={{ item.value | bool | lower }}
{% else %}
GITEA__oauth2__{{ item.key }}={{ item.value }}
{% endif %}
{% endfor %}
{% endif %}
# ============================================
# Other Configuration
# ============================================
GITEA__other__SHOW_FOOTER_VERSION={{ gitea_show_footer_version | bool | lower }}
GITEA__other__SHOW_FOOTER_TEMPLATE_LOAD_TIME={{ gitea_show_footer_template_load_time | bool | lower }}
GITEA__other__ENABLE_SITEMAP={{ gitea_enable_sitemap | bool | lower }}
GITEA__other__ENABLE_FEED={{ gitea_enable_feed | bool | lower }}
{% if gitea_other_extra_config %}
# Additional Other Configuration
{% for item in gitea_other_extra_config | dict2items %}
{% if item.value is boolean %}
GITEA__other__{{ item.key }}={{ item.value | bool | lower }}
{% else %}
GITEA__other__{{ item.key }}={{ item.value }}
{% endif %}
{% endfor %}
{% endif %}
# ============================================
# Additonal environment variables
# ============================================
{% for item in gitea_extra_config | dict2items %}
{% if item.value is boolean %}
{{ item.key }}={{ item.value | bool | lower }}
{% else %}
{{ item.key }}={{ item.value }}
{% endif %}
{% endfor %}
@@ -0,0 +1,4 @@
# gitea.local
[Definition]
failregex = .*(Failed authentication attempt|invalid credentials|Attempted access of unknown user).* from <HOST>
ignoreregex =
@@ -0,0 +1,11 @@
{# https://docs.gitea.com/administration/fail2ban-setup #}
[{{ gitea_fail2ban_jail_name }}]
enabled = true
filter = {{ gitea_fail2ban_filter }}
port = {{ gitea_fail2ban_port }}
logpath = {{ gitea_mounted_log_path }}
maxretry = {{ gitea_fail2ban_jail_maxretry }}
findtime = {{ gitea_fail2ban_jail_findtime }}
bantime = {{ gitea_fail2ban_jail_bantime }}
action = {{ gitea_fail2ban_jail_action }}
+44
View File
@@ -0,0 +1,44 @@
# Glance
Deploy Glance dashboard using Docker Compose.
## Description
Glance is a self-hosted dashboard that displays information from various sources in a simple, configurable interface.
## Variables
### Optional
| Variable | Default | Description |
|----------|---------|-------------|
| `glance_config_template` | `{{ app_templates_path }}/glance.yml.j2` | Template file for generating glance.yml config |
| `glance_config_path` | `{{ app_dir }}/config` | Configuration storage |
| `glance_http_port` | `8080` | Web interface port |
| `glance_container_version` | `latest` | Glance Docker image tag |
| `glance_restart_policy` | `{{ app_restart_policy }}` | Container restart policy |
## Example
```yaml
- role: patrickj.docker_apps.glance
vars:
glance_http_port: 3000
glance_config_template: "/path/to/your/custom/glance.yml.j2"
```
## Configuration
The role includes a default configuration template with example widgets (RSS feeds, weather, calendar, markets, etc.). To customize your dashboard:
1. **Option 1**: Create your own template file and set `glance_config_template` to point to it
2. **Option 2**: Manually edit `{app_dir}/glance.yml` after deployment
The default template includes widgets for:
- Calendar and weather
- RSS feeds (selfhosted, tech blogs)
- Twitch channels and YouTube videos
- Reddit subreddits and Hacker News
- Stock market data and GitHub releases
+16
View File
@@ -0,0 +1,16 @@
---
app_name: glance
# Container configuration
glance_container_name: "{{ app_name | default('glance') }}"
glance_container_version: latest
glance_restart_policy: "{{ app_restart_policy }}"
# Network configuration
glance_http_port: 8080
# Volume paths
glance_config_path: "{{ app_dir }}/config"
# App-specific configuration
glance_config_template: "{{ app_templates_path }}/glance.yml.j2"
+17
View File
@@ -0,0 +1,17 @@
---
galaxy_info:
author: Patrick Jaroszewski
description: Deploy Glance with Docker Compose
license: MIT
dependencies:
- role: patrickj.docker_apps.docker_compose_app
vars:
app_role_name: glance
app_subdirectories:
- "{{ glance_config_path }}"
app_backup_subdirectories:
- "{{ glance_config_path }}"
app_extra_templates:
- src: "{{ glance_config_template }}"
dest: "{{ glance_config_path }}/glance.yml"
+10
View File
@@ -0,0 +1,10 @@
---
services:
glance:
container_name: {{ glance_container_name }}
image: glanceapp/glance:{{ glance_container_version }}
restart: {{ glance_restart_policy }}
volumes:
- {{ glance_config_path }}:/app/config
ports:
- "{{ glance_http_port }}:8080"
+105
View File
@@ -0,0 +1,105 @@
pages:
- name: Home
# Optionally, if you only have a single page you can hide the desktop navigation for a cleaner look
# hide-desktop-navigation: true
columns:
- size: small
widgets:
- type: calendar
first-day-of-week: monday
- type: rss
limit: 10
collapse-after: 3
cache: 12h
feeds:
- url: https://selfh.st/rss/
title: selfh.st
limit: 4
- url: https://ciechanow.ski/atom.xml
- url: https://www.joshwcomeau.com/rss.xml
title: Josh Comeau
- url: https://samwho.dev/rss.xml
- url: https://ishadeed.com/feed.xml
title: Ahmad Shadeed
- type: twitch-channels
channels:
- theprimeagen
- j_blow
- giantwaffle
- cohhcarnage
- christitustech
- EJ_SA
- size: full
widgets:
- type: group
widgets:
- type: hacker-news
- type: lobsters
- type: videos
channels:
- UCXuqSBlHAE6Xw-yeJA0Tunw # Linus Tech Tips
- UCR-DXc1voovS8nhAvccRZhg # Jeff Geerling
- UCsBjURrPoezykLs9EqgamOA # Fireship
- UCBJycsmduvYEL83R_U4JriQ # Marques Brownlee
- UCHnyfMqiRRG1u-2MsSQLbXA # Veritasium
- type: group
widgets:
- type: reddit
subreddit: technology
show-thumbnails: true
- type: reddit
subreddit: selfhosted
show-thumbnails: true
- size: small
widgets:
- type: weather
location: London, United Kingdom
units: metric # alternatively "imperial"
hour-format: 12h # alternatively "24h"
# Optionally hide the location from being displayed in the widget
# hide-location: true
- type: markets
markets:
- symbol: SPY
name: S&P 500
- symbol: BTC-USD
name: Bitcoin
- symbol: NVDA
name: NVIDIA
- symbol: AAPL
name: Apple
- symbol: MSFT
name: Microsoft
- type: releases
cache: 1d
# Without authentication the Github API allows for up to 60 requests per hour. You can create a
# read-only token from your Github account settings and use it here to increase the limit.
# token: ...
repositories:
- glanceapp/glance
- go-gitea/gitea
- immich-app/immich
- syncthing/syncthing
# Add more pages here:
# - name: Your page name
# columns:
# - size: small
# widgets:
# # Add widgets here
# - size: full
# widgets:
# # Add widgets here
# - size: small
# widgets:
# # Add widgets here
+25
View File
@@ -0,0 +1,25 @@
# Grafana
Deploy Grafana data visualization platform using Docker Compose.
## Description
Grafana is an analytics and monitoring platform with beautiful dashboards and alerting capabilities.
## Variables
### Optional
| Variable | Default | Description |
|----------|---------|-------------|
| `grafana_http_port` | `3000` | Web interface port |
| `grafana_data_path` | `{{ app_dir }}/data` | Data storage |
| `grafana_container_version` | `latest` | Grafana Docker image tag |
## Example
```yaml
- role: patrickj.docker_apps.grafana
vars:
grafana_http_port: 3001
```
+8
View File
@@ -0,0 +1,8 @@
---
app_name: grafana
grafana_container_name: "{{ app_name | default('grafana') }}"
grafana_container_version: latest
grafana_restart_policy: "{{ app_restart_policy }}"
grafana_http_port: 3000
grafana_data_path: "{{ app_dir }}/data"
+14
View File
@@ -0,0 +1,14 @@
---
galaxy_info:
author: Patrick Jaroszewski
description: Deploy grafana with Docker Compose
license: MIT
dependencies:
- role: patrickj.docker_apps.docker_compose_app
vars:
app_role_name: grafana
app_subdirectories:
- "{{ grafana_data_path }}"
app_backup_subdirectories:
- "{{ grafana_data_path }}"
+10
View File
@@ -0,0 +1,10 @@
---
services:
grafana:
image: "grafana/grafana-oss:{{ grafana_container_version }}"
container_name: "{{ grafana_container_name }}"
restart: "{{ grafana_restart_policy }}"
ports:
- "{{ grafana_http_port }}:3000"
volumes:
- "{{ grafana_data_path }}:/var/lib/grafana"
+37
View File
@@ -0,0 +1,37 @@
# Immich
Deploy Immich photo management platform using Docker Compose.
## Description
Immich is a self-hosted photo and video backup solution with mobile apps, AI features, and automatic organization. Includes web server, machine learning, PostgreSQL database, and Redis.
## Variables
### Required (Set in Vault)
| Variable | Description |
|----------|-------------|
| `immich_db_password` | PostgreSQL database password (use only A-Za-z0-9 characters) |
### Optional
| Variable | Default | Description |
|----------|---------|-------------|
| `immich_http_port` | `2283` | Web interface port |
| `immich_library_path` | `{{ app_dir }}/library` | Photo and video upload storage location |
| `immich_pgdata_path` | `{{ app_dir }}/pgdata` | PostgreSQL database storage location |
| `immich_container_version` | `v2` | Immich version tag (can pin to specific version like "v2.1.0") |
| `immich_container_name` | `{{ app_name }}` | Container name |
| `immich_restart_policy` | `{{ app_restart_policy }}` | Container restart policy |
| `immich_timezone` | `{{ app_timezone }}` | Container timezone |
## Example
```yaml
- role: patrickj.docker_apps.immich
vars:
immich_db_password: "{{ vault_immich_db_password }}"
immich_library_path: /storage/photos
immich_container_version: "v2.1.0"
```
+18
View File
@@ -0,0 +1,18 @@
---
app_name: immich
# Container configuration
immich_container_name: "{{ app_name | default('immich') }}"
immich_container_version: v2
immich_restart_policy: "{{ app_restart_policy | default('unless-stopped') }}"
# Network configuration
immich_http_port: 2283
# Volume paths
immich_library_path: "{{ app_dir }}/library"
immich_pgdata_path: "{{ app_dir }}/pgdata"
# App-specific configuration
immich_db_password: postgres
immich_timezone: "{{ app_timezone }}"
+20
View File
@@ -0,0 +1,20 @@
---
galaxy_info:
author: Patrick Jaroszewski
description:: Deploy Immich with Docker Compose
license: MIT
dependencies:
- role: patrickj.docker_apps.docker_compose_app
vars:
app_role_name: immich
app_subdirectories:
- "{{ immich_library_path }}"
- "{{ immich_pgdata_path }}"
app_backup_subdirectories:
- "{{ immich_library_path }}"
- "{{ immich_pgdata_path }}"
app_extra_templates:
- src: "{{ app_templates_path }}/.env.j2"
dest: "{{ app_dir }}/.env"
app_compose_validate: false
+22
View File
@@ -0,0 +1,22 @@
# You can find documentation for all the supported env variables at https://docs.immich.app/install/environment-variables
# The location where your uploaded files are stored
UPLOAD_LOCATION={{ immich_library_path }}
# The location where your database files are stored. Network shares are not supported for the database
DB_DATA_LOCATION={{ immich_pgdata_path }}
# To set a timezone, uncomment the next line and change Etc/UTC to a TZ identifier from this list: https://en.wikipedia.org/wiki/List_of_tz_database_time_zones#List
TZ={{ immich_timezone }}
# The Immich version to use. You can pin this to a specific version like "v2.1.0"
IMMICH_VERSION={{ immich_container_version }}
# Connection secret for postgres. You should change it to a random password
# Please use only the characters `A-Za-z0-9`, without special characters or spaces
DB_PASSWORD={{ immich_db_password }}
# The values below this line do not need to be changed
###################################################################################
DB_USERNAME=postgres
DB_DATABASE_NAME=immich
+66
View File
@@ -0,0 +1,66 @@
name: immich
services:
immich-server:
container_name: "{{ immich_container_name }}"
image: ghcr.io/immich-app/immich-server:${IMMICH_VERSION:-release}
# extends:
# file: hwaccel.transcoding.yml
# service: cpu # set to one of [nvenc, quicksync, rkmpp, vaapi, vaapi-wsl] for accelerated transcoding
volumes:
# Do not edit the next line. If you want to change the media storage location on your system, edit the value of UPLOAD_LOCATION in the .env file
- ${UPLOAD_LOCATION}:/data
- /etc/localtime:/etc/localtime:ro
env_file:
- .env
ports:
- "{{ immich_http_port }}:2283"
depends_on:
- redis
- database
restart: {{ immich_restart_policy }}
healthcheck:
disable: false
immich-machine-learning:
container_name: immich_machine_learning
# For hardware acceleration, add one of -[armnn, cuda, rocm, openvino, rknn] to the image tag.
# Example tag: ${IMMICH_VERSION:-release}-cuda
image: ghcr.io/immich-app/immich-machine-learning:${IMMICH_VERSION:-release}
# extends: # uncomment this section for hardware acceleration - see https://docs.immich.app/features/ml-hardware-acceleration
# file: hwaccel.ml.yml
# service: cpu # set to one of [armnn, cuda, rocm, openvino, openvino-wsl, rknn] for accelerated inference - use the `-wsl` version for WSL2 where applicable
volumes:
- model-cache:/cache
env_file:
- .env
restart: {{ immich_restart_policy }}
healthcheck:
disable: false
redis:
container_name: immich_redis
image: docker.io/valkey/valkey:9@sha256:fb8d272e529ea567b9bf1302245796f21a2672b8368ca3fcb938ac334e613c8f
healthcheck:
test: redis-cli ping || exit 1
restart: {{ immich_restart_policy }}
database:
container_name: immich_postgres
image: ghcr.io/immich-app/postgres:14-vectorchord0.4.3-pgvectors0.2.0@sha256:bcf63357191b76a916ae5eb93464d65c07511da41e3bf7a8416db519b40b1c23
environment:
POSTGRES_PASSWORD: ${DB_PASSWORD}
POSTGRES_USER: ${DB_USERNAME}
POSTGRES_DB: ${DB_DATABASE_NAME}
POSTGRES_INITDB_ARGS: '--data-checksums'
# Uncomment the DB_STORAGE_TYPE: 'HDD' var if your database isn't stored on SSDs
# DB_STORAGE_TYPE: 'HDD'
volumes:
# Do not edit the next line. If you want to change the database storage location on your system, edit the value of DB_DATA_LOCATION in the .env file
- ${DB_DATA_LOCATION}:/var/lib/postgresql/data
shm_size: 128mb
restart: {{ immich_restart_policy }}
volumes:
model-cache:
+30
View File
@@ -0,0 +1,30 @@
# InfluxDB
Deploy InfluxDB time series database using Docker Compose.
## Description
InfluxDB is a high-performance time series database designed for handling large amounts of timestamped data. This deploys InfluxDB v2 with web UI and API.
## Variables
### Optional
| Variable | Default | Description |
|----------|---------|-------------|
| `influxdb_http_port` | `8086` | HTTP API and web UI port |
| `influxdb_udp_port` | `8089` | UDP port for data ingestion |
| `influxdb_data_path` | `{{ app_dir }}/data` | Database storage location |
| `influxdb_config_path` | `{{ app_dir }}/config` | Configuration files location |
| `influxdb_container_version` | `latest` | InfluxDB Docker image tag |
| `influxdb_container_name` | `{{ app_name }}` | Container name |
| `influxdb_restart_policy` | `{{ app_restart_policy }}` | Container restart policy |
## Example
```yaml
- role: patrickj.docker_apps.influxdb
vars:
influxdb_http_port: 8087
influxdb_container_version: "2.7"
```
+15
View File
@@ -0,0 +1,15 @@
---
app_name: influxdb
# Container configuration
influxdb_container_name: "{{ app_name | default('influxdb') }}"
influxdb_container_version: latest
influxdb_restart_policy: "{{ app_restart_policy }}"
# Network configuration
influxdb_http_port: 8086
influxdb_udp_port: 8089
# Volume paths
influxdb_data_path: "{{ app_dir }}/data"
influxdb_config_path: "{{ app_dir }}/config"
+16
View File
@@ -0,0 +1,16 @@
---
galaxy_info:
author: <your_name>
description: Deploy influxdb with Docker Compose
license: MIT
dependencies:
- role: patrickj.docker_apps.docker_compose_app
vars:
app_role_name: influxdb
app_subdirectories:
- "{{ influxdb_data_path }}"
- "{{ influxdb_config_path }}"
app_backup_subdirectories:
- "{{ influxdb_data_path }}"
- "{{ influxdb_config_path }}"
+12
View File
@@ -0,0 +1,12 @@
---
services:
influxdb:
image: "influxdb:{{ influxdb_container_version }}"
container_name: "{{ influxdb_container_name }}"
restart: "{{ influxdb_restart_policy }}"
ports:
- "{{ influxdb_http_port }}:8086"
- "{{ influxdb_udp_port }}:8089/udp"
volumes:
- "{{ influxdb_data_path }}:/var/lib/influxdb2"
- "{{ influxdb_config_path }}:/etc/influxdb2"
+50
View File
@@ -0,0 +1,50 @@
# Jellyfin
Deploy Jellyfin media server using Docker Compose.
## Description
Jellyfin is a free and open-source media server for organizing, managing, and streaming media files with optional GPU hardware acceleration.
## Variables
### Optional
| Variable | Default | Description |
|----------|---------|-------------|
| `jellyfin_http_port` | `8096` | Web interface port |
| `jellyfin_discovery_port` | `7359` | Auto-discovery port |
| `jellyfin_config_path` | `{{ app_dir }}/config` | Configuration storage |
| `jellyfin_cache_path` | `{{ app_dir }}/cache` | Cache storage |
| `jellyfin_container_version` | `latest` | Jellyfin Docker image tag |
| `jellyfin_container_name` | `{{ app_name }}` | Container name |
| `jellyfin_restart_policy` | `{{ app_restart_policy }}` | Container restart policy |
| `jellyfin_uid` | `{{ app_uid }}` | User ID for file permissions |
| `jellyfin_gid` | `{{ app_gid }}` | Group ID for file permissions |
| `jellyfin_gpu_passthrough` | `false` | Enable NVIDIA GPU support |
| `jellyfin_server_url` | See defaults | Custom domain for server |
| `jellyfin_libraries` | `[]` | List of media library mappings with `host_path` and `container_path` |
#### Example Media Libraries Configuration
```yaml
jellyfin_libraries:
- host_path: "/storage/movies"
container_path: /movies
- host_path: "/storage/tv_shows"
container_path: /tv_shows
- host_path: "/storage/anime"
container_path: /anime
```
## Example
```yaml
- role: patrickj.docker_apps.jellyfin
vars:
shared_media_path: /storage/media
jellyfin_gpu_passthrough: true
jellyfin_libraries:
- host_path: /storage/media/movies
container_path: /movies
```
+22
View File
@@ -0,0 +1,22 @@
---
app_name: jellyfin
# Container configuration
jellyfin_container_name: "{{ app_name | default('jellyfin') }}"
jellyfin_container_version: latest
jellyfin_restart_policy: "{{ app_restart_policy }}"
jellyfin_uid: "{{ app_uid }}"
jellyfin_gid: "{{ app_gid }}"
# Network configuration
jellyfin_http_port: 8096
jellyfin_discovery_port: 7359
# Volume paths
jellyfin_config_path: "{{ app_dir }}/config"
jellyfin_cache_path: "{{ app_dir }}/cache"
# App-specific configuration
jellyfin_gpu_passthrough: false
jellyfin_libraries: []
+16
View File
@@ -0,0 +1,16 @@
---
galaxy_info:
author: Patrick Jaroszewski
description: Deploy Jellyfin with Docker Compose
license: MIT
dependencies:
- role: patrickj.docker_apps.docker_compose_app
vars:
app_role_name: jellyfin
app_subdirectories:
- "{{ jellyfin_config_path }}"
- "{{ jellyfin_cache_path }}"
app_backup_subdirectories:
- "{{ jellyfin_config_path }}"
- "{{ jellyfin_cache_path }}"
+33
View File
@@ -0,0 +1,33 @@
---
services:
jellyfin:
image: "jellyfin/jellyfin:{{ jellyfin_container_version }}"
container_name: "{{ jellyfin_container_name }}"
user: {{ jellyfin_uid }}:{{ jellyfin_gid }}
restart: {{ jellyfin_restart_policy }}
ports:
- {{ jellyfin_http_port }}:8096/tcp
- {{ jellyfin_discovery_port }}:7359/udp
volumes:
- "{{ jellyfin_config_path }}:/config"
- "{{ jellyfin_cache_path }}:/cache"
{% for item in jellyfin_libraries %}
- "{{ item.host_path }}:{{ item.container_path }}:ro"
{% endfor %}
{% if jellyfin_server_url %}
# Optional - alternative address used for autodiscovery
environment:
- JELLYFIN_PublishedServerUrl={{ jellyfin_server_url }}
{% endif %}
{% if jellyfin_gpu_passthrough %}
deploy:
resources:
reservations:
devices:
- driver: nvidia
count: 1
capabilities: [gpu]
{% endif %}
+35
View File
@@ -0,0 +1,35 @@
# Linkwarden
Deploy Linkwarden bookmark manager using Docker Compose.
## Description
Linkwarden is a self-hosted bookmark manager with tagging, collections, and full-text search capabilities.
## Variables
### Required (Set in Vault)
| Variable | Description |
|----------|-------------|
| `linkwarden_nextauth_secret` | NextAuth authentication secret |
| `linkwarden_postgres_password` | PostgreSQL database password |
| `linkwarden_meili_master_key` | Meilisearch master key for search functionality |
### Optional
| Variable | Default | Description |
|----------|---------|-------------|
| `linkwarden_http_port` | `3000` | Web interface port |
| `linkwarden_data_path` | `{{ app_dir }}/data` | Application data storage path |
| `linkwarden_pgdata_path` | `{{ app_dir }}/pgdata` | PostgreSQL data storage path |
| `linkwarden_meili_data_path` | `{{ app_dir }}/meili_data` | Meilisearch data storage path |
| `linkwarden_container_version` | `latest` | Linkwarden Docker image tag |
## Example
```yaml
- role: patrickj.docker_apps.linkwarden
vars:
linkwarden_http_port: 3001
```
+20
View File
@@ -0,0 +1,20 @@
---
app_name: linkwarden
# Container configuration
linkwarden_container_name: "{{ app_name | default('linkwarden') }}"
linkwarden_container_version: latest
linkwarden_restart_policy: "{{ app_restart_policy }}"
# Network configuration
linkwarden_http_port: 3000
# Volume paths
linkwarden_data_path: "{{ app_dir }}/data"
linkwarden_pgdata_path: "{{ app_dir }}/pgdata"
linkwarden_meili_data_path: "{{ app_dir }}/meili_data"
# App-specific configuration
linkwarden_nextauth_secret: change-me!
linkwarden_postgres_password: change-me!
linkwarden_meili_master_key: change-me!
+22
View File
@@ -0,0 +1,22 @@
---
galaxy_info:
author: Patrick Jaroszewski
description: Deploy Linkwarden with Docker Compose
license: MIT
dependencies:
- role: patrickj.docker_apps.docker_compose_app
vars:
app_role_name: linkwarden
app_subdirectories:
- "{{ linkwarden_data_path }}"
- "{{ linkwarden_pgdata_path }}"
- "{{ linkwarden_meili_data_path }}"
app_backup_subdirectories:
- "{{ linkwarden_data_path }}"
- "{{ linkwarden_pgdata_path }}"
- "{{ linkwarden_meili_data_path }}"
app_extra_templates:
- src: "{{ app_templates_path }}/.env.j2"
dest: "{{ app_dir }}/.env"
app_compose_validate: false # Issues validating when needing a .env
+473
View File
@@ -0,0 +1,473 @@
NEXTAUTH_URL=http://localhost:3000/api/v1/auth
NEXTAUTH_SECRET={{ linkwarden_nextauth_secret }}
# Manual installation database settings
# Example: DATABASE_URL=postgresql://user:password@localhost:5432/linkwarden
DATABASE_URL=
# Docker installation database settings
POSTGRES_PASSWORD={{ linkwarden_postgres_password }}
# Additional Optional Settings
PAGINATION_TAKE_COUNT=
STORAGE_FOLDER=
AUTOSCROLL_TIMEOUT=
NEXT_PUBLIC_DISABLE_REGISTRATION=
NEXT_PUBLIC_CREDENTIALS_ENABLED=
DISABLE_NEW_SSO_USERS=
MAX_LINKS_PER_USER=
ARCHIVE_TAKE_COUNT=
BROWSER_TIMEOUT=
IGNORE_UNAUTHORIZED_CA=
IGNORE_HTTPS_ERRORS=
IGNORE_URL_SIZE_LIMIT=
NEXT_PUBLIC_DEMO=
NEXT_PUBLIC_DEMO_USERNAME=
NEXT_PUBLIC_DEMO_PASSWORD=
NEXT_PUBLIC_ADMIN=
NEXT_PUBLIC_MAX_FILE_BUFFER=
PDF_MAX_BUFFER=
SCREENSHOT_MAX_BUFFER=
READABILITY_MAX_BUFFER=
PREVIEW_MAX_BUFFER=
MONOLITH_MAX_BUFFER=
MONOLITH_CUSTOM_OPTIONS=
IMPORT_LIMIT=
PLAYWRIGHT_LAUNCH_OPTIONS_EXECUTABLE_PATH=
PLAYWRIGHT_WS_URL=
MAX_WORKERS=
DISABLE_PRESERVATION=
NEXT_PUBLIC_RSS_POLLING_INTERVAL_MINUTES=
RSS_SUBSCRIPTION_LIMIT_PER_USER=
TEXT_CONTENT_LIMIT=
SEARCH_FILTER_LIMIT=
INDEX_TAKE_COUNT=
MEILI_TIMEOUT=
# AI Settings
NEXT_PUBLIC_OLLAMA_ENDPOINT_URL=
OLLAMA_MODEL=
# https://ai-sdk.dev/providers/openai-compatible-providers
OPENAI_API_KEY=
OPENAI_MODEL=
# Optional: Set a custom OpenAI base URL and name (for third-party providers)
CUSTOM_OPENAI_BASE_URL=
CUSTOM_OPENAI_NAME=
# https://sdk.vercel.ai/providers/ai-sdk-providers/azure
AZURE_API_KEY=
AZURE_RESOURCE_NAME=
AZURE_MODEL=
# https://sdk.vercel.ai/providers/ai-sdk-providers/anthropic
ANTHROPIC_API_KEY=
ANTHROPIC_MODEL=
# https://github.com/OpenRouterTeam/ai-sdk-provider
OPENROUTER_API_KEY=
OPENROUTER_MODEL=
# https://ai-sdk.dev/providers/ai-sdk-providers/perplexity
PERPLEXITY_API_KEY=
PERPLEXITY_MODEL=
# MeiliSearch Settings
MEILI_HOST=
MEILI_MASTER_KEY={{ linkwarden_meili_master_key }}
# AWS S3 Settings
SPACES_KEY=
SPACES_SECRET=
SPACES_ENDPOINT=
SPACES_BUCKET_NAME=
SPACES_REGION=
SPACES_FORCE_PATH_STYLE=
# SMTP Settings
NEXT_PUBLIC_EMAIL_PROVIDER=
EMAIL_FROM=
EMAIL_SERVER=
BASE_URL=
# Proxy settings
PROXY=
PROXY_USERNAME=
PROXY_PASSWORD=
PROXY_BYPASS=
# PDF archive settings
PDF_MARGIN_TOP=
PDF_MARGIN_BOTTOM=
#################
# SSO Providers #
#################
# 42 School
NEXT_PUBLIC_FORTYTWO_ENABLED=
FORTYTWO_CUSTOM_NAME=
FORTYTWO_CLIENT_ID=
FORTYTWO_CLIENT_SECRET=
# Apple
NEXT_PUBLIC_APPLE_ENABLED=
APPLE_CUSTOM_NAME=
APPLE_ID=
APPLE_SECRET=
# Atlassian
NEXT_PUBLIC_ATLASSIAN_ENABLED=
ATLASSIAN_CUSTOM_NAME=
ATLASSIAN_CLIENT_ID=
ATLASSIAN_CLIENT_SECRET=
ATLASSIAN_SCOPE=
# Auth0
NEXT_PUBLIC_AUTH0_ENABLED=
AUTH0_CUSTOM_NAME=
AUTH0_ISSUER=
AUTH0_CLIENT_SECRET=
AUTH0_CLIENT_ID=
# Authelia
NEXT_PUBLIC_AUTHELIA_ENABLED=
AUTHELIA_CLIENT_ID=
AUTHELIA_CLIENT_SECRET=
AUTHELIA_WELLKNOWN_URL=
# Authentik
NEXT_PUBLIC_AUTHENTIK_ENABLED=
AUTHENTIK_CUSTOM_NAME=
AUTHENTIK_ISSUER=
AUTHENTIK_CLIENT_ID=
AUTHENTIK_CLIENT_SECRET=
# Azure AD B2C
NEXT_PUBLIC_AZURE_AD_B2C_ENABLED=
AZURE_AD_B2C_TENANT_NAME=
AZURE_AD_B2C_CLIENT_ID=
AZURE_AD_B2C_CLIENT_SECRET=
AZURE_AD_B2C_PRIMARY_USER_FLOW=
# Azure AD
NEXT_PUBLIC_AZURE_AD_ENABLED=
AZURE_AD_CLIENT_ID=
AZURE_AD_CLIENT_SECRET=
AZURE_AD_TENANT_ID=
# Battle.net
NEXT_PUBLIC_BATTLENET_ENABLED=
BATTLENET_CUSTOM_NAME=
BATTLENET_CLIENT_ID=
BATTLENET_CLIENT_SECRET=
BATTLENET_ISSUER=
# Box
NEXT_PUBLIC_BOX_ENABLED=
BOX_CUSTOM_NAME=
BOX_CLIENT_ID=
BOX_CLIENT_SECRET=
# Bungie
NEXT_PUBLIC_BUNGIE_ENABLED=
BUNGIE_CUSTOM_NAME=
BUNGIE_CLIENT_ID=
BUNGIE_CLIENT_SECRET=
BUNGIE_API_KEY=
# Cognito
NEXT_PUBLIC_COGNITO_ENABLED=
COGNITO_CUSTOM_NAME=
COGNITO_CLIENT_ID=
COGNITO_CLIENT_SECRET=
COGNITO_ISSUER=
# Coinbase
NEXT_PUBLIC_COINBASE_ENABLED=
COINBASE_CUSTOM_NAME=
COINBASE_CLIENT_ID=
COINBASE_CLIENT_SECRET=
# Discord
NEXT_PUBLIC_DISCORD_ENABLED=
DISCORD_CUSTOM_NAME=
DISCORD_CLIENT_ID=
DISCORD_CLIENT_SECRET=
# Dropbox
NEXT_PUBLIC_DROPBOX_ENABLED=
DROPBOX_CUSTOM_NAME=
DROPBOX_CLIENT_ID=
DROPBOX_CLIENT_SECRET=
# DuendeIndentityServer6
NEXT_PUBLIC_DUENDE_IDS6_ENABLED=
DUENDE_IDS6_CUSTOM_NAME=
DUENDE_IDS6_CLIENT_ID=
DUENDE_IDS6_CLIENT_SECRET=
DUENDE_IDS6_ISSUER=
# EVE Online
NEXT_PUBLIC_EVEONLINE_ENABLED=
EVEONLINE_CUSTOM_NAME=
EVEONLINE_CLIENT_ID=
EVEONLINE_CLIENT_SECRET=
# Facebook
NEXT_PUBLIC_FACEBOOK_ENABLED=
FACEBOOK_CUSTOM_NAME=
FACEBOOK_CLIENT_ID=
FACEBOOK_CLIENT_SECRET=
# FACEIT
NEXT_PUBLIC_FACEIT_ENABLED=
FACEIT_CUSTOM_NAME=
FACEIT_CLIENT_ID=
FACEIT_CLIENT_SECRET=
# Foursquare
NEXT_PUBLIC_FOURSQUARE_ENABLED=
FOURSQUARE_CUSTOM_NAME=
FOURSQUARE_CLIENT_ID=
FOURSQUARE_CLIENT_SECRET=
FOURSQUARE_APIVERSION=
# Freshbooks
NEXT_PUBLIC_FRESHBOOKS_ENABLED=
FRESHBOOKS_CUSTOM_NAME=
FRESHBOOKS_CLIENT_ID=
FRESHBOOKS_CLIENT_SECRET=
# FusionAuth
NEXT_PUBLIC_FUSIONAUTH_ENABLED=
FUSIONAUTH_CUSTOM_NAME=
FUSIONAUTH_CLIENT_ID=
FUSIONAUTH_CLIENT_SECRET=
FUSIONAUTH_ISSUER=
FUSIONAUTH_TENANT_ID=
# GitHub
NEXT_PUBLIC_GITHUB_ENABLED=
GITHUB_CUSTOM_NAME=
GITHUB_ID=
GITHUB_SECRET=
# GitLab
NEXT_PUBLIC_GITLAB_ENABLED=
GITLAB_CUSTOM_NAME=
GITLAB_CLIENT_ID=
GITLAB_CLIENT_SECRET=
GITLAB_AUTH_URL=
# Google
NEXT_PUBLIC_GOOGLE_ENABLED=
GOOGLE_CUSTOM_NAME=
GOOGLE_CLIENT_ID=
GOOGLE_CLIENT_SECRET=
# HubSpot
NEXT_PUBLIC_HUBSPOT_ENABLED=
HUBSPOT_CUSTOM_NAME=
HUBSPOT_CLIENT_ID=
HUBSPOT_CLIENT_SECRET=
# IdentityServer4
NEXT_PUBLIC_IDS4_ENABLED=
IDS4_CUSTOM_NAME=
IDS4_CLIENT_ID=
IDS4_CLIENT_SECRET=
IDS4_ISSUER=
# Kakao
NEXT_PUBLIC_KAKAO_ENABLED=
KAKAO_CUSTOM_NAME=
KAKAO_CLIENT_ID=
KAKAO_CLIENT_SECRET=
# Keycloak
NEXT_PUBLIC_KEYCLOAK_ENABLED=
KEYCLOAK_CUSTOM_NAME=
KEYCLOAK_ISSUER=
KEYCLOAK_CLIENT_ID=
KEYCLOAK_CLIENT_SECRET=
# LINE
NEXT_PUBLIC_LINE_ENABLED=
LINE_CUSTOM_NAME=
LINE_CLIENT_ID=
LINE_CLIENT_SECRET=
# LinkedIn
NEXT_PUBLIC_LINKEDIN_ENABLED=
LINKEDIN_CUSTOM_NAME=
LINKEDIN_CLIENT_ID=
LINKEDIN_CLIENT_SECRET=
# Mailchimp
NEXT_PUBLIC_MAILCHIMP_ENABLED=
MAILCHIMP_CUSTOM_NAME=
MAILCHIMP_CLIENT_ID=
MAILCHIMP_CLIENT_SECRET=
# Mail.ru
NEXT_PUBLIC_MAILRU_ENABLED=
MAILRU_CUSTOM_NAME=
MAILRU_CLIENT_ID=
MAILRU_CLIENT_SECRET=
# Naver
NEXT_PUBLIC_NAVER_ENABLED=
NAVER_CUSTOM_NAME=
NAVER_CLIENT_ID=
NAVER_CLIENT_SECRET=
# Netlify
NEXT_PUBLIC_NETLIFY_ENABLED=
NETLIFY_CUSTOM_NAME=
NETLIFY_CLIENT_ID=
NETLIFY_CLIENT_SECRET=
# Okta
NEXT_PUBLIC_OKTA_ENABLED=
OKTA_CUSTOM_NAME=
OKTA_CLIENT_ID=
OKTA_CLIENT_SECRET=
OKTA_ISSUER=
# OneLogin
NEXT_PUBLIC_ONELOGIN_ENABLED=
ONELOGIN_CUSTOM_NAME=
ONELOGIN_CLIENT_ID=
ONELOGIN_CLIENT_SECRET=
ONELOGIN_ISSUER=
# Osso
NEXT_PUBLIC_OSSO_ENABLED=
OSSO_CUSTOM_NAME=
OSSO_CLIENT_ID=
OSSO_CLIENT_SECRET=
OSSO_ISSUER=
# osu!
NEXT_PUBLIC_OSU_ENABLED=
OSU_CUSTOM_NAME=
OSU_CLIENT_ID=
OSU_CLIENT_SECRET=
# Patreon
NEXT_PUBLIC_PATREON_ENABLED=
PATREON_CUSTOM_NAME=
PATREON_CLIENT_ID=
PATREON_CLIENT_SECRET=
# Pinterest
NEXT_PUBLIC_PINTEREST_ENABLED=
PINTEREST_CUSTOM_NAME=
PINTEREST_CLIENT_ID=
PINTEREST_CLIENT_SECRET=
# Pipedrive
NEXT_PUBLIC_PIPEDRIVE_ENABLED=
PIPEDRIVE_CUSTOM_NAME=
PIPEDRIVE_CLIENT_ID=
PIPEDRIVE_CLIENT_SECRET=
# Reddit
NEXT_PUBLIC_REDDIT_ENABLED=
REDDIT_CUSTOM_NAME=
REDDIT_CLIENT_ID=
REDDIT_CLIENT_SECRET=
# Salesforce
NEXT_PUBLIC_SALESFORCE_ENABLED=
SALESFORCE_CUSTOM_NAME=
SALESFORCE_CLIENT_ID=
SALESFORCE_CLIENT_SECRET=
# Slack
NEXT_PUBLIC_SLACK_ENABLED=
SLACK_CUSTOM_NAME=
SLACK_CLIENT_ID=
SLACK_CLIENT_SECRET=
# Spotify
NEXT_PUBLIC_SPOTIFY_ENABLED=
SPOTIFY_CUSTOM_NAME=
SPOTIFY_CLIENT_ID=
SPOTIFY_CLIENT_SECRET=
# Strava
NEXT_PUBLIC_STRAVA_ENABLED=
STRAVA_CUSTOM_NAME=
STRAVA_CLIENT_ID=
STRAVA_CLIENT_SECRET=
# Synology
NEXT_PUBLIC_SYNOLOGY_ENABLED=
SYNOLOGY_CUSTOM_NAME=
SYNOLOGY_CLIENT_ID=
SYNOLOGY_CLIENT_SECRET=
SYNOLOGY_WELLKNOWN_URL=
# Todoist
NEXT_PUBLIC_TODOIST_ENABLED=
TODOIST_CUSTOM_NAME=
TODOIST_CLIENT_ID=
TODOIST_CLIENT_SECRET=
# Twitch
NEXT_PUBLIC_TWITCH_ENABLED=
TWITCH_CUSTOM_NAME=
TWITCH_CLIENT_ID=
TWITCH_CLIENT_SECRET=
# United Effects
NEXT_PUBLIC_UNITED_EFFECTS_ENABLED=
UNITED_EFFECTS_CUSTOM_NAME=
UNITED_EFFECTS_CLIENT_ID=
UNITED_EFFECTS_CLIENT_SECRET=
UNITED_EFFECTS_ISSUER=
# VK
NEXT_PUBLIC_VK_ENABLED=
VK_CUSTOM_NAME=
VK_CLIENT_ID=
VK_CLIENT_SECRET=
# Wikimedia
NEXT_PUBLIC_WIKIMEDIA_ENABLED=
WIKIMEDIA_CUSTOM_NAME=
WIKIMEDIA_CLIENT_ID=
WIKIMEDIA_CLIENT_SECRET=
# Wordpress.com
NEXT_PUBLIC_WORDPRESS_ENABLED=
WORDPRESS_CUSTOM_NAME=
WORDPRESS_CLIENT_ID=
WORDPRESS_CLIENT_SECRET=
# Yandex
NEXT_PUBLIC_YANDEX_ENABLED=
YANDEX_CUSTOM_NAME=
YANDEX_CLIENT_ID=
YANDEX_CLIENT_SECRET=
# Zitadel
NEXT_PUBLIC_ZITADEL_ENABLED=
ZITADEL_CUSTOM_NAME=
ZITADEL_CLIENT_ID=
ZITADEL_CLIENT_SECRET=
ZITADEL_ISSUER=
# Zoho
NEXT_PUBLIC_ZOHO_ENABLED=
ZOHO_CUSTOM_NAME=
ZOHO_CLIENT_ID=
ZOHO_CLIENT_SECRET=
# Zoom
NEXT_PUBLIC_ZOOM_ENABLED=
ZOOM_CUSTOM_NAME=
ZOOM_CLIENT_ID=
ZOOM_CLIENT_SECRET=
+27
View File
@@ -0,0 +1,27 @@
services:
postgres:
image: postgres:16-alpine
env_file: .env
restart: {{ linkwarden_restart_policy }}
volumes:
- {{ linkwarden_pgdata_path }}:/var/lib/postgresql/data
linkwarden:
env_file: .env
environment:
- DATABASE_URL=postgresql://postgres:${POSTGRES_PASSWORD}@postgres:5432/postgres
restart: {{ linkwarden_restart_policy }}
image: ghcr.io/linkwarden/linkwarden:{{ linkwarden_container_version }}
ports:
- {{ linkwarden_http_port }}:3000
volumes:
- {{ linkwarden_data_path }}:/data/data
depends_on:
- postgres
- meilisearch
meilisearch:
image: getmeili/meilisearch:v1.12.8
restart: {{ linkwarden_restart_policy }}
env_file:
- .env
volumes:
- {{ linkwarden_meili_data_path }}:/meili_data
+27
View File
@@ -0,0 +1,27 @@
# Mealie
Deploy Mealie recipe manager using Docker Compose.
## Description
Mealie is a self-hosted recipe manager with meal planning, shopping lists, and nutrition tracking.
## Variables
### Optional
| Variable | Default | Description |
|----------|---------|-------------|
| `mealie_http_port` | `9925` | Web interface port |
| `mealie_base_url` | `http://localhost:8080` | Base URL for application links and redirects |
| `mealie_data_path` | `{{ app_dir }}/data` | Application data storage path |
| `mealie_container_version` | `latest` | Mealie Docker image tag |
| `mealie_extra_env_vars` | `{}` | Additional environment variables as key-value pairs |
## Example
```yaml
- role: patrickj.docker_apps.mealie
vars:
mealie_base_url: "https://recipes.example.com"
```
+21
View File
@@ -0,0 +1,21 @@
---
app_name: mealie
# Container configuration
mealie_container_name: "{{ app_name | default('mealie') }}"
mealie_container_version: latest
mealie_restart_policy: "{{ app_restart_policy }}"
mealie_user: "{{ app_uid }}"
mealie_group: "{{ app_gid }}"
# Network configuration
mealie_http_port: 9925
# Volume paths
mealie_data_path: "{{ app_dir }}/data"
# App-specific configuration
mealie_timezone: "{{ app_timezone_cc }}"
mealie_base_url: http://localhost:8080
mealie_extra_env_vars: {}
# ALLOW_SIGNUP: "false"
+14
View File
@@ -0,0 +1,14 @@
---
galaxy_info:
author: Patrick Jaroszewski
description: Deploy Mealie with Docker Compose
license: MIT
dependencies:
- role: patrickj.docker_apps.docker_compose_app
vars:
app_role_name: mealie
app_subdirectories:
- "{{ mealie_data_path }}"
app_backup_subdirectories:
- "{{ mealie_data_path }}"
+25
View File
@@ -0,0 +1,25 @@
---
services:
mealie:
image: ghcr.io/mealie-recipes/mealie:{{ mealie_container_version }}
container_name: {{ mealie_container_name }}
restart: {{ mealie_restart_policy }}
ports:
- "{{ mealie_http_port }}:9000"
deploy:
resources:
limits:
memory: 1000M
volumes:
- "{{ mealie_data_path }}:/app/data/"
environment:
# Set Backend ENV Variables Here
PUID: {{ mealie_user }}
PGID: {{ mealie_group }}
TZ: {{ mealie_timezone }}
BASE_URL: {{ mealie_base_url }}
{% for item in mealie_extra_env_vars %}
{{ item.key }}: {{ item.value }}
{% endfor %}
+34
View File
@@ -0,0 +1,34 @@
# Navidrome
Deploy Navidrome music streaming server using Docker Compose.
## Description
Navidrome is a modern music server compatible with Subsonic/Airsonic clients, with web interface and mobile app support.
## Variables
### Required
| Variable | Default | Description |
|----------|---------|-------------|
| `navidrome_libraries` | `[]` | List of music library mappings with `host_path` and `container_path` |
### Optional
| Variable | Default | Description |
|----------|---------|-------------|
| `navidrome_http_port` | `4533` | Web interface port |
| `navidrome_data_path` | `{{ app_dir }}/data` | Database and application data storage |
| `navidrome_base_url` | `""` | Base URL if accessing through reverse proxy |
| `navidrome_container_version` | `latest` | Navidrome Docker image tag |
## Example
```yaml
- role: patrickj.docker_apps.navidrome
vars:
navidrome_libraries:
- host_path: /storage/music
container_path: /music
```
+21
View File
@@ -0,0 +1,21 @@
---
app_name: navidrome
# Container configuration
navidrome_container_name: "{{ app_name | default('navidrome') }}"
navidrome_container_version: latest
navidrome_restart_policy: "{{ app_restart_policy }}"
navidrome_uid: "{{ app_uid }}"
navidrome_gid: "{{ app_gid }}"
# Network configuration
navidrome_http_port: 4533
# Volume paths
navidrome_data_path: "{{ app_dir }}/data"
# App-specific configuration
navidrome_base_url: ""
navidrome_libraries: []
# - host_path: /path/to/music
# container_path: /music
+14
View File
@@ -0,0 +1,14 @@
---
galaxy_info:
author: Patrick Jaroszewski
description: Deploy Navidrome with Docker Compose
license: MIT
dependencies:
- role: patrickj.docker_apps.docker_compose_app
vars:
app_role_name: navidrome
app_subdirectories:
- "{{ navidrome_data_path }}"
app_backup_subdirectories:
- "{{ navidrome_data_path }}"
+22
View File
@@ -0,0 +1,22 @@
---
services:
navidrome:
image: deluan/navidrome:{{ navidrome_container_version }}
container_name: "{{ navidrome_container_name }}"
user: {{ navidrome_uid }}:{{ navidrome_gid }} # should be owner of volumes
restart: "{{ navidrome_restart_policy }}"
ports:
- "{{ navidrome_http_port }}:4533"
environment:
# Optional: put your config options customization here. Examples:
ND_SCANSCHEDULE: 1h
ND_LOGLEVEL: info
ND_SESSIONTIMEOUT: 24h
{% if navidrome_base_url is defined %}
ND_BASEURL: "{{ navidrome_base_url }}"
{% endif %}
volumes:
- "{{ navidrome_data_path }}:/data"
{% for item in navidrome_libraries %}
- "{{ item.host_path }}:{{ item.container_path }}:ro"
{% endfor %}
+29
View File
@@ -0,0 +1,29 @@
# Open WebUI
Deploy Open WebUI for LLM interactions using Docker Compose.
## Description
Open WebUI is a user-friendly web interface for Large Language Models, compatible with OpenAI API.
## Variables
### Optional
| Variable | Default | Description |
|----------|---------|-------------|
| `open_webui_http_port` | `5000` | Web interface port |
| `open_webui_data_path` | `{{ app_dir }}/data` | Application data storage |
| `open_webui_container_version` | `main` | Open WebUI Docker image tag |
| `open_webui_env_vars` | See defaults | Dictionary of environment variables |
## Example
```yaml
- role: patrickj.docker_apps.open-webui
vars:
open_webui_http_port: 8080
open_webui_env_vars:
OLLAMA_BASE_URL: http://localhost:11434
BYPASS_MODEL_ACCESS_CONTROL: "true"
```
+18
View File
@@ -0,0 +1,18 @@
---
app_name: open-webui
# Container configuration
open_webui_container_name: "{{ app_name | default('open-webui') }}"
open_webui_container_version: main
open_webui_restart_policy: "{{ app_restart_policy }}"
# Network configuration
open_webui_http_port: 5000
# Volume paths
open_webui_data_path: "{{ app_dir }}/data"
# App-specific configuration
open_webui_env_vars:
OLLAMA_BASE_URL: http://localhost:11434
BYPASS_MODEL_ACCESS_CONTROL: "true"
+14
View File
@@ -0,0 +1,14 @@
---
galaxy_info:
author: Patrick Jaroszewski
description: Deploy Open-WebUI with Docker Compose
license: MIT
dependencies:
- role: patrickj.docker_apps.docker_compose_app
vars:
app_role_name: open-webui
app_subdirectories:
- "{{ open_webui_data_path }}"
app_backup_subdirectories:
- "{{ open_webui_data_path }}"
+18
View File
@@ -0,0 +1,18 @@
---
services:
openWebUI:
image: ghcr.io/open-webui/open-webui:{{ open_webui_container_version }}
container_name: {{ open_webui_container_name }}
restart: {{ open_webui_restart_policy }}
ports:
- "{{ open_webui_http_port }}:8080"
volumes:
- "{{ open_webui_data_path }}:/app/backend/data"
{% if open_webui_env_vars | length > 0 %}
environment:
{% for item in open_webui_env_vars | dict2items %}
- {{ item.key }}={{ item.value }}
{% endfor %}
{% endif %}
+40
View File
@@ -0,0 +1,40 @@
# Paperless-ngx
Deploy Paperless-ngx document management system using Docker Compose.
## Description
Paperless-ngx is a document management system that transforms your physical documents into a searchable online archive.
## Variables
## Required
| Variable | Default | Description |
|----------|---------|-------------|
| `paperless_db_password` | `paperless` | PostgreSQL password |
| `paperless_consume_path` | `{{ app_dir }}/consume` | Document intake directory |
### Optional
| Variable | Default | Description |
|----------|---------|-------------|
| `paperless_http_port` | `8000` | Web interface port |
| `paperless_data_path` | `{{ app_dir }}/data` | Application data storage |
| `paperless_media_path` | `{{ app_dir }}/media` | Processed document storage |
| `paperless_export_path` | `{{ app_dir }}/export` | Document export directory |
| `paperless_pgdata_path` | `{{ app_dir }}/pgdata` | PostgreSQL data storage |
| `paperless_redisdata_path` | `{{ app_dir }}/redisdata` | Redis data storage |
| `paperless_container_version` | `latest` | Paperless-ngx Docker image tag |
| `paperless_db_name` | `paperless` | PostgreSQL database name |
| `paperless_db_user` | `paperless` | PostgreSQL username |
## Example
```yaml
- role: patrickj.docker_apps.paperless-ngx
vars:
paperless_http_port: 8080
paperless_db_password: "{{ vault_paperless_db_password }}"
paperless_consume_path: /path/to/consume
```
+23
View File
@@ -0,0 +1,23 @@
---
app_name: paperless-ngx
# Container configuration
paperless_container_name: "{{ app_name | default('paperless-ngx') }}"
paperless_container_version: latest
paperless_restart_policy: "{{ app_restart_policy }}"
# Network configuration
paperless_http_port: 8000
# Volume paths
paperless_data_path: "{{ app_dir }}/data"
paperless_media_path: "{{ app_dir }}/media"
paperless_export_path: "{{ app_dir }}/export"
paperless_consume_path: "{{ app_dir }}/consume"
paperless_pgdata_path: "{{ app_dir }}/pgdata"
paperless_redisdata_path: "{{ app_dir }}/redisdata"
# App-specific configuration
paperless_db_name: paperless
paperless_db_user: paperless
paperless_db_password: paperless
+23
View File
@@ -0,0 +1,23 @@
---
galaxy_info:
author: Patrick Jaroszewski
description: Deploy Mealie with Docker Compose
license: MIT
dependencies:
- role: patrickj.docker_apps.docker_compose_app
vars:
app_role_name: paperless-ngx
app_subdirectories:
- "{{ paperless_data_path }}"
- "{{ paperless_media_path }}"
- "{{ paperless_export_path}}"
- "{{ paperless_consume_path}}"
- "{{ paperless_pgdata_path}}"
- "{{ paperless_redisdata_path}}"
app_backup_subdirectories:
- "{{ paperless_data_path }}"
- "{{ paperless_media_path }}"
- "{{ paperless_export_path}}"
- "{{ paperless_pgdata_path}}"
- "{{ paperless_redisdata_path}}"
@@ -0,0 +1,50 @@
---
services:
broker:
image: docker.io/library/redis:8
restart: {{ paperless_restart_policy }}
volumes:
- "{{ paperless_redisdata_path }}:/data"
db:
image: docker.io/library/postgres:18
restart: {{ paperless_restart_policy }}
volumes:
- "{{ paperless_pgdata_path }}:/var/lib/postgresql"
environment:
POSTGRES_DB: paperless
POSTGRES_USER: paperless
POSTGRES_PASSWORD: paperless
webserver:
image: ghcr.io/paperless-ngx/paperless-ngx:{{ paperless_container_version }}
restart: {{ paperless_restart_policy }}
depends_on:
- db
- broker
- gotenberg
- tika
ports:
- "{{ paperless_http_port }}:8000"
volumes:
- "{{ paperless_data_path }}:/usr/src/paperless/data"
- "{{ paperless_media_path }}:/usr/src/paperless/media"
- "{{ paperless_export_path }}:/usr/src/paperless/export"
- "{{ paperless_consume_path }}:/usr/src/paperless/consume"
environment:
COMPOSE_PROJECT_NAME: {{ app_name }}
PAPERLESS_REDIS: redis://broker:6379
PAPERLESS_DBHOST: db
PAPERLESS_TIKA_ENABLED: 1
PAPERLESS_TIKA_GOTENBERG_ENDPOINT: http://gotenberg:3000
PAPERLESS_TIKA_ENDPOINT: http://tika:9998
gotenberg:
image: docker.io/gotenberg/gotenberg:8.25
restart: {{ paperless_restart_policy }}
# The gotenberg chromium route is used to convert .eml files. We do not
# want to allow external content like tracking pixels or even javascript.
command:
- "gotenberg"
- "--chromium-disable-javascript=true"
- "--chromium-allow-list=file:///tmp/.*"
tika:
image: docker.io/apache/tika:latest
restart: {{ paperless_restart_policy }}
+23
View File
@@ -0,0 +1,23 @@
# Redlib
Deploy Redlib privacy-focused Reddit frontend using Docker Compose.
## Description
Redlib is an alternative private front-end to Reddit, providing a clean interface without tracking.
## Variables
### Optional
| Variable | Default | Description |
|----------|---------|-------------|
| `redlib_http_port` | `8080` | Web interface port |
| `redlib_container_version` | `latest` | Redlib Docker image tag |
| `redlib_extra_env_vars` | `{}` | Dictionary of environment variables |
## Example
```yaml
- role: patrickj.docker_apps.redlib
```
+13
View File
@@ -0,0 +1,13 @@
---
app_name: redlib
# Container configuration
redlib_container_name: "{{ app_name | default('redlib') }}"
redlib_container_version: latest
redlib_restart_policy: "{{ app_restart_policy }}"
# Network configuration
redlib_http_port: 8080
# App-specific configuration
redlib_extra_env_vars: {}
+11
View File
@@ -0,0 +1,11 @@
---
galaxy_info:
author: Patrick Jaroszewski
description: Deploy redlib with Docker Compose
license: MIT
dependencies:
- role: patrickj.docker_apps.docker_compose_app
vars:
app_role_name: redlib
app_health_check: false # Issues with redlib healthcheck
+30
View File
@@ -0,0 +1,30 @@
---
services:
redlib:
image: quay.io/redlib/redlib:{{ redlib_container_version }}
restart: {{ redlib_restart_policy }}
container_name: {{ redlib_container_name }}
ports:
- "{{ redlib_http_port }}:8080"
user: nobody
read_only: true
security_opt:
- no-new-privileges:true
# - seccomp=seccomp-redlib.json
cap_drop:
- ALL
networks:
- redlib
healthcheck:
test: ["CMD", "wget", "--spider", "-q", "--tries=1", "http://localhost:8080/settings"]
interval: 5m
timeout: 3s
{% if redlib_extra_env_vars %}
environment:
{% for item in redlib_extra_env_vars | dict2items %}
- {{ item.key }}="{{ item.value }}"
{% endfor %}
{% endif %}
networks:
redlib:
+39
View File
@@ -0,0 +1,39 @@
# Speedtest Tracker
Deploy Speedtest Tracker internet monitoring tool using Docker Compose.
## Description
Speedtest Tracker runs automatic internet speed tests and tracks results over time with beautiful charts.
## Variables
### Required
| Variable | Description |
|----------|-------------|
| `speedtest_tracker_app_key` | Application key |
### Optional
| Variable | Default | Description |
|----------|---------|-------------|
| `speedtest_tracker_http_port` | `8080` | HTTP web interface port |
| `speedtest_tracker_https_port` | `8443` | HTTPS web interface port |
| `speedtest_tracker_http` | `true` | Enable HTTP port mapping |
| `speedtest_tracker_https` | `false` | Enable HTTPS port mapping |
| `speedtest_tracker_config_path` | `{{ app_dir }}/config` | Configuration and database storage |
| `speedtest_tracker_container_version` | `latest` | Speedtest Tracker Docker image tag |
| `speedtest_tracker_user` | `{{ app_uid }}` | User ID for file permissions |
| `speedtest_tracker_group` | `{{ app_gid }}` | Group ID for file permissions |
| `speedtest_tracker_timezone` | `{{ app_timezone_cc }}` | Display timezone |
| `speedtest_tracker_extra_env_vars` | See defaults | Dictionary of additional environment variables |
## Example
```yaml
- role: patrickj.docker_apps.speedtest-tracker
vars:
speedtest_tracker_extra_env_vars:
SPEEDTEST_SCHEDULE: "0 * * * *" # Run every hour
```
+23
View File
@@ -0,0 +1,23 @@
---
app_name: speedtest-tracker
# Container configuration
speedtest_tracker_container_name: "{{ app_name | default('speedtest-tracker') }}"
speedtest_tracker_container_version: latest
speedtest_tracker_restart_policy: "{{ app_restart_policy }}"
speedtest_tracker_user: "{{ app_uid }}"
speedtest_tracker_group: "{{ app_gid }}"
# Network configuration
speedtest_tracker_http_port: 8080
speedtest_tracker_https_port: 8443
speedtest_tracker_http: true
speedtest_tracker_https: false
# Volume paths
speedtest_tracker_config_path: "{{ app_dir }}/config"
# App-specific configuration
speedtest_tracker_timezone: "{{ app_timezone_cc }}"
speedtest_tracker_extra_env_vars:
SPEEDTEST_SCHEDULE: "0 * * * *"
+14
View File
@@ -0,0 +1,14 @@
---
galaxy_info:
author: Patrick Jaroszewski
description: Deploy Speedtest Tracker with Docker Compose
license: MIT
dependencies:
- role: patrickj.docker_apps.docker_compose_app
vars:
app_role_name: speedtest-tracker
app_subdirectories:
- "{{ speedtest_tracker_config_path }}"
app_backup_subdirectories:
- "{{ speedtest_tracker_config_path }}"
@@ -0,0 +1,26 @@
---
services:
speedtest-tracker:
image: lscr.io/linuxserver/speedtest-tracker:{{ speedtest_tracker_container_version }}
restart: {{ speedtest_tracker_restart_policy }}
container_name: {{ speedtest_tracker_container_name }}
ports:
{% if speedtest_tracker_http %}
- {{ speedtest_tracker_http_port }}:80
{% endif %}
{% if speedtest_tracker_https %}
- {{ speedtest_tracker_https_port }}:443
{% endif %}
environment:
- PUID={{ speedtest_tracker_user }}
- PGID={{ speedtest_tracker_group }}
- APP_KEY={{ speedtest_tracker_app_key }}
- DISPLAY_TIMEZONE={{ speedtest_tracker_timezone }}
{% for item in speedtest_tracker_extra_env_vars | dict2items %}
- {{ item.key }}="{{ item.value }}"
{% endfor %}
volumes:
- {{ speedtest_tracker_config_path }}:/config
{% if speedtest_tracker_ssl_path is defined %}
- {{ speedtest_tracker_ssl_path }}:/config/keys
{% endif %}
+25
View File
@@ -0,0 +1,25 @@
# Uptime Kuma
Deploy Uptime Kuma monitoring tool using Docker Compose.
## Description
Uptime Kuma is a fancy self-hosted monitoring tool with notifications and status pages.
## Variables
### Optional
| Variable | Default | Description |
|----------|---------|-------------|
| `uptime_kuma_http_port` | `3001` | Web interface port |
| `uptime_kuma_data_path` | `{{ app_dir }}/data` | Application data storage |
| `uptime_kuma_container_version` | `2` | Uptime Kuma Docker image tag |
## Example
```yaml
- role: patrickj.docker_apps.uptime-kuma
vars:
uptime_kuma_http_port: 3002
```
+13
View File
@@ -0,0 +1,13 @@
---
app_name: uptime-kuma
# Container configuration
uptime_kuma_container_name: "{{ app_name | default('uptime-kuma') }}"
uptime_kuma_container_version: 2
uptime_kuma_restart_policy: "{{ app_restart_policy }}"
# Network configuration
uptime_kuma_http_port: 3001
# Volume paths
uptime_kuma_data_path: "{{ app_dir }}/data"
+14
View File
@@ -0,0 +1,14 @@
---
galaxy_info:
author: Patrick Jaroszewski
description: Deploy Uptime Kuma with Docker Compose
license: MIT
dependencies:
- role: patrickj.docker_apps.docker_compose_app
vars:
app_role_name: uptime-kuma
app_subdirectories:
- "{{ uptime_kuma_data_path }}"
app_backup_subdirectories:
- "{{ uptime_kuma_data_path }}"
@@ -0,0 +1,10 @@
---
services:
uptime-kuma:
image: louislam/uptime-kuma:{{ uptime_kuma_container_version }}
container_name: "{{ uptime_kuma_container_name }}"
restart: "{{ uptime_kuma_restart_policy }}"
volumes:
- "{{ uptime_kuma_data_path }}:/app/data"
ports:
- "{{ uptime_kuma_http_port }}:3001"