This commit is contained in:
Graham McIntire 2025-09-06 12:46:26 -05:00
parent ffe9a59269
commit 27bb17d366
No known key found for this signature in database
34 changed files with 958 additions and 353 deletions

3
.gitignore vendored
View file

@ -1,2 +1,3 @@
# Terraform directories
**/.terraform/
**/.terraform/
**/terraform/

7
home/ansible/ansible.cfg Normal file
View file

@ -0,0 +1,7 @@
[defaults]
inventory = inventory.yml
host_key_checking = False
retry_files_enabled = False
[ssh_connection]
ssh_args = -o ControlMaster=auto -o ControlPersist=60s

View file

@ -0,0 +1,72 @@
---
- name: Bootstrap AlmaLinux server for Ansible management
hosts: caddy
become: yes
vars:
ansible_user: graham # Connect as graham initially
tasks:
- name: Create ansible user
user:
name: ansible
uid: 10001
shell: /bin/bash
home: /home/ansible
create_home: yes
state: present
- name: Add ansible user to wheel group
user:
name: ansible
groups: wheel
append: yes
- name: Ensure .ssh directory exists for ansible user
file:
path: /home/ansible/.ssh
state: directory
owner: ansible
group: ansible
mode: "0700"
- name: Add ansible SSH key to ansible user
authorized_key:
user: ansible
key: "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFghGMnDdkfNC6JPEhMxrKhYDmNcXjHXp/y/mf3uLtzb graham@mbp14.local"
state: present
- name: Add SSH keys from GitHub to graham user
authorized_key:
user: graham
key: "https://github.com/gmcintire.keys"
state: present
- name: Configure passwordless sudo for ansible user
copy:
content: "ansible ALL=(ALL) NOPASSWD: ALL"
dest: /etc/sudoers.d/ansible
mode: "0440"
validate: "visudo -cf %s"
- name: Install Python 3 (required for Ansible)
dnf:
name:
- python3
- python3-pip
state: present
- name: Set Python 3 as default python
alternatives:
name: python
link: /usr/bin/python
path: /usr/bin/python3
- name: Verify ansible user can sudo
command: sudo -u ansible sudo -l
changed_when: false
register: sudo_test
- name: Show sudo verification
debug:
msg: "Ansible user sudo access verified"
when: sudo_test.rc == 0

View file

@ -0,0 +1,177 @@
---
- name: Configure Caddy reverse proxy with Tailscale on AlmaLinux 10
hosts: caddy
become: yes
gather_facts: yes
strategy: free
vars:
tailscale_key: "{{ lookup('env', 'TAILSCALE_KEY') }}"
tasks:
- name: Enable passwordless sudo on AlmaLinux
ansible.builtin.lineinfile:
path: /etc/sudoers
state: present
regexp: "^%wheel"
line: "%wheel ALL=(ALL) NOPASSWD: ALL"
validate: "visudo -cf %s"
- name: Clean up repository files
ansible.builtin.file:
path: "{{ item }}"
state: absent
loop:
- /etc/yum.repos.d/caddy.repo
- /etc/yum.repos.d/tailscale-stable.repo
when: false # Only enable if you have issues
- name: Check if EPEL is already installed
ansible.builtin.stat:
path: /etc/yum.repos.d/epel.repo
register: epel_check
- name: Install EPEL repo
ansible.builtin.dnf:
name: epel-release
state: present
when: not epel_check.stat.exists
- name: Check if Caddy COPR repo exists
ansible.builtin.stat:
path: /etc/yum.repos.d/_copr:copr.fedorainfracloud.org:group_caddy:caddy.repo
register: caddy_repo_check
- name: Add Caddy COPR repository
ansible.builtin.command:
cmd: dnf copr enable -y @caddy/caddy
when: not caddy_repo_check.stat.exists
- name: Install all required packages in one transaction
ansible.builtin.dnf:
state: present
name:
- caddy
- firewalld
- htop
- rsync
- tmux
- tar
- unzip
- python3-libsemanage
- python3-policycoreutils
update_cache: yes
- name: Enable and start firewalld
service:
name: firewalld
state: started
enabled: yes
- name: Configure firewall for Caddy
firewalld:
port: "{{ item }}"
permanent: yes
state: enabled
immediate: yes
loop:
- "80/tcp"
- "443/tcp"
- "22/tcp"
- name: Check if Tailscale is installed
command: which tailscale
register: tailscale_check
changed_when: false
failed_when: false
- name: Install Tailscale on AlmaLinux
block:
- name: Add Tailscale repository
yum_repository:
name: tailscale-stable
description: Tailscale stable
baseurl: https://pkgs.tailscale.com/stable/centos/9/$basearch
repo_gpgcheck: yes
gpgcheck: yes
enabled: yes
gpgkey: https://pkgs.tailscale.com/stable/centos/9/repo.gpg
- name: Install Tailscale
dnf:
name: tailscale
state: present
- name: Enable and start Tailscale daemon
service:
name: tailscaled
state: started
enabled: yes
when: tailscale_check.rc != 0
- name: Allow Tailscale through firewall
firewalld:
port: 41641/udp
permanent: yes
state: enabled
immediate: yes
- name: Check if Tailscale is already authenticated
command: tailscale status --json
register: tailscale_status_check
changed_when: false
failed_when: false
- name: Authenticate Tailscale
command: tailscale up --authkey="{{ tailscale_key }}" --accept-routes --hostname=caddy
when:
- tailscale_key is defined
- tailscale_key != ""
- tailscale_status_check.rc != 0 or (tailscale_status_check.stdout | from_json).BackendState != "Running"
register: tailscale_auth
failed_when: false
ignore_errors: yes
- name: Get Tailscale status
command: tailscale status
register: tailscale_final_status
changed_when: false
failed_when: false
- name: Show final Tailscale status
debug:
var: tailscale_final_status.stdout_lines
- name: Enable and start Caddy
service:
name: caddy
state: started
enabled: yes
- name: Deploy Caddyfile configuration
template:
src: templates/Caddyfile.j2
dest: /etc/caddy/Caddyfile
owner: caddy
group: caddy
mode: "0644"
backup: yes
notify: reload caddy
- name: SELinux - Allow Caddy to proxy
seboolean:
name: httpd_can_network_connect
state: yes
persistent: yes
- name: SELinux - Allow Caddy to bind to ports
seport:
ports: "80,443"
proto: tcp
setype: http_port_t
state: present
handlers:
- name: reload caddy
service:
name: caddy
state: reloaded

