Remove infra folder — moved to lunarfront-infra repo

This commit is contained in:
Ryan Moon
2026-03-31 08:11:37 -05:00
parent d18d431bd0
commit ffef4c8727
25 changed files with 0 additions and 652 deletions

View File

@@ -1,7 +0,0 @@
---
- name: Set up Gitea
hosts: gitea
become: true
roles:
- gitea

View File

@@ -1,12 +0,0 @@
# Copy to vault.yml and encrypt with: ansible-vault encrypt vault.yml
# Reference in playbook with: ansible-playbook --ask-vault-pass gitea.yml
---
cf_origin_cert: |
-----BEGIN CERTIFICATE-----
<paste cert from Cloudflare here>
-----END CERTIFICATE-----
cf_origin_key: |
-----BEGIN PRIVATE KEY-----
<paste key from Cloudflare here>
-----END PRIVATE KEY-----

View File

@@ -1,9 +0,0 @@
---
- name: Set up infra server
hosts: infra
become: true
roles:
- gitea
- gitea-runner
- vaultwarden

View File

@@ -1,2 +0,0 @@
[gitea]
<GITEA_IP> ansible_user=root ansible_ssh_private_key_file=~/.ssh/id_ed25519

View File

@@ -1,10 +0,0 @@
---
gitea_runner_version: "0.2.11"
gitea_runner_data_dir: /var/lib/gitea-runner
gitea_instance_url: "https://git.example.com"
# Generate in Gitea: Site Admin → Actions → Runners → Create new runner
gitea_runner_token: ""
gitea_runner_name: "{{ inventory_hostname }}"
gitea_runner_labels: "ubuntu-latest:docker://node:20"

View File

@@ -1,6 +0,0 @@
---
- name: Restart gitea-runner
community.docker.docker_compose_v2:
project_src: "{{ gitea_runner_data_dir }}"
state: present
recreate: always

View File

@@ -1,27 +0,0 @@
---
- name: Create gitea-runner data directory
file:
path: "{{ gitea_runner_data_dir }}"
state: directory
owner: root
group: root
mode: "0700"
- name: Deploy docker-compose file
template:
src: docker-compose.yml.j2
dest: "{{ gitea_runner_data_dir }}/docker-compose.yml"
mode: "0600"
notify: Restart gitea-runner
- name: Deploy runner config
template:
src: config.yml.j2
dest: "{{ gitea_runner_data_dir }}/config.yml"
mode: "0600"
notify: Restart gitea-runner
- name: Start gitea-runner
community.docker.docker_compose_v2:
project_src: "{{ gitea_runner_data_dir }}"
state: present

View File

@@ -1,17 +0,0 @@
log:
level: info
runner:
file: /data/.runner
capacity: 2 # max concurrent jobs — lower if droplet is under load
labels:
- "ubuntu-latest:docker://node:20"
- "ubuntu-22.04:docker://node:20"
cache:
enabled: true
dir: /data/cache
container:
network: bridge
force_pull: false # reuse cached images to speed up builds

View File

@@ -1,14 +0,0 @@
services:
gitea-runner:
image: gitea/act_runner:{{ gitea_runner_version }}
container_name: gitea-runner
restart: unless-stopped
volumes:
- {{ gitea_runner_data_dir }}/config.yml:/config.yml
- {{ gitea_runner_data_dir }}/data:/data
- /var/run/docker.sock:/var/run/docker.sock # allows runner to spin up job containers
environment:
CONFIG_FILE: /config.yml
GITEA_INSTANCE_URL: "{{ gitea_instance_url }}"
GITEA_RUNNER_REGISTRATION_TOKEN: "{{ gitea_runner_token }}"
GITEA_RUNNER_NAME: "{{ gitea_runner_name }}"

View File

@@ -1,10 +0,0 @@
---
gitea_version: "1.22.3"
gitea_domain: "git.example.com"
gitea_http_port: 3000
gitea_ssh_port: 2222
gitea_data_dir: /var/lib/gitea
# Cloudflare Origin Certificate
cf_origin_cert: ""
cf_origin_key: ""

View File

@@ -1,11 +0,0 @@
---
- name: Restart gitea
community.docker.docker_compose_v2:
project_src: "{{ gitea_data_dir }}"
state: present
recreate: always
- name: Reload nginx
systemd:
name: nginx
state: reloaded

