Skip to content
doze AWS
0.3

These are the docs for doze AWS 0.3.

Every release on GitHub →

doze-aws is a single static binary. Run it with no arguments to serve every implemented service; it runs in the foreground until you interrupt it (Ctrl-C).

Terminal window
cd ~/code/harbour && doze-aws
# msg=listening addr=127.0.0.1:4566 services=s3,dynamodb,sqs,… instance=harbour
# msg="reachable at" url=http://127.0.0.1:4566

The instance’s label comes from the directory. Nothing is set up on the machine. See endpoints.md for the addressing model.

Command What it does
doze-aws Serve the enabled services (the default). If ./template.yaml exists (or --template names a file), it is applied at boot.
doze-aws doctor What this instance is, where it answers, and whether something answers there. The first thing to run when an SDK cannot connect.
doze-aws env Print the shell block that points an AWS SDK at this instance — endpoint, region, credentials, and the per-service AWS_ENDPOINT_URL_* hostnames. Use it as eval "$(doze-aws env)".
doze-aws apply [--var k=v ...] [file] Deploy a CloudFormation or SAM template (default ./template.yaml): create what’s missing, cheaply update what exists, never delete. --var supplies template parameters. Targets the running server if one is listening, the data dir otherwise. See cloudformation.md.
doze-aws export Write the running stack (queues, tables, buckets, functions, wiring, …) to stdout as a CloudFormation template. Secret values are left blank on purpose.
doze-aws version Print the build version and the list of implemented services.
doze-aws config print [flags] Resolve and print the effective configuration (defaults + config file + flags), then exit. Use it to see exactly what a given invocation would run.

There is no daemon and nothing to install or clean up: state lives under the data directory, and deleting it resets everything.

Flags apply to serving and to config print.

Flag Default Meaning
--config <path> ./doze-aws.toml if present Path to a TOML config file. Relative paths inside it resolve against the file, not against your working directory.
--name <name> the directory’s name This instance’s label, in the console and the log.
--listen <host:port> 127.0.0.1:4566 The address to answer on: another port for a second instance, 0.0.0.0:4566 for a sibling container. See endpoints.md.
--data-dir <dir> ./data, or beside doze-aws.toml Root directory: each region gets a subdirectory, with IAM and STS under _global. The flag resolves against your working directory; the config-file key resolves against the file.
--region <region> us-east-1 Default region for unqualified requests. Others are created on first use.
--account-id <12 digits> 000000000000 The account every ARN carries. Set at creation and effectively frozen — the data records it and a mismatch is refused.
--suffix <host> the instance’s own name What stands in for amazonaws.com in minted hostnames. Set this when a proxy owns the name and forwards to doze-aws on an address.
--services <a,b,…> all implemented Comma-separated subset of services to enable. Unknown names are an error.
--template <path> ./template.yaml if present CloudFormation/SAM template to apply at boot. See cloudformation.md.
--iam-mode <mode> soft IAM enforcement: soft (evaluate and record, never block), off (no evaluation at all), enforce (real denials). See SUPPORT.md.
--console on Serve the web management console at /_console.
--lambda-idle <duration> 10m How long a warm Lambda keeps its process before scaling to zero.
--sqs-strict off Refuse what SQS refuses for 60 seconds after a delete or a purge: re-creating a deleted queue’s name, and purging a queue twice. Both are immediate here by default. See SUPPORT.md.
--yes off Answer yes to the confirmation described below. For scripts, and for anyone who does this daily.

--data-dir, --services, --name and --region ask before proceeding when doze-aws.toml set the same key, because each one produces a running instance that looks like something went wrong:

These flags overrule doze-aws.toml:
--data-dir the resources you had are in the directory the file names, not here
--name URLs minted under the old name stop resolving — nothing claims it once you rename
Continue? [y/N]

Enter alone declines — the safe answer is the one you get by not deciding. Off a terminal (CI, doze-aws &) it explains and proceeds rather than asking a question nobody can answer; --yes skips the question and keeps the explanation. A flag the file did not set overrules no decision and is never questioned.

--account-id is not in that list: a mismatch is refused outright by the data’s own record of the account it was created under, because stored ARNs embed it.

Terminal window
# Only S3 + SQS, with data under /tmp/aws
doze-aws --services s3,sqs --data-dir /tmp/aws
# Watch what IAM would deny, without denying it
doze-aws --iam-mode soft

Service names: s3, dynamodb, sqs, sns, sts, kms, ssm, secretsmanager, eventbridge, lambda, kinesis, iam, cloudformation, apigateway, stepfunctions.

Instead of flags, put settings in doze-aws.toml (auto-loaded from the working directory, or point --config at one elsewhere):

name = "harbour" # the instance's label
region = "ap-south-1"
data-dir = "data" # relative to THIS FILE, not to your shell
services = ["s3", "dynamodb", "sqs"]

Every key is optional; omitted keys fall back to the defaults above.

Paths in this file resolve against the file, the way Cargo.toml and package.json work — so doze-aws --config /srv/harbour/doze-aws.toml run from anywhere puts the data in /srv/harbour/data. An absolute data-dir is used as written, which is how you point at a mounted volume. The --data-dir flag is the exception: typed in a shell, resolved from where you are standing.

Removed keys fail loudly rather than being ignored, and the error names the replacement — [s3] host became --suffix, for instance.

Precedence (lowest to highest): built-in defaults → config file → flags. A key set in the file survives unless the matching flag is explicitly passed, so you can keep a committed doze-aws.toml and override one thing on the command line. Run doze-aws config print to see the resolved result.

Point any AWS SDK or the AWS CLI at the instance. Credentials are not verified, so any non-empty values work. doze-aws env prints the right block for the configuration in front of you, including the per-service hostnames:

Terminal window
eval "$(doze-aws env)"
# or by hand:
export AWS_ENDPOINT_URL=http://127.0.0.1:4566
export AWS_ACCESS_KEY_ID=test AWS_SECRET_ACCESS_KEY=test AWS_REGION=us-east-1
aws sts get-caller-identity
aws s3 mb s3://my-bucket
aws s3 cp ./file.txt s3://my-bucket/
aws dynamodb create-table --table-name items \
--attribute-definitions AttributeName=id,AttributeType=S \
--key-schema AttributeName=id,KeyType=HASH --billing-mode PAY_PER_REQUEST
aws sqs create-queue --queue-name jobs

Both AWS SDK generations work (v1 aws-sdk-go / boto-era and v2 aws-sdk-go-v2), and both signature versions (SigV2 and SigV4) are accepted.

Per-SDK endpoint variables are honored too, so you can send one service elsewhere: AWS_ENDPOINT_URL_S3, AWS_ENDPOINT_URL_DYNAMODB, etc.

Data is written under --data-dir and survives restarts. The layout is one directory per region, with the region-less services under _global:

data/
instance.json what this data was created with — account, region
ap-south-1/ sqs/ s3/ dynamodb/ lambda/ …
eu-west-1/ the same, created on first use
_global/ iam/ sts/

To reset one service in one region, stop doze-aws and delete its directory; to reset everything, delete the whole data directory. There is nothing else to tear down.

instance.json is written by doze-aws, not by you. It records the account and region the data was created under, so starting the same data with a different --account-id is refused rather than silently orphaning every stored ARN — they are embedded in other resources as plain strings, and would break at fire time rather than at startup. A changed default region is reported, not refused: regions are separate directories and the old one’s resources are still there.