commit 53041ccc1a214dd97459a25a40ac8fe59c10d22d Author: Michael Czechowski Date: Mon Aug 11 12:07:23 2025 +0200 init project diff --git a/.env.example b/.env.example new file mode 100644 index 0000000..b413b41 --- /dev/null +++ b/.env.example @@ -0,0 +1,3 @@ +WORKSHOP_WIFI_SSID= +WORKSHOP_WIFI_PASSWORD= +WORKSHOP_DOMAIN= diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f1ac1d7 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +.env +result/ +.direnv/ diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..0d7901b --- /dev/null +++ b/Makefile @@ -0,0 +1,68 @@ +# 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" + +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 + +clean: + rm -rf result .direnv diff --git a/README.md b/README.md new file mode 100644 index 0000000..8948c97 --- /dev/null +++ b/README.md @@ -0,0 +1,89 @@ +# ๐Ÿช 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 + +- **WordPress** - CMS/Blog +- **Nextcloud** - File sharing +- **HedgeDoc** - Collaborative markdown +- **Jitsi** - Video conferencing +- **PrestaShop** - E-commerce + +## ๐Ÿงน Cleanup + +```bash +make clean # Clean local artifacts +make destroy-cloud # Destroy Hetzner infrastructure +``` diff --git a/docs/USB_BOOT_INSTRUCTIONS.md b/docs/USB_BOOT_INSTRUCTIONS.md new file mode 100644 index 0000000..4801951 --- /dev/null +++ b/docs/USB_BOOT_INSTRUCTIONS.md @@ -0,0 +1,121 @@ +# ๐Ÿช CODE CRISPIES Workshop +## USB Boot Instructions + +### ๐Ÿ“‹ Quick Reference Card + +**Your assigned server:** `__________.codecrispies.es` +**Workshop WiFi:** `CODE_CRISPIES_GUEST` / Password: `workshop2024` + +--- + +## ๐Ÿ’ป How to Boot from USB Drive + +### Step 1: Insert USB Drive +- Insert the CODE CRISPIES workshop USB drive +- Do NOT remove it until workshop ends + +### Step 2: Boot from USB + +#### ๐Ÿ–ฅ๏ธ **Desktop PC / Most Laptops** +1. **Restart** your computer +2. **Press and HOLD** one of these keys immediately as it starts: + - `F12` (most common) + - `F11` + - `F9` + - `ESC` +3. Select **USB Drive** or **UEFI: USB Drive** from boot menu +4. Press `Enter` + +#### ๐ŸŽ **Mac (Intel)** +1. **Restart** your Mac +2. **Press and HOLD** `Option` (โŒฅ) key immediately +3. Select the **USB drive** (may show as "EFI Boot") +4. Press `Enter` + +#### ๐ŸŽ **Mac (Apple Silicon M1/M2)** +1. **Shut down** completely +2. **Press and HOLD** the power button until you see startup options +3. Select the **USB drive** option +4. Click **Continue** + +#### ๐Ÿ”ง **If Boot Menu Doesn't Appear** + +**Windows PC:** +1. Boot into Windows +2. Hold `Shift` + click **Restart** +3. Choose **Troubleshoot** โ†’ **Advanced** โ†’ **UEFI Firmware** +4. Find **Boot Order** settings +5. Move **USB Drive** to top of list +6. Save and exit + +**Popular Manufacturer Keys:** +- **Dell:** `F12` +- **HP:** `F9` or `ESC` then `F9` +- **Lenovo:** `F12` or `Fn + F12` +- **ASUS:** `F8` or `ESC` +- **Acer:** `F12` +- **MSI:** `F11` +- **Samsung:** `F2` then navigate to Boot tab +- **Toshiba:** `F12` + +--- + +## โœ… What You Should See + +1. **NixOS Boot Screen** appears +2. System loads (takes 30-60 seconds) +3. **Desktop environment** starts automatically +4. **Terminal opens** with CODE CRISPIES welcome message +5. You see available servers and commands + +--- + +## ๐Ÿš€ Getting Started Commands + +```bash +# Connect to your assigned server +connect hopper + +# See available app recipes +recipes + +# Get help +help +``` + +--- + +## ๐Ÿ“ฑ Mobile Hotspot Instructions +**If WiFi isn't working:** + +**iPhone:** +Settings โ†’ Personal Hotspot โ†’ Turn On +Name: iPhone, Password: (ask facilitator) + +**Android:** +Settings โ†’ Network โ†’ Hotspot & Tethering โ†’ Mobile Hotspot +Name: Android, Password: (ask facilitator) + +--- + +## ๐Ÿ†˜ Troubleshooting + +โŒ **"No bootable device"** +โ†’ Try different F-key (F11, F9, ESC) +โ†’ USB drive may not be properly inserted + +โŒ **Mac won't boot USB** +โ†’ USB drive might need to be reformatted for Mac +โ†’ Ask facilitator for Mac-compatible USB + +โŒ **Boots to Windows/Mac instead** +โ†’ You didn't press the boot key fast enough +โ†’ Restart and try again immediately + +โŒ **Terminal doesn't open** +โ†’ Click terminal icon in taskbar +โ†’ Or press `Ctrl + Alt + T` + +โŒ **Can't connect to internet** +โ†’ Try different WiFi network +โ†’ Use mobile hotspot as backup diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..55c0dd5 --- /dev/null +++ b/flake.nix @@ -0,0 +1,108 @@ +{ + 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 "๐Ÿ“ฆ 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" + } + ''; + }; + + 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 + ]; + }; + }; +} diff --git a/local/flake.nix b/local/flake.nix new file mode 100644 index 0000000..6ca5e62 --- /dev/null +++ b/local/flake.nix @@ -0,0 +1,84 @@ +{ + 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"; + }; + + # 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"; + }) + ]; + + systemd.services.workshop-setup = { + wantedBy = [ "multi-user.target" ]; + after = [ "docker.service" ]; + script = '' + # Docker swarm + ${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 + ''; + }; + + services.openssh.enable = true; + networking = { + firewall.allowedTCPPorts = [ 22 80 443 ]; + hostName = "${participant}-local"; + }; + }; + }; + } + ) (nixpkgs.lib.range 1 15)); + + # DNS for *.local domains + 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); + }; + } + ]; + }; + }; +} diff --git a/scripts/deploy.sh b/scripts/deploy.sh new file mode 100644 index 0000000..fa8278c --- /dev/null +++ b/scripts/deploy.sh @@ -0,0 +1,52 @@ +#!/usr/bin/env bash +set -e + +echo "๐Ÿš€ Deploying Co-op Cloud workshop..." + +cd terraform +terraform apply \ + -var="hcloud_token=$HCLOUD_TOKEN" \ + -var="domain=codecrispi.es" \ + -var="ssh_public_key=$(cat ~/.ssh/id_rsa.pub)" \ + -auto-approve + +echo "โณ Waiting for servers to be ready..." + +# Wait for SSH + Docker to be ready on each server +terraform output -json participant_ips | jq -r 'keys[]' | while read participant; do + echo "Checking $participant.codecrispi.es..." + + # Wait for SSH to be available + while ! ssh -o ConnectTimeout=5 -o StrictHostKeyChecking=no workshop@$participant.codecrispi.es "exit" 2>/dev/null; do + echo " SSH not ready yet, retrying in 10s..." + sleep 10 + done + + # Wait for Docker + abra to be ready + while ! ssh -o StrictHostKeyChecking=no workshop@$participant.codecrispi.es "docker info && which abra" &>/dev/null; do + echo " Docker/abra not ready yet, retrying in 5s..." + sleep 5 + done + + echo " โœ… $participant ready!" +done + +echo "๐Ÿ”ง Setting up each server..." +terraform output -json participant_ips | jq -r 'keys[]' | while read participant; do + echo "Configuring $participant..." + + ssh -o StrictHostKeyChecking=no workshop@$participant.codecrispi.es << EOF + # Deploy Traefik + abra app deploy traefik.$participant.codecrispi.es + + # Wait for Traefik to be ready + until curl -f https://traefik.$participant.codecrispi.es/ping 2>/dev/null; do + echo "Waiting for Traefik..." + sleep 5 + done + + echo "โœ… $participant fully configured!" +EOF +done + +echo "๐ŸŽ‰ Workshop ready! Participants can access their servers." diff --git a/terraform/cloud-init.yml b/terraform/cloud-init.yml new file mode 100644 index 0000000..dd8c5b5 --- /dev/null +++ b/terraform/cloud-init.yml @@ -0,0 +1,34 @@ +#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 + - 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} diff --git a/terraform/main.tf b/terraform/main.tf new file mode 100644 index 0000000..7d90dd9 --- /dev/null +++ b/terraform/main.tf @@ -0,0 +1,44 @@ +locals { + domain = "codecrispi.es" + participants = [ + "hopper", "curie", "lovelace", "noether", "hamilton", + "franklin", "johnson", "clarke", "goldberg", "liskov", + "wing", "rosen", "shaw", "karp", "rich" + ] +} + +resource "hcloud_server" "participant" { + for_each = toset(local.participants) + + name = each.key + image = "ubuntu-22.04" + server_type = "cx21" + location = "nbg1" + + ssh_keys = [hcloud_ssh_key.workshop.id] + + user_data = templatefile("${path.module}/cloud-init.yml", { + participant_name = each.key + domain = local.domain + }) +} + +resource "hcloud_dns_record" "participant_main" { + for_each = toset(local.participants) + + zone_id = var.dns_zone_id + name = each.key + type = "A" + value = hcloud_server.participant[each.key].ipv4_address + ttl = 60 +} + +resource "hcloud_dns_record" "participant_wildcard" { + for_each = toset(local.participants) + + zone_id = var.dns_zone_id + name = "*.${each.key}" + type = "A" + value = hcloud_server.participant[each.key].ipv4_address + ttl = 60 +} diff --git a/usb/flake.nix b/usb/flake.nix new file mode 100644 index 0000000..c20038f --- /dev/null +++ b/usb/flake.nix @@ -0,0 +1,183 @@ +{ + 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 + ]; + }; + }; +}