How I Built and Hosted My Chess Engine on Lichess Using AWS Free Tier
I got bored of solving DSA problems and decided to build a chess engine instead. Here's how I built it, made it play on Lichess, and hosted it 24/7 using AWS—without paying anything.
How It Started
After solving a lot of DSA and LeetCode-style problems, I realized it wasn’t exciting me anymore. Most problems started to feel the same, and solving them didn’t feel challenging. I even deleted my LeetCode account to start fresh hoping to get the motivation back—but that didn’t help.
So I thought, why not try something I’ve been interested in for a long time? I’ve always been curious about how chess engines work. Computer chess has fascinated me since I was 14, and now that I have some experience with programming, I decided to build one of my own.
Play Against It
You can challenge the bot on Lichess anytime: https://lichess.org/@/QuackStrike
The Engine
I built the chess engine in C#. It plays standard chess and currently has an Elo rating of ~1900.
It supports time controls of bullet, blitz and rapid, and runs 24/7 on an AWS EC2 instance.
What It Does
The engine uses a bunch of classic search and evaluation techniques, including:
- Iterative Deepening – Searches deeper over time
- Alpha-Beta Pruning – Cuts off bad moves early
- Quiescence Search – Searches deeper when things get chaotic, with lots of captures, checks, and threats
- Null Move Pruning – Skips the current move to test if the position is still safe
- Late Move Reductions – Reduces search depth for low-priority moves
- Check Extensions – Extends the search when the current move gives a check
Evaluation Function
- Material: Standard piece values
(Pawn=100, Knight=300, Bishop=320, Rook=500, Queen=1000, King=10000)
- Pawn Structure:
- Doubled pawn penalty: -15
- Passed pawn bonus: +15 per rank
- Isolated pawn penalty: -15
- King Safety: Bonus for castling early, and pushing the enemy king to the edge in endgames
- Slider Mobility: Encourages bishops, rooks, and queens to stay active
Move Ordering
Moves are scored and sorted to improve search efficiency. Here’s the order of priority:
- Best Move / Transposition Table – Always tried first (score:
10,000,000
) - Captures (MVV-LVA) – Favor high-value captures with low-value attackers
(score:100,000 + material delta
) - Promotions – Bonus based on promoted piece’s value
- Castling – Fixed bonus (+10,000)
- Killer Moves – Quiet moves that previously caused cutoffs (+9,000)
- Countermoves – Refutations of the opponent’s last move (+8,000)
- History Heuristic – Based on past success of quiet moves
- Piece-Square Bonus – Encourages good placement, especially in midgame
- King Safety – Quiet moves that help defend the king (scaled by piece value)
- Slider Mobility Gain – Improves bishop/rook/queen activity
- Attacked Squares Penalty – Penalizes unsafe moves
All legal moves are scored using these rules and sorted highest to lowest for efficient search.
Speed and Optimization
- Uses
stackalloc
and pre-allocated arrays for fast move generation - Cuts off at 200 plies or when time runs out
- Uses a 16M-entry transposition table to avoid re-searching positions
Time Management
- Uses up to 25% of the remaining time per move (hard limit)
- Usually uses about 1/40th of the total time (soft limit)
- If only one legal move exists, it plays it instantly
Opening and Endgames
It uses opening books (Lichess cloud analysis) and endgame tablebases (for positions with less than or equal to 7 pieces) through the lichess-bot GitHub project, which is used to connect the running engine with Lichess, allowing it to play common openings and some theoretical endgames.
Hosting It 24/7 on AWS Free Tier
I hosted the engine on AWS using a Free Tier EC2 instance (t2.micro
). However, at first it kept running out of CPU credits, and when that happened, the whole instance slowed down and the bot just stopped playing altogether.
How I Fixed It
Here’s how I kept it running smoothly, without ever paying a rupee.
- Let it rest: AWS gives back CPU credits when idle
- Limited self-challenges: The bot only initiates new games every 2 hours (It can accept challenges anytime though)
- Only one game at a time: No parallel games = fewer resources used
- Used
tmux
: So the bot stays alive even after SSH disconnects
Now it runs non-stop pretty smoothly, and all of this stays within the Free Tier limits.
What’s Next
Some improvements I’m thinking about:
- Tune the evaluation function more precisely
- Experiment with better pruning and move ordering to speed things up
Final Thoughts
Building this engine was a fun break from the usual stuff. It got me back into building things, and I learned a lot along the way—both about algorithms and about deploying something real.
If you’re getting bored with practice problems, try building something you genuinely enjoy. It might take longer, but it’ll keep you going.