View file

@ -0,0 +1,40 @@
---
- name: Check and Install PostGIS
hosts: lab02
become: true
vars:
ct_id: 300
tasks:
- name: Check PostgreSQL version
command: |
pct exec {{ ct_id }} -- sudo -u postgres psql -c "SELECT version();"
register: pg_version
- name: Update apt cache in container
command: pct exec {{ ct_id }} -- bash -c "apt-get update"
- name: Search for PostGIS packages
command: pct exec {{ ct_id }} -- bash -c "apt-cache search postgis | grep postgresql"
register: postgis_packages
- name: Display available packages
debug:
msg: |
PostgreSQL Version:
{{ pg_version.stdout }}
Available PostGIS packages:
{{ postgis_packages.stdout }}
- name: Install PostGIS (flexible version)
command: pct exec {{ ct_id }} -- bash -c "apt-get install -y postgis"
register: install_result
- name: Enable PostGIS in APRS database
command: |
pct exec {{ ct_id }} -- sudo -u postgres psql -d aprs -c "CREATE EXTENSION IF NOT EXISTS postgis;"
- name: Display installation result
debug:
msg: "PostGIS installation completed!"

View file

@ -0,0 +1,33 @@
---
- name: Enable PostGIS Extension
hosts: lab02
become: true
vars:
ct_id: 300
tasks:
- name: Try to enable PostGIS extension
command: |
pct exec {{ ct_id }} -- sudo -u postgres psql -d aprs -c "CREATE EXTENSION IF NOT EXISTS postgis;"
register: postgis_enable
ignore_errors: yes
- name: Install PostGIS for PostgreSQL 15 if extension failed
command: pct exec {{ ct_id }} -- bash -c "apt-get install -y postgresql-15-postgis-3 || apt-get install -y postgis postgresql-postgis"
when: postgis_enable.rc != 0
register: install_result
ignore_errors: yes
- name: Try to enable PostGIS again if it was just installed
command: |
pct exec {{ ct_id }} -- sudo -u postgres psql -d aprs -c "CREATE EXTENSION IF NOT EXISTS postgis;"
when: postgis_enable.rc != 0
- name: Show results
debug:
msg: |
{% if postgis_enable.rc == 0 %}
PostGIS extension enabled successfully!
{% else %}
PostGIS installation attempt: {{ install_result.stderr | default('') }}
{% endif %}

View file

@ -0,0 +1,45 @@
---
- name: Enable PostGIS in APRS Database
hosts: lab02
become: true
vars:
ct_id: 300
tasks:
- name: Check if PostGIS is installed
command: |
pct exec {{ ct_id }} -- dpkg -l | grep postgis
register: postgis_check
ignore_errors: yes
- name: Install PostGIS if not present
command: pct exec {{ ct_id }} -- apt-get install -y postgresql-16-postgis-3 postgresql-16-postgis-3-scripts
when: postgis_check.rc != 0
- name: Enable PostGIS extension in APRS database
command: |
pct exec {{ ct_id }} -- sudo -u postgres psql -d aprs -c "CREATE EXTENSION IF NOT EXISTS postgis;"
register: postgis_result
- name: Enable PostGIS topology extension
command: |
pct exec {{ ct_id }} -- sudo -u postgres psql -d aprs -c "CREATE EXTENSION IF NOT EXISTS postgis_topology;"
ignore_errors: yes
- name: Verify PostGIS installation
command: |
pct exec {{ ct_id }} -- sudo -u postgres psql -d aprs -c "SELECT PostGIS_Version();"
register: postgis_version
ignore_errors: yes
- name: Display results
debug:
msg: |
PostGIS setup completed!
Extension creation: {{ postgis_result.stdout | default('Done') }}
{% if postgis_version.rc == 0 %}
PostGIS Version: {{ postgis_version.stdout }}
{% else %}
Note: PostGIS may require package installation
{% endif %}

View file

