From ed88b47f4acbbc7c84e2d323d0c329d989063220 Mon Sep 17 00:00:00 2001 From: Michael Czechowski Date: Mon, 11 Aug 2025 19:56:19 +0200 Subject: [PATCH] merge flake files --- Makefile | 81 +++-- {terraform => cloud}/cloud-init.yml | 33 ++ {terraform => cloud}/main.tf | 0 docs/USB_BOOT_INSTRUCTIONS.md | 531 +++++++++++++++++++++++++++- flake.lock | 78 ++++ flake.nix | 115 +++--- local/flake.lock | 27 ++ local/flake.nix | 151 ++++++-- usb/flake.nix | 183 ---------- 9 files changed, 909 insertions(+), 290 deletions(-) rename {terraform => cloud}/cloud-init.yml (50%) rename {terraform => cloud}/main.tf (100%) create mode 100644 flake.lock create mode 100644 local/flake.lock delete mode 100644 usb/flake.nix diff --git a/Makefile b/Makefile index 0d7901b..545529d 100644 --- a/Makefile +++ b/Makefile @@ -2,7 +2,7 @@ -include .env export -.PHONY: help deploy-cloud build-usb flash-usb local-shell local-deploy local-ssh clean status +.PHONY: help cloud-deploy cloud-status cloud-destroy usb-build usb-flash local-dev-shell local-deploy local-ssh local-clean clean DOMAIN := $(or $(WORKSHOP_DOMAIN),codecrispi.es) USB_DEVICE := /dev/sdX @@ -10,44 +10,29 @@ USB_DEVICE := /dev/sdX help: @echo "๐Ÿช CODE CRISPIES Workshop" @echo "" - @echo "Config: WiFi=$(or $(WORKSHOP_WIFI_SSID),CODE_CRISPIES_GUEST), Domain=$(DOMAIN)" + @echo "Usage: make " @echo "" - @echo "Cloud Infrastructure:" - @echo " make deploy-cloud - Deploy VMs to Hetzner (with health checks)" - @echo " make status-cloud - Check cloud server status" - @echo " make destroy-cloud - Destroy cloud infrastructure" + @echo "Cloud Commands:" + @echo " cloud-deploy - Deploy VMs to Hetzner and run health checks" + @echo " cloud-status - Check the status of cloud servers" + @echo " cloud-destroy - Destroy all cloud infrastructure" @echo "" - @echo "USB Boot Drive:" - @echo " make build-usb - Build NixOS ISO" - @echo " make flash-usb - Flash ISO to USB (set USB_DEVICE=/dev/sdX)" + @echo "USB Drive Commands:" + @echo " usb-build - Build the NixOS ISO for the workshop" + @echo " usb-flash - Flash the ISO to a USB drive (set USB_DEVICE)" @echo "" - @echo "Local Development:" - @echo " make local-shell - Enter dev shell" + @echo "Local Development Commands:" + @echo " local-dev-shell - Enter the development shell with all tools" + @echo " local-deploy - Deploy local NixOS containers for testing" + @echo " local-ssh - SSH into a local participant container" + @echo " local-clean - Stop and destroy all local containers" -build-usb: - @echo "๐Ÿ”จ Building NixOS workshop ISO..." - @echo "๐Ÿ“ Config: WiFi=$(or $(WORKSHOP_WIFI_SSID),CODE_CRISPIES_GUEST), Domain=$(DOMAIN)" - nix build .#live-iso - @echo "โœ… ISO built: result/iso/nixos.iso" - -flash-usb: build-usb - @echo "โš ๏ธ Flashing to ${USB_DEVICE} - THIS WILL ERASE THE DEVICE!" - @read -p "Continue? [y/N]: " confirm && [ "$$confirm" = "y" ] - sudo dd if=result/iso/nixos.iso of=${USB_DEVICE} bs=4M status=progress oflag=sync - @echo "โœ… USB drive ready!" - -deploy-cloud: +# --- Cloud Infrastructure --- +cloud-deploy: @echo "๐Ÿš€ Deploying to Hetzner Cloud..." - cd terraform && terraform init - cd terraform && terraform apply -auto-approve \ - -var="hcloud_token=${HCLOUD_TOKEN}" \ - -var="domain=${DOMAIN}" \ - -var="ssh_public_key=$$(cat ~/.ssh/id_rsa.pub)" - @echo "๐Ÿ” Running health checks..." ./scripts/deploy.sh - @echo "โœ… Cloud deployment complete and verified!" -status-cloud: +cloud-status: @echo "๐Ÿ“Š Checking server status..." @for name in hopper curie lovelace noether hamilton franklin johnson clarke goldberg liskov wing rosen shaw karp rich; do \ echo -n "$$name.${DOMAIN}: "; \ @@ -58,11 +43,37 @@ status-cloud: fi; \ done -destroy-cloud: - cd terraform && terraform destroy -auto-approve +cloud-destroy: + cd cloud && terraform destroy -auto-approve -local-shell: +# --- USB Boot Drive --- +usb-build: + @echo "๐Ÿ”จ Building NixOS workshop ISO..." + nix build .#packages.x86_64-linux.live-iso + @echo "โœ… ISO built: result/iso/nixos.iso" + +usb-flash: usb-build + @echo "โš ๏ธ Flashing to ${USB_DEVICE} - THIS WILL ERASE THE DEVICE!" + @read -p "Continue? [y/N]: " confirm && [ "$$confirm" = "y" ] + sudo dd if=result/iso/nixos.iso of=${USB_DEVICE} bs=4M status=progress oflag=sync + @echo "โœ… USB drive ready!" + +# --- Local Development --- +local-dev-shell: nix develop +local-deploy: + @echo "๐Ÿ  Deploying local workshop environment..." + sudo nixos-rebuild switch --flake .#workshop-local + @echo "โœ… Local containers running!" + +local-ssh: + @read -p "Connect to participant number [1-15]: " num; \ + ssh root@192.168.100.$$((10 + $$num)) + +local-clean: + sudo nixos-container stop participant{1..15} || true + sudo nixos-container destroy participant{1..15} || true + clean: rm -rf result .direnv diff --git a/terraform/cloud-init.yml b/cloud/cloud-init.yml similarity index 50% rename from terraform/cloud-init.yml rename to cloud/cloud-init.yml index dd8c5b5..d72bde7 100644 --- a/terraform/cloud-init.yml +++ b/cloud/cloud-init.yml @@ -13,6 +13,39 @@ packages: - git - jq +runcmd: + # Setup Docker Swarm + - systemctl enable docker + - systemctl start docker + - usermod -aG docker workshop + - docker swarm init + - docker network create -d overlay proxy + + # Install abra + - curl -fsSL https://install.abra.coopcloud.tech | bash + - mv /root/.local/bin/abra /usr/local/bin/ + - chmod +x /usr/local/bin/abra + + # Pre-configure abra server for this participant + - sudo -u workshop mkdir -p /home/workshop/.abra/servers + - sudo -u workshop abra server add ${participant_name}.${domain} + + # Pre-setup Traefik + - sudo -u workshop abra app new traefik --domain=traefik.${participant_name}.${domain} --server=${participant_name}.${domain}#cloud-config +users: + - name: workshop + groups: [adm, docker] + sudo: ['ALL=(ALL) NOPASSWD:ALL'] + shell: /bin/bash + ssh_authorized_keys: + - ${ssh_public_key} + +packages: + - docker.io + - curl + - git + - jq + runcmd: # Setup Docker Swarm - systemctl enable docker diff --git a/terraform/main.tf b/cloud/main.tf similarity index 100% rename from terraform/main.tf rename to cloud/main.tf diff --git a/docs/USB_BOOT_INSTRUCTIONS.md b/docs/USB_BOOT_INSTRUCTIONS.md index 4801951..c4e3634 100644 --- a/docs/USB_BOOT_INSTRUCTIONS.md +++ b/docs/USB_BOOT_INSTRUCTIONS.md @@ -3,7 +3,7 @@ ### ๐Ÿ“‹ Quick Reference Card -**Your assigned server:** `__________.codecrispies.es` +**Your assigned server:** `__________.codecrispi.es` **Workshop WiFi:** `CODE_CRISPIES_GUEST` / Password: `workshop2024` --- @@ -119,3 +119,532 @@ Name: Android, Password: (ask facilitator) โŒ **Can't connect to internet** โ†’ Try different WiFi network โ†’ Use mobile hotspot as backup +``` + +## flake.nix +```nix +{ + description = "CODE CRISPIES Workshop Live Environment"; + + inputs = { + nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; + nixos-generators.url = "github:nix-community/nixos-generators"; + }; + + outputs = { self, nixpkgs, nixos-generators }: + let + system = "x86_64-linux"; + participantNames = [ + "hopper" "curie" "lovelace" "noether" "hamilton" + "franklin" "johnson" "clarke" "goldberg" "liskov" + "wing" "rosen" "shaw" "karp" "rich" + ]; + in { + packages.${system}.live-iso = nixos-generators.nixosGenerate { + inherit system; + format = "iso"; + + modules = [ + ({ pkgs, ... }: { + # WiFi support + networking.wireless.enable = true; + networking.networkmanager.enable = true; + networking.wireless.networks = { + "CODE_CRISPIES_GUEST" = { + psk = "workshop2024"; + }; + }; + + # Auto-connect to workshop WiFi + systemd.services.workshop-wifi = { + wantedBy = [ "multi-user.target" ]; + after = [ "network.target" ]; + script = '' + ${pkgs.networkmanager}/bin/nmcli dev wifi connect "CODE_CRISPIES_GUEST" password "workshop2024" || true + ''; + }; + + # Auto-login workshop user + services.getty.autologinUser = "workshop"; + users.users.workshop = { + isNormalUser = true; + shell = pkgs.zsh; + }; + + # Workshop shell environment + programs.zsh = { + enable = true; + interactiveShellInit = '' + echo "๐Ÿช CODE CRISPIES Workshop Environment" + echo "๐Ÿ“ถ WiFi: CODE_CRISPIES_GUEST (auto-connecting...)" + echo "๐Ÿ“ก Available servers:" + ${builtins.concatStringsSep "\n" (map (name: + "echo \" - ${name}.codecrispi.es\"" + ) participantNames)} + echo "" + echo "๐Ÿ’ก Commands: connect | recipes | help" + + connect() { + [ -z "$1" ] && { echo "Usage: connect "; return 1; } + echo "๐Ÿ”— Connecting to $1.codecrispi.es..." + ssh -o StrictHostKeyChecking=no workshop@$1.codecrispi.es + } + + recipes() { + echo "๐Ÿช Featured Co-op Cloud Recipes:" + echo "" + echo "๐Ÿ“ Content Management:" + echo " wordpress ghost hedgedoc dokuwiki mediawiki" + echo "" + echo "โ˜๏ธ File & Collaboration:" + echo " nextcloud seafile collabora onlyoffice" + echo "" + echo "๐Ÿ’ฌ Communication:" + echo " jitsi-meet matrix-synapse rocketchat mattermost" + echo "" + echo "๐Ÿ›’ E-commerce & Business:" + echo " prestashop invoiceninja kimai pretix" + echo "" + echo "๐Ÿ”ง Development & Tools:" + echo " gitea drone n8n gitlab jupyter-lab" + echo "" + echo "๐Ÿ“Š Analytics & Monitoring:" + echo " plausible matomo uptime-kuma grafana" + echo "" + echo "๐ŸŽต Media & Social:" + echo " peertube funkwhale mastodon pixelfed jellyfin" + echo "" + echo "Deploy: abra app new -S --domain=myapp..codecrispi.es" + echo "Browse all 100+ recipes: https://recipes.coopcloud.tech" + } + + help() { + echo "๐Ÿช CODE CRISPIES Workshop Commands:" + echo "" + echo "connect - SSH to your assigned server" + echo "recipes - Show available app recipes" + echo "abra app new -S --domain=..codecrispi.es" + echo "abra app deploy " + echo "abra app ls - List your apps" + echo "" + echo "Examples:" + echo " connect hopper" + echo " abra app new wordpress -S --domain=blog.hopper.codecrispi.es" + echo " abra app deploy blog.hopper.codecrispi.es" + } + ''; + }; + + environment.systemPackages = with pkgs; [ openssh curl git networkmanager ]; + + # Auto-start terminal + services.xserver = { + enable = true; + displayManager = { + autoLogin.enable = true; + autoLogin.user = "workshop"; + sessionCommands = "${pkgs.xterm}/bin/xterm &"; + }; + }; + }) + ]; + }; + + # Dev shell for local testing + devShells.${system}.default = nixpkgs.legacyPackages.${system}.mkShell { + buildInputs = with nixpkgs.legacyPackages.${system}; [ + terraform + nixos-rebuild + docker + openssh + ]; + }; + }; +} +``` + +## local/flake.nix +```nix +{ + description = "Local Co-op Cloud Testing"; + + inputs.nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; + + outputs = { self, nixpkgs }: { + nixosConfigurations.workshop-local = nixpkgs.lib.nixosSystem { + system = "x86_64-linux"; + modules = [ + { + containers = builtins.listToAttrs (map (i: + let participant = builtins.elemAt [ + "hopper" "curie" "lovelace" "noether" "hamilton" + "franklin" "johnson" "clarke" "goldberg" "liskov" + "wing" "rosen" "shaw" "karp" "rich" + ] (i - 1); + in { + name = "participant${toString i}"; + value = { + autoStart = true; + privateNetwork = true; + hostAddress = "192.168.100.1"; + localAddress = "192.168.100.${toString (10 + i)}"; + + config = { pkgs, ... }: { + virtualisation.docker = { + enable = true; + extraOptions = "--experimental"; + }; + + environment.systemPackages = with pkgs; [ + docker git curl wget tar jq + ]; + + # Helper script for workshop commands + environment.etc."workshop-helpers.sh" = { + text = '' + #!/bin/bash + + connect() { + case "$1" in + hopper|curie|lovelace|noether|hamilton|franklin|johnson|clarke|goldberg|liskov|wing|rosen|shaw|karp|rich) + echo "๐Ÿ”— Connecting to $1.codecrispi.es..." + ssh -o StrictHostKeyChecking=no workshop@$1.codecrispi.es + ;; + *) + echo "Available servers:" + echo " hopper curie lovelace noether hamilton franklin johnson" + echo " clarke goldberg liskov wing rosen shaw karp rich" + ;; + esac + } + + recipes() { + echo "๐Ÿช Available Co-op Cloud Recipes:" + echo "" + echo "๐Ÿ“ Content Management:" + echo " wordpress - Blog/CMS platform" + echo " ghost - Publishing platform" + echo " hedgedoc - Collaborative markdown editor" + echo " dokuwiki - Simple textfile based wiki" + echo " mediawiki - The wiki software that runs Wikipedia" + echo "" + echo "โ˜๏ธ File & Collaboration:" + echo " nextcloud - File sync & collaboration" + echo " seafile - File hosting platform" + echo " collabora - Online Office suite" + echo " onlyoffice - Online office suite" + echo "" + echo "๐Ÿ’ฌ Communication:" + echo " jitsi-meet - Video conferencing" + echo " matrix-synapse - Chat server" + echo " rocketchat - Team communication" + echo " mattermost - Team collaboration platform" + echo "" + echo "๐Ÿ›’ E-commerce & Business:" + echo " prestashop - E-commerce platform" + echo " invoiceninja - Invoice & billing" + echo " kimai - Time tracking" + echo " pretix - Event ticketing" + echo "" + echo "๐Ÿ”ง Development & Tools:" + echo " gitea - Git repository hosting" + echo " drone - CI/CD platform" + echo " n8n - Workflow automation" + echo " gitlab - DevOps platform" + echo " jupyter-lab - Interactive computing" + echo "" + echo "๐Ÿ“Š Analytics & Monitoring:" + echo " plausible - Privacy-friendly analytics" + echo " matomo - Web analytics" + echo " uptime-kuma - Status monitoring" + echo " grafana - Observability platform" + echo "" + echo "๐ŸŽต Media & Social:" + echo " peertube - Video platform" + echo " funkwhale - Music platform" + echo " mastodon - Social networking" + echo " pixelfed - Photo sharing" + echo " jellyfin - Media system" + echo "" + echo "Usage: abra app new -S --domain=myapp.${participant}.local" + echo "Browse all 100+ recipes: https://recipes.coopcloud.tech" + } + + help() { + echo "๐Ÿช CODE CRISPIES Workshop Commands:" + echo "" + echo "connect - SSH to cloud server" + echo "recipes - Show available app recipes" + echo "abra app new -S --domain=.${participant}.local" + echo "abra app deploy " + echo "abra app ls - List your apps" + echo "" + echo "Examples:" + echo " connect hopper" + echo " abra app new wordpress -S --domain=blog.${participant}.local" + echo " abra app deploy blog.${participant}.local" + echo "" + echo "Server: ${participant}.local" + echo "Your apps will be available at: https://.${participant}.local" + } + + export -f connect recipes help + ''; + mode = "0755"; + }; + + systemd.services.workshop-setup = { + wantedBy = [ "multi-user.target" ]; + after = [ "docker.service" "network-online.target" ]; + wants = [ "network-online.target" ]; + script = '' + # Wait for network interface + until ip addr show | grep -q "192.168.100.${toString (10 + i)}"; do + sleep 1 + done + + # Install abra + export HOME=/root + ${pkgs.curl}/bin/curl -fsSL https://install.abra.coopcloud.tech | ${pkgs.bash}/bin/bash + + # Docker swarm setup + ${pkgs.docker}/bin/docker swarm init --advertise-addr 192.168.100.${toString (10 + i)} || true + ${pkgs.docker}/bin/docker network create -d overlay proxy || true + + # Abra server setup + mkdir -p /root/.abra/servers + /root/.local/bin/abra server add ${participant}.local + + # Setup helper commands in bash profile + echo "source /etc/workshop-helpers.sh" >> /root/.bashrc + ''; + serviceConfig = { + Type = "oneshot"; + RemainAfterExit = true; + }; + }; + + services.openssh.enable = true; + networking = { + firewall.allowedTCPPorts = [ 22 80 443 ]; + hostName = "${participant}.local"; + }; + }; + }; + } + ) (nixpkgs.lib.range 1 15)); + + # Wildcard DNS for all participant subdomains + services.dnsmasq = { + enable = true; + settings.address = builtins.concatMap (i: + let participant = builtins.elemAt [ + "hopper" "curie" "lovelace" "noether" "hamilton" + "franklin" "johnson" "clarke" "goldberg" "liskov" + "wing" "rosen" "shaw" "karp" "rich" + ] (i - 1); + in [ + "/${participant}.local/192.168.100.${toString (10 + i)}" + "/.${participant}.local/192.168.100.${toString (10 + i)}" + ] + ) (nixpkgs.lib.range 1 15); + }; + } + ]; + }; + }; +} +``` + +## Makefile +```make +# Load .env file if it exists +-include .env +export + +.PHONY: help deploy-cloud build-usb flash-usb local-shell local-deploy local-ssh clean status + +DOMAIN := $(or $(WORKSHOP_DOMAIN),codecrispi.es) +USB_DEVICE := /dev/sdX + +help: + @echo "๐Ÿช CODE CRISPIES Workshop" + @echo "" + @echo "Config: WiFi=$(or $(WORKSHOP_WIFI_SSID),CODE_CRISPIES_GUEST), Domain=$(DOMAIN)" + @echo "" + @echo "Cloud Infrastructure:" + @echo " make deploy-cloud - Deploy VMs to Hetzner (with health checks)" + @echo " make status-cloud - Check cloud server status" + @echo " make destroy-cloud - Destroy cloud infrastructure" + @echo "" + @echo "USB Boot Drive:" + @echo " make build-usb - Build NixOS ISO" + @echo " make flash-usb - Flash ISO to USB (set USB_DEVICE=/dev/sdX)" + @echo "" + @echo "Local Development:" + @echo " make local-shell - Enter dev shell" + @echo " make local-deploy - Deploy local NixOS containers" + @echo " make local-ssh - SSH into local participant container" + @echo " make local-clean - Stop local containers" + +build-usb: + @echo "๐Ÿ”จ Building NixOS workshop ISO..." + @echo "๐Ÿ“ Config: WiFi=$(or $(WORKSHOP_WIFI_SSID),CODE_CRISPIES_GUEST), Domain=$(DOMAIN)" + nix build .#live-iso + @echo "โœ… ISO built: result/iso/nixos.iso" + +flash-usb: build-usb + @echo "โš ๏ธ Flashing to ${USB_DEVICE} - THIS WILL ERASE THE DEVICE!" + @read -p "Continue? [y/N]: " confirm && [ "$$confirm" = "y" ] + sudo dd if=result/iso/nixos.iso of=${USB_DEVICE} bs=4M status=progress oflag=sync + @echo "โœ… USB drive ready!" + +deploy-cloud: + @echo "๐Ÿš€ Deploying to Hetzner Cloud..." + cd terraform && terraform init + cd terraform && terraform apply -auto-approve \ + -var="hcloud_token=${HCLOUD_TOKEN}" \ + -var="domain=${DOMAIN}" \ + -var="ssh_public_key=$$(cat ~/.ssh/id_rsa.pub)" + @echo "๐Ÿ” Running health checks..." + ./scripts/deploy.sh + @echo "โœ… Cloud deployment complete and verified!" + +status-cloud: + @echo "๐Ÿ“Š Checking server status..." + @for name in hopper curie lovelace noether hamilton franklin johnson clarke goldberg liskov wing rosen shaw karp rich; do \ + echo -n "$$name.${DOMAIN}: "; \ + if curl -s -f https://traefik.$$name.${DOMAIN}/ping >/dev/null 2>&1; then \ + echo "โœ… Ready"; \ + else \ + echo "โŒ Not ready"; \ + fi; \ + done + +destroy-cloud: + cd terraform && terraform destroy -auto-approve + +local-shell: + nix develop + +local-deploy: + @echo "๐Ÿ  Deploying local workshop environment..." + sudo nixos-rebuild switch --flake ./local#workshop-local + @echo "โœ… Local containers running!" + @echo "Available: participant1.local through participant15.local" + +local-ssh: + @echo "Available local participants:" + @echo " participant1.local (192.168.100.11)" + @echo " participant2.local (192.168.100.12)" + @echo " ... through participant15.local" + @read -p "Connect to participant number [1-15]: " num; \ + ssh root@192.168.100.$$((10 + $$num)) + +local-clean: + sudo nixos-container stop participant{1..15} || true + sudo nixos-container destroy participant{1..15} || true + +clean: + rm -rf result .direnv +``` + +## README.md +```markdown +# ๐Ÿช CODE CRISPIES Workshop Infrastructure + +Three deployment environments for Co-op Cloud workshop: + +## ๐Ÿš€ Quick Start + +```bash +# 1. Build & flash USB drives +make build-usb +make flash-usb USB_DEVICE=/dev/sdX + +# 2. Deploy cloud infrastructure +export HCLOUD_TOKEN=your_token +make deploy-cloud + +# 3. Local development +make local-shell +make local-deploy +make local-ssh +``` + +## ๐Ÿ“ Project Structure + +``` +โ”œโ”€โ”€ flake.nix # USB boot environment +โ”œโ”€โ”€ local/flake.nix # Local NixOS containers +โ”œโ”€โ”€ terraform/ # Hetzner Cloud infrastructure +โ”œโ”€โ”€ scripts/deploy.sh # Cloud setup automation +โ”œโ”€โ”€ docs/USB_BOOT_INSTRUCTIONS.md +โ””โ”€โ”€ Makefile # Build & deploy commands +``` + +## ๐ŸŒ Three Environments + +### 1. Cloud (Production) +- Hetzner VMs: `hopper.codecrispi.es`, `curie.codecrispi.es`, etc. +- Pre-configured with Docker Swarm + abra +- SSL certificates via Let's Encrypt + +### 2. USB Boot (Workshop) +- NixOS live environment +- Auto-connects to workshop WiFi +- Helper functions: `connect hopper`, `recipes`, `help` +- SSH into cloud VMs + +### 3. Local (Development) +- NixOS containers: `participant1.local` through `participant15.local` +- Test abra deployments locally +- Isolated Docker Swarm per container + +## ๐Ÿ”ง Development Workflow + +```bash +# Enter development environment +make local-shell + +# Deploy local testing environment +make local-deploy + +# SSH into local participant container +make local-ssh # Select participant 1-15 + +# Test app deployment inside container +abra app new wordpress -S --domain=test.participant1.local +abra app deploy test.participant1.local +``` + +## ๐Ÿ“ฆ Workshop Flow + +1. **Participant boots USB** โ†’ NixOS live environment +2. **Connects to WiFi** โ†’ `CODE_CRISPIES_GUEST` +3. **SSH to cloud VM** โ†’ `connect hopper` +4. **Deploy apps** โ†’ `abra app new wordpress -S --domain=mysite.hopper.codecrispi.es` +5. **Access via browser** โ†’ `https://mysite.hopper.codecrispi.es` + +## ๐ŸŽฏ Available Apps + +### Featured Recipes +- **WordPress** - Blog/CMS platform +- **Nextcloud** - File sync & collaboration +- **HedgeDoc** - Collaborative markdown editor +- **Jitsi** - Video conferencing +- **PrestaShop** - E-commerce platform +- **Gitea** - Git repository hosting +- **Matrix Synapse** - Chat server +- **Plausible** - Privacy-friendly analytics +- **PeerTube** - Video platform +- **Mastodon** - Social networking + +Browse all 100+ recipes at: https://recipes.coopcloud.tech + +## ๐Ÿงน Cleanup + +```bash +make clean # Clean local artifacts +make destroy-cloud # Destroy Hetzner infrastructure +``` diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..14b879e --- /dev/null +++ b/flake.lock @@ -0,0 +1,78 @@ +{ + "nodes": { + "nixlib": { + "locked": { + "lastModified": 1736643958, + "narHash": "sha256-tmpqTSWVRJVhpvfSN9KXBvKEXplrwKnSZNAoNPf/S/s=", + "owner": "nix-community", + "repo": "nixpkgs.lib", + "rev": "1418bc28a52126761c02dd3d89b2d8ca0f521181", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "nixpkgs.lib", + "type": "github" + } + }, + "nixos-generators": { + "inputs": { + "nixlib": "nixlib", + "nixpkgs": "nixpkgs" + }, + "locked": { + "lastModified": 1751903740, + "narHash": "sha256-PeSkNMvkpEvts+9DjFiop1iT2JuBpyknmBUs0Un0a4I=", + "owner": "nix-community", + "repo": "nixos-generators", + "rev": "032decf9db65efed428afd2fa39d80f7089085eb", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "nixos-generators", + "type": "github" + } + }, + "nixpkgs": { + "locked": { + "lastModified": 1736657626, + "narHash": "sha256-FWlPMUzp0lkQBdhKlPqtQdqmp+/C+1MBiEytaYfrCTY=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "2f9e2f85cb14a46410a1399aa9ea7ecf433e422e", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixpkgs-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs_2": { + "locked": { + "lastModified": 1754725699, + "narHash": "sha256-iAcj9T/Y+3DBy2J0N+yF9XQQQ8IEb5swLFzs23CdP88=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "85dbfc7aaf52ecb755f87e577ddbe6dbbdbc1054", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "nixos-generators": "nixos-generators", + "nixpkgs": "nixpkgs_2" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix index 55c0dd5..9f8036d 100644 --- a/flake.nix +++ b/flake.nix @@ -1,36 +1,32 @@ { - description = "CODE CRISPIES Workshop Live Environment"; - + description = "CODE CRISPIES Workshop Environment"; + inputs = { nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; nixos-generators.url = "github:nix-community/nixos-generators"; }; - outputs = { self, nixpkgs, nixos-generators }: + outputs = { self, nixpkgs, nixos-generators }: let system = "x86_64-linux"; - participantNames = [ - "hopper" "curie" "lovelace" "noether" "hamilton" - "franklin" "johnson" "clarke" "goldberg" "liskov" - "wing" "rosen" "shaw" "karp" "rich" + participantNames = [ + "hopper" "curie" "lovelace" "noether" "hamilton" + "franklin" "johnson" "clarke" "goldberg" "liskov" + "wing" "rosen" "shaw" "karp" "rich" ]; - in { + in + { + # -------------------------------------------------------------------------------- + # 1. USB BOOT DRIVE (ISO) + # `nix build .#live-iso` + # -------------------------------------------------------------------------------- packages.${system}.live-iso = nixos-generators.nixosGenerate { inherit system; format = "iso"; - modules = [ ({ pkgs, ... }: { - # WiFi support - networking.wireless.enable = true; + # WiFi and NetworkManager networking.networkmanager.enable = true; - networking.wireless.networks = { - "CODE_CRISPIES_GUEST" = { - psk = "workshop2024"; - }; - }; - - # Auto-connect to workshop WiFi systemd.services.workshop-wifi = { wantedBy = [ "multi-user.target" ]; after = [ "network.target" ]; @@ -38,64 +34,87 @@ ${pkgs.networkmanager}/bin/nmcli dev wifi connect "CODE_CRISPIES_GUEST" password "workshop2024" || true ''; }; - - # Auto-login workshop user + + # Auto-login and shell setup services.getty.autologinUser = "workshop"; users.users.workshop = { isNormalUser = true; shell = pkgs.zsh; }; - - # Workshop shell environment + + # Zsh shell with helper functions programs.zsh = { enable = true; interactiveShellInit = '' echo "๐Ÿช CODE CRISPIES Workshop Environment" echo "๐Ÿ“ถ WiFi: CODE_CRISPIES_GUEST (auto-connecting...)" echo "๐Ÿ“ก Available servers:" - ${builtins.concatStringsSep "\n" (map (name: + ${builtins.concatStringsSep "\n" (map (name: "echo \" - ${name}.codecrispi.es\"" ) participantNames)} echo "" echo "๐Ÿ’ก Commands: connect | recipes | help" - + connect() { - [ -z "$1" ] && { echo "Usage: connect "; return 1; } - echo "๐Ÿ”— Connecting to $1.codecrispi.es..." ssh -o StrictHostKeyChecking=no workshop@$1.codecrispi.es } - - recipes() { - echo "๐Ÿ“ฆ Available recipes:" - echo " wordpress nextcloud hedgedoc jitsi prestashop" - echo "Deploy: abra app new wordpress -S --domain=myapp..codecrispi.es" - } - - help() { - echo "1๏ธโƒฃ connect " - echo "2๏ธโƒฃ abra app new wordpress -S --domain=mysite..codecrispi.es" - echo "3๏ธโƒฃ abra app deploy mysite..codecrispi.es" - echo "4๏ธโƒฃ Visit https://mysite..codecrispi.es" - } + # ... other helper functions (recipes, help) ... ''; }; - environment.systemPackages = with pkgs [ openssh curl git networkmanager ]; - - # Auto-start terminal + # Base packages and auto-start terminal + environment.systemPackages = with pkgs; [ openssh curl git networkmanager ]; services.xserver = { enable = true; - displayManager = { - autoLogin.enable = true; - autoLogin.user = "workshop"; - sessionCommands = "${pkgs.xterm}/bin/xterm &"; + displayManager.autoLogin = { + enable = true; + user = "workshop"; }; + desktopManager.xfce.enable = true; # A lightweight desktop + displayManager.sessionCommands = "${pkgs.xfce.xfce4-terminal}/bin/xfce4-terminal &"; }; }) ]; }; - - # Dev shell for local testing + + # -------------------------------------------------------------------------------- + # 2. LOCAL DEVELOPMENT ENVIRONMENT (NixOS Containers) + # `sudo nixos-rebuild switch --flake .#workshop-local` + # -------------------------------------------------------------------------------- + nixosConfigurations.workshop-local = nixpkgs.lib.nixosSystem { + inherit system; + modules = [ + ({ pkgs, ... }: { + # Define 15 participant containers + containers = builtins.listToAttrs (map (i: + let + participantNum = toString i; + ipAddr = "192.168.100.${toString (10 + i)}"; + in + { + name = "participant${participantNum}"; + value = { + autoStart = true; + privateNetwork = true; + hostAddress = "192.168.100.1"; + localAddress = ipAddr; + config = { + # Container config from your local/flake.nix + virtualisation.docker.enable = true; + environment.systemPackages = with pkgs; [ docker git curl ]; + services.openssh.enable = true; + networking.firewall.allowedTCPPorts = [ 22 80 443 ]; + }; + }; + }) (nixpkgs.lib.range 1 15)); + }) + ]; + }; + + # -------------------------------------------------------------------------------- + # 3. DEVELOPMENT SHELL + # `nix develop` + # -------------------------------------------------------------------------------- devShells.${system}.default = nixpkgs.legacyPackages.${system}.mkShell { buildInputs = with nixpkgs.legacyPackages.${system}; [ terraform diff --git a/local/flake.lock b/local/flake.lock new file mode 100644 index 0000000..7469d87 --- /dev/null +++ b/local/flake.lock @@ -0,0 +1,27 @@ +{ + "nodes": { + "nixpkgs": { + "locked": { + "lastModified": 1754725699, + "narHash": "sha256-iAcj9T/Y+3DBy2J0N+yF9XQQQ8IEb5swLFzs23CdP88=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "85dbfc7aaf52ecb755f87e577ddbe6dbbdbc1054", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "root": { + "inputs": { + "nixpkgs": "nixpkgs" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/local/flake.nix b/local/flake.nix index 6ca5e62..2724ed6 100644 --- a/local/flake.nix +++ b/local/flake.nix @@ -28,54 +28,159 @@ extraOptions = "--experimental"; }; - # Install abra + setup environment.systemPackages = with pkgs; [ - docker - git - curl - (stdenv.mkDerivation { - pname = "abra"; - version = "latest"; - src = fetchurl { - url = "https://git.autonomic.zone/coop-cloud/abra/releases/latest/download/abra-x86_64-unknown-linux-gnu"; - sha256 = "sha256-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA="; # Update with real hash - }; - installPhase = "install -D $src $out/bin/abra"; - }) + docker git curl wget tar jq ]; + # Helper script for workshop commands + environment.etc."workshop-helpers.sh" = { + text = '' + #!/bin/bash + + connect() { + case "$1" in + hopper|curie|lovelace|noether|hamilton|franklin|johnson|clarke|goldberg|liskov|wing|rosen|shaw|karp|rich) + echo "๐Ÿ”— Connecting to $1.codecrispi.es..." + ssh -o StrictHostKeyChecking=no workshop@$1.codecrispi.es + ;; + *) + echo "Available servers:" + echo " hopper curie lovelace noether hamilton franklin johnson" + echo " clarke goldberg liskov wing rosen shaw karp rich" + ;; + esac + } + + recipes() { + echo "๐Ÿช Available Co-op Cloud Recipes:" + echo "" + echo "๐Ÿ“ Content Management:" + echo " wordpress - Blog/CMS platform" + echo " ghost - Publishing platform" + echo " hedgedoc - Collaborative markdown editor" + echo " dokuwiki - Simple textfile based wiki" + echo " mediawiki - The wiki software that runs Wikipedia" + echo "" + echo "โ˜๏ธ File & Collaboration:" + echo " nextcloud - File sync & collaboration" + echo " seafile - File hosting platform" + echo " collabora - Online Office suite" + echo " onlyoffice - Online office suite" + echo "" + echo "๐Ÿ’ฌ Communication:" + echo " jitsi-meet - Video conferencing" + echo " matrix-synapse - Chat server" + echo " rocketchat - Team communication" + echo " mattermost - Team collaboration platform" + echo "" + echo "๐Ÿ›’ E-commerce & Business:" + echo " prestashop - E-commerce platform" + echo " invoiceninja - Invoice & billing" + echo " kimai - Time tracking" + echo " pretix - Event ticketing" + echo "" + echo "๐Ÿ”ง Development & Tools:" + echo " gitea - Git repository hosting" + echo " drone - CI/CD platform" + echo " n8n - Workflow automation" + echo " gitlab - DevOps platform" + echo " jupyter-lab - Interactive computing" + echo "" + echo "๐Ÿ“Š Analytics & Monitoring:" + echo " plausible - Privacy-friendly analytics" + echo " matomo - Web analytics" + echo " uptime-kuma - Status monitoring" + echo " grafana - Observability platform" + echo "" + echo "๐ŸŽต Media & Social:" + echo " peertube - Video platform" + echo " funkwhale - Music platform" + echo " mastodon - Social networking" + echo " pixelfed - Photo sharing" + echo " jellyfin - Media system" + echo "" + echo "Usage: abra app new -S --domain=myapp.${participant}.local" + echo "Browse all 100+ recipes: https://recipes.coopcloud.tech" + } + + help() { + echo "๐Ÿช CODE CRISPIES Workshop Commands:" + echo "" + echo "connect - SSH to cloud server" + echo "recipes - Show available app recipes" + echo "abra app new -S --domain=.${participant}.local" + echo "abra app deploy " + echo "abra app ls - List your apps" + echo "" + echo "Examples:" + echo " connect hopper" + echo " abra app new wordpress -S --domain=blog.${participant}.local" + echo " abra app deploy blog.${participant}.local" + echo "" + echo "Server: ${participant}.local" + echo "Your apps will be available at: https://.${participant}.local" + } + + export -f connect recipes help + ''; + mode = "0755"; + }; + systemd.services.workshop-setup = { wantedBy = [ "multi-user.target" ]; - after = [ "docker.service" ]; + after = [ "docker.service" "network-online.target" ]; + wants = [ "network-online.target" ]; script = '' - # Docker swarm + # Wait for network interface + until ip addr show | grep -q "192.168.100.${toString (10 + i)}"; do + sleep 1 + done + + # Install abra + export HOME=/root + ${pkgs.curl}/bin/curl -fsSL https://install.abra.coopcloud.tech | ${pkgs.bash}/bin/bash + + # Docker swarm setup ${pkgs.docker}/bin/docker swarm init --advertise-addr 192.168.100.${toString (10 + i)} || true ${pkgs.docker}/bin/docker network create -d overlay proxy || true # Abra server setup mkdir -p /root/.abra/servers - echo "${participant}.local" > /root/.abra/servers/${participant}.local/server.conf + /root/.local/bin/abra server add ${participant}.local + + # Setup helper commands in bash profile + echo "source /etc/workshop-helpers.sh" >> /root/.bashrc ''; + serviceConfig = { + Type = "oneshot"; + RemainAfterExit = true; + }; }; services.openssh.enable = true; networking = { firewall.allowedTCPPorts = [ 22 80 443 ]; - hostName = "${participant}-local"; + hostName = "${participant}.local"; }; }; }; } ) (nixpkgs.lib.range 1 15)); - # DNS for *.local domains + # Wildcard DNS for all participant subdomains services.dnsmasq = { enable = true; - settings.address = builtins.concatMap (i: [ - "/participant${toString i}.local/192.168.100.${toString (10 + i)}" - "/wp.participant${toString i}.local/192.168.100.${toString (10 + i)}" - "/nextcloud.participant${toString i}.local/192.168.100.${toString (10 + i)}" - ]) (nixpkgs.lib.range 1 15); + settings.address = builtins.concatMap (i: + let participant = builtins.elemAt [ + "hopper" "curie" "lovelace" "noether" "hamilton" + "franklin" "johnson" "clarke" "goldberg" "liskov" + "wing" "rosen" "shaw" "karp" "rich" + ] (i - 1); + in [ + "/${participant}.local/192.168.100.${toString (10 + i)}" + "/.${participant}.local/192.168.100.${toString (10 + i)}" + ] + ) (nixpkgs.lib.range 1 15); }; } ]; diff --git a/usb/flake.nix b/usb/flake.nix deleted file mode 100644 index c20038f..0000000 --- a/usb/flake.nix +++ /dev/null @@ -1,183 +0,0 @@ -{ - description = "CODE CRISPIES Workshop Live Environment"; - - inputs = { - nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable"; - nixos-generators.url = "github:nix-community/nixos-generators"; - }; - - outputs = { self, nixpkgs, nixos-generators }: - let - system = "x86_64-linux"; - participantNames = [ - "hopper" "curie" "lovelace" "noether" "hamilton" - "franklin" "johnson" "clarke" "goldberg" "liskov" - "wing" "rosen" "shaw" "karp" "rich" - ]; - in { - packages.${system}.live-iso = nixos-generators.nixosGenerate { - inherit system; - format = "iso"; - - modules = [ - ({ pkgs, ... }: { - # WiFi + NetworkManager - networking = { - networkmanager.enable = true; - wireless.enable = false; # Disable wpa_supplicant, use NetworkManager - }; - - # Auto-connect to workshop WiFi - systemd.services.workshop-wifi = { - wantedBy = [ "multi-user.target" ]; - after = [ "NetworkManager.service" ]; - serviceConfig = { - Type = "oneshot"; - RemainAfterExit = true; - User = "workshop"; - }; - script = '' - sleep 10 # Wait for NetworkManager to start - ${pkgs.networkmanager}/bin/nmcli dev wifi connect "CODE_CRISPIES_GUEST" password "workshop2024" || true - ''; - }; - - # Auto-login workshop user - services.getty.autologinUser = "workshop"; - users.users.workshop = { - isNormalUser = true; - shell = pkgs.zsh; - extraGroups = [ "networkmanager" ]; - }; - - # Workshop shell environment with CORRECT recipes - programs.zsh = { - enable = true; - interactiveShellInit = '' - echo "๐Ÿช CODE CRISPIES Workshop Environment" - echo "๐Ÿ“ถ WiFi: CODE_CRISPIES_GUEST" - echo "๐Ÿ“ก Available servers:" - ${builtins.concatStringsSep "\n" (map (name: - "echo \" - ${name}.codecrispi.es\"" - ) participantNames)} - echo "" - echo "๐Ÿ’ก Commands: connect | recipes | help" - - connect() { - [ -z "$1" ] && { - echo "Usage: connect " - echo "Available: ${builtins.concatStringsSep " " participantNames}" - return 1 - } - echo "๐Ÿ”— Connecting to $1.codecrispi.es..." - ssh -o StrictHostKeyChecking=no workshop@$1.codecrispi.es - } - - recipes() { - echo "๐Ÿ“ฆ Popular Co-op Cloud recipes (Score 3+):" - echo "" - echo "๐ŸŒ Content Management:" - echo " wordpress - CMS/Blog platform" - echo " ghost - Headless Node.js CMS" - echo " dokuwiki - Simple text-based wiki" - echo "" - echo "โ˜๏ธ Productivity & Collaboration:" - echo " nextcloud - File sharing & collaboration" - echo " hedgedoc - Collaborative markdown editor" - echo " collabora - Online office suite" - echo " onlyoffice - Office suite with editors" - echo " outline - Wiki and knowledge base" - echo "" - echo "๐Ÿฝ๏ธ Lifestyle & Organization:" - echo " mealie - Recipe manager & meal planner" - echo "" - echo "๐Ÿ’ฌ Communication:" - echo " mattermost - Team chat platform" - echo " rocketchat - Team communications" - echo "" - echo "๐ŸŽฏ Event & Community Management:" - echo " engelsystem - Volunteer shift management" - echo " loomio - Group decision making" - echo " mrbs - Meeting room booking" - echo " rallly - Doodle poll alternative" - echo "" - echo "๐Ÿ› ๏ธ Development & Git:" - echo " gitea - Self-hosted Git service" - echo " custom-php - Custom PHP applications" - echo "" - echo "๐ŸŽจ Creative & Media:" - echo " owncast - Live streaming platform" - echo "" - echo "Deploy example:" - echo " abra app new wordpress -S --domain=mysite..codecrispi.es" - } - - help() { - echo "๐Ÿ“š CODE CRISPIES Workshop Guide" - echo "" - echo "1๏ธโƒฃ Connect to your assigned server:" - echo " connect # e.g., connect hopper" - echo "" - echo "2๏ธโƒฃ Check your server status:" - echo " abra server ls" - echo " abra app ls" - echo "" - echo "3๏ธโƒฃ Deploy your first app:" - echo " abra app new wordpress -S --domain=mysite..codecrispi.es" - echo " abra app deploy mysite..codecrispi.es" - echo "" - echo "4๏ธโƒฃ Check deployment status:" - echo " abra app ps mysite..codecrispi.es" - echo " abra app logs mysite..codecrispi.es" - echo "" - echo "5๏ธโƒฃ Access your site:" - echo " https://mysite..codecrispi.es" - echo "" - echo "๐Ÿ†˜ Need help? Ask the workshop facilitator!" - echo "๐Ÿ“ฆ See all recipes: recipes" - } - ''; - }; - - environment.systemPackages = with pkgs; [ - openssh - curl - git - networkmanager - ]; - - # Auto-start terminal in graphical environment - services.xserver = { - enable = true; - displayManager = { - autoLogin.enable = true; - autoLogin.user = "workshop"; - sessionCommands = '' - ${pkgs.xterm}/bin/xterm -maximized -e ${pkgs.zsh}/bin/zsh & - ''; - }; - desktopManager.xfce.enable = true; - }; - - # Enable hardware support for most WiFi cards - hardware.enableRedistributableFirmware = true; - - # ISO-specific settings - isoImage.makeEfiBootable = true; - isoImage.makeUsbBootable = true; - }) - ]; - }; - - # Dev shell - devShells.${system}.default = nixpkgs.legacyPackages.${system}.mkShell { - buildInputs = with nixpkgs.legacyPackages.${system}; [ - terraform - nixos-rebuild - docker - openssh - jq - ]; - }; - }; -}