---
title: Russia-reachable static mirror on cloud.ru S3
date: 2026-07-31
tags: aws-s3, static-hosting, nextjs, deployment, geo-blocking
type: success
reproducible: true
---

# Russia-reachable static mirror on cloud.ru S3

My Next.js frontend lived on AWS Amplify, served through CloudFront — and about a
third of its users are in Russia, where AWS edge nodes are unreachable. Those users
did not get an error page. They got a blank screen and a spinner, which is worse,
because nobody files a bug report about a blank screen. They just leave. For six
weeks I only knew something was wrong from two user screenshots.

The task: give Russian users a working URL without forking the codebase, without
telling anyone to install a VPN, and without moving the global site off AWS. Budget:
close to zero. The constraint that shaped everything — the app had to stay one
codebase with one build story.

The route that worked: a static mirror on cloud.ru Object Storage (S3-compatible,
on Russian soil). My agent scripted it end to end: switch Next.js to static export
(output: 'export', with generateStaticParams for every dynamic route, and
middleware.ts moved aside during the build — it is incompatible with export), sync
the out/ directory with the aws CLI pointed at --endpoint-url=https://s3.cloud.ru,
then fix the three gotchas that cost me a day each the first time: HTML files
arrive as binary/octet-stream (browsers download them instead of rendering — every
.html must be re-PUT with an explicit text/html content type), clean URLs need each
page copied to its directory/index.html form, and dynamic routes need a 404-to-SPA
fallback that restores the real id from the query string.

Result: a mirror at the bucket's s3-website.cloud.ru endpoint, reachable from
Russian networks, loading in under a second — confirmed by the same users who sent
the blank-screen screenshots. The global AWS site is untouched, the mirror redeploys
with one script, and the whole thing costs a few cents a month in storage.

## Reproduce this

Prerequisites: a static-exportable frontend (Next.js or similar), a cloud.ru account
with Object Storage enabled.

Your agent will need from you: the bucket name, your cloud.ru access keys (stored as
an aws-cli profile), and the list of dynamic routes to pre-render.

Steps: configure static export and generateStaticParams; move middleware aside for
the build; aws s3 sync out/ with --endpoint-url=https://s3.cloud.ru and public-read;
re-PUT every .html with content-type text/html; copy top-level pages to
directory/index.html form; enable website hosting with a 404-to-index SPA fallback.

Verify: open the website endpoint from a Russian network (or ask one real user) —
pages must render, not download; dynamic routes must restore from the query string.
