Skip to content

Docker Follower Node Deployment

Who this page is for

Use this if you want to run another AsterDrive instance as a follower with Docker, and you want it to auto-enroll from environment variables during first startup instead of manually running docker exec ... aster_drive node enroll.

This page only covers follower node deployment in Docker. For how the primary node understands follower nodes and how to create follower storage policies, see Follower Nodes.

The biggest difference from the old workflow is one thing:

  • A follower container can now read bootstrap ENV at startup and complete enrollment automatically.

That means first startup no longer requires:

  • manually entering the container to run aster_drive node enroll
  • restarting the container once more after enrollment finishes

Confirm These 4 Things First

1. The Primary Node Is Running Normally

At minimum:

  • The primary admin panel can open normally.
  • Admin -> System Settings -> Site Configuration -> Public Site URL is set to a real reachable HTTP(S) origin. If multiple origins are configured, put the primary origin that the follower can reach on the first line.
  • You have decided this follower's name, namespace, and the future base_url the primary node will use to access it.

2. The Follower Must Have Its Own Independent data/

The primary node and follower must never share:

  • data/config.toml
  • database
  • upload directory
  • temporary directory

A follower node is not "another copy of the primary node". It is another independent AsterDrive instance.

3. The Primary Node Must Be Able to Access the Follower base_url

If the primary and follower run on different machines, base_url will usually be one of:

  • https://follower.example.com
  • http://10.0.0.23:3000
  • http://host.example.com:3001

If both instances are in a Docker network and the primary can resolve the container name, you may also use the in-container address directly. Do not default to http://localhost:3000; that usually only works from the follower itself.

If the follower is behind NAT or CGNAT

The current Docker bootstrap solves "automatic first enrollment for a follower node". It does not yet solve "the primary cannot connect back to the follower but still needs to read and write objects".

If the primary cannot access the follower base_url, follower storage policies still cannot work reliably. An outbound-only reverse channel is being tracked in issue #136.

4. The Token Is Single-Use

Enrollment tokens generated by the primary admin panel:

  • expire after 30 minutes by default
  • become invalid after one successful exchange

So these ENV values are only suitable for first-start bootstrap. Do not leave old tokens in Compose long term.

1. Create a Follower Node and Generate a Token in the Primary Admin Panel

Entry:

text
Admin -> Follower Nodes

Create a follower node record first, and at least fill in:

  • name
  • namespace
  • base_url

After saving, the admin panel generates enrollment information. The Docker follower needs these two values at startup:

  • master_url
  • token

In the current version, the follower's object receiving target is pushed by the primary node from the follower node details page. In other words, Docker bootstrap only binds the primary and follower identities. Whether objects are ultimately written to a follower local directory or S3 is configured later in the primary admin panel by creating a receiving target.

2. Prepare the Follower Data Directory

If you use a bind mount, create the host directory first and change its owner:

bash
mkdir -p ./data
sudo chown -R 10001:10001 ./data

If you use a named volume, you can skip this step.

3. Write compose.yaml

This example assumes the follower is exposed on host port 3001:

yaml
services:
  asterdrive-follower:
    image: ghcr.io/apts-1547/asterdrive:latest
    container_name: asterdrive-follower
    ports:
      - "3001:3000"
    environment:
      ASTER__SERVER__HOST: 0.0.0.0
      ASTER__SERVER__START_MODE: follower
      ASTER__SERVER__FOLLOWER__MANAGED_INGRESS_LOCAL_ROOT: /data/managed-ingress
      ASTER__DATABASE__URL: sqlite:///data/asterdrive.db?mode=rwc
      ASTER_BOOTSTRAP_REMOTE_MASTER_URL: https://drive.example.com
      ASTER_BOOTSTRAP_REMOTE_ENROLLMENT_TOKEN: enr_replace_me
    volumes:
      - ./data:/data
      - /etc/localtime:/etc/localtime:ro
    restart: unless-stopped

The easiest confusion here is between two classes of environment variables:

  • ASTER__... These are long-term runtime configuration overrides. They use the same structure as config.toml, and values that should remain effective long term should stay here.
  • ASTER_BOOTSTRAP_REMOTE_* These are single-use bootstrap inputs. Remove them after first enrollment succeeds.

Understand the ENV values used on this page like this:

Environment variablePurposeRecommendation
ASTER__SERVER__HOSTMakes the in-container service listen on all interfaces for Docker port mappingUsually keep in Docker setups
ASTER__SERVER__START_MODESwitches the instance into follower modeKeep long term for follower nodes
ASTER__SERVER__FOLLOWER__MANAGED_INGRESS_LOCAL_ROOTRestricts local receiving targets pushed by the primary to this root directoryKeep if local receiving targets are needed
ASTER__DATABASE__URLSpecifies the follower's own databaseRecommended to set explicitly in Docker
ASTER_BOOTSTRAP_REMOTE_MASTER_URLPrimary address used during first enrollmentRemove after success
ASTER_BOOTSTRAP_REMOTE_ENROLLMENT_TOKENSingle-use enrollment token generated by the primaryRemove after success