@ -0,0 +1,35 @@
---
- name: Install PostGIS in PostgreSQL LXC
hosts: lab02
become: true
vars:
ct_id: 300
tasks:
- name: Update apt cache
command: pct exec {{ ct_id }} -- apt-get update
- name: Install PostGIS package
command: pct exec {{ ct_id }} -- apt-get install -y postgresql-16-postgis-3
- name: Enable PostGIS extension in APRS database
command: |
pct exec {{ ct_id }} -- sudo -u postgres psql -d aprs -c "CREATE EXTENSION IF NOT EXISTS postgis;"
- name: Enable PostGIS topology extension
command: |
pct exec {{ ct_id }} -- sudo -u postgres psql -d aprs -c "CREATE EXTENSION IF NOT EXISTS postgis_topology;"
- name: Verify PostGIS installation
command: |
pct exec {{ ct_id }} -- sudo -u postgres psql -d aprs -c "SELECT PostGIS_Version();"
register: postgis_version
- name: Display PostGIS version
debug:
msg: |
PostGIS has been installed successfully!
Version: {{ postgis_version.stdout }}
The APRS database now has spatial capabilities for location data.

View file

@ -38,17 +38,12 @@ all:
ansible_python_interpreter: /usr/bin/python3
ansible_ssh_common_args: "-o StrictHostKeyChecking=no"
k3s_version: v1.28.5+k3s1
vultr:
hosts:
caddy:
ansible_host: "caddy.w5isp.com"
vars:
ansible_user: root # Initial connection as root to create users
ansible_python_interpreter: /usr/bin/python3
ansible_ssh_common_args: "-o StrictHostKeyChecking=no"
caddy_servers:
hosts:
caddy:
ansible_host: 204.110.191.212
vars:
ansible_user: root # Will switch to ansible user after creation
ansible_python_interpreter: /usr/bin/python3
ansible_user: ansible # Now using ansible user after bootstrap
ansible_ssh_private_key_file: "~/.ssh/ansible"
ansible_python_interpreter: /usr/bin/python3
ansible_ssh_common_args: "-o StrictHostKeyChecking=no"

View file

@ -0,0 +1,50 @@
---
- name: Setup APRS Database in PostgreSQL LXC
hosts: lab02
become: true
vars:
ct_id: 300
tasks:
- name: Create APRS database and user
command: |
pct exec {{ ct_id }} -- sudo -u postgres psql -c "CREATE USER aprs WITH PASSWORD 'xK9mP2vQ7sR3nL5w';"
ignore_errors: yes
register: create_user
- name: Create APRS database
command: |
pct exec {{ ct_id }} -- sudo -u postgres psql -c "CREATE DATABASE aprs OWNER aprs;"
ignore_errors: yes
register: create_db
- name: Grant privileges on APRS database
command: |
pct exec {{ ct_id }} -- sudo -u postgres psql -d aprs -c "GRANT ALL PRIVILEGES ON DATABASE aprs TO aprs; GRANT ALL ON SCHEMA public TO aprs;"
- name: Test APRS database connection
command: |
pct exec {{ ct_id }} -- sudo -u postgres psql -d aprs -c "SELECT current_database(), current_user;"
register: db_test
- name: Display results
debug:
msg: |
APRS database setup completed!
User creation: {{ 'Created' if create_user.rc == 0 else 'Already exists or failed' }}
Database creation: {{ 'Created' if create_db.rc == 0 else 'Already exists or failed' }}
Connection details:
- Host: 10.0.19.5
- Port: 5432
- Database: aprs
- User: aprs
- Password: xK9mP2vQ7sR3nL5w
Connection test output:
{{ db_test.stdout }}
Connection strings:
- PostgreSQL: postgresql://aprs:xK9mP2vQ7sR3nL5w@10.0.19.5:5432/aprs
- Ecto: ecto://aprs:xK9mP2vQ7sR3nL5w@10.0.19.5:5432/aprs

View file

@ -0,0 +1,18 @@
# Caddy reverse proxy configuration
# Managed by Ansible - do not edit manually
# Forgejo Git server
git.w5isp.com {
# Caddy will automatically obtain Let's Encrypt certificates
reverse_proxy http://100.109.233.14 {
# Tell backend that SSL is handled by proxy
header_up Host {host}
header_up X-Real-IP {remote}
header_up X-Forwarded-Proto https
header_up X-Forwarded-Port 443
}
}
# Add more entries below as needed

View file

