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 URLis 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_urlthe 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.comhttp://10.0.0.23:3000http://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:
Admin -> Follower NodesCreate 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_urltoken
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:
mkdir -p ./data
sudo chown -R 10001:10001 ./dataIf 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:
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-stoppedThe easiest confusion here is between two classes of environment variables:
ASTER__...These are long-term runtime configuration overrides. They use the same structure asconfig.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 variable | Purpose | Recommendation |
|---|---|---|
ASTER__SERVER__HOST | Makes the in-container service listen on all interfaces for Docker port mapping | Usually keep in Docker setups |
ASTER__SERVER__START_MODE | Switches the instance into follower mode | Keep long term for follower nodes |
ASTER__SERVER__FOLLOWER__MANAGED_INGRESS_LOCAL_ROOT | Restricts local receiving targets pushed by the primary to this root directory | Keep if local receiving targets are needed |
ASTER__DATABASE__URL | Specifies the follower's own database | Recommended to set explicitly in Docker |
ASTER_BOOTSTRAP_REMOTE_MASTER_URL | Primary address used during first enrollment | Remove after success |
ASTER_BOOTSTRAP_REMOTE_ENROLLMENT_TOKEN | Single-use enrollment token generated by the primary | Remove 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
docker compose up -d
docker logs -f asterdrive-followerNormally, first startup completes these steps in order:
- Automatically generate config when
/data/config.tomldoes not exist. - Start in
followermode. - Use
ASTER_BOOTSTRAP_REMOTE_MASTER_URLandASTER_BOOTSTRAP_REMOTE_ENROLLMENT_TOKENto exchange bootstrap information with the primary. - Write the primary binding into the local database.
- Continue follower runtime initialization.
You should see log messages like:
Configuration loaded from: /data/config.tomlbootstrapped follower enrollment from environmentstartup 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:
docker psThen check health directly:
curl http://127.0.0.1:3001/health
curl http://127.0.0.1:3001/health/readyExpected result:
/healthreturns200./health/readyshould also return200after enrollment succeeds and startup completes.
Then go back to the primary admin panel:
Admin -> Follower NodesClick "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:
Admin -> Storage PoliciesCreate 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_URLASTER_BOOTSTRAP_REMOTE_ENROLLMENT_TOKEN
Then run again:
docker compose up -dThe 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_urlin 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.hostallows external access.
Existing /data/config.toml Still Says primary
The safest options are:
- directly change
[server].start_modetofollowerin/data/config.toml - or keep
ASTER__SERVER__START_MODE=followerin 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.