View File

@@ -1,88 +0,0 @@
---
- name: Install dependencies
apt:
name: [nginx, docker.io, docker-compose-v2]
state: present
update_cache: true
- name: Enable and start Docker
systemd:
name: docker
enabled: true
state: started
- name: Create gitea data directory
file:
path: "{{ gitea_data_dir }}"
state: directory
owner: root
group: root
mode: "0700"
- name: Deploy docker-compose file
template:
src: docker-compose.yml.j2
dest: "{{ gitea_data_dir }}/docker-compose.yml"
mode: "0600"
notify: Restart gitea
- name: Start gitea
community.docker.docker_compose_v2:
project_src: "{{ gitea_data_dir }}"
state: present
# ─── Cloudflare Origin Certificate ───────────────────────────────────────────
- name: Create SSL directory
file:
path: /etc/nginx/ssl
state: directory
owner: root
group: root
mode: "0700"
- name: Install Cloudflare origin certificate
copy:
content: "{{ cf_origin_cert }}"
dest: /etc/nginx/ssl/cf-origin.pem
owner: root
group: root
mode: "0600"
notify: Reload nginx
- name: Install Cloudflare origin key
copy:
content: "{{ cf_origin_key }}"
dest: /etc/nginx/ssl/cf-origin.key
owner: root
group: root
mode: "0600"
notify: Reload nginx
# ─── nginx ────────────────────────────────────────────────────────────────────
- name: Deploy nginx config
template:
src: nginx.conf.j2
dest: /etc/nginx/sites-available/gitea
mode: "0644"
notify: Reload nginx
- name: Enable nginx site
file:
src: /etc/nginx/sites-available/gitea
dest: /etc/nginx/sites-enabled/gitea
state: link
notify: Reload nginx
- name: Remove nginx default site
file:
path: /etc/nginx/sites-enabled/default
state: absent
notify: Reload nginx
- name: Ensure nginx is started
systemd:
name: nginx
enabled: true
state: started

View File

@@ -1,19 +0,0 @@
services:
gitea:
image: gitea/gitea:{{ gitea_version }}
container_name: gitea
restart: unless-stopped
volumes:
- {{ gitea_data_dir }}/data:/data
environment:
USER_UID: 1000
USER_GID: 1000
GITEA__server__DOMAIN: "{{ gitea_domain }}"
GITEA__server__ROOT_URL: "https://{{ gitea_domain }}/"
GITEA__server__HTTP_PORT: 3000
GITEA__server__SSH_DOMAIN: "{{ gitea_domain }}"
GITEA__server__SSH_PORT: "{{ gitea_ssh_port }}"
GITEA__server__START_SSH_SERVER: "true"
ports:
- "127.0.0.1:{{ gitea_http_port }}:3000"
- "{{ gitea_ssh_port }}:22"

View File