@ -0,0 +1,53 @@
---
- name: Upgrade PostgreSQL to 16 and Install PostGIS
hosts: lab02
become: true
vars:
ct_id: 300
tasks:
- name: Add PostgreSQL APT repository
command: pct exec {{ ct_id }} -- bash -c "wget -q https://www.postgresql.org/media/keys/ACCC4CF8.asc -O- | apt-key add - && echo 'deb http://apt.postgresql.org/pub/repos/apt bookworm-pgdg main' > /etc/apt/sources.list.d/pgdg.list"
- name: Update apt cache
command: pct exec {{ ct_id }} -- apt-get update -qq
- name: Install PostgreSQL 16
command: pct exec {{ ct_id }} -- apt-get install -y postgresql-16 postgresql-client-16
- name: Check current PostgreSQL clusters
command: pct exec {{ ct_id }} -- pg_lsclusters
register: clusters
- name: Display current clusters
debug:
msg: "{{ clusters.stdout }}"
- name: Drop old PostgreSQL 16 cluster if exists
command: pct exec {{ ct_id }} -- pg_dropcluster 16 main --stop
ignore_errors: yes
- name: Upgrade cluster from 15 to 16
command: pct exec {{ ct_id }} -- pg_upgradecluster 15 main
- name: Install PostGIS for PostgreSQL 16
command: pct exec {{ ct_id }} -- apt-get install -y postgresql-16-postgis-3
- name: Enable PostGIS in APRS database
command: pct exec {{ ct_id }} -- sudo -u postgres psql -p 5433 -d aprs -c "CREATE EXTENSION IF NOT EXISTS postgis;"
- name: Switch to port 5432 for PostgreSQL 16
command: pct exec {{ ct_id }} -- bash -c "sed -i 's/port = 5433/port = 5432/' /etc/postgresql/16/main/postgresql.conf && systemctl restart postgresql@16-main"
- name: Stop PostgreSQL 15
command: pct exec {{ ct_id }} -- systemctl stop postgresql@15-main
- name: Verify upgrade
command: pct exec {{ ct_id }} -- sudo -u postgres psql -c "SELECT version();"
register: version
- name: Display results
debug:
msg: |
PostgreSQL upgrade completed!
{{ version.stdout }}

View file

@ -0,0 +1,71 @@
---
- name: Upgrade PostgreSQL 15 to 16 in LXC
hosts: lab02
become: true
vars:
ct_id: 300
tasks:
- name: Stop PostgreSQL 15 service
command: pct exec {{ ct_id }} -- systemctl stop postgresql@15-main
- name: Add PostgreSQL APT repository key
command: pct exec {{ ct_id }} -- bash -c "wget -q -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | apt-key add -"
- name: Add PostgreSQL APT repository
command: pct exec {{ ct_id }} -- bash -c "echo 'deb http://apt.postgresql.org/pub/repos/apt bookworm-pgdg main' > /etc/apt/sources.list.d/pgdg.list"
- name: Update apt cache
command: pct exec {{ ct_id }} -- apt-get update
- name: Install PostgreSQL 16
command: pct exec {{ ct_id }} -- apt-get install -y postgresql-16 postgresql-client-16 postgresql-contrib-16
- name: Stop PostgreSQL 16 (auto-started after install)
command: pct exec {{ ct_id }} -- systemctl stop postgresql@16-main
- name: Upgrade the cluster from 15 to 16
command: pct exec {{ ct_id }} -- sudo -u postgres /usr/lib/postgresql/16/bin/pg_upgrade -b /usr/lib/postgresql/15/bin -B /usr/lib/postgresql/16/bin -d /var/lib/postgresql/15/main -D /var/lib/postgresql/16/main -o "-c config_file=/etc/postgresql/15/main/postgresql.conf" -O "-c config_file=/etc/postgresql/16/main/postgresql.conf"
- name: Copy PostgreSQL 15 configuration
command: pct exec {{ ct_id }} -- bash -c "cp /etc/postgresql/15/main/postgresql.conf /etc/postgresql/16/main/ && cp /etc/postgresql/15/main/pg_hba.conf /etc/postgresql/16/main/"
- name: Update PostgreSQL 16 port to 5432
command: pct exec {{ ct_id }} -- sed -i "s/port = 5433/port = 5432/" /etc/postgresql/16/main/postgresql.conf
- name: Start PostgreSQL 16
command: pct exec {{ ct_id }} -- systemctl start postgresql@16-main
- name: Enable PostgreSQL 16
command: pct exec {{ ct_id }} -- systemctl enable postgresql@16-main
- name: Disable PostgreSQL 15
command: pct exec {{ ct_id }} -- systemctl disable postgresql@15-main
- name: Install PostGIS for PostgreSQL 16
command: pct exec {{ ct_id }} -- apt-get install -y postgresql-16-postgis-3
- name: Enable PostGIS in APRS database
command: pct exec {{ ct_id }} -- sudo -u postgres psql -d aprs -c "CREATE EXTENSION IF NOT EXISTS postgis;"
- name: Enable PostGIS in Forgejo database (if needed)
command: pct exec {{ ct_id }} -- sudo -u postgres psql -d forgejo -c "CREATE EXTENSION IF NOT EXISTS postgis;"
ignore_errors: yes
- name: Verify PostgreSQL version
command: pct exec {{ ct_id }} -- sudo -u postgres psql -c "SELECT version();"
register: pg_version
- name: Verify PostGIS installation
command: pct exec {{ ct_id }} -- sudo -u postgres psql -d aprs -c "SELECT PostGIS_Version();"
register: postgis_version
- name: Display results
debug:
msg: |
PostgreSQL upgrade completed!
{{ pg_version.stdout }}
PostGIS Version in APRS database:
{{ postgis_version.stdout }}

View file

