Floci AWS Local Emulator on Ubuntu 24.04 on Azure User Guide
Overview
This guide covers the deployment and use of Floci 1.6.0 on Ubuntu 24.04 on Azure using cloudimg Azure Marketplace images.
Floci is a free, open source, MIT licensed local AWS emulator, a self hosted alternative to LocalStack. It gives you AWS shaped services on a single virtual machine without a cloud account, an auth token, or paid feature gates. Point your AWS SDK, CLI, Terraform, CDK, OpenTofu or test suite at http://localhost:4566 and keep your existing workflows, so teams can develop against AWS APIs and run continuous integration without spending on real cloud resources or per developer licences.
Floci is headless. It has no web interface: it is an emulator that speaks the AWS wire protocol. Everything below is done with the AWS CLI, an AWS SDK such as boto3, Terraform, or plain HTTP against port 4566.
It is lightweight. Floci 1.6.0 is a Quarkus native binary, not a heap heavy JVM. On this image the emulator idles at roughly 15 to 25 MiB of memory, so the recommended Standard_B2s (2 vCPU, 4 GB) runs it with very large headroom.
Security by design. Floci is auth-less by design, which is correct for a local development tool but dangerous as an open service on a public address, since an open AWS emulator is a service abuse and compute consumption surface. This image inverts that default:
-
The emulator port 4566 is closed in the network security group. The image ships with only SSH (port 22) open. A fresh appliance therefore never exposes an unauthenticated AWS emulator to the internet.
-
You reach the emulator deliberately. Either tunnel it over SSH (recommended, zero configuration) so it is only ever reachable from your own machine, or open port 4566 in the NSG restricted to your own source addresses, behind your VPN, peering or firewall. Floci binds
0.0.0.0:4566inside the VM, so both paths work, but it is the NSG, not the bind, that is the gate. -
There is no bootstrap credential. Floci is a fake AWS: it holds no real cloud credentials and accepts any non-empty access key and secret. There is no dashboard, no admin account and no default password baked into the image, so there is nothing to leak and nothing to seize.
What is included:
- Floci 1.6.0, the official upstream container pinned by image digest and captured into the image, so first boot is instant with no pull
- The emulator managed by one systemd service,
floci.service, that starts on boot, withfloci-firstboot.servicewriting the appliance information note on first start - Emulation of S3, SQS, EC2, ECS, Lambda, RDS, DynamoDB, ElastiCache, OpenSearch and around 69 AWS services on port 4566, using real Docker backed execution for the services that need it
- Docker Engine and the AWS CLI v2 preinstalled, so the emulator can be exercised the moment you connect
- A clean, empty emulator on first boot with no baked data and no default login
- Unattended security upgrades left enabled so the appliance keeps receiving patches
Prerequisites
- Active Azure subscription, an SSH public key, and a VNet and subnet in the target region
- Subscription to this listing on Azure Marketplace
- A Network Security Group allowing TCP 22 for administration. Port 4566 stays closed: reach the emulator over an SSH tunnel, or add a 4566 rule yourself later, restricted to the source addresses that need it rather than open to the internet.
Recommended virtual machine size: Standard_B2s (2 vCPU, 4 GB RAM) is ample for the core emulator and typical development and CI use. If you drive many Docker backed services at once (for example emulated RDS, ElastiCache or OpenSearch instances, each of which runs as an additional container), choose a larger size such as Standard_D2s_v5 or above.
Deploy the virtual machine
Deploy from the Azure Portal by selecting the image from Azure Marketplace, choosing your VM size, and supplying your SSH public key for the azureuser account. Keep the default inbound rules: SSH only. Do not open port 4566 to the internet.
Confirm the emulator is healthy
SSH in as azureuser and confirm the service is up. Floci exposes a LocalStack compatible liveness endpoint at /_localstack/health that lists which services are running and discloses nothing sensitive.
systemctl is-active docker.service floci.service
active
active
curl -s http://127.0.0.1:4566/_localstack/health | head -c 300
{"services":{"ssm":"running","sqs":"running","s3":"running","dynamodb":"running","sns":"running","lambda":"running","apigateway":"running","iam":"running","kafka":"running","mq":"running","elasticache":"running","memorydb":"running","rds":"running", ... }
The emulator runs as a single Quarkus native container under systemd, and stays tiny:
docker stats --no-stream --format '{{.Name}} MEM={{.MemUsage}} CPU={{.CPUPerc}}' floci
floci MEM=26.58MiB / 2GiB CPU=0.01%

Connect from your own machine
Because port 4566 is closed in the NSG, the clean way to reach the emulator is an SSH tunnel. It forwards your local localhost:4566 to the emulator on the VM, so the endpoint is only ever reachable from your own machine and never from the internet. Run this on your machine:
$ ssh -L 4566:localhost:4566 azureuser@<vm-ip>
Leave that session open. Now, in another terminal on your machine, any AWS tool that points at http://localhost:4566 reaches Floci. Floci is a fake AWS, so any non-empty credentials work:
$ export AWS_ACCESS_KEY_ID=test AWS_SECRET_ACCESS_KEY=test AWS_DEFAULT_REGION=us-east-1
$ aws --endpoint-url http://localhost:4566 s3 ls
If you would rather your team reach it directly, add an inbound NSG rule for TCP 4566 restricted to your own source address ranges (never 0.0.0.0/0), and set AWS_ENDPOINT_URL=http://<vm-ip>:4566.
Point your AWS tools at Floci
The commands below run on the VM itself (over your SSH session), where localhost:4566 reaches the emulator directly; from your own machine they are identical once the tunnel above is open. This is a real S3 round trip driven by the unmodified AWS CLI: a bucket is created, an object is written, listed, read back, and the two SHA 256 checksums match exactly.
export AWS_ACCESS_KEY_ID=test AWS_SECRET_ACCESS_KEY=test AWS_DEFAULT_REGION=us-east-1 AWS_PAGER=""
head -c 1048576 /dev/urandom > /tmp/demo-src.bin
aws --endpoint-url http://localhost:4566 s3 mb s3://cloudimg-demo
aws --no-progress --endpoint-url http://localhost:4566 s3 cp /tmp/demo-src.bin s3://cloudimg-demo/dataset.bin
aws --endpoint-url http://localhost:4566 s3 ls s3://cloudimg-demo/
aws --no-progress --endpoint-url http://localhost:4566 s3 cp s3://cloudimg-demo/dataset.bin /tmp/demo-out.bin
sha256sum /tmp/demo-src.bin /tmp/demo-out.bin
make_bucket: cloudimg-demo
upload: /tmp/demo-src.bin to s3://cloudimg-demo/dataset.bin
2026-08-07 23:21:12 1048576 dataset.bin
download: s3://cloudimg-demo/dataset.bin to /tmp/demo-out.bin
9ca07b3b2ddc1ae919c1219e0f7c73f0dffd95813e77ae264174261729b1cbf2 /tmp/demo-src.bin
9ca07b3b2ddc1ae919c1219e0f7c73f0dffd95813e77ae264174261729b1cbf2 /tmp/demo-out.bin

More AWS services at once
Floci emulates many services behind the same endpoint. Here SQS carries a message end to end, EC2 answers a describe call, and DynamoDB stores and returns an item.
export AWS_ACCESS_KEY_ID=test AWS_SECRET_ACCESS_KEY=test AWS_DEFAULT_REGION=us-east-1 AWS_PAGER=""
QURL=$(aws --endpoint-url http://localhost:4566 sqs create-queue --queue-name demo-queue --query QueueUrl --output text)
aws --endpoint-url http://localhost:4566 sqs send-message --queue-url "$QURL" --message-body "hello-from-cloudimg" >/dev/null
aws --endpoint-url http://localhost:4566 sqs receive-message --queue-url "$QURL" --query 'Messages[0].Body' --output text
aws --endpoint-url http://localhost:4566 ec2 describe-regions --query 'Regions[0:4].RegionName' --output text
aws --endpoint-url http://localhost:4566 dynamodb create-table --table-name demo \
--attribute-definitions AttributeName=id,AttributeType=S --key-schema AttributeName=id,KeyType=HASH \
--billing-mode PAY_PER_REQUEST >/dev/null 2>&1 || true
aws --endpoint-url http://localhost:4566 dynamodb put-item --table-name demo --item '{"id":{"S":"1"},"v":{"S":"cloudimg"}}'
aws --endpoint-url http://localhost:4566 dynamodb get-item --table-name demo --key '{"id":{"S":"1"}}' --query 'Item.v.S' --output text
hello-from-cloudimg
us-east-1 us-east-2 us-west-1 us-west-2
cloudimg

Use it from your applications and Terraform
Any AWS SDK works the same way: set the endpoint and any dummy credentials. With boto3, from your application code:
import boto3
s3 = boto3.client(
"s3",
endpoint_url="http://localhost:4566",
aws_access_key_id="test",
aws_secret_access_key="test",
region_name="us-east-1",
)
s3.create_bucket(Bucket="app-bucket")
s3.put_object(Bucket="app-bucket", Key="hello.txt", Body=b"hi")
print([o["Key"] for o in s3.list_objects_v2(Bucket="app-bucket").get("Contents", [])])
Terraform and OpenTofu point their AWS provider at the same endpoint, so plan and apply run against Floci instead of a real account:
provider "aws" {
region = "us-east-1"
access_key = "test"
secret_key = "test"
skip_credentials_validation = true
skip_requesting_account_id = true
s3_use_path_style = true
endpoints {
s3 = "http://localhost:4566"
sqs = "http://localhost:4566"
dynamodb = "http://localhost:4566"
}
}
resource "aws_s3_bucket" "demo" {
bucket = "terraform-demo"
}
Secure by default in practice
Floci is a fake AWS: the identity call returns the placeholder account 000000000000, confirming it holds no real cloud credentials. The emulator is bound inside the VM, and port 4566 is closed in the NSG, so it is only reachable over your SSH tunnel or a rule you open yourself. The appliance information note on the VM records the posture and how to connect.
export AWS_ACCESS_KEY_ID=test AWS_SECRET_ACCESS_KEY=test AWS_DEFAULT_REGION=us-east-1 AWS_PAGER=""
aws --endpoint-url http://localhost:4566 sts get-caller-identity
ss -tln | grep 4566
{
"UserId": "000000000000",
"Account": "000000000000",
"Arn": "arn:aws:iam::000000000000:root"
}
LISTEN 0 4096 0.0.0.0:4566 0.0.0.0:*

Managing the service
Floci runs as a standard systemd unit:
systemctl status floci.service --no-pager | head -5
● floci.service - Floci - self-hosted AWS local emulator (LocalStack alternative)
Loaded: loaded (/etc/systemd/system/floci.service; enabled; preset: enabled)
Active: active (running)
Restart or stop the emulator with sudo systemctl restart floci.service or sudo systemctl stop floci.service. Configuration is passed to the container through FLOCI_ environment variables; see the upstream configuration reference at https://floci.io/floci/ for options such as the default region, account id and storage mode.
Data and persistence
Emulated state (buckets, objects, queues, tables) is kept in the Docker named volume floci-data, so it survives a service restart. To wipe all emulated state and start clean:
sudo systemctl stop floci.service
sudo docker volume rm -f floci-data
sudo systemctl start floci.service
The shipped image starts empty: it carries no baked buckets, objects or queues.
Troubleshooting
- A client cannot reach
localhost:4566. Confirm the SSH tunnel session is still open, or that you added a restricted NSG rule for TCP 4566. Check the service on the VM withsystemctl is-active floci.serviceand the health endpoint withcurl http://127.0.0.1:4566/_localstack/health. - A Docker backed service (RDS, ElastiCache, OpenSearch) fails to start. These spin up additional containers and need memory and image pulls; on
Standard_B2srun one at a time, or move to a larger VM. Inspect the emulator log withsudo docker logs --tail 100 floci. - Reset everything.
sudo systemctl restart floci.servicerestarts the emulator; removing thefloci-datavolume as above clears all emulated state.
Licensing and support
Floci is free and open source under the MIT License, shipped unmodified. There is no per seat fee. The cloudimg charge covers packaging, security patching, image maintenance and 24/7 support. This image is produced by cloudimg and is not affiliated with, endorsed by, or sponsored by the Floci project; the Floci name is used only to identify the software shipped in this image. Support: support@cloudimg.co.uk