diff --git a/README.md b/README.md index c4fca918..339fdd4d 100644 --- a/README.md +++ b/README.md @@ -4,6 +4,15 @@ HomeCloud: your own AWS, on your hardware

+

+ Latest release + CI status + License: AGPL-3.0 + Docker image: ghcr.io/solinode/homecloud + Terraform modules: 17 of 17 pass + Discord +

+ **A self-hosted, AWS-compatible cloud in one binary: point your real Terraform, AWS CLI and SDK code at it, and it runs on real containers and VMs on your machine.**

diff --git a/pages/guides.css b/pages/guides.css new file mode 100644 index 00000000..17f0100e --- /dev/null +++ b/pages/guides.css @@ -0,0 +1,81 @@ +/* Guide pages. Loaded after site.css and uses its tokens, header, footer and code styles. */ + +.g-hero { position: relative; isolation: isolate; padding: 48px 0 8px; } +.g-hero .hero-bg { height: 640px; } +.crumbs { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; list-style: none; padding: 0; font-size: 13.5px; color: var(--faint); } +.crumbs li { display: inline-flex; align-items: center; gap: 6px; } +.crumbs li + li::before { content: "/"; color: var(--line-3); } +.crumbs li a { color: var(--muted); text-decoration: none; transition: color .15s; } +.crumbs li a:hover { color: var(--fg); } +.crumbs [aria-current] { color: var(--fg-2); } +.g-hero .eyebrow { margin-top: 28px; } +.g-hero h1 { margin-top: 16px; max-width: 860px; font-size: clamp(34px, 5vw, 56px); letter-spacing: -0.045em; line-height: 1.04; } +.g-hero .lead { max-width: 760px; margin-top: 18px; } +.g-meta { margin-top: 18px; display: flex; flex-wrap: wrap; gap: 6px 18px; font: 13px/1.5 var(--mono); color: var(--faint); } + +.g-layout { display: grid; grid-template-columns: minmax(0, 1fr) 248px; gap: 64px; align-items: start; padding-top: 40px; } +.g-aside { position: sticky; top: 96px; display: grid; gap: 20px; font-size: 14px; } +.g-aside h2 { font: 500 12px/1 var(--mono); text-transform: uppercase; letter-spacing: .08em; color: var(--faint); margin-bottom: 12px; } +.g-aside ol, .g-aside ul { list-style: none; padding: 0; display: grid; gap: 2px; } +.g-aside li a { display: block; padding: 5px 0 5px 12px; border-left: 1px solid var(--line-2); color: var(--muted); text-decoration: none; line-height: 1.4; transition: color .15s, border-color .15s; } +.g-aside li a:hover { color: var(--fg); border-left-color: var(--accent); } + +/* prose */ +.prose { max-width: 740px; font-size: 16.5px; line-height: 1.7; color: var(--fg-2); } +.prose > * + * { margin-top: 18px; } +.prose h2 { margin-top: 56px; font-size: clamp(25px, 3vw, 31px); letter-spacing: -0.035em; line-height: 1.15; color: var(--fg); scroll-margin-top: 88px; } +.prose h3 { margin-top: 34px; font-size: 19px; letter-spacing: -0.02em; line-height: 1.3; color: var(--fg); scroll-margin-top: 88px; } +.prose h2 + *, .prose h3 + * { margin-top: 14px; } +.prose > :first-child { margin-top: 0; } +.prose ul, .prose ol { padding-left: 22px; display: grid; gap: 8px; } +.prose li::marker { color: var(--faint); } +.prose strong { color: var(--fg); } +.prose .code, .prose .g-table, .prose .try, .prose .note-box { margin-top: 22px; } +.prose .code + p, .prose .g-table + p { margin-top: 22px; } +.prose :not(pre) > code { white-space: normal; overflow-wrap: anywhere; } +.prose .ticks { margin-top: 16px; font-size: 16px; } + +.note-box { padding: 16px 18px; border-radius: 12px; border: 1px solid var(--line-2); background: var(--panel); font-size: 15px; color: var(--muted); } +.note-box b { color: var(--fg); } +.note-box.warn { border-color: color-mix(in srgb, var(--warn) 35%, transparent); background: color-mix(in srgb, var(--warn) 6%, var(--panel)); } + +/* tables */ +.g-table { border-radius: var(--radius); border: 1px solid var(--line); background: var(--panel); overflow-x: auto; } +.g-table table { width: 100%; border-collapse: collapse; font-size: 14.5px; line-height: 1.55; } +.g-table th, .g-table td { text-align: left; padding: 12px 16px; border-top: 1px solid var(--line); vertical-align: top; } +.g-table thead th { border-top: 0; font: 500 12px/1.3 var(--mono); text-transform: uppercase; letter-spacing: .06em; color: var(--faint); padding-top: 15px; } +.g-table tbody th { font-weight: 600; color: var(--fg); white-space: nowrap; } +.g-table td { color: var(--muted); } +.g-table .us { color: var(--fg-2); } +.g-table thead .us { color: var(--accent-ink); } +.g-wide table { min-width: 640px; } + +/* try it */ +.try { position: relative; overflow: hidden; padding: 24px; border-radius: 18px; border: 1px solid var(--line-2); background: var(--panel); background-image: radial-gradient(ellipse 70% 80% at 100% 0%, var(--accent-soft), transparent 70%); } +.try h2, .prose .try h2 { margin: 0; font-size: 20px; letter-spacing: -0.025em; } +.try > p { margin-top: 8px; font-size: 15px; color: var(--muted); } +.try .cmd { margin-top: 16px; } +.try .cmd pre { font-size: 13.5px; } +.try-actions { margin-top: 16px; display: flex; flex-wrap: wrap; gap: 10px; } +.try-note { margin-top: 12px; font-size: 13.5px; color: var(--faint); } + +/* related guides */ +.related { margin-top: 88px; padding-top: 40px; border-top: 1px solid var(--line); } +.related h2 { font-size: clamp(24px, 3vw, 30px); letter-spacing: -0.035em; } +.related .guide-grid { margin-top: 24px; } + +@media (max-width: 1080px) { + .g-layout { grid-template-columns: minmax(0, 1fr); gap: 0; } + .g-aside { display: none; } +} +@media (max-width: 640px) { + .g-hero { padding-top: 28px; } + .g-hero h1 { font-size: clamp(30px, 8.6vw, 40px); } + .g-layout { padding-top: 28px; } + .prose { font-size: 16px; } + .prose h2 { margin-top: 44px; } + .try { padding: 18px; } + .try-actions .btn { flex: 1; justify-content: center; } + .g-table th, .g-table td { padding: 10px 12px; } + .related { margin-top: 64px; } +} diff --git a/pages/homecloud-vs-localstack/index.html b/pages/homecloud-vs-localstack/index.html new file mode 100644 index 00000000..2bcb5c91 --- /dev/null +++ b/pages/homecloud-vs-localstack/index.html @@ -0,0 +1,254 @@ + + + + + +HomeCloud vs LocalStack: an honest comparison + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+ + + +
+
+
+ +
+ +