@ -6,9 +6,9 @@ metadata:
type: Opaque
stringData:
database-password: "xK9mP2vQ7sR3nL5w"
# Direct connection to PostgreSQL on CM3588
database-url: "ecto://aprs:xK9mP2vQ7sR3nL5w@10.0.19.220:5432/aprs"
# Connection via PgBouncer on CM3588 (recommended)
database-url-pgbouncer: "ecto://aprs:xK9mP2vQ7sR3nL5w@10.0.19.220:6432/aprs"
# Direct connection to PostgreSQL VM
database-url: "ecto://aprs:xK9mP2vQ7sR3nL5w@10.0.19.5:5432/aprs"
# Connection via PgBouncer on PostgreSQL VM (if available)
database-url-pgbouncer: "ecto://aprs:xK9mP2vQ7sR3nL5w@10.0.19.5:6432/aprs"
erlang-cookie: "aprs-cluster-cookie-ksdf8934jfklsdjf983jfklsdf"
secret-key-base: "GJxzOUW3YXBAF7xB4mH5VcXY6BN1NYLnoJYadlZyiCxcRUGBw65w4Sco7+sNiW2t"

View file

@ -52,8 +52,8 @@ spec:
- sh
- -c
- |
echo "Waiting for PostgreSQL at 10.0.19.220:5432..."
until nc -z 10.0.19.220 5432; do
echo "Waiting for PostgreSQL at 10.0.19.5:5432..."
until nc -z 10.0.19.5 5432; do
echo "Database not ready, waiting..."
sleep 2
done

View file

@ -0,0 +1,28 @@
#!/bin/bash
# Script to create GitHub Container Registry pull secret for APRS
echo "This script will help you create a GitHub Container Registry pull secret"
echo "You need:"
echo "1. Your GitHub username"
echo "2. A GitHub Personal Access Token (PAT) with 'read:packages' scope"
echo ""
echo "To create a PAT:"
echo "1. Go to https://github.com/settings/tokens"
echo "2. Click 'Generate new token (classic)'"
echo "3. Select 'read:packages' scope"
echo "4. Generate the token"
echo ""
read -p "Enter your GitHub username: " GITHUB_USERNAME
read -s -p "Enter your GitHub PAT: " GITHUB_PAT
echo ""
kubectl create secret docker-registry ghcr-pull-secret \
--docker-server=ghcr.io \
--docker-username=$GITHUB_USERNAME \
--docker-password=$GITHUB_PAT \
--docker-email="${GITHUB_USERNAME}@users.noreply.github.com" \
--namespace=aprs \
--dry-run=client -o yaml | kubectl apply -f -
echo "Secret created/updated successfully!"

View file

@ -0,0 +1,18 @@
#!/bin/bash
# Manual commands to install PostGIS on the PostgreSQL LXC container
echo "Run these commands on the Proxmox host (lab02):"
echo ""
echo "# 1. Update package list in the container"
echo "pct exec 300 -- apt-get update"
echo ""
echo "# 2. Install PostGIS for PostgreSQL 15"
echo "pct exec 300 -- apt-get install -y postgresql-15-postgis-3"
echo ""
echo "# 3. Enable PostGIS extension in the APRS database"
echo "pct exec 300 -- sudo -u postgres psql -d aprs -c 'CREATE EXTENSION IF NOT EXISTS postgis;'"
echo ""
echo "# 4. Verify installation"
echo "pct exec 300 -- sudo -u postgres psql -d aprs -c 'SELECT PostGIS_Version();'"
echo ""
echo "After running these commands, the APRS migrations should work."

View file

@ -0,0 +1,73 @@
apiVersion: v1
kind: Service
metadata:
name: redis
namespace: aprs
labels:
app: redis
spec:
ports:
- port: 6379
targetPort: 6379
name: redis
selector:
app: redis
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: redis-data
namespace: aprs
spec:
accessModes:
- ReadWriteOnce
storageClassName: ceph-rbd
resources:
requests:
storage: 10Gi
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: redis
namespace: aprs
spec:
replicas: 1
selector:
matchLabels:
app: redis
template:
metadata:
labels:
app: redis
spec:
containers:
- name: redis
image: redis:7-alpine
command:
- redis-server
- --appendonly
- "yes"
- --save
- "900 1"
- --save
- "300 10"
- --save
- "60 10000"
ports:
- containerPort: 6379
name: redis
resources:
requests:
memory: "256Mi"
cpu: "100m"
limits:
memory: "512Mi"
cpu: "500m"
volumeMounts:
- name: redis-storage
mountPath: /data
volumes:
- name: redis-storage
persistentVolumeClaim:
claimName: redis-data

View file

