A password typed straight into docker run -e sits in shell history and process listings forever; docker secret create exists so it does not have to. This covers creating a Swarm secret from a file or standard input, confirming Docker stored the object, and removing a disposable test secret once you are done. About fifteen minutes on a running Swarm, using Docker CE CLI 29.8.1.
You need the Docker CLI, access to a Swarm manager, and a secret source you can read; a worker node cannot create Swarm secrets. The command changes cluster state, so do not run these examples against a production name until you have checked both the name and the input. Add sudo only if your Docker socket setup requires it.
Start with read-only checks. Neither creates nor alters a secret:
$ docker secret create --help
Usage: docker secret create [OPTIONS] SECRET [file|-]
Create a secret from a file or STDIN as content
Options:
-d, --driver string Secret driver
-l, --label list Secret labels
--template-driver string Template driver
$ docker version --format 'Client {{.Client.Version}} Server {{.Server.Version}}'
Client 29.8.1 Server 29.8.1
$ docker info --format '{{.Swarm.LocalNodeState}}'
active
The positional form is docker secret create [OPTIONS] SECRET [file|-]. The final argument is either a readable file path or - for standard input; the name is the first positional argument, not a filename or a label.
Checkpoint: continue only if docker info reports active and this node is a manager. Do not initialise a new Swarm just to make a test command run on a host that already belongs to someone else's deployment.
Put the value in a file with permissions suited to your workflow, then pass the path after the name:
$ SECRET_FILE='/path/to/secret.txt'
$ test -r "$SECRET_FILE"
$ docker secret create app_credentials "$SECRET_FILE"
u1j2k3l4m5n6o7p8q9r0s1t2u
That string is the secret ID, generated by Docker and different on every run. Docker reads the file as content; the path itself is never stored as the value.
Do not put a real password directly on a command line if shell history, terminal recording or process monitoring could expose it. Keep the input file private, and only remove it from disk once you have confirmed a required copy exists elsewhere: deleting your only recovery copy is irreversible.
Checkpoint: list the object by name. This shows metadata, never the payload:
$ docker secret ls --filter name=app_credentials
ID NAME CREATED UPDATED
u1j2k3l4m5n6o7p8q9r0s1t2u app_credentials 10 seconds ago 10 seconds ago
Use - when another process already supplies the content. This pattern avoids a second plaintext file on disk, though a real shell should feed the value through a protected input method rather than a placeholder:
$ printf '%s' 'REPLACE_WITH_TEST_VALUE' | docker secret create app_token -
v2w3x4y5z6a7b8c9d0e1f2g3h
printf adds no newline, so the stored value is exactly the bytes it received. This particular example suits a disposable test value only, since the placeholder ends up in shell history. For an existing protected file, the equivalent is:
$ cat -- '/path/to/secret.txt' | docker secret create app_token -
Pipelines hide failures: exit status normally reflects only the last command. Check Docker's own output, then verify the new name separately:
$ docker secret ls --filter name=app_token
ID NAME CREATED UPDATED
v2w3x4y5z6a7b8c9d0e1f2g3h app_token 5 seconds ago 5 seconds ago
Labels are metadata, useful for ownership or rotation tracking, but anyone who can inspect the object can read them too. Never put a password, token or private key in a label:
$ docker secret create \
--label owner=platform \
--label purpose=database \
app_database_password '/path/to/secret.txt'
w3x4y5z6a7b8c9d0e1f2g3h4i
Repeat --label for more than one. Confirm the metadata without asking Docker to print any content:
$ docker secret inspect app_database_password
[
{
"Spec": {
"Name": "app_database_password",
"Labels": {
"owner": "platform",
"purpose": "database"
}
}
}
]
Real output carries more fields, including IDs and timestamps, but never the secret value. That is not a reason to treat the ID, name or labels as harmless: metadata alone can disclose deployment details.
Deleting the source file does not undo the object Docker already created. If this was a test and nothing uses it, remove it explicitly:
$ docker secret rm app_token
app_token
Docker refuses removal while any Swarm service still uses the secret, and that refusal is doing you a favour: identify the service and plan a rotation rather than forcing a change through under pressure. If it is genuinely in use, create a replacement under a new name, update the service during a planned change, verify it, and only then remove the old object.
Confirm the cleanup:
$ docker secret ls --filter name=app_token
ID NAME CREATED UPDATED
The installed CLI also takes --driver and --template-driver, neither required for the ordinary file or standard-input workflow. Docker's reference puts the secret driver at API 1.31 or later and the template driver at 1.37 or later. Driver support depends on the Engine and the deployment, so check the target manager's API compatibility before either flag goes anywhere near automation.
A successful create only proves Docker accepted the request. It proves nothing about whether the consuming service has been updated, whether the application can actually read the secret, or whether a source file has been securely removed. Test each of those separately, with the least sensitive value you can get away with.
docker secret ls without exposing the payload.docker secret inspect.