2 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
14 changed files with 452 additions and 0 deletions
+1
View File
@@ -1,2 +1,3 @@
---
github_key_url: https://github.com/redjordan2539.keys
base_domain: delpilar.net
+33
View File
@@ -250,3 +250,36 @@ minecraft_servers:
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
+6
View File
@@ -32,3 +32,9 @@ all:
minecraft_servers:
hosts:
new-bark:
ntfy_servers:
hosts:
new-bark:
silverbullet_servers:
hosts:
new-bark:
+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
+16
View File
@@ -36,3 +36,19 @@
- 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