@ -0,0 +1,55 @@
#!/bin/bash
# Setup APRS database on PostgreSQL VM
set -e
POSTGRES_HOST="10.0.19.5"
POSTGRES_USER="postgres"
APRS_USER="aprs"
APRS_PASSWORD="xK9mP2vQ7sR3nL5w"
APRS_DATABASE="aprs"
echo "Setting up APRS database on PostgreSQL server at $POSTGRES_HOST"
echo "This requires the postgres user password or SSH access to the PostgreSQL VM"
echo ""
# Create the SQL commands
SQL_COMMANDS="
-- Create APRS user
CREATE USER $APRS_USER WITH PASSWORD '$APRS_PASSWORD';
-- Create APRS database
CREATE DATABASE $APRS_DATABASE OWNER $APRS_USER;
-- Grant privileges
GRANT ALL PRIVILEGES ON DATABASE $APRS_DATABASE TO $APRS_USER;
"
# Option 1: Try with psql directly (requires postgres password)
echo "Attempting to connect to PostgreSQL directly..."
echo "$SQL_COMMANDS" | psql -h $POSTGRES_HOST -U $POSTGRES_USER -d postgres 2>/dev/null && {
echo "✓ Database setup completed successfully!"
echo ""
echo "Connection details:"
echo " Host: $POSTGRES_HOST"
echo " Database: $APRS_DATABASE"
echo " User: $APRS_USER"
echo " Password: $APRS_PASSWORD"
echo ""
echo "Connection string:"
echo " ecto://$APRS_USER:$APRS_PASSWORD@$POSTGRES_HOST:5432/$APRS_DATABASE"
exit 0
}
# If direct connection fails, provide manual instructions
echo "Could not connect directly. Please run these commands on the PostgreSQL server:"
echo ""
echo "sudo -u postgres psql << EOF"
echo "$SQL_COMMANDS"
echo "EOF"
echo ""
echo "Or SSH to the PostgreSQL VM and run:"
echo " ssh <user>@$POSTGRES_HOST"
echo " sudo -u postgres psql"
echo " Then paste the following:"
echo "$SQL_COMMANDS"

View file

@ -0,0 +1,25 @@
-- Setup script for APRS database on PostgreSQL VM (10.0.19.5)
-- Run this as the postgres superuser
-- Create the aprs user with the password from the Kubernetes secret
CREATE USER aprs WITH PASSWORD 'xK9mP2vQ7sR3nL5w';
-- Create the aprs database owned by the aprs user
CREATE DATABASE aprs OWNER aprs;
-- Connect to the aprs database
\c aprs
-- Grant all privileges on the aprs database to the aprs user
GRANT ALL PRIVILEGES ON DATABASE aprs TO aprs;
-- Create schema and grant privileges
GRANT ALL ON SCHEMA public TO aprs;
-- If you need PostGIS extensions (for APRS location data), uncomment:
-- CREATE EXTENSION IF NOT EXISTS postgis;
-- CREATE EXTENSION IF NOT EXISTS postgis_topology;
-- Verify the setup
\du aprs
\l aprs

View file

@ -66,7 +66,7 @@ spec:
- name: FORGEJO__database__PASSWD
value: fj8K3n2Qp9Lx5mW7
- name: FORGEJO__server__ROOT_URL
value: http://git.tail683b6.ts.net/
value: https://git.tail683b6.ts.net/
- name: FORGEJO__server__DOMAIN
value: git.tail683b6.ts.net
- name: FORGEJO__server__SSH_DOMAIN
@ -118,6 +118,7 @@ metadata:
tailscale.com/expose: "true"
tailscale.com/hostname: "git"
tailscale.com/tags: "tag:k8s"
tailscale.com/funnel: "true"
spec:
type: LoadBalancer
loadBalancerClass: tailscale

View file

@ -0,0 +1,26 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: forgejo-proxy-config
namespace: forgejo
data:
app.ini: |
[server]
PROTOCOL = http
HTTP_PORT = 3000
ROOT_URL = https://git.w5isp.com/
DISABLE_SSH = false
SSH_PORT = 22
START_SSH_SERVER = true
OFFLINE_MODE = false
# Disable HTTPS redirect since proxy handles SSL
REDIRECT_OTHER_PORT = false
PORT_TO_REDIRECT = 0
# Trust proxy headers
REVERSE_PROXY_LIMIT = 1
REVERSE_PROXY_TRUSTED_PROXIES = 100.109.233.14,204.110.191.212,100.0.0.0/8
[service]
DISABLE_REGISTRATION = false
REQUIRE_SIGNIN_VIEW = false

View file

@ -0,0 +1,23 @@
apiVersion: v1
kind: Service
metadata:
name: forgejo-tailscale
namespace: forgejo
annotations:
tailscale.com/expose: "true"
tailscale.com/hostname: "git"
tailscale.com/funnel: "true"
spec:
type: LoadBalancer
loadBalancerClass: tailscale
selector:
app: forgejo
ports:
- name: http
port: 80
targetPort: 3000
protocol: TCP
- name: ssh
port: 22
targetPort: 2222
protocol: TCP

View file

@ -0,0 +1,22 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: forgejo
namespace: forgejo
spec:
template:
spec:
containers:
- name: forgejo
volumeMounts:
- mountPath: /data
name: data
- mountPath: /data/gitea/conf
name: config
volumes:
- name: data
persistentVolumeClaim:
claimName: forgejo-data-rbd-dynamic
- name: config
configMap:
name: forgejo-proxy-config

View file

@ -41,11 +41,11 @@ spec:
- name: FORGEJO__database__PASSWD
value: fj8K3n2Qp9Lx5mW7
- name: FORGEJO__server__ROOT_URL
value: http://10.0.19.3/
value: https://git.tail683b6.ts.net/
- name: FORGEJO__server__DOMAIN
value: "10.0.19.3"
value: git.tail683b6.ts.net
- name: FORGEJO__server__SSH_DOMAIN
value: "10.0.19.3"
value: git.tail683b6.ts.net
- name: FORGEJO__DEFAULT__APP_NAME
value: "w5isp's code"
volumeMounts:

View file

@ -0,0 +1,15 @@
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: forgejo
namespace: forgejo
spec:
defaultBackend:
service:
name: forgejo
port:
number: 80
ingressClassName: tailscale
tls:
- hosts:
- git

