DEV Community

Huzaifa Fareed
Huzaifa Fareed

Posted on

PE Fellowship - Mid Program Blog

I have been part of the Meta x MLH Fellowship for almost 7 weeks now, and it has
been nothing but fun. Meeting people across different regions, time zones, and
backgrounds has been the best part. Alongside building a project to learn
Production Engineering fundamentals, I have picked up a lot of what it means to
think like an SRE: debugging, diagnosing, and reasoning carefully about systems
under failure.

The project is a Flask portfolio, and it is now a live, HTTPS-secured site
running on my own VPS.

Live site: huzaifa-pe-portfolio.duckdns.org
Repo: zaifnatra/pe-portfolio

It is not just a static page: everything renders from Python lists through Jinja
templates, so adding an entry means adding one dictionary instead of a block of
HTML. The nav bar builds itself from the Flask URL map, so a new page shows up in
the menu automatically.

Portfolio homepage showing About Me, Education, Work Experience, and a map of countries visited

Hobbies page showing fishing and hiking photos with captions

There is also a timeline with a working API, so anyone can leave a post. It is
backed by MariaDB through Peewee, with server-side validation so bad input
returns a 400 instead of a row in the database.

Timeline page with a post form and existing posts showing Gravatar avatars

I wrote unit tests covering the database model and integration tests that hit the
Flask routes, running against an in-memory SQLite database so the suite never
touches real data. The whole thing is containerized with Docker Compose (Flask +
MariaDB + nginx), with TLS through certbot and rate limiting on the timeline
endpoint.

The bug that taught me the most

I rate limited POSTs to the timeline to 1 per minute per IP so nobody could flood
it. Then the timeline page itself started returning 503s.

The limit was keyed on client IP for every request, not just POSTs, so simply
loading the page burned the quota. The fix was an nginx map that only sets the
limit key for POST requests and leaves it empty otherwise, since nginx does not
account requests with an empty key:

map $request_method $timeline_post_key {
    POST    $binary_remote_addr;
    default "";
}
Enter fullscreen mode Exit fullscreen mode

Small change, but it was the first time I had to reason about a config from the
perspective of "what is this actually counting?" rather than "what did I intend
it to count?"

Some of my contributions

Stack: Flask, Jinja2, Peewee, MariaDB, Docker, nginx.

Have a look and leave something on
the timeline.

Top comments (0)