Tutorial · Cloud Storage · Self-hosted

Run webQsee's Cloud Gallery on your own min.io

Same architecture as the Amazon S3 setup, but the bucket lives on hardware you control. Ideal for teams who can't or don't want to put captures in a hyperscaler.

Estimated time: 20–30 min · Last reviewed: 2026-05 · Difficulty: Easy (assuming a running min.io)

Before you start
  • webQsee installed in Chrome or Edge, get it here
  • An active webQsee Professional or Team plan, see pricing
  • A running self-hosted min.io instance reachable from the browsers of every team member, served over HTTPS with a valid certificate (browsers won't accept self-signed certs for cross-origin S3 requests)
  • Admin credentials for the min.io console (the root user, or any user with the admin policy)
  • About 25 minutes

webQsee's Cloud Gallery talks to S3-compatible storage directly from the browser extension. webQsee's own backend never sees your captures, only the lightweight metadata (title, description, owner, status). That contract holds identically whether the bucket is on Amazon S3 or on your own min.io, the only practical difference is two extra connection-settings keys (endpoint and s3ForcePathStyle) and the fact that you operate the storage.

This guide walks through both halves: Part 1 sets up min.io and the webQsee admin's connection. Part 2 brings the rest of the team on board, including the web-only flow via view.webqsee.com.

Part 1 · Admin setup

You only do this once, as the team's owner/admin.

1. Create the bucket

  1. Open the min.io console

    Sign in at https://<your-minio-host> (the same URL the browser extension will use). Use root credentials or any account holding the built-in admin policy.

    Sanity check: You land on the min.io dashboard and the left nav shows Object Browser, Access Keys, Identity, Policies.
  2. Create a fresh bucket

    Click Object Browser → Create Bucket. Name it something short and unambiguous, this tutorial uses webqsee-demo. Leave versioning and object locking off; webQsee manages item lifecycle in its own metadata.

    Sanity check: The new bucket appears in the bucket list, status "0 objects, 0 B".
  3. Enable encryption (recommended)

    Open the bucket's Encryption tab and enable Server-Side Encryption with SSE-S3 (managed by min.io) or SSE-KMS if you already operate a KMS. webQsee uses standard PUT/GET, no custom encryption headers needed.

    Sanity check: The Encryption tab shows the chosen mode active.
  4. Configure CORS on the bucket

    min.io accepts CORS via the mc client. From a shell with mc configured (replace local with your alias):

    mc cors set local/webqsee-demo - <<'EOF'
    <CORSConfiguration>
      <CORSRule>
        <AllowedOrigin>*</AllowedOrigin>
        <AllowedMethod>GET</AllowedMethod>
        <AllowedMethod>PUT</AllowedMethod>
        <AllowedMethod>POST</AllowedMethod>
        <AllowedMethod>DELETE</AllowedMethod>
        <AllowedMethod>HEAD</AllowedMethod>
        <AllowedHeader>*</AllowedHeader>
        <ExposeHeader>ETag</ExposeHeader>
        <MaxAgeSeconds>3000</MaxAgeSeconds>
      </CORSRule>
    </CORSConfiguration>
    EOF

    If your min.io is behind nginx/Caddy/Traefik, the same CORS rules can equivalently be set there, in that case the bucket-level CORS is optional. Tighten AllowedOrigin to your extension origin if you want to lock things down.

    Sanity check: mc cors get local/webqsee-demo echoes back the rules. From DevTools on any HTTPS page, fetch('https://<minio>/webqsee-demo/', {method:'OPTIONS'}) returns 200 with Access-Control-Allow-Origin in the response.

2. Create a bucket-scoped policy and access key

One single policy that grants full read/write on exactly this bucket and nothing else. Same policy works for the admin and (later) every invited team member who points at the same bucket.

  1. Open Policies → Create Policy

    In the min.io console, go to Identity → Policies → Create Policy. Name it webqsee-bucket-rw. Paste this JSON, replacing every webqsee-demo with your real bucket name if it's different:

    {
      "Version": "2012-10-17",
      "Statement": [
        {
          "Effect": "Allow",
          "Action": [
            "s3:GetBucketLocation",
            "s3:ListAllMyBuckets"
          ],
          "Resource": "arn:aws:s3:::*"
        },
        {
          "Effect": "Allow",
          "Action": "s3:*",
          "Resource": [
            "arn:aws:s3:::webqsee-demo",
            "arn:aws:s3:::webqsee-demo/*"
          ]
        }
      ]
    }

    The first statement lets the extension probe "is this bucket reachable?" on connect, the second is the actual read/write/delete grant on the bucket and its objects.

    Sanity check: The new policy webqsee-bucket-rw shows up in the Policies list, no validation error.
  2. Create an access key bound to this policy

    Go to Identity → Access Keys → Create Access Key. min.io generates an Access Key ID and a Secret Key. Under Restrict beyond user policies, paste the same JSON from step 5 (or attach the webqsee-bucket-rw policy if you created the key against a dedicated user). Click Create.

    Save both strings now, the secret cannot be retrieved later. Treat the secret like a password.

    Sanity check: The Access Keys table shows your new key with status Enabled. You have the Access Key ID and Secret saved in a secure place (password manager, not chat).

3. Connect webQsee to the bucket

  1. Open the Cloud Gallery settings

    Inside the webQsee extension, open the main window (Alt+A or via the popup), then Gallery → Cloud Gallery → Edit Settings. You're going to fill in two groups of fields: team-wide settings (everyone shares these) and personal credentials (yours only, stored locally).

    Sanity check: A modal "Cloud Storage Settings" opens with two visible sections, "Team-wide" and "Personal credentials".
  2. Fill in the team-wide settings

    This is the bit every team member will inherit automatically once you save it:

    • Storage Type: Custom S3 (not "Amazon S3 KEY-Auth", that's the AWS preset).
    • Bucket name: webqsee-demo (or whatever you named it).
    • Connection settings (JSON):
      {
        "endpoint": "https://<your-minio-host>",
        "s3ForcePathStyle": true,
        "signatureVersion": "v4"
      }

      s3ForcePathStyle: true is required for min.io, this is the single most common reason "everything works against AWS but breaks against min.io". signatureVersion: "v4" is also required. Use the full HTTPS URL of your min.io endpoint, no trailing slash.

    Sanity check: The JSON editor validates green, no red squiggle. The endpoint resolves in a separate browser tab (you see the min.io login page).
  3. Enter your personal credentials

    In the Personal credentials section, paste the Access Key ID and Secret access key from step 6.

    Credentials live only in this browser instance, encrypted in extension-local storage. They never traverse webQsee's backend. If you use webQsee on a second machine (or a second browser profile), you re-enter the credentials there. That's by design.

    Sanity check: Both fields show their values (Secret masked with bullets). No "field required" warning.
  4. Save and let webQsee verify

    Click Save. webQsee runs a connectivity probe (a small ListBucket + HeadBucket) against your endpoint.

    Sanity check: Toast "Cloud Storage connected ✓" appears, the Cloud Gallery header switches to a green pill "Connected". If you see a red banner instead, jump to Troubleshooting below.

4. Verify with a test upload and view

  1. Take a quick capture in the local gallery

    From the webQsee popup on any webpage, take an Event Snapshot. The capture lands in Local Gallery within a couple of seconds.

    Sanity check: A new card appears in Local Gallery with a thumbnail and the number of captured events.
  2. Upload it to the Cloud Gallery

    Right-click the Local Gallery card and choose Upload to Cloud → Shared. Watch the progress indicator on the thumbnail.

    Sanity check: The card flips to a green "Uploaded" badge. Refresh the min.io console; in webqsee-demo/shared/ you see at least one new object (a .esa file and a small .thumb.png).
  3. Open the cloud item back

    Click the item in the Cloud Gallery. webQsee fetches the metadata from its backend, then pulls the actual .esa payload directly from min.io and opens it in the analyzer.

    Sanity check: The analyzer opens showing the captured events. In Chrome DevTools' Network tab on the analyzer window, you see a GET to https://<your-minio-host>/webqsee-demo/... that returned 200.

Part 2 · Invite team members

Each team member needs two things to participate: a webQsee team membership (free webQsee account, joined to your team via invitation code) and their own S3 credentials to read/write the bucket.

5. Send invitations

  1. Create an invitation code for each colleague

    In webQsee, open Settings → Team → Invitations → Create invitation. Optionally set a role (member or admin) and an expiry. Click Generate.

    Sanity check: A code (looks like WQ-XXXX-YYYY-ZZZZ) appears with a copy button. The Invitations table now shows the new code with status Pending.
  2. Deliver the code

    Send the code to your colleague via the channel you'd use for any small secret: email, Slack DM, signed message. Codes are single-use and expire by default.

    Sanity check: Colleague confirms they received a code that looks like WQ-XXXX-YYYY-ZZZZ.

6. Team member joins the team

Two paths, the team member picks whichever fits.

Path A · In the browser extension (recommended for editors)
  1. Install webQsee and sign up for a free account

    Colleague installs webQsee from the Chrome or Edge store and creates a free webQsee account (the same kind they'd create for personal use).

    Sanity check: The extension popup shows their name and "Personal team" as the active team.
  2. Redeem the invitation code

    From the popup menu pick Join team, paste the code, click Join.

    Sanity check: A "Joined team <your team name>" toast appears. The team-switcher in the main webQsee window now lists your team alongside their personal team.
Path B · In a browser tab via view.webqsee.com (no install)

For people who only need to view shared captures (auditors, support engineers, sales), the extension is optional.

  1. Open view.webqsee.com

    Colleague navigates to view.webqsee.com and signs in / signs up with a free webQsee account.

    Sanity check: The same analyzer UI as inside the extension is now running in a regular browser tab. The top bar shows the user's name and team picker.
  2. Redeem the invitation code

    Click the team-switcher, choose Join team by code, paste the code, click Join.

    Sanity check: Team switcher now lists your team. Without S3 credentials yet, the Cloud Gallery panel shows item titles and statuses but the previews are placeholders saying "S3 credentials required".

7. Team member adds S3 credentials

Each team member supplies their own Access Key ID + Secret. Two acceptable strategies:

  • Shared: the admin reuses the same access key they created in step 6 and sends it to every team member. Quickest, no per-user audit trail in min.io.
  • Per-user (recommended for > 3 members): the admin creates one min.io access key per team member, each one bound to the same webqsee-bucket-rw policy. min.io logs show who did what; revoking access for one person doesn't break the others.
  1. Open Cloud Gallery settings

    Same dialog the admin used in step 7. The team-wide section is already filled in (synced from the admin's setup); only the Personal credentials section is empty.

    Sanity check: The Storage Type, bucket name and Connection settings JSON are pre-filled and read-only; only Access Key ID + Secret are editable.
  2. Paste credentials and save

    Paste the access key delivered by the admin. Save.

    Sanity check: Toast "Personal credentials saved ✓". The Cloud Gallery header pill switches from grey "Credentials required" to green "Connected".
  3. Open any shared cloud item

    Pick any item that the admin uploaded in step 11. Click to open.

    Sanity check: The analyzer opens with the actual captured network and console events visible. Previews and thumbnails are no longer "S3 credentials required".
Final sanity check

Open webQsee → Gallery → Cloud Gallery. The header should read "Cloud Storage connected ✓". Upload one screenshot. Have a colleague open their webQsee (extension or view.webqsee.com) and they should see the same screenshot, click it open, and watch the network panel make a GET to https://<your-minio-host>/webqsee-demo/....

If items appear in the gallery list but previews say "S3 credentials required", the team member just hasn't filled in personal credentials yet, that's step 14. If the upload itself fails, jump straight to the CORS / endpoint troubleshooting below.

Troubleshooting

  • "net::ERR_CERT_AUTHORITY_INVALID" or mixed-content warning: min.io must be served over HTTPS with a certificate the browser trusts. Self-signed certs work in mc but not in browsers from extension origins. Put min.io behind nginx/Caddy/Traefik with a Let's Encrypt cert, or import the CA into the OS trust store of every team member's machine.
  • CORS error, "No 'Access-Control-Allow-Origin' header": the bucket CORS was not applied. Re-run the mc cors set command from step 4; verify with mc cors get. If you proxy min.io through nginx, the proxy strips CORS headers by default, add them back at the proxy layer.
  • SignatureDoesNotMatch: either the wrong secret was pasted (look for stray whitespace), or signatureVersion isn't v4 in the Connection settings JSON. min.io rejects v2.
  • "The bucket you are attempting to access must be addressed using the specified endpoint": s3ForcePathStyle isn't true. min.io serves at https://host/<bucket>/<key>, not virtual-hosted style.
  • 403 Forbidden on PUT: the policy ARN does not match the actual bucket name, or the access key isn't attached to the policy. Re-check both bucket names in the policy JSON against the actual bucket name in min.io.
  • NoSuchBucket: the bucket name typed into the webQsee Cloud Gallery settings does not match the actual bucket name on min.io. They must be identical, case-sensitive.
  • RequestTimeTooSkewed: the clock on min.io's host (or on the user's machine) is > 15 minutes off. Sync via NTP and retry.
  • "S3 credentials required" persists for one team member only: that member just hasn't completed step 14. Credentials are local-only by design.
  • Upload progress freezes at 0 %: usually a corporate proxy stripping the x-amz-* headers. Test from a network outside the proxy; if confirmed, allowlist https://<your-minio-host> at the proxy.

Related tutorials

Simplified Amazon S3 setup

The same flow against Amazon S3 with a single shared IAM user, for teams who prefer a hyperscaler over self-hosting.

Open tutorial

Multi-user S3 with RBAC

Per-user IAM credentials and tag-based folder isolation; works on min.io too, since min.io supports the same IAM model.

Open tutorial

Cloud Storage architecture

The why and how of webQsee's bring-your-own-bucket model: what ends up where, security boundaries, costs.

Open the docs

Create multiple webQsee teams

Run several teams under one admin, each with their own min.io bucket.

Open tutorial

Stop guessing. Start webQseeing.

Add webQsee to Chrome or Edge in one click. Most features are free, forever, no signup needed. Upgrade only if your team needs cloud sharing, S3 storage and Pro-grade tooling.

Works in Chrome 103+, Edge 103+ and most Chromium-based browsers. Install instructions.