mirror of
https://github.com/cole-maxwell1/todo-hetzner.git
synced 2026-10-27 19:02:49 -05:00
feat: add Hetzner-hosted todo application stack
Implement the server-rendered Go todo application with PostgreSQL persistence, Tailwind styling, health checks, and test coverage. Provision production and staging infrastructure with OpenTofu, including private networking, static IPs, Object Storage backups, and load balancing. Configure Rocky Linux hosts with Ansible, rootless Podman, PostgreSQL, WAL-G backup automation, staging restores, and generated inventory.
This commit is contained in:
@@ -0,0 +1,4 @@
|
||||
app_user: todo
|
||||
app_port: 8080
|
||||
app_db_name: todo
|
||||
app_db_user: todo_app
|
||||
@@ -0,0 +1,71 @@
|
||||
---
|
||||
- name: Look up application user
|
||||
ansible.builtin.getent:
|
||||
database: passwd
|
||||
key: "{{ app_user }}"
|
||||
|
||||
- name: Store application user ID
|
||||
ansible.builtin.set_fact:
|
||||
app_user_uid: "{{ ansible_facts.getent_passwd[app_user][1] }}"
|
||||
|
||||
- name: Create Quadlet directory
|
||||
ansible.builtin.file:
|
||||
path: "/home/{{ app_user }}/.config/containers/systemd"
|
||||
state: directory
|
||||
owner: "{{ app_user }}"
|
||||
group: "{{ app_user }}"
|
||||
mode: "0700"
|
||||
|
||||
- name: Install protected application environment
|
||||
ansible.builtin.template:
|
||||
src: app.env.j2
|
||||
dest: "/home/{{ app_user }}/.config/todo.env"
|
||||
owner: "{{ app_user }}"
|
||||
group: "{{ app_user }}"
|
||||
mode: "0600"
|
||||
no_log: true
|
||||
|
||||
- name: Authenticate to private registry
|
||||
ansible.builtin.command:
|
||||
argv:
|
||||
- podman
|
||||
- login
|
||||
- --username
|
||||
- "{{ registry_username }}"
|
||||
- --password-stdin
|
||||
- "{{ registry_server }}"
|
||||
stdin: "{{ registry_password }}"
|
||||
become_user: "{{ app_user }}"
|
||||
environment:
|
||||
XDG_RUNTIME_DIR: "/run/user/{{ app_user_uid }}"
|
||||
changed_when: true
|
||||
no_log: true
|
||||
when:
|
||||
- registry_username is defined
|
||||
- registry_password is defined
|
||||
- registry_server is defined
|
||||
|
||||
- name: Install application Quadlet
|
||||
ansible.builtin.template:
|
||||
src: app-todo.container.j2
|
||||
dest: "/home/{{ app_user }}/.config/containers/systemd/app-todo.container"
|
||||
owner: "{{ app_user }}"
|
||||
group: "{{ app_user }}"
|
||||
mode: "0644"
|
||||
|
||||
- name: Reload application user manager
|
||||
ansible.builtin.command:
|
||||
argv: [systemctl, --user, daemon-reload]
|
||||
become_user: "{{ app_user }}"
|
||||
environment:
|
||||
XDG_RUNTIME_DIR: "/run/user/{{ app_user_uid }}"
|
||||
changed_when: false
|
||||
|
||||
- name: Enable application service
|
||||
ansible.builtin.command:
|
||||
argv: [systemctl, --user, enable, --now, app-todo.service]
|
||||
become_user: "{{ app_user }}"
|
||||
environment:
|
||||
XDG_RUNTIME_DIR: "/run/user/{{ app_user_uid }}"
|
||||
register: app_enable
|
||||
changed_when: "'Created symlink' in app_enable.stderr"
|
||||
@@ -0,0 +1,22 @@
|
||||
[Unit]
|
||||
Description=Todo web application
|
||||
After=network-online.target
|
||||
Wants=network-online.target
|
||||
|
||||
[Container]
|
||||
Image={{ app_image }}
|
||||
ContainerName=app-todo
|
||||
EnvironmentFile=/home/{{ app_user }}/.config/todo.env
|
||||
Network=host
|
||||
Pull=never
|
||||
NoNewPrivileges=true
|
||||
ReadOnly=true
|
||||
DropCapability=all
|
||||
|
||||
[Service]
|
||||
Restart=always
|
||||
RestartSec=5
|
||||
TimeoutStopSec=15
|
||||
|
||||
[Install]
|
||||
WantedBy=default.target
|
||||
@@ -0,0 +1,2 @@
|
||||
APP_ADDR=0.0.0.0:{{ app_port }}
|
||||
DATABASE_URL=postgres://{{ app_db_user | urlencode }}:{{ app_db_password | urlencode }}@127.0.0.1:5432/{{ app_db_name | urlencode }}?sslmode=disable
|
||||
Reference in New Issue
Block a user