Solve chess puzzles, earn Cashu ecash!
ChessU is a web application where users solve chess puzzles and receive Cashu tokens (ecash) as rewards. Users can solve 1 puzzle every 30 seconds and earn 10 sats per successful solution.
- 201 easy chess puzzles (rating 800-1400)
- Cashu token rewards (Bitcoin ecash)
- Lightning Network donations to puzzle pot
- Rate limiting (30 seconds between solves)
- Clean UI with interactive chessboard
- Backend: Node.js + Express
- Wallet: coco-cashu (Cashu protocol)
- Database: SQLite
- Frontend: Vanilla JS + chessboard.js + chess.js
- Deployment: Docker
Key settings in server/server.js:
const config = {
testMint: 'https://nofees.testnut.cashu.space',
mainMint: 'https://mint.minibits.cash/Bitcoin',
activeMode: process.env.ACTIVE_MODE || 'test',
puzzleReward: 10, // sats per puzzle
rateLimitSeconds: 30, // seconds between solves
};Create a .env file:
ACTIVE_MODE=main
WALLET_SEED=your-secure-random-seed-hereGenerate a secure seed:
openssl rand -hex 32docker-compose up -dVisit http://localhost:3000
To refresh the puzzle database with new easy puzzles from Lichess:
curl -L https://database.lichess.org/lichess_db_puzzle.csv.zst -o lichess_db_puzzle.csv.zstzstd -d lichess_db_puzzle.csv.zstawk -F',' 'NR==1 || ($4 >= 800 && $4 <= 1400)' lichess_db_puzzle.csv | head -202 > easy_puzzles.csvThis extracts the header row plus 201 puzzles with ratings between 800 and 1400.
Create convert_puzzles.js:
import fs from 'fs';
const csvContent = fs.readFileSync('easy_puzzles.csv', 'utf-8');
const lines = csvContent.trim().split('\n');
const puzzles = [];
for (let i = 1; i < lines.length; i++) {
const values = lines[i].split(',');
const puzzle = {
id: values[0],
fen: values[1],
solution: values[2].split(' '),
rating: parseInt(values[3]),
themes: values[7] ? values[7].split(' ') : []
};
puzzles.push(puzzle);
}
console.log(`Converted ${puzzles.length} puzzles`);
fs.writeFileSync('server/easy_puzzles.json', JSON.stringify(puzzles, null, 2));
console.log('Written to server/easy_puzzles.json');Run the conversion:
node convert_puzzles.jsrm lichess_db_puzzle.csv lichess_db_puzzle.csv.zst easy_puzzles.csv convert_puzzles.jsdocker-compose build && docker-compose down && docker-compose up -d- Create VPS with Ubuntu 22.04
- Install Docker:
apt update
apt install docker.io docker-compose- Clone repo and configure:
git clone <your-repo>
cd cashu-chess-puzzle
nano .env # Add WALLET_SEED and ACTIVE_MODE- Set up nginx + SSL:
apt install nginx certbot python3-certbot-nginxConfigure nginx reverse proxy:
server {
server_name yourdomain.com;
location / {
proxy_pass http://localhost:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_cache_bypass $http_upgrade;
}
}- Get SSL certificate:
certbot --nginx -d yourdomain.com- Start application:
docker-compose up -d- Keep wallet seed in
.envfile (not in git) - Only store small amounts (treat as hot wallet)
- Rate limiting prevents abuse
- Backup
wallet-data/wallet.dbregularly - Use DNS servers (8.8.8.8, 1.1.1.1) for reliability
Daily backup of wallet database:
# Add to crontab
0 2 * * * tar -czf /root/backups/wallet-$(date +\%Y\%m\%d).tar.gz /path/to/wallet-data/wallet.dbcashu-chess-puzzle/
├── docker-compose.yml # Container orchestration
├── Dockerfile # Node.js app container
├── .env # Environment variables (not in git)
├── .gitignore
├── server/
│ ├── server.js # Express server + Cashu wallet
│ └── easy_puzzles.json # 201 chess puzzles
├── public/
│ ├── index.html # Landing page
│ ├── puzzle.html # Main puzzle interface
│ └── donate.html # Donation page
└── wallet-data/ # SQLite database (persisted)
└── wallet.db
MIT
while testing on my laptop:
docker-compose build && docker-compose down && docker-compose up -dto restart docker after changing some codedocker save -o docker-save--chessu.tar cashu-chess-puzzle-chessuscp docker-save--chessu.tar root@chessu.cash:
On the VPS:
cd ~/cashu-chess-puzzle
docker-compose down && docker load -i ~/docker-save--chessu.tar && docker-compose up -d