View file

@ -3,6 +3,9 @@ kind: Ingress
metadata:
name: forgejo-tailscale
namespace: forgejo
annotations:
tailscale.com/hostname: "git"
tailscale.com/tags: "tag:k8s"
spec:
ingressClassName: tailscale
defaultBackend:
@ -12,4 +15,4 @@ spec:
number: 80
tls:
- hosts:
- forgejo
- git

View file

@ -0,0 +1,41 @@
apiVersion: v1
kind: Service
metadata:
name: forgejo-tailscale
namespace: forgejo
annotations:
tailscale.com/expose: "true"
tailscale.com/hostname: "git"
tailscale.com/tags: "tag:k8s"
# Enable HTTPS with serve
tailscale.com/serve-config: |
{
"TCP": {
"443": {
"HTTPS": true
}
},
"Web": {
"${TS_CERT_DOMAIN}:443": {
"Handlers": {
"/": {
"Proxy": "http://forgejo.forgejo.svc.cluster.local:80"
}
}
}
}
}
spec:
type: LoadBalancer
loadBalancerClass: tailscale
selector:
app: forgejo
ports:
- port: 443
targetPort: 3000
protocol: TCP
name: https
- port: 22
targetPort: 2222
protocol: TCP
name: ssh

View file

@ -1,235 +0,0 @@
#cloud-config
# Cloud-init configuration for Debian 13 Vultr server with Caddy proxy and Tailscale
# Update and upgrade packages on first boot
package_update: true
package_upgrade: true
# Configure hostname
hostname: caddy
# Configure timezone
timezone: America/Chicago
# Install packages
packages:
# SSH server
- openssh-server
# Include all base packages
- sudo
- curl
- wget
- git
- vim
- tmux
- htop
- rsync
- net-tools
- dnsutils
- build-essential
- python3
- python3-pip
- apt-transport-https
- ca-certificates
- gnupg
- lsb-release
- software-properties-common
- fail2ban
- ufw
# Caddy and web server tools
- debian-keyring
- debian-archive-keyring
# Create users with sudo access
users:
- name: graham
groups: sudo
shell: /bin/bash
sudo: ALL=(ALL) NOPASSWD:ALL
ssh_import_id:
- gh:gmcintire
- name: andy
groups: sudo
shell: /bin/bash
sudo: ALL=(ALL) NOPASSWD:ALL
ssh_import_id:
- gh:nsnw
- name: ansible
uid: 10001
groups: sudo
shell: /bin/bash
sudo: ALL=(ALL) NOPASSWD:ALL
ssh_authorized_keys:
- ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIFghGMnDdkfNC6JPEhMxrKhYDmNcXjHXp/y/mf3uLtzb graham@mbp14.local
# Configure SSH
ssh_pwauth: false
disable_root: false # Allow root initially for Vultr SSH keys
# Write configuration files
write_files:
- path: /etc/ssh/sshd_config.d/99-custom.conf
content: |
PermitRootLogin prohibit-password
PasswordAuthentication no
PubkeyAuthentication yes
AuthorizedKeysFile .ssh/authorized_keys
Banner /etc/issue.net
- path: /etc/issue.net
content: |
******************************************************************
* Authorized access only. All activity is monitored. *
******************************************************************
- path: /etc/apt/sources.list.d/caddy-stable.list
content: |
deb [signed-by=/usr/share/keyrings/caddy-stable-archive-keyring.gpg] https://dl.cloudsmith.io/public/caddy/stable/deb/debian any-version main
- path: /etc/caddy/Caddyfile
content: |
# Global options
{
# Email for Let's Encrypt
email admin@example.com
# Enable the admin endpoint
admin off
}
# Default site - return 404 for undefined hosts
:80 {
respond 404
}
# Example reverse proxy configuration
# example.com {
# reverse_proxy localhost:8080
# }
permissions: '0644'
owner: root:root
- path: /etc/sysctl.d/99-tailscale.conf
content: |
# Tailscale UDP GRO fix
net.ipv4.udp_rmem_min = 131072
net.ipv4.udp_wmem_min = 131072
net.core.rmem_default = 131072
net.core.wmem_default = 131072
net.core.netdev_max_backlog = 5000
- path: /opt/scripts/install-tailscale.sh
content: |
#!/bin/bash
# Install Tailscale
curl -fsSL https://pkgs.tailscale.com/stable/debian/bookworm.noarmor.gpg | tee /usr/share/keyrings/tailscale-archive-keyring.gpg >/dev/null
curl -fsSL https://pkgs.tailscale.com/stable/debian/bookworm.tailscale-keyring.list | tee /etc/apt/sources.list.d/tailscale.list
apt-get update
apt-get install -y tailscale
# Enable and start tailscaled
systemctl enable tailscaled
systemctl start tailscaled
# If TAILSCALE_KEY is provided, authenticate
if [ -n "$TAILSCALE_KEY" ]; then
tailscale up --authkey="$TAILSCALE_KEY" --accept-routes --hostname=$(hostname)
fi
permissions: '0755'
- path: /opt/scripts/setup-caddy.sh
content: |
#!/bin/bash
# Ensure Caddy starts after network is ready
mkdir -p /etc/systemd/system/caddy.service.d
cat > /etc/systemd/system/caddy.service.d/override.conf <<EOF
[Unit]
After=network-online.target
Wants=network-online.target
[Service]
# Restart on failure
Restart=on-failure
RestartSec=5s
EOF
systemctl daemon-reload
systemctl enable caddy
systemctl start caddy
permissions: '0755'
# Configure firewall
ufw:
enabled: true
rules:
- port: 22
protocol: tcp
rule: allow
comment: SSH
- port: 80
protocol: tcp
rule: allow
comment: HTTP
- port: 443
protocol: tcp
rule: allow
comment: HTTPS
- port: 41641
protocol: udp
rule: allow
from_any: true
comment: Tailscale
# Run commands on first boot
runcmd:
# Ensure SSH is started and enabled
- systemctl enable ssh
- systemctl start ssh
- systemctl reload ssh
# Add Caddy GPG key and install
- curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg
- apt-get update
- apt-get install -y caddy
# Apply sysctl settings
- sysctl -p /etc/sysctl.d/99-tailscale.conf
# Create Caddy directories
- mkdir -p /etc/caddy/sites-enabled
- chown -R caddy:caddy /etc/caddy
# Install Tailscale
- /opt/scripts/install-tailscale.sh
# Setup Caddy service
- /opt/scripts/setup-caddy.sh
# Configure fail2ban for Caddy
- |
cat > /etc/fail2ban/jail.d/caddy.conf <<EOF
[caddy-status]
enabled = true
filter = caddy-status
logpath = /var/log/caddy/access.log
maxretry = 5
bantime = 600
EOF
# Enable services
- systemctl enable fail2ban
- systemctl start fail2ban
# Final message
final_message: "Debian 13 Caddy proxy setup complete! System ready after $UPTIME seconds"
# Power state - don't reboot automatically for proxy servers
power_state:
delay: now
mode: poweroff
message: Initial configuration complete
condition: false

