Open-source project
pk910/PoWFaucet avatar
pk910/PoWFaucet

PoWFaucet: a self-hosted Sepolia faucet with proof-of-work protection

Modularized faucet for EVM chains with different protection methods (Captcha, Mining, IP, Mainnet Balance, Gitcoin Passport and more)

5,630 stars2,049 forksTypeScriptAGPL-3.0

At a glance

What is it?
pk910/PoWFaucet is a modular TypeScript faucet server for EVM testnets. Its best known module makes requesters mine a proof-of-work challenge before they receive funds, and operators can swap in captcha, IP, mainnet balance or Gitcoin Passport checks instead.
Who is it for?
Adopt PoWFaucet if you run a testnet and need a faucet that a single bot cannot drain, and you are willing to hold the wallet key and fund the balance yourself. Skip it if you need a hosted public faucet with no infrastructure: the project's own instances at sepolia-faucet.pk910.de and hoodi-faucet.pk910.de already serve that case.
Can I use it commercially?
Yes, with strict conditions. AGPL-3.0 is a network copyleft licence: if people use a modified version over a network, for example as a hosted service, you must offer them its source code under the same licence.
Is it still maintained?
Yes. The repository last received commits 3 days ago.
What is it written in?
Mainly TypeScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on September 30, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The bot problem a testnet faucet cannot avoid

A faucet hands out free testnet ETH, which means the only thing standing between the wallet and an automated drain is the cost of making a request. PoWFaucet exists because that cost is normally near zero. The README states the motivation plainly: faucets for ETH testnets are spammed by bots, and the project tries to reduce the efficiency of automated requests through several protection methods. It is aimed at testnet operators and client teams who run their own distribution wallet, not at end users looking for a one-off drip. The project's own instances cover Sepolia, Hoodi and Ephemery, and the README lists them with balance and uptime badges, so the intended audience is whoever pays for and monitors that wallet.

Proof-of-work as a rate limiter, not as coin generation

The README spends a paragraph correcting a common misreading. The mining step does not generate new coins. It is one of several protection methods the faucet uses to stop anyone from requesting a large amount of funds and draining the faucet wallet. In practice that means the client is asked to solve a computational puzzle before the server releases a payout; a browser can solve a small puzzle once, while an attacker trying to claim thousands of addresses pays the puzzle cost on every attempt. That is the whole economic argument, and it is why the project describes PoW as the best and most reliable method on a network that has run low on reserves. The faucet also ships other protection modules, including Captcha, IP, Mainnet Balance and Gitcoin Passport, and the repository describes the server as modularized, so the operator picks a combination rather than accepting one fixed policy.

What the repository layout tells you about the architecture

The top-level entries split the system into a server, a browser client, a WASM component and a set of shared libraries. src/ holds the TypeScript server, faucet-client/ is a separate npm project with its own build-client.js, faucet-wasm/ is the WebAssembly piece that the pow-captcha build script feeds, and libs/ is copied into the compiled output by the test scripts. The Dockerfile confirms the runtime shape: a node:22-slim stage runs npm run bundle to produce a single server bundle, a second stage builds the client, and the final image is nginxinc/nginx-unprivileged:1.27. Nginx serves the static files and proxies /api/ and /ws/ to the Node backend, which is why the container exposes port 8080. Configuration lives in faucet-config.yaml, with faucet-config.example.yaml as the starting point, and the Docker image copies that example into the working directory and creates a writable /data directory for config, database and other runtime files.

Installing PoWFaucet with Docker and making a first request

The README does not repeat installation steps; it points to the Faucet Operator Wiki for installation and configuration instructions and to a demo instances page for module combinations. The Dockerfile is the concrete artefact in the repository. It builds both the server bundle and the client, then runs them behind nginx on port 8080 as the nginx user, with the entrypoint script at /entrypoint.sh and the working directory set to /data.

dockerfile
FROM --platform=$BUILDPLATFORM node:22-slim AS build-server-env
WORKDIR /build
COPY package*.json ./
RUN npm install
COPY ./libs libs
COPY ./tsconfig.json .
COPY ./webpack.config.js .
COPY ./src src
RUN npm run bundle

That stage is the server build. The final stage copies the bundle and the built static assets, then starts nginx with the configuration from docker/nginx.conf, which proxies /api/ and /ws/ to Node. Because the image runs as the unprivileged nginx user and writes to /data, a bind mount for /data is the practical place to keep faucet-config.yaml and the database across restarts.

If you prefer to run from source, package.json defines the scripts. The start script compiles TypeScript and runs the compiled entry point.

bash
npm install
npm run start

npm run start runs tsc and then node dist/app.js, so the server reads faucet-config.yaml from the working directory. There is also a bundle script that runs tsc and webpack in production mode, and a build-client script that changes into faucet-client and runs node build-client.js. The package also declares a bin entry at bundle/powfaucet.cjs and pkg targets for node18-linux-x64 and node18-win-x64, so a packaged binary is part of the release story even though the README does not walk through it.

Secrets do not have to sit in the YAML. The README states that secrets can be injected at runtime instead of being stored in faucet-config.yaml, and it names FAUCET_SECRET, FAUCET_ETH_WALLET_KEY, FAUCET_CAPTCHA_SECRET, FAUCET_GITHUB_APP_SECRET and FAUCET_PASSPORT_SCORER_API_KEY as the local examples. FAUCET_ETH_WALLET_KEY is the one that matters most: the README is explicit that you must transfer the funds you want to distribute to the faucet wallet yourself. A first real use is therefore to set that variable, point the config at your testnet RPC, start the container, and open the served page to submit an address and watch the mining step run in the browser.

