# CI Actions Reusable Forgejo/Gitea actions for toph's infrastructure. ## Available Actions ### `deploy-site` Deploy a static site to production via S3 and Nomad. **Usage:** ```yaml name: Deploy on: push: branches: [main] jobs: deploy: runs-on: self-hosted steps: - uses: actions/checkout@v4 - name: Build site (if needed) run: npm run build - name: Deploy uses: https://git.toph.so/toph/ci-actions/deploy-site@main with: site-name: mysite traefik-rule: Host(`mysite.example.com`) source-dir: dist # optional, defaults to current dir env: S3_ACCESS_KEY: ${{ secrets.S3_ACCESS_KEY }} S3_SECRET_KEY: ${{ secrets.S3_SECRET_KEY }} ``` **Inputs:** - `site-name` (required): Site identifier used as Nomad service name - `traefik-rule` (required): Traefik routing rule (see examples below) - `source-dir` (optional): Directory with built files, defaults to `.` - `s3-endpoint` (optional): S3 endpoint, defaults to `https://s3.toph.so` **Environment variables:** - `S3_ACCESS_KEY`: S3 access key (set via Forgejo secrets) - `S3_SECRET_KEY`: S3 secret key (set via Forgejo secrets) **What it does:** 1. Packages the site directory as a tarball 2. Uploads to S3 at `s3://artifacts/.tar.gz` 3. Sets public-read ACL on the artifact 4. Dispatches Nomad job to deploy the site 5. Site becomes available via the specified Traefik rule with Let's Encrypt SSL **Infrastructure handles:** - Docker containers (static-web-server) - Resource limits (100 CPU, 64MB RAM) - Traefik routing & Let's Encrypt SSL - Automatic restarts ## Traefik Rule Examples **Single domain:** ```yaml traefik-rule: Host(`example.com`) ``` **Multiple domains (with www):** ```yaml traefik-rule: Host(`example.com`) || Host(`www.example.com`) ``` **Subdomain:** ```yaml traefik-rule: Host(`blog.example.com`) ``` **toph.so domain:** ```yaml traefik-rule: Host(`mysite.toph.so`) ``` **Path-based routing:** ```yaml traefik-rule: Host(`example.com`) && PathPrefix(`/docs`) ``` ## Setup ### 1. Deploy S3 service (SeaweedFS) ```bash cd /srv/infra nix run .#bosun -- run s3 ``` ### 2. Create artifacts bucket ```bash # Configure AWS CLI export AWS_ACCESS_KEY_ID= export AWS_SECRET_ACCESS_KEY= export AWS_ENDPOINT_URL=https://s3.toph.so export AWS_EC2_METADATA_DISABLED=true # Create bucket aws s3 mb s3://artifacts # Set public-read policy for the bucket aws s3api put-bucket-acl --bucket artifacts --acl public-read ``` ### 3. Add Forgejo secrets In your repository settings (or organization settings for global secrets): - `S3_ACCESS_KEY`: The access key from S3 credentials - `S3_SECRET_KEY`: The secret key from S3 credentials That's it! The action will automatically create individual Nomad service jobs for each site. ## Examples ### Simple HTML site ```yaml name: Deploy on: push: branches: [main] jobs: deploy: runs-on: self-hosted steps: - uses: actions/checkout@v4 - uses: https://git.toph.so/toph/ci-actions/deploy-site@main with: site-name: mysite traefik-rule: Host(`mysite.toph.so`) source-dir: . # HTML files in repo root env: S3_ACCESS_KEY: ${{ secrets.S3_ACCESS_KEY }} S3_SECRET_KEY: ${{ secrets.S3_SECRET_KEY }} ``` ### Node.js/Vite site with custom domain ```yaml name: Deploy on: push: branches: [main] jobs: deploy: runs-on: self-hosted steps: - uses: actions/checkout@v4 - name: Setup Node uses: actions/setup-node@v4 with: node-version: 20 - name: Install & build run: | npm ci npm run build - uses: https://git.toph.so/toph/ci-actions/deploy-site@main with: site-name: myapp traefik-rule: Host(`app.example.com`) || Host(`www.app.example.com`) source-dir: dist env: S3_ACCESS_KEY: ${{ secrets.S3_ACCESS_KEY }} S3_SECRET_KEY: ${{ secrets.S3_SECRET_KEY }} ``` ### Hugo site ```yaml name: Deploy on: push: branches: [main] jobs: deploy: runs-on: self-hosted steps: - uses: actions/checkout@v4 with: submodules: true # For Hugo themes - name: Setup Hugo run: | wget https://github.com/gohugoio/hugo/releases/download/v0.121.0/hugo_extended_0.121.0_linux-amd64.tar.gz tar xzf hugo_extended_0.121.0_linux-amd64.tar.gz sudo mv hugo /usr/local/bin/ - name: Build run: hugo --minify - uses: https://git.toph.so/toph/ci-actions/deploy-site@main with: site-name: myblog traefik-rule: Host(`blog.example.com`) source-dir: public env: S3_ACCESS_KEY: ${{ secrets.S3_ACCESS_KEY }} S3_SECRET_KEY: ${{ secrets.S3_SECRET_KEY }} ``` ## S3 Access - **API endpoint**: https://s3.toph.so - **Console**: https://s3-console.toph.so (restricted to Tailscale) - **Credentials**: Stored in Nomad variables at `nomad/jobs/s3` - **Backend**: SeaweedFS (S3-compatible) ## Troubleshooting ### AWS CLI not found The action automatically installs AWS CLI if not present on the runner. ### Access denied during upload Check that: 1. `S3_ACCESS_KEY` and `S3_SECRET_KEY` are set in Forgejo secrets 2. The credentials match those in the S3 Nomad job config 3. S3 service is running: `nomad job status s3` ### Site not accessible Check: 1. Nomad allocation is running: `nomad job status static-site` 2. Traefik has picked up the service: check Traefik dashboard 3. DNS resolves: `dig .toph.so` 4. Certificate is valid: `curl -v https://.toph.so` ## Development To add a new action: ```bash mkdir -p new-action cd new-action vim action.yaml ``` Then commit and push to `main`. ## License MIT