This commit is contained in:
Mike McFetridge
2026-07-20 09:23:17 -04:00
parent c1315882da
commit 72272e4006
3179 changed files with 562960 additions and 14 deletions
+86
View File
@@ -0,0 +1,86 @@
---
tags:
- Documentation
- Bookstack
- Notes
---
# AI Development
# AI Development Prompt Templates
Here is a clean, professional, and well-structured markdown template based on your provided prompts. I have eliminated redundancies (like the duplicated review points), organized the sections into logical modules, and formatted it so you can quickly copy-paste it whenever you need AI-assisted development.
# AI Development Prompt Templates
## 1. Code Generation
Use this prompt when you need to build a new class, module, or specific functionality from scratch.
<div class="code-block ng-tns-c1605810258-63 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" id="bkmrk-plaintext"><div class="formatted-code-block-internal-container ng-tns-c1605810258-63"><div class="animated-opacity ng-tns-c1605810258-63"><div class="code-block-decoration header-formatted gds-emphasized-body-m ng-tns-c1605810258-63 ng-star-inserted"><span class="ng-tns-c1605810258-63">Plaintext</span><div class="buttons ng-tns-c1605810258-63 ng-star-inserted"></div></div></div></div></div>```
Act as an expert software engineer. I need to implement the following functionality:
- **Task:** [e.g., Create a class/module for a rate-limiter]
- **Language/Framework:** [programming language/framework]
### Key Requirements
1. [Requirement 1]
2. [Requirement 2]
3. [Requirement 3]
### Implementation Guidelines
- Include a proper constructor/initialization method.
- Implement main public methods with clear docstrings.
- Break down complex logic into private helper methods where appropriate.
- Ensure proper encapsulation and strict adherence to OOP principles.
- Implement thorough error handling and guard against edge cases.
- Optimize for performance and follow best practices for [language/framework].
- Do not unnecessarily remove any context. Include clear inline comments explaining the core logic.
```
<div class="code-block ng-tns-c1605810258-63 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" id="bkmrk--1"><div class="formatted-code-block-internal-container ng-tns-c1605810258-63"><div class="animated-opacity ng-tns-c1605810258-63"></div></div></div>## 2. Code Review &amp; Explanation
Use this prompt when you want to deeply understand an existing piece of code and identify potential vulnerabilities or flaws.
<div class="code-block ng-tns-c1605810258-64 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" id="bkmrk-plaintext-1"><div class="formatted-code-block-internal-container ng-tns-c1605810258-64"><div class="animated-opacity ng-tns-c1605810258-64"><div class="code-block-decoration header-formatted gds-emphasized-body-m ng-tns-c1605810258-64 ng-star-inserted"><span class="ng-tns-c1605810258-64">Plaintext</span><div class="buttons ng-tns-c1605810258-64 ng-star-inserted"></div></div></div></div></div>```
Act as a senior code reviewer. Please review and explain the following code snippet in detail:
---
[PASTE CODE HERE]
---
### Analysis Requested
1. **Purpose:** What is the primary objective of this code section?
2. **Step-by-Step Walkthrough:** How does it execute line-by-line?
3. **Evaluation:** Are there any potential issues or limitations with this approach?
### Evaluation Criteria
Please evaluate the code against the following lenses:
- **Code Quality:** Readability, maintainability, and adherence to clean code standards.
- **Robustness:** Potential bugs, unhandled edge cases, or missing error states.
- **Performance:** Execution bottlenecks or optimization opportunities.
- **Security:** Any vulnerabilities or safety concerns.
Provide specific suggestions for improvement and explain the reasoning behind each recommendation.
```
<div class="code-block ng-tns-c1605810258-64 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" id="bkmrk--4"><div class="formatted-code-block-internal-container ng-tns-c1605810258-64"><div class="animated-opacity ng-tns-c1605810258-64"></div></div></div>## 3. Code Refactoring &amp; Rewriting
Use this prompt when you have working code but want to elevate it to production-grade quality.
<div class="code-block ng-tns-c1605810258-65 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" id="bkmrk-plaintext-2"><div class="formatted-code-block-internal-container ng-tns-c1605810258-65"><div class="animated-opacity ng-tns-c1605810258-65"><div class="code-block-decoration header-formatted gds-emphasized-body-m ng-tns-c1605810258-65 ng-star-inserted"><span class="ng-tns-c1605810258-65">Plaintext</span><div class="buttons ng-tns-c1605810258-65 ng-star-inserted"></div></div></div></div></div>```
Act as a principal engineer. Please review and rewrite the following code to make it production-ready, highly optimized, and maintainable.
---
[PASTE CODE HERE]
---
### Refactoring Requirements
Please refactor the code while prioritizing the following:
- **Robustness:** Add comprehensive error handling and address edge cases.
- **Performance:** Optimize execution time and memory footprint where applicable.
- **Security:** Fix any potential security vulnerabilities.
- **Clean Code:** Improve readability, maintainability, and alignment with modern language best practices.
Please provide the final refactored code with clear comments, accompanied by a brief summary of the key improvements made and why they were necessary.
```
+430
View File
@@ -0,0 +1,430 @@
---
tags:
- Documentation
- Bookstack
- Notes
---
# Ansible
# Install Ansible and Make a Playbook
<iframe height="336" src="https://www.youtube.com/embed/mi9HPGap0R0" width="600"></iframe>
<p class="callout info">*This document and video was written and produced by Brian @ Awesome Open Source. Please support his channel and ongoing efforts through Patreon: [https://www.patreon.com/bePatron?u=234177](https://www.patreon.com/bePatron?u=234177)*</p>
Ansible is an incredibly powerful and robust tool made specifically for automating workflows and actions. It works on Linux, MacOS, and Windows, and can help reduce your task load by thousands, or even tens of thousands of individual actions. We will be rolling out Ansible during our series on building an MSP as a tool to help us deal with a growing business where we are supporting our clients and their multitudes of devices. We will employ Ansible's power to push out updates, agents for the various software services we'll employ, and so much more.
This is just an introduction to ansible, and will get you started with it, but it is highly recommended that you also check out other series on ansible. I'll link to one below that will take you a bit deeper. You should, of course start getting comfortable with the ansible documentation. This is one of the most well documented tools in the open source world. The answers are there for you, just waiting to be read and put to use.
### What You'll Need
<div dir="auto" id="bkmrk-a-machine-to-use-as-">- A machine to use as an Ansible controller (the server that you run Ansible commands from).
- An SSH Public / Private key pair
- SSH Access to any target machine (client machine)
- About thirty minutes of your time
</div>### SSH Key Pair Setup
For this series, I'll be installing Ansible itself on a Ubuntu 22.04 LTS Incus (LXD) container. This is a dedicated virtual machine I'm creating for the sole purpose of running Ansible. You can do the same, or use your main laptop or desktop machine. Keep in mind, that as we grow our use of Ansible, we will want to start scheduling certain tasks to run, so we'll want a machine that is always on and ready.
To setup an SSH key pair, we can run the following command:
`ssh-keygen -t ed25519 -C "ansible"`
The command above tells ssh to generate a key pair using the ed25519 encryption. This encryption is similar in strength to RSA 256, but is a much shorter key, and uses less computer power to generate.
When you submit the command, you'll be prompted on where to store the command, and what to call it. This is up to you, but I highly recommend, you keep the key pair in
`/home/<your user>/.ssh/`
as this is where OpenSSH looks for the keys automatically. As for the name, name it something that makes sense for it's purpose. In my case I will name it 'ansible'. So my entier path and name will look like
`/home/<your user>/.ssh/ansible`
Next, you'll be prompted for a passphrase for this key. We want to leave this blank so that we won't be prompted each time for our passphrase as ansible goes to login to the machines it's taking action on.
Just press Enter to keep the passphrase blank. Next, confirm that you want it blank (empy) by simply pressing Enter again.
SSH will now generate a secure public and private key pair for you. If you do an `ls` on this folder ( /home/&lt;your user&gt;/.ssh ) you'll see that two new files haave been added. They'll be called `ansible` and `ansible.pub`. The file ending in .pub is your public key file and can be shared out to all of the machines you want to access with ansible. the other file is your private key file and should never be shared with anyone, nor sent to public machines. The `ansible` file is your key to access any host with the `ansible.pub` file on it.
### Send Our New Key to Target Machines
In order for ansible to run, we need to share our new key to target machines. We can do this wil the command
`ssh-copy-id`
This command allows us to specify which key to share, and to which host and for which user we share it.
I'll be adding 3 hosts to start, but it's not required. You can do just one if you prefer. My hosts will have the IPs
192.168.10.20, 192.168.10.21, and 192.168.10.22
Don't worry, your hosts don't have to have consecutive IP addresses.
Let's copy and SSH key over to the first host machine.
`ssh-copy-id -i /home/brian/.ssh/ansible `[`brian@192.168.10.20`](mailto:brian@192.168.10.20)
`-i `tells ssh that we are going to specify the file to send. We then tell it the path and key to send. You may notice I just put 'ansible' and not 'ansible.pub'. This is ok, as the `ssh-copy-id` command knows to send the public key, not the private key.
We press enter, then will be prompted for our password to access this machine via SSH. Enter the password, and you should get a message confirming that 1 key has been copied.
You can not attempt to access the machine using the new key with the ssh command as follows:
`ssh -i /home/brian/.ssh/ansible <a href="mailto:brian@192.168.10.20">brian@192.168.10.20</a>`
You should be logged onto the machine without being prompted for any password.
You have now copied your ssh key to another machine. Repeat the above process for however many machines you want to have ansible accessing.
### Install Ansible
Ansible is already packaged in most distribution repositories, but the Ubuntu 22.04 version lags behind a bit, so let's make sure we get the latest version possible. To do this, we'll add the ansible ppa repository instead.
`sudo add-apt-repository ppa:ansible/ansible`
When you submit the above command, you'll be prompted to press Enter, so press Enter, then you should see your system attempt to update the package cache. Let's runt he update one more time just to be sure.
`sudo apt update -y`
Now we can install the latest version of ansible with
`sudo apt install ansible -y`
### Creating an Ansible Inventory
Ansible uses an inventory file to know what machines you want it to access and perform actions on. This file can be yaml or plain text. We'll be starting with the plain text file for now, as I think it's a little bit easier to grasp initially. Feel free, however, to check out the documentation if you are a yaml expert.
Let's make our new file with
`nano inventory`
Note that Ansible can deal with machines collected into groups, and that a machine can be in more than one group, and that you can even group other groups as well.
We'll start with two groups for our example, but use whatever groups make sense for your needs. The organization for our inventory file will be like the following:
```
[group_name]
machine_alias_1 ansible_host=<machine_ip_1>
machine_alias_2 ansible_host=<machine_ip_2>
[group_name_2]
machine_alias_3 ansible_host=<machine_ip_3>
```
The items in square brackets are the group names we assign, and then below any group name we list the machines that are part of that gorup. We list the machines with an alias name, any name that describes what machine it is. This can be the machine hostname, or just an alias we want for the machine. After the alias, we put a space, then indicate the machines ip or fqdn for ansible to connect to the machine with. We identify it with the key `ansible_host=` then enter the ip or fqdn for the machine. Let's look at an actual example of our inventory file now.
```
[home_server]
dashy ansible_host=192.168.10.20
vaultwarden ansible_host=192.168.10.21
[home_desktops]
brian_studio ansible_host=192.168.10.22
```
Above, you'll see two groups home\_server, and home\_desktops. The home\_server group has two machines in it, and one machine is held under the home\_desktops group.
<p class="callout info">NOTE: Ansible doesn't allow spaces in group names or aliases, nor hyphens ( - ), so you need to use underscores ( \_ ) in names where you want to separate words. </p>
We can save our 'inventory' file with CTRL + O, then press Enter to confirm, and exit the nano editor with CTRL + X.
### Create an Ansible Playbook
Playbooks, are pretty much exactly what they sound like. They are the instructions that you want ansible to execute on a target machine, or set of machines. You can target individual machines (by alias), or group(s) of machines, and even the entire inventory if you want.
Playbooks are written in yaml (yes, the space dependent, very picky file format), but it does make plays easier to read, and as you get more accustomed to yaml, easier to update and modify as needed.
While stiill in our ansible\_projects folder, we'll create a new file called update\_ubuntu\_servers.yml.
`nano update_ubuntu_server.yml`
This will hold the plays we need in order to update our servers and desktops that are running Ubuntu as a base operating system.
In the file, we'll start by stating which target machines from our inventory file we want to perform an update on.
```yaml
---
- hosts: all
```
In the above file, we start with three hyphens on the first line to indicate the beginning of our yaml file. below that we tell ansible that we want to run this on all hosts in our inventory file. Now, if you have machines with differing operating systems, you could group them by OS, but there are some smart checks we can do to make sure we don't try to do `apt updte` on an OpenSuse, Redhat, or other non-apt system as well.
To run the updates in apt, we need to be a sudo user. In ansible this uses the 'become' parameter, so let's add that to our file.
```yaml
---
- hosts: all
become: true
```
It's 'become' as in "become super user" or root.
Now that we've got the initial portion set, we can start creating 'tasks' for ansible to perform on these systems. The first task is to update the package cache, and the next task is to run the update on any packages that need it, although we list them in the reverse order in the yaml file.
```
---
- hosts: all
become: true
tasks:
- name: Update packages on Ubuntu systems
become: true
apt:
upgrade: dist
update_cache: yes
```
Given our additions above, we can see that we give the task a name, this helps us know what task is being performed. This can be any string really, so call the task whatever makes sense.
Next, we again tell it this needs to be done as a super user with `become: true`.
And finally, we add the 'apt' module, and give it two actions to complete. `upgrade`, and we define that we want it to do a distribution level upgrade with `upgrade: dist`. Next we tell it that it needs to update the cahce of packages with `update_cache: yes`.
We can save this file and run it as is, and presuming you've setup your target machines properly, it will indeed update the cache of packages, and then run the upgrade procedure.
But, what about kernel updates? This usually includes the need for a reboot as well. I think we should go ahead and include that as part of our instruction set. to do that we just add another `-name` block under our `tasks:` section.
First, let's have Ansible check to see if a reboot is required.
```
---
- hosts: all
become: true
tasks:
- name: Update packages on Ubuntu systems
become: true
apt:
upgrade: dist
update_cache: yes
 
- name: Check if a reboot is needed
become: true
stat:
path: /var/run/reboot-required
register: reboot_required
```
In our next task section, we give it a descriptive name so we'll know what we've asked ansible to do. Then, again, we tell it to do this task as a super user. Next, we call the `stat` module. This can pull status information for us. We tell the 'stat' module to look in `/var/run/reboot-required` with the `path:` line, and finally we save the information in a variable with `register: reboot_required`. The variable name is 'reboot\_required', and the stat command will check to see if that path exists or not.
Now that we know if a reboot is required, let's tell Ansible to perform the reboot if the variable 'reboot\_required' is set to 'true' or 'yes'. To do that, we add another `-name:` section under our `tasks:` in our yaml file.
```
---
- hosts: all
become: true
tasks:
- name: Update packages on Ubuntu systems
become: true
apt:
upgrade: dist
update_cache: yes
- name: Check if a reboot is needed
become: true
stat:
path: /var/run/reboot-required
register: reboot_required
- name: Rebooting Machine After Upgrade
become: true
ansible.builtin.reboot:
reboot_timeout: 120
when: reboot_required.stat.exists
```
Here, we name our task 'Rebooting Machine After Upgrade', then tell Ansible it must be run with super user privileges, and finally call on the built in Ansible module to reboot a machine, `ansible.builtin.reboot`.
Below that we add a short waiting time of 120 seconds (2 minutes). This just gives the upgrade time to fully complete before the reboot. Finally, we tell Ansible to only do this reboot when our 'reboot\_required' variable shows that the `reboot-required` path exists. The `when` in Ansible is a nice easy way to add some logic to a task.
For example, if your friend asked, "Can you feed my dog?" That's pretyy open ended, and you may not want to feed their dog forever. So it's better for your friend to say, "Can you feed my dog *when* I go on vacation next month?". Now your friend has put a qualifier on when you should feed the dog.
This is the same as in Ansible. We are saying, "when /var/run/reboot-required exists, wait 2 minutes, then reboot the machine." Otherwise no reboot is necessary, so we leave the machine running.
Now we are ready to save our file, and exit the nano editor. We will run this with the `ansible-playbook` command. With the command we want to give Ansible instruction to use our 'ansible' private key, and tell it which host(s) to run the play on. Since we put the 'when' clause in our play, we can, of course just tell it 'all', but later on that may be a bit inefficient.
`ansible-playbook --key-file ~/.ssh/ansible_key -i inventory --ask-become-pass update_ubuntu_server.yml`
When you press Enter, you'll see Ansible ask you for your super user password, this is the password on the remote machines, and if entered incorrectly, will generate a list of failed task attempts. Next, Ansible will ensure it can reach each target machine, then it will begin running through each task in the playbook. At the end you'll get a summary of whether a play succeeded or failed, how many changes were made, how many tasks were skipped, and so on. What we are looking for is no tasks skipped, and no tasks failed.
Once we have that result, we have a play we can now use anytime we want in order to keep all of our servers up to date. We can even set this up to run as a cron job, but we need a secure way to feed Ansible our super user password for the tasks that require super user privileges.
### Avoiding Fails on Different OSes
We can avoid fails that occur from running plays on machines or operating systems that don't make sense. Such as running apt on a Fedora machine. Again, we can turn to the 'when' operator in Ansible playbooks. The step where Ansible "gathers facts" is an important one, as Ansible grabs a bunch of details about our various machines. We can then use this information to create conditions
`when: ansible_distribution == 'Ubuntu'`
and
`when: ansible_distribution == 'Fedora'`
We can add this to our existing playbook, and add a section to update Fedora as well.
```
---
- hosts: all
become: true
tasks:
- name: Update packages on Ubuntu systems
become: true
apt:
upgrade: dist
update_cache: yes
when: ansible_distribution == 'Ubuntu'
- name: Update packages on Fedora systems
become: true
dnf:
update_only: true
update_cache: true
when: ansible_distribution == 'Fedora'
- name: Check if a reboot is needed
become: true
stat:
path: /var/run/reboot-required
register: reboot_required
- name: Rebooting Machine After Upgrade
become: true
ansible.builtin.reboot:
reboot_timeout: 120
when: reboot_required.stat.exists
```
In the above, we've added a new task named 'Update packages on Fedora systems', and instead of 'apt', we use 'dnf' as this is the package manager for Fedora, CentOS, Red Hat, etc.
Finally, we added a 'when' clause to the Ubuntu update task, and one to the Fedora update task. This clause will ensure that these tasks only attempt to update systems where the distribution matches the package manager we are using.
You're now setup with a great base for using Ansible to get things built out for automated management of systems and packages. We'll be using this in future videos in this series, so dig in, start watching and reading, and get comfortable with Ansible.
Series for learning Ansible that I suggest:
<iframe height="314" src="https://www.youtube.com/embed/3RiVKs8GHYQ?list=PLT98CRl2KxKEUHie1m24-wkyHpEsa4Y70&pp=iAQB" width="560"></iframe>
<div class="text-muted text-small" id="bkmrk--23"><div class="entity-meta">
</div></div>
# Semaphore - Ansible GUI
[https://semaphoreui.com/docs/](https://semaphoreui.com/docs/)
Semaphore UI is a modern, open-source web UI and API for running automation with **Ansible**, **Terraform/OpenTofu**, **PowerShell**, **Shell/Bash**, and **Python**.
Semaphore is written in **Go** (lightweight, fast) and runs on **Windows**, **macOS**, and **Linux**. It supports **SQLite**, **MySQL**, and **PostgreSQL**.
## Choose your path
- **Im installing or operating Semaphore (admins/operators)**
- Install: [Installation](https://semaphoreui.com/docs/admin-guide/installation)
- Configure: [Configuration](https://semaphoreui.com/docs/admin-guide/configuration)
- Secure: [Security](https://semaphoreui.com/docs/admin-guide/security)
- Auth: [LDAP](https://semaphoreui.com/docs/admin-guide/ldap) or [OpenID Connect](https://semaphoreui.com/docs/admin-guide/openid)
- Scale &amp; run remotely: [Runners](https://semaphoreui.com/docs/admin-guide/runners)
- Keep it healthy: [Logs](https://semaphoreui.com/docs/admin-guide/logs), [Upgrading](https://semaphoreui.com/docs/admin-guide/upgrading), [Troubleshooting](https://semaphoreui.com/docs/admin-guide/troubleshooting)
- Enterprise setups: [High availability](https://semaphoreui.com/docs/admin-guide/ha)
- **Im using Semaphore day-to-day (teams/users)**
- Organize work: [Projects](https://semaphoreui.com/docs/user-guide/projects) and [Teams](https://semaphoreui.com/docs/user-guide/team)
- Run automation: [Tasks](https://semaphoreui.com/docs/user-guide/tasks) and [Schedules](https://semaphoreui.com/docs/user-guide/schedules)
- Connect your code: [Repositories](https://semaphoreui.com/docs/user-guide/repositories)
- Targets and variables: [Inventory](https://semaphoreui.com/docs/user-guide/inventory) and [Variable Groups](https://semaphoreui.com/docs/user-guide/environment)
- Credentials: [Key Store](https://semaphoreui.com/docs/user-guide/key-store)
- Connect tools: [Integrations](https://semaphoreui.com/docs/user-guide/integrations)
- **Im here for a specific tool**
- [Ansible](https://semaphoreui.com/docs/user-guide/apps/ansible)
- [Terraform/OpenTofu](https://semaphoreui.com/docs/user-guide/apps/terraform)
- [Shell/Bash](https://semaphoreui.com/docs/user-guide/apps/bash)
- [PowerShell](https://semaphoreui.com/docs/user-guide/apps/powershell)
- [Python](https://semaphoreui.com/docs/user-guide/apps/python)
## First run checklist (from zero to first task)
Use this as a simple “happy path” to get productive quickly:
1. **Install Semaphore** using your preferred method: [Installation](https://semaphoreui.com/docs/admin-guide/installation)
2. **Run initial setup** (config + first admin user): [Interactive setup](https://semaphoreui.com/docs/admin-guide/configuration/cli)
3. **Create a project** to isolate work (teams, infra, apps): [Projects](https://semaphoreui.com/docs/user-guide/projects)
4. **Connect what Semaphore needs**
- Source: [Repositories](https://semaphoreui.com/docs/user-guide/repositories)
- Secrets/credentials: [Key Store](https://semaphoreui.com/docs/user-guide/key-store)
- Targets: [Inventory](https://semaphoreui.com/docs/user-guide/inventory)
- Variables: [Variable Groups](https://semaphoreui.com/docs/user-guide/environment)
5. **Create a task template and run it**
- App-specific guides: [Ansible](https://semaphoreui.com/docs/user-guide/apps/ansible), [Terraform/OpenTofu](https://semaphoreui.com/docs/user-guide/apps/terraform), [Shell/Bash](https://semaphoreui.com/docs/user-guide/apps/bash)
- Run and monitor: [Tasks](https://semaphoreui.com/docs/user-guide/tasks)
6. **Automate &amp; operationalize**
- Schedule runs: [Schedules](https://semaphoreui.com/docs/user-guide/schedules)
- Control access: [RBAC](https://semaphoreui.com/docs/user-guide/rbac)
- Get alerts: [Notifications](https://semaphoreui.com/docs/admin-guide/notifications)
## Docker Compose - Sample
```
services:
semaphore:
ports:
- 3300:3300
image: semaphoreui/semaphore:latest
container_name: semaphore
environment:
SEMAPHORE_DB_DIALECT: sqlite
SEMAPHORE_ADMIN: AdminName
SEMAPHORE_ADMIN_PASSWORD: LongDatabasePassword
SEMAPHORE_ADMIN_NAME: FullName
SEMAPHORE_ADMIN_EMAIL: EmailAddress@example.com
SEMAPHORE_PORT: "3300"
ANSIBLE_HOST_KEY_CHECKING: "False"
SEMAPHORE_ACCESS_KEY_ENCRYPTION: "VeryLongEncryptionPassword"
volumes:
- semaphore_data:/var/lib/semaphore
- semaphore_config:/etc/semaphore
- semaphore_tmp:/tmp/semaphore
networks:
- semaphore-net
volumes:
semaphore_data:
semaphore_config:
semaphore_tmp:
networks:
semaphore-net:
driver: bridge
```
## Key concepts (glossary)
If youre new, these terms show up everywhere in the UI:
- **Project**: the main unit of separation (teams/infrastructures/applications) — [Projects](https://semaphoreui.com/docs/user-guide/projects)
- **Repository**: where your playbooks/modules/scripts live — [Repositories](https://semaphoreui.com/docs/user-guide/repositories)
- **Inventory**: hosts/groups/connection settings for Ansible-style runs — [Inventory](https://semaphoreui.com/docs/user-guide/inventory)
- **Variable Group (Environment)**: reusable variables and configuration per project — [Variable Groups](https://semaphoreui.com/docs/user-guide/environment)
- **Key Store**: encrypted credentials (SSH keys, tokens, passwords) — [Key Store](https://semaphoreui.com/docs/user-guide/key-store)
- **Task / Task template**: the definition and the run of automation — [Tasks](https://semaphoreui.com/docs/user-guide/tasks)
- **Runner**: where tasks execute (local or remote) — [Runners](https://semaphoreui.com/docs/admin-guide/runners)
## Common workflows
- **CI/CD in Semaphore**: build, deploy, and rollback — [CI/CD](https://semaphoreui.com/docs/admin-guide/cicd)
- **Run at scale**: distribute execution using runners — [Runners](https://semaphoreui.com/docs/admin-guide/runners)
- **Programmatic automation**: integrate Semaphore into your pipelines — [API](https://semaphoreui.com/docs/admin-guide/api)
- **Manage via CLI**: setup, users, runners, migrations — [CLI](https://semaphoreui.com/docs/admin-guide/cli)
## Get help, report issues, or contribute
- **Help / community**: join the [Discord](https://discord.gg/5R6k7hNGcH)
- **Bug reports / feature requests**: open an issue on [GitHub Issues](https://github.com/semaphoreui/semaphore/issues)
- **Source code**: [GitHub](https://github.com/semaphoreui/semaphore)
## FAQ
If something isnt working as expected, start here: [Troubleshooting FAQ](https://semaphoreui.com/docs/faq/troubleshooting)
File diff suppressed because it is too large Load Diff
+93
View File
@@ -0,0 +1,93 @@
---
tags:
- Documentation
- Bookstack
- Notes
---
# ASUS Laptop
# Installing Keyboard LED
Ah, the output reveals exactly what's happening. OpenRGB is running in standalone mode and warning you about missing **udev rules**, which means it lacks the direct hardware permissions to hook into your Asus ROG laptop's internal SMBus/I2C controllers.
Because we are running this as a system startup task, the cleanest, most rock-solid approach is to completely sidestep OpenRGB and use the **native Linux kernel controls** (`sysfs`) that we found earlier. The kernel already has full root permissions and is running natively on your hardware without any extra utilities or udev rules required.
Let's test the native kernel interface directly. Run this command to see if your keyboard springs to life:
<div class="code-block ng-tns-c602925248-115 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" id="bkmrk-bash"><div class="formatted-code-block-internal-container ng-tns-c602925248-115"><div class="animated-opacity ng-tns-c602925248-115"><div class="code-block-decoration header-formatted gds-emphasized-body-m ng-tns-c602925248-115 ng-star-inserted"><span class="ng-tns-c602925248-115">Bash</span><div class="buttons ng-tns-c602925248-115 ng-star-inserted"></div></div></div></div></div>```
echo 3 | sudo tee /sys/class/leds/asus::kbd_backlight/brightness
```
<div class="code-block ng-tns-c602925248-115 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" id="bkmrk--1"><div class="formatted-code-block-internal-container ng-tns-c602925248-115"><div class="animated-opacity ng-tns-c602925248-115"></div></div></div>### Option A: If that turned your lights on (The Native Fix)
If the command above worked, we can make your startup service incredibly lightweight. We don't need OpenRGB or `rogauracore` at all.
1. Open your service file:
<div class="code-block ng-tns-c602925248-116 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation"><div class="formatted-code-block-internal-container ng-tns-c602925248-116"><div class="animated-opacity ng-tns-c602925248-116"><div class="code-block-decoration header-formatted gds-emphasized-body-m ng-tns-c602925248-116 ng-star-inserted"><span class="ng-tns-c602925248-116">Bash</span><div class="buttons ng-tns-c602925248-116 ng-star-inserted"></div></div></div></div></div>```
sudo nano /etc/systemd/system/keyboard-led.service
```
<div class="code-block ng-tns-c602925248-116 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation"><div class="formatted-code-block-internal-container ng-tns-c602925248-116"><div class="animated-opacity ng-tns-c602925248-116"></div></div></div>
2. Replace the entire contents with this clean shell execution:
<div class="code-block ng-tns-c602925248-117 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation"><div class="formatted-code-block-internal-container ng-tns-c602925248-117"><div class="animated-opacity ng-tns-c602925248-117"><div class="code-block-decoration header-formatted gds-emphasized-body-m ng-tns-c602925248-117 ng-star-inserted"><span class="ng-tns-c602925248-117">Ini, TOML</span><div class="buttons ng-tns-c602925248-117 ng-star-inserted"></div></div></div></div></div>```
[Unit]
Description=Asus ROG Keyboard LED Native Initialization
After=multi-user.target
[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/usr/bin/sh -c "echo 3 > /sys/class/leds/asus::kbd_backlight/brightness"
[Install]
WantedBy=multi-user.target
```
<div class="code-block ng-tns-c602925248-117 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation"><div class="formatted-code-block-internal-container ng-tns-c602925248-117"><div class="animated-opacity ng-tns-c602925248-117"></div></div></div>
3. Save, reload, and enable:
<div class="code-block ng-tns-c602925248-118 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation"><div class="formatted-code-block-internal-container ng-tns-c602925248-118"><div class="animated-opacity ng-tns-c602925248-118"><div class="code-block-decoration header-formatted gds-emphasized-body-m ng-tns-c602925248-118 ng-star-inserted"><span class="ng-tns-c602925248-118">Bash</span><div class="buttons ng-tns-c602925248-118 ng-star-inserted"></div></div></div></div></div>```
sudo systemctl daemon-reload
sudo systemctl reset-failed keyboard-led.service
sudo systemctl start keyboard-led.service
sudo systemctl enable keyboard-led.service
```
<div class="code-block ng-tns-c602925248-118 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation"><div class="formatted-code-block-internal-container ng-tns-c602925248-118"><div class="animated-opacity ng-tns-c602925248-118"></div></div></div>
### Option B: If you still want OpenRGB's specific color profiles
If you want to stick with OpenRGB (for instance, to set custom HEX colors or complex animations), we need to fix those `udev` rules so OpenRGB can talk to the hardware interface.
1. Download and install the official OpenRGB udev rules template:
<div class="code-block ng-tns-c602925248-119 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation"><div class="formatted-code-block-internal-container ng-tns-c602925248-119"><div class="animated-opacity ng-tns-c602925248-119"><div class="code-block-decoration header-formatted gds-emphasized-body-m ng-tns-c602925248-119 ng-star-inserted"><span class="ng-tns-c602925248-119">Bash</span><div class="buttons ng-tns-c602925248-119 ng-star-inserted"></div></div></div></div></div>```
sudo wget -O /etc/udev/rules.d/60-openrgb.rules https://gitlab.com/CalcProgrammer1/OpenRGB/-/raw/master/60-openrgb.rules
```
<div class="code-block ng-tns-c602925248-119 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation"><div class="formatted-code-block-internal-container ng-tns-c602925248-119"><div class="animated-opacity ng-tns-c602925248-119"></div></div></div>
2. Reload your system's device rules:
<div class="code-block ng-tns-c602925248-120 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation"><div class="formatted-code-block-internal-container ng-tns-c602925248-120"><div class="animated-opacity ng-tns-c602925248-120"><div class="code-block-decoration header-formatted gds-emphasized-body-m ng-tns-c602925248-120 ng-star-inserted"><span class="ng-tns-c602925248-120">Bash</span><div class="buttons ng-tns-c602925248-120 ng-star-inserted"></div></div></div></div></div>```
sudo udevadm control --reload-rules && sudo udevadm trigger
```
<div class="code-block ng-tns-c602925248-120 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation"><div class="formatted-code-block-internal-container ng-tns-c602925248-120"><div class="animated-opacity ng-tns-c602925248-120"></div></div></div>
3. Try running the OpenRGB command again to test:
<div class="code-block ng-tns-c602925248-121 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation"><div class="formatted-code-block-internal-container ng-tns-c602925248-121"><div class="animated-opacity ng-tns-c602925248-121"><div class="code-block-decoration header-formatted gds-emphasized-body-m ng-tns-c602925248-121 ng-star-inserted"><span class="ng-tns-c602925248-121">Bash</span><div class="buttons ng-tns-c602925248-121 ng-star-inserted"></div></div></div></div></div>```
sudo /usr/local/bin/openrgb --appimage-extract-and-run --device 0 --mode static --color 00FF00 --brightness 100
```
<div class="code-block ng-tns-c602925248-121 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation"><div class="formatted-code-block-internal-container ng-tns-c602925248-121"><div class="animated-opacity ng-tns-c602925248-121"></div></div></div>
If you prefer the simplicity of a working keyboard without extra dependencies, **Option A** is highly recommended!
+207
View File
@@ -0,0 +1,207 @@
---
tags:
- Documentation
- Bookstack
- Notes
---
# Authentik
# Install and Setup
<iframe height="336" src="https://www.youtube.com/embed/KlDJ4K45M_o" width="600"></iframe>
<p class="callout info">*This document and video was written and produced by Brian @ Awesome Open Source. Please support his channel and ongoing efforts through Patreon: [https://www.patreon.com/bePatron?u=234177](https://www.patreon.com/bePatron?u=234177)*</p>
## Introduction
As the internet and services have become more and more the norm in our society protecting our services with authentication has become ever more important as well. This is where amazing projects like Authentik, and Authelia come in. These solutions give you the opportunity to setup a Single Sign On system for all of your services. That means you just need to have one very secure login, and you can access any of the services you use everyday.
### What You'll Need
- Docker and Docker Compose Installed on a Host that you can access from the Internet
- A domain or sub-domain that you own and can set an A or CNAME Record for.
- NGinX Proxy Manager (or other reverse proxy of your choice)
- an SMTP Email Server
- About 30 minutes of your time
### Installation
#### Configure and Install Authentik
Let's create our folder structure. First, we want to create a parent 'docker' folder, and inside that place any / all of our application folders we may want to run on this host. In this case our application folder will be 'authentik'.
`mkdir -p docker/authentik`
Next, we'll move into our new folder and create our docker-compose.yml file. This file defines our application containers, and helps put them all into a private network on our host so the various parts of the overall application can communicate securely.
`nano docker-compose.yml`
Copy the block of yaml code from below, and paste it into the document we just opened. You can paste in the linux terminal by right clicking, and selecting paste, or by using CTRL + Shift + V.
<div id="bkmrk-services%3A-postgresql"><div class="cm-editor ͼ1 ͼ2 ͼ4 ͼ1p"><div class="cm-scroller" tabindex="-1"><div class="cm-gutters cm-gutters-before"><div class="cm-gutter cm-lineNumbers"><div class="cm-gutterElement"><div><div><div>---</div>
<div>services:</div><div> postgresql:</div><div> image: docker.io/library/postgres:16-alpine</div><div> restart: unless-stopped</div><div> container_name: authentik-db</div><div> healthcheck:</div><div> test: ["CMD-SHELL", "pg_isready -d $${POSTGRES_DB} -U $${POSTGRES_USER}"]</div><div> start_period: 20s</div><div> interval: 30s</div><div> retries: 5</div><div> timeout: 5s</div><div> volumes:</div><div> - ./database:/var/lib/postgresql/data</div><div> environment:</div><div> POSTGRES_PASSWORD: ${PG_PASS:?database password required}</div><div> POSTGRES_USER: ${PG_USER:-authentik}</div><div> POSTGRES_DB: ${PG_DB:-authentik}</div><div> env_file:</div><div> - .env</div><div> networks:</div><div> - authentik</div>
<div> redis:</div><div> image: docker.io/library/redis:alpine</div><div> command: --save 60 1 --loglevel warning</div><div> restart: unless-stopped</div><div> container_name: authentik-redis</div><div> healthcheck:</div><div> test: ["CMD-SHELL", "redis-cli ping | grep PONG"]</div><div> start_period: 20s</div><div> interval: 30s</div><div> retries: 5</div><div> timeout: 3s</div><div> volumes:</div><div> - ./redis:/data</div><div> networks:</div><div> - authentik</div>
<div> server:</div><div> image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2025.8.1}</div><div> restart: unless-stopped</div><div> container_name: authentik-server</div><div> command: server</div><div> environment:</div><div> AUTHENTIK_REDIS__HOST: redis</div><div> AUTHENTIK_POSTGRESQL__HOST: postgresql</div><div> AUTHENTIK_POSTGRESQL__USER: ${PG_USER:-authentik}</div><div> AUTHENTIK_POSTGRESQL__NAME: ${PG_DB:-authentik}</div><div> AUTHENTIK_POSTGRESQL__PASSWORD: ${PG_PASS}</div><div> volumes:</div><div> - ./media:/media</div><div> - ./custom-templates:/templates</div><div> env_file:</div><div> - .env</div><div> ports:</div><div> - "${COMPOSE_PORT_HTTP:-9000}:9000"</div><div> - "${COMPOSE_PORT_HTTPS:-9443}:9443"</div><div> depends_on:</div><div> - postgresql</div><div> - redis</div><div> networks:</div><div> - authentik</div>
<div> worker:</div><div> image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2025.8.1}</div><div> restart: unless-stopped</div><div> container_name: authentik-worker</div><div> command: worker</div><div> environment:</div><div> AUTHENTIK_REDIS__HOST: redis</div><div> AUTHENTIK_POSTGRESQL__HOST: postgresql</div><div> AUTHENTIK_POSTGRESQL__USER: ${PG_USER:-authentik}</div><div> AUTHENTIK_POSTGRESQL__NAME: ${PG_DB:-authentik}</div><div> AUTHENTIK_POSTGRESQL__PASSWORD: ${PG_PASS}</div><div> # `user: root` and the docker socket volume are optional.</div><div> # See more for the docker socket integration here:</div><div> # https://goauthentik.io/docs/outposts/integrations/docker</div><div> # Removing `user: root` also prevents the worker from fixing the permissions</div><div> # on the mounted folders, so when removing this make sure the folders have the correct UID/GID</div><div> # (1000:1000 by default)</div><div> user: root</div><div> volumes:</div><div> - /var/run/docker.sock:/var/run/docker.sock</div><div> - ./media:/media</div><div> - ./certs:/certs</div><div> - ./custom-templates:/templates</div><div> env_file:</div><div> - .env</div><div> depends_on:</div><div> - postgresql</div><div> - redis</div><div> networks:</div><div> - authentik</div>
<div>networks:</div><div> authentik:</div><div> external: true</div>
</div></div>
</div></div></div></div></div></div><p class="callout warning">NOTE: In the above, if you used it in the past, I have adjusted it to remove (comment out) one line which said `user: root` based on errors after an upgrade to 2025.8.2. Many people had the same error, and this was determined to be the cause.</p>
Once you've pasted in the code, save the file with CTRL + O, then press Enter to confirm, and exit the nano editor with CTRL + X.
Next we need to create an environment variable file that the docker-compose.yml file will read. This file allows us to customize our variables for the container setup without having to repeatedly enter like values throughout the docker-compose file.
`nano .env`
<p class="callout info">Note: The period in front of the filename. In unix based systems a filename starting with a period is a hidden file, and will not be shown with commands like `ls` alone. Instead you must use the flag `-a` (all) to show everything in a folder including hidden files, like this `ls -a`.</p>
Once open, copy the file contents below, and paste them into the .env file.
<div id="bkmrk-pg_user%3Dauthentik-pg"><div class="cm-editor ͼ1 ͼ2 ͼ4 ͼ1q"><div class="cm-scroller" tabindex="-1"><div class="cm-gutters cm-gutters-before"><div class="cm-gutter cm-lineNumbers"><div class="cm-gutterElement"><div><div>\#For a fresh authentik installation, you need to generate a password and a secret key.</div></div></div><div class="cm-gutterElement"><span style="font-family:'Lucida Console', 'DejaVu Sans Mono', 'Ubuntu Mono', Monaco, monospace;">PG\_USER=authentik</span></div></div></div><div class="cm-content"><div class="cm-line">PG_PASS=aReallyLongStrongPasswordShouldBePutHere</div><div class="cm-line"><div><div>
</div><div>\#Enable error reporting</div><div>AUTHENTIK_ERROR_REPORTING__ENABLED=true</div></div></div><div class="cm-line">
</div><div class="cm-line">AUTHENTIK_SECRET_KEY=someincrediblylongcomplexkeygoeshere</div><div class="cm-line">
</div><div class="cm-line">\# SMTP Host Emails are sent to</div><div class="cm-line">AUTHENTIK_EMAIL__HOST=smtp.example.com</div><div class="cm-line">AUTHENTIK_EMAIL__PORT=587</div><div class="cm-line">
</div><div class="cm-line">\# Optionally authenticate (don't add quotation marks to your password)</div><div class="cm-line">AUTHENTIK_EMAIL__USERNAME=auth@example.com</div><div class="cm-line">AUTHENTIK_EMAIL__PASSWORD=a-L0n6-Strong_password_should_go_here</div><div class="cm-line">
</div><div class="cm-line">\# Use StartTLS</div><div class="cm-line">AUTHENTIK_EMAIL__USE_TLS=true</div><div class="cm-line">
</div><div class="cm-line">\# Use SSL</div><div class="cm-line">AUTHENTIK_EMAIL__USE_SSL=false</div><div class="cm-line">AUTHENTIK_EMAIL__TIMEOUT=10</div><div class="cm-line">
</div><div class="cm-line">\# Email address authentik will send from, should have a correct @domain</div><div class="cm-line"><div><div>AUTHENTIK_EMAIL__FROM=admn@example.com</div></div></div><div class="cm-line"><div><div>
</div><div>\# Authentik listens on port 9000 for HTTP and 9443 for HTTPS. To change the exposed ports change these values</div></div></div><div class="cm-line">COMPOSE_PORT_HTTP=80</div><div class="cm-line">COMPOSE_PORT_HTTPS=443</div><div class="cm-line">
</div><div class="cm-line">\# Authentik Version to Pull</div><div class="cm-line">ATHENTIK_TAG=2025.6.3</div></div><div class="cm-layer cm-layer-above cm-cursorLayer">
</div><div class="cm-layer cm-selectionLayer">
</div></div></div></div>I have intentionally added placeholders to most of the values. You'll want to go through and update these placeholders to be actual values for your installation. The values you must change at a minimum are:
PG\_PASS - This value can be any long, strong password you want.
AUTHENTIK\_SECRET\_KEY - This values should be a long string of numbers, letters (upper and lower case), and symbols at least 64 characters in length.
You should additionally setup the SMTP email options as this is a major part of user management and self-service in any authentication provider, such as when a user needs to reset his / her password, MFA device, register (if allowed). It's also how the Authentik install will send you information about events, updates, etc.
Finally, for the COMPOSE\_PORT\_HTTP and COMPOSE\_PORT\_HTTPS you may want to change these to be ports that aren't quite so common. If your host is also running NGINX Proxy Manager you should definitely change these to less common ports, as 80 and 443 are already in use by NPM.
Once you've updated the values appropriately, you can save and close the file with CTRL + O, then Enter to confirm, and then CTRL + X.
Now you are ready to bring up your Authentik application. Use the commands:
`docker compose up -d && docker compose logs -f`
The first part tells docker to get the necessary images and start the containers running in the background, and the second part tells docker once the containers are up, show us the logs.
You can discontinue the logs with CTRL + C.
Now navigate to the IP address of your host machine, and the port you set for the non SSL (HTTP) access in the .env file. You should see the Authentik login page. If so, then you are doing well. Next, setup the reverse proxy.
## Reverse Proxy Setup
Login to NGinX Proxy Manager (NPM) and click into the Proxy Hosts section. Select Add Proxy Host from the upper right, and int he modal (pop-up) window that opens, we'll begin adding the information needed to get our domain name to resolve to our new server.
In the domain name field, enter your desired domain name. I used authentik.mydomain.com.
I own the domain mydomain.com' have setup an A-record in DNS on the domain that will point the domain name to my public IP address.
Next, enter the private IP of your Authentik server. You can use localhost if the Authentik server is running on the machine you are running NPM on. Next, enter the port number you entered in the .env file. If you didn't change it, it will be 80.
Enable the options for Block Common Exploits and Websocket Support.
Now move to the SSL tab, and select “Request a New Certificate” from the drop-down box.
Enable the options for Force SSL, HTTP/2 Support, and both HSTS options.
Enter your email address in the Email field, and enable the Agree to Terms of Service option.
Click Save. If all is setup properly, the modal window will simply go away after a few seconds (maybe 30). Then you'll have a CA Certified LetsEncrypt certificate for your Authentik server.
You should now be able to get to your Authentik install using the FQDN (fully qualified domain name).
## Configure
To create your first (admin) user, you need to go to your domain at a special address.
[https://authentik.yourdomain.com/if/flow/initial-setup/](https://authentik.yourdomain.com/if/flow/initial-setup/)
Of course, use your actual domain name.
Enter your preferred email, and learn from my mistake and make sure it's correct before moving on. Next enter a long, strong password, then enter it again to confirm it. I cannot stress enough, you should absolutely use a password manager for keeping and helping you create long, strong passwords. I highly recommend Bitwarden, and Vaultwarden if you prefer to self host.
Click Create Account, and you should be logged in as an administrative user.
## Proxy Login
Make sure you have an outpost setup, and setup properly. We can use the authentik embedded outpost in this case.
### Make Sure Outpost is set Correctly
Click on Outposts on the left side menu, then click the edit icon in the list of outposts. if this is a new install you likely only have one outpost at this point.
In the pop-up window that opens, verify that your authentik\_host has the same URL as your Authentik site. If you are using [https://auth.my-great-domain.com](https://auth.my-great-domain.com/) to reach your Authentik install, then you want this value to be the same.
You can now dismiss the pop-up if everything looks good. Additionally, in the outposts list, you should see a green check mark under health and version.
### Add a Provider
Next we need to add a provider for our setup.
Click on Providers in the left side menu.
In this view, click on Create at the top.
Again, when the pop-up window opens, select Proxy Provider, then click Next.
On the next page, enter a name that identifies the application you are creating a proxy authenticator for. The Proxy authentication is useful for applications and services you run that don't provide authentication in the app, but that you might like to expose to the internet. For instance, a dashboard, speedtest, etc.
Choose Authorize Application from the Authentication Flow drop down.
Next, what you select will depend on how you are proxying your service traffic to your applications and service. If you are using a reverse proxy like NGinX Proxy Manager, Caddy, Traefik, etc, then you'll want to choose Forward Auth (single application). If, however, you don't yet have a reverse proxy setup, then you'll potentially want to use the Proxy option, which then turns Authentik into a reverse proxy for the site as well.
In our case we'll go with Forward Auth (single application).
Now fill in your sites externally available FQDN (fully qualified domain name), for instance [https://mydash.example.com](https://mydash.example.com/)
You can change Token Validity to any timeframe you wish, but leaving it at 24 hours should be fine.
Click Finish.
You should be returned to your Provider list, and you should see the provider you just created. You'll likely have a warning in the list that the provider is not associated to any applications. No worries, we'll fix this right now.
### Add an Application Entry for the Provider
In the left side menu click on Applications.
On the Applications page, click the Create button at the top, and you'll be presented with a pop-up window (modal window) where you need to fill in your application information.
Give your application a name that helps you easily identify the application. If you are creating an authentication for your dashboard, then call it Dashboard for instance. As you fill in the Name field, you'll notice that the slug field is automatically filled in. The slug should not be changed unless you have a reason to do so, and the slug should always be lowercase, and not have spaces in it.
Now move down to the Provider field, and select the provider you just created.
When creating these types of authentication flows, you always want to create a new provider, and a matching application entry for that provider, then select the provider for that application.
Finally, click the Create button at the bottom of the modal window.
### Ensure the Provider is now Satisfied with the Application Entry
Navigate back to your Providers list on the left, and notice that our provider no longer shows the warning about not being associated to an application.
### Set the Application in Outposts
We are almost there. Navigate back to Outposts, and click the edit icon next to our outpost. In the modal window, next to the Applications label, you should now see your application listed. You will click on this line in the field to select the application.
Click the Update button at the bottom of the modal window. You should now see the application name listed under the Providers column for the outpost. As you add more applications and providers, you'll see them added for any outpost you add them to. In this case, you can use this same outpost for multiple applications and providers needing a simple Forward Auth setup.
### Get your Reverse Proxy Snippet
Finally, navigate back to Providers on the left side menu, and click the Name of your provider. This will show the Provider details in a new page. Scroll down, and notice various reverse proxy options are shown as tabs. Select the reverse proxy you are using, and you'll see a snippet of code that you'll use to setup your reverse proxy entry so it will start using Authentik before the application will load.
In our case, we've used NGinX Proxy Manager, so I'll click that tab, and copy that bit of code.
I'll open NGinX Proxy Manager and select the 3-dot icon on the row for my application, then select Edit.
Move to the Advanced tab in the modal window, and paste in the code snippet.
In the pasted snippet, scroll down to the line for proxy\_pass, and change the FQDN for your Authentik instance to its internal IP address and port number.
NOTE: This is only done if you are running NGinX Proxy Manager, Authentik, and your Application on the same local area network.
In my case I change authentik.routemehome.org to 192.168.10.42.
Click Save.
If you now try to load your application, you should be prompted to login with Authentik. Verify you can login using your credentials, and you'd now setup.
File diff suppressed because one or more lines are too long
+196
View File
@@ -0,0 +1,196 @@
---
tags:
- Documentation
- Bookstack
- Notes
---
# CheckMK
# Open Source Network, Server, and Machine Monitoring
CheckMK is a network and systems monitoring solution that can span from a small home user's needs into the enterprise with ease. There are many of these solutions out there, and all of them have their pros and cons, but for many of them, the con is that they are complicated to setup, maintain, and keep running.
Thus far, this is where CheckMK seems to be a little different. The setup is pretty straight forward, their documentation is outstanding, and the maintenance of the system seems to be quite easy.
If you've been looking for a monitoring solution for your various devices and networks, then this may just be the solution for you. As always, CheckMK is open source, and available in a free (community / raw) version, but the open source software is supported by the option to have more functionality / capability with their professional and enterprise level offerings as well. So, if you like CheckMK, and think it would be a good fit for your buisness, consider contributin to open source by giving them some business with their paid tiers as well.
## What You'll Need
- Either a Server (I Used and LXC Container on ProxMox) or Docker and Docker-Compose
- If you want to use this across the cloud, then you'll also want a VPN between your various networks, or a domain name that points to the public IP of the network where you'll run CheckMK, and a reverse proxy like NGinX-Proxy-Manager.
- About 20 minutes of your time to get started.
## Installation
In order to install CheckMK on Docker, jump down to the "Instlaling On Docker" section below. If you are installing on a regular Linux based server, then keep reading.
There are a pretty basic set of steps to get this installed actually. I used Ubuntu, but if you are using a different base distro, like Fedora, Cnetos, etc, then you can check [their instructions here](https://docs.checkmk.com/latest/en/install_packages.html).
#### Installing on Ubuntu
Make sure you're logged in with a non-root user that has sudo privileges. If you don't know what this means, essentially, make a new user who's not root, then give that user sudo privileges by adding them to the sudo group.
`adduser < your user name >`
Enter the password, and re-type it when prompted.
After completing the `adduser` portion, add the user to the "sudo" group with:
`usermod -aG sudo < your user name >`
Now logout from the root account, and login with your new user account.
If you need to run something with elevated privileges, just put `sudo` in front of the command. You'll be prompted for your user's password occasionally in order to run anything as "sudo".
To find the version for your distro and release (mine is Ubuntu 20.04 LTS), gotto [https://checkmk.com/de/download](https://checkmk.com/de/download) and select through the options down the page to filter down to your needs.
!\[\]([http://shownotes.opensourceisawesome.com/content/images/2022/07/image.png](http://shownotes.opensourceisawesome.com/content/images/2022/07/image.png))
Below that, you'll find a "wget" command, which is perfect for downloading a package to your server directly when logged in via SSH.
In my case the command is:
`wget https://download.checkmk.com/checkmk/2.1.0p8/check-mk-raw-2.1.0p8_0.focal_amd64.deb`
Once downloaded, we'll install it using the command:
`sudo apt install ./check-mk-raw-2.1.0p8_0.focal_amd64.deb`
Let the installer run, and you should get some output toward the end showing that the system is installed. Afterward, check that it's installed by running:
`omd version`
You should get a version number for the CheckMK you just installed.
Next, you need to create a "Monitoring" site. You can name the site anything, but we'll stick with what their documentation says, and call it "monitoring":
`omd create monitoring`
Note, you may need `sudo` for this step.
Once the monitoring site is created, you'll get a default user of `cmkadmin`, and a password that is autogenerated. Make sure to copy the password somewher so you don't lose it. You can change it via the web ui later.
Now, we need to start our site into a running state.
`omd start monitoring`
Again, you may need to use `sudo` in front of that command.
You should see output similar to this:
```
Starting mkeventd...OK
Starting liveproxyd...OK
Starting mknotifyd...OK
Starting rrdcached...OK
Starting cmc...OK
Starting apache...OK
Starting dcd...OK
Starting redis...OK
Initializing Crontab...OK
```
You should now be able to access your CheckMK server via your favorite modern web browser at the IP address of your host system, and the location /cmk:
`http://192.168.10.42/cmk` was the address I used.
### Installing on Docker
If you are like me, and you prefer to containerize anything and everything due to the simplicity of upkeep, updates, and maintenance, then you'll be more interested in running CheckMK in docker. I went through their instructions, and took a bit from here and there, and decied I wanted to create a nice docker-compose file instead of using their docker run, so that'what we'll be using. Before that, a quick section on installing Docker and Docker-Compose if you don't already have it. If you do, then skip down to the 'Installing CheckMK in Docker' secton below.
### Installing Docker-CE and Docker-Compose
If you already have Docker and Docker-Compose installed, feel free to skip down to the next section.
You may want to install some pre-requisite softwre as well:
Debian / Ubuntu
`sudo apt install git curl wget`
Fedora / Redhat
`dnf install git curl wget`
Arch
`sudo pacman -Sy git curl wget`
You can easily install Docker-CE, Docker-Compose, Portainer-CE, and NGinX Proxy manager by using this quick install script I created and maintain on Github. Just use the command:
`wget <a href="https://gitlab.com/bmcgonag/docker_installs/-/raw/main/install_docker_nproxyman.sh">https://gitlab.com/bmcgonag/docker_installs/-/raw/main/install_docker_nproxyman.sh</a>`
To download the script to your desired host.
Change the permissios to make the script executable:
`chmod +x ./install_docker_nproxyman.sh`
and then run the script with the command:
`./install_docker_nproxyman.sh`
When run, the script will prompt you to select your host operating system, then will ask you which bits of software you want to install.
Simply enter 'y' for each thing you want to install.
For instance, you may want to answer 'y' to NGinX Proxy Manager, and Portainer-CE if you don't already use these in your system.
At some point, you'll be asked for your super user (sudo) password as well.
Allow the script to complete installation.
At this point, you might want to log out and back in, as this will allow you to use the `docker` and `docker-compose` commands without the need of `sudo` in front of them.
### Installing CheckMK on Docker
I like to keep all of my docker containers in a certain folder structure. Make a "docker" folder, then inside that make a new "checkmk" folder.
`mkdir -p docker/checkmk`
Next, move into the checkmk folder we just created, and make a new file called "docker-compose.yml"
`cd docker/checkmk`
`nano docker-compose.yml`
Now paste the contents of the code-block below into that file:
```
version: '3.3'
services:
check-mk-raw:
ports:
- '8080:5000'
tmpfs: '/opt/omd/sites/cmk/tmp:uid=1000,gid=1000'
volumes:
- './monitoring:/omd/sites'
- '/etc/localtime:/etc/localtime:ro'
container_name: monitoring
restart: always
image: 'checkmk/check-mk-raw:2.0.0-latest'
```
You may want to change the left side of the port mapping in the file from 8080 to another port if 8080 is already in use on your host machine. Remember to only change the left side, leave the 5000 alone.
When done, save the file with CTRL + O, press Enter to confirm, and then exit the nano text editor with CTRL + X.
Now, we'll pull down CheckMK and start the container with the command:
`docker-compose up -d && docker-compose logs -f`
This command starts the container running first, then shows us log outpu as the container is started. We can watch for any startup errors.
Additionally, by watching the logs, we can see the admin username `cmkadmin` and the default password create for our admin user in the logging. We'll need this to login for the first time.
As long as htere are no errors you can get out of the logs view with CTRL + C.
Now, go to your host machine's IP and port 8080 (unless you changed it in the docker-compose file above, then use the port you set).
I used `http://192.168.10.112:8080`.
Now log in, and get ready to setup your Folders and host machines.
For more on how to setup a host machine (client) and the folder structure see the CheckMK docs as well as the video linked at this top of this post.
+110
View File
@@ -0,0 +1,110 @@
---
tags:
- Documentation
- Bookstack
- Notes
---
# Chezmoi Guide
# Guide
**chezmoi** is a powerful, go-anywhere tool for managing your dotfiles across multiple machines. Unlike simple symlinking, it treats your configuration as a source-controlled project, allowing you to manage secrets, use templates for different OSs, and keep everything in a Git repository.
Now, just remember to always edit your dotfiles templates. Chezmoi give you some helpers:
chezmoi cd # will cd you to the dotfiles repo directory to edit files, or use;
chezmoi edit ~/.zshrc # will open the template in your editor
Whenever you change the template or the data file, just update everything:
chezmoi update
push the changes to your repo:
chezmoi cd
git add .
git commit -m "Update dotfiles"
git push
If you create new dotfiles, let's say you started to use Fish, then don't forget to add it to Chezmoi like this:
chezmoi add --autotemplate ~/.fishrc
You can use the convenience script to install the dotfiles on any machine with a single command. Simply run the following command in your terminal:
export GITHUB\\\_USERNAME=mmcfetridge1969
sh -c "$(curl -fsLS get.chezmoi.io)" -- init --apply $GITHUB\\\_USERNAME
Apply will install all the dependencies and add files to your $HOME.
chezmoi apply
Update - From time to time, start the update simply with:
chezmoi diff
chezmoi update
## 1. Getting Started
To begin, youll need to initialize your local state. This creates a hidden directory (usually `~/.local/share/chezmoi`) where the "source" versions of your files live.
- **Initialize:** `chezmoi init`
- **Add a file:** `chezmoi add ~/.bashrc`
- *This moves the file's logic into the source directory and leaves the original file in your home folder untouched.*
- **Edit a file:** `chezmoi edit ~/.bashrc`
- *This opens the source version in your default editor ($EDITOR).*
## 2. The Core Workflow
Once you have added files, you need to manage the synchronization between your **source state** (the repo) and your **destination state** (your home directory).
<table id="bkmrk-command-action-chezm"><thead><tr><td>**Command**</td><td>**Action**</td></tr></thead><tbody><tr><td><span>`chezmoi diff`</span></td><td><span>See changes between your source state and your actual home files.</span></td></tr><tr><td><span>`chezmoi apply`</span></td><td><span>Push changes from your source state to your home directory.</span></td></tr><tr><td><span>`chezmoi cd`</span></td><td><span>Launch a shell in the source directory (great for Git commits).</span></td></tr><tr><td><span>`chezmoi update`</span></td><td><span>Pulls the latest changes from your repo and applies them in one go.</span></td></tr></tbody></table>
## 3. Using Templates
One of chezmoi's best features is the ability to use **text/template** logic. This allows one `.zshrc` file to work differently on macOS than it does on Linux.
1. **Turn a file into a template:**
`chezmoi add --template ~/.zshrc` (or rename it manually in the source dir to `dot_zshrc.tmpl`).
2. **Add Logic:**
Inside the file, you can use snippets like:
<div class="code-block ng-tns-c2069566202-501 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation"><div class="formatted-code-block-internal-container ng-tns-c2069566202-501"><div class="animated-opacity ng-tns-c2069566202-501"><div class="code-block-decoration header-formatted gds-emphasized-body-m ng-tns-c2069566202-501 ng-star-inserted"><span class="ng-tns-c2069566202-501">Bash</span><div class="buttons ng-tns-c2069566202-501 ng-star-inserted"></div></div></div></div></div>```
{{ if eq .chezmoi.os "darwin" }}
alias ls='ls -G'
{{ else }}
alias ls='ls --color=auto'
{{ end }}
```
<div class="code-block ng-tns-c2069566202-501 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation"><div class="formatted-code-block-internal-container ng-tns-c2069566202-501"><div class="animated-opacity ng-tns-c2069566202-501"></div></div></div>
## 4. Managing Secrets
Never hardcode API keys or passwords in your dotfiles. Chezmoi integrates natively with password managers like **1Password, Bitwarden, KeepassXC, and LastPass**.
- **Example (Bitwarden):**
`{{ (bitwarden "item" "my-api-key").notes }}`
- **Keep it Private:** When you run `chezmoi apply`, it fetches the secret and injects it into the destination file without ever storing the secret in your Git repo.
## 5. Syncing to a New Machine
To set up a brand new computer with all your settings in seconds:
1. **Install chezmoi.**
2. **Run the init command with your repo URL:**
`chezmoi init https://github.com/username/dotfiles.git`
3. **Review and Apply:**
`chezmoi diff` (to check)
`chezmoi apply` (to execute)
> \[!TIP\]
>
> Use `chezmoi status` to see a quick summary of which files have changed and are waiting to be managed or updated.
+605
View File
@@ -0,0 +1,605 @@
---
tags:
- Documentation
- Bookstack
- Notes
---
# Dashboards
# Dashy - Powerful, Informative, Configurable Self-Hosting Dashboard
<iframe height="336" src="https://www.youtube.com/embed/QsQUzutGarA" width="600"></iframe>
<p class="callout info">*This document and video was written and produced by Brian @ Awesome Open Source. Please support his channel and ongoing efforts through Patreon: [https://www.patreon.com/bePatron?u=234177](https://www.patreon.com/bePatron?u=234177)*</p>
Along the same lines as Homer, Heimdall, and Monitorr; I wanted to continue our look into personal web dashboards. I've posted about those few, and talked about others as well.
Sometimes the question comes up, and it's a valid one, "Why would I use this over the bookmarks tooldbar in (Chrome, firfox, etc)?"
The thing these dashboards give you, is a much lovelier UI, but also many of them provide some extra information. Heimdall and Homer can be setup to provide details about Pi-hole, qBittorrent, Sonarr, etc. Dashy gives you up / down indications at a glance, and as it's an active project, will hopefully get some more status features moving forward.
The one thing I really like about Dashy is it's various methods for configuration. You can configure it through the terminal directly in the configuration file, or you can go through the User Interface with a nicely laid out configuration tool, an interactive (WYSIWYG) configuration editor, and / or just update the .yml right there in the browser window.
For me, a person who updates their dashboard semi-regularly, it's a nice convenience to not have to leave the Web User Interface and SSH into another machine to make changes / updates.
## What You'll Need
<div dir="auto" id="bkmrk-docker-ce-docker-com">- Docker-CE
- Docker-Compose
- (Optional) NGinX Proxy Manager
- (Optional) Portainer-CE
- About 10 minutes of your time (not including adding items to the Dashboard)
</div>## Installation
[Check out this video on installing Docker, Docker-Compose, NGinX Proxy Manager, and Portainer-CE](https://www.youtube.com/watch?v=TdEKVPWbC58) with a single script in under 5 minutes.
For organizational purposes, you should run your docker containers (docker or docker-compose) from a folder called docker. Inside that folder you should create sub-folders for each application you run. So, inside the "docker" folder, we'll create a new folder called "dashy".
`cd docker`
`mkdir dashy`
`cd dashy`
Now, we want to make a couple of sub-folders inside of our new "dashy" folder. They'll be called "public" and "icons".
`mkdir {public,icons}`
NOTE: You can create your "dashy" sub-folder, and your "public" and "icons" sub-folders in a single command with:
`mkdir -p dashy/{public,icons}`
You can do a quick listing of your "dashy" directory with the command:
`ls`
Mkae sure both folders show up.
Now we'll create a simple text file called "docker-run.txt"
`nano docker-run.txt`
Inside of the file, you'll want to paste the code block below, and then we'll make any necessary modifications for your system.
```
docker run -d \
-p 8295:8080 \
--volume </path/to/your>/docker/dashy/public/conf.yml:/app/public/conf.yml \
--volume </path/to/your>/docker/dashy/icons:/app/public/item-icons/icons \
--name dashy \
--restart=unless-stopped \
lissy93/dashy:latest
```
or you can use this docker compose file.
```yaml
name: dashy
services:
dashy:
ports:
- 8295:8080
volumes:
- </path/to/your>/docker/dashy/public/conf.yml:/app/public/conf.yml
- </path/to/your>/docker/dashy/icons:/app/public/item-icons/icons
container_name: dashy
restart: unless-stopped
image: lissy93/dashy:latest
```
and save it as "docker-compose.yml".
Now, we'll make a couple of modifications as needed. First, if your host machine has port 8290 in use, change the port on the left side of the colon ':' to one that is not in use on your host.
Next, change the portion in the two volume mappings with '&lt; &gt;' around it to be the proper path of your docker folder.
In my case I have
`/home/brian/docker/dashy/public/conf.yml`
and
`/home/brian/docker/dashy/public/icons`
Again, only change the left side of the colon.
Now, save the file with CTRL+O, then press Enter to confirm, and exit the nano editor with CTRL+X.
### Our Initial Configuration File
For us to start with a fairly clean Dashy install, we'll want to use a fairly small conf.yml file.
So make a conf.yml text file in the public sub-folder with the command:
`nano public/conf.yml`
Inside this file, you'll paste the following code block:
```
appConfig:
theme: colorful
layout: auto
iconSize: medium
language: en
pageInfo:
title: Home Lab
description: Welcome to your Home Lab!
navLinks:
- title: GitHub
path: https://github.com/Lissy93/dashy
- title: Documentation
path: https://dashy.to/docs
footerText: ''
sections:
- name: Starter Only
icon: fas fa-server
items:
- title: Google
description: Search
url: https://google.com
```
Now, we'll save this file with CTRL+O, press Enter to confirm, and use CTRL+X to exit the nano editor.
### Authentication
If you want to add some Authentication on top of Dashy, I highly recommend Authelia, but there is a built in authentication piece as well.
You can modify the above block as follows:
```
appConfig:
theme: colorful
layout: auto
iconSize: medium
language: en
auth:
users:
- user: your-preferred-username
hash: hash-of-a-password-you-choose-using-sha256-hashing
type: admin
pageInfo:
title: Home Lab
description: Welcome to your Home Lab!
navLinks:
- title: GitHub
path: https://github.com/Lissy93/dashy
- title: Documentation
path: https://dashy.to/docs
footerText: ''
sections:
- name: Starter Only
icon: fas fa-server
items:
- title: Google
description: Search
url: https://google.com
```
### Getting Icons for your Dashboard
We'll be pulling a really great github repo down that has tons of icons for self-hosted applicationis, adn this just really pulls together any dashboard, regardless of which one you use.
So, move into the "icons" sub-folder we create earlier, and use the command:
`git clone <a href="https://github.com/walkxcode/dashboard-icons.git">https://github.com/walkxcode/dashboard-icons.git</a>`
Clone the github repository.
Once pulled down, do an `ls` and you'll see a new folder called "dashboard-icons". Inside that you'll find several folders, but you'll likely be most interested in the "png" folder, which holds the png files for all of the icons in the repository.
Now, move back one step into your "dashy" folder with
`cd ..`
### Pull and Run Dashy
Let's get our `docker run` command by running the command:
`cat docker-run.txt`
This will list out your docker-run command in the terminal. Highlight it, copy it, and paste it into the waiting terminal prompt. Press Enter, and docker will pull down the latest dashy image, and start it running using our starter conf.yml file.
Once it runs, give it about 1 minute, then go to your browser and enter the host machine's IP address, and enter the port you set on the left side of the port mapping in the docker run command.
For instance, my host is at 192.168.10.26, and I used port 8295, so I went to
`http://192.168.10.26:8295`
If all went according to plan, you should see your Dashy starter page load up.
Now you can start configuring, theming, and making your own special dashy dashboard page. Check out the video for more on how to navigate the Dashy User Interface, and how to configure your ultimate dashboard!
# Adding Widgets to the Dashy Dashboard
<iframe height="314" src="https://www.youtube.com/embed/dyur-NDngBc" width="560"></iframe>
<p class="callout info">*This document and video was written and produced by Brian @ Awesome Open Source. Please support his channel and ongoing efforts through Patreon: [https://www.patreon.com/bePatron?u=234177](https://www.patreon.com/bePatron?u=234177)*</p>
I showed you how to setup and use a really nice homepage / dashboard for all of your self hosted services a while back called Dashy. I've stuck with it since then, and have just been super happy with it. It has active development, and tons of new features since then. One of those features is the ability to add all kinds of other widgets to the dashy interface.
Many of you have asked me how to add those widgets, so here we go.
Depending on what you're trying to view / see in your dashboard, you may need to install another bit of software on your server to provide the information for the dashboard to show. In my case, I'm going to walk you quickly through installing Glances, a really cool application that can provide you all kinds of data about your system. You can view it directly in the terminal / cli, or it can be presented as a web page (which is what we'll be using today).
I have a [video on Glances and NetData](https://www.youtube.com/watch?v=EI81Dyi04_8) that I'll link here as well for you to check out.
### What You'll Need
<div dir="auto" id="bkmrk-dashy-installed-and-">- Dashy Installed and Ready to go - [I have a video on it here](https://www.youtube.com/watch?v=QsQUzutGarA), if you want to go through that first and get it installed.
- Glances running as a web server and background service (we'll go through that next)
- About 15 minutes of your time.
</div>## Installing Glances
You need to have python3 and pip3 installed. So,d epending on your distro, you may need to use a different package manager for this, than I do.
I'm using Ubuntu 20.04, so I'll be using the apt package manger. If you're running Debian / Ubuntu based distros, the commands should work for you as is.
If you're using Fedora, RedHat, or Centos (Alma, Rocky), you'll probably want to use Yum, RPM, or DNF. For Open Suse, you'll want to use Zypper, and for Arch, Pacman or PacAUR I'm guessing.
### Install Python3
Open a terminal (CLI) window, and do the following: First make sure you have the lates package updates.
`sudo apt update`
Enter your super user password if prompted. If you're running Debian as root, you won't need the `sudo` part, just leave it off.
Next, we'll install python3 with:
`sudo apt install python3 -y`
After that completes, we'll install pip3 with:
`sudo apt install python3-pip`
Now that those are installed, we need to install Glances and Bottle (which will allow Glances to run as a web server).
### Install Glances and Bottle
Use the following pip3 commands to install Glances and Bottle:
`pip3 install bottle`
If you get an error, try it with `sudo` like:
`sudo pip3 install bottle`
Now, do the same, but for Glances:
`pip3 install glances`
and again, if you needed sudo for Bottle, you'll need it for Glances, so do:
`sudo pip3 install glances`
Once those are finished installing, you can test that glances works by running the command:
`glances`
in your terminal. You should see a page full of information about your system show up.
You can stop glacnes with the CTRL + C key combination.
Next, you can make sure Bottle is working and run glances in web-server mode with the command:
`glances -w`
You'll see some output on the terminal, and should have something like `Glances Web User Interface started on <a href="http://0.0.0.0:61208/">http://0.0.0.0:61208/</a>` on the screen.
Now, open a browser and go to
`http://localhost:61208`
or use the ip address of the machine you are working on:
`http://192.168.1.x:61208`
of course, using the correct private IP of the machine.
You should see a nice view of Glances, almos exactly as it looked in the terminal.
Now you can stop that process in the terminal with CTRL + C, an dwe need to turn that into a service that will run automatically, even after we reboot the machine.
### Create the Glances Service
We'll be adding a new file to `/etc/systemd/system/` called `glancesweb.service`
So in a terminal window do the following:
`sudo nano /etc/systemd/system/glancesweb.service`
This will open a text editor in your terminal, and it should be empty.
Use the following code to start off:
```
[Unit]
Description = Glances in Web Server Mode
After = network.target
[Service]
ExecStart = /usr/local/bin/glances -w -t 5
[Install]
WantedBy = multi-user.target
```
If you are running as root, this should work, but we need to make sure glances is running from the path we expect, which is currently `/usr/local/bin/`. To find this out, save the file with CTRL + O, then press Enter to confirm, then use CTRL + X to exit the nano editor.
In the terminal, do the command:
`which glances`
You should get output like:
`/usr/local/bin/glances`
but, if you aren't running as root during the install you may get something like:
`/home/<your usre>/.local/bin/glances`
Whatever you get, highlight it, right click, select copy, and then we'll open the nano editor back up with:
`sudo nano /etc/systemd/sysetm/glancesweb.service`
On that line starting with `ExecStart`, make sure to remove the path (if it's different from what you got with the `which glances` command, and replace it with what you copied.
In my case, I would make it look like
```
[Service]
ExecStart = /home/<your usre>/.local/bin/glances -w -t 5
```
Now, because it's running from my home directory, I need to add one more line just below this one. If you are running from the `/usr/local/bin` directory, you **do not** need this line.
`User = <your user>`
so for me, the file looks like:
```
[Service]
ExecStart = /home/brian/.local/bin/glances -w -t 5
User = brian
```
Yours should have your username of course.
Now, save the file with CTRL + O, then press Enter to confirm, and use CTRL + X to exit.
Next, we need to start and enable our service.
We do the following commands to do this:
`sudo systemctl start glances.service`
`sudo systemctl enable glances.service`
As long as you don't get any errors after each of those, you can check the status with
`sudo systemctl status glances`
You should see a row in the output near the top that shows `active`. If you see `failed`, you need to recheck the `glancesweb.service` file, and make sure you have everything correct.
Now that it's running, you can again go to the ip address of:
`http://<local ip>:61208`
and view your glances in the web browser. As long as it shows up, we are ready to move forward with getting some widgets in Dashy.
## Adding Widgets to Dashy
At the time of writing, Dashy widgets can only be added from the configuration file, and not through the UI / GUI editor. I believe it's being worked on, but the config file isn't hard to modify, so let's jump into it.
If you're running Dashy in the way I showed in my video previously, you'll want to get on the server it runs on, and navigate to the foldeer where the configuration file is located. For me it's in a folder in my home directory called `docker/dashy/public`.
So I do
`cd ~/docker/dashy/public`
Now if you do
`ls`
you should see a file called `conf.yml`. This is the configuration file you want.
First, let's copy conf.yml to a new backup version, just in case we mess something up, it's easy to bring it back to the way it is right now.
`cp conf.yml conf.bak.yml`
Now, let's modify our `conf.yml` file to add a widget.
`nano conf.yml`
You may need to use `sudo`. If you see a red bar at the bottom of your nano editor, you need to exit with CTRL + X, and re-open it with `sudo`.
`sudo nano conf.yml`
Now, move down through the file until you see the first section called `sections`.
Just below that line, create a new line. Keep in mind that yaml or `.yml` is very space specific. So mind your spacing.
Let's add a new Widget section for our server. My server's name is "Aria".
```
sections:
- name: Aria Info
```
Next, we'll add a `widgets` indicator, and our first widget. We'll add the glances cpu usage widget.
```
sections:
- name: Aria Info
widgets:
- type: gl-current-cpu
options:
hostname: http:192.168.10.209:61208
```
At this point, you can save with CTRL + O, and then go to your browser and open your Dashy dashboard, to see your new widget and ensure it works. You need to, of course, replace the IP in the example above with the IP address of your server that you installed glances on. You may have to refresh Dashy if you're already running it, and you may have to tell firefox to release the cache then refresh (firefox is great, but it really hates to refresh and show new sutff).
Let's add another widget. Continuing in the nano editor from where we are. we'll add:
```
sections:
- name: Aria Info
widgets:
- type: gl-current-cpu
options:
hostname: http:192.168.10.209:61208
- type: gl-current-mem
options:
hostname: http:192.168.10.209:61208
```
You can again save, and take a look at your Dashy dashboard to see the new widget. You can now just go crazy adding widgets to Dashy using this same method.
Let's say you want to add two servers data. It's now hard. We just create another section for our next server like so:
```
sections:
- name: Aria Info
widgets:
- type: gl-current-cpu
options:
hostname: http:192.168.10.209:61208
- type: gl-current-mem
options:
hostname: http:192.168.10.209:61208
- name: Liratta Info
widgets:
- type: gl-current-cpu
options:
hostname: http:192.168.10.152:61208
- type: gl-current-mem
options:
hostname: http:192.168.10.152:61208
```
Notice the different name and ip address in our second section. Also, understand that the glances / bottle install and service setup, needs to be done on each server / machine you want this information from.
Now you can turn Dashy into an incrdible tool for all kinds of great information.
<div class="text-muted text-small" id="bkmrk--1"><div class="entity-meta">
</div></div>
# Homepage
<iframe height="336" src="https://www.youtube.com/embed/3Ux7zfCCM1A" width="600"></iframe>
<p class="callout info">*This document and video was written and produced by Brian @ Awesome Open Source. Please support his channel and ongoing efforts through Patreon: [https://www.patreon.com/bePatron?u=234177](https://www.patreon.com/bePatron?u=234177)*</p>
Self hosted dashboards are incredibly useful for a myriad of reasons. They provide quick access to all of your self hosted services, quick links to bookmarks of your most used online sites and services, and can offer some very useful monitoring information about your services at a glance.
Homepage is no different in this regard, and is a fast loading piece of software to boot. One of the nicest features is that as you save changes to the configuration file, the page reloads quickly to show you how your changes have affected the page layout. This is something I've struggled with in Dashy since I started using it, having to work around caching in the browser by opening the dev tools and refreshing the page multiple times.
#### Installing Homepage
Now that we have docker and docker-compose installed, let's get ready to install Homepage. First we'll setup our desired folder structure. I put all of my docker applications inside of a top level (parent) folder called "docker". This makes it very easy to run a script that will backup all of my docker applications and compress them into a zipped format.
`mkdir -p docker/homepage`
This command will create the docker folder if it does not already exist, and will use the existing one if it does. Then it will create the homepage folder inside of that parent docker folder.
Now we'll move into the homepage folder and create a new file called docker-compose.yml.
`cd docker/homepage`
`nano docker-compose.yml`
In this case, I'm using the nano text editor directly in the terminal, but you can use any text editor you are more comfortable with. Make sure the editor is not a rich-text editor by default, as the yaml we will be adding is space dependent, and can be messed up with hidden rtf characters.
<p class="callout info">Adding a new environment variable based on latest updates to Homepage. In this newer version you need to tell Homepage where it should expect to be accessed at. So if you use IP and port, you'll want o put that, but if you use a sub-domain like 'homepage.mydomain.net', then you'll want to enter that subdomain.</p>
Copy the yaml code from the block below, and paste it into your new docker-compose.yml document.
```yaml
---
services:
homepage:
image: ghcr.io/gethomepage/homepage:latest
container_name: homepage
environment:
HOMEPAGE_ALLOWED_HOSTS: "*" # required, may need port. See gethomepage.dev/installation/#homepage_allowed_hosts
PUID: 1000 # Reference PUID from .env
PGID: 1000 # Reference PGID from .env
DOCKER_HOST: tcp://socket-proxy:2375
ports:
- 3000:3000
env_file:
- .env # Link to the .env file
volumes:
- ./config:/app/config # Make sure your local config directory exists
- ./images:/app/public/images
- /var/run/docker.sock:/var/run/docker.sock:ro # optional, for docker integrations
restart: unless-stopped
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000"]
interval: 10s
retries: 3
timeout: 10s
start_period: 30s
dockerproxy:
image: ghcr.io/tecnativa/docker-socket-proxy:latest
container_name: dockerproxy
environment:
- CONTAINERS=1 # Allow access to viewing containers
- SERVICES=1 # Allow access to viewing services (necessary when using Docker Swarm)
- TASKS=1 # Allow access to viewing tasks (necessary when using Docker Swarm)
- POST=0 # Disallow any POST operations (effectively read-only)
ports:
- 127.0.0.1:2375:2375
volumes:
- /var/run/docker.sock:/var/run/docker.sock:ro # Mounted as read-only
restart: unless-stopped
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:2375"]
interval: 10s
retries: 3
timeout: 10s
start_period: 30s
```
The changes you may want / need to make is to the port mapping (8921:3000), and to the environment variable HOMEPAGE\_ALLOWED\_HOSTNAMES. You can always change the left side port in a docker port mapping, just not the right side. The left side of the mapping is how you'll access the application once it's up and running. You simply want to make sure that it's not trying to use a port already in use on the host system. In this case I changed 3000 (the original left side port number) to 8921 in order to avoid a very common port used in nodejs based applications. As long as port 8921 is free on your host system, you won't need to change it.
Save the docker-compose.yml document with CTRL + O, then press Enter to confirm, and exit the nano editor with CTRL + X.
#### Run the Application
Now we are ready to run our application for the first time. We'll use the following command to run it:
`docker compose up -d`
If you have an older version of docker-compose, you may need to put a hyphen (-) between the words docker and compose, like this:
`docker-compose up -d`
NOTE: the un-hyphenated version is the newer version of docker-compose.
Allow docker to pull down the latest image of Homepage, and start up the container. When it's complete you'll be back at a normal terminal prompt.
Now go to your favorite modern browser and enter the IP address of your host machine (if you're running the application on the physical machine you're working on, you can use [http://localhost:8921](http://localhost:8921)) and the port 8921 (unless you changed the left side of the port mapping to another number, in which case you should use that port number. In my case, I went to:
[http://192.168.10.154:8921](http://192.168.10.154:8921)
You should now be presented with the default Homepage layout screen. After loading the web page for the first time, you'll find that back in the terminal you now have multiple yaml files in the "config" folder. These are initially created after you load the page for the first time.
You can now start modifying the yaml files to customize your Homepage as you please. I highly recommend reading the documentation on the configuration options, as there are many, and you can get very detailed on what can be displayed.
[https://gethomepage.dev/en/installation/](https://gethomepage.dev/en/installation/)
For a solid starting spot, I recommend opening the "services.yaml" and "bookmarks.yaml" files and playing with those a bit. You can add multiple service sections under each group, and you can add more groups as well in the services.yaml file. The same goes for the bookmarks.yaml file.
Make sure to check out the video for more detail on how to do that as well.
---
<div class="text-muted text-small" id="bkmrk--1"><div class="entity-meta">
</div></div>
+65
View File
@@ -0,0 +1,65 @@
---
tags:
- Documentation
- Bookstack
- Notes
---
# Docker
# Cheet Sheet Commands
## Running Containers
<table id="bkmrk-command-description-"><thead><tr><th>COMMAND</th><th>DESCRIPTION</th></tr></thead><tbody><tr><td>`docker run <image>`</td><td>Start a new container from an image</td></tr><tr><td>`docker run -it <image>`</td><td>Start a new container in interactive mode</td></tr><tr><td>`docker run --rm <image>`</td><td>Start a new container and remove it when it exits</td></tr><tr><td>`docker create <image>`</td><td>Create a new container</td></tr><tr><td>`docker start <container>`</td><td>Start a container</td></tr><tr><td>`docker stop <container>`</td><td>Graceful stop a container</td></tr><tr><td>`docker kill <container>`</td><td>Kill (SIGKILL) a container</td></tr><tr><td>`docker restart <container>`</td><td>Graceful stop and restart a container</td></tr><tr><td>`docker pause <container>`</td><td>Suspend a container</td></tr><tr><td>`docker unpause <container>`</td><td>Resume a container</td></tr><tr><td>`docker rm <container>`</td><td>Destroy a container</td></tr></tbody></table>
## Container Bulk Management
<table id="bkmrk-command-description--1"><thead><tr><th>COMMAND</th><th>DESCRIPTION</th></tr></thead><tbody><tr><td>`docker stop $(docker ps -q)`</td><td>To stop all the running containers</td></tr><tr><td>`docker stop $(docker ps -a -q)`</td><td>To stop all the stopped and running containers</td></tr><tr><td>`docker kill $(docker ps -q)`</td><td>To kill all the running containers</td></tr><tr><td>`docker kill $(docker ps -a -q)`</td><td>To kill all the stopped and running containers</td></tr><tr><td>`docker restart $(docker ps -q)`</td><td>To restart all running containers</td></tr><tr><td>`docker restart $(docker ps -a -q)`</td><td>To restart all the stopped and running containers</td></tr><tr><td>`docker rm $(docker ps -q)`</td><td>To destroy all running containers</td></tr><tr><td>`docker rm $(docker ps -a -q)`</td><td>To destroy all the stopped and running containers</td></tr><tr><td>`docker pause $(docker ps -q)`</td><td>To pause all running containers</td></tr><tr><td>`docker pause $(docker ps -a -q)`</td><td>To pause all the stopped and running containers</td></tr><tr><td>`docker start $(docker ps -q)`</td><td>To start all running containers</td></tr><tr><td>`docker start $(docker ps -a -q)`</td><td>To start all the stopped and running containers</td></tr><tr><td>`docker rm -vf $(docker ps -a -q)`</td><td>To delete all containers including its volumes use</td></tr><tr><td>`docker rmi -f $(docker images -a -q)`</td><td>To delete all the images</td></tr><tr><td>`docker system prune`</td><td>To delete all dangling and unused images, containers, cache and volumes</td></tr><tr><td>`docker system prune -a`</td><td>To delete all used and unused images</td></tr><tr><td>`docker system prune --volumes`</td><td>To delete all docker volumes</td></tr></tbody></table>
## Inspect Containers
<table id="bkmrk-command-description--2"><thead><tr><th>COMMAND</th><th>DESCRIPTION</th></tr></thead><tbody><tr><td>`docker ps`</td><td>List running containers</td></tr><tr><td>`docker ps --all`</td><td>List all containers, including stopped</td></tr><tr><td>`docker logs <container>`</td><td>Show a container output</td></tr><tr><td>`docker logs -f <container>`</td><td>Follow a container output</td></tr><tr><td>`docker top <container>`</td><td>List the processes running in a container</td></tr><tr><td>`docker diff`</td><td>Show the differences with the image (modified files)</td></tr><tr><td>`docker inspect`</td><td>Show information of a container (json formatted)</td></tr></tbody></table>
## Executing Commands
<table id="bkmrk-command-description--3"><thead><tr><th>COMMAND</th><th>DESCRIPTION</th></tr></thead><tbody><tr><td>`docker attach <container>`</td><td>Attach to a container</td></tr><tr><td>`docker cp <container>:<container-path> <host-path>`</td><td>Copy files from the container</td></tr><tr><td>`docker cp <host-path> <container>:<container-path>`</td><td>Copy files into the container</td></tr><tr><td>`docker export <container>`</td><td>Export the content of the container (tar archive)</td></tr><tr><td>`docker exec <container>`</td><td>Run a command inside a container</td></tr><tr><td>`docker exec -it <container> /bin/bash`</td><td>Open an interactive shell inside a container (there is no bash in some images, use /bin/sh)</td></tr><tr><td>`docker wait <container>`</td><td>Wait until the container terminates and return the exit code</td></tr></tbody></table>
## Images
<table id="bkmrk-command-description--4"><thead><tr><th>COMMAND</th><th>DESCRIPTION</th></tr></thead><tbody><tr><td>`docker image ls`</td><td>List all local images</td></tr><tr><td>`docker history <image>`</td><td>Show the image history</td></tr><tr><td>`docker inspect <image>`</td><td>Show information (json formatted)</td></tr><tr><td>`docker tag <image> <tag>`</td><td>Tag an image</td></tr><tr><td>`docker commit <container> <image>`</td><td>Create an image (from a container)</td></tr><tr><td>`docker import <url>`</td><td>Create an image (from a tarball)</td></tr><tr><td>`docker rmi <image>`</td><td>Delete images</td></tr><tr><td>`docker pull <user>/<repository>:<tag>`</td><td>Pull an image from a registry</td></tr><tr><td>`docker push <user>/<repository>:<tag>`</td><td>Push and image to a registry</td></tr><tr><td>`docker search <test>`</td><td>Search an image on the official registry</td></tr><tr><td>`docker login`</td><td>Login to a registry</td></tr><tr><td>`docker logout`</td><td>Logout from a registry</td></tr><tr><td>`docker save <user>/<repository>:<tag>`</td><td>Export an image/repo as a tarball</td></tr><tr><td>`docker load`</td><td>Load images from a tarball</td></tr></tbody></table>
## Volumes
<table id="bkmrk-command-description--5"><thead><tr><th>COMMAND</th><th>DESCRIPTION</th></tr></thead><tbody><tr><td>`docker volume ls`</td><td>List all vol1umes</td></tr><tr><td>`docker volume create <volume>`</td><td>Create a volume</td></tr><tr><td>`docker volume inspect <volume>`</td><td>Show information (json formatted)</td></tr><tr><td>`docker volume rm <volume>`</td><td>Destroy a volume</td></tr><tr><td>`docker volume ls --filter="dangling=true"`</td><td>List all dangling volumes (not referenced by any container)</td></tr><tr><td>`docker volume prune`</td><td>Delete all volumes (not referenced by any container)</td></tr><tr><td>`docker run --rm --volumes-from <container> -v $(pwd):/backup busybox tar cvfz /backup/backup.tar.gz <container-path>`</td><td>Backup a container</td></tr><tr><td>`docker run --rm --volumes-from <container> -v $(pwd):/backup busybox sh -c "cd <container-path> && tar xvfz /backup/backup.tar.gz --strip 1"`</td><td>Restore a container from backup</td></tr></tbody></table>
# Docker Install Script
This script is intended as a convenient way to configure docker's package # repositories and to install Docker Engine, This script is not recommended # for production environments. Before running this script, make yourself familiar # with potential risks and limitations, and refer to the installation manual # at [https://docs.docker.com/engine/install/](https://docs.docker.com/engine/install/) for alternative installation methods.
\# # The script:
\- Requires `root` or `sudo` privileges to run.
\- Attempts to detect your Linux distribution and version and configure your package management system for you.
\- Doesn't allow you to customize most installation parameters.
\- Installs dependencies and recommendations without asking for confirmation.
\- Installs the latest stable release (by default) of Docker CLI, Docker Engine, Docker Buildx, Docker Compose, containerd, and runc. When using this script to provision a machine, this may result in unexpected major version upgrades of these packages. Always test upgrades in a test environment before # deploying to your production systems.
\- Isn't designed to upgrade an existing Docker installation. When using the script to update an existing installation, dependencies may not be updated to the expected version, resulting in outdated versions.
\# # Source code is available at [https://github.com/docker/docker-install/](https://github.com/docker/docker-install/)
\# # Usage # ============================================================================== # #
To install the latest stable versions of Docker CLI, Docker Engine, and their # dependencies:
1\. download the script # # $ curl -fsSL [https://get.docker.com](https://get.docker.com) -o install-docker.sh
2\. verify the script's content $ cat install-docker.sh
3\. run the script with --dry-run to verify the steps it executes $ sh install-docker.sh --dry-run
4\. run the script either as root, or using sudo to perform the installation. $ sudo sh install-docker.sh
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,138 @@
---
tags:
- Documentation
- Bookstack
- Notes
---
# Home-Lab Environment
# Environment Documentation
I have standardized your domain listings into a clean table, removed the empty unassigned IP rows to reduce clutter (while keeping your standard sequential block visible), and extracted the miscellaneous Windows 10 license key into a dedicated, secure metadata section so it doesn't skew your networking tables.
# Home-Lab Environment Documentation
## 1. Public Domains &amp; External Servers
This table tracks external public-facing domains, their current A-record IP destinations, and hosting providers.
<table id="bkmrk-domain-name-target-i"><thead><tr><td>**Domain Name**</td><td>**Target IP Address**</td><td>**Host / Provider**</td><td>**Status / Notes**</td></tr></thead><tbody><tr><td><span>`mcfetridge.us`</span></td><td><span>129.213.86.62</span></td><td><span>Oracle Server</span></td><td><span>Active</span></td></tr><tr><td><span>`mikemcfetridge.com`</span></td><td><span>75.152.47.1</span></td><td><span>Home</span></td><td><span>Active</span></td></tr><tr><td><span>`mmcfetridge.net`</span></td><td><span>216.144.227.142</span></td><td><span>RackNerd Server</span></td><td><span>Active</span></td></tr><tr><td><span>`mmcfetridge.xyz`</span></td><td><span>107.175.245.171</span></td><td><span>*N/A*</span></td><td><span>Deprecated / Not used anymore</span></td></tr></tbody></table>
## 2. Local IP Asset Management (Subnet: `192.168.2.0/24`)
This mapping tracks internal static IPs, infrastructure hosts, container stacks, and active client hardware.
### Infrastructure &amp; Server Hosts
<table id="bkmrk-ip-address-server-na"><thead><tr><td>**IP Address**</td><td>**Server Name**</td><td>**Applications**</td><td>**Functional Comments**</td></tr></thead><tbody><tr><td><span>**192.168.2.1**</span></td><td><span>PVE</span></td><td><span>Proxmox</span></td><td><span>Main Proxmox Virtualization Environment</span></td></tr><tr><td><span>**192.168.2.2**</span></td><td><span>PVE2</span></td><td><span>Proxmox</span></td><td><span>Secondary Proxmox Node (Cluster/Failover)</span></td></tr><tr><td><span>**192.168.2.3**</span></td><td><span>docker-prod-01</span></td><td><span>Docker</span></td><td><span>Production Docker environment</span></td></tr><tr><td><span>**192.168.2.4**</span></td><td><span>pangolin</span></td><td><span>*None Listed*</span></td><td><span>Assigned host</span></td></tr><tr><td><span>**192.168.2.5**</span></td><td><span>Domain Locker</span></td><td><span>Docker Monitoring</span></td><td><span>Container ecosystem tracking &amp; monitoring</span></td></tr></tbody></table>
### Network Services &amp; Core Stacks
<table id="bkmrk-ip-address-server-na-1"><thead><tr><td>**IP Address**</td><td>**Server Name**</td><td>**Applications**</td><td>**Functional Comments**</td></tr></thead><tbody><tr><td><span>**192.168.2.8**</span></td><td><span>Pi-Hole</span></td><td><span>Ad-blocking / DNS</span></td><td><span>Network-wide ad blocker</span></td></tr><tr><td><span>**192.168.2.9**</span></td><td><span>TECHNITIUMDNS-SERVER</span></td><td><span>DNS</span></td><td><span>Local authoritative DNS Server</span></td></tr><tr><td><span>**192.168.2.10**</span></td><td><span>ArrStack</span></td><td><span>Media Management</span></td><td><span>Automation stack</span></td></tr><tr><td><span>**192.168.2.12**</span></td><td><span>linkwarden</span></td><td><span>lw</span></td><td><span>Web bookmark and internet link management</span></td></tr><tr><td><span>**192.168.2.15**</span></td><td><span>docker-deploy</span></td><td><span>CI/CD Deployer</span></td><td><span>Dedicated environment for deployments</span></td></tr><tr><td><span>**192.168.2.19**</span></td><td><span>VAULTWARDEN-SERVER</span></td><td><span>Passwords</span></td><td><span>Self-hosted Bitwarden backend (Password Server)</span></td></tr></tbody></table>
### End-User Devices &amp; Client Leases
<table id="bkmrk-ip-address-device-na"><thead><tr><td>**IP Address**</td><td>**Device Name**</td><td>**Device Type**</td><td>**Functional Comments**</td></tr></thead><tbody><tr><td><span>**192.168.2.248**</span></td><td><span>My iPad</span></td><td><span>Tablet</span></td><td><span>Personal client</span></td></tr><tr><td><span>**192.168.2.249**</span></td><td><span>My Laptop</span></td><td><span>Laptop</span></td><td><span>Primary workstation</span></td></tr></tbody></table>
> 💡 **Note:** IP addresses `192.168.2.6` through `192.168.2.7`, `192.168.2.11`, `192.168.2.13` through `192.168.2.14`, `192.168.2.16` through `192.168.2.18`, and `192.168.2.20` through `192.168.2.30` are currently unassigned and reserved for future static scaling.
## 3. Network Security &amp; Trusted Subnets (CIDR)
The following blocks are designated as **Trusted IP CIDRs** within internal firewall and reverse proxy definitions.
- `127.0.0.0/8` — Localhost loopback network
- `10.0.0.0/8` — Class A Private network space
- `172.16.0.0/12` — Class B Private network space (Commonly used by internal Docker bridges)
- `192.168.0.0/22` — Covers local scopes from `192.168.0.0` through `192.168.3.255`
## 4. Environment Metadata &amp; Licenses
> 🔑 **Windows 10 Pro Generic KMS / Setup Key:** &gt; `W269N-WFGWX-YVC9B-4J6C9-T83GX`
# 🌐 Configuring Dynamic DNS (DDNS) with ddclient and Namecheap
This guide walks you through installing and configuring `ddclient` on Ubuntu to automatically update your Namecheap domain with your network's public IP address.
## 1. Installation
Install the `ddclient` utility from the standard package manager:
<div class="code-block ng-tns-c1605810258-312 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" id="bkmrk-bash"><div class="formatted-code-block-internal-container ng-tns-c1605810258-312"><div class="animated-opacity ng-tns-c1605810258-312"><div class="code-block-decoration header-formatted gds-emphasized-body-m ng-tns-c1605810258-312 ng-star-inserted"><span class="ng-tns-c1605810258-312">Bash</span><div class="buttons ng-tns-c1605810258-312 ng-star-inserted"></div></div></div></div></div>```
sudo apt update && sudo apt install ddclient -y
```
<div class="code-block ng-tns-c1605810258-312 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" id="bkmrk--1"><div class="formatted-code-block-internal-container ng-tns-c1605810258-312"><div class="animated-opacity ng-tns-c1605810258-312"></div></div></div>> 💡 **Note:** During the installation, a text-based setup wizard will appear in your terminal. You can safely select **"Other"** when prompted for a provider and cycle through the defaults. We will completely overwrite these wizard settings manually in the next step.
## 2. Configuration
Open the configuration file using the `nano` text editor:
<div class="code-block ng-tns-c1605810258-313 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" id="bkmrk-bash-1"><div class="formatted-code-block-internal-container ng-tns-c1605810258-313"><div class="animated-opacity ng-tns-c1605810258-313"><div class="code-block-decoration header-formatted gds-emphasized-body-m ng-tns-c1605810258-313 ng-star-inserted"><span class="ng-tns-c1605810258-313">Bash</span><div class="buttons ng-tns-c1605810258-313 ng-star-inserted"></div></div></div></div></div>```
sudo nano /etc/ddclient.conf
```
<div class="code-block ng-tns-c1605810258-313 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" id="bkmrk--4"><div class="formatted-code-block-internal-container ng-tns-c1605810258-313"><div class="animated-opacity ng-tns-c1605810258-313"></div></div></div>Completely clear any auto-generated text and replace it with the following clean, accurate configuration block for Namecheap:
<div class="code-block ng-tns-c1605810258-314 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" id="bkmrk-ini%2C-toml"><div class="formatted-code-block-internal-container ng-tns-c1605810258-314"><div class="animated-opacity ng-tns-c1605810258-314"><div class="code-block-decoration header-formatted gds-emphasized-body-m ng-tns-c1605810258-314 ng-star-inserted"><span class="ng-tns-c1605810258-314">Ini, TOML</span><div class="buttons ng-tns-c1605810258-314 ng-star-inserted"></div></div></div></div></div>```
# Configuration for Namecheap Dynamic DNS
protocol=namecheap
server=dynamicdns.park-your-domain.com
use=web, web=https://api.ipify.org
login=mikemcfetridge.com
password='your_namecheap_ddns_password'
@
```
<div class="code-block ng-tns-c1605810258-314 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" id="bkmrk--7"><div class="formatted-code-block-internal-container ng-tns-c1605810258-314"><div class="animated-opacity ng-tns-c1605810258-314"></div></div></div>### 📋 Configuration Breakdown:
- **`server`**: Points directly to Namecheap's dedicated dynamic DNS handling infrastructure.
- **`use=web`**: Tells the client to fetch your external public IP using a web lookup utility (`ipify.org`) rather than checking your local router or network interface directly.
- **`login`**: Your root registered domain name.
- **`password`**: The unique, long alphanumeric DDNS password/token generated inside your Namecheap domain dashboard (this is *not* your Namecheap account password).
- **`@`**: Instructs `ddclient` to update the root domain apex itself. *(If you wanted to update a subdomain like `vpn.mikemcfetridge.com`, you would replace `@` with `vpn`).*
Save the file by pressing `CTRL + O`, then hit `Enter`, and exit the editor by pressing `CTRL + X`.
## 3. Managing the Service
Enable and start the background daemon process so that your system tracks and updates your IP automatically on reboots:
<div class="code-block ng-tns-c1605810258-315 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" id="bkmrk-bash-2"><div class="formatted-code-block-internal-container ng-tns-c1605810258-315"><div class="animated-opacity ng-tns-c1605810258-315"><div class="code-block-decoration header-formatted gds-emphasized-body-m ng-tns-c1605810258-315 ng-star-inserted"><span class="ng-tns-c1605810258-315">Bash</span><div class="buttons ng-tns-c1605810258-315 ng-star-inserted"></div></div></div></div></div>```
# Enable the service to start automatically on system boot
sudo systemctl enable ddclient
# Start the service right now
sudo systemctl start ddclient
# Check the running operational status of the service
sudo systemctl status ddclient
```
<div class="code-block ng-tns-c1605810258-315 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" id="bkmrk--10"><div class="formatted-code-block-internal-container ng-tns-c1605810258-315"><div class="animated-opacity ng-tns-c1605810258-315"></div></div></div>## 4. Verification and Debugging
To verify that your configuration is error-free and successfully communicating with Namecheap's servers, run a manual forced update simulation with verbose logging enabled:
<div class="code-block ng-tns-c1605810258-316 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" id="bkmrk-bash-3"><div class="formatted-code-block-internal-container ng-tns-c1605810258-316"><div class="animated-opacity ng-tns-c1605810258-316"><div class="code-block-decoration header-formatted gds-emphasized-body-m ng-tns-c1605810258-316 ng-star-inserted"><span class="ng-tns-c1605810258-316">Bash</span><div class="buttons ng-tns-c1605810258-316 ng-star-inserted"></div></div></div></div></div>```
sudo ddclient -daemon=0 -debug -verbose -noquiet -force
```
<div class="code-block ng-tns-c1605810258-316 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" id="bkmrk--13"><div class="formatted-code-block-internal-container ng-tns-c1605810258-316"><div class="animated-opacity ng-tns-c1605810258-316"></div></div></div>### Expected Output
Your terminal will print comprehensive initialization flags. Scroll down to the bottom of the output stream and verify that you see a `SUCCESS` confirmation similar to this:
<div class="code-block ng-tns-c1605810258-317 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" id="bkmrk-plaintext"><div class="formatted-code-block-internal-container ng-tns-c1605810258-317"><div class="animated-opacity ng-tns-c1605810258-317"><div class="code-block-decoration header-formatted gds-emphasized-body-m ng-tns-c1605810258-317 ng-star-inserted"><span class="ng-tns-c1605810258-317">Plaintext</span><div class="buttons ng-tns-c1605810258-317 ng-star-inserted"></div></div></div></div></div>```
opt{daemon} : 0
opt{debug} : 1
...
RECEIVE: <debug><![CDATA[]]></debug>
RECEIVE: </interface-response>
SUCCESS: updating @: good: IP address set to 174.179.116.220
```
<div class="code-block ng-tns-c1605810258-317 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" id="bkmrk--16"><div class="formatted-code-block-internal-container ng-tns-c1605810258-317"><div class="animated-opacity ng-tns-c1605810258-317"></div></div></div>If you see `SUCCESS: updating @: good`, your settings are valid, and `ddclient` is safely maintaining your public IP routing mapping behind the scenes!
+174
View File
@@ -0,0 +1,174 @@
---
tags:
- Documentation
- Bookstack
- Notes
---
# Kubernetes
# ☸️ Production-Ready Kubernetes Setup Guide (Ubuntu)
This guide walks you through setting up a Kubernetes cluster using `kubeadm` on Ubuntu Server (20.04, 22.04, or 24.04).
## 1. Prerequisites &amp; Resource Allocation
Ensure all machines in your planned cluster meet the following baseline requirements:
- **Operating System:** Clean installation of Ubuntu Server on all nodes.
- **Master Node:** Minimum 2 vCPUs, 4GB RAM, and 50GB storage.
- **Worker Nodes:** Minimum 1 vCPU (2 recommended), 2GB RAM (4GB recommended).
- **Network:** Unique hostnames, MAC addresses, and product\_uuids for every node. Fully static IP addresses are highly recommended.
## 2. Preparation (Execute on ALL Nodes)
Run these steps across every machine (Master and Workers) to prepare the operating system.
### Step 2.1: System Update &amp; Disable Swap
Kubernetes requires swap memory to be completely disabled to ensure kubelet resource scheduling works deterministically.
<div class="code-block ng-tns-c1605810258-279 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" id="bkmrk-bash"><div class="formatted-code-block-internal-container ng-tns-c1605810258-279"><div class="animated-opacity ng-tns-c1605810258-279"><div class="code-block-decoration header-formatted gds-emphasized-body-m ng-tns-c1605810258-279 ng-star-inserted"><span class="ng-tns-c1605810258-279">Bash</span><div class="buttons ng-tns-c1605810258-279 ng-star-inserted"></div></div></div></div></div>```
# Update local package lists and upgrade existing software
sudo apt update && sudo apt upgrade -y
# Disable swap immediately
sudo swapoff -a
# Persist the change across reboots by commenting out the swap line in /etc/fstab
sudo sed -i '/ swap / s/^\(.*\)$/#\1/g' /etc/fstab
```
<div class="code-block ng-tns-c1605810258-279 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" id="bkmrk--1"><div class="formatted-code-block-internal-container ng-tns-c1605810258-279"><div class="animated-opacity ng-tns-c1605810258-279"></div></div></div>### Step 2.2: Configure Kernel Modules and Networking
Load the necessary kernel modules for container isolation and networking, and configure required `sysctl` network parameters.
<div class="code-block ng-tns-c1605810258-280 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" id="bkmrk-bash-1"><div class="formatted-code-block-internal-container ng-tns-c1605810258-280"><div class="animated-opacity ng-tns-c1605810258-280"><div class="code-block-decoration header-formatted gds-emphasized-body-m ng-tns-c1605810258-280 ng-star-inserted"><span class="ng-tns-c1605810258-280">Bash</span><div class="buttons ng-tns-c1605810258-280 ng-star-inserted"></div></div></div></div></div>```
# Configure modules to load automatically on boot
cat <<EOF | sudo tee /etc/modules-load.d/k8s.conf
overlay
br_netfilter
EOF
# Load the modules into the current kernel session
sudo modprobe overlay
sudo modprobe br_netfilter
# Enable IPv4 forwarding and iptables bridging rules
cat <<EOF | sudo tee /etc/sysctl.d/k8s.conf
net.bridge.bridge-nf-call-iptables = 1
net.bridge.bridge-nf-call-ip6tables = 1
net.ipv4.ip_forward = 1
EOF
# Apply sysctl parameters immediately without a reboot
sudo sysctl --system
```
<div class="code-block ng-tns-c1605810258-280 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" id="bkmrk--4"><div class="formatted-code-block-internal-container ng-tns-c1605810258-280"><div class="animated-opacity ng-tns-c1605810258-280"></div></div></div>### Step 2.3: Install and Configure Containerd (CRI)
We will install `containerd`, generate its default configurations, and explicitly enable the `SystemdCgroup` driver so it aligns properly with Kubernetes' cgroup management.
<div class="code-block ng-tns-c1605810258-281 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" id="bkmrk-bash-2"><div class="formatted-code-block-internal-container ng-tns-c1605810258-281"><div class="animated-opacity ng-tns-c1605810258-281"><div class="code-block-decoration header-formatted gds-emphasized-body-m ng-tns-c1605810258-281 ng-star-inserted"><span class="ng-tns-c1605810258-281">Bash</span><div class="buttons ng-tns-c1605810258-281 ng-star-inserted"></div></div></div></div></div>```
# Install the containerd package
sudo apt update && sudo apt install -y containerd
# Generate default configuration directory and file
sudo mkdir -p /etc/containerd
containerd config default | sudo tee /etc/containerd/config.toml > /dev/null
# Configure containerd to use SystemdCgroup
sudo sed -i 's/SystemdCgroup = false/SystemdCgroup = true/g' /etc/etc/containerd/config.toml
# Restart and enable containerd service
sudo systemctl restart containerd
sudo systemctl enable containerd
```
<div class="code-block ng-tns-c1605810258-281 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" id="bkmrk--7"><div class="formatted-code-block-internal-container ng-tns-c1605810258-281"><div class="animated-opacity ng-tns-c1605810258-281"></div></div></div>### Step 2.4: Install Kubernetes CLI/Server Tools (`pkgs.k8s.io`)
This pulls from the modernized community-hosted repositories. *(Note: Adjust `v1.30` in the path if you intend to pin your cluster to a specific minor edition).*
<div class="code-block ng-tns-c1605810258-282 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" id="bkmrk-bash-3"><div class="formatted-code-block-internal-container ng-tns-c1605810258-282"><div class="animated-opacity ng-tns-c1605810258-282"><div class="code-block-decoration header-formatted gds-emphasized-body-m ng-tns-c1605810258-282 ng-star-inserted"><span class="ng-tns-c1605810258-282">Bash</span><div class="buttons ng-tns-c1605810258-282 ng-star-inserted"></div></div></div></div></div>```
# Download dependencies for secure repository signatures
sudo apt-get update && sudo apt-get install -y apt-transport-https ca-certificates curl gpg
# Download the public signing key for the modern Kubernetes package repository
sudo mkdir -p /etc/apt/keyrings
curl -fsSL https://pkgs.k8s.io/core:/stable:/v1.30/deb/Release.key | sudo gpg --dearmor -o /etc/apt/keyrings/kubernetes-apt-keyring.gpg
# Add the correct apt repository reference string
echo 'deb [signed-by=/etc/apt/keyrings/kubernetes-apt-keyring.gpg] https://pkgs.k8s.io/core:/stable:/v1.30/deb/ /' | sudo tee /etc/apt/sources.list.d/kubernetes.list
# Update your lists and install the core binaries
sudo apt-get update
sudo apt-get install -y kubelet kubeadm kubectl
# Prevent accidental background package upgrades from breaking cluster state
sudo apt-mark hold kubelet kubeadm kubectl
```
<div class="code-block ng-tns-c1605810258-282 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" id="bkmrk--10"><div class="formatted-code-block-internal-container ng-tns-c1605810258-282"><div class="animated-opacity ng-tns-c1605810258-282"></div></div></div>## 3. Control Plane Initialization (Execute on MASTER Node Only)
### Step 3.1: Initialize via Kubeadm
Choose your Pod network CIDR block. If using **Calico**, the default block is `192.168.0.0/16`. If using **Flannel**, the default block is `10.244.0.0/16`.
<div class="code-block ng-tns-c1605810258-283 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" id="bkmrk-bash-4"><div class="formatted-code-block-internal-container ng-tns-c1605810258-283"><div class="animated-opacity ng-tns-c1605810258-283"><div class="code-block-decoration header-formatted gds-emphasized-body-m ng-tns-c1605810258-283 ng-star-inserted"><span class="ng-tns-c1605810258-283">Bash</span><div class="buttons ng-tns-c1605810258-283 ng-star-inserted"></div></div></div></div></div>```
# Initialize the master plane node (Using Calico default networking block)
sudo kubeadm init --pod-network-cidr=192.168.0.0/16
```
<div class="code-block ng-tns-c1605810258-283 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" id="bkmrk--13"><div class="formatted-code-block-internal-container ng-tns-c1605810258-283"><div class="animated-opacity ng-tns-c1605810258-283"></div></div></div>*(Once complete, look at the end of your terminal output. Copy and save the unique `kubeadm join` block generated—you will need it for your workers).*
### Step 3.2: Configure local `kubectl` access
To allow your non-root system user account to issue instructions to the API server:
<div class="code-block ng-tns-c1605810258-284 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" id="bkmrk-bash-5"><div class="formatted-code-block-internal-container ng-tns-c1605810258-284"><div class="animated-opacity ng-tns-c1605810258-284"><div class="code-block-decoration header-formatted gds-emphasized-body-m ng-tns-c1605810258-284 ng-star-inserted"><span class="ng-tns-c1605810258-284">Bash</span><div class="buttons ng-tns-c1605810258-284 ng-star-inserted"></div></div></div></div></div>```
mkdir -p $HOME/.kube
sudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config
sudo chown $(id -u):$(id -g) $HOME/.kube/config
```
<div class="code-block ng-tns-c1605810258-284 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" id="bkmrk--16"><div class="formatted-code-block-internal-container ng-tns-c1605810258-284"><div class="animated-opacity ng-tns-c1605810258-284"></div></div></div>### Step 3.3: Deploy the Pod CNI (Calico Deployment)
Deploying a single clear network operator ensures network tracking stays clean.
<div class="code-block ng-tns-c1605810258-285 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" id="bkmrk-bash-6"><div class="formatted-code-block-internal-container ng-tns-c1605810258-285"><div class="animated-opacity ng-tns-c1605810258-285"><div class="code-block-decoration header-formatted gds-emphasized-body-m ng-tns-c1605810258-285 ng-star-inserted"><span class="ng-tns-c1605810258-285">Bash</span><div class="buttons ng-tns-c1605810258-285 ng-star-inserted"></div></div></div></div></div>```
# Install the Tigera Calico Operator
kubectl create -f https://raw.githubusercontent.com/projectcalico/calico/v3.26.0/manifests/tigera-operator.yaml
# Download the custom resource manifest definition
wget https://raw.githubusercontent.com/projectcalico/calico/v3.26.0/manifests/custom-resources.yaml
# (Optional modification) If you used a pod-network-cidr other than 192.168.0.0/16,
# edit custom-resources.yaml using nano to alter the "cidr:" line inside to match it.
# Apply the custom network layout manifest
kubectl create -f custom-resources.yaml
```
<div class="code-block ng-tns-c1605810258-285 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" id="bkmrk--19"><div class="formatted-code-block-internal-container ng-tns-c1605810258-285"><div class="animated-opacity ng-tns-c1605810258-285"></div></div></div>## 4. Join Worker Nodes (Execute on WORKER Nodes Only)
Move over to your designated worker VMs. Take the output you preserved from Step 3.1 and execute it with administrative flags:
<div class="code-block ng-tns-c1605810258-286 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" id="bkmrk-bash-7"><div class="formatted-code-block-internal-container ng-tns-c1605810258-286"><div class="animated-opacity ng-tns-c1605810258-286"><div class="code-block-decoration header-formatted gds-emphasized-body-m ng-tns-c1605810258-286 ng-star-inserted"><span class="ng-tns-c1605810258-286">Bash</span><div class="buttons ng-tns-c1605810258-286 ng-star-inserted"></div></div></div></div></div>```
sudo kubeadm join <master-node-ip>:6443 --token <token-string> \
--discovery-token-ca-cert-hash sha256:<hash-string>
```
<div class="code-block ng-tns-c1605810258-286 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" id="bkmrk--22"><div class="formatted-code-block-internal-container ng-tns-c1605810258-286"><div class="animated-opacity ng-tns-c1605810258-286"></div></div></div>### Missing your join token string?
If you ever lose the string or it expires (tokens automatically timeout after 24 hours), generate a brand-new execution block by running this command back on the **Master node**:
<div class="code-block ng-tns-c1605810258-287 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" id="bkmrk-bash-8"><div class="formatted-code-block-internal-container ng-tns-c1605810258-287"><div class="animated-opacity ng-tns-c1605810258-287"><div class="code-block-decoration header-formatted gds-emphasized-body-m ng-tns-c1605810258-287 ng-star-inserted"><span class="ng-tns-c1605810258-287">Bash</span><div class="buttons ng-tns-c1605810258-287 ng-star-inserted"></div></div></div></div></div>```
kubeadm token create --print-join-command
```
+295
View File
@@ -0,0 +1,295 @@
---
tags:
- Documentation
- Bookstack
- Notes
---
# Mailcow
# Installation
# Installation of mailcow[¶](https://docs.mailcow.email/getstarted/install/#installation-of-mailcow "Permanent link")
## Prerequisites[¶](https://docs.mailcow.email/getstarted/install/#prerequisites "Permanent link")
### System Packages[¶](https://docs.mailcow.email/getstarted/install/#system-packages "Permanent link")
The following Linux packages are required for using mailcow and may need to be installed depending on your distribution:
- git
- openssl
- curl
- awk
- sha1sum
- grep
- cut
- jq (**new as of [2025-09](https://mailcow.email/posts/2025/release-2025-09/#2025-09-release-10th-september-2025)**)
### Docker and Docker Compose[¶](https://docs.mailcow.email/getstarted/install/#docker-and-docker-compose "Permanent link")
For the installation, you will need:
- **Docker**: Version `>= 24.0.0`
- **Docker Compose**: Version `>= 2.0`
Installation guides can be found here:
- [Install Docker](https://docs.docker.com/install/)
- [Install Docker Compose](https://docs.docker.com/compose/install/)
### Quick Installation[¶](https://docs.mailcow.email/getstarted/install/#quick-installation "Permanent link")
#### System Packages[¶](https://docs.mailcow.email/getstarted/install/#system-packages_1 "Permanent link")
##### Debian/Ubuntu:[¶](https://docs.mailcow.email/getstarted/install/#debianubuntu "Permanent link")
```
apt update
apt install -y git openssl curl gawk coreutils grep jq
```
#### Docker[¶](https://docs.mailcow.email/getstarted/install/#docker "Permanent link")
Important
Use the **latest available Docker Engine** and not the version from your Linux distribution's package sources.
##### Debian/Ubuntu:[¶](https://docs.mailcow.email/getstarted/install/#debianubuntu_1 "Permanent link")
```
curl -sSL https://get.docker.com/ | CHANNEL=stable sh
systemctl enable --now docker
```
#### Docker Compose[¶](https://docs.mailcow.email/getstarted/install/#docker-compose "Permanent link")
Warning
**mailcow requires Docker Compose version `>= 2.0`.**
##### Installation via Package Manager (Plugin)[¶](https://docs.mailcow.email/getstarted/install/#installation-via-package-manager-plugin "Permanent link")
Note
This method requires that the Docker repository has been added (see [Docker](https://docs.mailcow.email/getstarted/install/#docker)).
###### Debian/Ubuntu:[¶](https://docs.mailcow.email/getstarted/install/#debianubuntu_2 "Permanent link")
```
apt update
apt install docker-compose-plugin
```
## Installing mailcow[¶](https://docs.mailcow.email/getstarted/install/#installing-mailcow "Permanent link")
1. Clone the repository:
```
su
umask 0022
cd /opt
git clone https://github.com/mailcow/mailcow-dockerized
cd mailcow-dockerized
```
2. Generate the configuration file:
```
./generate_config.sh
```
3. Adjust the configuration if necessary:
```
nano mailcow.conf
```
---
## Starting mailcow[¶](https://docs.mailcow.email/getstarted/install/#starting-mailcow "Permanent link")
Download the images and start the containers:
<div class="tabbed-set tabbed-alternate" id="bkmrk-docker-compose-%28plug"><div class="tabbed-labels tabbed-labels--linked">[Docker Compose (Plugin)](https://docs.mailcow.email/getstarted/install/#__tabbed_1_1)[Docker Compose (Standalone)](https://docs.mailcow.email/getstarted/install/#__tabbed_1_2)</div><div class="tabbed-content"><div class="tabbed-block"><div class="highlight"><nav class="md-code__nav"></nav></div></div></div></div>```
docker compose pull
docker compose up -d
```
<div class="tabbed-set tabbed-alternate" id="bkmrk--3"><div class="tabbed-content"><div class="tabbed-block"><div class="highlight"></div></div></div><div class="tabbed-control tabbed-control--prev">
</div><div class="tabbed-control tabbed-control--next">
</div></div>Done!
You can now access **`https://${MAILCOW_HOSTNAME}/admin`** using the default credentials `admin` and the password `moohoo`.
---
## Troubleshooting[¶](https://docs.mailcow.email/getstarted/install/#troubleshooting "Permanent link")
### MTU not equal to 1500 (e.g., OpenStack)[¶](https://docs.mailcow.email/getstarted/install/#mtu-not-equal-to-1500-eg-openstack "Permanent link")
Adjust the network settings in `docker-compose.yml`:
```
networks:
mailcow-network:
driver_opts:
com.docker.network.driver.mtu: 1450
```
### No IPv6 on the Host System[¶](https://docs.mailcow.email/getstarted/install/#no-ipv6-on-the-host-system "Permanent link")
Disable IPv6 for the mailcow network if your host system does not support IPv6. More information can be found [here](https://docs.mailcow.email/post_installation/firststeps-disable_ipv6/).
---
## Important Notes[¶](https://docs.mailcow.email/getstarted/install/#important-notes "Permanent link")
- **Data Persistence**: Your data is stored in Docker volumes and remains intact even if you recreate or delete containers.
- **Reverse Proxy**: If you are not using a reverse proxy, you should [redirect HTTP to HTTPS](https://docs.mailcow.email/manual-guides/u_e-80_to_443/).
# DNS Entries
Below you can find a list of **recommended DNS records**. While some are mandatory for a mail server (A, MX), others are recommended to build a good reputation score (TXT/SPF) or used for auto-configuration of mail clients (SRV).
## References[¶](https://docs.mailcow.email/getstarted/prerequisite-dns/#references "Permanent link")
- A good article covering all relevant topics: ["3 DNS Records Every Email Marketer Must Know"](https://www.rackaid.com/blog/email-dns-records)
- Another great one, but Zimbra as an example platform: ["Best Practices on Email Protection: SPF, DKIM and DMARC"](https://wiki.zimbra.com/wiki/Best_Practices_on_Email_Protection:_SPF,_DKIM_and_DMARC)
- An in-depth discussion of SPF, DKIM and DMARC: ["How to eliminate spam and protect your name with DMARC"](https://www.skelleton.net/2015/03/21/how-to-eliminate-spam-and-protect-your-name-with-dmarc/)
- A thorough guide on understanding DMARC: ["Demystifying DMARC: A guide to preventing email spoofing"](https://seanthegeek.net/459/demystifying-dmarc/)
## Reverse DNS of your IP address[¶](https://docs.mailcow.email/getstarted/prerequisite-dns/#reverse-dns-of-your-ip-address "Permanent link")
Make sure that the PTR record of your IP address matches the FQDN of your mailcow host: `${MAILCOW_HOSTNAME}` <sup id="bkmrk-1">[1](https://docs.mailcow.email/getstarted/prerequisite-dns/#fn:1)</sup>. This record is usually set at the provider you leased the IP address (server) from. Please make sure that you create the record for IPv4 and IPv6 address (if you are using IPv6)!
## The minimal DNS configuration[¶](https://docs.mailcow.email/getstarted/prerequisite-dns/#the-minimal-dns-configuration "Permanent link")
This example shows you a set of records for one domain managed by mailcow. Each domain that is added to mailcow needs at least this set of records to function correctly.
```
# Name Type Value
mail IN A 1.2.3.4
autodiscover IN CNAME mail.example.org. (your ${MAILCOW_HOSTNAME})
autoconfig IN CNAME mail.example.org. (your ${MAILCOW_HOSTNAME})
@ IN MX 10 mail.example.org. (your ${MAILCOW_HOSTNAME})
```
**Note:** The `mail` DNS record which binds the subdomain to the given ip address must only be set for the domain on which mailcow is running and that is used to access the web interface. For every other mailcow managed domain, the `MX` record will route the traffic.
## DKIM, SPF and DMARC[¶](https://docs.mailcow.email/getstarted/prerequisite-dns/#dkim-spf-and-dmarc "Permanent link")
In the example DNS zone file snippet below, a simple **SPF** TXT record is used to only allow THIS server (the MX) to send mail for your domain. Every other server is disallowed but able to ("`~all`"). Please refer to [SPF Project](http://www.open-spf.org/) for further reading.
```
# Name Type Value
@ IN TXT "v=spf1 mx a -all"
```
It is highly recommended to create a **DKIM** TXT record in your mailcow UI and set the corresponding TXT record in your DNS records. Please refer to [OpenDKIM](http://www.opendkim.org/) for further reading.
```
# Name Type Value
dkim._domainkey IN TXT "v=DKIM1; k=rsa; t=s; s=email; p=..."
```
The last step in protecting yourself and others is the implementation of a **DMARC** TXT record, for example by using the [DMARC Assistant](http://www.kitterman.com/dmarc/assistant.html) ([check](https://dmarcian.com/dmarc-inspector/google.com)).
```
# Name Type Value
_dmarc IN TXT "v=DMARC1; p=reject; rua=mailto:mailauth-reports@example.org"
```
## The advanced DNS configuration[¶](https://docs.mailcow.email/getstarted/prerequisite-dns/#the-advanced-dns-configuration "Permanent link")
**SRV** records specify the server(s) for a specific protocol on your domain. If you want to explicitly announce a service as not provided, give "." as the target address (instead of "mail.example.org."). Please refer to [RFC 2782](https://tools.ietf.org/html/rfc2782).
```
# Name Type Priority Weight Port Value
_autodiscover._tcp IN SRV 0 1 443 mail.example.org. (your ${MAILCOW_HOSTNAME})
_caldavs._tcp IN SRV 0 1 443 mail.example.org. (your ${MAILCOW_HOSTNAME})
_caldavs._tcp IN TXT "path=/SOGo/dav/"
_carddavs._tcp IN SRV 0 1 443 mail.example.org. (your ${MAILCOW_HOSTNAME})
_carddavs._tcp IN TXT "path=/SOGo/dav/"
_imap._tcp IN SRV 0 1 143 mail.example.org. (your ${MAILCOW_HOSTNAME})
_imaps._tcp IN SRV 0 1 993 mail.example.org. (your ${MAILCOW_HOSTNAME})
_pop3._tcp IN SRV 0 1 110 mail.example.org. (your ${MAILCOW_HOSTNAME})
_pop3s._tcp IN SRV 0 1 995 mail.example.org. (your ${MAILCOW_HOSTNAME})
_sieve._tcp IN SRV 0 1 4190 mail.example.org. (your ${MAILCOW_HOSTNAME})
_smtps._tcp IN SRV 0 1 465 mail.example.org. (your ${MAILCOW_HOSTNAME})
_submission._tcp IN SRV 0 1 587 mail.example.org. (your ${MAILCOW_HOSTNAME})
_submissions._tcp IN SRV 0 1 465 mail.example.org. (your ${MAILCOW_HOSTNAME})
```
## Testing[¶](https://docs.mailcow.email/getstarted/prerequisite-dns/#testing "Permanent link")
Here are some tools you can use to verify your DNS configuration:
- [MX Toolbox](https://mxtoolbox.com/SuperTool.aspx) (DNS, SMTP, RBL)
- [port25.com](https://www.port25.com/dkim-wizard/) (DKIM, SPF)
- [Mail-tester](https://www.mail-tester.com/) (DKIM, DMARC, SPF)
- [DMARC Analyzer](https://www.dmarcanalyzer.com/spf/checker/) (DMARC, SPF)
- [MultiRBL.valli.org](http://multirbl.valli.org/) (DNSBL, RBL, FCrDNS)
## Misc[¶](https://docs.mailcow.email/getstarted/prerequisite-dns/#misc "Permanent link")
### Optional DMARC Statistics[¶](https://docs.mailcow.email/getstarted/prerequisite-dns/#optional-dmarc-statistics "Permanent link")
If you are interested in statistics, you can additionally register with some of the many below DMARC statistic services - or self-host your own.
Tip
It is worth considering that if you request DMARC statistic reports to your mailcow server and your mailcow server is not configured correctly to receive these reports, you may not get accurate and complete results. Please consider using an alternative email domain for receiving DMARC reports.
It is worth mentioning, that the following suggestions are not a comprehensive list of all services and tools available, but only a small few of the many choices.
- [Postmaster Tool](https://postmaster.google.com/v2/manage_domains)
- [parsedmarc](https://github.com/domainaware/parsedmarc) (self-hosted)
- [Fraudmarc](https://fraudmarc.com/)
- [Postmark](https://dmarc.postmarkapp.com/)
- [Dmarcian](https://dmarcian.com/)
Tip
These services may provide you with a TXT record you need to insert into your DNS records as the provider specifies. Please ensure you read the provider's documentation from the service you choose as this process may vary.
### Email test for SPF, DKIM and DMARC:[¶](https://docs.mailcow.email/getstarted/prerequisite-dns/#email-test-for-spf-dkim-and-dmarc "Permanent link")
To run a rudimentary email authentication check, send a mail to `check-auth at verifier.port25.com` and wait for a reply. You will find a report similar to the following:
```
==========================================================
Summary of Results
==========================================================
SPF check: pass
"iprev" check: pass
DKIM check: pass
DKIM check: pass
SpamAssassin check: ham
==========================================================
Details:
==========================================================
....
```
The full report will contain more technical details.
### Fully Qualified Domain Name (FQDN)[¶](https://docs.mailcow.email/getstarted/prerequisite-dns/#fully-qualified-domain-name-fqdn "Permanent link")
<div class="footnote" id="bkmrk-a%C2%A0fully-qualified-do">---
1. A **Fully Qualified Domain Name** (**FQDN**) is the complete (absolute) domain name for a specific computer or host, on the Internet. The FQDN consists of at least three parts divided by a dot: the hostname, the domain name, and the Top Level Domain (**TLD** for short). In the example of `mx.mailcow.email` the hostname would be `mx`, the domain name `mailcow` and the TLD `email`. [](https://docs.mailcow.email/getstarted/prerequisite-dns/#fnref:1 "Jump back to footnote 1 in the text")
</div>
+152
View File
@@ -0,0 +1,152 @@
---
tags:
- Documentation
- Bookstack
- Notes
---
# Mesh Central
# MeshCentral - an Open Source, Self Hosted Remote Machine Management and Access tool
#
<iframe height="336" src="https://www.youtube.com/embed/pGBIjBGqlfI" width="600"></iframe>
If you have been looking for a self-hosted, open source, free way to do remote support for yourself, your family, your friends, your business, or anything else, this is an excellent tool for doing exactly that.
The best part is we can now install MeshCentral with Docker, and this makes it so much easier to get going. It was already easy, but now it's even simpler. We are going to install it, and setup NGinX Proxy Manager to give our install a Fully Qualified Domain Name and LetsEncrypt for CA Certified SSL Encryption.
## Install with Docker-CE, Docker-Compose, and NGinX Proxy Manager
We'll be using an image on DockerHub from typhonragewind, and he has this setup really well for getting everything up and running pretty easily.
Before we begin, you will want to have Docker-CE (not docker.io) and Docker-Compose installed on your system. I have a post on how to do this [here](http://shownotes.opensourceisawesome.com/putting-it-all-together/). Definitely go get that step done first, then come back to continue with the MeshCentral install.
### Install MeshCentral
Head over to [https://github.com/Typhonragewind/meshcentral-docker](https://github.com/Typhonragewind/meshcentral-docker) and scroll down to see the docker-compose.yml text on the page.
<p class="callout info">It's always best to check the original source pages for any updates. As these articles age, the projects will progress and change over time. Make sure you get the latest and greatest!</p>
Copy the text.
For convenience, here's my file contents for the docker-compose.yml.
```yaml
version: '3'
services:
meshcentral:
restart: always
container_name: meshcentral
image: typhonragewind/meshcentral:latest
ports:
- 8086:443 #MeshCentral will moan and try everything not to use port 80, but you can also use it if you so desire, just change the config.json according to your needs
environment:
- HOSTNAME=meshctrl.mydomain.com #your hostname
- REVERSE_PROXY=192.168.21.217 #set to your reverse proxy IP if you want to put meshcentral behind a reverse proxy
- REVERSE_PROXY_TLS_PORT=443
- IFRAME=false #set to true if you wish to enable iframe support
- ALLOW_NEW_ACCOUNTS=false #set to false if you want disable self-service creation of new accounts besides the first (admin)
- WEBRTC=true #set to true to enable WebRTC - per documentation it is not officially released with meshcentral, but is solid enough to work with. Use with caution
- TZ=America/Chicago
volumes:
- ./meshcentral/data:/opt/meshcentral/meshcentral-data #config.json and other important files live here. A must for data persistence
- ./meshcentral/user_files:/opt/meshcentral/meshcentral-files #where file uploads for users live
```
Now open a terminal window, and create a directory called "meshcentral"
`mkdir meshcentral`
and move into that directory
`cd meshcentral`
Now make a "docker-compose.yml" file
`nano docker-compose.yml`
and Paste in the docker-compose text you just copied from the GitHub page above. Use CTRL + Shift + V to paste in the terminal window.
Next, we want to make a few changes to the docker-compose text before saving.
First up, if you want a port that is different than the default 8086 set in the yaml file, then change the left side of the port mapping only. DO NOT change the right side of the port mapping. Notice, the author warns you that if you try to make it port 80, it's going to cause issues, so I suggest not using port 80 for this. Just make sure to use a port that you are not currently using on your host machine.
Next, setup a hostname for your server. If you want to setup a hostname, this is where you specify it. If you want to access this from outside your private network, set a publicly routable hostname. Make sure you own the domain you use if you use a publicly routable domain.
If you don't want to use a publicly accessible domain, then setup a hostname for your private netwrok...somthing like "meshcentral.local".
If you'll be using a reverse proxy (which in this tutorial we will be using NGinX-Proxy-Manager), then you need to enter the IP address of the host machine for your proxy. In my case it's 192.168.7.125, but make sure to use the IP of your proxy host.
I left REVERSE\_PROXY\_TLS\_PORT as 443, and sugget you do the smae. I changed IFRAME to "false".
I am also changing ALLOW\_NEW\_ACCOUNTS to false, because I don't want to allow anyone else to sign up, but me. If you have an IT team, or other users you want to allow to access the system, you can leave this enabled, but you can also create other users from inside the MeshCentral UI when it's up and running.
Finally, I set WEBRTC to be "true", as I want the fastest possible connection between my machines, and this will allow that when it's available.
### Volumes
We need to setup a space for our volumes to be mapped as well. This allows us to update the containers without losing data.
First save your changes with CTRL + O, then Enter, and then use CTRL + X to exit.
Now make a folder called "meshcentral" again.
`mkdir meshcentral`
So you should have a folder called "meshcentral" inside the folder called "meshcentral".
### Start it Up
Now use the command
`docker-compose up -d`
to pull down the images, and start the container(s).
When you see 'done' in the terminal, give it about 2 minutes, then navigate to your hose machine's IP address with the port 8086. Make sure to use https for the URL.
for me I went to https://192.168.7.51:8086. You'll get a self signed certificate warning, but feel free to accept the risk, and move forward.
## Setup NGinX Proxy Manager for Access
If you are going to be accessing this system from outside your network, then you'll want to setup a routable domain name. You can use something like DuckDNS to get a dynamic DNS address that will update when your public IP updates, or you can purchase your own domain name, and create an entry that points to your Public IP address.
Either way, once you get the domain to your network, you need a way to route that traffic more safely around your network to your various machines and containers. This is where NGinX Proxy Manager comes in.
Open up NPM and click the "Proxy Hosts" option if you aren't already on that view. Now click to Add a New Host.
In the pop-up form, enter the domain name that will be used to access your meshcentral install. for example if you are going to use "meshcentral.remotemanagement.com" (presuming you won remotemanagement.com) then you would enter "meshcentral.remotemanagement.com" into the blank, and press tab to accept the entry.
Next, change the `http` to `https` in the field below the domain name, then tab over to the Forward Hostname / IP field, and enter the IP of the host machine you have MeshCentral running on (if it's a different machine than the one your NPM is running on). If you have both NPM and MeshCentral running on one machine, then enter the docker gateway IP in this field. You can get the docker gateway IP through the terminal.
`docker network inspect bridge`
Check the JSON for the key 'Gateway' and make note of the IP value. Usually this is 172.17.0.1, but not always, so it's good to double check.
Next, tab to the port field in NPM, and enter the port you set on the left side of the port mapping in the yaml docker-compose file. If you left it as the default it will be 8086.
Now, Save.
In the NPM interface, click the new entry, and make sure you are taken to the proper server. You should again see the Certifiacte warning.
#### Let's Get Our LetsEncrypt Certificates
In NPM, click the 3-dot icon on the right end of your new proxy host entry, and select 'Edit'.
Go to the "SSL" tab in the pop-up window, and select "Request a New Certificate". Move down, and enable "Force SSL". Next, enter your email address for LetsEncrypt, and enable the "I Agree" option. Now click Save.
It may take a few seconds, but if everything works, the pop-up will close without any warnings or errors.
You can again click on the URL you set for this host entry, and it will open in a new tab. You should now see the login screen of your MeshCentral install, and you can see a verified SSL lock icon in the URL bar.
Click the 'Crate an Account' option in the login window, and create your new account for Mesh Central.
Make sure to check out the video at the top, to see how to use MeshCentral, add machines, control them, and navigate the UI.
---
<div class="text-muted text-small" id="bkmrk--2"><div class="entity-meta">
</div></div>
+208
View File
@@ -0,0 +1,208 @@
---
tags:
- Documentation
- Bookstack
- Notes
---
# n8n.io
# Workflow Automation
#
<iframe height="314" src="https://www.youtube.com/embed/lpRsqiBc2JQ" width="560"></iframe>
n8n is a freely licensed (based on the Apache 2.0, but more permissive) workflow automation tool set. It enables you to drag and drop nodes for various tools to generate amazing information workflows.
Be sure to check out the end of the article for a discount code for 20% off of any of the n8n hosted / licensed options.
Say you have a customer interest, or sales lead form, and you want the information entered in that form to be added to a database, and to also send a notification to you through your chat application (like RocketChat or Slack, etc). This is exactly what n8n does. It allows you to use drag and drop nodes for various tools, to create a workflow where you can push data from a web form into n8n, potentially pretty up the data you receive, and then push that data down a pipeline of nodes to go into other applications and perform tasks automatically. You imagination is really thte limiting factor with something like n8n.
## What You'll Need
<div dir="auto" id="bkmrk-docker-and-docker-co">- Docker and Docker-Compose installed on a host server / system.
- (optional) NGinX Proxy Manager or some other reverse proxy if you want access from the outside interente.
- About 10 minutes of your time
</div>### Installing Docker-CE and Docker-Compose
If you already have Docker and Docker-Compose installed, feel free to skip down to the next section.
You may want to install some pre-requisite softwre as well:
Debian / Ubuntu
`sudo apt install git curl wget`
Fedora / Redhat
`dnf install git curl wget`
Arch
`sudo pacman -Sy git curl wget`
You can easily install Docker-CE, Docker-Compose, Portainer-CE, and NGinX Proxy manager by using this quick install script I created and maintain on Github. Just use the command:
`wget <a href="https://gitlab.com/bmcgonag/docker_installs/-/raw/main/install_docker_nproxyman.sh">https://gitlab.com/bmcgonag/docker_installs/-/raw/main/install_docker_nproxyman.sh</a>`
To download the script to your desired host.
Change the permissios to make the script executable:
`chmod +x ./install_docker_nproxyman.sh`
and then run the script with the command:
`./install_docker_nproxyman.sh`
When run, the script will prompt you to select your host operating system, then will ask you which bits of software you want to install.
Simply enter 'y' for each thing you want to install.
For instance, you may want to answer 'y' to NGinX Proxy Manager, and Portainer-CE if you don't already use these in your system.
At some point, you'll be asked for your super user (sudo) password as well.
Allow the script to complete installation.
At this point, you might want to log out and back in, as this will allow you to use the `docker` and `docker-compose` commands without the need of `sudo` in front of them.
### Installing n8n
Installing n8n is fairly straight forward. There are only a couple of files we'll need to setup, and for the most part, it will be copy / paste.
First, let's prepare our folder structure. I like to have everything I run in docker, inside of a folder called "docker". This way I simply backup the entire "docker" folder, and everything is backed up in case of catastrophic failure.
To create a new "docker" folder, just do the following in the terminal:
`mkdir docker`
Now, let's move into the "docker" folder, and create a new folder called "n8n".
`cd docker`
`mkdir n8n`
Finally, let's move into our "n8n" folder and start creating the files we need.
`cd n8n`
Now, we'll create a folder and two files for our application. First, let's create a hidden folder called ".n8n" where we'll put a configuration file.
NOTICE: there is a period "." in front of our folder name for ".n8n". This is important as it makes this a *hidden* folder in our system. You can only see it if you do the `ls` command with the `-a` argument afterward like this `ls -a`.
`mkdir .n8n`
Mow move into the ".n8n" folder and create a new file called "config".
`cd .n8n`
`nano config`
Inside this file, paste the following lines of text:
```
{
"encryptionKey": "abcdefg1234567890ABCdefG0123456789"
}
```
Once pasted into your new file, remove the placeholder key "abcdefg1234567890ABCdefG0123456789", and replace the characters with a key of your onw. The key should be long and strong, so make sure it's got upper and lower case letters and numbers randomly.
Save the file with CTRL + O, press Enter to confirm, and then exit the nano text editor with CTRL + X.
Next, we'll go back one level in our folder structure with the command:
`cd ..`
You should be back in the "docker/n8n" folder now. Let's create our dokcer-compose.yml file with
`nano docker-compose.yml`
Now paste the code block below into that file:
```
version: '3.3'
services:
n8n:
container_name: n8n
ports:
- 5678:5678
environment:
- WEBHOOK_URL=https://n8nio.your-great-domain.org/
- EXECUTIONS_PROCESS=main
volumes:
- ./.n8n:/home/node/.n8n
image: n8nio/n8n
restart: unless-stopped
```
In the above file, the only two things you may want to change are:
<div dir="auto" id="bkmrk-the-left-side-of-the">1. the left side of the port mapping. If your host machine (the machine / server you are running docker on) has port 5678 already in use, then change the left side port to a port number that is not in use on your host. Otherwise, feel free to leave it as 5678.
2. The WEBHOOK\_URL value should be changed to either your hosts private IP address on your local network (LAN), or to the domain / subdomain you want to use for yoru n8n instance. NOTE: You should own the domain name you intend to use.
</div>Now, we can run our docker-compose file with the command
`docker-compose up -d`
If you want to see logging of the output of your container as it starts use the command:
`docker-compose logs -f` after you see the 'done' message from the `docker-compose up -d` command.
I like to run them in a single line like this:
`docker-compose up -d && docker-compose logs -f`
This way I get to see the log output immediately after the container is finished starting.
To exit the logs, use the hotkey combination:
`CTRL + C`
### Test your Install
You can now open your favorite modern browser and go to the LAN ip address of your host, and port 5678 to see that the n8n startup screen loads.
In my case I went to `http://192.168.10.42:5678`
If you don't want / need / intend to run n8n from outside your local network, then you can just continue to use your system as it is now.
If, however, you do want to have access to your n8n system, then you'll want to set it to use a domain / sub-domain. For that we need to setup a reverse proxy.
I used NGinX Proxy Manager, but feel free to use any reverse prosy you like.
### Setting Up a Reverse Proxy
If you used my script to install docker and docker-compose, then you also had the option to install NGinX Proxy Manager. If you didn't do it initially, not to worry, just re-run the script, and this time choose 'y' when asked about NGinX Proxy Manager, and it should be installed and started. You'll want to go in, and change the defaults set in the compose file, then restart it for security. Make sure you forward ports 80 and 443 to your NGinX Proxy Manager host machine's IP address in your router.
Now, open the UI for NPM, and let's cretae our reverse proxy. You can call your site url anything you want as long as you own the domain / sub-domain you are using.
I called mine `auto.routemehome.org`.
Type that into your url field, then press tab. Next, move to the IP field, and enter the IP address of your host machine for n8n. If you are running n8n on the same docker install as NPM, then you can use the docker0 IP address as well.
If you setup NPM and n8n to run on the same docker network (a little mroe advnced, but definitely do-able), you can refer to n8n by container name instead of IP - note: these cannot be on the default network).
Now in the port field enter 5678 (or whatever you changed the left side of the port mapping to in the compose file).
Tick the options for "Block Common Exploits" and "Websocket Support",t hen click 'Save'.
Test your new entry and make sure the page loads as expected. If not, open it up in edit mode, and check for mistakes. if you don't find any, ensure you have an A-record pointing to your external IP, that you ISP doesn't blcok access to port 80 and / or 443, and that you ahve setup your port-forwarding properly in your router. At the very least, you should see the generic NGinx Proxy Manager 'Congratulations' page.
If everything worked, let's get your SSL certificate. Open the NPM item in edit mode by clicking the 3-dots at the right, and selecting 'Edit' from the drop-down list.
Move to the 'SSL' tab, and click the drop-down that says 'None'. Select, request a new certificate, then tick the box for 'Force SSL', and the item for 'Accept the LetsEncrpt Terms of Service', and make sure your email is filled in.
Click 'Save' and be patient as LetsEncrypt challenges your domain and issues an SSL certificate. If the Edit pop-up closes with no errors, test your site again, and you should now be accessing your n8n site with SSL.
Congratulations, you can start making workflows on n8n!
Make sure to check out the video at the top of this article for all the cool things you can do with n8n.
---
<div class="text-muted text-small" id="bkmrk--2"><div class="entity-meta">
</div></div>
@@ -0,0 +1,317 @@
---
tags:
- Documentation
- Bookstack
- Notes
---
# NGinX Proxy Manager
# Install and Setup NGinX Proxy Manager
#
<iframe height="336" src="https://www.youtube.com/embed/RBVcnxTiIL0" width="600"></iframe>
### What's NginX?
NginX (pronounced Engine-X) is a web-server, and reverse proxy. Basically, it can serve up web pages, and can provide a proxy service for incoming web requests. It all sounds a bit generic, but that's because it is. NginX can serve web pages, but can also direct requests for Web pages, Web Services, and Web Applications to the right place. Essentially, it's a hub and router. It receives a request for any number of web services, and routes the requests to the proper location.
NginX in and of itself, if configured through the terminal in configuration files. It's not pretty, it's not overly difficult, but you definitely have to have a good feel for all of the options that can be set.
NginX Proxy Manager is a nice Graphical User Interface (GUI) for the user to utilize vs. having to edit and create a bunch of configurations.
### Workflow of NginX Proxy Manager
When you want to route a user to a specific web page or site, NginX is a great tool for the job. NginX will listen on your server, and once it receives a request, will route the request to the appropriate service, server, page, or application.
#### Clarification of the term "Router"
I need to be clear about something here. NginX is not an application router. Many applications use routers to move you from page, or portion of a page or application, to another. These are application level routers. Also, NginX is not a hardware router, like the one on your home network that routes all of your network traffic to various machines, smart devices, etc.
NginX is a Proxy Router. It acts as a proxy for the requested web page or site, and forwards that request on to the appropriate site on your server, then returns the response information to the browser.
#### Workflow Continued
Requests for websites come into a server on a standard port (generaly 80 or 443). When those requests are received, NginX will parse the request by name, and look through it's configuration files to see if any of them match for the request being made.
If I request `fixitdelrio.com`, NginX will look for a configuration file that tells it what to do with requests for that site. If it finds a match it will then use the other information in that confiuration to push that request along to the appropriate server or service.
The configuration might tell NginX, "Hey, when you see `fixitdelrio.com`, send it to the IP 10.20.30.40 please." So, since we asked so nicely, NginX does as requested.
For another site being run on the same server, like `opensourceisawesome.com`, NginX will send the request along to the same IP, but a different port. While we make the request on the standard port 80, NginX knows that really that site is running on port 24356, and has in it's confguration file to push our request along to 10.20.30.40:24356. Thus, we ask for `opensourceisawesome.com`, and don't have to know it's running on a special port.
### What about SSL and Encryption?
NginX can also deal with SSL and Encryption, and can be quite helpful with it as well.
If I want to run `lubbocklug.org` on https instead of http, I can use NginX to help me do that. I can use NginX-Proxy-Manager to tell the request for http://lubbocklug.org to always force the requestor over to https://lubbocklug.org, thus they never go to my site without encryption.
This is huge in today's world of unethical hackers. Protecting our users is one of the most important steps we can take as self-hosters.
## Okay, I'm tired of the Intro...tell me how to do it.
Information sourced from [https://nginxproxymanager.com/setup/](https://nginxproxymanager.com/setup/)
First, you want to install Docker. Docker CE (Community Edition) is a wonderful tool that uses a very lightweight virtualisation engine to run applications, web sites, and services. You can hose many containers (a virtualized application server) on a single Docker install.
Instructions for Installing Docker CE will vary from Operating System to Operating System, so it will be better if you Google "[How to Install Docker CE](https://www.google.com/search?source=hp&ei=dAu8XrCmI4GwsAWSibuIAg&q=How+to+Install+Docker+CE&oq=How+to+Install+Docker+CE&gs_lcp=CgZwc3ktYWIQAzICCAAyAggAMgIIADICCAAyAggAMgIIADICCAAyAggAMgIIADICCAA6BQgAEIMBUM0JWJonYN0uaABwAHgAgAGIAogBixeSAQcxMS4xMS4ymAEAoAEBqgEHZ3dzLXdpeg&sclient=psy-ab&ved=0ahUKEwiwsK6ujbHpAhUBGKwKHZLEDiEQ4dUDCAg&uact=5)" and find the best instructions for your OS.
Once you have Docker installed, you will want to install NginX Proxy Manager. This part is fairly straight-forward, so let's look at how it's done.
#### docker-compose.yml
Next, we need a docker-copose.yml (pronounced yamuhl) file. This file tells docker what images to pull, what containers to start, what to call them, how they connect to each other if there is more than one, and all kinds of other information. It's, again, pretty straight-forward, so let's jump into it.
Still in our `nginx_proxy_manager` folder, we now want to create a file called `docker-compose.yml`. So enter the command
`nano docker-compose.yml`
Copy the code below using CTRL+C (Win, Linux, Unix) or CMD+C (MacOS).
```
version: '3.8'
services:
app:
image: 'jc21/nginx-proxy-manager:latest'
restart: unless-stopped
ports:
- '80:80'
- '81:81'
- '443:443'
volumes:
- ./data:/data
- ./letsencrypt:/etc/letsencrypt
```
Now paste the text into the blank text editor window. Use CTRL+Shift+V for Linux, Unix, Win; and usse CMD+V for MacOS.
Again, we need to edit come values in this file. We want a couple of these values to match the values we changed in our config.json. Using your arrow keys move down to the section titled `# environment:`. Under that section you need to either remove the `#` symbol in front of the second line, or remove this entire section (3 lines).
I suggest if you are not going to use IPv6, then make that section look like this.
```
environment:
# Uncomment this if IPv6 is not enabled on your host
DISABLE_IPV6: 'true'
```
If you intend to use IPv6, then change `true` to `false`, and ensure it's still surrounded by single quotes '.
Now use your arrow keys to move down to the section titled `db:`. Below it, we want to chagne three values.
First let's change the value for MYSQL\_ROOT\_PASSWORD. We, again, want to make this a strong, but different password from the config file earlier.
After that, change the MYSQL\_USER value to match what we entered in our config.json file for "user", and our MYSQL\_PASSWORD value to match what we entered in our config.json file for "password".
Once those changes are made, save the file with CTRL+O, then press Enter / Return. Next press CTRL+X to exit the nano editor.
#### Start the NginX Proxy Manager
Finally, we will use our docker-compose.yml file to fetch the docker images, and start our containers (yep, there are 2 conttainers - 1 for NginX Proxy Manager, and 1 for the MySql database for configs).
In the same terminal window, enter the command:
`docker-compose up -d`
if your user is not part of the `docker ` group, you may have to use
`sudo docker-compose up -d`
Then, enter your sudo password when prompted.
If all goes well, you should be able to browse to your server URL or IP address on port 81 to see the NginX-Proxy-Manager admin portal.
something like `http://opensourceisawesome.com:81` &lt; of course using your own domain or IP.
If you see the admin portal, congratulations! You've got it setup! Now NginX is listening on port 80 and port 443 for web-requests.
The next part is setting up various sites for NginX to proxy.
### Proxying Site Traffic with NGinX Proxy Manager
Now that NGinX Proxy Manager is up and running, let's setup a site. Click on 'Proxy Hosts' on the dashboard. The card will likely have a 0, and the view will be empty, or should, so we need to add a new host.
<div dir="auto" id="bkmrk-dashboard-view"><figure class="kg-card kg-image-card kg-card-hascaption" id="bkmrk-dashboard-view-1">![](http://shownotes.opensourceisawesome.com/content/images/2020/05/NProxyMan-1.png)<figcaption>Dashboard View</figcaption></figure></div>Now click on the 'Add Proxy Host' button on the upper right of the Proxy Hosts view.
<div dir="auto" id="bkmrk--1"><figure class="kg-card kg-image-card" id="bkmrk--2">![](http://shownotes.opensourceisawesome.com/content/images/2020/05/NProxyMan-2.png)</figure></div>You should see a modal (pop-up) window like the one below.
<div dir="auto" id="bkmrk-add-proxy-host-modal"><figure class="kg-card kg-image-card kg-card-hascaption" id="bkmrk-add-proxy-host-modal-1">![](http://shownotes.opensourceisawesome.com/content/images/2020/05/NproxyMan_3-AddProxyHost.png)<figcaption>Add Proxy Host Modal Window</figcaption></figure></div>Enter the domain name you want NGinX to listen for in the "Domain Name" field. Domain names should be entered wtihout http or https on the front. so only enter something like `billybobsbassboatsandboots.com` or if you are listening for a subdomain `inventory.billybobsbassboatsandboots.com`
Next, enter the hostname or IP address of the server where the site you entered in the previous step is running. Finally, enter the port number on which that site is listening / hosting it's traffic. If you're using Docker to host these sites, then you can see any port mapping using the `docker ps` or `sudo docker ps` command.
Click 'Save'.
If all goes well, the modal (pop-up) window will close, and you should see an entry in your Proxy Hosts view.
Now you can click on the domain name to have it open in a new tab. If everything is setup properly, you should see your web site.
### But what about SSL?
SSL is absolutely an option, and pretty easy to get setup with NginX Proxy Manager. You do have to make sure that you've setup your domain to be reached on port 80. Don't get confused. The port you entered in the last step above, does not need to be 80, but the Domain Name you entered should not have a port added on the end of it...that's all it means.
Essentially, you need to be able to get to `billybobsbassboatandboots.com` without having to add a specific port number. So we don't want to have to do `billybobsbassboatandboots.com:11232` or anything.
Once you are sure that your site comes up on port 80, you'll want to click on the three vertical dot icon at the right end of the line with your domain on it.
<div dir="auto" id="bkmrk-click-the-3-dot-menu"><figure class="kg-card kg-image-card kg-card-hascaption" id="bkmrk-click-the-3-dot-menu-1">![](http://shownotes.opensourceisawesome.com/content/images/2020/05/NProxyMan-5-edit.png)<figcaption>Click the 3-dot Menu Option</figcaption></figure></div>Select 'Edit' from the menu that is shown, and we'll edit our NginX entry. In the modal (pop-up) window, we want to move to the second tab "Custom Locations". In this section we just want to re-type the same domain name we entered on the first tab, but in the 'Location' field.
Next, click the drop-down menu under 'Scheme', and select "https". Now enter the IP or Hostname address of the server we are proxying the traffic to (usually the same as what we entered on the first tab as well. Finally, enter the port you mapped to 443 in the Port field.
Now we want to move to the third tab, "SSL". Here you want to click where it says "None", and select "Request a new SSL Certificate". If you want to force users to always go to the secure version of your site (which you almost always do), turn on the switch next to the "Force SSL" option.
Now enter your email address into the email field, and turn on the option next to "I agree to the LetsEncrypt Terms of Service".
<div dir="auto" id="bkmrk-options-to-request-a"><figure class="kg-card kg-image-card kg-card-hascaption" id="bkmrk-options-to-request-a-1">![](http://shownotes.opensourceisawesome.com/content/images/2020/05/Request-ssl-NPorxyMan.png)<figcaption>Options to Request a LetsEncrypt SSL Certificate for your site.</figcaption></figure></div>Now click "Save". It may take a minute or so, but if you are returned to the Proxy Hosts view, and no errors are displayed, then your site should now be available on https.
## Conclusion
This process of proxying traffic through a single endpoint, is useful for controlling not only the traffic to and from your home or server, but also for allowing you to run multiple web-sites / hosts on a single server install.
Repeat the above steps for each site you are hosting, and over time you'll get a full list of sites being proxied by NginX. You can add custom options as you become more familiar with NginX right inside the Edit modal as well (tab 4).
I hope this is helpful to you, and please subscribe to my channel so you'll know when I release new Open Source, Self-hosted videos.
---
<div class="text-muted text-small" id="bkmrk--4"><div class="entity-meta">
</div></div>
# Securing NGinX Proxy Manager
#
<iframe height="336" src="https://www.youtube.com/embed/UfCkwlPIozw" width="600"></iframe>
I've covered NGinX Proxy Manager, a web GUI for NGinX Web Server in multiple videos. I essentially use it anytime I want to give a web site a public URL with Ssl encryption (so basically always).
One of the questions I get fairly often is about how to Secure the admin portal of NGinX Proxy Manager itself. So, in this video I go through the actions with securing the Admin Portal and show you how you can also use the tools in NPM to secure your various self hosted web sites and web applications with even more than just their respective login screens.
## Installing NGinX Proxy Manager
Again, I've discussed this, and done this in multiple videos, as well as in multiple posts on this site, but let me cover it again here, so you're not jumping around looking for bits and pieces.
To install NPM you need to install docker and docker-compose, and create a new folder on the server you want to run it in. Next, you'll create two files inside that folder:
<div dir="auto" id="bkmrk-config.json-docker-c">- config.json
- docker-compose.yml
</div>Inside the config.json file, you'll put the following:
```
{
"database": {
"engine": "mysql",
"host": "db",
"name": "npm",
"user": "<your desired username>",
"password": "<a strong password>",
"port": 3306
}
}
```
And inside the docker-compose.yml file you'll put:
```
version: '3'
services:
app:
image: 'jc21/nginx-proxy-manager:latest'
ports:
- '80:80'
- '81:81'
- '443:443'
volumes:
- ./config.json:/app/config/production.json
- ./data:/data
- ./letsencrypt:/etc/letsencrypt
db:
image: 'jc21/mariadb-aria:10.4'
environment:
MYSQL_ROOT_PASSWORD: 'npm'
MYSQL_DATABASE: 'npm'
MYSQL_USER: '<username from config.json>'
MYSQL_PASSWORD: '<strong password from config.json>'
volumes:
- ./data/mysql:/var/lib/mysql
```
Make sure to replace the items with &lt; and &gt; around it in each file, and that the username and passwords in each file match.
Now run the command:
`docker-compose up -d`
Give it a minute to pull down everything, and get started, and then in your browser go to the IP address of your server. You should get a Congratulations screen.
if you go tot he IP address at port 81 ([http://192.168.1.x:81](http://192.168.1.x:81)), you'll be prompted to login to NPM.
Default credentials are:
username: <a>admin@example.com</a>
passwrod: changeme
Make sure to update the email and password, from the default values, then log out, and back in usign the new values you entered.
Now, you're ready to start proxying traffic.
## Securing NGinX Proxy Manger Admin Console
The simples and most direct way is to secure NPM to itself. Yep, you just make a loop so that when you ask for a specific URL that you'll have created an A Record for, you get your NGinX Proxy Manager install will proxy the traffic to it's port 81 admin console.
Let's add a new Host entry, and on the dtails page enter the URL you want to use to access the admin console.
In my case, I called it "manage" and created an A Record to point to my public IP address, which is port forwarded 80, 443 to my NPM server.
In my Details tab, I'll enter "manage.example.com" (replace example.com with your domain of course).
Next, enter the IP address of your docker0 interface. You can find this with either:
`ifconfig`
or
`ip addr show docker0`
Next, enter 81 for the port number.
Turn on the "Block Common Exploits" option, and Save.
We Save now so we can test it and make sure we are routed properly to our Admin login page. This is still unencrypted, so don't log in, but make suer you get to the Admin login page by visiting your URL.
If you get to the page successfully, you can go back to NPM via the IP nad Port, and click the 3 dot icon at the right end of your 'manage' row. Select 'Edit' andn move to the 'SSL' tab.
Choose "Request a New Certificate" from the first dropdown.
Turn on "Force SSL".
Fill in your email address. LetsEnctrypt uses this to let you know if your Certificates have issues or will expire soon and haven't been renewed.
Select to 'Accept the Terms of Service'.
Click 'Save'.
Now, attempt again, to reach your URL. You should be routed to an SSL encrypted site, and you can now login to your Admin console.
## What About Keeping the Rest of the Internet Out?
Yep, you just created a publicly accessible URL for your NPM admin console. Not to fear. You can still secure it further. Go to the "Access Lists" tab, and create a new Access List.
Give your new List a name, and then move to the Authorization tab. Enter as many emails and passwords for users you want to have access to the site. If you want to restrict to http basic auth, then save, and close your browser (Note: you may have to clear your cache). Then, re-open, and visit your site, and you should get a prompt for Credentials before you get to the main login screen of NPM itself.
Want more than just basic authentication?
You can also add public IP addresses that will be allowed to access the site. Edit your Access List, and move to the Access tab. Enter yoru public IP address, then try to access the site from a machine not on your LAN, and you'll find you won't be able to.
Now, let's say you want to access the site with one or the other, Username and passsword, or Public IP. Then on the Details tab of your Access List, and enable the option for 'Satisfy Any'. This makes it so either User or IP will be allowed. When this is disabled, then you must have both User credentials and be on an allowed Public IP.
### Conclusion
You have amazing open source tools at your fingertips, and making them more secure is highly recommended. Please use the tools and capabilities to run securely.
---
<div class="text-muted text-small" id="bkmrk--2"><div class="entity-meta">
</div></div>
+108
View File
@@ -0,0 +1,108 @@
---
tags:
- Documentation
- Bookstack
- Notes
---
# Obsidian
# Setup
Here is a clean, professional, and well-structured Markdown guide for your Obsidian Self-Hosted LiveSync documentation.
I have organized the configuration into logical, step-by-step technical phases, cleaned up syntax formatting (such as fixing case sensitivity in commands like `docker exec`), and added visual callouts for important warnings and credentials.
# Obsidian Self-Hosted LiveSync Configuration Guide
This guide details the deployment of a self-hosted CouchDB instance using Docker Compose and the generation of configuration URIs to enable cross-device synchronization for Obsidian.
## 1. Prerequisites
- A reverse proxy (e.g., Nginx Proxy Manager, Cloudflare Tunnels, or Caddy) configured to route external traffic to your container.
- SSL/TLS certificate configured for your sync domain: `https://obsidian.mikemcfetridge.com`
## 2. Database Deployment (Docker Compose)
Deploy the specialized CouchDB image tailored for Obsidian LiveSync. Create a `docker-compose.yml` file in your directory and add the service definition below:
<div class="code-block ng-tns-c1605810258-88 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" id="bkmrk-yaml"><div class="formatted-code-block-internal-container ng-tns-c1605810258-88"><div class="animated-opacity ng-tns-c1605810258-88"><div class="code-block-decoration header-formatted gds-emphasized-body-m ng-tns-c1605810258-88 ng-star-inserted"><span class="ng-tns-c1605810258-88">YAML</span><div class="buttons ng-tns-c1605810258-88 ng-star-inserted"></div></div></div></div></div>```
services:
couchdb-obsidian-livesync:
image: 'docker.io/oleduc/docker-obsidian-livesync-couchdb:master'
container_name: couchdb-obsidian-livesync
restart: always
ports:
- '5984:5984'
environment:
- COUCHDB_DATABASE=obsidian
- COUCHDB_USER=miker
- COUCHDB_PASSWORD=tw9222dvO91ZHb
- SERVER_DOMAIN=https://obsidian.mikemcfetridge.com
volumes:
- ./data:/opt/couchdb/data
```
<div class="code-block ng-tns-c1605810258-88 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" id="bkmrk--1"><div class="formatted-code-block-internal-container ng-tns-c1605810258-88"><div class="animated-opacity ng-tns-c1605810258-88"></div></div></div>### Deployment Verification
1. Launch the container stack in detached mode:
<div class="code-block ng-tns-c1605810258-89 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation"><div class="formatted-code-block-internal-container ng-tns-c1605810258-89"><div class="animated-opacity ng-tns-c1605810258-89"><div class="code-block-decoration header-formatted gds-emphasized-body-m ng-tns-c1605810258-89 ng-star-inserted"><span class="ng-tns-c1605810258-89">Bash</span><div class="buttons ng-tns-c1605810258-89 ng-star-inserted"></div></div></div></div></div>```
docker compose up -d
```
<div class="code-block ng-tns-c1605810258-89 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation"><div class="formatted-code-block-internal-container ng-tns-c1605810258-89"><div class="animated-opacity ng-tns-c1605810258-89"></div></div></div>
2. Validate that the CouchDB instance is active and accessible via the web administration console by navigating to: `https://obsidian.mikemcfetridge.com/_utils`
## 3. Generate the Client Setup URI
To easily provision your desktop and mobile clients, log into the running container environment to generate an encrypted initialization URI using Deno.
### Step 1: Open an Interactive Terminal in the Container
<div class="code-block ng-tns-c1605810258-90 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" id="bkmrk-bash"><div class="formatted-code-block-internal-container ng-tns-c1605810258-90"><div class="animated-opacity ng-tns-c1605810258-90"><div class="code-block-decoration header-formatted gds-emphasized-body-m ng-tns-c1605810258-90 ng-star-inserted"><span class="ng-tns-c1605810258-90">Bash</span><div class="buttons ng-tns-c1605810258-90 ng-star-inserted"></div></div></div></div></div>```
docker exec -it couchdb-obsidian-livesync /bin/bash
```
<div class="code-block ng-tns-c1605810258-90 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" id="bkmrk--4"><div class="formatted-code-block-internal-container ng-tns-c1605810258-90"><div class="animated-opacity ng-tns-c1605810258-90"></div></div></div>### Step 2: Configure Environment Variables &amp; Run the Generator Script
Paste the following block into the container terminal to set up the runtime environment and execute the configuration tool:
<div class="code-block ng-tns-c1605810258-91 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" id="bkmrk-bash-1"><div class="formatted-code-block-internal-container ng-tns-c1605810258-91"><div class="animated-opacity ng-tns-c1605810258-91"><div class="code-block-decoration header-formatted gds-emphasized-body-m ng-tns-c1605810258-91 ng-star-inserted"><span class="ng-tns-c1605810258-91">Bash</span><div class="buttons ng-tns-c1605810258-91 ng-star-inserted"></div></div></div></div></div>```
export hostname=https://obsidian.mikemcfetridge.com
export database=obsidian
export username=miker
export password=tw9222dvO91ZHb
export passphrase=7ixpCPi5OEDF6J
# Execute the setup URI generator script
deno run -A https://raw.githubusercontent.com/vrtmrz/obsidian-livesync/main/utils/flyio/generate_setupuri.ts
```
<div class="code-block ng-tns-c1605810258-91 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" id="bkmrk--7"><div class="formatted-code-block-internal-container ng-tns-c1605810258-91"><div class="animated-opacity ng-tns-c1605810258-91"></div></div></div>### Step 3: Capture the Output
The script will output your specific **Setup-URI Passphrase** and the **Obsidian configuration string**.
> ⚠️ **Important:** The text passphrase generated by the script will **never** be shown again. Save it immediately in a secure location.
*Example Output:*
<div class="code-block ng-tns-c1605810258-92 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" id="bkmrk-plaintext"><div class="formatted-code-block-internal-container ng-tns-c1605810258-92"><div class="animated-opacity ng-tns-c1605810258-92"><div class="code-block-decoration header-formatted gds-emphasized-body-m ng-tns-c1605810258-92 ng-star-inserted"><span class="ng-tns-c1605810258-92">Plaintext</span><div class="buttons ng-tns-c1605810258-92 ng-star-inserted"></div></div></div></div></div>```
Your passphrase of Setup-URI is: little-shadow
obsidian://setuplivesync?settings=%25dcc45454e4eda1f3feb43f050100000041732c3c957c9bac41a96df3040ab6b5uEIf1EWiXa%2BgGabAhHBCF9wkHfvj%2BwSfHlZOctmyUYdDfqwkIfbibE4yge9uNaARqtixj4OZH9XZs3S4cjRclUNvpZiqsq46SOniGB9X2Svk58HFcwfNaW67mNQLQn2cSWRwvN9SudeqVWiLjWKczz6DWBcYGwwsyO%2BLxnw86txKZBC6yE2AaY%2B2dz%2F0qWQBZaxh%2FCJWjxPyRGewUhfUbZnuLQmtu0RY%2FfYgVQQZ%2FNvzmmUpSrpFeJq%2BYP%2F3V1w9PmVNSiDo62a9rnWjjBpk0ffQGxuNEb36Tu9i%2BrRKROnz4T3nsOX6IWZJd4WhuljboUsz9dKHwcNSsDFyNDFx3XMPcjaFO1%2BcMulxP8zJh%2BS3p%2BNrvg5kdsM0%2BGsg%2F29mMUnbFXXETdIAX62Jb%2FhuuRaOy0Cwjccpg02tpXc6HGj7tZCXh1fh4EPNUK09QmkzDOtIcb33yva%2FMNCzY9cVr0TCLr2MVLlnRR9P1sQkGCDTqI0NJvG1B0FvGE3XASBQpCKQH1XnED0z5IFsTH4m8gjHbR2XtDaTbFqNA%2BL9cGjztPXKa0g8xD0mruF5uH1zCp0sELD%2Fghw%2FsXUYcCPt7gmVryU9ioFzjRVt7UTexFpr50ZPOfOfVwfy3FCHk4lCNDREeHdstj2EI19lyBL4NyVuIt5%2FqE%2FaOib04ZefjsTETB%2F7rdbblwebgD1Il%2FWPjtL3uKyxiM11W6pUQtXiT7CvoXfu3rf9K5%2FihFjiomY08xYb60Q1LyIjhG1SIB%2BsvS7Vc9qzyGFW1JdQUEWz3IFpX7QVuk1ZX2uovJiAqwD4eTp0xIUXPNLmeTbQ0rFeKd8yYR6DpMLejkWedW9x%2FxL0q62yvlXsOuAKhQLOgPRQ3A%3D%3D
```
<div class="code-block ng-tns-c1605810258-92 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" id="bkmrk--10"><div class="formatted-code-block-internal-container ng-tns-c1605810258-92"><div class="animated-opacity ng-tns-c1605810258-92"></div></div></div>## 4. Client Plugin Provisioning
Repeat these final configuration steps across each device (Desktop, Mobile, or Tablet) you intend to synchronize.
1. **Install Plugin:** Ensure the community plugin **Self-hosted LiveSync** is installed and enabled inside your Obsidian client.
2. **Import Settings:** Open the Obsidian Command Palette (`Ctrl+P` or `Cmd+P`), choose **Self-hosted LiveSync: Use the copied setup URI**, and paste your full `obsidian://setuplivesync?settings=...` string.
3. **Authenticate:** Provide the setup-uri text passphrase generated in Section 3 when prompted.
4. **Initialize:** Click **Yes** when prompted to initiate the storage sync configuration sequence. Select **Keep them disabled** during the initial sync dialogue if you wish to configure sync intervals manually later.
5. **Finalize:** Reload the Obsidian application to apply and activate the synchronization backend.
+99
View File
@@ -0,0 +1,99 @@
---
tags:
- Documentation
- Bookstack
- Notes
---
# Personal
# Miker's Resume
Since you are operating at the executive GS-15 level within the Federal government, I have tailored the language to heavily emphasize **strategic leadership, multi-million dollar budgetary oversight, policy enforcement, and technical governance** while structuring the layout to be instantly scannable for both senior leadership reviewers and automated ATS systems.
# MICHAEL E. MCFETRIDGE
**Bealeton, VA 22712** | **202-870-2233** | **mmcfetridg@aol.com** **Clearance:** Department of Homeland Security Customs and Border Protection: **Active Secret**
## PROFESSIONAL SUMMARY
Highly accomplished Executive IT Program/Project Manager and Section Chief with over 20 years of comprehensive experience leading enterprise-level Data Center Operations, Cloud/Infrastructure migrations, and 24x7 Mission-Critical Systems. Proven track record at the GS-15 level managing multi-disciplinary engineering teams, driving federal IT modernization initiatives, and executing high-value technical strategies. Expert in aligning data center priorities with agency objectives, translating highly complex architectures into actionable executive briefs, and driving robust ITSM/ITIL and Cybersecurity frameworks.
## CORE COMPETENCIES
- **Executive Leadership:** Data Center Operations, Section/Branch Management, High-Value Staffing &amp; Coaching, Multi-million Dollar Budgetary Forecasting.
- **Project &amp; Quality Management:** PMI PMBOK, CMMI, Agile (Scrum Master/Product Owner), CBP System Life-Cycle Handbook, Plan of Action &amp; Milestones (POA&amp;M).
- **Infrastructure &amp; Operations:** Proxmox (PVE), Enterprise Data Center Relocation, zLinux Mainframe Migration, Active Directory, Server Blade/SAN Architectures, Disaster Recovery (DR/BCO).
- **Networking &amp; Core Services:** LAN/WAN, VPN, VLAN, MPLS, DHCP/WINS, Technitium/Pi-hole DNS Services, Enterprise Messaging Infrastructure.
- **Cybersecurity &amp; Compliance:** NIST Framework Compliance, System Security Plans (SSP), Certification &amp; Accreditation (C&amp;A), Authority to Operate (ATO) Lifecycles.
## PROFESSIONAL EXPERIENCE
### U.S. Customs and Border Protection | Springfield, VA
**Program/Project Manager, Data Center Operations** *(August 2015 Present)* *GS-2210-15 | Current Salary: $127,036 | Supervisor: Mike Newell, Branch Chief (703-921-6595)*
#### Enterprise Data Center Operations Branch — Section Chief *(Feb 2018 Present)*
- **Personnel &amp; Resource Leadership:** Direct a senior team of 30+ Federal employees and contractors, defining short- and long-term operating strategies across multiple geographical locations.
- **Strategic Architecture &amp; Engineering:** Manage multiple specialized infrastructure engineering sections tasked with bare-metal/virtual server installations, automated OS provisioning, and complex infrastructure optimization.
- **Executive Governance:** Represent the Data Center Operations group at the IT Change Management Board; capture and report performance baselines, technical metrics, and milestone status directly to agency leadership.
- **Talent Cultivation:** Direct all staffing operations including hiring, resource scheduling, performance evaluations, and the formal creation of Individual Development Plans (IDP).
#### Enterprise Operations Center (EOC) — Watch Commander (Acting) *(Dec 2016 Feb 2018)*
- **24x7 Operational Monitoring:** Commanded complex enterprise monitoring environments to guarantee total application availability and strict Service Level Objective (SLO) compliance.
- **Incident Lifecycle Standardization:** Architected and institutionalized a unified enterprise incident management and alarm-escalation playbook for EOC Watch Officers.
- **Root Cause Analysis (RCA):** Designed formal RCA protocols to map systemic infrastructure dependencies, isolate cross-layer failures, and author actionable remediation training blueprints.
#### Data Center Operations Branch — Branch Chief (TDY Acting) *(Oct 2016 Dec 2016)*
- **Budgetary Stewardship:** Exercised ultimate oversight over branch hardware, software, and workforce allocations.
- **Senior Briefings:** Authored and presented strategic briefs to the Chief Information Officer (CIO) regarding controversial technical matters and mitigation blueprints.
- **Security Risk Management:** Managed critical security vectors, executing Plans of Action and Milestones (POA&amp;M) to systematically remediate infrastructure vulnerabilities.
#### Platform Engineering Branch — Branch Chief (120-Day TDY) *(Jan 2015 May 2015)*
- **Enterprise Architecture:** Partnered with the Chief Technology Officer (CTO) to plan and evaluate scalable, agency-wide target architectures to achieve compliance with federal mandates.
- **Modernization Roadmap:** Managed system engineering cohorts evaluating emerging technologies to lower the agency's total cost of ownership.
#### Data Center Relocation — Project / Program Manager *(Jul 2013 Aug 2015)*
- **Enterprise Email Migration:** Spearheaded a high-visibility $7M Email-as-a-Service enhancement initiative, seamlessly migrating 70K+ production accounts over to the Department of Homeland Security (DHS) Data Center.
- **Capital Investment Analysis:** Developed comprehensive business cases, capital planning models, and statements of work (SOW) to ensure strict vendor compliance with target procurement schedules.
#### Windows Server Group — Government Lead *(Jun 2008 Jul 2013)*
- **Scale-Out Deployments:** Coordinated a 12-member engineering team in designing and scaling a high-availability server farm housing over 1,300 servers under a 100% uptime baseline.
- **Security Authorization:** Authored detailed System Security Plans (SSP) utilizing NIST guidelines, coordinating directly with ISSOs to obtain strict Authorities to Operate (ATO).
### Digital Solutions Inc.
**Network Systems Administrator / Engineer** *(2000 2008)*
- **Commodity Server Administration:** Spearheaded Tier-3 administration, patching (WSUS), and storage provisioning (SAN) for a farm of 400+ Windows/Novell servers supporting mission-critical systems (ATS, US VISIT, SAP).
- **Directory Consolidation:** Successfully migrated and consolidated 23 legacy NT 4.0 domains into a singular, unified Windows Server Active Directory domain architecture using advanced migration toolkits.
- **Disaster Recovery Engineering:** Formulated a comprehensive backup/recovery strategy that verified a 72-hour system restore threshold at the remote CBP secondary recovery site.
### CACI, Inc.
**System / Network Engineer** *(1996 2000)*
- **Infrastructure Engineering:** Designed, installed, and tuned Windows Server infrastructures, configuring key DHCP, WINS, and IIS web services.
- **Deployment Documentation:** Authored standardized, rigorous engineering guides mapping deployment methodologies across custom federal installations.
## EDUCATION &amp; CERTIFICATIONS
### Education &amp; Academic Certificates
- **Masters Certificate in Program Management** George Washington University (2009)
- **High School Diploma** Annandale High School (1988)
### Professional Certifications &amp; Training
- **Certified ScrumMaster (CSM)** | **Certified Scrum Product Owner (CSPO)**
- **ITIL v3 Foundation &amp; Practitioner** (IT Infrastructure Library)
- **Supervisory Leadership Training (SLT) Program** US CBP (2016)
- **Microsoft Certified Systems Engineer (MCSE)** (1999)
- **CCNA Training** Global Knowledge (2003)
- **Symantec Veritas NetBackup Enterprise 6.0** Training (2006)
- **Microsoft Active Directory and Network Infrastructure** Training (2007)
+395
View File
@@ -0,0 +1,395 @@
---
tags:
- Documentation
- Bookstack
- Notes
---
# Scripts
# Universal Linux install script
You nailed it! That is exactly how everything pieces together.
I see only two very minor things in the final version you pasted that could use a quick tweak before you run it live:
1. **The Leftover Note:** At the bottom of your Arch section, you still have the old echo lines saying *"Note: AirVPN (eddie-ui) requires the AUR... install it later via: yay -S eddie-ui"*. Since the script now installs `yay` and runs that command automatically right above it, you can safely remove those lines so it doesn't give you a confusing warning.
2. **`set -e` Risk with Flatpak:** At the very top, we have `set -e` enabled, which forces the script to crash and stop if *any* command fails. Flatpak can sometimes return a non-zero exit code if an application is *already* installed or partially skips. To prevent the script from stopping right at the very end over a harmless Flatpak message, we can append `|| true` to the flatpak command.
Here is the 100% clean, finalized version ready for your `/usr/local/bin` or dotfiles repository:
<div class="code-block ng-tns-c2069566202-467 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" id="bkmrk-bash"><div class="formatted-code-block-internal-container ng-tns-c2069566202-467"><div class="animated-opacity ng-tns-c2069566202-467"><div class="code-block-decoration header-formatted gds-emphasized-body-m ng-tns-c2069566202-467 ng-star-inserted"><span class="ng-tns-c2069566202-467">Bash</span><div class="buttons ng-tns-c2069566202-467 ng-star-inserted"></div></div></div></div></div>```
#!/bin/sh
set -e # Exit immediately if a command exits with a non-zero status
# 1. OS DETECTION & VARIABLES
CURRENT_USER=$(whoami)
USER_HOME="/home/$CURRENT_USER"
if [ -f /etc/os-release ]; then
. /etc/os-release
DISTRO_NAME=$ID
else
echo "Cannot determine OS distribution. /etc/os-release missing."
exit 1
fi
echo "Starting deployment script for user: $CURRENT_USER on $DISTRO_NAME"
# 2. SHARED TASKS (Runs on both systems)
echo "-----------------------------------------------"
echo "Resetting SSH directory permissions..."
echo "-----------------------------------------------"
if [ -d "$USER_HOME/.ssh" ]; then
chmod 700 "$USER_HOME/.ssh"
if ls "$USER_HOME/.ssh"/*.pub > /dev/null 2>&1; then
chmod 644 "$USER_HOME/.ssh"/*.pub
fi
if [ -f "$USER_HOME/.ssh/id_rsa" ]; then
chmod 600 "$USER_HOME/.ssh/id_rsa"
fi
fi
# 3. DISTRO SPECIFIC APPLICATIONS
if [ "$DISTRO_NAME" = "ubuntu" ] || [ "$DISTRO_NAME" = "debian" ]; then
echo "-----------------------------------------------"
echo "Running Ubuntu/Debian Setup Tasks"
echo "-----------------------------------------------"
# Prerequisite updates
sudo apt update && sudo apt install -y curl wget git gpg software-properties-common ca-certificates
# AirVPN Eddie repository
curl -fsSL https://eddie.website/repository/keys/eddie_maintainer_gpg.key | sudo tee /usr/share/keyrings/eddie.website-keyring.asc > /dev/null
echo "deb [signed-by=/usr/share/keyrings/eddie.website-keyring.asc] http://eddie.website/repository/apt stable main" | sudo tee /etc/apt/sources.list.d/eddie.website.list
# Eza repository
sudo mkdir -p /etc/apt/keyrings
wget -qO- https://raw.githubusercontent.com/eza-community/eza/main/deb.asc | sudo gpg --dearmor -o /etc/apt/keyrings/gierens.gpg
echo "deb [signed-by=/etc/apt/keyrings/gierens.gpg] http://deb.gierens.de stable main" | sudo tee /etc/apt/sources.list.d/gierens.list
sudo chmod 644 /etc/apt/keyrings/gierens.gpg /etc/apt/sources.list.d/gierens.list
# Fastfetch PPA
sudo add-apt-repository -y ppa:zhangsongcui3371/fastfetch
# Refresh and Bulk Install Native APT Apps
sudo apt update
sudo apt install -y \
eddie-ui eza fastfetch bat zsh build-essential autoconf make \
libssl-dev htop blender vlc filezilla inotify-tools fzf \
docker-compose ansible zsh-autosuggestions zsh-syntax-highlighting flatpak
# Snap fallback for Alacritty
sudo apt install -y snapd
sudo snap install alacritty --classic
# Cleanup
sudo apt upgrade -y && sudo apt autoremove -y && sudo apt autoclean -y
elif [ "$DISTRO_NAME" = "arch" ]; then
echo "-----------------------------------------------"
echo "Running Arch Linux Setup Tasks"
echo "-----------------------------------------------"
sudo pacman -Syu --noconfirm
# Native Arch Equivalents
sudo pacman -S --noconfirm --needed \
curl wget git bat zsh base-devel openssl ca-certificates \
htop blender vlc filezilla inotify-tools eza fzf docker-compose \
ansible zsh-autosuggestions zsh-syntax-highlighting flatpak fastfetch alacritty
# Automated Yay Installation
if ! command -v yay >/dev/null 2>&1; then
echo "-----------------------------------------------"
echo "Installing YAY (AUR Helper)..."
echo "-----------------------------------------------"
YAY_BUILD_DIR=$(mktemp -d)
git clone https://aur.archlinux.org/yay-bin.git "$YAY_BUILD_DIR"
# Build and install as user
(cd "$YAY_BUILD_DIR" && makepkg -si --noconfirm)
rm -rf "$YAY_BUILD_DIR"
else
echo "yay is already installed. Skipping..."
fi
# Use Yay for AirVPN Eddie
echo "-----------------------------------------------"
echo "Installing AirVPN Eddie via AUR..."
echo "-----------------------------------------------"
yay -S --noconfirm eddie-ui
fi
# 4. UNIVERSAL INDEPENDENT BINARIES
echo "-----------------------------------------------"
echo "Installing Zoxide..."
echo "-----------------------------------------------"
curl -sSfL https://raw.githubusercontent.com/ajeetdsouza/zoxide/main/install.sh | sh
# Configure shell scripts safely
for rc in ".zshrc" ".bashrc"; do
if [ -f "$USER_HOME/$rc" ]; then
shell_name=$(echo "$rc" | sed 's/\.//;s/rc//')
if ! grep -q "zoxide init $shell_name" "$USER_HOME/$rc"; then
echo "eval \"\$(zoxide init $shell_name)\"" >> "$USER_HOME/$rc"
fi
fi
done
echo "-----------------------------------------------"
echo "Installing Starship..."
echo "-----------------------------------------------"
curl -sS https://starship.rs/install.sh | sh -s -- -y
echo "-----------------------------------------------"
echo "Installing Powerlevel10k..."
echo "-----------------------------------------------"
if [ ! -d "$USER_HOME/powerlevel10k" ]; then
git clone --depth=1 https://github.com/romkatv/powerlevel10k.git "$USER_HOME/powerlevel10k"
fi
if [ -f "$USER_HOME/.zshrc" ]; then
if ! grep -q "powerlevel10k.zsh-theme" "$USER_HOME/.zshrc"; then
echo "source ~/powerlevel10k/powerlevel10k.zsh-theme" >> "$USER_HOME/.zshrc"
fi
fi
# 5. FLATPAK APPLICATIONS
echo "-----------------------------------------------"
echo "Installing Flatpak Applications..."
echo "-----------------------------------------------"
flatpak remote-add --if-not-exists flathub https://dl.flathub.org/repo/flathub.flatpakrepo
# Appending '|| true' ensures the script finishes even if Flatpak encounters minor warnings
flatpak install -y flathub \
com.obsproject.Studio \
org.tenacityaudio.Tenacity \
md.obsidian.Obsidian \
org.gimp.GIMP \
com.github.zadam.trilium \
com.spotify.Client \
io.github.shiftey.Desktop \
com.brave.Browser \
com.visualstudio.code \
org.qbittorrent.qBittorrent \
org.wezfurlong.wezterm || true
echo "-----------------------------------------------"
echo "Deployment Complete! Please restart your terminal."
echo "-----------------------------------------------"
```
<div class="code-block ng-tns-c2069566202-467 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" id="bkmrk--1"><div class="formatted-code-block-internal-container ng-tns-c2069566202-467"><div class="animated-opacity ng-tns-c2069566202-467"></div></div></div>Save this to a file (like `setup.sh`), make it executable with `chmod +x setup.sh`, and you are ready to distro-hop completely friction-free!
# BASH Files for Arch
The good news is that most of your configuration is already compatible with **Arch Linux**! Bash is Bash, regardless of the distribution.
However, Arch is a "minimalist" rolling release, so the main differences lie in **package names** and **binary locations**. I've identified a few spots where your current scripts assume a Debian/Ubuntu-like environment (e.g., specific paths like `/usr/bin/starship`).
Here is the "Arch-optimized" version of your files with the necessary corrections.
## 1. `.bashrc`
**Key Changes:**
- **Pathing:** Changed `/usr/bin/starship` to a simple `command -v` check. On Arch, binaries are usually in `/usr/bin/`, but it's safer to let the shell find them.
- **Initialization:** Cleaned up the double `eval` at the bottom (you had `starship` and `zoxide` mashed together).
- **Safety:** Added checks for `fzf` and `zoxide`.
<div class="code-block ng-tns-c2069566202-494 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" id="bkmrk-bash"><div class="formatted-code-block-internal-container ng-tns-c2069566202-494"><div class="animated-opacity ng-tns-c2069566202-494"><div class="code-block-decoration header-formatted gds-emphasized-body-m ng-tns-c2069566202-494 ng-star-inserted"><span class="ng-tns-c2069566202-494">Bash</span><div class="buttons ng-tns-c2069566202-494 ng-star-inserted"></div></div></div></div></div>```
# If not running interactively, don't do anything
case $- in
*i*) ;;
*) return;;
esac
# Load fastfetch (Ensure 'fastfetch' is installed via pacman)
if command -v fastfetch &> /dev/null; then
fastfetch
fi
# Starship Prompt Logic
if command -v starship &> /dev/null; then
eval "$(starship init bash)"
else
echo "Starship not found. Install with: sudo pacman -S starship"
fi
# History Settings
HISTCONTROL=ignoreboth
shopt -s histappend
HISTSIZE=20000
HISTFILESIZE=10000
shopt -s checkwinsize
shopt -s cmdhist
# Lesspipe (On Arch, install 'lesspipe' from AUR or use the core version)
[ -x /usr/bin/lesspipe.sh ] && eval "$(SHELL=/bin/sh /usr/bin/lesspipe.sh)"
# Load Aliases and Functions
[[ -f ~/.bash_aliases ]] && . ~/.bash_aliases
[[ -f ~/.bash_functions ]] && . ~/.bash_functions
# Bash Completion (Arch path)
if ! shopt -oq posix; then
if [ -f /usr/share/bash-completion/bash_completion ]; then
. /usr/share/bash-completion/bash_completion
fi
fi
# Default Editor
export EDITOR='nano'
# FZF (Install via: sudo pacman -S fzf)
if command -v fzf &> /dev/null; then
eval "$(fzf --bash)"
fi
# LM Studio Path
export PATH="$PATH:$HOME/.lmstudio/bin"
# Zoxide (Install via: sudo pacman -S zoxide)
if command -v zoxide &> /dev/null; then
eval "$(zoxide init bash)"
fi
# Cargo/Rust
[[ -f "$HOME/.cargo/env" ]] && . "$HOME/.cargo/env"
# Auto-ls on cd
cd() {
builtin cd "$@" && ls -lA
}
```
<div class="code-block ng-tns-c2069566202-494 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" id="bkmrk--1"><div class="formatted-code-block-internal-container ng-tns-c2069566202-494"><div class="animated-opacity ng-tns-c2069566202-494"></div></div></div>## 2. `.bash_aliases`
**Key Changes:**
- **Netstat:** Arch uses `iproute2` by default. `netstat` is part of `net-tools` (deprecated). I updated the alias to use `ss`, which is the modern Arch way, but kept the name `ports`.
- **Typo Fix:** Fixed `lias addup` to `alias addup`.
- **Eza:** Ensure you run `sudo pacman -S eza` first.
<div class="code-block ng-tns-c2069566202-495 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" id="bkmrk-bash-1"><div class="formatted-code-block-internal-container ng-tns-c2069566202-495"><div class="animated-opacity ng-tns-c2069566202-495"><div class="code-block-decoration header-formatted gds-emphasized-body-m ng-tns-c2069566202-495 ng-star-inserted"><span class="ng-tns-c2069566202-495">Bash</span><div class="buttons ng-tns-c2069566202-495 ng-star-inserted"></div></div></div></div></div>```
# EZA Aliases
alias ls='eza --all --long --group --group-directories-first --icons --header --time-style long-iso'
alias l='eza -lahF --icons --sort=size --group-directories-first'
alias lss='eza -hF --icons --sort=size --group-directories-first'
alias la='eza -ahF --icons --sort=size --group-directories-first'
alias lst='eza -lahT --icons --sort=size --group-directories-first'
alias lt='eza -aT --icons --group-directories-first --sort=size'
# Navigation
alias ..='cd ..'
alias ...='cd ../../../'
alias ....='cd ../../../../'
alias .4='cd ../../../../'
alias .5='cd ../../../../..'
# Disk Usage
alias used='du -sch .[!.]* * 2>/dev/null | sort -h'
alias totalusage='df -hl --total | grep total'
alias partusage='df -hlT --exclude-type=tmpfs --exclude-type=devtmpfs'
alias most='du -hsx * | sort -rh | head -10'
alias mnt="mount | awk -F' ' '{ printf \"%s\t%s\n\",\$1,\$3; }' | column -t | grep ^/dev/ | sort"
# System Tools
alias c='clear'
alias h='history'
alias path='echo -e ${PATH//:/\\n}'
alias ports='ss -tulanp' # Modern Arch replacement for netstat
alias jctl="journalctl -p 3 -xb"
# Power Management
alias reboot='sudo reboot'
alias poweroff='sudo poweroff'
# Git Aliases
alias addup='git add -u'
alias addall='git add .'
alias branch='git branch'
alias checkout='git checkout'
alias stat='git status'
alias commit='git commit -m'
alias push='git push origin'
alias pull='git pull origin'
# Apps
alias n=nano
alias sn='sudo nano'
alias bashrc="nano ~/.bashrc && source ~/.bashrc"
```
<div class="code-block ng-tns-c2069566202-495 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" id="bkmrk--4"><div class="formatted-code-block-internal-container ng-tns-c2069566202-495"><div class="animated-opacity ng-tns-c2069566202-495"></div></div></div>## 3. `.bash_functions`
**Key Changes:**
- **xtract:** Added a check for `7z` (p7zip) vs `unzip`.
- **Prompt Logic:** Your `set_bash_prompt` was being overwritten by `starship` in the `.bashrc`. If you use Starship, you don't actually need the `set_bash_prompt` or `git_branch` functions anymore—Starship handles that much more efficiently. I've left them here just in case you want to toggle Starship off.
<div class="code-block ng-tns-c2069566202-496 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" id="bkmrk-bash-2"><div class="formatted-code-block-internal-container ng-tns-c2069566202-496"><div class="animated-opacity ng-tns-c2069566202-496"><div class="code-block-decoration header-formatted gds-emphasized-body-m ng-tns-c2069566202-496 ng-star-inserted"><span class="ng-tns-c2069566202-496">Bash</span><div class="buttons ng-tns-c2069566202-496 ng-star-inserted"></div></div></div></div></div>```
# Extract archives
xtract() {
if [ -z "$1" ]; then
echo "Usage: xtract <archive>"
else
case "$1" in
*.tar.bz2|*.tbz2|*.tbz) tar xvjf "$1" ;;
*.tgz|*.tar.gz) tar xvf "$1" ;;
*.tar.xz|*.txz) tar xvJf "$1" ;;
*.tar) tar xvf "$1" ;;
*.rar) unp "$1" ;; # Install 'unp' or use 7z
*.zip) unzip "$1" ;;
*.7z) 7z x "$1" ;;
*) echo "Sorry, '$1' could not be decompressed." ;;
esac
fi
}
# Go up N directories
up(){
local d=""
limit=${1:-1}
for ((i=1 ; i <= limit ; i++)); do d=$d/..; done
d=$(echo $d | sed 's/^\///')
cd "$d"
}
# Create and enter dir
mkcd() {
mkdir -p "$1" && cd "$1"
}
# External IP
myip() {
curl -s https://ifconfig.me
}
# Colored Man Pages
man() {
LESS_TERMCAP_md=$'\e[1;31m' \
LESS_TERMCAP_me=$'\e[0m' \
LESS_TERMCAP_se=$'\e[0m' \
LESS_TERMCAP_so=$'\e[1;44;33m' \
LESS_TERMCAP_ue=$'\e[0m' \
LESS_TERMCAP_us=$'\e[1;32m' \
command man "$@"
}
```
<div class="code-block ng-tns-c2069566202-496 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" id="bkmrk--7"><div class="formatted-code-block-internal-container ng-tns-c2069566202-496"><div class="animated-opacity ng-tns-c2069566202-496"></div></div></div>### Arch Linux Checklist
To make sure all these aliases work, run this command to install the necessary dependencies:
<div class="code-block ng-tns-c2069566202-497 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" id="bkmrk-bash-3"><div class="formatted-code-block-internal-container ng-tns-c2069566202-497"><div class="animated-opacity ng-tns-c2069566202-497"><div class="code-block-decoration header-formatted gds-emphasized-body-m ng-tns-c2069566202-497 ng-star-inserted"><span class="ng-tns-c2069566202-497">Bash</span><div class="buttons ng-tns-c2069566202-497 ng-star-inserted"></div></div></div></div></div>```
sudo pacman -S starship fastfetch eza fzf zoxide bat p7zip unzip
```
<div class="code-block ng-tns-c2069566202-497 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" id="bkmrk--10"><div class="formatted-code-block-internal-container ng-tns-c2069566202-497"><div class="animated-opacity ng-tns-c2069566202-497"></div></div></div>*(Note: `bat` is used in your `finddoc` alias, and `eza` is used for all your `ls` replacements.)*
@@ -0,0 +1,123 @@
---
tags:
- Documentation
- Bookstack
- Notes
---
# Server Hardening & Security Baseline
# Ubuntu Server Hardening & Security Baseline
A comprehensive guide to securing a fresh Ubuntu Server installation for production or home-lab deployment.
## Phase 1: Initial System Updates &amp; Hostname
Always ensure the repository lists and core software dependencies are fully up to date before making configuration changes.
<div class="code-block ng-tns-c1605810258-137 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" id="bkmrk-bash"><div class="formatted-code-block-internal-container ng-tns-c1605810258-137"><div class="animated-opacity ng-tns-c1605810258-137"><div class="code-block-decoration header-formatted gds-emphasized-body-m ng-tns-c1605810258-137 ng-star-inserted"><span class="ng-tns-c1605810258-137">Bash</span><div class="buttons ng-tns-c1605810258-137 ng-star-inserted"></div></div></div></div></div>```
# Update package lists and upgrade all system software
sudo apt update && sudo apt upgrade -y
# Set a clean, fully qualified domain name (FQDN) hostname
sudo hostnamectl set-hostname your-server-name
```
<div class="code-block ng-tns-c1605810258-137 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" id="bkmrk--1"><div class="formatted-code-block-internal-container ng-tns-c1605810258-137"><div class="animated-opacity ng-tns-c1605810258-137"></div></div></div>## Phase 2: Secure User Management
Never run applications directly as the root user. Create a dedicated administrative user with sudo privileges and lock down root access.
### 1. Create a Sudo User
<div class="code-block ng-tns-c1605810258-138 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" id="bkmrk-bash-1"><div class="formatted-code-block-internal-container ng-tns-c1605810258-138"><div class="animated-opacity ng-tns-c1605810258-138"><div class="code-block-decoration header-formatted gds-emphasized-body-m ng-tns-c1605810258-138 ng-star-inserted"><span class="ng-tns-c1605810258-138">Bash</span><div class="buttons ng-tns-c1605810258-138 ng-star-inserted"></div></div></div></div></div>```
# Create the new administrative user
sudo adduser sysadmin
# Add the user to the sudo group
sudo usermod -aG sudo sysadmin
```
<div class="code-block ng-tns-c1605810258-138 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" id="bkmrk--4"><div class="formatted-code-block-internal-container ng-tns-c1605810258-138"><div class="animated-opacity ng-tns-c1605810258-138"></div></div></div>### 2. Disable the Root Password &amp; Active Shell
<div class="code-block ng-tns-c1605810258-139 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" id="bkmrk-bash-2"><div class="formatted-code-block-internal-container ng-tns-c1605810258-139"><div class="animated-opacity ng-tns-c1605810258-139"><div class="code-block-decoration header-formatted gds-emphasized-body-m ng-tns-c1605810258-139 ng-star-inserted"><span class="ng-tns-c1605810258-139">Bash</span><div class="buttons ng-tns-c1605810258-139 ng-star-inserted"></div></div></div></div></div>```
# Lock the root user account
sudo passwd -l root
```
<div class="code-block ng-tns-c1605810258-139 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" id="bkmrk--7"><div class="formatted-code-block-internal-container ng-tns-c1605810258-139"><div class="animated-opacity ng-tns-c1605810258-139"></div></div></div>## Phase 3: SSH Hardening (Targeted `/etc/ssh/sshd_config`)
Enforce cryptographic authentication over passwords and close common remote exploit vectors.
1. Generate an SSH Keypair on your local machine (if you haven't already):
<div class="code-block ng-tns-c1605810258-140 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation"><div class="formatted-code-block-internal-container ng-tns-c1605810258-140"><div class="animated-opacity ng-tns-c1605810258-140"><div class="code-block-decoration header-formatted gds-emphasized-body-m ng-tns-c1605810258-140 ng-star-inserted"><span class="ng-tns-c1605810258-140">Bash</span><div class="buttons ng-tns-c1605810258-140 ng-star-inserted"></div></div></div></div></div>```
ssh-keygen -t ed25519 -b 521 -C "admin-key"
```
<div class="code-block ng-tns-c1605810258-140 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation"><div class="formatted-code-block-internal-container ng-tns-c1605810258-140"><div class="animated-opacity ng-tns-c1605810258-140"></div></div></div>
2. Copy the key to your server:
<div class="code-block ng-tns-c1605810258-141 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation"><div class="formatted-code-block-internal-container ng-tns-c1605810258-141"><div class="animated-opacity ng-tns-c1605810258-141"><div class="code-block-decoration header-formatted gds-emphasized-body-m ng-tns-c1605810258-141 ng-star-inserted"><span class="ng-tns-c1605810258-141">Bash</span><div class="buttons ng-tns-c1605810258-141 ng-star-inserted"></div></div></div></div></div>```
ssh-copy-id -i ~/.ssh/id_ed25519.pub sysadmin@YOUR_SERVER_IP
```
<div class="code-block ng-tns-c1605810258-141 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation"><div class="formatted-code-block-internal-container ng-tns-c1605810258-141"><div class="animated-opacity ng-tns-c1605810258-141"></div></div></div>
3. Edit the SSH Daemon Configuration (`sudo nano /etc/ssh/sshd_config.d/hardening.conf`):
<div class="code-block ng-tns-c1605810258-142 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation"><div class="formatted-code-block-internal-container ng-tns-c1605810258-142"><div class="animated-opacity ng-tns-c1605810258-142"><div class="code-block-decoration header-formatted gds-emphasized-body-m ng-tns-c1605810258-142 ng-star-inserted"><span class="ng-tns-c1605810258-142">Ini, TOML</span><div class="buttons ng-tns-c1605810258-142 ng-star-inserted"></div></div></div></div></div>```
# Enforce modern, secure SSH configurations
Port 22 # Change to a custom port (e.g., 2222) to stop automated bot sweeps
PermitRootLogin no # Drop direct root login capabilities completely
PasswordAuthentication no # Disable password authentication; enforce SSH Keys only
PubkeyAuthentication yes # Explicitly permit public key authentication
X11Forwarding no # Disable GUI forwarding to reduce attack surface
MaxAuthTries 3 # Limit authentication attempts per connection drop
ClientAliveInterval 300 # Disconnect idle sessions after 5 minutes
ClientAliveCountMax 0 # Enforce explicit logout when idle threshold met
```
<div class="code-block ng-tns-c1605810258-142 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation"><div class="formatted-code-block-internal-container ng-tns-c1605810258-142"><div class="animated-opacity ng-tns-c1605810258-142"></div></div></div>
4. Validate the syntax and restart the daemon:
<div class="code-block ng-tns-c1605810258-143 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation"><div class="formatted-code-block-internal-container ng-tns-c1605810258-143"><div class="animated-opacity ng-tns-c1605810258-143"><div class="code-block-decoration header-formatted gds-emphasized-body-m ng-tns-c1605810258-143 ng-star-inserted"><span class="ng-tns-c1605810258-143">Bash</span><div class="buttons ng-tns-c1605810258-143 ng-star-inserted"></div></div></div></div></div>```
sudo sshd -t
sudo systemctl restart ssh
```
<div class="code-block ng-tns-c1605810258-143 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation"><div class="formatted-code-block-internal-container ng-tns-c1605810258-143"><div class="animated-opacity ng-tns-c1605810258-143"></div></div></div>
## Phase 4: Firewall Configuration (UFW)
Implement a strict "default-deny" inbound network posture using the Uncomplicated Firewall.
<div class="code-block ng-tns-c1605810258-144 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" id="bkmrk-bash-3"><div class="formatted-code-block-internal-container ng-tns-c1605810258-144"><div class="animated-opacity ng-tns-c1605810258-144"><div class="code-block-decoration header-formatted gds-emphasized-body-m ng-tns-c1605810258-144 ng-star-inserted"><span class="ng-tns-c1605810258-144">Bash</span><div class="buttons ng-tns-c1605810258-144 ng-star-inserted"></div></div></div></div></div>```
# Set default firewall rules
sudo ufw default deny incoming
sudo ufw default allow outgoing
# Allow your specific SSH port (Match the port set in Phase 3)
sudo ufw allow 22/tcp
# (Optional) Allow Web traffic if hosting applications
sudo ufw allow 80/tcp
sudo ufw allow 443/tcp
# Enable the firewall
sudo ufw enable
sudo ufw status verbose
```
<div class="code-block ng-tns-c1605810258-144 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" id="bkmrk--10"><div class="formatted-code-block-internal-container ng-tns-c1605810258-144"><div class="animated-opacity ng-tns-c1605810258-144"></div></div></div>## Phase 5: Automated Security Patching
Install `unattended-upgrades` to guarantee that critical security vulnerabilities are patched automatically without requiring manual sysadmin intervention.
<div class="code-block ng-tns-c1605810258-145 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" id="bkmrk-bash-4"><div class="formatted-code-block-internal-container ng-tns-c1605810258-145"><div class="animated-opacity ng-tns-c1605810258-145"><div class="code-block-decoration header-formatted gds-emphasized-body-m ng-tns-c1605810258-145 ng-star-inserted"><span class="ng-tns-c1605810258-145">Bash</span><div class="buttons ng-tns-c1605810258-145 ng-star-inserted"></div></div></div></div></div>```
# Install the upgrade package tool
```
@@ -0,0 +1,57 @@
---
tags:
- Documentation
- Bookstack
- Notes
---
# Troubleshooting
# Create Directory structure with subdirectories
It looks like your Git client (likely GitAhead, GitHub Desktop, or a similar GUI tool) ran into a credential roadblock while trying to clone that repository. Since you're dealing with a `Docker-Boilerplates` repo, getting this sorted quickly so you can deploy is the priority.
Here is how to troubleshoot and fix this, depending on how you connect to GitHub.
## 1. The Most Common Fix: Personal Access Tokens (HTTPS)
If you are cloning via **HTTPS** (a URL starting with `https://github.com/...`), GitHub **no longer accepts your standard account password** for Git operations.
### Step 1: Generate a PAT on GitHub
<div class="container" id="bkmrk-go-to-your-github-ac"><div class="markdown markdown-main-panel tutor-markdown-rendering enable-luminous-fast-follows stronger enable-updated-hr-color" dir="ltr">1. Go to your GitHub account **Settings** &gt; **Developer Settings** &gt; **Personal Access Tokens** (Tokens classic).
2. Click **Generate new token**.
3. Give it a descriptive name (e.g., "Homelab Desktop") and select the **`repo`** scope (this gives full control of private repositories).
4. Click **Generate token** and **copy it immediately** (you won't see it again).
</div></div>### Step 2: Use it in your Git Client
When your Git GUI prompts you for your password during the retry, **paste the PAT instead of your actual GitHub password**.
## 2. The SSH Route (If you use `git@github.com:...`)
If you are cloning via **SSH**, GitHub doesn't use passwords at all. Instead, it relies on your local SSH key.
<div class="container" id="bkmrk-check-your-active-ke"><div class="markdown markdown-main-panel tutor-markdown-rendering enable-luminous-fast-follows stronger enable-updated-hr-color" dir="ltr">- **Check your active keys:** Open a terminal and run `ssh-add -l` to see if your private key is loaded into your SSH agent.
- **Add your key:** If it isn't listed, add it using:
<div class="code-block ng-tns-c2069566202-321 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation"><div class="formatted-code-block-internal-container ng-tns-c2069566202-321"><div class="animated-opacity ng-tns-c2069566202-321"><div class="code-block-decoration header-formatted gds-emphasized-body-m ng-tns-c2069566202-321 ng-star-inserted"><span class="ng-tns-c2069566202-321">Bash</span><div class="buttons ng-tns-c2069566202-321 ng-star-inserted"></div></div></div></div></div>```
ssh-add ~/.ssh/id_ed25519
```
<div class="code-block ng-tns-c2069566202-321 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation"><div class="formatted-code-block-internal-container ng-tns-c2069566202-321"><div class="animated-opacity ng-tns-c2069566202-321"></div></div></div>*(Replace `id_ed25519` with the actual name of your private key file).*
- **Verify connection:** Test your connection to GitHub directly via terminal:
<div class="code-block ng-tns-c2069566202-322 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation"><div class="formatted-code-block-internal-container ng-tns-c2069566202-322"><div class="animated-opacity ng-tns-c2069566202-322"><div class="code-block-decoration header-formatted gds-emphasized-body-m ng-tns-c2069566202-322 ng-star-inserted"><span class="ng-tns-c2069566202-322">Bash</span><div class="buttons ng-tns-c2069566202-322 ng-star-inserted"></div></div></div></div></div>```
ssh -T git@github.com
```
<div class="code-block ng-tns-c2069566202-322 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation"><div class="formatted-code-block-internal-container ng-tns-c2069566202-322"><div class="animated-opacity ng-tns-c2069566202-322"></div></div></div>If it says *"Hi \[YourUsername\]! You've successfully authenticated..."*, your SSH setup is perfect, and the issue is just your Git GUI not pointing to the correct key.
</div></div>## 3. Quick Sanity Checks
<div class="container" id="bkmrk-are-you-logged-in-wi"><div class="markdown markdown-main-panel tutor-markdown-rendering enable-luminous-fast-follows stronger enable-updated-hr-color" dir="ltr">- **Are you logged in within the app?** If this is a GUI like GitAhead or GitHub Desktop, go to **File &gt; Options (or Preferences) &gt; Accounts** and verify your GitHub account is actively signed in. If it is, **log out and log back in** to force a token refresh.
- **Repository Permissions:** Double-check that the repository actually exists at that exact URL and that your account hasn't lost access (or that it hasn't been archived by the owner).
</div></div><div class="container" id="bkmrk-"><div class="markdown markdown-main-panel tutor-markdown-rendering enable-luminous-fast-follows stronger enable-updated-hr-color" dir="ltr" id="bkmrk--1"></div></div>
@@ -0,0 +1,668 @@
---
tags:
- Documentation
- Bookstack
- Notes
---
# Web Application Firewall (WAF)
# SOCFortess
# SOCFortress Docs
# WAF Management Platform
<div class="markdown-heading" dir="auto" id="bkmrk-">[<svg aria-hidden="true" class="octicon octicon-link" data-component="Octicon" height="16" version="1.1" viewbox="0 0 16 16" width="16"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg>](https://github.com/socfortress/waf-platform-public/blob/main/README.md#waf-management-platform)</div>Self-hosted Web Application Firewall with a modern admin UI. Powered by **Caddy + Coraza** (OWASP Core Rule Set v4) as the WAF engine, a **FastAPI** management API, and a **React** dashboard.
This repository contains everything you need to **run** the platform from prebuilt container images — no source build required.
## 📺 Watch the demo
<div class="markdown-heading" dir="auto" id="bkmrk--2">[<svg aria-hidden="true" class="octicon octicon-link" data-component="Octicon" height="16" version="1.1" viewbox="0 0 16 16" width="16"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg>](https://github.com/socfortress/waf-platform-public/blob/main/README.md#-watch-the-demo)</div>Deploy the WAF, get automatic TLS, block live attacks, and tune a false positive — in about 10 minutes:
[![Watch the demo on YouTube](https://camo.githubusercontent.com/e252a2d7b4fd9ab6ea64ec33e7a5aa5d60623d081c9740023f5a10fe5a944c01/68747470733a2f2f696d672e796f75747562652e636f6d2f76692f5a766a66505850335833302f6d617872657364656661756c742e6a7067)](https://youtu.be/ZvjfPXP3X30)
---
## Architecture
<div class="markdown-heading" dir="auto" id="bkmrk--6">[<svg aria-hidden="true" class="octicon octicon-link" data-component="Octicon" height="16" version="1.1" viewbox="0 0 16 16" width="16"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg>](https://github.com/socfortress/waf-platform-public/blob/main/README.md#architecture)</div>```
Internet
┌─────────────────────┐ ┌──────────────────────────┐
│ Caddy + Coraza │ ───► │ Your protected upstream │
│ WAF engine (80/443) │ │ app(s) │
└─────────────────────┘ └──────────────────────────┘
▲ (Admin API 2019, container-internal only)
┌─────────────────────┐ ┌────────────┐ ┌─────────┐
│ FastAPI Admin API │ ◄─►│ PostgreSQL │ │ Redis │
│ (8000, internal) │ └────────────┘ └─────────┘
└─────────────────────┘
┌─────────────────────┐
│ React Admin UI │ ← you log in here: https://localhost:8443
│ (Nginx, 8443 HTTPS) │
└─────────────────────┘
```
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" id="bkmrk--8"><div class="zeroclipboard-container"><svg aria-hidden="true" class="octicon octicon-copy js-clipboard-copy-icon" data-component="Octicon" data-view-component="true" height="16" version="1.1" viewbox="0 0 16 16" width="16"></svg></div></div>---
## Features
<div class="markdown-heading" dir="auto" id="bkmrk--10">[<svg aria-hidden="true" class="octicon octicon-link" data-component="Octicon" height="16" version="1.1" viewbox="0 0 16 16" width="16"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg>](https://github.com/socfortress/waf-platform-public/blob/main/README.md#features)</div>- **Caddy + Coraza WAF** with the OWASP Core Rule Set v4, in detection or blocking mode per site.
- **Site management** — front any number of upstream apps behind the WAF.
- **CRS &amp; custom rules** — tune the ruleset, add custom rules, manage false-positive exclusions from the UI.
- **Authentication** with TOTP 2FA and role-based access control.
- **Log viewer** — searchable, PostgreSQL-backed request/blocking logs with GeoIP enrichment.
- **Alerting** — email notifications on configurable conditions.
---
## Quick start
<div class="markdown-heading" dir="auto" id="bkmrk--13">[<svg aria-hidden="true" class="octicon octicon-link" data-component="Octicon" height="16" version="1.1" viewbox="0 0 16 16" width="16"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg>](https://github.com/socfortress/waf-platform-public/blob/main/README.md#quick-start)</div>### Prerequisites
<div class="markdown-heading" dir="auto" id="bkmrk--15">[<svg aria-hidden="true" class="octicon octicon-link" data-component="Octicon" height="16" version="1.1" viewbox="0 0 16 16" width="16"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg>](https://github.com/socfortress/waf-platform-public/blob/main/README.md#prerequisites)</div>- Docker ≥ 24 and Docker Compose ≥ 2.20
- 2 GB RAM minimum
- Ports **80**, **443**, and **8443** available on the host
- A free **MaxMind GeoLite2** license key (see [GeoIP setup](https://github.com/socfortress/waf-platform-public/blob/main/README.md#geoip-setup))
### 1. Get this repo
<div class="markdown-heading" dir="auto" id="bkmrk--17">[<svg aria-hidden="true" class="octicon octicon-link" data-component="Octicon" height="16" version="1.1" viewbox="0 0 16 16" width="16"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg>](https://github.com/socfortress/waf-platform-public/blob/main/README.md#1-get-this-repo)</div>```
git clone https://github.com/socfortress/waf-platform-public.git waf-platform
cd waf-platform
cp .env.example .env
```
<div class="highlight highlight-source-shell notranslate position-relative overflow-auto" dir="auto" id="bkmrk--19"><div class="zeroclipboard-container"><svg aria-hidden="true" class="octicon octicon-copy js-clipboard-copy-icon" data-component="Octicon" data-view-component="true" height="16" version="1.1" viewbox="0 0 16 16" width="16"></svg></div></div>### 2. Configure `.env`
<div class="markdown-heading" dir="auto" id="bkmrk--20">[<svg aria-hidden="true" class="octicon octicon-link" data-component="Octicon" height="16" version="1.1" viewbox="0 0 16 16" width="16"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg>](https://github.com/socfortress/waf-platform-public/blob/main/README.md#2-configure-env)</div>Edit `.env` and replace every `CHANGE_ME` value:
<table id="bkmrk-variable-purpose-how"><thead><tr><th>Variable</th><th>Purpose</th><th>How to generate</th></tr></thead><tbody><tr><td>`POSTGRES_PASSWORD`</td><td>Database password</td><td>`openssl rand -hex 32`</td></tr><tr><td>`SECRET_KEY`</td><td>JWT signing key</td><td>`python3 -c "import secrets; print(secrets.token_hex(32))"`</td></tr><tr><td>`TOTP_ENCRYPTION_KEY`</td><td>TOTP secret encryption</td><td>`python3 -c "from cryptography.fernet import Fernet; print(Fernet.generate_key().decode())"`</td></tr><tr><td>`BOOTSTRAP_ADMIN_EMAIL`</td><td>First superadmin email</td><td>Any valid email</td></tr><tr><td>`BOOTSTRAP_ADMIN_PASSWORD`</td><td>First superadmin password</td><td>Strong password — **change after first login**</td></tr><tr><td>`ALLOWED_ORIGINS`</td><td>CORS origins</td><td>`https://localhost:8443` for the default local deploy</td></tr></tbody></table>
Optional — email alerts: `SMTP_HOST`, `SMTP_PORT`, `SMTP_USER`, `SMTP_PASSWORD`, `SMTP_FROM`.
Optional — pin a version: set `WAF_IMAGE_TAG` to a release tag (e.g. `v1.0.0`) instead of `latest`.
### 3. GeoIP setup
<div class="markdown-heading" dir="auto" id="bkmrk--22">[<svg aria-hidden="true" class="octicon octicon-link" data-component="Octicon" height="16" version="1.1" viewbox="0 0 16 16" width="16"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg>](https://github.com/socfortress/waf-platform-public/blob/main/README.md#3-geoip-setup)</div>The log viewer enriches client IPs with country/city data using MaxMind's GeoLite2 database. MaxMind's license does not allow us to redistribute it, so you supply your own (it's free):
1. Create a free account at [https://www.maxmind.com/en/geolite2/signup](https://www.maxmind.com/en/geolite2/signup).
2. Download **GeoLite2 City** (`.mmdb` format).
3. Place the file in this directory as `GeoLite2-City.mmdb`, **or** set `GEOIP_DB_PATH` in `.env` to its full path.
> The stack will start without it, but GeoIP enrichment in logs will be disabled.
### 4. Start the stack
<div class="markdown-heading" dir="auto" id="bkmrk--24">[<svg aria-hidden="true" class="octicon octicon-link" data-component="Octicon" height="16" version="1.1" viewbox="0 0 16 16" width="16"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg>](https://github.com/socfortress/waf-platform-public/blob/main/README.md#4-start-the-stack)</div>```
docker compose up -d
```
<div class="highlight highlight-source-shell notranslate position-relative overflow-auto" dir="auto" id="bkmrk--26"><div class="zeroclipboard-container"><svg aria-hidden="true" class="octicon octicon-copy js-clipboard-copy-icon" data-component="Octicon" data-view-component="true" height="16" version="1.1" viewbox="0 0 16 16" width="16"></svg></div></div>Wait until all containers report healthy (typically 3060 seconds):
```
docker compose ps
```
<div class="highlight highlight-source-shell notranslate position-relative overflow-auto" dir="auto" id="bkmrk--27"><div class="zeroclipboard-container"><svg aria-hidden="true" class="octicon octicon-copy js-clipboard-copy-icon" data-component="Octicon" data-view-component="true" height="16" version="1.1" viewbox="0 0 16 16" width="16"></svg></div></div>### 5. First login
<div class="markdown-heading" dir="auto" id="bkmrk--28">[<svg aria-hidden="true" class="octicon octicon-link" data-component="Octicon" height="16" version="1.1" viewbox="0 0 16 16" width="16"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg>](https://github.com/socfortress/waf-platform-public/blob/main/README.md#5-first-login)</div>1. Open **[https://localhost:8443](https://localhost:8443/)** (the UI uses a self-signed certificate on first boot — accept the browser warning, or upload your own cert in the UI).
2. Log in with the `BOOTSTRAP_ADMIN_EMAIL` / `BOOTSTRAP_ADMIN_PASSWORD` from `.env`.
3. **Change your password immediately** via Users → Edit.
4. Optionally enroll TOTP under Settings → Security.
---
## Protecting your app
<div class="markdown-heading" dir="auto" id="bkmrk--31">[<svg aria-hidden="true" class="octicon octicon-link" data-component="Octicon" height="16" version="1.1" viewbox="0 0 16 16" width="16"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg>](https://github.com/socfortress/waf-platform-public/blob/main/README.md#protecting-your-app)</div>A fresh install has **no sites configured** — Caddy listens on 80/443 but does not proxy anything yet (a bare request to `http://localhost/` returns an empty `200`). You configure protection from the admin UI:
1. Log in (see above) and add your upstream application as a **site**.
2. Choose **detection** mode (log only) or **blocking** mode (reject attacks).
3. The WAF then proxies and protects that site.
### Optional: verify against the bundled test upstream
<div class="markdown-heading" dir="auto" id="bkmrk--33">[<svg aria-hidden="true" class="octicon octicon-link" data-component="Octicon" height="16" version="1.1" viewbox="0 0 16 16" width="16"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg>](https://github.com/socfortress/waf-platform-public/blob/main/README.md#optional-verify-against-the-bundled-test-upstream)</div>The stack includes a throwaway `http-echo` container you can use as a target. Add a test site in **blocking** mode pointing at `http-echo:5678`, then:
```
curl http://localhost/ # → upstream-ok
curl -s -o /dev/null -w "%{http_code}\n" "http://localhost/?id=1+OR+1%3D1" # → 403 (SQLi blocked)
```
<div class="highlight highlight-source-shell notranslate position-relative overflow-auto" dir="auto" id="bkmrk--35"><div class="zeroclipboard-container"><svg aria-hidden="true" class="octicon octicon-copy js-clipboard-copy-icon" data-component="Octicon" data-view-component="true" height="16" version="1.1" viewbox="0 0 16 16" width="16"></svg></div></div>A benign request returns `200`; the SQLi probe returns `403` once the site is in blocking mode.
---
## Updating
<div class="markdown-heading" dir="auto" id="bkmrk--37">[<svg aria-hidden="true" class="octicon octicon-link" data-component="Octicon" height="16" version="1.1" viewbox="0 0 16 16" width="16"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg>](https://github.com/socfortress/waf-platform-public/blob/main/README.md#updating)</div>```
docker compose pull # fetch the latest images (or your pinned WAF_IMAGE_TAG)
docker compose up -d # recreate changed containers
```
<div class="highlight highlight-source-shell notranslate position-relative overflow-auto" dir="auto" id="bkmrk--39"><div class="zeroclipboard-container"><svg aria-hidden="true" class="octicon octicon-copy js-clipboard-copy-icon" data-component="Octicon" data-view-component="true" height="16" version="1.1" viewbox="0 0 16 16" width="16"></svg></div></div>Your data (Postgres, Redis, rules, certs) lives in named Docker volumes and survives updates.
---
## Managing the stack
<div class="markdown-heading" dir="auto" id="bkmrk--41">[<svg aria-hidden="true" class="octicon octicon-link" data-component="Octicon" height="16" version="1.1" viewbox="0 0 16 16" width="16"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg>](https://github.com/socfortress/waf-platform-public/blob/main/README.md#managing-the-stack)</div>```
docker compose ps # status
docker compose logs -f # follow logs
docker compose down # stop (volumes preserved)
docker compose down -v # stop AND delete all data volumes — destructive
```
<div class="highlight highlight-source-shell notranslate position-relative overflow-auto" dir="auto" id="bkmrk--43"><div class="zeroclipboard-container"><svg aria-hidden="true" class="octicon octicon-copy js-clipboard-copy-icon" data-component="Octicon" data-view-component="true" height="16" version="1.1" viewbox="0 0 16 16" width="16"></svg></div></div>---
## Security notes
<div class="markdown-heading" dir="auto" id="bkmrk--45">[<svg aria-hidden="true" class="octicon octicon-link" data-component="Octicon" height="16" version="1.1" viewbox="0 0 16 16" width="16"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg>](https://github.com/socfortress/waf-platform-public/blob/main/README.md#security-notes)</div>- Passwords are bcrypt-hashed; TOTP secrets are encrypted at rest.
- Secrets are read from environment variables only — never hardcoded. Keep `.env` private.
- The Caddy Admin API (port 2019) is bound inside the Docker network only; it is not exposed to the host.
- CORS is restricted to `ALLOWED_ORIGINS` — no wildcard.
- Auth endpoints are rate-limited; refresh tokens rotate on every use.
- For production, place the UI behind your own TLS termination / trusted certificate rather than the self-signed default.
---
## Support &amp; licensing
<div class="markdown-heading" dir="auto" id="bkmrk--48">[<svg aria-hidden="true" class="octicon octicon-link" data-component="Octicon" height="16" version="1.1" viewbox="0 0 16 16" width="16"><path d="m7.775 3.275 1.25-1.25a3.5 3.5 0 1 1 4.95 4.95l-2.5 2.5a3.5 3.5 0 0 1-4.95 0 .751.751 0 0 1 .018-1.042.751.751 0 0 1 1.042-.018 1.998 1.998 0 0 0 2.83 0l2.5-2.5a2.002 2.002 0 0 0-2.83-2.83l-1.25 1.25a.751.751 0 0 1-1.042-.018.751.751 0 0 1-.018-1.042Zm-4.69 9.64a1.998 1.998 0 0 0 2.83 0l1.25-1.25a.751.751 0 0 1 1.042.018.751.751 0 0 1 .018 1.042l-1.25 1.25a3.5 3.5 0 1 1-4.95-4.95l2.5-2.5a3.5 3.5 0 0 1 4.95 0 .751.751 0 0 1-.018 1.042.751.751 0 0 1-1.042.018 1.998 1.998 0 0 0-2.83 0l-2.5 2.5a1.998 1.998 0 0 0 0 2.83Z"></path></svg>](https://github.com/socfortress/waf-platform-public/blob/main/README.md#support--licensing)</div>- **License:** see [LICENSE](https://github.com/socfortress/waf-platform-public/blob/main/LICENSE).
- **Issues / questions:** open an issue on this repository.
- Commercial support is available from [SOCFortress](https://www.socfortress.co/).
# EDGE WAF - SOCFortress and NPM
I have installed SOCFortress WAF to test and compare to my current proxy which is Nginx Proxy Manager. The one area of concern that I have and cannot locate in SOCFortress is the ability to add Custom Configuration for authentik for headers. In Nginx Proxy manager, I can add this information in Custom Nginx Configuration section. Does SOCFortress allow this and if so where?
The short answer is **no, not directly in the UI** the way you are used to with Nginx Proxy Manager (NPM).
The primary reason for this is a difference in the underlying architecture: **SOCFortress WAF does not use Nginx.** <span class="citation-9">Instead, the SOCFortress WAF platform is built on top of </span>**<span class="citation-9">Caddy</span>**<span class="citation-9"> as its reverse proxy engine, combined with </span>**<span class="citation-9">Coraza</span>**<span class="citation-9 citation-end-9"> (a Go-based WAF engine) running the OWASP Core Rule Set (CRS).</span> Because it uses Caddy instead of Nginx, any native Nginx syntax or snippet you used to paste into NPM will not work here.
<div _ngcontent-ng-c405365209="" chatcontentdimensions="" class="chat-history-scroll-container lm" id="bkmrk-socfortress---medium"><div _ngcontent-ng-c405365209="" class="conversation-container message-actions-hover-boundary ng-star-inserted"><div _ngcontent-ng-c3598951857=""><div _ngcontent-ng-c3060770435="" class="response-container response-container-with-gpi ng-tns-c3060770435-20 no-background" data-hveid="1" jslog="173900;track:impression,attention"><div _ngcontent-ng-c3060770435="" class="presented-response-container ng-tns-c3060770435-20" data-hveid="2" jslog="283401;track:impression,attention"><div _ngcontent-ng-c3060770435="" class="response-container-content ng-tns-c3060770435-20 has-thoughts"><div _ngcontent-ng-c3598951857="" class="response-content ng-tns-c3060770435-20"><div _ngcontent-ng-c1922256434="" class="container"><div _ngcontent-ng-c2066222059="" aria-busy="false" aria-live="off" class="markdown markdown-main-panel enable-luminous-fast-follows enable-updated-hr-color stronger tutor-markdown-rendering" dir="ltr" inline-copy-host=""><div _ngcontent-ng-c2854609078="" class="source-inline-chip-container luminous-sources hide-from-message-actions ng-star-inserted"><div _ngcontent-ng-c2854609078="" class="source-label-container gds-body-s ng-star-inserted" dir="auto"><span class="source-title">SOCFortress - Medium</span></div></div></div></div></div></div></div></div></div></div></div>To achieve what you are trying to do for your authentik integration (forwarding headers, establishing proxy providers, or setting up forward auth), you have to approach it differently.
### How to manage this in SOCFortress WAF
Because the SOCFortress WAF UI focuses entirely on the security layer (toggling rules, managing exclusions, and GeoIP blocking) rather than deep proxy customizations, you have two primary options:
#### 1. Use Caddys Native File System (The Backend Route)
If you need to inject custom proxy headers or set up an upstream forward-auth middleware for authentik, you cannot use the UI wrapper. You must modify the underlying **Caddyfile** configuration directly.
<div _ngcontent-ng-c405365209="" chatcontentdimensions="" class="chat-history-scroll-container lm" id="bkmrk-socfortress-spins-up"><div _ngcontent-ng-c405365209="" class="conversation-container message-actions-hover-boundary ng-star-inserted"><div _ngcontent-ng-c3598951857=""><div _ngcontent-ng-c3060770435="" class="response-container response-container-with-gpi ng-tns-c3060770435-20 no-background" data-hveid="1" jslog="173900;track:impression,attention"><div _ngcontent-ng-c3060770435="" class="presented-response-container ng-tns-c3060770435-20" data-hveid="2" jslog="283401;track:impression,attention"><div _ngcontent-ng-c3060770435="" class="response-container-content ng-tns-c3060770435-20 has-thoughts"><div _ngcontent-ng-c3598951857="" class="response-content ng-tns-c3060770435-20"><div _ngcontent-ng-c1922256434="" class="container"><div _ngcontent-ng-c2066222059="" aria-busy="false" aria-live="off" class="markdown markdown-main-panel enable-luminous-fast-follows enable-updated-hr-color stronger tutor-markdown-rendering" dir="ltr" inline-copy-host="">- <span class="citation-8 citation-end-8">SOCFortress spins up via Docker Compose.</span> You will need to locate the volume or directory where the WAF platform stores its generated Caddy configuration.
<div _ngcontent-ng-c2854609078="" class="source-inline-chip-container luminous-sources hide-from-message-actions ng-star-inserted"><div _ngcontent-ng-c2854609078="" class="source-label-container gds-body-s ng-star-inserted" dir="auto"><span class="source-title">SOCFortress - Medium</span></div></div>
- Instead of Nginx directives (`proxy_set_header`), you will use Caddys `header_up` or `forward_auth` directives.
</div></div></div></div></div></div></div></div></div>#### 2. The Recommended Topology: Layer Both Tools
If you love the ease of Nginx Proxy Manager for advanced routing, SSL client certificates, and authentik header manipulation, you don't actually have to abandon it. Because SOCFortress is a dedicated WAF, it is highly common to chain them together:
`Internet` ➔ `SOCFortress WAF (Filters bad traffic)` ➔ `Nginx Proxy Manager (Handles Authentik, headers, & routing)` ➔ `Your Apps`
<span class="citation-7 citation-end-7">By placing SOCFortress at the edge, it strips out SQL injections, XSS, and bot traffic before it ever hits NPM.</span> NPM can then securely parse your custom headers and pass them back to your applications exactly as you have it configured right now.
<div _ngcontent-ng-c405365209="" chatcontentdimensions="" class="chat-history-scroll-container lm" id="bkmrk-socfortress---medium-1"><div _ngcontent-ng-c405365209="" class="conversation-container message-actions-hover-boundary ng-star-inserted"><div _ngcontent-ng-c3598951857=""><div _ngcontent-ng-c3060770435="" class="response-container response-container-with-gpi ng-tns-c3060770435-20 no-background" data-hveid="1" jslog="173900;track:impression,attention"><div _ngcontent-ng-c3060770435="" class="presented-response-container ng-tns-c3060770435-20" data-hveid="2" jslog="283401;track:impression,attention"><div _ngcontent-ng-c3060770435="" class="response-container-content ng-tns-c3060770435-20 has-thoughts"><div _ngcontent-ng-c3598951857="" class="response-content ng-tns-c3060770435-20"><div _ngcontent-ng-c1922256434="" class="container"><div _ngcontent-ng-c2066222059="" aria-busy="false" aria-live="off" class="markdown markdown-main-panel enable-luminous-fast-follows enable-updated-hr-color stronger tutor-markdown-rendering" dir="ltr" inline-copy-host=""><div _ngcontent-ng-c2854609078="" class="source-inline-chip-container luminous-sources hide-from-message-actions ng-star-inserted"><div _ngcontent-ng-c2854609078="" class="source-label-container gds-body-s ng-star-inserted" dir="auto"><span class="source-title">SOCFortress - Medium</span></div></div></div></div></div></div></div></div></div></div></div>Are you attempting to use authentik via standard proxy headers (like `X-Authentik-Username`) or are you trying to implement a full Forward Auth middleware block?
<div _ngcontent-ng-c405365209="" chatcontentdimensions="" class="chat-history-scroll-container lm" id="bkmrk-"><div _ngcontent-ng-c405365209="" class="conversation-container message-actions-hover-boundary ng-star-inserted" id="bkmrk--1"><div _ngcontent-ng-c3598951857=""><div _ngcontent-ng-c3060770435="" class="response-container response-container-with-gpi ng-tns-c3060770435-20 no-background" data-hveid="1" jslog="173900;track:impression,attention"><div _ngcontent-ng-c3060770435="" class="presented-response-container ng-tns-c3060770435-20" data-hveid="2" jslog="283401;track:impression,attention"><div _ngcontent-ng-c3060770435="" class="response-container-content ng-tns-c3060770435-20 has-thoughts"><div _ngcontent-ng-c3598951857="" class="response-content ng-tns-c3060770435-20"><div _ngcontent-ng-c1922256434="" class="container"><div _ngcontent-ng-c2066222059="" aria-busy="false" aria-live="off" class="markdown markdown-main-panel enable-luminous-fast-follows enable-updated-hr-color stronger tutor-markdown-rendering" dir="ltr" id="bkmrk--2" inline-copy-host=""></div></div><div _ngcontent-ng-c3598951857="" class="response-footer complete has-thoughts gap"><div _ngcontent-ng-c3537663079="" jslog="268370;track:generic_click,impression">
</div></div></div></div></div><div _ngcontent-ng-c3060770435="" class="response-container-footer ng-tns-c3060770435-20 ng-star-inserted"><div _ngcontent-ng-c356251628="" class="actions-container-v2 ng-tns-c356251628-21"><div _ngcontent-ng-c356251628="" class="buttons-container-v2 ng-tns-c356251628-21 ng-star-inserted"><button aria-label="Good response" aria-pressed="false" class="mdc-icon-button mat-mdc-icon-button mat-mdc-button-base mat-badge mat-unthemed mat-badge-overlap mat-badge-above mat-badge-after mat-badge-small mat-badge-hidden ng-star-inserted"></button><button aria-label="Bad response" aria-pressed="false" class="mdc-icon-button mat-mdc-icon-button mat-mdc-button-base mat-badge mat-unthemed mat-badge-overlap mat-badge-above mat-badge-after mat-badge-small mat-badge-hidden ng-star-inserted"></button><button aria-label="Copy" class="mdc-icon-button mat-mdc-icon-button mat-mdc-button-base mat-badge mat-unthemed mat-badge-overlap mat-badge-above mat-badge-after mat-badge-small mat-badge-hidden ng-star-inserted"></button><div _ngcontent-ng-c356251628="" class="ng-tns-c356251628-21 ng-star-inserted"><div _ngcontent-ng-c356251628="" class="menu-button-wrapper ng-tns-c356251628-21 ng-star-inserted"><div _ngcontent-ng-c356251628="" class="more-menu-button-container ng-tns-c356251628-21"><button aria-label="Show more options" class="mdc-icon-button mat-mdc-icon-button mat-mdc-button-base mat-badge mat-unthemed mat-badge-overlap mat-badge-above mat-badge-after mat-badge-small mat-badge-hidden ng-star-inserted"></button>
</div></div></div><div _ngcontent-ng-c356251628="" class="spacer ng-tns-c356251628-21 ng-star-inserted">
</div></div></div></div></div></div><div _ngcontent-ng-c405365209="" class="restart-chat-button-scroll-placeholder ng-star-inserted">
</div></div><div _ngcontent-ng-c405365209="" class="conversation-container message-actions-hover-boundary ng-star-inserted"><div _ngcontent-ng-c3824630338="" class="user-query-container"><div _ngcontent-ng-c3824630338="" class="file-preview-container ng-star-inserted">
</div><div _ngcontent-ng-c3824630338="" class="query-content ng-star-inserted verticle-align-for-single-line-text" data-hveid="0" data-ved="0CAAQ3ucQahcKEwixkur_vK-VAxUAAAAAHQAAAAAQVA" decode-data-ved="1" jslog="275422;track:impression,attention"><div _ngcontent-ng-c3824630338="" aria-level="2" class="query-text gds-body-l" dir="ltr" role="heading">
</div></div></div></div></div>I like this approach, how would you go about setting this up
Setting up this multi-layer structure is highly effective because it gives you the best of both worlds: enterprise-grade threat filtering at the front door, and easy web routing at the back.
To achieve this seamlessly, the most critical shift is moving **SSL termination** to the SOCFortress WAF layer. Because a WAF needs to inspect the actual HTTP payload for malicious activity (like SQL injections or cross-site scripting), it *must* hold your public SSL certificates.
Here is exactly how to sequence this setup:
## The Blueprint
<div _ngcontent-ng-c405365209="" chatcontentdimensions="" class="chat-history-scroll-container lm" id="bkmrk-1-configure-npm-to-a"><div _ngcontent-ng-c405365209="" class="conversation-container message-actions-hover-boundary ng-star-inserted"><div _ngcontent-ng-c3598951857=""><div _ngcontent-ng-c3060770435="" class="response-container response-container-with-gpi ng-tns-c3060770435-22 no-background" data-hveid="1" jslog="173900;track:impression,attention"><div _ngcontent-ng-c3060770435="" class="presented-response-container ng-tns-c3060770435-22" data-hveid="2" jslog="283401;track:impression,attention"><div _ngcontent-ng-c3060770435="" class="response-container-content ng-tns-c3060770435-22"><div _ngcontent-ng-c3598951857="" class="response-content ng-tns-c3060770435-22"><div _ngcontent-ng-c1922256434="" class="container"><div _ngcontent-ng-c2066222059="" aria-busy="false" aria-live="off" class="markdown markdown-main-panel enable-luminous-fast-follows enable-updated-hr-color stronger tutor-markdown-rendering" dir="ltr" inline-copy-host=""><div class="attachment-container unknown"><div class="sequence-container" data-hveid="3" jslog="308913;track:impression,attention"><div class="sequence-event ng-star-inserted"><div class="sequence-event-marker-container hide-from-message-actions" hide-from-message-actions=""><div class="sequence-event-marker gds-body-s ng-star-inserted">1</div><div class="sequence-event-line ng-star-inserted">
</div></div><div class="sequence-event-content"><div class="hide-from-message-actions" hide-from-message-actions=""><div class="sequence-event-title gds-emphasized-body-l">Configure NPM to accept HTTP traffic</div><div class="sequence-event-subtitle gds-extended-caption ng-star-inserted">Nginx Proxy Manager Side</div></div><div class="sequence-event-description gds-body-l">
</div></div></div></div></div></div></div></div></div></div></div></div></div></div>Keep your internal host configurations inside NPM exactly as they are right now, including your custom headers for authentik. However, **disable SSL** inside NPM for these hosts. NPM will now listen for unencrypted HTTP traffic from the internal network, specifically from the SOCFortress container.
<div _ngcontent-ng-c405365209="" chatcontentdimensions="" class="chat-history-scroll-container lm" id="bkmrk-2-establish-docker-n"><div _ngcontent-ng-c405365209="" class="conversation-container message-actions-hover-boundary ng-star-inserted"><div _ngcontent-ng-c3598951857=""><div _ngcontent-ng-c3060770435="" class="response-container response-container-with-gpi ng-tns-c3060770435-22 no-background" data-hveid="1" jslog="173900;track:impression,attention"><div _ngcontent-ng-c3060770435="" class="presented-response-container ng-tns-c3060770435-22" data-hveid="2" jslog="283401;track:impression,attention"><div _ngcontent-ng-c3060770435="" class="response-container-content ng-tns-c3060770435-22"><div _ngcontent-ng-c3598951857="" class="response-content ng-tns-c3060770435-22"><div _ngcontent-ng-c1922256434="" class="container"><div _ngcontent-ng-c2066222059="" aria-busy="false" aria-live="off" class="markdown markdown-main-panel enable-luminous-fast-follows enable-updated-hr-color stronger tutor-markdown-rendering" dir="ltr" inline-copy-host=""><div class="attachment-container unknown"><div class="sequence-container" data-hveid="3" jslog="308913;track:impression,attention"><div class="sequence-event ng-star-inserted"><div class="sequence-event-content"><div class="sequence-event-description gds-body-l">
</div></div></div><div class="sequence-event ng-star-inserted"><div class="sequence-event-marker-container hide-from-message-actions" hide-from-message-actions=""><div class="sequence-event-marker gds-body-s ng-star-inserted">2</div><div class="sequence-event-line ng-star-inserted">
</div></div><div class="sequence-event-content"><div class="hide-from-message-actions" hide-from-message-actions=""><div class="sequence-event-title gds-emphasized-body-l">Establish Docker network communication</div><div class="sequence-event-subtitle gds-extended-caption ng-star-inserted">Networking Side</div></div><div class="sequence-event-description gds-body-l">
</div></div></div></div></div></div></div></div></div></div></div></div></div></div>Ensure the SOCFortress WAF container can reach your NPM container. If they are on the same machine, the cleanest method is to join them to a shared custom Docker network:
<div _ngcontent-ng-c1958104536="" class="code-block ng-tns-c1958104536-26 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" data-hveid="4" id="bkmrk-bash" jslog="223238;track:impression,attention;BardVeMetadataKey:[["r_30b702b296852146","c_4a90e1c3e176c650",null,"rc_c6288839219dd582",null,null,"en",null,1,null,null,1,0]]"><div _ngcontent-ng-c1958104536="" class="formatted-code-block-internal-container ng-tns-c1958104536-26"><div _ngcontent-ng-c1958104536="" class="animated-opacity ng-tns-c1958104536-26"><div _ngcontent-ng-c1958104536="" class="code-block-decoration header-formatted gds-emphasized-body-m ng-tns-c1958104536-26 ng-star-inserted"><span class="ng-tns-c1958104536-26">Bash</span><div _ngcontent-ng-c1958104536="" class="buttons ng-tns-c1958104536-26 ng-star-inserted"><button aria-label="Download code" class="mdc-icon-button mat-mdc-icon-button mat-mdc-button-base mat-badge mat-unthemed mat-badge-overlap mat-badge-above mat-badge-after mat-badge-small mat-badge-hidden ng-star-inserted"></button><button aria-label="Copy code" class="mdc-icon-button mat-mdc-icon-button mat-mdc-button-base mat-badge mat-unthemed mat-badge-overlap mat-badge-above mat-badge-after mat-badge-small mat-badge-hidden ng-star-inserted"></button>
</div></div></div></div></div>```
docker network connect your_shared_network_name socfortress-waf-container
```
<div _ngcontent-ng-c405365209="" chatcontentdimensions="" class="chat-history-scroll-container lm" id="bkmrk-3-point-the-public-d"><div _ngcontent-ng-c405365209="" class="conversation-container message-actions-hover-boundary ng-star-inserted"><div _ngcontent-ng-c3598951857=""><div _ngcontent-ng-c3060770435="" class="response-container response-container-with-gpi ng-tns-c3060770435-22 no-background" data-hveid="1" jslog="173900;track:impression,attention"><div _ngcontent-ng-c3060770435="" class="presented-response-container ng-tns-c3060770435-22" data-hveid="2" jslog="283401;track:impression,attention"><div _ngcontent-ng-c3060770435="" class="response-container-content ng-tns-c3060770435-22"><div _ngcontent-ng-c3598951857="" class="response-content ng-tns-c3060770435-22"><div _ngcontent-ng-c1922256434="" class="container"><div _ngcontent-ng-c2066222059="" aria-busy="false" aria-live="off" class="markdown markdown-main-panel enable-luminous-fast-follows enable-updated-hr-color stronger tutor-markdown-rendering" dir="ltr" inline-copy-host=""><div class="attachment-container unknown"><div class="sequence-container" data-hveid="3" jslog="308913;track:impression,attention"><div class="sequence-event ng-star-inserted"><div class="sequence-event-content"><div class="sequence-event-description gds-body-l">
</div></div></div><div class="sequence-event ng-star-inserted"><div class="sequence-event-marker-container hide-from-message-actions" hide-from-message-actions=""><div class="sequence-event-marker gds-body-s ng-star-inserted">3</div><div class="sequence-event-line ng-star-inserted">
</div></div><div class="sequence-event-content"><div class="hide-from-message-actions" hide-from-message-actions=""><div class="sequence-event-title gds-emphasized-body-l">Point the public DNS to SOCFortress</div><div class="sequence-event-subtitle gds-extended-caption ng-star-inserted">DNS Side</div></div><div class="sequence-event-description gds-body-l">
</div></div></div></div></div></div></div></div></div></div></div></div></div></div>Update your firewall, port forwarding, or public DNS records so that ports **80** and **443** point directly to the host machine running SOCFortress WAF, rather than Nginx Proxy Manager.
<div _ngcontent-ng-c405365209="" chatcontentdimensions="" class="chat-history-scroll-container lm" id="bkmrk-4-add-the-applicatio"><div _ngcontent-ng-c405365209="" class="conversation-container message-actions-hover-boundary ng-star-inserted"><div _ngcontent-ng-c3598951857=""><div _ngcontent-ng-c3060770435="" class="response-container response-container-with-gpi ng-tns-c3060770435-22 no-background" data-hveid="1" jslog="173900;track:impression,attention"><div _ngcontent-ng-c3060770435="" class="presented-response-container ng-tns-c3060770435-22" data-hveid="2" jslog="283401;track:impression,attention"><div _ngcontent-ng-c3060770435="" class="response-container-content ng-tns-c3060770435-22"><div _ngcontent-ng-c3598951857="" class="response-content ng-tns-c3060770435-22"><div _ngcontent-ng-c1922256434="" class="container"><div _ngcontent-ng-c2066222059="" aria-busy="false" aria-live="off" class="markdown markdown-main-panel enable-luminous-fast-follows enable-updated-hr-color stronger tutor-markdown-rendering" dir="ltr" inline-copy-host=""><div class="attachment-container unknown"><div class="sequence-container" data-hveid="3" jslog="308913;track:impression,attention"><div class="sequence-event ng-star-inserted"><div class="sequence-event-content"><div class="sequence-event-description gds-body-l">
</div></div></div><div class="sequence-event ng-star-inserted"><div class="sequence-event-marker-container hide-from-message-actions" hide-from-message-actions=""><div class="sequence-event-marker gds-body-s ng-star-inserted">4</div></div><div class="sequence-event-content"><div class="hide-from-message-actions" hide-from-message-actions=""><div class="sequence-event-title gds-emphasized-body-l">Add the application in SOCFortress WAF</div><div class="sequence-event-subtitle gds-extended-caption ng-star-inserted">SOCFortress Side</div></div><div class="sequence-event-description gds-body-l">
</div></div></div></div></div></div></div></div></div></div></div></div></div></div>Open the SOCFortress UI and create a new protected application asset:
<div _ngcontent-ng-c405365209="" chatcontentdimensions="" class="chat-history-scroll-container lm" id="bkmrk-domain%2Fhost%3A-your-pu"><div _ngcontent-ng-c405365209="" class="conversation-container message-actions-hover-boundary ng-star-inserted"><div _ngcontent-ng-c3598951857=""><div _ngcontent-ng-c3060770435="" class="response-container response-container-with-gpi ng-tns-c3060770435-22 no-background" data-hveid="1" jslog="173900;track:impression,attention"><div _ngcontent-ng-c3060770435="" class="presented-response-container ng-tns-c3060770435-22" data-hveid="2" jslog="283401;track:impression,attention"><div _ngcontent-ng-c3060770435="" class="response-container-content ng-tns-c3060770435-22"><div _ngcontent-ng-c3598951857="" class="response-content ng-tns-c3060770435-22"><div _ngcontent-ng-c1922256434="" class="container"><div _ngcontent-ng-c2066222059="" aria-busy="false" aria-live="off" class="markdown markdown-main-panel enable-luminous-fast-follows enable-updated-hr-color stronger tutor-markdown-rendering" dir="ltr" inline-copy-host=""><div class="attachment-container unknown"><div class="sequence-container" data-hveid="3" jslog="308913;track:impression,attention"><div class="sequence-event ng-star-inserted"><div class="sequence-event-content"><div class="sequence-event-description gds-body-l">- **Domain/Host:** Your public domain (e.g., `app.domain.com`).
- **Upstream/Backend URL:** Point this directly to your NPM container. Use NPM's container name or its IP on the shared network (e.g., `http://nginx-proxy-manager:80` or `[http://172.20.0.5:80](http://172.20.0.5:80)`).
- **Cert Mode:** Enable Let's Encrypt or upload your custom certificates here. SOCFortress (via Caddy) will handle the HTTPS handshake with the internet.
</div></div></div></div></div></div></div></div></div></div></div></div></div></div>### Understanding the Traffic Flow
Once active, a user request flows through your network using this lifecycle:
```
[User Browser]
▼ (HTTPS - TLS Encrypted)
[SOCFortress WAF] <-- Decrypts traffic & runs Coraza OWASP CRS rules
▼ (HTTP - Internal Network)
[Nginx Proxy Manager] <-- Matches domain, executes your Custom Authentik Config, injects headers
▼ (HTTP/HTTPS)
[Your Application Backend]
```
> ⚠️ **Important Note on Client IPs:** Because NPM now sits behind SOCFortress, NPM will think *every* request is coming from the SOCFortress WAF IP. To ensure your authentik logs show the real user's location, make sure you have `Real IP` or `X-Forwarded-For` headers enabled in your NPM advanced config to pass through the original client IP.
<div _ngcontent-ng-c405365209="" chatcontentdimensions="" class="chat-history-scroll-container lm" id="bkmrk--3"><div _ngcontent-ng-c405365209="" class="conversation-container message-actions-hover-boundary ng-star-inserted" id="bkmrk--4"><div _ngcontent-ng-c3598951857=""><div _ngcontent-ng-c3060770435="" class="response-container response-container-with-gpi ng-tns-c3060770435-22 no-background" data-hveid="1" jslog="173900;track:impression,attention"><div _ngcontent-ng-c3060770435="" class="presented-response-container ng-tns-c3060770435-22" data-hveid="2" jslog="283401;track:impression,attention"><div _ngcontent-ng-c3060770435="" class="response-container-content ng-tns-c3060770435-22"><div _ngcontent-ng-c3598951857="" class="response-content ng-tns-c3060770435-22"><div _ngcontent-ng-c1922256434="" class="container"><div _ngcontent-ng-c2066222059="" aria-busy="false" aria-live="off" class="markdown markdown-main-panel enable-luminous-fast-follows enable-updated-hr-color stronger tutor-markdown-rendering" dir="ltr" id="bkmrk--5" inline-copy-host=""></div></div><div _ngcontent-ng-c3598951857="" class="response-footer contains-extensions-response complete gap"><div _ngcontent-ng-c3537663079="" jslog="268370;track:generic_click,impression">
</div></div></div></div></div><div _ngcontent-ng-c3060770435="" class="response-container-footer ng-tns-c3060770435-22 ng-star-inserted"><div _ngcontent-ng-c356251628="" class="actions-container-v2 ng-tns-c356251628-23"><div _ngcontent-ng-c356251628="" class="buttons-container-v2 ng-tns-c356251628-23 ng-star-inserted"><button aria-label="Good response" aria-pressed="false" class="mdc-icon-button mat-mdc-icon-button mat-mdc-button-base mat-badge mat-unthemed mat-badge-overlap mat-badge-above mat-badge-after mat-badge-small mat-badge-hidden ng-star-inserted"></button><button aria-label="Bad response" aria-pressed="false" class="mdc-icon-button mat-mdc-icon-button mat-mdc-button-base mat-badge mat-unthemed mat-badge-overlap mat-badge-above mat-badge-after mat-badge-small mat-badge-hidden ng-star-inserted"></button><button aria-label="Copy" class="mdc-icon-button mat-mdc-icon-button mat-mdc-button-base mat-badge mat-unthemed mat-badge-overlap mat-badge-above mat-badge-after mat-badge-small mat-badge-hidden ng-star-inserted"></button><div _ngcontent-ng-c356251628="" class="ng-tns-c356251628-23 ng-star-inserted"><div _ngcontent-ng-c356251628="" class="menu-button-wrapper ng-tns-c356251628-23 ng-star-inserted"><div _ngcontent-ng-c356251628="" class="more-menu-button-container ng-tns-c356251628-23"><button aria-label="Show more options" class="mdc-icon-button mat-mdc-icon-button mat-mdc-button-base mat-badge mat-unthemed mat-badge-overlap mat-badge-above mat-badge-after mat-badge-small mat-badge-hidden ng-star-inserted"></button>
</div></div></div><div _ngcontent-ng-c356251628="" class="spacer ng-tns-c356251628-23 ng-star-inserted">
</div></div></div></div></div></div><div _ngcontent-ng-c405365209="" class="restart-chat-button-scroll-placeholder ng-star-inserted">
</div></div><div _ngcontent-ng-c405365209="" class="conversation-container message-actions-hover-boundary ng-star-inserted"><div _ngcontent-ng-c3824630338="" class="user-query-container"><div _ngcontent-ng-c3824630338="" class="file-preview-container ng-star-inserted">
</div><div _ngcontent-ng-c3824630338="" class="query-content ng-star-inserted" data-hveid="0" data-ved="0CAAQ3ucQahcKEwixkur_vK-VAxUAAAAAHQAAAAAQVw" decode-data-ved="1" jslog="275422;track:impression,attention"><div _ngcontent-ng-c3824630338="" aria-level="2" class="query-text gds-body-l" dir="ltr" role="heading">
</div></div></div></div></div>So the only site entry in SOCFortress is pointing to my NPM and the NPM hold all my site forwarding minus the SSL certs, correct?
Yes, you have it **100% correct**.
You are essentially reducing SOCFortress down to a smart "security shield" at your front door, while letting NPM continue to act as the traffic controller that knows exactly which application gets what headers.
To visualize how clean this makes your configuration, here is how the responsibilities are split:
### What SOCFortress Does:
<div _ngcontent-ng-c405365209="" chatcontentdimensions="" class="chat-history-scroll-container lm" id="bkmrk-listens-on-public-po"><div _ngcontent-ng-c405365209="" class="conversation-container message-actions-hover-boundary ng-star-inserted"><div _ngcontent-ng-c3598951857=""><div _ngcontent-ng-c3060770435="" class="response-container response-container-with-gpi ng-tns-c3060770435-24 no-background response-container-has-multiple-responses" data-hveid="1" jslog="173900;track:impression,attention"><div _ngcontent-ng-c3060770435="" class="presented-response-container ng-tns-c3060770435-24" data-hveid="2" jslog="283401;track:impression,attention"><div _ngcontent-ng-c3060770435="" class="response-container-content ng-tns-c3060770435-24"><div _ngcontent-ng-c3598951857="" class="response-content ng-tns-c3060770435-24"><div _ngcontent-ng-c1922256434="" class="container"><div _ngcontent-ng-c2066222059="" aria-busy="false" aria-live="polite" class="markdown markdown-main-panel enable-luminous-fast-follows enable-updated-hr-color stronger tutor-markdown-rendering" dir="ltr" inline-copy-host="">- Listens on public ports `80` and `443`.
- Handles the **SSL/TLS Certificates** for your domains.
- Inspects incoming requests for malicious payloads (WAF).
- Has **one job** for routing: Forward *all* clean traffic for your domains directly to NPM's HTTP port.
</div></div></div></div></div></div></div></div></div>### What Nginx Proxy Manager Does:
<div _ngcontent-ng-c405365209="" chatcontentdimensions="" class="chat-history-scroll-container lm" id="bkmrk-listens-internally-o"><div _ngcontent-ng-c405365209="" class="conversation-container message-actions-hover-boundary ng-star-inserted"><div _ngcontent-ng-c3598951857=""><div _ngcontent-ng-c3060770435="" class="response-container response-container-with-gpi ng-tns-c3060770435-24 no-background response-container-has-multiple-responses" data-hveid="1" jslog="173900;track:impression,attention"><div _ngcontent-ng-c3060770435="" class="presented-response-container ng-tns-c3060770435-24" data-hveid="2" jslog="283401;track:impression,attention"><div _ngcontent-ng-c3060770435="" class="response-container-content ng-tns-c3060770435-24"><div _ngcontent-ng-c3598951857="" class="response-content ng-tns-c3060770435-24"><div _ngcontent-ng-c1922256434="" class="container"><div _ngcontent-ng-c2066222059="" aria-busy="false" aria-live="polite" class="markdown markdown-main-panel enable-luminous-fast-follows enable-updated-hr-color stronger tutor-markdown-rendering" dir="ltr" inline-copy-host="">- Listens internally on port `80` (no SSL configured inside NPM).
- Looks at the incoming domain name (e.g., `app1.yourdomain.com`).
- Executes your **Custom Nginx Configuration** for authentik (injecting user headers, checking auth states).
- Forwards the final, authenticated request to your actual backend application container.
</div></div></div></div></div></div></div></div></div>### A Quick Tip for a Smooth Cutover
When you remove the SSL certificates from NPM, Nginx will expect plain HTTP traffic. In the SOCFortress asset configuration, make sure your upstream/backend destination is explicitly set to use **`http://`** and not `https://` when pointing to NPM.
If you use a common Docker network, you can just point SOCFortress to `http://nginx-proxy-manager-container-name:80` and it will map perfectly.
To handle a setup where **SOCFortress (Caddy+Coraza)** sits at the edge and **Nginx Proxy Manager (NPM)** sits behind it, you have to break the port binding conflict on the host machine.
Only **one** service can bind to ports `80` and `443` on your host's network interface. Since SOCFortress is your WAF edge, it gets the privilege of claiming those host ports.
## 1. The Strategy
1. **SOCFortress (`caddy-waf`)** binds to the host's `80:80` and `443:443`. It catches all incoming public internet traffic first.
2. **Nginx Proxy Manager (`nginx-proxy-manager`)** removes its public host port bindings for `80` and `443`.
3. **Internal Routing:** Because both services share the `waf-internal` Docker network, the Caddy WAF can route traffic directly to NPM using NPM's container name (`nginx-proxy-manager`) on internal ports `80` and `443`.
## 2. Updated Docker Compose
Here is how your `app` (NPM) and `caddy-waf` services should look in the file.
Notice that NPM's ports `80` and `443` have been removed from the host mapping, but port `81` is kept so you can still log into the NPM Admin UI from your local network.
<div _ngcontent-ng-c1958104536="" class="code-block ng-tns-c1958104536-32 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" data-hveid="3" id="bkmrk-yaml" jslog="223238;track:impression,attention;BardVeMetadataKey:[["r_d832160a9ba7de36","c_26bc2a2bba230e76",null,"rc_c711e786aee4e246",null,null,"en",null,1,null,null,1,0]]"><div _ngcontent-ng-c1958104536="" class="formatted-code-block-internal-container ng-tns-c1958104536-32"><div _ngcontent-ng-c1958104536="" class="animated-opacity ng-tns-c1958104536-32"><div _ngcontent-ng-c1958104536="" class="code-block-decoration header-formatted gds-emphasized-body-m ng-tns-c1958104536-32 ng-star-inserted"><span class="ng-tns-c1958104536-32">YAML</span><div _ngcontent-ng-c1958104536="" class="buttons ng-tns-c1958104536-32 ng-star-inserted"><button aria-label="Download code" class="mdc-icon-button mat-mdc-icon-button mat-mdc-button-base mat-badge mat-unthemed mat-badge-overlap mat-badge-above mat-badge-after mat-badge-small mat-badge-hidden ng-star-inserted"></button><button aria-label="Copy code" class="mdc-icon-button mat-mdc-icon-button mat-mdc-button-base mat-badge mat-unthemed mat-badge-overlap mat-badge-above mat-badge-after mat-badge-small mat-badge-hidden ng-star-inserted"></button></div></div></div></div></div>```
app:
image: 'jc21/nginx-proxy-manager:latest'
container_name: nginx-proxy-manager
restart: unless-stopped
env_file: .env
environment:
- TZ=${TZ}
- DB_MYSQL_HOST=db
- DB_MYSQL_PORT=3306
- DB_MYSQL_USER=${MYSQL_USER}
- DB_MYSQL_PASSWORD=${MYSQL_PASSWORD}
- DB_MYSQL_NAME=${MYSQL_DATABASE}
ports:
- '81:81' # Kept so you can access the NPM dashboard on host-ip:81
# '80:80' and '443:443' REMOVED here. They are reachable internally via the network.
volumes:
- ./data/npm:/data
- ./data/letsencrypt:/etc/letsencrypt
depends_on:
- db
networks:
- proxy
- proxydb
- waf-internal
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:81/api/status"]
interval: 20s
timeout: 5s
retries: 5
start_period: 40s
caddy-waf:
image: ghcr.io/socfortress/waf-caddy:${WAF_IMAGE_TAG:-latest}
container_name: caddy-waf
ports:
- "80:80" # Claims the host ports
- "443:443" # Claims the host ports
extra_hosts:
- "host.docker.internal:host-gateway"
volumes:
- coraza-rules:/etc/coraza/rules
- caddy-config:/etc/caddy
- coraza-custom:/etc/coraza/custom
- crs-data:/etc/coraza/crs-rules
- coraza-logs:/var/log/coraza
networks:
- waf-internal
depends_on:
http-echo:
condition: service_started
healthcheck:
test: ["CMD", "wget", "-q", "-O-", "http://localhost:2019/config/"]
interval: 30s
timeout: 10s
retries: 3
start_period: 20s
deploy:
resources:
limits:
cpus: "1.0"
memory: 512M
restart: unless-stopped
```
<div _ngcontent-ng-c1958104536="" class="code-block ng-tns-c1958104536-32 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" data-hveid="3" id="bkmrk--7" jslog="223238;track:impression,attention;BardVeMetadataKey:[["r_d832160a9ba7de36","c_26bc2a2bba230e76",null,"rc_c711e786aee4e246",null,null,"en",null,1,null,null,1,0]]"><div _ngcontent-ng-c1958104536="" class="formatted-code-block-internal-container ng-tns-c1958104536-32"><div _ngcontent-ng-c1958104536="" class="animated-opacity ng-tns-c1958104536-32"></div></div></div>## 3. How to Route Traffic in the WAF
When you configure your backend pools or proxy routes inside the SOCFortress Admin UI, you will point the upstream traffic to NPM.
Instead of an IP address, use Docker's internal DNS resolver:
- **Upstream Target:** `http://nginx-proxy-manager:80` (or port `443` if passing through SSL)
From there, NPM will receive the clean, inspected traffic and can handle the final routing to your other services (like Gitea, Mailcow, or homepage) living on your `proxy` network.
<div _ngcontent-ng-c405365209="" chatcontentdimensions="" class="chat-history-scroll-container lm" id="bkmrk--9"><div _ngcontent-ng-c405365209="" class="conversation-container message-actions-hover-boundary ng-star-inserted" id="bkmrk--10"><div _ngcontent-ng-c3598951857=""><div _ngcontent-ng-c3060770435="" class="response-container response-container-with-gpi ng-tns-c3060770435-24 no-background response-container-has-multiple-responses" data-hveid="1" jslog="173900;track:impression,attention"><div _ngcontent-ng-c3060770435="" class="response-container-footer ng-tns-c3060770435-24 ng-star-inserted"><div _ngcontent-ng-c356251628="" class="actions-container-v2 ng-tns-c356251628-25"><div _ngcontent-ng-c356251628="" class="buttons-container-v2 ng-tns-c356251628-25 ng-star-inserted"><button aria-label="Good response" aria-pressed="false" class="mdc-icon-button mat-mdc-icon-button mat-mdc-button-base mat-badge mat-unthemed mat-badge-overlap mat-badge-above mat-badge-after mat-badge-small mat-badge-hidden ng-star-inserted"></button><button aria-label="Bad response" aria-pressed="false" class="mdc-icon-button mat-mdc-icon-button mat-mdc-button-base mat-badge mat-unthemed mat-badge-overlap mat-badge-above mat-badge-after mat-badge-small mat-badge-hidden ng-star-inserted"></button><div _ngcontent-ng-c356251628="" class="ng-tns-c356251628-25 ng-star-inserted"><button aria-label="Redo" class="mdc-icon-button mat-mdc-icon-button mat-mdc-button-base mat-badge mat-unthemed mat-badge-overlap mat-badge-above mat-badge-after mat-badge-small mat-badge-hidden ng-star-inserted"></button>
</div><button aria-label="Copy" class="mdc-icon-button mat-mdc-icon-button mat-mdc-button-base mat-badge mat-unthemed mat-badge-overlap mat-badge-above mat-badge-after mat-badge-small mat-badge-hidden ng-star-inserted"></button><div _ngcontent-ng-c356251628="" class="ng-tns-c356251628-25 ng-star-inserted"><div _ngcontent-ng-c356251628="" class="menu-button-wrapper ng-tns-c356251628-25 ng-star-inserted"><div _ngcontent-ng-c356251628="" class="more-menu-button-container ng-tns-c356251628-25"><button aria-label="Show more options" class="mdc-icon-button mat-mdc-icon-button mat-mdc-button-base mat-badge mat-unthemed mat-badge-overlap mat-badge-above mat-badge-after mat-badge-small mat-badge-hidden ng-star-inserted"></button>
</div></div></div><div _ngcontent-ng-c356251628="" class="spacer ng-tns-c356251628-25 ng-star-inserted">
</div></div></div></div></div></div><div _ngcontent-ng-c405365209="" class="restart-chat-button-scroll-placeholder ng-star-inserted">
</div></div><div _ngcontent-ng-c405365209="" class="autosuggest-scrim">
</div></div><fieldset class="input-area-container ng-trigger ng-trigger-inputAreaAnimation" id="bkmrk-%C2%A0-4"></fieldset>
# Docker Compose
```
---
services:
db:
image: 'jc21/mariadb-aria:latest'
container_name: npm-db
restart: unless-stopped
env_file: .env
environment:
- MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD}
- MYSQL_DATABASE=${MYSQL_DATABASE}
- MYSQL_USER=${MYSQL_USER}
- MYSQL_PASSWORD=${MYSQL_PASSWORD}
- MARIADB_AUTO_UPGRADE=1
volumes:
- ./data/mysql:/var/lib/mysql
networks:
- proxydb
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-u${MYSQL_USER}", "-p${MYSQL_PASSWORD}"]
interval: 20s
timeout: 5s
retries: 5
start_period: 30s
app:
image: 'jc21/nginx-proxy-manager:latest'
container_name: nginx-proxy-manager
restart: unless-stopped
env_file: .env
environment:
- TZ=${TZ}
- DB_MYSQL_HOST=db
- DB_MYSQL_PORT=3306
- DB_MYSQL_USER=${MYSQL_USER}
- DB_MYSQL_PASSWORD=${MYSQL_PASSWORD}
- DB_MYSQL_NAME=${MYSQL_DATABASE}
ports:
- '81:81' # Kept so you can access the NPM dashboard on host-ip:81
# '80:80' and '443:443' REMOVED here. They are reachable internally via the network.
volumes:
- ./data/npm:/data
- ./data/letsencrypt:/etc/letsencrypt
depends_on:
- db
networks:
- proxy
- proxydb
- waf-internal
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:81/api/status"]
interval: 20s
timeout: 5s
retries: 5
start_period: 40s
# ---------------------------------------------------------------------------
# Caddy + Coraza: WAF engine and reverse proxy
# ---------------------------------------------------------------------------
caddy-waf:
image: ghcr.io/socfortress/waf-caddy:${WAF_IMAGE_TAG:-latest}
container_name: caddy-waf
ports:
- "80:80"
- "443:443"
# Lets the WAF proxy to apps running on the Docker host (e.g. an nginx
# upstream) via http://host.docker.internal:<port>. See demo/README.md.
extra_hosts:
- "host.docker.internal:host-gateway"
volumes:
- coraza-rules:/etc/coraza/rules
- caddy-config:/etc/caddy
- coraza-custom:/etc/coraza/custom
- crs-data:/etc/coraza/crs-rules # live CRS dir (seeded by admin-api)
- coraza-logs:/var/log/coraza
networks:
- waf-internal
depends_on:
http-echo:
condition: service_started
healthcheck:
test: ["CMD", "wget", "-q", "-O-", "http://localhost:2019/config/"]
interval: 30s
timeout: 10s
retries: 3
start_period: 20s
deploy:
resources:
limits:
cpus: "1.0"
memory: 512M
restart: unless-stopped
# ---------------------------------------------------------------------------
# Dummy upstream — replace with your real protected app(s)
# ---------------------------------------------------------------------------
http-echo:
image: hashicorp/http-echo:0.2.3
container_name: http-echo
command: ["-text=upstream-ok"]
user: "65534:65534"
networks:
- waf-internal
healthcheck:
test: ["NONE"]
deploy:
resources:
limits:
cpus: "0.25"
memory: 64M
restart: unless-stopped
# ---------------------------------------------------------------------------
# FastAPI Admin API
# ---------------------------------------------------------------------------
admin-api:
image: ghcr.io/socfortress/waf-admin-api:${WAF_IMAGE_TAG:-latest}
container_name: admin-api
env_file: .env
volumes:
- tls-certs:/certs # shared TLS cert volume (see admin-ui)
# GeoLite2 DB is user-supplied — MaxMind licensing forbids redistribution.
# Point GEOIP_DB_PATH at your downloaded GeoLite2-City.mmdb (see README).
- ./GeoLite2-City/GeoLite2-City.mmdb}:/etc/geoip-bundle/GeoLite2-City.mmdb:ro
- geoip-data:/etc/geoip
- coraza-rules:/etc/coraza/rules
- caddy-config:/etc/caddy
- coraza-custom:/etc/coraza/custom
- crs-data:/etc/coraza/crs-rules # live CRS dir (seeded from image bundle)
- coraza-logs:/var/log/coraza
networks:
- waf-internal
depends_on:
postgres:
condition: service_healthy
redis:
condition: service_healthy
healthcheck:
test: ["CMD", "wget", "-q", "-O-", "http://localhost:8000/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 30s
deploy:
resources:
limits:
cpus: "1.0"
memory: 512M
restart: unless-stopped
# ---------------------------------------------------------------------------
# React Admin UI (served by Nginx, HTTPS on 8443)
# ---------------------------------------------------------------------------
admin-ui:
image: ghcr.io/socfortress/waf-admin-ui:${WAF_IMAGE_TAG:-latest}
container_name: admin-ui
ports:
- "8443:8080"
volumes:
- tls-certs:/etc/nginx/certs # shared with admin-api for cert upload + reload
networks:
- waf-internal
depends_on:
admin-api:
condition: service_healthy
healthcheck:
test: ["CMD", "wget", "-q", "--no-check-certificate", "-O-", "https://localhost:8080/"]
interval: 30s
timeout: 10s
retries: 3
start_period: 30s
deploy:
resources:
limits:
cpus: "0.5"
memory: 128M
restart: unless-stopped
# ---------------------------------------------------------------------------
# PostgreSQL 16
# ---------------------------------------------------------------------------
postgres:
image: postgres:16.3-alpine
container_name: postgres
env_file: .env
volumes:
- postgres-data:/var/lib/postgresql/data
networks:
- waf-internal
healthcheck:
test: ["CMD-SHELL", "pg_isready -U $$POSTGRES_USER -d $$POSTGRES_DB"]
interval: 10s
timeout: 5s
retries: 5
start_period: 10s
deploy:
resources:
limits:
cpus: "1.0"
memory: 512M
restart: unless-stopped
# ---------------------------------------------------------------------------
# Redis 7
# ---------------------------------------------------------------------------
redis:
image: redis:7.2.5-alpine
container_name: redis
user: redis
command: ["redis-server", "--appendonly", "yes"]
volumes:
- redis-data:/data
networks:
- waf-internal
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 10s
timeout: 5s
retries: 5
start_period: 5s
deploy:
resources:
limits:
cpus: "0.5"
memory: 256M
restart: unless-stopped
# =============================================================================
# Networks
# =============================================================================
networks:
proxy:
external: true
proxydb:
external: true
waf-internal:
driver: bridge
# =============================================================================
# Named volumes
# =============================================================================
volumes:
coraza-rules:
coraza-custom:
coraza-logs:
caddy-config:
crs-data:
geoip-data:
postgres-data:
redis-data:
tls-certs:
```