Skip to content
article

Developer survival guide from Tehran: npm, Docker, Go, GitHub and the 403 lifestyle

What breaks, what still works, and how a team of 14 keeps shipping

Arash Karimi@arash_403

July 12, 2026 · 3 min read

سلام. I write backend for a ride hailing and delivery app in Tehran, Go and Python, team of 14. Many people outside do not know what sanctions mean for a normal developer, and many developers in other sanctioned countries ask me the same questions. So this is the long version. Everything here is about using public open source and running things ourselves. Nothing exotic.

The real problem is over-compliance

US sanctions are written for governments and banks. But companies are afraid of fines, so they block much more than the law asks. Blocking a whole country by IP is cheap for them. For us it means a random 403 in the middle of a build.

What works, what does not

  • GitHub: in 2019 GitHub restricted accounts from Iran. In January 2021 they announced they got a license and restored service for developers in Iran. So today GitHub mostly works for us. Paying for anything on it does not, we have no international cards.
  • Google Play: we cannot open developer accounts. Iranian apps go to local stores like Cafe Bazaar and Myket.
  • Cloud (AWS, GCP, Azure): no. Accounts get closed when they notice. We run on local data centres.
  • Paid SaaS: no payment rails, so no paid SaaS. Everything is self-hosted: Gitea, Sentry, Grafana, Prometheus.
  • Package registries: the registries themselves mostly work. What breaks is install scripts that download binaries from somewhere that blocks us.

npm: the postinstall problem

Some packages download a binary during install from cloud storage. When that storage gives 403, your npm ci dies. Most of these packages have an environment variable to skip or redirect the download:

# puppeteer: do not download Chrome, use the system one
export PUPPETEER_SKIP_DOWNLOAD=true          # older versions: PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=true
export PUPPETEER_EXECUTABLE_PATH=/usr/bin/chromium

# electron: download from a mirror you can reach
export ELECTRON_MIRROR="https://your-mirror.example/electron/"

# and the registry itself, if you run Verdaccio
npm config set registry http://verdaccio.internal:4873/

Go

go env -w GOPROXY=http://athens.internal:3000,https://goproxy.io,direct
go env -w GOSUMDB=off   # only if sum.golang.org is unreachable for you, and know what you lose

Turning off the checksum database is a real security trade-off. We keep go.sum in git and review changes to it in PRs, so at least we notice if something changes under us.

Docker

We run a pull-through cache with the official registry image, and every machine uses it as a mirror. The cache itself fills from a public mirror that Iranian hosting companies run.

# /etc/docker/daemon.json
{
  "registry-mirrors": ["http://registry-cache.internal:5000"]
}
# docker-compose.yml for the cache
services:
  cache:
    image: registry:2
    environment:
      REGISTRY_PROXY_REMOTEURL: https://registry-1.docker.io
    volumes:
      - ./registry-data:/var/lib/registry
    ports:
      - "5000:5000"

Python, Flutter, Gradle

  • pip: pip config set global.index-url http://devpi.internal/root/pypi/+simple/ with devpi as cache.
  • Flutter: PUB_HOSTED_URL and FLUTTER_STORAGE_BASE_URL point to mirrors. Same variables developers in China use.
  • Gradle: put your mirror first in repositories in settings.gradle, and keep the Gradle cache warm on CI.

My opinion (labelled, Marta)

Sanctions are made to pressure a government. The government has its own channels and its own money. The person who cannot get a free cloud tier to learn Kubernetes is a 22 year old junior who probably disagrees with the government more than you do. I understand why sanctions exist. I do not understand why they are designed to hit exactly the people who would build a different future.

Hafez, as always:
یوسف گم گشته باز آید به کنعان غم مخور

And if you are in Cuba, Syria, Venezuela, Sudan, or anywhere with the same 403: comment your tricks, let's make the list longer.

Written by

Arash Karimi

Backend dev in Tehran. Go + Python. My error log is 40% code and 60% "403 Forbidden: your country is not supported". سلام 👋

Get the best of #wars_votes_and_wires weekly

One email each Monday with the most useful posts. No spam; unsubscribe in one click.

Comments

14

Sign in to join the conversation.

Sign in to comment
Karl Lindqvist@kernel_karl3 rep in Wars, Votes and Wires
The pull-through cache is the correct answer for everyone, sanctioned or not. Docker Hub rate limits hit us in Gothenburg too. The GOSUMDB caveat is honest, thank you for writing it.
4 net votes
Jordan Pike@jpike#7 in Wars, Votes and Wires
sanctions that block a junior dev from a free tier while the regime's own people buy whatever they want through front companies are the policy version of a firewall rule that blocks users and lets the attacker through. the over-compliance part is the real story and almost nobody covers it
6 net votes
Arash Karimi@arash_403#1 in Wars, Votes and Wires
Exactly, my friend. Over-compliance is bigger problem than the law itself.
8 net votes
Brett Hollister@brett_hsv6 rep in Wars, Votes and Wires
Respectfully brother, I'm for sanctions on the regime and I'm not changing on that. But blocking a dev from an npm postinstall download isn't hurting the IRGC none. I reckon there's a smarter way to write these rules. my 2 cents
6 net votes
Arash Karimi@arash_403#1 in Wars, Votes and Wires
Thank you, this is fair and honest. We can disagree on sanctions and agree on npm)
6 net votes
Onyeka Obi@onyeka_hottakes7 rep in Wars, Votes and Wires
and the same governments sanctioning you sell weapons to everybody else. hypocrisy as a service
10 net votes
Arash Karimi@arash_403#1 in Wars, Votes and Wires
Maybe. But I don't want to make this thread about who is worse. I only want my npm install to finish)
10 net votes
Nate Calloway@nostep_nate7 rep in Wars, Votes and Wires
Rare agreement with jpike. Sanctions are central planning for foreign policy. They hurt the wrong people and they don't work. Cuba: 60+ years. How's that going?
5 net votes
Jordan Pike@jpike#7 in Wars, Votes and Wires
don't get used to it nate
5 net votes
Hiba Osman@hiba_dxb5 rep in Wars, Votes and Wires
This brings back Khartoum university for me. Half the downloads we needed gave us 403 in those years, we passed USB sticks with JDK installers around the lab. Ya zol, it is 2026 and it is the same story with different logos.
10 net votes
Youssef Abdelrahman@youssef_eg1 rep in Wars, Votes and Wires
Egypt is not even sanctioned and half the payment forms still reject my card 😂 respect ya 3am
3 net votes
Kabir Sethi@0xkabir2 rep in Wars, Votes and Wires
the puppeteer env var tip saved me 20 min on a CI box that can't reach google storage lol. good writeup bhai
8 net votes
José Gregorio Marcano@chamo_coder1 rep in Wars, Votes and Wires
Pana, same vaina in Venezuela. App store payouts blocked, cloud signups rejected, Stripe no existe para nosotros. Your list is better than ours, burda de útil. Adding devpi to our setup this week. Saludos desde Valencia.
6 net votes
Arash Karimi@arash_403#1 in Wars, Votes and Wires
Saludos my friend. Please write your list here too, I want to learn from you also.
6 net votes