Skip to content

DigitalOcean Marketplace: Droplet 1-Click App image #74

Description

@thiras

What are you trying to do?

List the deCDN node as a DigitalOcean Marketplace Droplet 1-Click App, so an operator can pick "deCDN node" when creating a Droplet and end up with a hardened, running node, with no control machine and no hand-edited user-data.

cloud-init/ already covers most of this, but a Marketplace image has to follow DigitalOcean's own rules. Their image checks, root-only SSH key injection and snapshot model don't fit the current bootstrap unchanged.

What would help?

DigitalOcean requirements (upstream)

  • Vendor approval. Apply via Become a Vendor. DigitalOcean reviews the application, then sends a form for the listing. The listing is managed in the Vendor Portal: description, logo, getting-started docs, support contact, keywords. It must say clearly that DigitalOcean doesn't build or support the software.

  • Packer-built snapshot, based on digitalocean/marketplace-partners marketplace-image.json. Build on the $6 Droplet size with the smallest practical disk. Supported bases include Debian 12/13 and Ubuntu 24.04.

  • img_check.sh must pass. It fails the image on any of these:

    • a password on root or any user;
    • content in any authorized_keys or id_rsa;
    • leftover bash history;
    • pending security updates;
    • no cloud-init;
    • the DigitalOcean agent baked in.

    It warns on leftover logs and on a missing firewall. Run cleanup.sh just before the snapshot.

  • Hooks:

    • first boot: /var/lib/cloud/scripts/per-instance/NN-*.sh;
    • first login: root .bashrc, restored from /etc/skel when done;
    • message of the day: /etc/update-motd.d/99-*.
  • Updates: new images go through the Vendor Portal or its API (PATCH /api/v1/vendor-portal/apps/<app_id>).

Gaps in this repo

  1. Blocked on an upstream release. The image must install a real decdn version with decdn_node_install_method: release, verified against the GPG-signed SHA256SUMS. We can't ship a snapshot built from local binaries.

  2. Root login vs. baseline hardening. DigitalOcean injects the customer's key for root only, and baseline disables root login (see cloud-init/README.md). The first-boot script must move root's injected key to an admin user before hardening runs, or the customer is locked out.

  3. No node identity in the snapshot. The eth keystore and node identity must be generated per Droplet at first boot. /etc/decdn and /var/lib/decdn must be empty at snapshot time, or every customer shares an identity. The build should assert this.

  4. Collecting the RPC URL. Reuse the awaiting-secret state:

    • first boot runs --tags baseline and stops;
    • a first-login prompt writes /etc/decdn/decdn.env at 0600;
    • it then runs the full site.yml.

    No secret goes into the image or into user-data.

  5. Bake, don't clone. Packer bakes the repo at a pinned SHA, the hash-locked venv (cloud-init/requirements.txt) and the collections from collections.lock.yml. First boot only runs the playbook.

  6. decdn_region from metadata. Read the region from 169.254.169.254/metadata/v1/region and map it to an ISO 3166-1 alpha-2 code (e.g. nyc1 → US, fra1 → DE).

  7. Already fine: baseline opens the udp/4433 firewall hole (no firewall warning), and Droplets are x86_64, which the role supports.

Proposed deliverables

  • marketplace/digitalocean/: Packer template, first-boot script (key hand-off, region, baseline), first-login script (RPC URL prompt, full run), message of the day, pre-snapshot cleanup that runs DigitalOcean's cleanup.sh
  • CI job: Packer build plus img_check.sh on the result, keyed to release tags. Needs a DigitalOcean API token as a repo secret.
  • A lint/test in the style of the existing gates asserting no identity or secret material is in the image
  • Listing copy. Every protocol or economic claim must cite an ADR. Today only arbitrum-sepolia exists, so this would be a testnet listing.
  • Vendor application (non-code, can start now since approval takes time)

Out of scope for now: Kubernetes 1-Click

A Kubernetes 1-Click needs the chart and the ghcr.io/decdn/decdn-node image published (PUBLISH_ENABLED), plus a deploy.sh / upgrade.sh / uninstall.sh / values.yml stack submitted as a PR to digitalocean/marketplace-kubernetes. That stack must install from values.yml alone, but the chart requires an operator-provisioned existingSecret and never creates a Secret. Revisit separately.

Related: #48 (Terraform for DigitalOcean Droplets + Block Storage).

Deploy path

cloud-init, Ansible

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Fields

    Priority

    None yet

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions