Skip to content

ImadSaddik/ImadSaddikWebsite

Imad Saddik's website

ci_pipeline_status Backend Coverage Frontend Coverage gitHub_license website_status

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 🌝

readme_thumbnail

Project showcase

Check out the video below for a quick tour of the website!

Watch the Project Tour

Project setup

To set up the project locally, follow these steps:

Frontend

Install pnpm if you don't have it using npm:

npm install -g pnpm@latest-10

Note

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 install

Next, create a .env file by copying the example file:

cp .env.example .env

Finally, start the development server:

pnpm dev

Open your browser and go to http://localhost:8080/ to view the frontend. Don't worry about the backend connection at this point.

Backend

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.txt

Now, create a .env file by copying the example file. You don't need to modify anything once you copy it:

cp .env.example .env

Finally, start the FastAPI development server:

uvicorn main:app --reload --host 0.0.0.0 --port 8000

You 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.

Configuration

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 to development or production.

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).

Meilisearch

Installation

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_data

Now, move to that directory and download the latest stable release of Meilisearch:

cd ~/meilisearch_data
curl -L https://install.meilisearch.com | sh

Start 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!

...

Populate Meilisearch with data

To load the initial settings and documents into Meilisearch, run the following script from the project root:

python backend/scripts/seed_meilisearch.py

For more details about the seed data, refer to the seed README.

Managing Meilisearch with a GUI

Instead of interacting with Meilisearch only through code or scripts, you can use this useful GUI tool to manage your Meilisearch instance visually.

To use this tool, go to this hosted dashboard and click on the plus button to add a new Meilisearch instance.

meilisearch_ui_add_instance Click the plus button to add a new Meilisearch instance.

Note

If you want to run the GUI tool locally, follow the instructions in the meilisearch-ui repository.

Depending on where your Meilisearch is running, the connection process is different:

  1. Running locally: If Meilisearch is running on your own computer, it works immediately. Meilisearch allows all connections by default, so you can simply enter http://127.0.0.1:7700 as the host and your master key.

  2. Running on a VM (Production): If Meilisearch is running on your DigitalOcean Droplet, you cannot connect directly because the firewall blocks port 7700 for security. You should not open this port to the public. Instead, you must create a secure "bridge" (SSH tunnel) that maps your local port to the server's port.

Important

Meilisearch is already configured to accept connections. You only need to establish a secure tunnel to reach it.

Open a new terminal window and run this command to create the bridge:

# Syntax: ssh -L <local_port>:127.0.0.1:<remote_port> <user>@<server_ip>
ssh -L 7700:127.0.0.1:7700 -i ~/.ssh/<your_key_name> <your_username>@<your_droplet_ip>

Keep this terminal open. This command tells SSH to listen to port 7700 on your computer and forward any traffic securely to port 7700 on the server.

In the dialog that appears, give your instance a name. Since you are using a bridge (or running locally), enter http://127.0.0.1:7700 as the URL and the master key you used when starting Meilisearch.

meilisearch_ui_instance_details Enter the details of your Meilisearch instance.

Click "Confirm" to add the instance. You should now be able to manage your Meilisearch instance visually. You can view indexes, search documents, update settings, monitor activity and more.

meilisearch_ui_dashboard The Meilisearch home page.

Run all services using tmux

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 tmux

For 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.sh

This 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).

Useful tools & scripts

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.

Production infrastructure

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.

Contributing

Contributions are welcome! I appreciate you taking the time to help improve the project.

To ensure a smooth and collaborative process, please read the contributing guide before you get started. It provides detailed instructions on:

  • Setting up the development environment
  • Running tests for both frontend and backend
  • Following the code style and linting guidelines
  • The pull request process

If you find a typo or have a suggestion, feel free to open an issue or a pull request!

Licence

This project is licensed under the MIT License. See the LICENSE file for details.

Contact

You can reach me through:

About

My website's source code lives in this repository.

Topics

Resources

License

Code of conduct

Contributing

Stars

Watchers

Forks

Packages

No packages published

Contributors 7