Initial commit - realms platform

This commit is contained in:
doomtube 2026-01-06 00:26:54 -05:00
parent 2aa075e842
commit b3682b1936
12 changed files with 148 additions and 100 deletions

View file

@ -23,7 +23,7 @@ jobs:
# Build Backend (C++/Drogon) # Build Backend (C++/Drogon)
# =========================================================================== # ===========================================================================
build-backend: build-backend:
runs-on: docker runs-on: ubuntu-latest
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@v4 uses: actions/checkout@v4
@ -50,7 +50,7 @@ jobs:
# Build Frontend (SvelteKit) # Build Frontend (SvelteKit)
# =========================================================================== # ===========================================================================
build-frontend: build-frontend:
runs-on: docker runs-on: ubuntu-latest
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@v4 uses: actions/checkout@v4
@ -77,7 +77,7 @@ jobs:
# Build Chat Service # Build Chat Service
# =========================================================================== # ===========================================================================
build-chat: build-chat:
runs-on: docker runs-on: ubuntu-latest
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@v4 uses: actions/checkout@v4
@ -104,7 +104,7 @@ jobs:
# Build OpenResty (Nginx + Lua) # Build OpenResty (Nginx + Lua)
# =========================================================================== # ===========================================================================
build-openresty: build-openresty:
runs-on: docker runs-on: ubuntu-latest
steps: steps:
- name: Checkout code - name: Checkout code
uses: actions/checkout@v4 uses: actions/checkout@v4

View file

@ -22,7 +22,7 @@ jobs:
deploy: deploy:
# Only deploy if build succeeded OR manual trigger # Only deploy if build succeeded OR manual trigger
if: ${{ github.event.workflow_run.conclusion == 'success' || github.event_name == 'workflow_dispatch' }} if: ${{ github.event.workflow_run.conclusion == 'success' || github.event_name == 'workflow_dispatch' }}
runs-on: docker runs-on: ubuntu-latest
steps: steps:
- name: Checkout code - name: Checkout code

5
.gitignore vendored
View file

@ -122,6 +122,11 @@ secrets.json
.gnupg/ .gnupg/
backend/config.json backend/config.json
!backend/config.json.example !backend/config.json.example
terraform.tfvars
terraform.tfstate
terraform.tfstate.backup
.terraform/
.terraform.lock.hcl
# Temporary Files # Temporary Files
# ====================================================== # ======================================================

View file

@ -24,6 +24,12 @@ services:
interval: 10s interval: 10s
timeout: 5s timeout: 5s
retries: 5 retries: 5
deploy:
resources:
limits:
memory: 256M
reservations:
memory: 128M
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
# Forgejo Git Server # Forgejo Git Server
@ -105,6 +111,14 @@ services:
timeout: 10s timeout: 10s
retries: 3 retries: 3
start_period: 60s start_period: 60s
security_opt:
- no-new-privileges:true
deploy:
resources:
limits:
memory: 384M
reservations:
memory: 192M
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
# Caddy Reverse Proxy # Caddy Reverse Proxy
@ -128,6 +142,14 @@ services:
- forgejo-public - forgejo-public
environment: environment:
FORGEJO_DOMAIN: ${FORGEJO_DOMAIN} FORGEJO_DOMAIN: ${FORGEJO_DOMAIN}
security_opt:
- no-new-privileges:true
deploy:
resources:
limits:
memory: 64M
reservations:
memory: 32M
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
# Forgejo Actions Runner # Forgejo Actions Runner
@ -161,6 +183,12 @@ services:
fi fi
forgejo-runner daemon --config /data/config.yaml forgejo-runner daemon --config /data/config.yaml
' '
deploy:
resources:
limits:
memory: 256M
reservations:
memory: 128M
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
# Docker-in-Docker for Runner # Docker-in-Docker for Runner
@ -184,6 +212,8 @@ services:
resources: resources:
limits: limits:
memory: 512M memory: 512M
reservations:
memory: 256M
# ============================================================================= # =============================================================================
# Networks # Networks

View file