View file

@ -73,7 +73,7 @@ resource "dnsimple_zone_record" "w5isp_jellyfin" {
resource "dnsimple_zone_record" "w5isp_wildcard" {
zone_name = "w5isp.com"
name = "*"
value = "144.202.72.28" # Reserved IP for Caddy proxy
value = "204.110.191.212" # New Caddy proxy server
type = "A"
ttl = 3600
}
@ -168,11 +168,11 @@ resource "dnsimple_zone_record" "w5isp_sendgrid4" {
ttl = 36000
}
# Caddy proxy server on Vultr - using reserved IP
# Caddy proxy server
resource "dnsimple_zone_record" "w5isp_caddy" {
zone_name = "w5isp.com"
name = "caddy"
value = "144.202.72.28" # Reserved IP
value = "204.110.191.212" # New Caddy proxy server
type = "A"
ttl = 3600
}

View file

@ -1,25 +1,9 @@
# Vultr Outputs
output "vultr_instance_ip" {
description = "Public IP address of the Vultr caddy proxy instance"
value = vultr_instance.caddy_proxy.main_ip
# Caddy Proxy Outputs
output "caddy_proxy_ip" {
description = "IP address of the Caddy proxy server"
value = "204.110.191.212"
}
output "vultr_reserved_ip" {
description = "Reserved IP address for the Caddy proxy (144.202.72.28)"
value = data.vultr_reserved_ip.caddy.subnet
}
output "vultr_instance_id" {
description = "ID of the Vultr caddy proxy instance"
value = vultr_instance.caddy_proxy.id
}
output "vultr_instance_label" {
description = "Label of the Vultr caddy proxy instance"
value = vultr_instance.caddy_proxy.label
}
# # # Proxmox Outputs
# output "control_plane_ips" {

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -1,71 +0,0 @@
# Dallas region
data "vultr_region" "dallas" {
filter {
name = "id"
values = ["dfw"]
}
}
# Debian 13 image (Trixie)
data "vultr_os" "debian13" {
filter {
name = "name"
values = ["Debian 13 x64 (trixie)"]
}
}
# vc2-1c-1gb plan
data "vultr_plan" "vc2_1c_1gb" {
filter {
name = "id"
values = ["vc2-1c-1gb"]
}
}
# SSH Keys
data "vultr_ssh_key" "g" {
filter {
name = "name"
values = ["g"]
}
}
data "vultr_ssh_key" "graham" {
filter {
name = "name"
values = ["graham@mcintire.me"]
}
}
# Get the reserved IP by label
data "vultr_reserved_ip" "caddy" {
filter {
name = "label"
values = ["caddy"]
}
}
resource "vultr_instance" "caddy_proxy" {
plan = data.vultr_plan.vc2_1c_1gb.id
region = data.vultr_region.dallas.id
os_id = data.vultr_os.debian13.id
label = "caddy"
hostname = "caddy"
# Disable backups
backups = "disabled"
# Attach the reserved IP
reserved_ip_id = data.vultr_reserved_ip.caddy.id
# SSH keys for initial access
ssh_key_ids = [
data.vultr_ssh_key.g.id,
data.vultr_ssh_key.graham.id
]
# Cloud-init configuration for Debian 13
user_data = base64encode(file("${path.module}/debian13-caddy-cloud-init.yml"))
tags = ["caddy", "proxy", "tailscale"]
}