Comparison

+

HomeCloud vs LocalStack

+

Both run AWS APIs on your own machine. LocalStack emulates a very wide range of services; HomeCloud covers about 30 and runs each on a real engine, with IAM always enforced and a console built in. This is the side-by-side, including the rows where LocalStack wins.

+

HomeCloud v0.4.0Updated 2026-10-116 min read

+
+
+ +
+
+

We maintain HomeCloud, so read this with that in mind. We have tried to state LocalStack's strengths as plainly as our own, and the source for every row is our comparison document, which also covers moto, MinIO with k3s, OpenStack and the AWS free tier. LocalStack changes quickly: check its current documentation and licensing before deciding.

+ +

At a glance

+
+ + + + + + + + + + + + + + + + + +
HomeCloud compared with LocalStack Community and LocalStack Pro
HomeCloudLocalStack CommunityLocalStack Pro
AWS APIsAbout 30 servicesCore servicesThe most services of any emulator
Behind the APIReal engines in Docker: Lambda runtime images, PostgreSQL/MySQL/MariaDB, Redis/Valkey, MinIO, nginx, CoreDNSEmulation; some services start real containers (for example Lambda)Emulation plus real engines for several services
IAM enforcementOn by default, one evaluator for every serviceNot enforcedAvailable, opt-in
Web consoleBuilt in, works offline, modeled on AWS'sHosted web app, needs an accountHosted web app
PersistenceState on disk by default; backup and restore commandsEphemeral by defaultPersistence and snapshots
DeploymentOne Go binary plus Docker, or one imageOne containerOne container plus a licence
Regions / accountsOne region, one accountManyMany
Multi-nodeNo (designed, not built)NoNo
Cost and licenceFree, AGPL-3.0, no paid tierFree tier; check current termsPaid subscription
MaturityYoung: first release September 2026Mature, large communityMature, commercial support
+
+

