Kubo (IPFS node) integration 
Blumen could be used together with Kubo, an IPFS node implementation, in a way that would avoid an upload step through Blumen and instead with a simple file transfer.
Uploading a distribution to a self-hosted IPFS node has certain benefits:
- Less reliance on centralized IPFS providers, most of which don't guarantee persistence of data
- Personal data not leaked or exposed
- Free forever besides server costs
- Expanding the network
- Faster retrieval on IPFS gateways
Configuration 
It is recommended to enable accelerated DHT client to make the node appear in the DHT faster when locating the website distribution on the network:
ipfs config --json Routing.AcceleratedDHTClient trueReannouncing pinned content to the network should be enabled as well. It is best to announce all CIDs within the distribution and not only the root one (the one that shows up in blumen pack output):
ipfs config Reprovider.Interval 1h # Reannounce every hour
ipfs config Reprovider.Strategy pinned # Announce all pinned CIDs, including non-recursiveEnabling Auto TLS will make it possible for IPFS clients and certain IPFS gateways (such as inbrowser.link) to fetch content in a browser directly:
ipfs config --json AutoTLS.Enabled trueManual 
Packing the distribution 
Blumen has a command that will only generate a CAR archive without uploading it anywhere called blumen pack:
 blumen pack <dir> --dist .This will generate a .car distribution archive in a current directory.
Uploading on a remote server 
The simplest and fastest way to upload the distribution would be with rsync. The target server should have SSH enabled.
rsync -avz ./dist.car user@ip:/home/userImporting to Kubo 
Once the file is on the server, the only thing left is importing it to Kubo through DAG import.
ipfs dag import ./dist.carNow the distribution is both uploaded to Kubo and is recursively pinned.
Confirm via
ipfs pin ls --type=recursiveAutomatic 
It is not required to do that manually and the process is fairly easy to automate. Below is a sample GitHub Actions workflow for uploading a website distribution generated by Blumen to a remote server with Kubo.
name: Deploy to Kubo
on:
  push:
    branches: main
jobs:
  deploy:
    runs-on: ubuntu-latest
    outputs:
      cid: ${{ steps.pack_blumen.outputs.cid }}
    steps:
      - name: Checkout repository
        uses: actions/checkout@v4
      - uses: denoland/setup-deno@v2
        with:
          deno-version: v2.2.2
      - name: Install dependencies
        run: cd www && deno install --allow-scripts
      - uses: actions/cache@v4
        with:
          path: |
            ~/.deno
            ~/.cache/deno
          key: ${{ runner.os }}-deno-${{ hashFiles('**/deps.ts') }}
      - name: Build website
        run: |
          deno task build
      - name: Pack the website with Blumen
        id: pack_blumen # <- Required for step outputs
        run: |
          output=$(deno --allow-read --allow-env --allow-write npm:blumen pack --dist .)
          echo "$output"
          cid=$(echo "$output" | grep -oP 'Root CID: \K\S+')
          echo "CID=$cid" >> $GITHUB_OUTPUT
          echo "$output" >> $GITHUB_STEP_SUMMARY
      - name: Upload the CAR file via Rsync
        uses: burnett01/[email protected]
        with:
          switches: -avzr --delete
          path: dist.car
          remote_path: /var/lib/ipfs/staging
          remote_host: ${{ secrets.REMOTE_HOST }}
          remote_user: ${{ secrets.REMOTE_USER }}
          remote_key: ${{ secrets.REMOTE_KEY }}
      - name: IPFS DAG import to Kubo
        uses: appleboy/ssh-action@v1
        with:
          host: ${{ secrets.REMOTE_HOST }}
          username: ${{ secrets.REMOTE_USER }}
          key: ${{ secrets.REMOTE_KEY }}
          script: docker exec ipfs_host ipfs dag import /export/dist.carname: Deploy to Kubo
on:
  push:
    branches: main
jobs:
  deploy:
    runs-on: ubuntu-latest
    outputs:
      cid: ${{ steps.pack_blumen.outputs.cid }}
    steps:
      - name: Checkout repository
        uses: actions/checkout@v4
      - name: Setup Bun
        uses: oven-sh/setup-bun@v2
        with:
          bun-version: latest
      - name: Install dependencies
        run: bun install
      - uses: actions/cache@v4
        with:
          path: ~/.bun
          key: ${{ runner.os }}-bun-${{ hashFiles('**/bun.lock') }}
      - name: Build website
        run: bun run build
      - name: Pack the website with Blumen
        id: pack_blumen
        run: |
          output=$(bunx blumen pack --dist .)
          echo "$output"
          cid=$(echo "$output" | grep -oP 'Root CID: \K\S+')
          echo "CID=$cid" >> $GITHUB_OUTPUT
          echo "$output" >> $GITHUB_STEP_SUMMARY
      - name: Upload the CAR file via Rsync
        uses: burnett01/[email protected]
        with:
          switches: -avzr --delete
          path: dist.car
          remote_path: /var/lib/ipfs/staging
          remote_host: ${{ secrets.REMOTE_HOST }}
          remote_user: ${{ secrets.REMOTE_USER }}
          remote_key: ${{ secrets.REMOTE_KEY }}
      - name: IPFS DAG import to Kubo
        uses: appleboy/ssh-action@v1
        with:
          host: ${{ secrets.REMOTE_HOST }}
          username: ${{ secrets.REMOTE_USER }}
          key: ${{ secrets.REMOTE_KEY }}
          script: docker exec ipfs_host ipfs dag import /export/dist.carname: Deploy to Kubo
on:
  push:
    branches: main
jobs:
  deploy:
    runs-on: ubuntu-latest
    outputs:
      cid: ${{ steps.pack_blumen.outputs.cid }}
    steps:
      - name: Checkout repository
        uses: actions/checkout@v4
      - name: Setup pnpm
        uses: pnpm/action-setup@v4
      - name: Install dependencies
        run: pnpm install
      - uses: actions/cache@v4
        with:
          path: |
            ~/.pnpm-store
            node_modules
          key: ${{ runner.os }}-pnpm-${{ hashFiles('**/pnpm-lock.yaml') }}
      - name: Build website
        run: pnpm run build
      - name: Pack the website with Blumen
        id: pack_blumen
        run: |
          output=$(pnpm dlx blumen pack --dist .)
          echo "$output"
          cid=$(echo "$output" | grep -oP 'Root CID: \K\S+')
          echo "CID=$cid" >> $GITHUB_OUTPUT
          echo "$output" >> $GITHUB_STEP_SUMMARY
      - name: Upload the CAR file via Rsync
        uses: burnett01/[email protected]
        with:
          switches: -avzr --delete
          path: dist.car
          remote_path: /var/lib/ipfs/staging
          remote_host: ${{ secrets.REMOTE_HOST }}
          remote_user: ${{ secrets.REMOTE_USER }}
          remote_key: ${{ secrets.REMOTE_KEY }}
      - name: IPFS DAG import to Kubo
        uses: appleboy/ssh-action@v1
        with:
          host: ${{ secrets.REMOTE_HOST }}
          username: ${{ secrets.REMOTE_USER }}
          key: ${{ secrets.REMOTE_KEY }}
          script: docker exec ipfs_host ipfs dag import /export/dist.car