Where PoWFaucet is the wrong tool

The proof-of-work module shifts cost onto the requester, and that is also its main weakness. A legitimate user on a low-powered device, or one who simply wants testnet ETH for a quick contract deployment, now waits for a puzzle to solve before the faucet responds. The protection is proportional to the payout, so an operator who sets the difficulty high enough to deter a determined attacker also makes the faucet unpleasant for ordinary users. The README's own framing concedes the context: PoW is described as the best option on a network that has run low on fund reserves, which implies that on a well-funded testnet the trade-off may not be worth it. There is a second constraint that has nothing to do with difficulty. PoWFaucet does not create testnet ETH. An operator who has no source of testnet funds cannot run a useful instance, and the README states that directly rather than burying it. Finally, the documentation surface is thin in the repository itself. Installation and configuration live in the wiki, not in the README, and the README does not document rollback, backup or upgrade procedures for the database under /data.

How PoWFaucet differs from a hosted faucet service

The obvious alternative for most people is a hosted faucet such as the public instances the project itself operates, or a provider-run faucet tied to an infrastructure account. The difference is not the payout, it is who holds the wallet and who absorbs abuse. A hosted service decides its own rate limits and identity checks, and you accept them as given; PoWFaucet puts faucet-config.yaml and the wallet key in your hands, which means you choose the protection module and you fund the balance. That is more work and more risk, and it is the reason the README points operators at the wiki instead of promising a one-command setup. Within the self-hosted space the comparison is between protection modules rather than between products: a captcha module outsources the decision to a third party and needs FAUCET_CAPTCHA_SECRET, a Gitcoin Passport module needs FAUCET_PASSPORT_SCORER_API_KEY, and the PoW module needs neither but costs the requester CPU time. Mixing modules is the point of the modular design.

Maintenance, licensing and upgrade cost

The repository is not archived and the last push was on 2026-09-21, one day before this writing. Recent releases are v2.5.1 from 2026-07-30, v2.5.0 from 2026-05-09, and a Dev Snapshot from 2026-08-28, so versioned releases arrive on a scale of months rather than weeks. The package version in package.json is 2.5.1, matching the latest tagged release. Upgrading means rebuilding: the Dockerfile compiles the server bundle with npm run bundle and the client with node build-client.js, and the image copies faucet-config.example.yaml fresh, so any local edits to that file are not part of the image and belong in the /data mount. The licence is AGPL-3.0, declared in both the README badge and package.json. AGPL is a strong copyleft licence, and running a modified version as a network service is the scenario its terms are written for. That is a factual property of the licence, not legal advice; if you plan to fork and host a modified faucet publicly, have a lawyer read the terms rather than relying on a summary.

Editorial conclusion

Adopt PoWFaucet if you run a testnet and need a faucet that a single bot cannot drain, and you are willing to hold the wallet key and fund the balance yourself. Skip it if you need a hosted public faucet with no infrastructure: the project's own instances at sepolia-faucet.pk910.de and hoodi-faucet.pk910.de already serve that case. Before deploying, verify that your chosen protection module is the one you actually configured, and check that the faucet wallet holds the funds you intend to distribute.

Frequently asked questions

Why use a Sepolia ETH faucet?

Faucets for ETH testnets exist to distribute testnet funds, and PoWFaucet's README states that such faucets are spammed by bots, which is why it adds protection methods to reduce the efficiency of automated requests. The project operates a public Sepolia instance at sepolia-faucet.pk910.de.

What is the Sepolia testnet in relation to PoWFaucet?

Sepolia is one of the testnets PoWFaucet serves; the README lists a Sepolia instance with a version badge, an uptime badge and a faucet balance badge, and the repository links to the eth-clients/sepolia project. The same layout is repeated for Hoodi and Ephemery.

Does PoWFaucet generate testnet ETH through mining?

No. The README states that the faucet does not generate new coins with the mining process; mining is only a protection method to prevent anyone from requesting a large amount of funds and draining the faucet wallet. Operators must transfer the funds they want to distribute to the faucet wallet themselves.

How do I install and run my own PoWFaucet instance?

The README directs operators to the Faucet Operator Wiki for installation and configuration instructions, and to a demo instances page for module combinations. The repository ships a Dockerfile that builds the server and client and serves them behind nginx on port 8080, plus npm scripts such as npm run start for running from source.

How do I keep the faucet wallet key out of the config file?

The README states that secrets can be injected at runtime instead of being stored in faucet-config.yaml, and the local examples document FAUCET_SECRET, FAUCET_ETH_WALLET_KEY, FAUCET_CAPTCHA_SECRET, FAUCET_GITHUB_APP_SECRET and FAUCET_PASSPORT_SCORER_API_KEY.

What licence does PoWFaucet use?

The project is licensed under AGPL-3.0, as declared in both the README badge and the license field of package.json.

Official sources

  1. Issues
  2. License: AGPL-3.0
  3. pk910/PoWFaucet on GitHub
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/pk910-powfaucet.svg)](https://hysenlabs.com/projects/pk910-powfaucet)