CI/CD Pipelines

Use NullBore in CI/CD pipelines for preview deploys, integration testing, or temporary access to build artifacts.

Preview deploys

Open a tunnel in your CI pipeline to create a preview URL for each PR:

# GitHub Actions example
- name: Start preview server
  run: |
    npm start &
    sleep 5

- name: Open tunnel
  run: |
    nullbore open --port 3000 --name "pr-${{ github.event.number }}" --ttl 4h
    echo "Preview: https://pr-${{ github.event.number }}.tunnel.nullbore.com"

- name: Comment on PR
  uses: actions/github-script@v7
  with:
    script: |
      github.rest.issues.createComment({
        issue_number: context.issue.number,
        owner: context.repo.owner,
        repo: context.repo.repo,
        body: '🕳️ Preview: https://pr-${{ github.event.number }}.tunnel.nullbore.com'
      })

Integration testing

Expose a local test server for external integration tests:

- name: Start and expose test server
  run: |
    ./test-server &
    nullbore open --port 8080 --name "test-${{ github.run_id }}" --ttl 30m --idle

- name: Run integration tests
  run: |
    ENDPOINT="https://test-${{ github.run_id }}.tunnel.nullbore.com" npm test

API-driven

For more control, use the REST API directly:

# Open
TUNNEL=$(curl -s -X POST https://tunnel.nullbore.com/v1/tunnels \
  -H "Authorization: Bearer $NULLBORE_API_KEY" \
  -H "Content-Type: application/json" \
  -d "{\"local_port\": 3000, \"name\": \"ci-${GITHUB_RUN_ID}\", \"ttl\": \"1h\"}")

TUNNEL_ID=$(echo $TUNNEL | jq -r .id)
TUNNEL_URL=$(echo $TUNNEL | jq -r '.slug')

echo "Tunnel: https://${TUNNEL_URL}.tunnel.nullbore.com"

# ... run tests ...

# Close
curl -X DELETE "https://tunnel.nullbore.com/v1/tunnels/${TUNNEL_ID}" \
  -H "Authorization: Bearer $NULLBORE_API_KEY"

Tips

  • Use --idle mode so tunnels don't expire during long test runs
  • Use unique names per run (pr-123, ci-456) to avoid conflicts
  • Store your API key as a CI secret (NULLBORE_API_KEY)
  • Set reasonable TTLs — CI tunnels shouldn't live forever