@ -379,16 +379,77 @@ write_files:
reservations: reservations:
memory: 32M memory: 32M
# Forgejo Actions Runner (CI/CD)
forgejo-runner:
image: code.forgejo.org/forgejo/runner:6.3.1
container_name: forgejo-runner
restart: unless-stopped
depends_on:
forgejo:
condition: service_healthy
docker-dind:
condition: service_started
environment:
DOCKER_HOST: tcp://docker-dind:2376
DOCKER_TLS_VERIFY: "1"
DOCKER_CERT_PATH: /certs/client
volumes:
- /mnt/forgejo/runner-data:/data
- dind-certs-client:/certs/client:ro
networks:
- forgejo-internal
- dind-network
command: >
sh -c '
if [ ! -f /data/.runner ]; then
echo "Runner not registered. Run: docker compose exec forgejo-runner forgejo-runner register"
sleep infinity
fi
forgejo-runner daemon --config /data/config.yaml
'
deploy:
resources:
limits:
memory: 256M
reservations:
memory: 128M
# Docker-in-Docker for Runner (builds images in CI/CD)
docker-dind:
image: docker:27-dind
container_name: forgejo-dind
restart: unless-stopped
privileged: true
environment:
DOCKER_TLS_CERTDIR: /certs
volumes:
- dind-certs-ca:/certs/ca
- dind-certs-client:/certs/client
- dind-storage:/var/lib/docker
networks:
- dind-network
deploy:
resources:
limits:
memory: 512M
reservations:
memory: 256M
networks: networks:
forgejo-internal: forgejo-internal:
driver: bridge driver: bridge
internal: true internal: true
forgejo-public: forgejo-public:
driver: bridge driver: bridge
dind-network:
driver: bridge
volumes: volumes:
caddy_data: caddy_data:
caddy_config: caddy_config:
dind-certs-ca:
dind-certs-client:
dind-storage:
permissions: '0644' permissions: '0644'
# Caddy Dockerfile with rate-limit plugin # Caddy Dockerfile with rate-limit plugin
@ -516,6 +577,15 @@ write_files:
| cd /opt/forgejo && docker compose logs -f | | cd /opt/forgejo && docker compose logs -f |
| cd /opt/forgejo && docker compose restart | | cd /opt/forgejo && docker compose restart |
| | | |
| Runner Registration: |
| 1. Get token from Forgejo: Site Admin > Actions > Runners |
| 2. Register runner: |
| cd /opt/forgejo && docker compose exec forgejo-runner \ |
| forgejo-runner register --instance https://${domain} |
| --token YOUR_TOKEN --name realms-runner |
| --labels ubuntu-latest,docker |
| 3. Restart: docker compose restart forgejo-runner |
| |
+---------------------------------------------------------------+ +---------------------------------------------------------------+
permissions: '0644' permissions: '0644'
@ -580,7 +650,7 @@ runcmd:
# Start Forgejo stack (build Caddy with rate-limit plugin, pull others) # Start Forgejo stack (build Caddy with rate-limit plugin, pull others)
- cd /opt/forgejo && docker compose build caddy - cd /opt/forgejo && docker compose build caddy
- cd /opt/forgejo && docker compose pull forgejo forgejo-db - cd /opt/forgejo && docker compose pull forgejo forgejo-db forgejo-runner docker-dind
- cd /opt/forgejo && docker compose up -d - cd /opt/forgejo && docker compose up -d
# Enable unattended upgrades # Enable unattended upgrades

View file

@ -1,76 +0,0 @@
# =============================================================================
# DigitalOcean Terraform Configuration
# =============================================================================
# Copy this file to terraform.tfvars and fill in your values
# NEVER commit terraform.tfvars to version control!
#
# Set the DO token via environment variable:
# export TF_VAR_do_token="dop_v1_your_token_here"
# =============================================================================
# =============================================================================
# Project Configuration
# =============================================================================
project_name = "realms"
environment = "production"
region = "nyc3"
# =============================================================================
# VPC Configuration
# =============================================================================
vpc_ip_range = "10.10.0.0/16"
# =============================================================================
# SSH Configuration
# =============================================================================
# Add your admin SSH public key(s) here
# Generate with: ssh-keygen -t ed25519 -C "your_email@example.com"
admin_ssh_public_keys = {
# "admin-name" = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAINlczdk2KKjY2CyYV1Ql8enjRn8gpBBgSLmbbCUyG5Qs admin@doom.tube"
}
# SSH ports (non-standard for security)
jump_host_ssh_port = 49822 # Jump host public SSH
forgejo_ssh_port = 52913 # Forgejo system SSH (VPC only)
forgejo_git_ssh_port = 2222 # Forgejo Git SSH (public)
# =============================================================================
# Jump Host Configuration
# =============================================================================
jump_host_size = "s-1vcpu-512mb-10gb" # $4/mo
jump_host_image = "debian-12-x64"
# =============================================================================
# Forgejo Configuration
# =============================================================================
forgejo_droplet_size = "s-1vcpu-1gb-intel" # $7/mo - 1GB RAM, 1 Intel vCPU
forgejo_droplet_image = "debian-12-x64"
forgejo_volume_size = 50 # GB for repositories and LFS
forgejo_domain = "qbit.realms.pub"
# =============================================================================
# DNS Configuration (requires domain to be managed by DigitalOcean)
# =============================================================================
# Set to true to automatically create/update A record for Forgejo
manage_dns = true
# Base domain managed by DigitalOcean DNS
dns_zone = "realms.pub"
# =============================================================================
# Backup Configuration
# =============================================================================
enable_droplet_backups = true
# =============================================================================
# Additional Tags
# =============================================================================
tags = []

