{"config":{"lang":["en"],"separator":"[\\s\\u200b\\-_,:!=\\[\\]()\"`/]+|\\.(?!\\d)|&[lg]t;|(?!\\b)(?=[A-Z][a-z])","pipeline":["stopWordFilter"]},"docs":[{"location":"","title":"Welcome to Changemaker Lite","text":"
Stop feeding your secrets to corporations. Own your political infrastructure.
"},{"location":"#quick-start","title":"Quick Start","text":"Get up and running in minutes:
# Clone the repository\ngit clone https://gitea.bnkops.com/admin/changemaker.lite\ncd changemaker.lite\n\n# Configure environment\n./config.sh\n\n# Start all services\ndocker compose up -d\n\n# For production deployment with Cloudflare tunnels\n./start-production.sh\n"},{"location":"#services","title":"Services","text":"Changemaker Lite includes these essential services:
"},{"location":"#core-services","title":"Core Services","text":"./config.sh to configure your environmentdocker compose up -d./start-production.shchangemaker.lite/\n\u251c\u2500\u2500 docker-compose.yml # Service definitions\n\u251c\u2500\u2500 config.sh # Configuration wizard\n\u251c\u2500\u2500 start-production.sh # Production deployment script\n\u251c\u2500\u2500 mkdocs/ # Documentation source\n\u2502 \u251c\u2500\u2500 docs/ # Markdown files\n\u2502 \u2514\u2500\u2500 mkdocs.yml # MkDocs configuration\n\u251c\u2500\u2500 configs/ # Service configurations\n\u2502 \u251c\u2500\u2500 homepage/ # Homepage dashboard config\n\u2502 \u251c\u2500\u2500 code-server/ # VS Code settings\n\u2502 \u2514\u2500\u2500 cloudflare/ # Tunnel configurations\n\u251c\u2500\u2500 map/ # Map application\n\u2502 \u251c\u2500\u2500 app/ # Node.js application\n\u2502 \u251c\u2500\u2500 Dockerfile # Container definition\n\u2502 \u2514\u2500\u2500 .env # Map configuration\n\u2514\u2500\u2500 assets/ # Shared assets\n \u251c\u2500\u2500 images/ # Image files\n \u251c\u2500\u2500 icons/ # Service icons\n \u2514\u2500\u2500 uploads/ # Listmonk uploads\n"},{"location":"#key-features","title":"Key Features","text":"lololol
okay well just doing some fast writing because why the heck not.
\"I would ask for an apology from the city (Municipality of Jasper) as a result,\"
lololol
"},{"location":"adv/","title":"Advanced Configurations","text":"We are also publishing how BNKops does several advanced workflows. These include things like assembling hardware, how to manage a network, how to manage several changemakers simultaneously, and integrating AI.
"},{"location":"adv/ansible/","title":"Setting Up Ansible with Tailscale for Remote Server Management","text":""},{"location":"adv/ansible/#overview","title":"Overview","text":"This guide walks you through setting up Ansible to manage remote servers (like ThinkCentre units) using Tailscale for secure networking. This approach provides reliable remote access without complex port forwarding or VPN configurations.
In plainer language; this allows you to manage several Changemaker nodes remotely. If you are a full time campaigner, this can enable you to manage several campaigns infrastructure from a central location while each user gets their own Changemaker box.
"},{"location":"adv/ansible/#what-youll-learn","title":"What You'll Learn","text":"# Create project directory\nmkdir ~/ansible_quickstart\ncd ~/ansible_quickstart\n\n# Create directory structure\nmkdir -p group_vars host_vars roles playbooks\n"},{"location":"adv/ansible/#2-install-ansible","title":"2. Install Ansible","text":"sudo apt update\nsudo apt install ansible\n"},{"location":"adv/ansible/#3-generate-ssh-keys-if-not-already-done","title":"3. Generate SSH Keys (if not already done)","text":"# Generate SSH key pair\nssh-keygen -t rsa -b 4096 -f ~/.ssh/id_rsa\n\n# Display public key (save this for later)\ncat ~/.ssh/id_rsa.pub\n"},{"location":"adv/ansible/#part-2-target-node-setup-physical-access-required-initially","title":"Part 2: Target Node Setup (Physical Access Required Initially)","text":""},{"location":"adv/ansible/#1-enable-ssh-on-target-node","title":"1. Enable SSH on Target Node","text":"Access each target node physically (monitor + keyboard):
# Update system\nsudo apt update && sudo apt upgrade -y\n\n# Install and enable SSH\nsudo apt install openssh-server\nsudo systemctl enable ssh\nsudo systemctl start ssh\n\n# Check SSH status\nsudo systemctl status ssh\n Note: If you get \"Unit ssh.service could not be found\", you need to install the SSH server first:
# Install OpenSSH server\nsudo apt install openssh-server\n\n# Then start and enable SSH\nsudo systemctl start ssh\nsudo systemctl enable ssh\n\n# Verify SSH is running and listening\nsudo ss -tlnp | grep :22\n You should see SSH listening on port 22.
"},{"location":"adv/ansible/#2-configure-ssh-key-authentication","title":"2. Configure SSH Key Authentication","text":"# Create .ssh directory\nmkdir -p ~/.ssh\nchmod 700 ~/.ssh\n\n# Create authorized_keys file\nnano ~/.ssh/authorized_keys\n Paste your public key from the master node, then:
# Set proper permissions\nchmod 600 ~/.ssh/authorized_keys\n"},{"location":"adv/ansible/#3-configure-ssh-security","title":"3. Configure SSH Security","text":"# Edit SSH config\nsudo nano /etc/ssh/sshd_config\n Ensure these lines are uncommented:
PubkeyAuthentication yes\nAuthorizedKeysFile .ssh/authorized_keys .ssh/authorized_keys2\n # Restart SSH service\nsudo systemctl restart ssh\n"},{"location":"adv/ansible/#4-configure-firewall","title":"4. Configure Firewall","text":"# Check firewall status\nsudo ufw status\n\n# Allow SSH through firewall\nsudo ufw allow ssh\n\n# Fix home directory permissions (required for SSH keys)\nchmod 755 ~/\n"},{"location":"adv/ansible/#part-3-test-local-ssh-connection","title":"Part 3: Test Local SSH Connection","text":"Before proceeding with remote access, test SSH connectivity locally:
# From master node, test SSH to target\nssh username@<target-local-ip>\n Common Issues and Solutions:
sudo ufw allow ssh)PubkeyAuthentication yes is setWe initially tried Cloudflare Tunnels but encountered complexity with:
Tailscale is superior because:
# Install Tailscale\ncurl -fsSL https://tailscale.com/install.sh | sh\n\n# Connect to Tailscale network\nsudo tailscale up\n Follow the authentication URL to connect with your Google/Microsoft/GitHub account.
"},{"location":"adv/ansible/#2-install-tailscale-on-target-nodes","title":"2. Install Tailscale on Target Nodes","text":"On each target node:
# Install Tailscale\ncurl -fsSL https://tailscale.com/install.sh | sh\n\n# Connect to Tailscale network\nsudo tailscale up\n Authenticate each device through the provided URL.
"},{"location":"adv/ansible/#3-get-tailscale-ip-addresses","title":"3. Get Tailscale IP Addresses","text":"On each machine:
# Get your Tailscale IP\ntailscale ip -4\n Each device receives a persistent IP like 100.x.x.x.
# Create inventory.ini\ncd ~/ansible_quickstart\nnano inventory.ini\n Content:
[thinkcenter]\ntc-node1 ansible_host=100.x.x.x ansible_user=your-username\ntc-node2 ansible_host=100.x.x.x ansible_user=your-username\n\n[all:vars]\nansible_ssh_private_key_file=~/.ssh/id_rsa\nansible_host_key_checking=False\n Replace:
100.x.x.x with actual Tailscale IPsyour-username with your actual username# Test connection to all nodes\nansible all -i inventory.ini -m ping\n Expected output:
tc-node1 | SUCCESS => {\n \"changed\": false,\n \"ping\": \"pong\"\n}\n"},{"location":"adv/ansible/#part-6-create-and-run-playbooks","title":"Part 6: Create and Run Playbooks","text":""},{"location":"adv/ansible/#1-simple-information-gathering-playbook","title":"1. Simple Information Gathering Playbook","text":"mkdir -p playbooks\nnano playbooks/info-playbook.yml\n Content:
---\n- name: Gather Node Information\n hosts: all\n tasks:\n - name: Get system information\n setup:\n\n - name: Display basic system info\n debug:\n msg: |\n Hostname: {{ ansible_hostname }}\n Operating System: {{ ansible_distribution }} {{ ansible_distribution_version }}\n Architecture: {{ ansible_architecture }}\n Memory: {{ ansible_memtotal_mb }}MB\n CPU Cores: {{ ansible_processor_vcpus }}\n\n - name: Show disk usage\n command: df -h /\n register: disk_info\n\n - name: Display disk usage\n debug:\n msg: \"Root filesystem usage: {{ disk_info.stdout_lines[1] }}\"\n\n - name: Check uptime\n command: uptime\n register: uptime_info\n\n - name: Display uptime\n debug:\n msg: \"System uptime: {{ uptime_info.stdout }}\"\n"},{"location":"adv/ansible/#2-run-the-playbook","title":"2. Run the Playbook","text":"ansible-playbook -i inventory.ini playbooks/info-playbook.yml\n"},{"location":"adv/ansible/#part-7-advanced-playbook-example","title":"Part 7: Advanced Playbook Example","text":""},{"location":"adv/ansible/#system-setup-playbook","title":"System Setup Playbook","text":"nano playbooks/setup-node.yml\n Content:
---\n- name: Setup ThinkCentre Node\n hosts: all\n become: yes\n tasks:\n - name: Update package cache\n apt:\n update_cache: yes\n\n - name: Install essential packages\n package:\n name:\n - htop\n - vim\n - curl\n - git\n - docker.io\n state: present\n\n - name: Add user to docker group\n user:\n name: \"{{ ansible_user }}\"\n groups: docker\n append: yes\n\n - name: Create management directory\n file:\n path: /opt/management\n state: directory\n owner: \"{{ ansible_user }}\"\n group: \"{{ ansible_user }}\"\n"},{"location":"adv/ansible/#troubleshooting-guide","title":"Troubleshooting Guide","text":""},{"location":"adv/ansible/#ssh-issues","title":"SSH Issues","text":"Problem: SSH connection hangs
sudo ufw status and sudo ufw allow sshsudo systemctl status sshProblem: Permission denied (publickey)
chmod 600 ~/.ssh/authorized_keyschmod 755 ~/PubkeyAuthentication yesProblem: Bad owner or permissions on SSH config
chmod 600 ~/.ssh/config\n"},{"location":"adv/ansible/#ansible-issues","title":"Ansible Issues","text":"Problem: Host key verification failed
ansible_host_key_checking=FalseProblem: Ansible command not found
sudo apt install ansible\n Problem: Connection timeouts
ping <tailscale-ip>tailscale statusProblem: Can't connect to Tailscale IP
tailscale statussudo systemctl status tailscaledsudo tailscale up[thinkcenter]\ntc-node1 ansible_host=100.125.148.60 ansible_user=bunker-admin\ntc-node2 ansible_host=100.x.x.x ansible_user=bunker-admin\ntc-node3 ansible_host=100.x.x.x ansible_user=bunker-admin\n"},{"location":"adv/ansible/#group-management","title":"Group Management","text":"[webservers]\ntc-node1 ansible_host=100.x.x.x ansible_user=bunker-admin\ntc-node2 ansible_host=100.x.x.x ansible_user=bunker-admin\n\n[databases]\ntc-node3 ansible_host=100.x.x.x ansible_user=bunker-admin\n\n[all:vars]\nansible_ssh_private_key_file=~/.ssh/id_rsa\nansible_host_key_checking=False\n Run playbooks on specific groups:
ansible-playbook -i inventory.ini -l webservers playbook.yml\n"},{"location":"adv/ansible/#best-practices","title":"Best Practices","text":""},{"location":"adv/ansible/#security","title":"Security","text":"become: yes only when necessaryansible_quickstart/\n\u251c\u2500\u2500 inventory.ini\n\u251c\u2500\u2500 group_vars/\n\u251c\u2500\u2500 host_vars/\n\u251c\u2500\u2500 roles/\n\u2514\u2500\u2500 playbooks/\n \u251c\u2500\u2500 info-playbook.yml\n \u251c\u2500\u2500 setup-node.yml\n \u2514\u2500\u2500 maintenance.yml\n"},{"location":"adv/ansible/#monitoring-and-maintenance","title":"Monitoring and Maintenance","text":"Create regular maintenance playbooks:
- name: System maintenance\n hosts: all\n become: yes\n tasks:\n - name: Update all packages\n apt:\n upgrade: dist\n update_cache: yes\n\n - name: Clean package cache\n apt:\n autoclean: yes\n autoremove: yes\n"},{"location":"adv/ansible/#alternative-approaches-we-considered","title":"Alternative Approaches We Considered","text":""},{"location":"adv/ansible/#cloudflare-tunnels","title":"Cloudflare Tunnels","text":"This setup provides:
The combination of Ansible + Tailscale is ideal for managing distributed infrastructure without the complexity of traditional VPN setups or the limitations of cloud-specific solutions.
"},{"location":"adv/ansible/#quick-reference-commands","title":"Quick Reference Commands","text":"# Check Tailscale status\ntailscale status\n\n# Test Ansible connectivity\nansible all -i inventory.ini -m ping\n\n# Run playbook on all hosts\nansible-playbook -i inventory.ini playbook.yml\n\n# Run playbook on specific group\nansible-playbook -i inventory.ini -l groupname playbook.yml\n\n# Run single command on all hosts\nansible all -i inventory.ini -m command -a \"uptime\"\n\n# SSH to node via Tailscale\nssh username@100.x.x.x\n"},{"location":"adv/vscode-ssh/","title":"Remote Development with VSCode over Tailscale","text":""},{"location":"adv/vscode-ssh/#overview","title":"Overview","text":"This guide describes how to set up Visual Studio Code for remote development on servers using the Tailscale network. This enables development directly on remote machines as if they were local, with full access to files, terminals, and debugging capabilities.
"},{"location":"adv/vscode-ssh/#what-youll-learn","title":"What You'll Learn","text":"Before starting, verify the setup:
# Check Tailscale connectivity\ntailscale status\n\n# Test SSH access\nssh <username>@<tailscale-ip>\n\n# Check VSCode is installed\ncode --version\n"},{"location":"adv/vscode-ssh/#part-1-install-and-configure-remote-ssh-extension","title":"Part 1: Install and Configure Remote-SSH Extension","text":""},{"location":"adv/vscode-ssh/#1-install-the-remote-development-extensions","title":"1. Install the Remote Development Extensions","text":"Option A: Install Remote Development Pack (Recommended)
This pack includes:
Option B: Install Individual Extension
After installation, the following should be visible:
Method A: Through VSCode
Method B: Direct File Editing
# Edit SSH config file directly\nnano ~/.ssh/config\n"},{"location":"adv/vscode-ssh/#2-add-server-configurations","title":"2. Add Server Configurations","text":"Add servers to the SSH config file:
# Example Node\nHost node1\n HostName <tailscale-ip>\n User <username>\n IdentityFile ~/.ssh/id_rsa\n ForwardAgent yes\n ServerAliveInterval 60\n ServerAliveCountMax 3\n\n# Additional nodes (add as needed)\nHost node2\n HostName <tailscale-ip>\n User <username>\n IdentityFile ~/.ssh/id_rsa\n ForwardAgent yes\n ServerAliveInterval 60\n ServerAliveCountMax 3\n Configuration Options Explained:
Host: Friendly name for the connectionHostName: Tailscale IP addressUser: Username on the remote serverIdentityFile: Path to the SSH private keyForwardAgent: Enables SSH agent forwarding for Git operationsServerAliveInterval: Keeps connection alive (prevents timeouts)ServerAliveCountMax: Number of keepalive attempts# Ensure SSH config has correct permissions\nchmod 600 ~/.ssh/config\n\n# Verify SSH key permissions\nchmod 600 ~/.ssh/id_rsa\nchmod 644 ~/.ssh/id_rsa.pub\n"},{"location":"adv/vscode-ssh/#part-3-connect-to-remote-servers","title":"Part 3: Connect to Remote Servers","text":""},{"location":"adv/vscode-ssh/#1-connect-via-command-palette","title":"1. Connect via Command Palette","text":"node1)On first connection, VSCode will:
Expected Timeline: - First connection: 1-3 minutes (installs VSCode Server) - Subsequent connections: 10-30 seconds
"},{"location":"adv/vscode-ssh/#part-4-remote-development-environment-setup","title":"Part 4: Remote Development Environment Setup","text":""},{"location":"adv/vscode-ssh/#1-open-remote-workspace","title":"1. Open Remote Workspace","text":"Once connected:
# In the VSCode terminal (now running on remote server)\n# Navigate to the project directory\ncd /home/<username>/projects\n\n# Open current directory in VSCode\ncode .\n\n# Or open a specific project\ncode /opt/myproject\n"},{"location":"adv/vscode-ssh/#2-install-extensions-on-remote-server","title":"2. Install Extensions on Remote Server","text":"Extensions must be installed separately on the remote server:
Essential Development Extensions:
To Install:
# In VSCode terminal (remote)\ngit config --global user.name \"<Full Name>\"\ngit config --global user.email \"<email@example.com>\"\n\n# Test Git connectivity\ngit clone https://github.com/<username>/<repo>.git\n"},{"location":"adv/vscode-ssh/#part-5-remote-development-workflows","title":"Part 5: Remote Development Workflows","text":""},{"location":"adv/vscode-ssh/#1-file-management","title":"1. File Management","text":"File Explorer:
File Transfer:
# Upload files to remote (from local terminal)\nscp localfile.txt <username>@<tailscale-ip>:/home/<username>/\n\n# Download files from remote\nscp <username>@<tailscale-ip>:/remote/path/file.txt ./local/path/\n"},{"location":"adv/vscode-ssh/#2-terminal-usage","title":"2. Terminal Usage","text":"Integrated Terminal:
Common Remote Terminal Commands:
# Check system resources\nhtop\ndf -h\nfree -h\n\n# Install packages\nsudo apt update\nsudo apt install nodejs npm\n\n# Start services\nsudo systemctl start nginx\nsudo docker-compose up -d\n"},{"location":"adv/vscode-ssh/#3-port-forwarding","title":"3. Port Forwarding","text":"Automatic Port Forwarding: VSCode automatically detects and forwards common development ports.
Manual Port Forwarding:
http://localhost:port on the local machineExample: Web Development
# Start a web server on remote (port 3000)\nnpm start\n\n# VSCode automatically suggests forwarding port 3000\n# Access at http://localhost:3000 on the local machine\n"},{"location":"adv/vscode-ssh/#4-debugging-remote-applications","title":"4. Debugging Remote Applications","text":"Python Debugging:
// .vscode/launch.json on remote server\n{\n \"version\": \"0.2.0\",\n \"configurations\": [\n {\n \"name\": \"Python: Current File\",\n \"type\": \"python\",\n \"request\": \"launch\",\n \"program\": \"${file}\",\n \"console\": \"integratedTerminal\"\n }\n ]\n}\n Node.js Debugging:
// .vscode/launch.json\n{\n \"version\": \"0.2.0\",\n \"configurations\": [\n {\n \"name\": \"Launch Program\",\n \"type\": \"node\",\n \"request\": \"launch\",\n \"program\": \"${workspaceFolder}/app.js\"\n }\n ]\n}\n"},{"location":"adv/vscode-ssh/#part-6-advanced-configuration","title":"Part 6: Advanced Configuration","text":""},{"location":"adv/vscode-ssh/#1-workspace-settings","title":"1. Workspace Settings","text":"Create remote-specific settings:
// .vscode/settings.json (on remote server)\n{\n \"python.defaultInterpreterPath\": \"/usr/bin/python3\",\n \"terminal.integrated.shell.linux\": \"/bin/bash\",\n \"files.autoSave\": \"afterDelay\",\n \"editor.formatOnSave\": true,\n \"remote.SSH.remotePlatform\": {\n \"node1\": \"linux\"\n }\n}\n"},{"location":"adv/vscode-ssh/#2-multi-server-management","title":"2. Multi-Server Management","text":"Switch Between Servers:
Compare Files Across Servers:
Settings Sync:
# On remote server\n# Create virtual environment\npython3 -m venv venv\nsource venv/bin/activate\n\n# Install packages\npip install flask django requests\n\n# VSCode automatically detects Python interpreter\n VSCode Python Configuration:
// .vscode/settings.json\n{\n \"python.defaultInterpreterPath\": \"./venv/bin/python\",\n \"python.linting.enabled\": true,\n \"python.linting.pylintEnabled\": true\n}\n"},{"location":"adv/vscode-ssh/#2-nodejs-development","title":"2. Node.js Development","text":"# On remote server\n# Install Node.js\ncurl -fsSL https://deb.nodesource.com/setup_18.x | sudo -E bash -\nsudo apt-get install -y nodejs\n\n# Create project\nmkdir myapp && cd myapp\nnpm init -y\nnpm install express\n"},{"location":"adv/vscode-ssh/#3-docker-development","title":"3. Docker Development","text":"# On remote server\n# Install Docker (if not already done via Ansible)\nsudo apt install docker.io docker-compose\nsudo usermod -aG docker $USER\n\n# Create Dockerfile\ncat > Dockerfile << EOF\nFROM node:18\nWORKDIR /app\nCOPY package*.json ./\nRUN npm install\nCOPY . .\nEXPOSE 3000\nCMD [\"npm\", \"start\"]\nEOF\n VSCode Docker Integration:
Problem: \"Could not establish connection to remote host\"
Solutions:
# Check Tailscale connectivity\ntailscale status\nping <tailscale-ip>\n\n# Test SSH manually\nssh <username>@<tailscale-ip>\n\n# Check SSH config syntax\nssh -T node1\n Problem: \"Permission denied (publickey)\"
Solutions:
# Check SSH key permissions\nchmod 600 ~/.ssh/id_rsa\nchmod 600 ~/.ssh/config\n\n# Verify SSH agent\nssh-add ~/.ssh/id_rsa\nssh-add -l\n\n# Test SSH connection verbosely\nssh -v <username>@<tailscale-ip>\n Problem: \"Host key verification failed\"
Solutions:
# Remove old host key\nssh-keygen -R <tailscale-ip>\n\n# Or disable host key checking (less secure)\n# Add to SSH config:\n# StrictHostKeyChecking no\n"},{"location":"adv/vscode-ssh/#vscode-specific-issues","title":"VSCode-Specific Issues","text":"Problem: Extensions not working on remote
Solutions:
Problem: Slow performance
Solutions: - Use .vscode/settings.json to exclude large directories:
{\n \"files.watcherExclude\": {\n \"**/node_modules/**\": true,\n \"**/.git/objects/**\": true,\n \"**/dist/**\": true\n }\n}\n Problem: Terminal not starting
Solutions:
# Check shell path in remote settings\n\"terminal.integrated.shell.linux\": \"/bin/bash\"\n\n# Or let VSCode auto-detect\n\"terminal.integrated.defaultProfile.linux\": \"bash\"\n"},{"location":"adv/vscode-ssh/#network-and-performance-issues","title":"Network and Performance Issues","text":"Problem: Connection timeouts
Solutions: Add to SSH config:
ServerAliveInterval 60\nServerAliveCountMax 3\nTCPKeepAlive yes\n Problem: File transfer slow
Solutions: - Use .vscodeignore to exclude unnecessary files - Compress large files before transfer - Use rsync for large file operations:
rsync -avz --progress localdir/ <username>@<tailscale-ip>:remotedir/\n"},{"location":"adv/vscode-ssh/#part-9-best-practices","title":"Part 9: Best Practices","text":""},{"location":"adv/vscode-ssh/#security-best-practices","title":"Security Best Practices","text":"Exclude unnecessary files:
// .vscode/settings.json\n{\n \"files.watcherExclude\": {\n \"**/node_modules/**\": true,\n \"**/.git/**\": true,\n \"**/dist/**\": true,\n \"**/build/**\": true\n },\n \"search.exclude\": {\n \"**/node_modules\": true,\n \"**/bower_components\": true,\n \"**/*.code-search\": true\n }\n}\n Use remote workspace for large projects
Use version control effectively:
# Always work in Git repositories\ngit status\ngit add .\ngit commit -m \"feature: add new functionality\"\ngit push origin main\n Environment separation:
# Development\nssh node1\ncd /home/<username>/dev-projects\n\n# Production\nssh node2\ncd /opt/production-apps\n Backup important work:
# Regular backups via Git\ngit push origin main\n\n# Or manual backup\nscp -r <username>@<tailscale-ip>:/important/project ./backup/\n SSH Config for Team:
# Shared development server\nHost team-dev\n HostName <tailscale-ip>\n User <team-user>\n IdentityFile ~/.ssh/team_dev_key\n ForwardAgent yes\n\n# Personal development\nHost my-dev\n HostName <tailscale-ip>\n User <username>\n IdentityFile ~/.ssh/id_rsa\n"},{"location":"adv/vscode-ssh/#project-structure","title":"Project Structure","text":"/opt/projects/\n\u251c\u2500\u2500 project-a/\n\u2502 \u251c\u2500\u2500 dev/ # Development branch\n\u2502 \u251c\u2500\u2500 staging/ # Staging environment\n\u2502 \u2514\u2500\u2500 docs/ # Documentation\n\u251c\u2500\u2500 project-b/\n\u2514\u2500\u2500 shared-tools/ # Common utilities\n"},{"location":"adv/vscode-ssh/#access-management","title":"Access Management","text":"# Create shared project directory\nsudo mkdir -p /opt/projects\nsudo chown -R :developers /opt/projects\nsudo chmod -R g+w /opt/projects\n\n# Add users to developers group\nsudo usermod -a -G developers <username>\n"},{"location":"adv/vscode-ssh/#quick-reference","title":"Quick Reference","text":""},{"location":"adv/vscode-ssh/#essential-vscode-remote-commands","title":"Essential VSCode Remote Commands","text":"# Command Palette shortcuts\nCtrl+Shift+P \u2192 \"Remote-SSH: Connect to Host...\"\nCtrl+Shift+P \u2192 \"Remote-SSH: Open SSH Configuration File...\"\nCtrl+Shift+P \u2192 \"Remote-SSH: Kill VS Code Server on Host...\"\n\n# Terminal\nCtrl+` \u2192 Open integrated terminal\nCtrl+Shift+` \u2192 Create new terminal\n\n# File operations\nCtrl+O \u2192 Open file\nCtrl+S \u2192 Save file\nCtrl+Shift+E \u2192 Focus file explorer\n"},{"location":"adv/vscode-ssh/#ssh-connection-quick-test","title":"SSH Connection Quick Test","text":"# Test connectivity\nssh -T node1\n\n# Connect with verbose output\nssh -v <username>@<tailscale-ip>\n\n# Check SSH config\nssh -F ~/.ssh/config node1\n"},{"location":"adv/vscode-ssh/#port-forwarding-commands","title":"Port Forwarding Commands","text":"# Manual port forwarding\nssh -L 3000:localhost:3000 <username>@<tailscale-ip>\n\n# Background tunnel\nssh -f -N -L 8080:localhost:80 <username>@<tailscale-ip>\n"},{"location":"adv/vscode-ssh/#conclusion","title":"Conclusion","text":"This remote development setup provides:
The combination of VSCode Remote Development with Tailscale networking creates a powerful, flexible development environment that works from anywhere while maintaining security and performance.
Whether developing Python applications, Node.js services, or managing Docker containers, this setup provides a professional remote development experience that rivals local development while leveraging the power and resources of remote servers.
"},{"location":"blog/2025/07/03/blog-1/","title":"Blog 1","text":"Hello! Just putting something up here because, well, gosh darn, feels like the right thing to do.
Making swift progress. Can now write things fast as heck lad.
"},{"location":"blog/2025/07/10/2/","title":"2","text":"Wow. Big build day. Added (admittedly still buggy) shifts support to the system. Power did it in a day.
Other updates recently include:
server.js into modular components. Need to make more content about how to use the system in general too.
"},{"location":"blog/2025/08/01/3/","title":"3","text":"Alrighty yall, it was a wild month of development, and we have a lot to cover! Here\u2019s the latest on Changemaker Lite, including our new landing page, major updates to the map application, and a comprehensive overview of all changes made in the last month.
Campaigning is going! We have candidates working the system in the field, and we\u2019re excited to see how it performs in real-world scenarios.
"},{"location":"blog/2025/08/01/3/#monthly-development-report-august-2025","title":"Monthly Development Report \u2013 August 2025","text":""},{"location":"blog/2025/08/01/3/#git-change-summary-julyaugust-2025","title":"Git Change Summary (July\u2013August 2025)","text":"Below is a summary of all changes pushed to git in the last month:
For a detailed commit log, see git-report.txt.
lander.html","text":"The lander.html file is a modern, responsive landing page for Changemaker Lite, featuring:
The page is styled with CSS variables for easy theming and includes scripts for search, theme switching, and smooth scrolling.
"},{"location":"blog/2025/08/01/3/#new-features-in-map-readmemd","title":"New Features in Map (README.md)","text":"The map application has received significant upgrades:
API Endpoints: Comprehensive REST API for locations, shifts, authentication, admin, and geocoding, all with rate limiting and security features.
Database Schema: Auto-created tables for locations, users, settings, shifts, and signups, with detailed field definitions.
For more details, see the full README.md and explore the live application.
Welcome to Changemaker-Lite! You're about to reclaim your digital sovereignty and stop feeding your secrets to corporations. This guide will help you set up your own political infrastructure that you actually own and control.
This documentation is broken into a few sections, which you can see in the navigation bar to the left:
Of course, everything is also searachable, so if you want to find something specific, just use the search bar at the top right.
If you come across anything that is unclear, please open an issue in the Git Repository, reach out to us at admin@thebunkerops.ca, or edit it yourself by clicking the pencil icon at the top right of each page.
"},{"location":"build/#quick-start","title":"Quick Start","text":""},{"location":"build/#build-changemaker-lite","title":"Build Changemaker-Lite","text":"# Clone the repository\ngit clone https://gitea.bnkops.com/admin/changemaker.lite\ncd changemaker.lite\n Cloudflare Credentials
The config.sh script will ask you for your optional Cloudflare credentials to get started. You can find more information on how to find this in the Cloudlflare Configuration
# Configure environment (creates .env file)\n./config.sh\n # Start all services\ndocker compose up -d\n"},{"location":"build/#optional-site-builld","title":"Optional - Site Builld","text":"If you want to have your site prepared for launch, you can now proceed with reseting the site build. See Build Site for more detials.
"},{"location":"build/#deploy","title":"Deploy","text":"Cloudflare
Right now, we suggest deploying using Cloudflare for simplicity and protections against 99% of surface level attacks to digital infrastructure. If you want to avoid using this service, we recommend checking out Pagolin as a drop in replacement.
For secure public access, use the production deployment script:
./start-production.sh\n"},{"location":"build/#map","title":"Map","text":"Map is the canvassing application that is custom view of nocodb data. Map is best built after production deployment to reduce duplicate build efforts.
Instructions on how to build the map are available in the map manual in the build directory.
"},{"location":"build/#quick-start-for-map","title":"Quick Start for Map","text":"Get your NocoDB API token and URL, update the .env file in the map directory, and then run:
cd map\nchmod +x build-nocodb.sh # builds the nocodb tables\n./build-nocodb.sh\n Copy the urls of the newly created nocodb views and update the .env file in the map directory with them, and then run: cd map\ndocker compose up -d\n You Map instance will be available at http://localhost:3000 or on the domain you set up during production deployment.
"},{"location":"build/#why-changemaker-lite","title":"Why Changemaker Lite?","text":"Before we dive into the technical setup, let's be clear about what you're doing here:
The Reality
If you do politics, who is reading your secrets? Every corporate platform you use is extracting your power, selling your data, and building profiles on your community. It's time to break free.
"},{"location":"build/#what-youre-getting","title":"What You're Getting","text":"Getting Started on Ubuntu
Want some help getting started with a baseline buildout for a Ubuntu server? You can use our BNKops Server Build Script
New to Linux?
Consider Linux Mint - it looks like Windows but opens the door to true digital freedom.
"},{"location":"build/#hardware-requirements","title":"Hardware Requirements","text":"Cloud Hosting
You can run this on a VPS from providers like Hetzner, DigitalOcean, or Linode for ~$20/month.
"},{"location":"build/#software-prerequisites","title":"Software Prerequisites","text":"Ensure the following software is installed on your system. The BNKops Server Build Script can help set these up if you're on Ubuntu.
# Install Docker\ncurl -fsSL https://get.docker.com | sudo sh\n\n# Add your user to docker group\nsudo usermod -aG docker $USER\n\n# Log out and back in for group changes to take effect\n # Verify Docker Compose v2 is installed\ndocker compose version\n # Install required packages\nsudo apt update\nsudo apt install -y git curl jq openssl\n"},{"location":"build/#installation","title":"Installation","text":""},{"location":"build/#1-clone-repository","title":"1. Clone Repository","text":"git clone https://gitea.bnkops.com/admin/changemaker.lite\ncd changemaker.lite\n"},{"location":"build/#2-run-configuration-wizard","title":"2. Run Configuration Wizard","text":"The config.sh script will guide you through the initial setup:
./config.sh\n This wizard will:
.env file with secure defaultsDuring setup, you'll be prompted for:
example.com)Launch all services with Docker Compose:
docker compose up -d\n Wait for services to initialize (first run may take 5-10 minutes):
# Watch container status\ndocker compose ps\n\n# View logs\ndocker compose logs -f\n"},{"location":"build/#4-verify-installation","title":"4. Verify Installation","text":"Check that all services are running:
docker compose ps\n Expected output should show all services as \"Up\":
Once services are running, access them locally:
"},{"location":"build/#homepage-dashboard","title":"\ud83c\udfe0 Homepage Dashboard","text":"Map
Map is the canvassing application that is custom view of nocodb data. Map is best built after production deployment to reduce duplicate build efforts.
"},{"location":"build/#map-manual","title":"Map Manual","text":""},{"location":"build/#production-deployment","title":"Production Deployment","text":""},{"location":"build/#deploy-with-cloudflare-tunnels","title":"Deploy with Cloudflare Tunnels","text":"For secure public access, use the production deployment script:
./start-production.sh\n This script will:
cloudflaredchangemaker-liteAfter successful deployment, services will be available at:
Public Services:
https://yourdomain.com - Main documentation sitehttps://listmonk.yourdomain.com - Email campaignshttps://docs.yourdomain.com - Documentation previewhttps://n8n.yourdomain.com - Automation platformhttps://db.yourdomain.com - NocoDBhttps://git.yourdomain.com - Giteahttps://map.yourdomain.com - Map viewerhttps://qr.yourdomain.com - QR generatorProtected Services (require authentication):
https://homepage.yourdomain.com - Dashboardhttps://code.yourdomain.com - Code ServerKey settings in .env file:
# Domain Configuration\nDOMAIN=yourdomain.com\nBASE_DOMAIN=https://yourdomain.com\n\n# Service Ports (automatically assigned to avoid conflicts)\nHOMEPAGE_PORT=3010\nCODE_SERVER_PORT=8888\nLISTMONK_PORT=9000\nMKDOCS_PORT=4000\nMKDOCS_SITE_SERVER_PORT=4001\nN8N_PORT=5678\nNOCODB_PORT=8090\nGITEA_WEB_PORT=3030\nGITEA_SSH_PORT=2222\nMAP_PORT=3000\nMINI_QR_PORT=8089\n\n# Cloudflare (for production)\nCF_API_TOKEN=your_token\nCF_ZONE_ID=your_zone_id\nCF_ACCOUNT_ID=your_account_id\n"},{"location":"build/#reconfigure-services","title":"Reconfigure Services","text":"To update configuration:
# Re-run configuration wizard\n./config.sh\n\n# Restart services\ndocker compose down && docker compose up -d\n"},{"location":"build/#common-tasks","title":"Common Tasks","text":""},{"location":"build/#service-management","title":"Service Management","text":"# View all services\ndocker compose ps\n\n# View logs for specific service\ndocker compose logs -f [service-name]\n\n# Restart a service\ndocker compose restart [service-name]\n\n# Stop all services\ndocker compose down\n\n# Stop and remove all data (CAUTION!)\ndocker compose down -v\n"},{"location":"build/#backup-data","title":"Backup Data","text":"# Backup all volumes\ndocker run --rm -v changemaker_listmonk-data:/data -v $(pwd):/backup alpine tar czf /backup/listmonk-backup.tar.gz -C /data .\n\n# Backup configuration\ntar czf configs-backup.tar.gz configs/\n\n# Backup documentation\ntar czf docs-backup.tar.gz mkdocs/docs/\n"},{"location":"build/#update-services","title":"Update Services","text":"# Pull latest images\ndocker compose pull\n\n# Recreate containers with new images\ndocker compose up -d\n"},{"location":"build/#troubleshooting","title":"Troubleshooting","text":""},{"location":"build/#port-conflicts","title":"Port Conflicts","text":"If services fail to start due to port conflicts:
sudo ss -tulpn | grep LISTEN\n ./config.sh\n .env file and change conflicting portsFix permission problems:
# Get your user and group IDs\nid -u # User ID\nid -g # Group ID\n\n# Update .env file with correct IDs\nUSER_ID=1000\nGROUP_ID=1000\n\n# Restart services\ndocker compose down && docker compose up -d\n"},{"location":"build/#service-wont-start","title":"Service Won't Start","text":"Debug service issues:
# Check detailed logs\ndocker compose logs [service-name] --tail 50\n\n# Check container status\ndocker ps -a\n\n# Inspect container\ndocker inspect [container-name]\n"},{"location":"build/#cloudflare-tunnel-issues","title":"Cloudflare Tunnel Issues","text":"# Check tunnel service status\nsudo systemctl status cloudflared-changemaker\n\n# View tunnel logs\nsudo journalctl -u cloudflared-changemaker -f\n\n# Restart tunnel\nsudo systemctl restart cloudflared-changemaker\n"},{"location":"build/#next-steps","title":"Next Steps","text":"Now that your Changemaker Lite instance is running:
Map is BNKops canvassing application built for community organizing and door-to-door canvassing.
Complete Configuration
For detailed configuration, usage instructions, and troubleshooting, see the Map Configuration Guide.
Clean NocoDB
Currently the way to get a good result is to ensure the target nocodb database is empty. You can do this by deleting all bases. The script should still work with other volumes however may insert tables into odd locations; still debugging. Again, see config if needing to do manually.
"},{"location":"build/map/#prerequisites","title":"Prerequisites","text":"Edit the .env file in the map/ directory:
cd map\n Update your .env file with your NocoDB details, specifically the instance and api token:
NOCODB_API_URL=[change me]\nNOCODB_API_TOKEN=[change me]\n\n# NocoDB View URL is the URL to your NocoDB view where the map data is stored.\nNOCODB_VIEW_URL=[change me]\n\n# NOCODB_LOGIN_SHEET is the URL to your NocoDB login sheet.\nNOCODB_LOGIN_SHEET=[change me]\n\n# NOCODB_SETTINGS_SHEET is the URL to your NocoDB settings sheet.\nNOCODB_SETTINGS_SHEET=[change me]\n\n# NOCODB_SHIFTS_SHEET is the URL to your shifts sheet.\nNOCODB_SHIFTS_SHEET=[change me]\n\n# NOCODB_SHIFT_SIGNUPS_SHEET is the URL to your NocoDB shift signups sheet where users can add their own shifts.\nNOCODB_SHIFT_SIGNUPS_SHEET=[change me]\n\n# NOCODB_CUTS_SHEET is the URL to your NocoDB Cuts sheet.\nNOCODB_CUTS_SHEET=[change me]\n\nDOMAIN=[change me]\n\n# MkDocs Integration\nMKDOCS_URL=[change me]\nMKDOCS_SEARCH_URL=[change me]\nMKDOCS_SITE_SERVER_PORT=4002\n\n# Server Configuration\nPORT=3000\nNODE_ENV=production\n\n# Session Secret (IMPORTANT: Generate a secure random string for production)\nSESSION_SECRET=[change me]\n\n# Map Defaults (Edmonton, Alberta, Canada)\nDEFAULT_LAT=53.5461\nDEFAULT_LNG=-113.4938\nDEFAULT_ZOOM=11\n\n# Optional: Map Boundaries (prevents users from adding points outside area)\n# BOUND_NORTH=53.7\n# BOUND_SOUTH=53.4\n# BOUND_EAST=-113.3\n# BOUND_WEST=-113.7\n\n# Cloudflare Settings\nTRUST_PROXY=true\nCOOKIE_DOMAIN=[change me]\n\n# Update NODE_ENV to production for HTTPS\nNODE_ENV=production\n\n# Add allowed origin\nALLOWED_ORIGINS=[change me]\n\n# SMTP Configuration\nSMTP_HOST=[change me]\nSMTP_PORT=587 \nSMTP_SECURE=false\nSMTP_USER=[change me]\nSMTP_PASS=[change me]\nEMAIL_FROM_NAME=\"[change me]\"\nEMAIL_FROM_ADDRESS=[change me]\n\n# App Configuration\nAPP_NAME=\"[change me]\"\n\n# Listmonk Configuration\nLISTMONK_API_URL=[change me]\nLISTMONK_USERNAME=[change me]\nLISTMONK_PASSWORD=[change me]\nLISTMONK_SYNC_ENABLED=true\nLISTMONK_INITIAL_SYNC=false # Set to true only for first run to sync existing data\n"},{"location":"build/map/#3-auto-create-database-structure","title":"3. Auto-Create Database Structure","text":"Run the build script to create required tables:
chmod +x build-nocodb.sh\n./build-nocodb.sh\n This creates three tables: - Locations - Main map data with geo-location, contact info, support levels - Login - User authentication (email, name, admin flag) - Settings - Admin configuration and QR codes
"},{"location":"build/map/#4-get-table-urls","title":"4. Get Table URLs","text":"After the script completes:
https://your-nocodb.com/dashboard/#/nc/project-id/table-idEdit your .env file and add the table URLs:
# NocoDB View URL is the URL to your NocoDB view where the map data is stored.\nNOCODB_VIEW_URL=[change me]\n\n# NOCODB_LOGIN_SHEET is the URL to your NocoDB login sheet.\nNOCODB_LOGIN_SHEET=[change me]\n\n# NOCODB_SETTINGS_SHEET is the URL to your NocoDB settings sheet.\nNOCODB_SETTINGS_SHEET=[change me]\n\n# NOCODB_SHIFTS_SHEET is the URL to your shifts sheet.\nNOCODB_SHIFTS_SHEET=[change me]\n\n# NOCODB_SHIFT_SIGNUPS_SHEET is the URL to your NocoDB shift signups sheet where users can add their own shifts.\nNOCODB_SHIFT_SIGNUPS_SHEET=[change me]\n\n# NOCODB_CUTS_SHEET is the URL to your NocoDB Cuts sheet.\nNOCODB_CUTS_SHEET=[change me]\n"},{"location":"build/map/#6-build-and-deploy","title":"6. Build and Deploy","text":"Build the Docker image and start the application:
# Build the Docker image\ndocker-compose build\n\n# Start the application\ndocker-compose up -d\n"},{"location":"build/map/#verify-installation","title":"Verify Installation","text":"Check container status:
docker-compose ps\n View logs:
docker-compose logs -f map-viewer\n Access the application at http://localhost:3000
/admin.html for configurationdocker-compose down\ngit pull origin main\ndocker-compose build\ndocker-compose up -d\n"},{"location":"build/map/#development-mode","title":"Development Mode","text":"cd app\nnpm install\nnpm run dev\n"},{"location":"build/map/#health-check","title":"Health Check","text":"curl http://localhost:3000/health\n"},{"location":"build/map/#support","title":"Support","text":"For detailed configuration, troubleshooting, and usage instructions, see the Map Configuration Guide.
"},{"location":"build/server/","title":"BNKops Server Build","text":"Purpose: a Ubuntu server build-out for general application
This documentation is a overview of the full build out for a server OS and baseline for running Changemaker-lite. It is a manual to re-install this server on any machine.
All of the following systems are free and the majority are open source.
"},{"location":"build/server/#ubuntu-os","title":"Ubuntu OS","text":"Ubuntu is a Linux distribution derived from Debian and composed mostly of free and open-source software.
"},{"location":"build/server/#install-ubuntu","title":"Install Ubuntu","text":""},{"location":"build/server/#post-install","title":"Post Install","text":"Post installation, run update:
sudo apt update\n sudo apt upgrade\n"},{"location":"build/server/#configuration","title":"Configuration","text":"Further configurations:
Visual Studio Code is a new choice of tool that combines the simplicity of a code editor with what developers need for the core edit-build-debug cycle.
"},{"location":"build/server/#install-using-app-centre","title":"Install Using App Centre","text":""},{"location":"build/server/#obsidian","title":"Obsidian","text":"The free and flexible app for your private\u00a0thoughts.
"},{"location":"build/server/#install-using-app-center","title":"Install Using App Center","text":""},{"location":"build/server/#curl","title":"Curl","text":"command line tool and library for transferring data with URLs (since 1998)
"},{"location":"build/server/#install","title":"Install","text":"sudo apt install curl \n"},{"location":"build/server/#glances","title":"Glances","text":"Glances an Eye on your system. A top/htop alternative for GNU/Linux, BSD, Mac OS and Windows operating systems.
"},{"location":"build/server/#install_1","title":"Install","text":"sudo snap install glances \n"},{"location":"build/server/#syncthing","title":"Syncthing","text":"Syncthing is a continuous file synchronization program. It synchronizes files between two or more computers in real time, safely protected from prying eyes. Your data is your data alone and you deserve to choose where it is stored, whether it is shared with some third party, and how it\u2019s transmitted over the internet.
"},{"location":"build/server/#install_2","title":"Install","text":"# Add the release PGP keys:\nsudo mkdir -p /etc/apt/keyrings\nsudo curl -L -o /etc/apt/keyrings/syncthing-archive-keyring.gpg https://syncthing.net/release-key.gpg\n # Add the \"stable\" channel to your APT sources:\necho \"deb [signed-by=/etc/apt/keyrings/syncthing-archive-keyring.gpg] https://apt.syncthing.net/ syncthing stable\" | sudo tee /etc/apt/sources.list.d/syncthing.list\n # Update and install syncthing:\nsudo apt-get update\nsudo apt-get install syncthing\n"},{"location":"build/server/#post-install_1","title":"Post Install","text":"Run syncthing as a system service.
sudo systemctl start syncthing@yourusername\n sudo systemctl enable syncthing@yourusername\n"},{"location":"build/server/#docker","title":"Docker","text":"Docker helps developers build, share, run, and verify applications anywhere \u2014 without tedious environment configuration or management.
# Add Docker's official GPG key:\nsudo apt-get update\nsudo apt-get install ca-certificates curl\nsudo install -m 0755 -d /etc/apt/keyrings\nsudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc\nsudo chmod a+r /etc/apt/keyrings/docker.asc\n\n# Add the repository to Apt sources:\necho \\\n \"deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu \\\n $(. /etc/os-release && echo \"${UBUNTU_CODENAME:-$VERSION_CODENAME}\") stable\" | \\\n sudo tee /etc/apt/sources.list.d/docker.list > /dev/null\nsudo apt-get update\n sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin\n"},{"location":"build/server/#update-users","title":"Update Users","text":"sudo groupadd docker\n sudo usermod -aG docker $USER\n newgrp docker\n"},{"location":"build/server/#enable-on-boot","title":"Enable on Boot","text":"sudo systemctl enable docker.service\nsudo systemctl enable containerd.service\n"},{"location":"build/server/#cloudflared","title":"Cloudflared","text":"Connect, protect, and build everywhere. We make websites, apps, and networks faster and more secure. Our developer platform is the best place to build modern apps and deliver AI initiatives.
sudo mkdir -p --mode=0755 /usr/share/keyrings\ncurl -fsSL https://pkg.cloudflare.com/cloudflare-main.gpg | sudo tee /usr/share/keyrings/cloudflare-main.gpg >/dev/null\n echo \"deb [signed-by=/usr/share/keyrings/cloudflare-main.gpg] https://pkg.cloudflare.com/cloudflared any main\" | sudo tee /etc/apt/sources.list.d/cloudflared.list\n sudo apt-get update && sudo apt-get install cloudflared\n"},{"location":"build/server/#post-install_2","title":"Post Install","text":"Login to Cloudflare
cloudflared login\n"},{"location":"build/server/#configuration_1","title":"Configuration","text":"The ./config.sh and ./start-production.sh scripts will properly configure a Cloudflare tunnel and service to put your system online. More info in the Cloudflare Configuration.
If you need to convert files from one markup format into another, pandoc is your swiss-army knife.
sudo apt install pandoc\n"},{"location":"build/site/","title":"Building the Site with MkDocs Material","text":"Welcome! This guide will help you get started building and customizing your site using MkDocs Material.
"},{"location":"build/site/#reset-site","title":"Reset Site","text":"You can read through all the BNKops cmlite documentation already in your docs folder or you can reset your docs folder to a baseline to start and read more manuals here. To reset docs folder to baseline, run the following:
./reset-site.sh\n"},{"location":"build/site/#how-to-build-your-site-step-by-step","title":"\ud83d\ude80 How to Build Your Site (Step by Step)","text":"cd mkdocs\nmkdocs build\n This creates the static website from your documents and places them in the mkdocs/site directory.Preview your site locally: Visit localhost:4000 for local development or live.youdomain.com to see a public live load.
mkdocs/docs folder is included automatically.Material for MkDocs Documentation
Build vs Serve
Your website is built in stages. Any edits to documents in the mkdocs directory are instantly served and visible at localhost:4000 or if in production mode live.yourdomain.com. The live site is not meant as a public access point and will crash if too many requests are made to it.
Running mkdocs build pushes any changes to the site directory, which then a ngnix server pushes them to the production server for public access at your root domain (yourdomain.com).
You can think of it as serve/live = draft for personal review and build = save/push to production for the public.
This combination allows for rapid development of documentation while ensuring your live site does not get updated until your content is ready.
"},{"location":"build/site/#resetting-the-site","title":"\ud83e\uddf9 Resetting the Site","text":"If you want to start fresh:
Delete all folders EXCEPT these folders:
/blog/javascripts/hooks/assets/stylesheets/overridesReset the landing page:
index.md file and remove everything at the very top (the \"front matter\")./overrides/home.html to change the landing page.Reset the mkdocs.yml
mkdocs.yml and delete the nav section entirely. home.html.claude\nmkdocs.yml and remove the nav section to start with a blank menu. Add your own pages as you go.mkdocs serve (see above) to see changes instantly as you edit./assets, /stylesheets, /javascripts, or /overrides.Quick Start Guide
"},{"location":"build/site/#more-resources","title":"\ud83d\udcda More Resources","text":"Happy building!
"},{"location":"config/","title":"Configuration","text":"There are several configuration steps to building a production ready Changemaker-Lite.
In the order we suggest doing them:
"},{"location":"config/cloudflare-config/","title":"Configure Cloudflare","text":"Cloudflare is the largest DNS routing service on the planet. We use their free service tier to provide Changemaker users with a fast, secure, and reliable way to get online that blocks 99% of surface level attacks and has built in user authenticaion (if you so choose to use it)
"},{"location":"config/cloudflare-config/#credentials","title":"Credentials","text":"The config.sh and start-production.sh scripts require the following Cloudflare credentials to function properly:
Zone.DNS (Read/Write)Account.Cloudflare Tunnel (Read/Write)Access (Read/Write)Automatic Configuration of Tunnel
The start-production.sh script will automatically create a tunnel and system service for Cloudflare.
cloudflared tunnel create or via the Cloudflare dashboard.# In .env file\nCF_API_TOKEN=your_cloudflare_api_token\nCF_ZONE_ID=your_cloudflare_zone_id\nCF_ACCOUNT_ID=your_cloudflare_account_id\nCF_TUNNEL_ID=will_be_set_by_start_production # This will be set by start-production.sh\n"},{"location":"config/cloudflare-config/#notes","title":"Notes:","text":"This section describes the configuration and features of the code-server environment.
"},{"location":"config/coder/#accessing-code-server","title":"Accessing Code Server","text":"http://localhost:8080After the first build, the code-server password is stored in:
configs/code-server/.config/code-server/config.yaml\n Look for the password: field in that file. For example:
password: 0c0dca951a2d12eff1665817\n Note: It is recommended not to change this password manually, as it is securely generated.
"},{"location":"config/coder/#main-configuration-options","title":"Main Configuration Options","text":"bind-addr: The address and port code-server listens on (default: 127.0.0.1:8080)auth: Authentication method (default: password)password: The login password (see above)cert: Whether to use HTTPS (default: false)The code-server environment includes:
@anthropic-ai/claude-code) globally installedpython3-pip, python3-venv, python3-full, pipxCairoSVG, Pillow, libcairo2-dev, libfreetype6-dev, libjpeg-dev, libpng-dev, libwebp-dev, libtiff5-dev, libopenjp2-7-dev, liblcms2-devweasyprint, fonts-robotobuild-essential, pkg-config, python3-dev, zlib1g-dev/home/coder/.venv/mkdocsrun-mkdocs for running MkDocs commands easilyThe virtual environment for MkDocs is automatically added to your PATH. You can run MkDocs commands directly, or use the provided script. For example, to build the site, from a clean terminal we would rung:
cd mkdocs \nmkdocs build\n"},{"location":"config/coder/#claude-code-integration","title":"Claude Code Integration","text":"The code-server environment comes with Claude Code (@anthropic-ai/claude-code) globally installed via npm.
Claude Code is an AI-powered coding assistant by Anthropic, designed to help you write, refactor, and understand code directly within your development environment.
"},{"location":"config/coder/#usage","title":"Usage","text":"Note: Claude Code requires an API key or account with Anthropic for full functionality. Refer to the extension settings for configuration.
"},{"location":"config/coder/#call-claude","title":"Call Claude","text":"To use claude simply type claude into the terminal and follow instructions.
claude\n"},{"location":"config/coder/#shell-environment","title":"Shell Environment","text":"The .bashrc is configured to include the MkDocs virtual environment and user-local binaries in your PATH for convenience.
The code-server environment provides robust code navigation and editing features, including:
Code-server includes features to support collaboration:
When using code-server, consider the following security aspects:
The code-server environment includes Ollama, a tool for running large language models locally on your machine.
"},{"location":"config/coder/#what-is-ollama","title":"What is Ollama?","text":"Ollama is a lightweight, extensible framework for building and running language models locally. It provides a simple API for creating, running, and managing models, making it easy to integrate AI capabilities into your development workflow without relying on external services.
"},{"location":"config/coder/#getting-started-with-ollama","title":"Getting Started with Ollama","text":""},{"location":"config/coder/#staring-ollama","title":"Staring Ollama","text":"For ollama to be available, you need to open a terminal and run:
ollama serve\n This will start the ollama server and you can then proceed to pulling a model and chatting.
"},{"location":"config/coder/#pulling-a-model","title":"Pulling a Model","text":"To get started, you'll need to pull a model. For development and testing, we recommend starting with a smaller model like Gemma 2B:
ollama pull gemma2:2b\n For even lighter resource usage, you can use the 1B parameter version:
ollama pull gemma2:1b\n"},{"location":"config/coder/#running-a-model","title":"Running a Model","text":"Once you've pulled a model, you can start an interactive session:
ollama run gemma2:2b\n"},{"location":"config/coder/#available-models","title":"Available Models","text":"Popular models available through Ollama include:
Ollama provides a REST API that runs on http://localhost:11434 by default. You can integrate this into your applications:
curl http://localhost:11434/api/generate -d '{\n \"model\": \"gemma2:2b\",\n \"prompt\": \"Write a Python function to calculate fibonacci numbers\",\n \"stream\": false\n}'\n"},{"location":"config/coder/#model-management","title":"Model Management","text":"List installed models:
ollama list\n Remove a model:
ollama rm gemma2:2b\n Show model information:
ollama show gemma2:2b\n"},{"location":"config/coder/#resource-considerations","title":"Resource Considerations","text":"Ollama can be integrated with various development tools and editors through its API, enabling features like:
For more information, visit the Ollama documentation.
For more detailed information on configuring and using code-server, refer to the official code-server documentation.
"},{"location":"config/map/","title":"Map Configuration","text":"The Map system is a containerized web application that visualizes geographic data from NocoDB on an interactive map using Leaflet.js. It's designed for canvassing applications and community organizing.
"},{"location":"config/map/#features","title":"Features","text":"The setup process involves several steps that must be completed in order:
.env file with your NocoDB details.env fileToken Security
Keep your API token secure and never commit it to version control. The token provides full access to your NocoDB data.
"},{"location":"config/map/#step-2-configure-environment","title":"Step 2: Configure Environment","text":"Edit the .env file in the map/ directory:
# NocoDB API Configuration\nNOCODB_API_URL=https://your-nocodb-instance.com/api/v1\nNOCODB_API_TOKEN=your-api-token-here\n\n# These URLs will be populated after running build-nocodb.sh\nNOCODB_VIEW_URL=\nNOCODB_LOGIN_SHEET=\nNOCODB_SETTINGS_SHEET=\n\n# Server Configuration\nPORT=3000\nNODE_ENV=production\n\n# Session Secret (generate with: openssl rand -hex 32)\nSESSION_SECRET=your-secure-random-string\n\n# Map Defaults (Edmonton, Alberta, Canada)\nDEFAULT_LAT=53.5461\nDEFAULT_LNG=-113.4938\nDEFAULT_ZOOM=11\n\n# Optional: Map Boundaries (prevents users from adding points outside area)\n# BOUND_NORTH=53.7\n# BOUND_SOUTH=53.4\n# BOUND_EAST=-113.3\n# BOUND_WEST=-113.7\n\n# Production Settings\nTRUST_PROXY=true\nCOOKIE_DOMAIN=.yourdomain.com\nALLOWED_ORIGINS=https://map.yourdomain.com,http://localhost:3000\n"},{"location":"config/map/#required-configuration","title":"Required Configuration","text":"NOCODB_API_URL: Your NocoDB instance API URL (usually ends with /api/v1)NOCODB_API_TOKEN: The token you created in Step 1SESSION_SECRET: Generate a secure random string for session encryptionDEFAULT_LAT/LNG/ZOOM: Default map center and zoom levelBOUND_*: Map boundaries to restrict where users can add pointsCOOKIE_DOMAIN: Your domain for cookie securityALLOWED_ORIGINS: Comma-separated list of allowed origins for CORSThe build-nocodb.sh script will automatically create the required tables in your NocoDB instance.
cd map\nchmod +x build-nocodb.sh\n./build-nocodb.sh\n"},{"location":"config/map/#what-the-script-creates","title":"What the Script Creates","text":"The script creates three tables with the following structure:
"},{"location":"config/map/#1-locations-table","title":"1. Locations Table","text":"Main table for storing map data:
Geo-Location (Geo-Data): Format \"latitude;longitude\"latitude (Decimal): Precision 10, Scale 8longitude (Decimal): Precision 11, Scale 8First Name (Single Line Text): Person's first nameLast Name (Single Line Text): Person's last nameEmail (Email): Email addressPhone (Single Line Text): Phone numberUnit Number (Single Line Text): Unit or apartment numberAddress (Single Line Text): Street addressSupport Level (Single Select): Options: \"1\", \"2\", \"3\", \"4\"Sign (Checkbox): Has campaign signSign Size (Single Select): Options: \"Regular\", \"Large\", \"Unsure\"Notes (Long Text): Additional details and commentsUser authentication table:
Email (Email): User email address (Primary)Name (Single Line Text): User display nameAdmin (Checkbox): Admin privilegesAdmin configuration table:
key (Single Line Text): Setting identifiertitle (Single Line Text): Display namevalue (Long Text): Setting valueGeo-Location (Text): Format \"latitude;longitude\"latitude (Decimal): Precision 10, Scale 8longitude (Decimal): Precision 11, Scale 8zoom (Number): Map zoom levelcategory (Single Select): Setting categoryupdated_by (Single Line Text): Last updater emailupdated_at (DateTime): Last update timeqr_code_1_image (Attachment): QR code 1 imageqr_code_2_image (Attachment): QR code 2 imageqr_code_3_image (Attachment): QR code 3 imageThe script also creates: - A default admin user (admin@example.com) - A default start location setting
"},{"location":"config/map/#step-4-get-table-urls","title":"Step 4: Get Table URLs","text":"After the script completes successfully:
https://your-nocodb.com/dashboard/#/nc/project-id/table-idYou need URLs for: - Locations table \u2192 NOCODB_VIEW_URL - Login table \u2192 NOCODB_LOGIN_SHEET - Settings table \u2192 NOCODB_SETTINGS_SHEET
Edit your .env file and add the table URLs:
# Update these with the actual URLs from your NocoDB instance\nNOCODB_VIEW_URL=https://your-nocodb.com/dashboard/#/nc/project-id/locations-table-id\nNOCODB_LOGIN_SHEET=https://your-nocodb.com/dashboard/#/nc/project-id/login-table-id\nNOCODB_SETTINGS_SHEET=https://your-nocodb.com/dashboard/#/nc/project-id/settings-table-id\n URL Format
Make sure to use the complete dashboard URLs, not the API URLs. The application will automatically extract the project and table IDs from these URLs.
"},{"location":"config/map/#step-6-build-and-deploy","title":"Step 6: Build and Deploy","text":"Build the Docker image and start the application:
# Build the Docker image\ndocker-compose build\n\n# Start the application\ndocker-compose up -d\n"},{"location":"config/map/#verify-deployment","title":"Verify Deployment","text":"Check that the container is running:
docker-compose ps\n Check the logs:
docker-compose logs -f map-viewer\n Access the application at http://localhost:3000 (or your configured domain)
/admin.htmlGET /api/locations - Fetch all locations (requires auth)POST /api/locations - Create new location (requires auth)GET /api/locations/:id - Get single location (requires auth)PUT /api/locations/:id - Update location (requires auth)DELETE /api/locations/:id - Delete location (requires auth)GET /api/config/start-location - Get map start locationGET /health - Health checkPOST /api/auth/login - User loginGET /api/auth/check - Check authentication statusPOST /api/auth/logout - User logoutGET /api/admin/start-location - Get start location with source infoPOST /api/admin/start-location - Update map start locationGET /api/admin/walk-sheet-config - Get walk sheet configurationPOST /api/admin/walk-sheet-config - Save walk sheet configurationGeo-Location, latitude, longitude)NOCODB_VIEW_URL is correctNOCODB_LOGIN_SHEET URL is correctNOCODB_API_URL and NOCODB_API_TOKEN are correctFor development and debugging:
cd map/app\nnpm install\nnpm run dev\n This will start the application with hot reload and detailed logging.
"},{"location":"config/map/#logs-and-monitoring","title":"Logs and Monitoring","text":"View application logs:
docker-compose logs -f map-viewer\n Check health status:
curl http://localhost:3000/health\n"},{"location":"config/map/#security-considerations","title":"Security Considerations","text":"ALLOWED_ORIGINSCOOKIE_DOMAIN properlySESSION_SECRET# Stop the application\ndocker-compose down\n\n# Pull updates (if using git)\ngit pull origin main\n\n# Rebuild and restart\ndocker-compose build\ndocker-compose up -d\n"},{"location":"config/map/#backup-considerations","title":"Backup Considerations","text":".env file securelyFor issues or questions: 1. Check the troubleshooting section above 2. Review NocoDB documentation 3. Check Docker and Docker Compose documentation 4. Open an issue on GitHub
"},{"location":"config/mkdocs/","title":"MkDocs Customization & Features Overview","text":"BNKops has been building our own features, widgets, and css styles for MKdocs material theme.
This document explains the custom styling, repository widgets, and key features enabled in this MkDocs site.
For more info on how to build your site see Site Build
"},{"location":"config/mkdocs/#using-the-repository-widget-in-documentation","title":"Using the Repository Widget in Documentation","text":"You can embed repository widgets directly in your Markdown documentation to display live repository stats and metadata. To do this, add a div with the appropriate class and data-repo attribute for the repository you want to display.
Example (for a Gitea repository):
<div class=\"gitea-widget\" data-repo=\"admin/changemaker.lite\"></div>\n This will render a styled card with information about the admin/changemaker.lite repository:
Options: You can control the widget display with additional data attributes: - data-show-description=\"false\" \u2014 Hide the description - data-show-language=\"false\" \u2014 Hide the language - data-show-last-update=\"false\" \u2014 Hide the last update date
Example with options:
<div class=\"gitea-widget\" data-repo=\"admin/changemaker.lite\" data-show-description=\"false\"></div>\n For GitHub repositories, use the github-widget class:
<div class=\"github-widget\" data-repo=\"lyqht/mini-qr\"></div>\n"},{"location":"config/mkdocs/#custom-css-styling-stylesheetsextracss","title":"Custom CSS Styling (stylesheets/extra.css)","text":"The extra.css file provides extensive custom styling for the site, including:
Login and Git Code Buttons: Custom styles for .login-button and .git-code-button to create visually distinct, modern buttons with hover effects.
Code Block Improvements: Forces code blocks to wrap text (white-space: pre-wrap) and ensures inline code and tables with code display correctly on all devices.
GitHub Widget Styles: Styles for .github-widget and its subcomponents, including:
Dark mode adjustments.
Gitea Widget Styles: Similar to GitHub widget, but with Gitea branding (green accents). Includes .gitea-widget, .gitea-widget-container, and related classes for header, stats, description, footer, loading, and error states.
Responsive Design: Media queries ensure widgets and tables look good on mobile devices.
hooks/repo_widget_hook.py)","text":"docs/assets/repo-data/.serve mode).lyqht-mini-qr.json).javascripts/github-widget.js)","text":"javascripts/gitea-widget.js)","text":"mkdocs.yml)","text":"Key features and plugins enabled:
Material Theme: Modern, responsive UI with dark/light mode toggle, custom fonts, and accent colors.
Navigation Enhancements:
Table of contents with permalinks.
Content Features:
Admonitions, tabbed content, task lists, and emoji support.
Plugins:
Tags: Tagging for content organization.
Custom Hooks:
repo_widget_hook.py for repository widget data.
Extra CSS/JS:
Custom styles and scripts for widgets and homepage.
Extra Configuration:
This MkDocs site is highly customized for developer documentation, with visually rich repository widgets, improved code and table rendering, and a modern, responsive UI. All repository stats are fetched at build time for performance and reliability.
"},{"location":"how%20to/canvass/","title":"Canvas","text":"This is BNKops canvassing how to! In the following document, you will find all sorts of tips and tricks for door knocking, canvassing, and using the BNKops canvassing app.
"},{"location":"manual/","title":"Manuals","text":"The following are manuals, some accompanied by videos, on the use of the system.
"},{"location":"manual/map/","title":"Map System Manual","text":"This comprehensive manual covers all features of the Map System - a powerful campaign management platform with interactive mapping, volunteer coordination, data management, and communication tools. (Insert screenshot - feature overview)
"},{"location":"manual/map/#1-getting-started","title":"1. Getting Started","text":""},{"location":"manual/map/#logging-in","title":"Logging In","text":"https://yoursite.com or http://localhost:3000).What are Cuts?: Polygon overlays that define geographic regions like wards, neighborhoods, or custom areas.
"},{"location":"manual/map/#viewing-cuts-all-users","title":"Viewing Cuts (All Users)","text":"For technical support, contact your system administrator or refer to the comprehensive documentation available through the help system. (Insert screenshot - help resources)
"},{"location":"phil/","title":"Philosophy: Your Secrets, Your Power, Your Movement","text":""},{"location":"phil/#the-question-that-changes-everything","title":"The Question That Changes Everything!","text":"If you are a political actor, who do you trust with your secrets?
This isn't just a technical question\u2014it's the core political question of our time. Every email you send, every document you create, every contact list you build, every strategy you develop: where does it live? Who owns the servers? Who has the keys?
"},{"location":"phil/#the-corporate-extraction-machine","title":"The Corporate Extraction Machine","text":""},{"location":"phil/#how-they-hook-you","title":"How They Hook You","text":"Corporate software companies have perfected the art of digital snake oil sales:
You Are Not the Customer
If you're not paying for the product, you ARE the product. But even when you are paying, you're often still the product.
Corporate platforms don't make money from your subscription fees\u2014they make money from:
BNKops is a cooperative based in amiskwaciy-w\u00e2skahikan (Edmonton, Alberta) on Treaty 6 territory. We're not a corporation\u2014we're a collective of skilled organizers, developers, and community builders who believe technology should serve liberation, not oppression.
"},{"location":"phil/#our-principles","title":"Our Principles","text":""},{"location":"phil/#liberation-first","title":"\ud83c\udff3\ufe0f\u200d\u26a7\ufe0f \ud83c\udff3\ufe0f\u200d\ud83c\udf08 \ud83c\uddf5\ud83c\uddf8 Liberation First","text":"Technology that centers the most marginalized voices and fights for collective liberation. We believe strongly that the medium is the message; if you the use the medium of fascists, what does that say about your movement?
"},{"location":"phil/#community-over-profit","title":"\ud83e\udd1d Community Over Profit","text":"We operate as a cooperative because we believe in shared ownership and democratic decision-making. No venture capitalists, no shareholders, no extraction.
"},{"location":"phil/#data-sovereignty","title":"\u26a1 Data Sovereignty","text":"Your data belongs to you and your community. We build tools that let you own your digital infrastructure completely.
"},{"location":"phil/#security-culture","title":"\ud83d\udd12 Security Culture","text":"Real security comes from community control, not corporate promises. We integrate security culture practices into our technology design.
"},{"location":"phil/#why-this-matters","title":"Why This Matters","text":"When you control your technology infrastructure:
Traditional security culture asks: \"Who needs to know this information?\"
Digital security culture asks: \"Who controls the infrastructure where this information lives?\"
"},{"location":"phil/#community-technology","title":"Community Technology","text":"We believe in community technology - tools that:
The tools we use shape the movements we build. Corporate tools create corporate movements\u2014hierarchical, surveilled, and dependent. Community-controlled tools create community-controlled movements\u2014democratic, secure, and sovereign.
"},{"location":"phil/#common-questions","title":"Common Questions","text":""},{"location":"phil/#isnt-this-just-for-tech-people","title":"\"Isn't this just for tech people?\"","text":"No. We specifically designed Changemaker Lite for organizers, activists, and movement builders who may not have technical backgrounds. Our philosophy is that everyone deserves digital sovereignty, not just people with computer science degrees.
This is not to say that you won't need to learn! These tools are just that; tools. They have no fancy or white-labeled marketing and are technical in nature. You will need to learn to use them, just as any worker needs to learn the power tools they use on the job.
"},{"location":"phil/#what-about-convenience","title":"\"What about convenience?\"","text":"Corporate platforms are convenient because they've extracted billions of dollars from users to fund that convenience. When you own your tools, there's a learning curve\u2014but it's the same learning curve as learning to organize, learning to build power, learning to create change.
"},{"location":"phil/#cant-we-just-use-corporate-tools-carefully","title":"\"Can't we just use corporate tools carefully?\"","text":"Would you hold your most sensitive organizing meetings in a room owned by your opposition? Would you store your membership lists in filing cabinets at a corporation that profits from surveillance? Digital tools are the same.
"},{"location":"phil/#what-about-security","title":"\"What about security?\"","text":"Real security comes from community control, not corporate promises. When you control your infrastructure:
As Shoshana Zuboff documents in \"The Age of Surveillance Capitalism,\" we're living through a new form of capitalism that extracts value from human experience itself. Political movements are particularly valuable targets because:
You don't have to replace everything at once. Start with one tool, one campaign, one project. Learn the technology alongside your organizing.
"},{"location":"phil/#build-community-capacity","title":"Build Community Capacity","text":"The goal isn't individual self-sufficiency\u2014it's community technological sovereignty. Share skills, pool resources, learn together.
"},{"location":"phil/#connect-with-others","title":"Connect with Others","text":"You're not alone in this. The free and open source software community, the digital security community, and the appropriate technology movement are all working on similar problems.
"},{"location":"phil/#remember-why","title":"Remember Why","text":"This isn't about technology for its own sake. It's about building the infrastructure for the world we want to see\u2014where communities have power, where people control their own data, where technology serves liberation.
"},{"location":"phil/#resources-for-deeper-learning","title":"Resources for Deeper Learning","text":""},{"location":"phil/#essential-reading","title":"Essential Reading","text":"This philosophy document is a living document. Contribute your thoughts, experiences, and improvements through the BNKops documentation platform.
"},{"location":"phil/cost-comparison/","title":"Cost Comparison: Corporation vs. Community","text":""},{"location":"phil/cost-comparison/#the-true-cost-of-corporate-dependency","title":"The True Cost of Corporate Dependency","text":"When movements choose corporate software, they're not just paying subscription fees\u2014they're paying with their power, their privacy, and their future. Let's break down the real costs.
"},{"location":"phil/cost-comparison/#monthly-cost-analysis","title":"Monthly Cost Analysis","text":""},{"location":"phil/cost-comparison/#small-campaign-50-supporters-5000-emailsmonth","title":"Small Campaign (50 supporters, 5,000 emails/month)","text":"Service Category Corporate Solution Monthly Cost Changemaker Lite Monthly Cost Email Marketing Mailchimp $59/month Listmonk $0* Database & CRM Airtable Pro $240/month NocoDB $0* Website Hosting Squarespace $40/month Static Server $0* Documentation Notion Team $96/month MkDocs $0* Development GitHub Codespaces $87/month Code Server $0* Automation Zapier Professional $73/month n8n $0* File Storage Google Workspace $72/month PostgreSQL + Storage $0* Analytics Corporate tracking Privacy cost\u2020 Self-hosted $0* TOTAL $667/month $50/month*Included in base Changemaker Lite hosting cost \u2020Privacy costs are incalculable but include surveillance, data sales, and community manipulation
"},{"location":"phil/cost-comparison/#medium-campaign-500-supporters-50000-emailsmonth","title":"Medium Campaign (500 supporters, 50,000 emails/month)","text":"Service Category Corporate Solution Monthly Cost Changemaker Lite Monthly Cost Email Marketing Mailchimp $299/month Listmonk $0* Database & CRM Airtable Pro $600/month NocoDB $0* Website Hosting Squarespace $65/month Static Server $0* Documentation Notion Team $240/month MkDocs $0* Development GitHub Codespaces $174/month Code Server $0* Automation Zapier Professional $146/month n8n $0* File Storage Google Workspace $144/month PostgreSQL + Storage $0* Analytics Corporate tracking Privacy cost\u2020 Self-hosted $0* TOTAL $1,668/month $75/month"},{"location":"phil/cost-comparison/#large-campaign-5000-supporters-500000-emailsmonth","title":"Large Campaign (5,000 supporters, 500,000 emails/month)","text":"Service Category Corporate Solution Monthly Cost Changemaker Lite Monthly Cost Email Marketing Mailchimp $1,499/month Listmonk $0* Database & CRM Airtable Pro $1,200/month NocoDB $0* Website Hosting Squarespace + CDN $120/month Static Server $0* Documentation Notion Team $480/month MkDocs $0* Development GitHub Codespaces $348/month Code Server $0* Automation Zapier Professional $292/month n8n $0* File Storage Google Workspace $288/month PostgreSQL + Storage $0* Analytics Corporate tracking Privacy cost\u2020 Self-hosted $0* TOTAL $4,227/month $150/month"},{"location":"phil/cost-comparison/#annual-savings-breakdown","title":"Annual Savings Breakdown","text":""},{"location":"phil/cost-comparison/#3-year-cost-comparison","title":"3-Year Cost Comparison","text":"Campaign Size Corporate Total Changemaker Total Savings Small $24,012 $1,800 $22,212 Medium $60,048 $2,700 $57,348 Large $152,172 $5,400 $146,772"},{"location":"phil/cost-comparison/#hidden-costs-of-corporate-software","title":"Hidden Costs of Corporate Software","text":""},{"location":"phil/cost-comparison/#what-you-cant-put-a-price-on","title":"What You Can't Put a Price On","text":""},{"location":"phil/cost-comparison/#privacy-violations","title":"Privacy Violations","text":"Corporate software costs grow exponentially: - Year 1: \"Starter\" pricing to hook you - Year 2: Feature limits force tier upgrades - Year 3: Usage growth triggers premium pricing - Year 4: Platform changes force expensive migrations - Year 5: Lock-in enables arbitrary price increases
Changemaker Lite costs grow linearly with actual infrastructure needs: - Year 1: Base infrastructure costs - Year 2: Modest increases for storage/bandwidth only - Year 3: Scale only with actual technical requirements - Year 4: Community-driven improvements at no extra cost - Year 5: Established infrastructure with declining per-user costs
"},{"location":"phil/cost-comparison/#10-year-projection","title":"10-Year Projection","text":"Year Corporate (Medium Campaign) Changemaker Lite Annual Savings 1 $20,016 $900 $19,116 2 $22,017 $900 $21,117 3 $24,219 $1,080 $23,139 4 $26,641 $1,080 $25,561 5 $29,305 $1,260 $28,045 6 $32,235 $1,260 $30,975 7 $35,459 $1,440 $34,019 8 $39,005 $1,440 $37,565 9 $42,905 $1,620 $41,285 10 $47,196 $1,620 $45,576 TOTAL $318,998 $12,600 $306,398"},{"location":"phil/cost-comparison/#calculate-your-own-savings","title":"Calculate Your Own Savings","text":""},{"location":"phil/cost-comparison/#current-corporate-costs-worksheet","title":"Current Corporate Costs Worksheet","text":"Email Marketing: $____/month Database/CRM: $____/month Website Hosting: $____/month Documentation: $____/month Development Tools: $____/month Automation: $____/month File Storage: $____/month Other SaaS: $____/month
Monthly Total: $____ Annual Total: $____
Changemaker Alternative: $50-150/month Your Annual Savings: $____
"},{"location":"phil/cost-comparison/#beyond-the-numbers","title":"Beyond the Numbers","text":""},{"location":"phil/cost-comparison/#what-movements-do-with-their-savings","title":"What Movements Do With Their Savings","text":"The money saved by choosing community-controlled technology doesn't disappear\u2014it goes directly back into movement building:
You don't have to switch everything at once:
Most campaigns recover their entire first-year investment in 60-90 days through subscription savings alone.
Ready to stop feeding your budget to corporate surveillance? Get started with Changemaker Lite today and take control of your digital infrastructure.
"},{"location":"services/","title":"Services","text":"Changemaker Lite includes several powerful services that work together to provide a complete documentation and development platform. Each service is containerized and can be accessed through its dedicated port.
"},{"location":"services/#available-services","title":"Available Services","text":""},{"location":"services/#code-server","title":"Code Server","text":"Port: 8888 | Visual Studio Code in your browser for remote development
Port: 9000 | Self-hosted newsletter and mailing list manager
Port: 5432 | Reliable database backend - Data persistence for Listmonk - ACID compliance - High performance - Backup and restore capabilities
"},{"location":"services/#mkdocs-material","title":"MkDocs Material","text":"Port: 4000 | Documentation site generator with live preview
Port: 4001 | Nginx-powered static site hosting - High-performance serving - Built documentation hosting - Caching and compression - Security headers
"},{"location":"services/#n8n","title":"n8n","text":"Port: 5678 | Workflow automation tool
Port: 8090 | No-code database platform
Port: 3010 | Modern dashboard for all services
Port: 3030 | Self-hosted Git service
Port: 8089 | Simple QR code generator service
Port: 3000 | Canvassing and community organizing application
\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510 \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510 \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502 Homepage \u2502 \u2502 Code Server \u2502 \u2502 MkDocs \u2502\n\u2502 :3010 \u2502 \u2502 :8888 \u2502 \u2502 :4000 \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518 \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518 \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n\n\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510 \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510 \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502 Static Server \u2502 \u2502 Listmonk \u2502 \u2502 n8n \u2502\n\u2502 :4001 \u2502 \u2502 :9000 \u2502 \u2502 :5678 \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518 \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518 \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n\n\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510 \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510 \u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502 NocoDB \u2502 \u2502 PostgreSQL \u2502 \u2502 PostgreSQL \u2502\n\u2502 :8090 \u2502 \u2502 (listmonk-db) \u2502 \u2502 (root_db) \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518 \u2502 :5432 \u2502 \u2502 :5432 \u2502\n \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518 \u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n\n\u250c\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2510\n\u2502 Map \u2502\n\u2502 :3000 \u2502\n\u2514\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2518\n"},{"location":"services/code-server/","title":"Code Server","text":""},{"location":"services/code-server/#overview","title":"Overview","text":"Code Server provides a full Visual Studio Code experience in your web browser, allowing you to develop from any device. It runs on your server and provides access to your development environment through a web interface.
"},{"location":"services/code-server/#features","title":"Features","text":"http://localhost:8888/home/coder/mkdocs/DOCKER_USER: The user to run code-server as (default: coder)DEFAULT_WORKSPACE: Default workspace directoryUSER_ID: User ID for file permissionsGROUP_ID: Group ID for file permissions./configs/code-server/.config: VS Code configuration./configs/code-server/.local: Local data./mkdocs: Main workspace directoryhttp://localhost:8888/home/coder/mkdocs/ workspaceConsider installing these extensions for better documentation work:
For more detailed information, visit the official Code Server documentation.
"},{"location":"services/gitea/","title":"Gitea","text":"Self-hosted Git service for collaborative development.
"},{"location":"services/gitea/#overview","title":"Overview","text":"Gitea is a lightweight, self-hosted Git service similar to GitHub, GitLab, and Bitbucket. It provides a web interface for managing repositories, issues, pull requests, and more.
"},{"location":"services/gitea/#features","title":"Features","text":"${GITEA_WEB_PORT:-3030} (default: 3030)${GITEA_SSH_PORT:-2222} (default: 2222)http://localhost:${GITEA_WEB_PORT:-3030}/data/giteaGITEA__database__DB_TYPE: Database type (e.g., sqlite3, mysql, postgres)GITEA__database__HOST: Database host (default: ${GITEA_DB_HOST:-gitea-db:3306})GITEA__database__NAME: Database name (default: ${GITEA_DB_NAME:-gitea})GITEA__database__USER: Database user (default: ${GITEA_DB_USER:-gitea})GITEA__database__PASSWD: Database password (from .env)GITEA__server__ROOT_URL: Root URL (e.g., ${GITEA_ROOT_URL})GITEA__server__HTTP_PORT: Web port (default: 3000 inside container)GITEA__server__DOMAIN: Domain (e.g., ${GITEA_DOMAIN})gitea_data:/data: Gitea configuration and data/etc/timezone:/etc/timezone:ro/etc/localtime:/etc/localtime:rohttp://localhost:${GITEA_WEB_PORT:-3030}For more details, visit the official Gitea documentation.
"},{"location":"services/homepage/","title":"Homepage","text":"Modern dashboard for accessing all your self-hosted services.
"},{"location":"services/homepage/#overview","title":"Overview","text":"Homepage is a modern, fully static, fast, secure fully configurable application dashboard with integrations for over 100 services. It provides a beautiful and customizable interface to access all your Changemaker Lite services from a single location.
"},{"location":"services/homepage/#features","title":"Features","text":"http://localhost:3010HOMEPAGE_PORT: External port mapping (default: 3010)PUID: User ID for file permissions (default: 1000)PGID: Group ID for file permissions (default: 1000)TZ: Timezone setting (default: Etc/UTC)HOMEPAGE_ALLOWED_HOSTS: Allowed hosts for the dashboardHomepage uses YAML configuration files located in ./configs/homepage/:
settings.yaml: Global settings and theme configurationservices.yaml: Service definitions and widgetsbookmarks.yaml: Bookmark categories and linkswidgets.yaml: Dashboard widgets configurationdocker.yaml: Docker integration settings./configs/homepage:/app/config: Configuration files./assets/icons:/app/public/icons: Custom service icons./assets/images:/app/public/images: Background images and assets/var/run/docker.sock:/var/run/docker.sock: Docker socket for container monitoringHomepage is pre-configured with all Changemaker Lite services:
"},{"location":"services/homepage/#essential-tools","title":"Essential Tools","text":"Edit configs/homepage/services.yaml to add new services:
- Custom Category:\n - My Service:\n href: http://localhost:8080\n description: Custom service description\n icon: mdi-application\n widget:\n type: ping\n url: http://localhost:8080\n"},{"location":"services/homepage/#custom-icons","title":"Custom Icons","text":"Add custom icons to ./assets/icons/ directory and reference them in services.yaml:
icon: /icons/my-custom-icon.png\n"},{"location":"services/homepage/#themes-and-styling","title":"Themes and Styling","text":"Modify configs/homepage/settings.yaml to customize appearance:
theme: dark # or light\ncolor: purple # slate, gray, zinc, neutral, stone, red, orange, amber, yellow, lime, green, emerald, teal, cyan, sky, blue, indigo, violet, purple, fuchsia, pink, rose\n"},{"location":"services/homepage/#widgets","title":"Widgets","text":"Enable live monitoring widgets in configs/homepage/services.yaml:
- Service Name:\n widget:\n type: docker\n container: container-name\n server: my-docker\n"},{"location":"services/homepage/#service-monitoring","title":"Service Monitoring","text":"Homepage can display real-time status information for your services:
Homepage monitors Docker containers automatically when configured:
/var/run/docker.sock)docker.yamlservices.yamlConfiguration not loading: Check YAML syntax in configuration files
docker logs homepage-changemaker\n Icons not displaying: Verify icon paths and file permissions
ls -la ./assets/icons/\n Services not reachable: Verify network connectivity between containers
docker exec homepage-changemaker ping service-name\n Widget data not updating: Check Docker socket permissions and container access
docker exec homepage-changemaker ls -la /var/run/docker.sock\n"},{"location":"services/homepage/#configuration-examples","title":"Configuration Examples","text":""},{"location":"services/homepage/#basic-service-widget","title":"Basic Service Widget","text":"- Code Server:\n href: http://localhost:8888\n description: VS Code in the browser\n icon: code-server\n widget:\n type: docker\n container: code-server-changemaker\n"},{"location":"services/homepage/#custom-dashboard-layout","title":"Custom Dashboard Layout","text":"# settings.yaml\nlayout:\n style: columns\n columns: 3\n\n# Responsive breakpoints\nresponsive:\n mobile: 1\n tablet: 2\n desktop: 3\n"},{"location":"services/homepage/#official-documentation","title":"Official Documentation","text":"For comprehensive configuration guides and advanced features:
Self-hosted newsletter and mailing list manager.
"},{"location":"services/listmonk/#overview","title":"Overview","text":"Listmonk is a modern, feature-rich newsletter and mailing list manager designed for high performance and easy management. It provides a complete solution for email campaigns, subscriber management, and analytics.
"},{"location":"services/listmonk/#features","title":"Features","text":"http://localhost:9000LISTMONK_ADMIN_USER environment variableLISTMONK_ADMIN_PASSWORD environment variableLISTMONK_ADMIN_USER: Admin usernameLISTMONK_ADMIN_PASSWORD: Admin passwordPOSTGRES_USER: Database usernamePOSTGRES_PASSWORD: Database passwordPOSTGRES_DB: Database nameListmonk uses PostgreSQL as its backend database. The database is automatically configured through the docker-compose setup.
"},{"location":"services/listmonk/#uploads","title":"Uploads","text":"./assets/uploadshttp://localhost:9000For comprehensive guides and API documentation, visit: - Listmonk Documentation - GitHub Repository
"},{"location":"services/map/","title":"Map","text":"Interactive map service for geospatial data visualization, powered by NocoDB and Leaflet.js.
"},{"location":"services/map/#overview","title":"Overview","text":"The Map service provides an interactive web-based map for displaying, searching, and analyzing geospatial data from a NocoDB backend. It supports real-time geolocation, adding new locations, and is optimized for both desktop and mobile use.
"},{"location":"services/map/#features","title":"Features","text":"${MAP_PORT:-3000} (default: 3000)http://localhost:${MAP_PORT:-3000}/app/public/All configuration is done via environment variables:
Variable Description DefaultNOCODB_API_URL NocoDB API base URL Required NOCODB_API_TOKEN API authentication token Required NOCODB_VIEW_URL Full NocoDB view URL Required PORT Server port 3000 DEFAULT_LAT Default map latitude 53.5461 DEFAULT_LNG Default map longitude -113.4938 DEFAULT_ZOOM Default map zoom level 11"},{"location":"services/map/#volumes","title":"Volumes","text":"./map/app/public: Map public assetshttp://localhost:${MAP_PORT:-3000}geodata (Text): Format \"latitude;longitude\" latitude (Decimal): Precision 10, Scale 8longitude (Decimal): Precision 11, Scale 8First Name (Text): Person's first nameLast Name (Text): Person's last name Email (Email): Contact email addressUnit Number (Text): Apartment/unit numberSupport Level (Single Select): Address (Text): Full street addressSign (Checkbox): Has campaign sign (true/false)Sign Size (Single Select): Small, Medium, LargeGeo-Location (Text): Formatted as \"latitude;longitude\"GET /api/locations - Fetch all locationsPOST /api/locations - Create new locationGET /api/locations/:id - Get single locationPUT /api/locations/:id - Update locationDELETE /api/locations/:id - Delete locationGET /health - Health checkSimple QR code generator service.
"},{"location":"services/mini-qr/#overview","title":"Overview","text":"Mini QR is a lightweight service for generating QR codes for URLs, text, or other data. It provides a web interface for quick QR code creation and download.
"},{"location":"services/mini-qr/#features","title":"Features","text":"${MINI_QR_PORT:-8089} (default: 8089)http://localhost:${MINI_QR_PORT:-8089}QR_DEFAULT_SIZE: Default size of generated QR codesQR_IMAGE_FORMAT: Image format (e.g., png, svg)./configs/mini-qr: QR code service configurationhttp://localhost:${MINI_QR_PORT:-8089}Modern documentation site generator with live preview.
Looking for more info on BNKops code-server integration?
\u2192 Code Server Configuration
"},{"location":"services/mkdocs/#overview","title":"Overview","text":"MkDocs Material is a powerful documentation framework built on top of MkDocs, providing a beautiful Material Design theme and advanced features for creating professional documentation sites.
"},{"location":"services/mkdocs/#features","title":"Features","text":"http://localhost:4000Configuration is managed through mkdocs.yml in the project root.
./mkdocs: Documentation source files./assets/images: Shared images directorySITE_URL: Base domain for the siteUSER_ID: User ID for file permissionsGROUP_ID: Group ID for file permissionsmkdocs/\n\u251c\u2500\u2500 mkdocs.yml # Configuration file\n\u251c\u2500\u2500 docs/ # Documentation source\n\u2502 \u251c\u2500\u2500 index.md # Homepage\n\u2502 \u251c\u2500\u2500 services/ # Service documentation\n\u2502 \u251c\u2500\u2500 blog/ # Blog posts\n\u2502 \u2514\u2500\u2500 overrides/ # Template overrides\n\u2514\u2500\u2500 site/ # Built static site\n"},{"location":"services/mkdocs/#writing-documentation","title":"Writing Documentation","text":""},{"location":"services/mkdocs/#markdown-basics","title":"Markdown Basics","text":"# Page Title\n\nThis is a sample documentation page.\n\n## Section\n\nContent goes here with **bold** and *italic* text.\n\n### Code Example\n\n```python\ndef hello_world():\n print(\"Hello, World!\")\n Note
This is an informational note.
## Building and Deployment\n\n### Development\n\nThe development server runs automatically with live reload.\n\n### Building Static Site\n\n```bash\ndocker exec mkdocs-changemaker mkdocs build\n The built site will be available in the mkdocs/site/ directory.
Customize appearance in mkdocs.yml:
theme:\n name: material\n palette:\n primary: blue\n accent: indigo\n"},{"location":"services/mkdocs/#custom-css","title":"Custom CSS","text":"Add custom styles in docs/stylesheets/extra.css.
For comprehensive MkDocs Material documentation: - MkDocs Material - MkDocs Documentation - Markdown Guide
"},{"location":"services/n8n/","title":"n8n","text":"Workflow automation tool for connecting services and automating tasks.
"},{"location":"services/n8n/#overview","title":"Overview","text":"n8n is a powerful workflow automation tool that allows you to connect various apps and services together. It provides a visual interface for creating automated workflows, making it easy to integrate different systems and automate repetitive tasks.
"},{"location":"services/n8n/#features","title":"Features","text":"http://localhost:5678N8N_DEFAULT_USER_EMAILN8N_DEFAULT_USER_PASSWORDN8N_HOST: Hostname for n8n (default: n8n.${DOMAIN})N8N_PORT: Internal port (5678)N8N_PROTOCOL: Protocol for webhooks (https)NODE_ENV: Environment (production)WEBHOOK_URL: Base URL for webhooksGENERIC_TIMEZONE: Timezone settingN8N_ENCRYPTION_KEY: Encryption key for credentialsN8N_USER_MANAGEMENT_DISABLED: Enable/disable user managementN8N_DEFAULT_USER_EMAIL: Default admin emailN8N_DEFAULT_USER_PASSWORD: Default admin passwordn8n_data: Persistent data storage./local-files: Local file access for workflowshttp://localhost:5678Webhook \u2192 Email\n"},{"location":"services/n8n/#scheduled-documentation-backup","title":"Scheduled Documentation Backup","text":"Schedule \u2192 Read Files \u2192 Compress \u2192 Upload to Storage\n"},{"location":"services/n8n/#git-integration","title":"Git Integration","text":"Git Webhook \u2192 Process Changes \u2192 Update Documentation \u2192 Notify Team\n"},{"location":"services/n8n/#security-considerations","title":"Security Considerations","text":"n8n can integrate with all services in your Changemaker Lite setup:
# Check container logs\ndocker logs n8n-changemaker\n\n# Access container shell\ndocker exec -it n8n-changemaker sh\n\n# Check workflow executions in the UI\n# Visit http://localhost:5678 \u2192 Executions\n"},{"location":"services/n8n/#official-documentation","title":"Official Documentation","text":"For comprehensive n8n documentation:
No-code database platform that turns any database into a smart spreadsheet.
"},{"location":"services/nocodb/#overview","title":"Overview","text":"NocoDB is an open-source no-code platform that transforms any database into a smart spreadsheet interface. It provides a user-friendly way to manage data, create forms, build APIs, and collaborate on database operations without requiring extensive technical knowledge.
"},{"location":"services/nocodb/#features","title":"Features","text":"http://localhost:8090root_db instance)NOCODB_PORT: External port mapping (default: 8090)NC_DB: Database connection string for PostgreSQL backendNocoDB uses a dedicated PostgreSQL instance (root_db) with the following configuration:
root_dbpostgrespasswordroot_db (internal container name)nc_data: Application data and configuration storagedb_data: PostgreSQL database fileshttp://localhost:8090NocoDB can integrate well with other Changemaker Lite services:
NocoDB automatically generates REST APIs for all your tables:
# Get all records from a table\nGET http://localhost:8090/api/v1/db/data/v1/{project}/table/{table}\n\n# Create a new record\nPOST http://localhost:8090/api/v1/db/data/v1/{project}/table/{table}\n\n# Update a record\nPATCH http://localhost:8090/api/v1/db/data/v1/{project}/table/{table}/{id}\n"},{"location":"services/nocodb/#backup-and-data-management","title":"Backup and Data Management","text":""},{"location":"services/nocodb/#database-backup","title":"Database Backup","text":"Since NocoDB uses PostgreSQL, you can backup the database:
# Backup NocoDB database\ndocker exec root_db pg_dump -U postgres root_db > nocodb_backup.sql\n\n# Restore from backup\ndocker exec -i root_db psql -U postgres root_db < nocodb_backup.sql\n"},{"location":"services/nocodb/#application-data","title":"Application Data","text":"Application settings and metadata are stored in the nc_data volume.
Service won't start: Check if the PostgreSQL database is healthy
docker logs root_db\n Database connection errors: Verify database credentials and network connectivity
docker exec nocodb nc_data nc\n Performance issues: Monitor resource usage and optimize queries
docker stats nocodb root_db\n"},{"location":"services/nocodb/#official-documentation","title":"Official Documentation","text":"For comprehensive guides and advanced features:
Reliable database backend for applications.
"},{"location":"services/postgresql/#overview","title":"Overview","text":"PostgreSQL is a powerful, open-source relational database system. In Changemaker Lite, it serves as the backend database for Listmonk and can be used by other applications requiring persistent data storage.
"},{"location":"services/postgresql/#features","title":"Features","text":"listmonk-db (internal container name)POSTGRES_DB environment variablePOSTGRES_USER environment variablePOSTGRES_PASSWORD environment variablePOSTGRES_USER: Database usernamePOSTGRES_PASSWORD: Database password POSTGRES_DB: Database nameThe PostgreSQL container includes health checks to ensure the database is ready before dependent services start.
"},{"location":"services/postgresql/#data-persistence","title":"Data Persistence","text":"Database data is stored in a Docker volume (listmonk-data) to ensure persistence across container restarts.
You can connect to PostgreSQL from your host machine using:
psql -h localhost -p 5432 -U [username] -d [database]\n"},{"location":"services/postgresql/#from-other-containers","title":"From Other Containers","text":"Other containers can connect using the internal hostname listmonk-db on port 5432.
docker exec listmonk-db pg_dump -U [username] [database] > backup.sql\n"},{"location":"services/postgresql/#restore","title":"Restore","text":"docker exec -i listmonk-db psql -U [username] [database] < backup.sql\n"},{"location":"services/postgresql/#monitoring","title":"Monitoring","text":"Monitor database health and performance through: - Container logs: docker logs listmonk-db - Database metrics and queries - Connection monitoring
For comprehensive PostgreSQL documentation: - PostgreSQL Documentation - Docker PostgreSQL Image
"},{"location":"services/static-server/","title":"Static Site Server","text":"Nginx-powered static site server for hosting built documentation and websites.
"},{"location":"services/static-server/#overview","title":"Overview","text":"The Static Site Server uses Nginx to serve your built documentation and static websites. It's configured to serve the built MkDocs site and other static content with high performance and reliability.
"},{"location":"services/static-server/#features","title":"Features","text":"http://localhost:4001/config/www (mounted from ./mkdocs/site)PUID: User ID for file permissions (default: 1000)PGID: Group ID for file permissions (default: 1000)TZ: Timezone setting (default: Etc/UTC)./mkdocs/site:/config/www: Static site filesdocker exec mkdocs-changemaker mkdocs buildhttp://localhost:4001./mkdocs/site/ will be served staticallymkdocs/site/ # Served at /\n\u251c\u2500\u2500 index.html # Homepage\n\u251c\u2500\u2500 assets/ # CSS, JS, images\n\u251c\u2500\u2500 services/ # Service documentation\n\u2514\u2500\u2500 search/ # Search functionality\n"},{"location":"services/static-server/#performance-features","title":"Performance Features","text":"For advanced Nginx configuration, you can: 1. Create custom Nginx config files 2. Mount them as volumes 3. Restart the container
"},{"location":"services/static-server/#monitoring","title":"Monitoring","text":"Monitor the static site server through: - Container logs: docker logs mkdocs-site-server-changemaker - Access logs for traffic analysis - Performance metrics
./mkdocs/site/PUID and PGID settings# Check container logs\ndocker logs mkdocs-site-server-changemaker\n\n# Verify files are present\ndocker exec mkdocs-site-server-changemaker ls -la /config/www\n\n# Test file serving\ncurl -I http://localhost:4001\n"},{"location":"services/static-server/#official-documentation","title":"Official Documentation","text":"For more information about the underlying Nginx server: - LinuxServer.io Nginx - Nginx Documentation
"},{"location":"blog/archive/2025/","title":"2025","text":""}]}