Initial build: Great Bear microbrewery site
- TanStack Start (React 19, Tailwind 4) frontend recreated from Stitch design - PocketBase backend with schema migration + idempotent content seed - Single Docker image running both services (non-root, healthchecked) - deploy.sh to build & push to registry.tanshu.com - Ansible playbook (roles: app, caddy) deploying to www.greatbear.in with Caddy TLS entries for the site and the PocketBase admin
This commit is contained in:
@@ -0,0 +1,9 @@
|
||||
[defaults]
|
||||
inventory = inventory/hosts.yml
|
||||
roles_path = roles
|
||||
host_key_checking = True
|
||||
retry_files_enabled = False
|
||||
interpreter_python = auto_silent
|
||||
|
||||
[ssh_connection]
|
||||
pipelining = True
|
||||
@@ -0,0 +1,31 @@
|
||||
---
|
||||
# Deployment variables for The Great Bear.
|
||||
# NOTE: This file contains credentials. For anything beyond a private homelab
|
||||
# repo, encrypt it with: ansible-vault encrypt group_vars/greatbear/vars.yml
|
||||
|
||||
# --- Domains (Caddy provisions TLS for both automatically) ---
|
||||
site_domain: www.greatbear.in
|
||||
admin_domain: admin.greatbear.in
|
||||
|
||||
# --- Container image ---
|
||||
registry_url: registry.tanshu.com
|
||||
registry_username: ta-registry
|
||||
registry_password: ff28a01f00c0f39315d94cd9dcb1e554968dba25676a8ea5f2be34e96a9a099f
|
||||
app_image: registry.tanshu.com/tanshu/greatbear
|
||||
app_image_tag: latest
|
||||
|
||||
# --- Container runtime ---
|
||||
app_container_name: greatbear
|
||||
app_volume_name: greatbear_pb_data
|
||||
# Ports are bound to loopback only; Caddy proxies public traffic to them.
|
||||
app_site_publish: 127.0.0.1:3000:3000
|
||||
app_admin_publish: 127.0.0.1:8090:8090
|
||||
|
||||
# --- PocketBase initial admin (idempotent bootstrap on container start) ---
|
||||
pb_superuser_email: admin@greatbear.in
|
||||
pb_superuser_password: GreatBear!Admin2024
|
||||
|
||||
# --- Caddy ---
|
||||
caddy_config_dir: /etc/caddy/caddy.d
|
||||
caddyfile_path: /etc/caddy/Caddyfile
|
||||
caddy_service: caddy
|
||||
@@ -0,0 +1,9 @@
|
||||
all:
|
||||
children:
|
||||
greatbear:
|
||||
hosts:
|
||||
www.greatbear.in:
|
||||
ansible_user: root
|
||||
# ansible_ssh_private_key_file: ~/.ssh/id_ed25519
|
||||
# Override ansible_user if you log in as a non-root sudo user:
|
||||
# ansible_user: ubuntu
|
||||
@@ -0,0 +1,58 @@
|
||||
---
|
||||
# Pull the image from the private registry and (re)create the app container.
|
||||
- name: Log in to the private registry
|
||||
community.docker.docker_login:
|
||||
registry_url: "{{ registry_url }}"
|
||||
username: "{{ registry_username }}"
|
||||
password: "{{ registry_password }}"
|
||||
|
||||
- name: Pull the application image
|
||||
community.docker.docker_image:
|
||||
name: "{{ app_image }}"
|
||||
tag: "{{ app_image_tag }}"
|
||||
source: pull
|
||||
force_source: true
|
||||
|
||||
- name: Run the application container
|
||||
community.docker.docker_container:
|
||||
name: "{{ app_container_name }}"
|
||||
image: "{{ app_image }}:{{ app_image_tag }}"
|
||||
state: started
|
||||
recreate: true
|
||||
restart_policy: unless-stopped
|
||||
published_ports:
|
||||
- "{{ app_site_publish }}"
|
||||
- "{{ app_admin_publish }}"
|
||||
volumes:
|
||||
- "{{ app_volume_name }}:/data"
|
||||
env:
|
||||
PORT: "3000"
|
||||
PB_URL: "http://127.0.0.1:8090"
|
||||
PB_SUPERUSER_EMAIL: "{{ pb_superuser_email }}"
|
||||
PB_SUPERUSER_PASSWORD: "{{ pb_superuser_password }}"
|
||||
comparisons:
|
||||
image: ignore # recreate: true already handles image updates
|
||||
container_default_behavior: compatibility
|
||||
|
||||
- name: Wait for PocketBase to become healthy
|
||||
ansible.builtin.uri:
|
||||
url: http://127.0.0.1:8090/api/health
|
||||
status_code: 200
|
||||
register: pb_health
|
||||
retries: 30
|
||||
delay: 5
|
||||
until: pb_health.status == 200
|
||||
|
||||
- name: Wait for the site to respond
|
||||
ansible.builtin.uri:
|
||||
url: http://127.0.0.1:3000/
|
||||
status_code: 200
|
||||
register: site_health
|
||||
retries: 30
|
||||
delay: 5
|
||||
until: site_health.status == 200
|
||||
|
||||
- name: Log out of the private registry
|
||||
community.docker.docker_login:
|
||||
registry_url: "{{ registry_url }}"
|
||||
state: absent
|
||||
@@ -0,0 +1,5 @@
|
||||
---
|
||||
- name: Reload Caddy
|
||||
ansible.builtin.systemd:
|
||||
name: "{{ caddy_service }}"
|
||||
state: reloaded
|
||||
@@ -0,0 +1,47 @@
|
||||
---
|
||||
# Manage Caddy entries for the site and the PocketBase admin/API host.
|
||||
- name: Ensure Caddy config include directory exists
|
||||
ansible.builtin.file:
|
||||
path: "{{ caddy_config_dir }}"
|
||||
state: directory
|
||||
owner: root
|
||||
group: root
|
||||
mode: "0755"
|
||||
|
||||
- name: Check whether the main Caddyfile exists
|
||||
ansible.builtin.stat:
|
||||
path: "{{ caddyfile_path }}"
|
||||
register: caddyfile_stat
|
||||
|
||||
- name: Ensure the main Caddyfile imports conf.d entries
|
||||
ansible.builtin.lineinfile:
|
||||
path: "{{ caddyfile_path }}"
|
||||
line: "import {{ caddy_config_dir }}/*.conf"
|
||||
insertafter: EOF
|
||||
state: present
|
||||
when: caddyfile_stat.stat.exists
|
||||
notify: Reload Caddy
|
||||
|
||||
- name: Install Great Bear Caddy entries
|
||||
ansible.builtin.template:
|
||||
src: greatbear.conf.j2
|
||||
dest: "{{ caddy_config_dir }}/greatbear.conf"
|
||||
owner: root
|
||||
group: root
|
||||
mode: "0644"
|
||||
notify: Reload Caddy
|
||||
|
||||
- name: Validate Caddy configuration
|
||||
ansible.builtin.command:
|
||||
cmd: "caddy validate --config {{ caddyfile_path }} --adapter caddyfile"
|
||||
changed_when: false
|
||||
when: caddyfile_stat.stat.exists
|
||||
|
||||
- name: Flush handlers (reload Caddy now)
|
||||
ansible.builtin.meta: flush_handlers
|
||||
|
||||
- name: Ensure Caddy is enabled and running
|
||||
ansible.builtin.systemd:
|
||||
name: "{{ caddy_service }}"
|
||||
state: started
|
||||
enabled: true
|
||||
@@ -0,0 +1,12 @@
|
||||
# The Great Bear — managed by Ansible. Changes will be overwritten.
|
||||
# Frontend (TanStack Start)
|
||||
{{ site_domain }} {
|
||||
encode zstd gzip
|
||||
reverse_proxy 127.0.0.1:3000
|
||||
}
|
||||
|
||||
# PocketBase API + admin UI (http://{{ admin_domain }}/_/)
|
||||
{{ admin_domain }} {
|
||||
encode zstd gzip
|
||||
reverse_proxy 127.0.0.1:8090
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
---
|
||||
- name: Deploy The Great Bear (PocketBase + TanStack Start)
|
||||
hosts: greatbear
|
||||
become: true
|
||||
roles:
|
||||
- role: app
|
||||
tags: [app, deploy]
|
||||
- role: caddy
|
||||
tags: [caddy, web]
|
||||
Reference in New Issue
Block a user