3 Commits
Author SHA1 Message Date
jdelpilarandJordan Del Pilar 2eaa2e9c5e 21 feat add new silverbullet role (#23)
Johto Infrastructure Pipeline / Run Ansible Lint (push) Successful in 2m19s
Johto Infrastructure Pipeline / Deploy to Production (push) Successful in 3m24s
### Description
This PR adds a new silvetbullet role that configures and starts the silverbullet container
Changes
- Creates required silverbullet `space` directory
- creates silverbullet `.container` file
- starts new and updated `.container` files

### Related Issue
Closes #21

### Testing Done
- [x] [e.g., Ran local unit tests]
- [x] [e.g., Verified service starts under Podman]
- [x] [e.g., Manual check of configuration file output]

### Checklist
- [x] My code follows the project's style guidelines.
- [x] I have performed a self-review of my own code.
- [x] I have updated the documentation (if necessary).

---------

Co-authored-by: Jordan Del Pilar <[email protected]>
Reviewed-on: #23
2026-07-27 20:40:42 -07:00
jdelpilarandJordan Del Pilar 8d61a21a1b feat(ntfy):add ntfy server role (#20)
Johto Infrastructure Pipeline / Run Ansible Lint (push) Successful in 1m52s
Johto Infrastructure Pipeline / Deploy to Production (push) Successful in 3m20s
### Description
This PR adds a new `ntfy_server` role to configure, start, and test a ntfy container.
This container is designed to be secure by default by requiring auth by default

### Related Issue
Closes #15

### Testing Done
- [x] verified new container file was created correctly\
- [x] verified ntfy server webui is working and requires auth
- [x] verified with automated test that ntfy server is working and accepting post requests

### Checklist
- [x] My code follows the project's style guidelines.
- [x] I have performed a self-review of my own code.
- [x] I have updated the documentation (if necessary).

---------

Co-authored-by: Jordan Del Pilar <[email protected]>
Reviewed-on: #20
2026-07-16 13:14:06 -07:00
jdelpilarandJordan Del Pilar 857ec00b14 feat(minecraft): add new minecraft server role (#19)
Johto Infrastructure Pipeline / Run Ansible Lint (push) Successful in 1m52s
Johto Infrastructure Pipeline / Deploy to Production (push) Successful in 3m9s
### Description
This PR adds new `minecraft_server` to configure and start a Minecraft server container on targeted hosts.

### Related Issue
Closes #18

### Testing Done
- [x] Verifed new role creates container files correctly
- [x] verified new container is able to start and run via systemd
- [x] verified server is accessible via Minecraft client

### Checklist
- [x] My code follows the project's style guidelines.
- [x] I have performed a self-review of my own code.
- [x] I have updated the documentation (if necessary).

---------

Co-authored-by: Jordan Del Pilar <[email protected]>
Reviewed-on: #19
2026-07-15 12:41:15 -07:00
19 changed files with 612 additions and 0 deletions
+1
View File
@@ -1,2 +1,3 @@
--- ---
github_key_url: https://github.com/redjordan2539.keys github_key_url: https://github.com/redjordan2539.keys
base_domain: delpilar.net
+46
View File
@@ -12,6 +12,8 @@ ansible_become_password: !vault |
podman_config_base_dir: /appdata/podman podman_config_base_dir: /appdata/podman
podman_quadlet_base_dir: "/home/{{ ansible_user }}/.config/containers/systemd" podman_quadlet_base_dir: "/home/{{ ansible_user }}/.config/containers/systemd"
timezone: America/Los_Angeles
dns_services: dns_services:
- name: adguard - name: adguard
image: docker.io/adguard/adguardhome:latest image: docker.io/adguard/adguardhome:latest
@@ -237,3 +239,47 @@ backup_paths:
- /storage/public-assets - /storage/public-assets
keep_daily: 7 keep_daily: 7
keep_weekly: 4 keep_weekly: 4
minecraft_servers:
- name: vanilla
image: docker.io/itzg/minecraft-server:latest
port: 25565
env:
MEMORY: 4G
USE_AIKAR_FLAGS: "true"
TYPE: PAPER
ENABLE_AUTOPAUSE: "true"
OPS: redjordan1
ntfy_web_user: jdelpilar
ntfy_web_pass: !vault |
$ANSIBLE_VAULT;1.1;AES256
39363231343664626436343130316662336663303939343334353138353864383334363362343362
6366633162323162393263336137313534303563353337340a316362653735306538363733333461
38626362386263613932366664316630306361313036353839373562663534613962346339626538
3866356430663962660a613962396662333538333836666334613064343266376431633463326164
39333735343634316336613933303765373934393834663933626439643138663561
ntfy_users:
- username: jdelpilar
pass: !vault |
$ANSIBLE_VAULT;1.1;AES256
63613562396339323236636436613162633933306338333662633933613832613038313230333165
3365636562366165363861353638306264653739396532320a366564346331396266653762306165
33333639373532653762363563653534353661366239306265303538376237393438636437393632
3138386130306430640a383932383634313764373565636463636233623063613961353961643531
35613864303162393362616634626238316334343533646261643063303963383932653534316466
31313231643239653865363163623136316234386433393263366537323866326633313261656533
313965396432613533653934323464626334
level: admin
- username: hass
pass: !vault |
$ANSIBLE_VAULT;1.1;AES256
65656330333535306239343935306234633730376361393234376266393837636436313262353939
3635653139383864396533373534306236386662643535650a373765303531633563326563663736
39666339343439333730373834353962343962383335633466656162356465366537303532623438
6361633163623061660a323565346663313238396431373932333562313237326238313235373330
33663632333266623162373033376432336538393334386663393866623836663562343936396234
38633431623838653035623066346138386234623861316461653430623638656563633261383238
353132376664303838316637663035633862
level: user
+9
View File
@@ -29,3 +29,12 @@ all:
gitea_servers: gitea_servers:
hosts: hosts:
new-bark: new-bark:
minecraft_servers:
hosts:
new-bark:
ntfy_servers:
hosts:
new-bark:
silverbullet_servers:
hosts:
new-bark:
+59
View File
@@ -0,0 +1,59 @@
# Role: Minecraft Server
Sets up and deploys minecraft server container
## Tags
- minecraft
## Required Variables
Below is an annotated breakdown of the required variables and their structure for this role
These blocks should be defined in the `host_vars` file for any host that should be a minecraft server
> [!WARNING]
> Any variable marked `# !SENSITIVE` **should not** be stored in plain text under any circumstance
### Minecraft Info
Defines settings for the Minecraft server container settings
```yaml
# (required) List of all minecraft server containers to be deployed
# you can run as many minecraft servers as the hardware can handle. However, all will need a unique port
# at least one service is required
minecraft_servers:
# (required) name of the server container
# all containers and services will be prefixed with 'mc-'
# for example if you list 'vanilla' as the name the resulting container/service name will be 'mc-vanilla'
# format: snake_case
- name:
# (required) URL of container image
# can be from any container registry
# recommended image is: docker.io/itzg/minecraft-server:latest
# format: url
image: docker.io/itzg/minecraft-server:latest
# (optional) host port to bind to the container
# this must be unique for each server instance
# default: 25565
# format: int
port:
# (optional) list of environment variables to pass to the container
# these are primarily used to define settings for the minecraft server
# for more info please read the docs for your specific container image
# memory setting example listed to show proper format
# format: key value pair
env:
MEMORY: 4G
```
## Templates
### minecraft.container.j2
This template is used to generate .container files for Minecraft servers. This template is heavily opinionated to be a minecraft server instance and should not be used a generic template for quadlets.
## Execution
> [!NOTE]
> If this role makes changes to the quadlet file on the host the server will be restarted. If you are hosting this server for multiple users please keep that in mind
To run this command without running all roles in the playbook, use the following command
```bash
ansible-playbook site.yaml --tags "minecraft"
```
@@ -0,0 +1,4 @@
---
container_owner: jdelpilar
mc_port: 25565
timezone: America/Los_Angeles
@@ -0,0 +1,7 @@
- name: Restart changed Minecraft Services
ansible.builtin.systemd:
name: "mc-{{ item.item.name }}"
state: restarted
scope: user
daemon_reload: true
loop: "{{ minecraft_quadlet_results.results | selectattr('changed', 'equalto', true) | list }}"
+27
View File
@@ -0,0 +1,27 @@
---
- name: Create Minecraft Directories
ansible.builtin.file:
path: "{{ podman_config_base_dir }}/mc-{{ item.name }}/data"
state: directory
mode: "0755"
loop: "{{ minecraft_servers }}"
- name: Create Minecraft Quadlets
ansible.builtin.template:
src: minecraft.container.j2
dest: "{{ podman_quadlet_base_dir }}/services/mc-{{ item.name }}.container"
owner: "{{ ansible_user }}"
mode: "644"
loop: "{{ minecraft_servers }}"
register: minecraft_quadlet_results
notify: Restart changed Minecraft Services
- name: Flush Handlers
ansible.builtin.meta: flush_handlers
- name: Start Minecraft Servers
ansible.builtin.systemd:
name: "mc-{{ item.name }}"
state: started
scope: user
loop: "{{ minecraft_servers }}"
@@ -0,0 +1,40 @@
# {{ ansible_managed }}
[Unit]
After=network-online.target
StartLimitBurst=10
StartLimitIntervalSec=120
[Container]
ContainerName=mc-{{ item.name }}
Image={{ item.image }}
Network=management-net
PublishPort={{ item.port | default(mc_port) }}:25565
AutoUpdate=registry
Label=category=management
Label=owner={{ item.container_owner | default('jdelpilar') }}
Volume={{ podman_config_base_dir }}/mc-{{ item.name }}/data:/data
{% if item.volumes is defined %}
{% for volume in item.volumes %}
Volume={{ volume }}
{% endfor %}
{% endif %}
Environment=TZ={{ timezone | default('America/Los_Angeles') }}
Environment=EULA=true
{% if item.env is defined %}
{% for key, value in item.env.items() | sort %}
Environment={{ key }}={{ value }}
{% endfor %}
{% endif %}
[Service]
Restart=on-failure
RestartSec=5
[Install]
WantedBy=default.target
+106
View File
@@ -0,0 +1,106 @@
# Role: ntfy Server
This role sets up, starts and test the ntfy container.
This role is designed to only create one ntfy container per host.
## Tags
- ntfy
- comms
## Required Variables
Below is an annotated breakdown of the required variables and their structure for this role
> [!WARNING]
> Any variable marked `# !SENSITIVE` **should not** be stored in plain text under any circumstance
### ntfy User Info
Defines users to be set up and used in ntfy.
These settings should be defined on each server you plan on setting up ntfy on as they are unique to each server
```yaml
# (required) username of the primary web user of the ntfy webui
# this account is used during the role to send a test post request to verify the server is running
# this username must also be defined in the below ntfy_users list
# format: username
ntfy_web_user:
# (required) password of the above web user
# this is used during basic auth to send the test request to the server
# !SENSITIVE
# format: string
ntfy_web_pass:
# (required) list of users to be created in the ntfy instance
# you must defined the above ntfy_web_user in this list
ntfy_users:
# (required) username of the user to be created
# format: username
- username:
# (required) password hash for the user
# for more info on the requirements of this hash please read below
# !SENSITIVE
# format: string
pass:
# (required) user level of the generated user
# you must define at least one admin user per instance
# format: choice("user", "admin")
level:
```
### ntfy container Info
Defines settings for the ntfy container
```yaml
# (optional) name of the ntfy container
# default: ntfy
# format: snake_case
ntfy_name:
# (optional) path to ntfy container image
# can be set to any container register
# default: docker.io/binwiederhier/ntfy
# format: URL
ntfy_image:
# (optional) name of the container owner
# typically set to the same user as the ansible user
# default: {{ ansible_user }}
# format: username
container_owner:
# (optional) flag to enable traefik labels in the container
# default: true
# format: bool
ntfy_enable_traefik:
# (optional) subdomain of the ntfy instance
# only used if `ntfy_enable_traefik` == true
# default: ntfy
# format: string
ntfy_subdomain:
# (optional) port to ntfy webui
# only used if `ntfy_enable_traefik` == true
# default: 80
# format: int
ntfy_port:
# (optional) podman network to bind ntfy container to
# default: management-net
# format: string
ntfy_network:
# (optional) URL of the ntfy webui
# default: ntfy.delpilar.net
# format: url
ntfy_url:
```
## Templates
### ntfy.container.j2
This template is used to generate .container files for ntfy services. This template includes a section for traefik labels.
## Execution
To run this role without running all other roles use the following command
```bash
ansible-playbook site.yaml --tags "ntfy"
```
+9
View File
@@ -0,0 +1,9 @@
---
ntfy_name: ntfy
ntfy_image: docker.io/binwiederhier/ntfy
container_owner: "{{ ansible_user }}"
ntfy_enable_traefik: true
ntfy_subdomain: ntfy
ntfy_port: 80
ntfy_network: management-net
ntfy_url: ntfy.delpilar.net
+6
View File
@@ -0,0 +1,6 @@
- name: Restart ntfy on Change
ansible.builtin.systemd:
name: "{{ ntfy_name }}"
state: restarted
scope: user
daemon_reload: true
+40
View File
@@ -0,0 +1,40 @@
---
- name: Create ntfy Directories
ansible.builtin.file:
path: "{{ podman_config_base_dir }}/{{ ntfy_name }}/{{ item }}"
state: directory
mode: "0755"
loop:
- "/cache"
- "/auth"
- name: Create ntfy Quadlet
ansible.builtin.template:
src: ntfy.container.j2
dest: "{{ podman_quadlet_base_dir }}/management/{{ ntfy_name }}.container"
owner: "{{ ansible_user }}"
mode: "644"
notify: Restart ntfy on Change
- name: Flush Handlers
ansible.builtin.meta: flush_handlers
- name: Start ntfy Servers
ansible.builtin.systemd:
name: "{{ ntfy_name }}"
state: started
scope: user
- name: Verify server is running
ansible.builtin.uri:
url: "https://{{ ntfy_url }}/ansible_test"
method: POST
body: "Deployment Successful! ntfy is online"
url_username: "{{ ntfy_web_user }}"
url_password: "{{ ntfy_web_pass }}"
force_basic_auth: true
status_code: 200
register: ntfy_health_check
until: ntfy_health_check.status == 200
retries: 10
delay: 3
@@ -0,0 +1,57 @@
# {{ ansible_managed }}
[Unit]
After=network-online.target
StartLimitBurst=10
StartLimitIntervalSec=120
[Container]
ContainerName={{ ntfy_name }}
Image={{ ntfy_image }}
Network={{ ntfy_network | default('management-net', true) }}
AutoUpdate=registry
Label=category=management
Label=owner={{ container_owner | default('jdelpilar', true) }}
{% if ntfy_enable_traefik | default(true) %}
Label=traefik.enable=true
Label=traefik.http.routers.{{ ntfy_name }}.rule=Host(`{{ ntfy_url | default(ntfy_name + base_domain, true) }}`)
Label=traefik.http.routers.{{ ntfy_name }}.entrypoints={{ traefik_entrypoint | default('websecure', true) }}
Label=traefik.http.routers.{{ ntfy_name }}.tls.certresolver={{ traefik_resolver | default('cloudflare', true) }}
Label=traefik.http.services.{{ ntfy_name }}.loadbalancer.server.port={{ ntfy_port | default(80, true) }}
Label=traefik.docker.network={{ ntfy_network | default('management-net', true) }}
Label=traefik.http.routers.{{ ntfy_name }}.tls=true
{% endif %}
Volume={{ podman_config_base_dir }}/{{ ntfy_name }}/cache:/var/cache/ntfy
Volume={{ podman_config_base_dir }}/{{ ntfy_name }}/auth:/var/lib/ntfy
{% if item.volumes is defined %}
{% for volume in item.volumes %}
Volume={{ volume }}
{% endfor %}
{% endif %}
Environment=TZ={{ timezone | default('America/Los_Angeles') }}
Environment=NTFY_BASE_URL=https://{{ ntfy_url | default(ntfy_name + base_domain, true) }}
Environment=NTFY_AUTH_FILE=/var/lib/ntfy/user.db
Environment=NTFY_AUTH_DEFAULT_ACCESS=deny-all
Environment=NTFY_ENABLE_LOGIN=true
Environment=NTFY_REQUIRE_LOGIN=true
Environment=NTFY_AUTH_USERS="{% for user in ntfy_users %}{{ user['username'] }}:{{ user['pass'] }}:{{ user['level'] }}{{ ',' if not loop.last }}{% endfor %}"
{% if ntfy_env is defined %}
{% for key, value in ntfy_env.items() | sort %}
Environment={{ key }}={{ value }}
{% endfor %}
{% endif %}
Exec=serve
[Service]
Restart=on-failure
RestartSec=5
[Install]
WantedBy=default.target
+84
View File
@@ -0,0 +1,84 @@
# Role: SilverBullet Server
Sets up and deploys SilverBullet container
For more information about SilverBullet check out [their website](https://silverbullet.md/)
## Tags
- silverbullet
- docs
## Required Variables
Below is an annotated breakdown of the required variables and their structure for this role
> [!WARNING]
> Any variable marked `# !SENSITIVE` **should not** be stored in plain text under any circumstance
### SilverBullet Info
Defines settings for the SilverBullet Server.
Most of these variables are optional, and have predefined defaults in the role itself, however it is possible to define custom variables in `host_vars` files.
Any variable marked as optional has a default value defined in `defaults/main.yaml` for this role
```yaml
# (optional): Name of the silverbullet container
# This name is also the name of the service created by the quadlet file,
# as well as the name of the .container file
# default: silverbullet
# format: snake_case
silverbullet_name:
# (optional): Image of the silverbullet container
# This can be any image from any register that podman supports
# default: ghcr.io/silverbulletmd/silverbullet:latest
# format: URL
silverbullet_image:
# (optional): Port of the silverbullet webui
# this is used for traefik labels to allow for access to the webui
# the default value is defined by the silverbullet container itself. For information on changing it, view the documentation for your image
# default: 3000
# format: int
silverbullet_port:
# (optional): Username of the silverbullet user
# this is the default user created for silverbullet
# note, this value has a default, but it is highly recommended to change it via `host_vars`
# default: jdelpilar
# format: username
silverbullet_user:
# (optional): password for the above created user
# note, this value has a default, but it is highly recommended to change it via `host_vars`
# !SENSITIVE
# default: generated password
# format: password
silverbullet_pass:
# (optional): url of the silverbullet instance
# this is used to set the url in traefik
# default: silverbullet.delpilar.net
# format: url
silverbullet_url:
```
## Templates
### silverbullet.container.j2
This template creates a `.container` file for silverbullet
By default this template supports the following additional variables not listed above.
- silver_bullet_volumes: used to define additional mounted volumes
- format: <host_path>:<container_path>
- silver_bullet_env: used to define additional environment variables used by the container
- format: dict(<key>:<value>)
## Execution
> [!NOTE]
> This role restarts any containers where the `.container` file is changed. As such, please ensure that all work is saved and all users are made aware of any potential downtime.
To run this role without running any other roles, please use this command
```bash
ansible-playbook site.yaml --tags silverbullet
```
To run all roles with the `docs` tag at once, please use this command
```bash
ansible-playbook site.yaml --tags docs
```
@@ -0,0 +1,14 @@
---
silverbullet_name: silverbullet
silverbullet_image: ghcr.io/silverbulletmd/silverbullet:latest
silverbullet_port: 3000
silverbullet_user: jdelpilar
silverbullet_pass: !vault |
$ANSIBLE_VAULT;1.1;AES256
37643331363732343135383232666363326464313534316264316261613161333633306239336365
3430613632323734616233303336363331646364303530660a373639323639656664336236303837
35613464313563303565666638643463326431616665613837353264346132636133396636383232
6430343764626363310a323033333662656532386131663734613436663665356164396662613636
38383863313064313563306439653434646533353363373338306633393562373235
silverbullet_enable_traefik: true
silverbullet_url: silverbullet.delpilar.net
@@ -0,0 +1,6 @@
- name: Restart changed Silverbullet Services
ansible.builtin.systemd:
name: "{{ silverbullet_name }}"
state: restarted
scope: user
daemon_reload: true
+24
View File
@@ -0,0 +1,24 @@
---
- name: Create SilverBullet Directory
ansible.builtin.file:
path: "{{ podman_config_base_dir }}/{{ silverbullet_name }}/space"
state: directory
mode: "0755"
- name: Create SilverBullet Quadlet
ansible.builtin.template:
src: silverbullet.container.j2
dest: "{{ podman_quadlet_base_dir }}/services/{{ silverbullet_name }}.container"
owner: "{{ ansible_user }}"
mode: "644"
notify: Restart changed Silverbullet Services
- name: Flush Handlers
ansible.builtin.meta: flush_handlers
- name: Start SilverBullet
ansible.builtin.systemd:
name: "{{ silverbullet_name }}"
state: started
scope: user
daemon_reload: true
@@ -0,0 +1,50 @@
# {{ ansible_managed }}
[Unit]
After=network-online.target
StartLimitBurst=10
StartLimitIntervalSec=120
[Container]
ContainerName={{ silverbullet_name }}
Image={{ silverbullet_image }}
Network=services-net
PublishPort={{ silverbullet_port }}:3000
AutoUpdate=registry
Label=category=management
Label=owner={{ container_owner | default('jdelpilar') }}
{% if silverbullet_enable_traefik %}
Label=traefik.enable=true
Label=traefik.http.routers.{{ silverbullet_name }}.rule=Host(`{{ silverbullet_url | default(silverbullet_name + "." + base_domain, true) }}`)
Label=traefik.http.routers.{{ silverbullet_name }}.entrypoints={{ traefik_entrypoint | default('websecure', true) }}
Label=traefik.http.routers.{{ silverbullet_name }}.tls.certresolver={{ traefik_resolver | default('cloudflare', true) }}
Label=traefik.http.services.{{ silverbullet_name }}.loadbalancer.server.port={{ silverbullet_port | default(3000, true) }}
Label=traefik.docker.network=services-net
Label=traefik.http.routers.{{ silverbullet_name }}.tls=true
{% endif %}
Volume={{ podman_config_base_dir }}/{{ silverbullet_name }}/space:/space
{% if silverbullet_volumes is defined %}
{% for volume in silverbullet_volumes %}
Volume={{ volume }}
{% endfor %}
{% endif %}
Environment=TZ={{ timezone | default('America/Los_Angeles') }}
Environment=SB_USER={{ silverbullet_user }}:{{ silverbullet_pass }}
{% if silverbullet_env is defined %}
{% for key, value in silverbullet_env.items() | sort %}
Environment={{ key }}={{ value }}
{% endfor %}
{% endif %}
[Service]
Restart=on-failure
RestartSec=5
[Install]
WantedBy=default.target
+23
View File
@@ -29,3 +29,26 @@
tags: tags:
- common - common
- backup - backup
- name: Minecraft Setup
hosts: minecraft_servers
roles:
- minecraft_server
tags:
- minecraft
- name: Ntfy Setup
hosts: ntfy_servers
roles:
- ntfy_server
tags:
- ntfy
- comms
- name: SilverBullet Setup
hosts: silverbullet_servers
roles:
- silverbullet_server
tags:
- silverbullet
- docs