The source code for my website, imadsaddik.com, is stored in this repository. The frontend is built with Vue.js, and the backend uses FastAPI. The site is deployed on DigitalOcean, and the search feature is powered by Meilisearch.
I created this website to bring together everything I do online. You will find helpful blog posts about programming, courses I have worked on, and astronomy tutorials if you enjoy space 🌝
Check out the video below for a quick tour of the website!
To set up the project locally, follow these steps:
Install pnpm if you don't have it using npm:
npm install -g pnpm@latest-10Note
You can install pnpm using other methods. For more details, check the official pnpm installation guide.
After installing pnpm, navigate to the frontend directory and install the dependencies:
cd frontend
pnpm installNext, create a .env file by copying the example file:
cp .env.example .envFinally, start the development server:
pnpm devOpen your browser and go to http://localhost:8080/ to view the frontend. Don't worry about the backend connection at this point.
Navigate to the backend directory and create a virtual environment. I prefer to use anaconda, but you can also use venv, uv, or any other tool of your choice.
# Using conda
conda create -n venv python=3.13 -y
conda activate venv
# Using venv
python -m venv venv
source venv/bin/activate # On Windows use `venv\Scripts\activate`Next, install the required dependencies. Don't forget to activate your virtual environment if you haven't done so already:
pip install -r requirements.txtNow, create a .env file by copying the example file. You don't need to modify anything once you copy it:
cp .env.example .envFinally, start the FastAPI development server:
uvicorn main:app --reload --host 0.0.0.0 --port 8000You are almost done! The next and final step is to start Meilisearch, and populate it with data. This will enable the search functionality, list blogs, courses, and more.
Both the frontend and backend use .env files to manage configuration.
In the backend, the .env file contains the following variables:
MEILISEARCH_URL: The URL of your Meilisearch instance (default:http://localhost:7700).MEILISEARCH_MASTER_KEY: The master key to secure your search engine. Must match the key used when starting Meilisearch.MEILISEARCH_INDEX_NAME: The name of the index to store articles (default:articles).ENVIRONMENT: Set todevelopmentorproduction.
In the frontend, the .env file contains the following variables:
VITE_API_BASE_URL: The URL of the backend API (default:http://localhost:8000).BASE_URL: The base URL used by Playwright for E2E testing (default:http://localhost:8080).
Before installing Meilisearch, decide where you want to store the Meilisearch data. Create a directory for Meilisearch data storage somewhere on your system, for example:
mkdir -p ~/meilisearch_dataNow, move to that directory and download the latest stable release of Meilisearch:
cd ~/meilisearch_data
curl -L https://install.meilisearch.com | shStart Meilisearch:
./meilisearch --master-key='aStrongMasterKey'Note
The master key used here is a dummy key for local development. In a production environment, make sure to use a strong and secure master key.
aStrongMasterKey is the same key used in the .env file created earlier.
If that last command fails with a permission error like this:
2026-01-03T21:01:04.724569Z ERROR meilisearch: error=Permission denied (os error 13)
Error: Permission denied (os error 13)
Retry starting Meilisearch with sudo:
sudo ./meilisearch --master-key='aStrongMasterKey'The output should look like this:
888b d888 d8b 888 d8b 888
8888b d8888 Y8P 888 Y8P 888
88888b.d88888 888 888
888Y88888P888 .d88b. 888 888 888 .d8888b .d88b. 8888b. 888d888 .d8888b 88888b.
888 Y888P 888 d8P Y8b 888 888 888 88K d8P Y8b "88b 888P" d88P" 888 "88b
888 Y8P 888 88888888 888 888 888 "Y8888b. 88888888 .d888888 888 888 888 888
888 " 888 Y8b. 888 888 888 X88 Y8b. 888 888 888 Y88b. 888 888
888 888 "Y8888 888 888 888 88888P' "Y8888 "Y888888 888 "Y8888P 888 888
Config file path: "none"
Database path: "./data.ms"
Server listening on: "http://localhost:7700"
Environment: "development"
Commit SHA: "unknown"
Commit date: "unknown"
Package version: "1.18.0"
Thank you for using Meilisearch!
...
To load the initial settings and documents into Meilisearch, run the following script from the project root:
python backend/scripts/seed_meilisearch.pyFor more details about the seed data, refer to the seed README.
If you don't want to start each server in a separate window manually, you can use run_all_services_tmux.sh to start everything in a tmux session.
Warning
Open the bash script and make sure that the paths, and commands are correct before running it.
Now, install tmux if you don't have it already. On Debian or Ubuntu, you can install it using:
sudo apt install tmuxFor other operating systems, refer to the official tmux installation guide.
After installing tmux, navigate to the bash_scripts directory and run the script:
cd bash_scripts
./run_all_services_tmux.shThis will create a new tmux session named imad_saddik_personal_website with three panes: one for Meilisearch, one for the frontend, and one for the backend.
The backend pane is located at the bottom and spans the full width of the window, while the top half is split into two panes for Meilisearch (left) and the frontend (right).
This repository contains several helper tools to assist with maintenance and analysis:
-
Dashboard analysis: A collection of tools to analyze Nginx logs using GoAccess data. Useful for tracking traffic and identifying bad actors.
-
Bash scripts: A set of utility scripts for tasks such as:
- Optimizing images (
optimize_jpeg_images.sh,optimize_png_images.sh) - Finding large media files (
find_media.sh) - Managing backups (
clean_backups.sh)
Check the respective README files in those directories for more usage details.
- Optimizing images (
The infrastructure/ directory contains configuration files and scripts used to deploy the website in a production environment:
- nginx/: Configuration files for the Nginx web server, including Cloudflare-specific settings.
- supervisor/: Configuration for Supervisor to manage the backend process.
- systemd/: Systemd service files (e.g., for Meilisearch).
- scripts/: Deployment and maintenance scripts, such as Gunicorn startup and monthly cleanup tasks.
For more details, refer to the infrastructure README.
Contributions are welcome! To keep the code clean and consistent, please follow these simple steps:
I use pre-commit hooks to check the code automatically before every commit. This helps catch small mistakes early.
First, install pre-commit in your virtual environment:
pip install pre-commitThen, set up the hooks:
pre-commit installNote
The pre-commit hooks will also automatically regenerate the sitemap.xml file if you make changes to the frontend.
Please make sure your code follows the project style. You can run these commands to fix most style issues:
- Frontend: Run
pnpm lintandpnpm formatin thefrontendfolder. - Backend: Run
ruff check . --fixin thebackendfolder.
Before submitting your changes, run the tests to make sure everything still works:
Inside the frontend folder run these tests:
- Unit tests:
pnpm run test:run - E2E tests:
pnpm run test:e2e(requires the frontend, meilisearch, and backend to be running)
Inside the backend folder run these tests:
-
Unit tests:
pytest tests/unit -
Integration tests:
pytest tests/integration(requires Meilisearch to be running) -
Load tests:
locust -f tests/load/locustfile.py
Then open http://localhost:8089 to start the swarm.
If you find a typo or have a suggestion, feel free to open an issue or a pull request!
This project is licensed under the MIT License. See the LICENSE file for details.
You can reach me through:
- Email – [email protected].
- LinkedIn – Connect with me.