Receiving targets are not passed in bootstrap ENV. The current flow is: the follower enrolls first, then the primary node pushes receiving targets through the follower API. The entry is Admin -> Follower Nodes, which is better for later review, modification, and troubleshooting.

4. First Startup

bash
docker compose up -d
docker logs -f asterdrive-follower

Normally, first startup completes these steps in order:

  1. Automatically generate config when /data/config.toml does not exist.
  2. Start in follower mode.
  3. Use ASTER_BOOTSTRAP_REMOTE_MASTER_URL and ASTER_BOOTSTRAP_REMOTE_ENROLLMENT_TOKEN to exchange bootstrap information with the primary.
  4. Write the primary binding into the local database.
  5. Continue follower runtime initialization.

You should see log messages like:

  • Configuration loaded from: /data/config.toml
  • bootstrapped follower enrollment from environment
  • startup complete - listening on 0.0.0.0:3000

On this path, you do not need to run node enroll manually, and you do not need an extra restart after first startup.

Bootstrap ENV must appear as a pair

ASTER_BOOTSTRAP_REMOTE_MASTER_URL and ASTER_BOOTSTRAP_REMOTE_ENROLLMENT_TOKEN must be set together.

If only one is set, the service will report incomplete configuration early in startup. If neither is set, it starts as a normal follower and does not auto-enroll.

5. Verify the Follower Is Ready

Check container status first:

bash
docker ps

Then check health directly:

bash
curl http://127.0.0.1:3001/health
curl http://127.0.0.1:3001/health/ready

Expected result:

  • /health returns 200.
  • /health/ready should also return 200 after enrollment succeeds and startup completes.

Then go back to the primary admin panel:

text
Admin -> Follower Nodes

Click "Test Connection". After it passes, open the follower node details and create a default receiving target.

When the connection test passes, the primary also reads the follower's internal storage protocol capabilities. The current internal protocol version is v2. If the capability summary says the protocol is incompatible, upgrade the primary or follower before creating remote policies.

For the first receiving target, choose:

  • Driver: local
  • Base path: a relative path such as default
  • Check "Set as default receiving target"

The path for a local receiving target is restricted under the follower's server.follower.managed_ingress_local_root. If you want the follower to write to S3 / MinIO instead, create an s3 receiving target here too, not through bootstrap ENV.

After the receiving target is applied, go to:

text
Admin -> Storage Policies

Create a storage policy of type Follower Node.

If the follower policy uses presigned upload or download, also confirm the browser can access the follower base_url, and that the reverse proxy in front of the follower does not strip CORS headers from internal storage APIs. Uploads need to allow content-type and expose ETag; Range downloads need to allow range and expose Accept-Ranges, Content-Range, and Content-Length.

6. Remove Single-Use Bootstrap ENV After First Success

After confirming the follower is ready, the primary connection test passes, and the default receiving target has been applied, remove these ENV values from Compose:

  • ASTER_BOOTSTRAP_REMOTE_MASTER_URL
  • ASTER_BOOTSTRAP_REMOTE_ENROLLMENT_TOKEN

Then run again:

bash
docker compose up -d

The primary binding has already been persisted in the database. Later follower restarts do not need bootstrap again. But long-term runtime settings such as ASTER__SERVER__START_MODE=follower should still remain.

Common Issues

Logs Say the Token Is Completed, Expired, or Replaced

This means you are using an old token. Generate a new enrollment token in the primary admin panel, then update Compose.

/health Is 200 but /health/ready Is Still 503

This usually means the follower process is alive, but the primary binding has not taken effect. Check first:

  • whether bootstrap ENV values are correct
  • whether the token has expired
  • whether the binding was actually written into the follower local database
  • whether bootstrap failure warnings appear in logs

The Follower Starts, but the Primary Connection Test Fails

Check these three things first:

  • Whether the base_url in the primary admin panel is an address the primary can actually reach.
  • Whether port mapping, reverse proxy, or NAT routes traffic correctly to the follower's 3000.
  • Whether the follower server.host allows external access.

Existing /data/config.toml Still Says primary

The safest options are:

  • directly change [server].start_mode to follower in /data/config.toml
  • or keep ASTER__SERVER__START_MODE=follower in Compose long term, as shown above

The bootstrap token does not automatically change an existing primary config to follower. Change start_mode explicitly, or keep the environment override long term.

If startup includes ASTER_BOOTSTRAP_REMOTE_* but the final loaded mode is still primary, the service stops and asks you to switch to follower first. This prevents accidentally enrolling a primary instance as a follower node.

Released under the MIT License