name: Deploy Nix Site description: Deploy static site built with Nix flake to S3 and Nomad inputs: site-name: description: 'Site identifier (used as service name in Nomad)' required: true traefik-rule: description: 'Traefik routing rule (e.g., Host(`example.com`) or Host(`example.com`) || Host(`www.example.com`))' required: true flake-output: description: 'Nix flake output to build (e.g., .#packages.x86_64-linux.default or .#)' required: false default: '.#' s3-endpoint: description: 'S3 endpoint' required: false default: 'https://s3.toph.so' runs: using: composite steps: - name: Install tools shell: bash run: | # Install AWS CLI nix profile install nixpkgs#awscli2 # Install Nomad nix profile install nixpkgs#nomad # Make available in PATH export PATH="$HOME/.nix-profile/bin:$PATH" echo "$HOME/.nix-profile/bin" >> $GITHUB_PATH # Set Nomad address echo "NOMAD_ADDR=http://alvin:4646" >> $GITHUB_ENV - name: Build site with Nix shell: bash run: | nix build ${{ inputs.flake-output }} --print-build-logs # Find the result if [ -L result ]; then BUILD_OUTPUT="result" else echo "Error: No result symlink found after nix build" exit 1 fi echo "BUILD_OUTPUT=$BUILD_OUTPUT" >> $GITHUB_ENV - name: Package and upload to S3 shell: bash run: | ARTIFACT_NAME="${{ github.sha }}.tar.gz" # Package the built output tar czf "/tmp/${ARTIFACT_NAME}" -C "$BUILD_OUTPUT" . # Configure AWS CLI for S3 export AWS_ACCESS_KEY_ID="${{ env.S3_ACCESS_KEY }}" export AWS_SECRET_ACCESS_KEY="${{ env.S3_SECRET_KEY }}" export AWS_ENDPOINT_URL="${{ inputs.s3-endpoint }}" export AWS_EC2_METADATA_DISABLED=true # Upload to S3 aws s3 cp "/tmp/${ARTIFACT_NAME}" "s3://artifacts/${ARTIFACT_NAME}" # Make publicly readable aws s3api put-object-acl \ --bucket artifacts \ --key "${ARTIFACT_NAME}" \ --acl public-read echo "📦 Artifact uploaded: ${{ inputs.s3-endpoint }}/artifacts/${ARTIFACT_NAME}" - name: Deploy via Nomad shell: bash run: | cat > /tmp/deploy-${{ inputs.site-name }}.nomad.json <<'NOMAD_EOF' { "Job": { "ID": "${{ inputs.site-name }}", "Name": "${{ inputs.site-name }}", "Type": "service", "Datacenters": ["contabo"], "Constraints": [{ "LTarget": "${node.unique.name}", "RTarget": "alvin", "Operand": "=" }], "TaskGroups": [{ "Name": "web", "Count": 1, "Networks": [{ "Mode": "bridge", "DynamicPorts": [{ "Label": "http", "To": 8080 }] }], "Services": [{ "Name": "${{ inputs.site-name }}", "PortLabel": "http", "Provider": "nomad", "Tags": [ "traefik.enable=true", "traefik.http.routers.${{ inputs.site-name }}.rule=${{ inputs.traefik-rule }}", "traefik.http.routers.${{ inputs.site-name }}.entrypoints=websecure", "traefik.http.routers.${{ inputs.site-name }}.tls.certresolver=letsencrypt" ] }], "Tasks": [{ "Name": "server", "Driver": "docker", "Config": { "image": "joseluisq/static-web-server:2", "ports": ["http"] }, "Env": { "SERVER_ROOT": "/local/public", "SERVER_LOG_LEVEL": "info" }, "Artifacts": [{ "GetterSource": "${{ inputs.s3-endpoint }}/artifacts/${{ github.sha }}.tar.gz", "RelativeDest": "local/public", "GetterMode": "dir" }], "Resources": { "CPU": 100, "MemoryMB": 64 } }] }] } } NOMAD_EOF nomad job run /tmp/deploy-${{ inputs.site-name }}.nomad.json - name: Deployment summary shell: bash run: | echo "✅ Deployed ${{ inputs.site-name }}" echo "📋 Traefik rule: ${{ inputs.traefik-rule }}"