@@ -1,24 +0,0 @@
server {
listen 80;
server_name {{ gitea_domain }};
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
server_name {{ gitea_domain }};
ssl_certificate /etc/nginx/ssl/cf-origin.pem;
ssl_certificate_key /etc/nginx/ssl/cf-origin.key;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
location / {
proxy_pass http://127.0.0.1:{{ gitea_http_port }};
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}

View File

@@ -1,18 +0,0 @@
---
vaultwarden_domain: "vault.example.com"
vaultwarden_port: 8080
vaultwarden_data_dir: /var/lib/vaultwarden
# Set to your postgres connection string or leave as default for SQLite
vaultwarden_database_url: "" # e.g. postgresql://user:pass@host/vaultwarden
# Restrict signups after first admin account is created
vaultwarden_signups_allowed: "true"
# Admin token — set this to a strong random string
# Generate with: openssl rand -base64 48
vaultwarden_admin_token: ""
# Cloudflare Origin Certificate
cf_origin_cert: ""
cf_origin_key: ""

View File

@@ -1,11 +0,0 @@
---
- name: Restart vaultwarden
community.docker.docker_compose_v2:
project_src: "{{ vaultwarden_data_dir }}"
state: present
recreate: always
- name: Reload nginx
systemd:
name: nginx
state: reloaded

View File

@@ -1,76 +0,0 @@
---
- name: Install dependencies
apt:
name: [docker.io, docker-compose-v2]
state: present
update_cache: true
- name: Enable and start Docker
systemd:
name: docker
enabled: true
state: started
- name: Create vaultwarden data directory
file:
path: "{{ vaultwarden_data_dir }}"
state: directory
owner: root
group: root
mode: "0700"
- name: Deploy docker-compose file
template:
src: docker-compose.yml.j2
dest: "{{ vaultwarden_data_dir }}/docker-compose.yml"
mode: "0600"
notify: Restart vaultwarden
- name: Start vaultwarden
community.docker.docker_compose_v2:
project_src: "{{ vaultwarden_data_dir }}"
state: present
# ─── Cloudflare Origin Certificate ───────────────────────────────────────────
- name: Create SSL directory
file:
path: /etc/nginx/ssl
state: directory
owner: root
group: root
mode: "0700"
- name: Install Cloudflare origin certificate
copy:
content: "{{ cf_origin_cert }}"
dest: /etc/nginx/ssl/cf-origin.pem
owner: root
group: root
mode: "0600"
notify: Reload nginx
- name: Install Cloudflare origin key
copy:
content: "{{ cf_origin_key }}"
dest: /etc/nginx/ssl/cf-origin.key
owner: root
group: root
mode: "0600"
notify: Reload nginx
# ─── nginx ────────────────────────────────────────────────────────────────────
- name: Deploy nginx config
template:
src: nginx.conf.j2
dest: /etc/nginx/sites-available/vaultwarden
mode: "0644"
notify: Reload nginx
- name: Enable nginx site
file:
src: /etc/nginx/sites-available/vaultwarden
dest: /etc/nginx/sites-enabled/vaultwarden
state: link
notify: Reload nginx

View File

@@ -1,16 +0,0 @@
services:
vaultwarden:
image: vaultwarden/server:latest
container_name: vaultwarden
restart: unless-stopped
volumes:
- {{ vaultwarden_data_dir }}/data:/data
environment:
DOMAIN: "https://{{ vaultwarden_domain }}"
SIGNUPS_ALLOWED: "{{ vaultwarden_signups_allowed }}"
ADMIN_TOKEN: "{{ vaultwarden_admin_token }}"
{% if vaultwarden_database_url %}
DATABASE_URL: "{{ vaultwarden_database_url }}"
{% endif %}
ports:
- "127.0.0.1:{{ vaultwarden_port }}:80"

View File

@@ -1,27 +0,0 @@
server {
listen 80;
server_name {{ vaultwarden_domain }};
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
server_name {{ vaultwarden_domain }};
ssl_certificate /etc/nginx/ssl/cf-origin.pem;
ssl_certificate_key /etc/nginx/ssl/cf-origin.key;
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
# Required for Bitwarden web vault
client_max_body_size 525m;
location / {
proxy_pass http://127.0.0.1:{{ vaultwarden_port }};
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}

View File

@@ -1,4 +0,0 @@
.terraform/
terraform.tfvars
*.tfstate
*.tfstate.backup

View File

@@ -1,49 +0,0 @@
# This file is maintained automatically by "terraform init".
# Manual edits may be lost in future updates.
provider "registry.terraform.io/cloudflare/cloudflare" {
version = "4.52.7"
constraints = "~> 4.0"
hashes = [
"h1:pPItIWii5oymR+geZB219ROSPuSODPLTlM4S/u8xLvM=",
"zh:0c904ce31a4c6c4a5b3bf7ff1560e77c0cc7e2450c8553ded8e8c90398e1418b",
"zh:36183d310c36373fe4cb936b83c595c6fd3b0a94bc7827f28e5789ccbf59752e",
"zh:556a568a6f0235e8f41647de9e4d3a1e7b1d6502df8b19b54ec441f1c653ea10",
"zh:633ebbd5b0245e75e500ef9be4d9e62288f97e8da3baaa51323892a786d90285",
"zh:6acfe60cf52a65ba8f044f748548d2119e7f4fd7f8ebcb14698960d87c68f529",
"zh:890df766e9b839623b1f0437355032a3c006226a6c200cd911e15ee1a9014e9f",
"zh:904acc31ebb9d6ef68c792074b30532ee61bf515f19e0a3c75b46f126cca1f13",
"zh:a1d0a81246afc8750286d3f6fe7a8fbe6460dd2662407b28dbfbabb612e5fa9d",
"zh:a41a36fe253fc365fe2b7ffc749624688b2693b4634862fda161179ab100029f",
"zh:a7ef269e77ffa8715c8945a2c14322c7ff159ea44c15f62505f3cbb2cae3b32d",
"zh:b01aa3bed30610633b762df64332b26f8844a68c3960cebcb30f04918efc67fe",
"zh:b069cc2cd18cae10757df3ae030508eac8d55de7e49eda7a5e3e11f2f7fe6455",
"zh:b2d2c6313729ebb7465dceece374049e2d08bda34473901be9ff46a8836d42b2",
"zh:db0e114edaf4bc2f3d4769958807c83022bfbc619a00bdf4c4bd17faa4ab2d8b",
"zh:ecc0aa8b9044f664fd2aaf8fa992d976578f78478980555b4b8f6148e8d1a5fe",
]
}
provider "registry.terraform.io/digitalocean/digitalocean" {
version = "2.81.0"
constraints = "~> 2.0"
hashes = [
"h1:47cuHN8MQlnexcfUS5Toyvcg/9hk+EvHr2uNbfkmPfU=",
"zh:0a35eca6ee12b78f4a080b02f1f77b51159d919cfddc15aea0855b41d3632013",
"zh:0f871a3f513b789be86403c8b0568f86425fd3c4c3acb971f1f01c8ff165aafc",
"zh:5b15aa1cc7cbfdb12f2b97b7bd55f1e77dac844d7312919b9727ba11f4a92e56",
"zh:9be812992b0720161ec5f0518957a3b406728dbc31b437f0a336781eb6915714",
"zh:9f2bf1509893ebcc4659408c1aff4f7337646a0369863c6d762998ec8f025d0f",
"zh:a297f7c3d1192efb0f16ca5d9d5df4ac074f8d0f474b1c7d259884dd56998b26",
"zh:a81e51fead5aac3e060cbe58f1bb8e4bc32e030668bf6a0511496a4a2a8c60ee",
"zh:cc224fbe556281319cd2e525368b6c90b360e2ad1c58771eeb2dfd7ce2153ab9",
"zh:d40bc07848e8bbce99fe66a6da12d279cb91caedd0ec61c6948b57f2e076f359",
"zh:d470e974fb520fe2b462f15a44069915636cbbb937a80584414357b045c8b910",
"zh:db4c728d0f26bf24c4d4c0f8000de73f79ef35a16b96c3306b6bccb91abf4b16",
"zh:df02c98612152e31aac9d4d894134949608fa6d666da338ef76e4eec40be45c3",
"zh:e8f47d8cc609e53a290e73064bb6efb9d5ff576e8389e53919e140fbafff9f1c",
"zh:eb1942471dfb434ac96ed5c6e7d7360ed1e314b8c0fa9e4bbfb38c1f83b9f33e",
"zh:fc1f47533813c1abf7888fd8f84a15876d9f7acd62b6746de2db1ca6816bf1e9",
"zh:ff57bb5b47460e2c7cde320ad50851ca0ae3931d3ab21bfc2af0a8f1fb5cdd9c",
]
}

View File

@@ -1,152 +0,0 @@
terraform {
required_providers {
digitalocean = {
source = "digitalocean/digitalocean"
version = "~> 2.0"
}
cloudflare = {
source = "cloudflare/cloudflare"
version = "~> 4.0"
}
}
backend "s3" {
endpoints = {
s3 = "https://nyc3.digitaloceanspaces.com"
}
bucket = "lunarfront-infra"
key = "terraform/gitea.tfstate"
region = "us-east-1" # required by S3 backend, ignored by Spaces
skip_credentials_validation = true
skip_metadata_api_check = true
skip_region_validation = true
skip_requesting_account_id = true
force_path_style = true
}
}
provider "digitalocean" {
token = var.do_token
}
provider "cloudflare" {
api_token = var.cloudflare_api_token
}
# ─── Cloudflare zone lookup ───────────────────────────────────────────────────
data "cloudflare_zone" "main" {
name = var.domain
}
# ─── Droplet ──────────────────────────────────────────────────────────────────
data "digitalocean_ssh_key" "main" {
name = var.ssh_key_name
}
resource "digitalocean_droplet" "gitea" {
name = "gitea"
region = var.region
size = var.droplet_size
image = "ubuntu-24-04-x64"
ssh_keys = [data.digitalocean_ssh_key.main.id]
tags = ["infra", "gitea"]
}
# ─── Firewall ─────────────────────────────────────────────────────────────────
# Cloudflare IPv4 ranges — http://www.cloudflare.com/ips-v4
locals {
cloudflare_ipv4 = [
"173.245.48.0/20",
"103.21.244.0/22",
"103.22.200.0/22",
"103.31.4.0/22",
"141.101.64.0/18",
"108.162.192.0/18",
"190.93.240.0/20",
"188.114.96.0/20",
"197.234.240.0/22",
"198.41.128.0/17",
"162.158.0.0/15",
"104.16.0.0/13",
"104.24.0.0/14",
"172.64.0.0/13",
"131.0.72.0/22",
]
cloudflare_ipv6 = [
"2400:cb00::/32",
"2606:4700::/32",
"2803:f800::/32",
"2405:b500::/32",
"2405:8100::/32",
"2a06:98c0::/29",
"2c0f:f248::/32",
]
}
resource "digitalocean_firewall" "gitea" {
name = "gitea-firewall"
droplet_ids = [digitalocean_droplet.gitea.id]
# SSH — open to all (lock down to your IP if preferred)
inbound_rule {
protocol = "tcp"
port_range = "22"
source_addresses = ["0.0.0.0/0", "::/0"]
}
# HTTP/HTTPS — Cloudflare IPs only
inbound_rule {
protocol = "tcp"
port_range = "80"
source_addresses = concat(local.cloudflare_ipv4, local.cloudflare_ipv6)
}
inbound_rule {
protocol = "tcp"
port_range = "443"
source_addresses = concat(local.cloudflare_ipv4, local.cloudflare_ipv6)
}
# Gitea SSH for git push/pull — open to all
inbound_rule {
protocol = "tcp"
port_range = "2222"
source_addresses = ["0.0.0.0/0", "::/0"]
}
outbound_rule {
protocol = "tcp"
port_range = "1-65535"
destination_addresses = ["0.0.0.0/0", "::/0"]
}
outbound_rule {
protocol = "udp"
port_range = "1-65535"
destination_addresses = ["0.0.0.0/0", "::/0"]
}
}
# ─── DNS records ──────────────────────────────────────────────────────────────
resource "cloudflare_record" "gitea" {
zone_id = data.cloudflare_zone.main.id
name = "git"
type = "A"
value = digitalocean_droplet.gitea.ipv4_address
proxied = true
ttl = 1
}
resource "cloudflare_record" "vaultwarden" {
zone_id = data.cloudflare_zone.main.id
name = "vault"
type = "A"
value = digitalocean_droplet.gitea.ipv4_address
proxied = true
ttl = 1
}

View File

@@ -1,4 +0,0 @@
output "gitea_ip" {
description = "Public IP of the Gitea droplet"
value = digitalocean_droplet.gitea.ipv4_address
}

View File

@@ -1,6 +0,0 @@
do_token = "your-digitalocean-api-token"
ssh_key_name = "your-key-name-in-do"
region = "nyc3"
droplet_size = "s-1vcpu-2gb"
cloudflare_api_token = "your-cloudflare-api-token"
domain = "example.com"

View File

@@ -1,33 +0,0 @@
variable "do_token" {
description = "DigitalOcean API token"
type = string
sensitive = true
}
variable "ssh_key_name" {
description = "Name of the SSH key uploaded to DigitalOcean"
type = string
}
variable "region" {
description = "DigitalOcean region"
type = string
default = "nyc3"
}
variable "droplet_size" {
description = "Droplet size slug"
type = string
default = "s-1vcpu-2gb"
}
variable "cloudflare_api_token" {
description = "Cloudflare API token (needs Zone:DNS:Edit permission)"
type = string
sensitive = true
}
variable "domain" {
description = "Root domain managed in Cloudflare (e.g. example.com)"
type = string
}