View file

@ -94,9 +94,9 @@ variable "jump_host_image" {
# ============================================================================= # =============================================================================
variable "forgejo_droplet_size" { variable "forgejo_droplet_size" {
description = "Size slug for the Forgejo droplet" description = "Size slug for the Forgejo droplet (2GB+ recommended for Actions Runner)"
type = string type = string
default = "s-1vcpu-1gb-intel" default = "s-2vcpu-2gb-intel"
} }
variable "forgejo_droplet_image" { variable "forgejo_droplet_image" {

View file

@ -16,11 +16,19 @@ locals {
# SSH Keys # SSH Keys
# ============================================================================= # =============================================================================
resource "digitalocean_ssh_key" "admin" { # Get all SSH keys on account
for_each = var.admin_ssh_public_keys data "digitalocean_ssh_keys" "all" {}
name = "${var.project_name}-app-${var.environment}-${each.key}" # Find the internal VPC key (created by devops/terraform for jump host access)
public_key = each.value locals {
internal_key_name = "${var.project_name}-${var.environment}-internal-key"
internal_key_ids = [for k in data.digitalocean_ssh_keys.all.ssh_keys : k.id if k.name == local.internal_key_name]
# Combine: internal key (for jump host) + all admin keys
all_ssh_key_ids = distinct(concat(
local.internal_key_ids,
[for k in data.digitalocean_ssh_keys.all.ssh_keys : k.id]
))
} }
# ============================================================================= # =============================================================================
@ -35,7 +43,7 @@ module "app_server" {
region = var.region region = var.region
vpc_uuid = var.vpc_uuid vpc_uuid = var.vpc_uuid
vpc_ip_range = var.vpc_ip_range vpc_ip_range = var.vpc_ip_range
ssh_keys = [for key in digitalocean_ssh_key.admin : key.id] ssh_keys = local.all_ssh_key_ids
droplet_size = var.app_droplet_size droplet_size = var.app_droplet_size
droplet_image = var.app_droplet_image droplet_image = var.app_droplet_image
ssh_port = var.app_ssh_port ssh_port = var.app_ssh_port
@ -44,5 +52,6 @@ module "app_server" {
tags = local.common_tags tags = local.common_tags
manage_dns = var.manage_dns manage_dns = var.manage_dns
dns_zone = var.dns_zone dns_zone = var.dns_zone
dns_record_name = var.dns_record_name
forgejo_registry = var.forgejo_registry forgejo_registry = var.forgejo_registry
} }

View file

@ -180,17 +180,7 @@ resource "digitalocean_record" "app" {
domain = var.dns_zone domain = var.dns_zone
type = "A" type = "A"
name = "@" name = var.dns_record_name
value = digitalocean_droplet.app.ipv4_address
ttl = 600
}
resource "digitalocean_record" "app_www" {
count = var.manage_dns ? 1 : 0
domain = var.dns_zone
type = "A"
name = "www"
value = digitalocean_droplet.app.ipv4_address value = digitalocean_droplet.app.ipv4_address
ttl = 600 ttl = 600
} }

View file

@ -84,6 +84,12 @@ variable "dns_zone" {
default = "realms.pub" default = "realms.pub"
} }
variable "dns_record_name" {
description = "DNS record name (subdomain). Use '@' for root or 'beeta' for beeta.realms.pub"
type = string
default = "beeta"
}
# ============================================================================= # =============================================================================
# Forgejo Registry # Forgejo Registry
# ============================================================================= # =============================================================================

View file

@ -0,0 +1,8 @@
terraform {
required_providers {
digitalocean = {
source = "digitalocean/digitalocean"
version = "~> 2.34"
}
}
}

View file

@ -104,6 +104,12 @@ variable "dns_zone" {
default = "realms.pub" default = "realms.pub"
} }
variable "dns_record_name" {
description = "DNS record name (subdomain). Use '@' for root or 'beeta' for beeta.realms.pub"
type = string
default = "beeta"
}
# ============================================================================= # =============================================================================
# Backup Configuration # Backup Configuration
# ============================================================================= # =============================================================================