"Yes" in a row never means "the same as AWS". Every emulator has gaps; HomeCloud's are listed per service and per operation in docs/aws-compat.md.

+ +

Where HomeCloud is stronger

+
    +
  • Real workloads by default. RDS gives you a real PostgreSQL, MySQL or MariaDB; ElastiCache a real Redis or Valkey; EC2 instances are containers you can shell into, or QEMU/KVM virtual machines for two images; ECS services sit behind a real nginx load balancer; security groups really filter traffic. With LocalStack Community several of these services are not available, and with Pro the depth varies per service.
  • +
  • IAM is always on. Requests from the CLI, SDKs, Terraform and the console go through one policy evaluator with resource policies, conditions, permissions boundaries and iam:PassRole. A test that passes has at least been checked for the permissions it needs.
  • +
  • A console in the box, with CloudWatch metrics and logs for every resource and a CloudTrail record of every API call, so a failed run can be inspected rather than guessed at.
  • +
  • Built to be left running: IAM users and access keys for a team or a class, backups, upgrades, TLS, a system service.
  • +
  • Fully open source. Every feature is in the AGPL-3.0 code.
  • +
+ +

Where LocalStack is stronger

+
    +
  • Service coverage. LocalStack Pro covers far more services and operations. Kinesis, EKS, Athena, Glue, OpenSearch, REST API Gateway, WebSocket APIs and AppSync are not in HomeCloud.
  • +
  • Multi-region and multi-account setups work. HomeCloud has us-east-1 and one account; cross-region features are refused.
  • +
  • Start-up time and footprint. A single container emulating services in-process is light. HomeCloud starts MinIO on first boot and real engines on demand, which takes longer and uses more memory.
  • +
  • Ecosystem and maturity: years of production use, the awslocal, tflocal and cdklocal wrappers, testing integrations, extensive documentation and commercial support.
  • +
+ +

The same test on each

+

A concrete way to see the difference is a test that depends on permissions. Give a user read-only access to S3 and try to write:

+
+
shellHomeCloud
+
homecloud iam create-user reader --policy AmazonS3ReadOnlyAccess
+homecloud iam create-access-key reader
+# with reader's keys exported:
+aws s3 cp ./report.csv s3://reports/          # fails with AccessDenied, as on AWS
+
+

On an emulator that does not enforce IAM, the same upload succeeds, and the missing permission shows up only after deployment. Conversely, if the test needs Kinesis, it cannot run on HomeCloud at all.

+ +

Other options

+
+ + + + + + + + + +
Other ways to run AWS without AWS
ToolPick it when
motoYou want fast, in-process mocks for Python unit tests that reset between tests.
MinIO + k3sYou only need S3-compatible storage, plus Kubernetes for compute.
OpenStackYou need a multi-node private cloud with real VMs, and have people to run it.
AWS itselfYou need exactly AWS's behavior. For final integration and staging tests, nothing replaces it.
+
+ +

So which one?

+

Use HomeCloud when your stack fits within its services and you want real compute, enforced IAM, a console and persistent state on your own machine or server, for free. Use LocalStack when you need wider coverage, several regions or accounts, or the lightest possible container in CI. Many teams will reasonably use both. If you are moving tests over, the LocalStack alternative guide lists what to change; for specific workloads see Terraform, Lambda and self-hosting.

+

Spotted something out of date about LocalStack or HomeCloud? Open an issue or a pull request against docs/comparison.md.

+ + +
+ +
+ + +
+
+ + + + + + diff --git a/pages/index.html b/pages/index.html index 8d3bc2ae..f5b8cae2 100644 --- a/pages/index.html +++ b/pages/index.html @@ -51,6 +51,7 @@ Services Tests & CI Self-hosting + Guides Docs Demo @@ -576,6 +577,23 @@

Open source, all of it.

+
+
+
+

Guides

+

Guides for common setups.

+
+ +
+
+