๐ See the source code on GitHub:
Material for MkDocs Portfolio Template
๐ฅ Live Demo:Portfolio Site
This article teaches you how to create stunning, professional portfolios using Material for MkDocs, a fast, customizable, and open-source static site generator trusted by over 20,000 users to build responsive, searchable, and beautifully designed websites.
This is one of the most frustrating article I've ever written (Weird way to start an article, right?) ๐. It was truly a bittersweet experience.
Did I hear you say why? Glad you asked... Now let me lay it down for you.
โ๏ธ Table of Contents
- โ๏ธ
Environment Setup (Optional)
- ๐ฆ
Project Scaffolding
- ๐คฌ
Frustrations (Optional)
- ๐ถโโ๏ธ
Walk Through
- ๐
Deployment (Github Actions Included)
โ๏ธ Environment Setup (Optional)
I always write my articles with beginners in mind because I was once one, too. If you're already experienced, feel free to skip this section. This guide assumes you're using Ubuntu Linux. The following commands will help you to set up a fresh server environment and serve as a reference point some time in the future because eventually, youโll probably be needing it again.
๐ก For other Linux distributions: Replace apt
with your system's package manager like yum
, pkg
, apk
and so on.
๐ก For Windows users: You can install Windows Subsystem for Linux (WSL)
with the command wsl --install
in your terminal, access it with your favourite code editor and then run the commands below.
# Update package lists and upgrade existing packages
sudo apt -y update && sudo apt -y upgrade
# Install Docker, Docker Compose, and add current user to the docker group for non-root access
sudo apt -y install docker.io
sudo apt -y install docker-compose
sudo usermod -aG docker $USER
# Install useful dependencies
sudo apt -y install tree
sudo apt -y install vim
# Install Python 3.10 virtual environment package
sudo apt -y install python3.10-venv
# Install pip for Python 3
sudo apt -y install python3-pip
# Install OpenSSH server and enable/start the SSH service
sudo apt -y install openssh-server
sudo systemctl enable ssh
sudo systemctl start ssh
# Allow SSH through the firewall and enable UFW (Uncomplicated Firewall)
sudo ufw allow ssh
sudo ufw enable
# Generate a new RSA SSH key pair with no passphrase and a comment for identification
ssh-keygen -t rsa -f ~/.ssh/id_rsa -N "" -C "ssh-key"
# Reboot the system to apply changes
sudo shutdown -r now
Now that we're done with running the above commands and restarting the server so changes take full effect, we will be moving to the next section which will be...
๐ฆ Project Scaffolding
In this section, we will setting up the project structure by creating and executing the setup.sh
# Create & make setup script executable
touch setup.sh && chmod +x setup.sh
# Excute setup script (populate script from github link provided)
./setup.sh
After successful execution, your project directory should look like this:
portfolio/
โโโ .github
โโโ .gitignore
โโโ Journal.md
โโโ docs
โโโ mkdocs.yml
โโโ requirements.txt
โโโ site
To activate your virtual environment and start the project, run the following commands:
# Activate virtual environment
source env/bin/activate
# Navigate into the project folder
cd portfolio
# Start the development serve
mkdocs serve
INFO - Building documentation...
INFO - Cleaning site directory
INFO - Documentation built in 0.31 seconds
INFO - [17:59:56] Watching paths for changes: 'docs', 'mkdocs.yml'
INFO - [17:59:56] Serving on http://127.0.0.1:8000/
If you happen to be running on a VM or an external server. You can use this instead, as it binds the IP to the host to make it accessible on your web browser.
mkdocs serve -a "$(hostname -I | awk '{print $1}'):8000"
Head to the project URL, and you should see the screen below in your browser, which means the portfolio template is now up and running! ๐
ย
๐ When the foundation is not solid, everything built upon it will crumble in due time.
ย
The setup script that was run established a solid foundation. However, if you want to build on top of that, this reference page is crucial: https://squidfunk.github.io/mkdocs-material/customization/
because itโs what will take your portfolio from what you see above to what you'll see below ๐.
๐คฌ Frustrations (Optional)
This tutorial might look cute, but let me tell you, there was a whooooole lotta frustration trying to figure out where to put what, getting things to work, and why something that worked perfectly on local breaks in production. (That kind of mess)
It got so annoying that I ended up writing a script to scaffold the whole project from scratch because, just like a Microsoft Word CV, one tiny tweak can break the whole format, and suddenly you're spending hours trying to reformat stuff that shouldn't even be broken in the first place. And ohhhh! Don't even get me started on setting up Github Actions, that was the real rabbit hole 2.0. What I thought would take me just a few hours to figure out ended up taking a week.
๐ถโโ๏ธ Walk Through
Wheeeew! Now that Iโve got that off my chest. Allow me, your one and only tour guide, MrChike
, to take you on a cruise through the inner workings of this project.
Ready, Player One? ๐ฎ
-
docs/: Your development environment (HTML, CSS & JavaScript)
- overrides/: Customise any part of the site to your taste
๐ก Treat the markdowns(*.md) files like HTML: you can add HTML tags like div
to it, and it would still work because it would be converted to index.html, as you will see under site/
docs/
โโโ articles.md
โโโ assets
โ โโโ images
โ โ โโโ logo.svg
โ โโโ javascripts
โ โ โโโ extra.js
โ โโโ stylesheets
โ โโโ extra.css
โโโ certifications.md
โโโ contributions.md
โโโ index.md
โโโ overrides
โ โโโ partials
โ โโโ logo.html
โโโ projects.md
- sites/: Production environment
๐ก This folder is intended for public access. You don't need to modify it manually as it's regenerated before each deployment. That's why it's included in .gitignore
. This folder is what gets deployed to the gh-pages
branch and displayed on your portfolio website.
site/
โโโ 404.html
โโโ articles
โ โโโ index.html
โโโ assets
โ โโโ images
โ โโโ javascripts
โ โโโ stylesheets
โโโ certifications
โ โโโ index.html
โโโ contributions
โ โโโ index.html
โโโ css
โ โโโ base.css
โ โโโ bootstrap.min.css
โ โโโ bootstrap.min.css.map
โ โโโ brands.min.css
โ โโโ fontawesome.min.css
โ โโโ solid.min.css
โ โโโ v4-font-face.min.css
โโโ img
โ โโโ favicon.ico
โ โโโ grid.png
โโโ index.html
โโโ js
โ โโโ base.js
โ โโโ bootstrap.bundle.min.js
โ โโโ bootstrap.bundle.min.js.map
โ โโโ darkmode.js
โโโ overrides
โ โโโ partials
โโโ projects
โ โโโ index.html
โโโ search
โ โโโ lunr.js
โ โโโ main.js
โ โโโ search_index.json
โ โโโ worker.js
โโโ sitemap.xml
โโโ sitemap.xml.gz
โโโ webfonts
- deploy.yml: Github Actions Configuration file for automated deployment
.github/
โโโ workflows
โโโ deploy.yml
- Journal.md: A log of your experiences and insights while working on your projects. (Keeping a journal is a great habit to develop when working on projects.)
- mkdocs.yml: Configuration file for MKDocs
- requirements.txt: Lists your project dependencies. (It's good practice to include specific versions, as dependencies are frequently updated and changes may break your project in the future.)
.
โโโ Journal.md
โโโ mkdocs.yml
โโโ requirements.txt
Now you have a good grasp of the project structure, let's advance to deployment.
๐ Deployment (Github Actions Included)
In this section, we will focus on both manual and automated deployment but first i will lay down the steps in order to follow.
- ๐ Create a
GitHub
Repository (if not existing already) - ๐ Generate SSH keys
- ๐๏ธ Add your SSH public key to GitHub
- ๐งโ๐ป Manual Deployment using
mkdocs gh-deploy
- ๐ Create a Personal Access Token (PAT)
- ๐คซ Add the PAT as a GitHub Secret
- ๐ค Automated Deployment using GitHub Actions
๐ Create a GitHub Repository
Take Home Assignment: Figure it out! ๐
๐ Generate SSH keys
- First, confirm if you have SSH keys available
ls -lh ~/.ssh/
-rw------- 1 mrchike mrchike 2.6K Jun 20 05:26 id_rsa
-rw-r--r-- 1 mrchike mrchike 572 Jun 20 05:26 id_rsa.pub
-rw------- 1 mrchike mrchike 978 Jun 20 05:28 known_hosts
-rw-r--r-- 1 mrchike mrchike 142 Jun 20 05:16 known_hosts.old
๐ก The id_rsa.pub
is your authentication public key to access external servers (in this case, GitHub).
โ ๏ธ Note on SSH Keys:
If you try using a custom name for your SSH key (i.e something other than id_rsa.pub
), GitHub may reject the connection during deployment. If you encounter this issue, a simple workaround is to generate a new key and overwrite the existing one using the command:
ssh-keygen
This will recreate id_rsa
and id_rsa.pub
, which are the default names GitHub expects unless otherwise configured.
You will need to register it on your GitHub account to have access to push/pull changes. So run the following command to print it out.
cat ~/.ssh/id_rsa.pub
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDKiPnhAeI70ooWzt7yDgopgmgllifUBwvev1RKBq/UM1rQ/std0PHokt+qcGZlIAtFWUsGdOZi+FDLpOywsL1+XO4UlBVW4M/qQasoVnE/CdT77GxaZQ0btYlHm5FS4mKYRWtxSIxjq3b+qRWB6U4KFkfOG3iQAinLI+iD0olcAikCaA8mRKTg541+qDxY33oSE3a9svjP8keVmB9ALN6zdGoDuLa3gX9OCK8wIOzewYDFfr3wMHpT/oJ0sG5oPtBFMBDHJcdt46T+u3uZCbaRs/Hre7UbYXgXkcQWNZ8fpSj4JieebjP8MrHxkRVG5mmM5/wumaC342fmTBbiA4wJUhOErR7zX/SDlUN5NDAyBiq7vDhdkVrj3sTisXgGnboRhLbrOt0TzAo3QRxyXQTZe7rQPh+9D/DDLgGuVz0PB0YOvSDcbVpWwsZvWzE+oBJi9Xxp3bkJH79+6M/AUZ36D9qd1jzI8sTf1+LNj8nxdNtIWmDtpWeRIIbgBcfusvs= YOUR-SSH-KEY
Now, copy your SSH Key as you'll be needing it for the next step.
๐๏ธ Add your SSH public key to GitHub
You can register your SSH key in one of two ways:
- User-wide access:
https://github.com/settings/keys
- Repo-specific access
(Deploy Key)
:https://github.com/YOUR-USERNAME/REPO-NAME/settings/keys
- e.g
https://github.com/MrChike/temp/settings/keys
- e.g
๐ก Your use case should determine your preference.
If you want to use the key across multiple repositories from the same machine, go with user-wide access.
If you only want to allow access to a single repository (i.e for CI/CD purposes), then use a repo-specific deploy key.
Once you've decided on your preference, add your SSH Key.
๐ For Repo-specific access (Deploy Key)
make sure you tick Allow write access
Congrats! ๐ It's time to see our first deployment in action.
๐งโ๐ป Manual Deployment using mkdocs gh-deploy
First we will start by initializing git in our project forlder
git init
hint: Using 'master' as the name for the initial branch. This default branch name
hint: is subject to change. To configure the initial branch name to use in all
hint: of your new repositories, which will suppress this warning, call:
hint:
hint: git config --global init.defaultBranch <name>
hint:
hint: Names commonly chosen instead of 'master' are 'main', 'trunk' and
hint: 'development'. The just-created branch can be renamed via this command:
hint:
hint: git branch -m <name>
Initialized empty Git repository in /path/to/project/portfolio/.git/
Then set your preferred default branch name. Feel free to name it whatever you want but in this tutorial i will be going with master
.
git config --global init.defaultBranch master
Now that we've done that, let's connect to our remote repo, commit changes and push to the master branch. Also, note that all GitHub-related URLs should be yours, I only use this tutorial repo to serve as a guide.
# Connects your local repo to the remote GitHub repository via SSH
git remote add origin git@github.com:MrChike/mkdocs-portfolio.git
# Stages all changes and commits them with a message
git add . && git commit -m "Initial Commit"
# Pushes the 'master' branch to GitHub and sets it as the upstream branch
git push --set-upstream origin master
[master (root-commit) 516f9ae] Initial Commit
14 files changed, 159 insertions(+)
create mode 100644 .github/workflows/deploy.yml
create mode 100644 .gitignore
create mode 100644 Journal.md
create mode 100644 docs/articles.md
create mode 100644 docs/assets/images/logo.svg
create mode 100644 docs/assets/javascripts/extra.js
create mode 100644 docs/assets/stylesheets/extra.css
create mode 100644 docs/certifications.md
create mode 100644 docs/contributions.md
create mode 100644 docs/index.md
create mode 100644 docs/overrides/partials/logo.html
create mode 100644 docs/projects.md
create mode 100644 mkdocs.yml
create mode 100644 requirements.txt
Enumerating objects: 24, done.
Counting objects: 100% (24/24), done.
Delta compression using up to 12 threads
Compressing objects: 100% (11/11), done.
Writing objects: 100% (24/24), 3.23 KiB | 826.00 KiB/s, done.
Total 24 (delta 0), reused 0 (delta 0), pack-reused 0
To github.com:MrChike/temp.git
* [new branch] master -> master
Branch 'master' set up to track remote branch 'master' from 'origin'.
Now that we've pushed, let's deploy our site by running the command:
mkdocs gh-deploy --force
INFO - Cleaning site directory
INFO - Building documentation to directory: /path/to/portfolio/site
INFO - Documentation built in 0.39 seconds
WARNING - Version check skipped: No version specified in previous deployment.
INFO - Copying '/path/to/portfolio/site' to 'gh-pages' branch and pushing to GitHub.
Enumerating objects: 72, done.
Counting objects: 100% (72/72), done.
Delta compression using up to 12 threads
Compressing objects: 100% (63/63), done.
Writing objects: 100% (72/72), 579.32 KiB | 1.66 MiB/s, done.
Total 72 (delta 8), reused 0 (delta 0), pack-reused 0
remote: Resolving deltas: 100% (8/8), done.
remote:
remote: Create a pull request for 'gh-pages' on GitHub by visiting:
remote: https://github.com/MrChike/mkdocs-portfolio/pull/new/gh-pages
remote:
To github.com:MrChike/mkdocs-portfolio.git
* [new branch] gh-pages -> gh-pages
INFO - Your documentation should shortly be available at: https://MrChike.github.io/mkdocs-portfolio/
Now, the portfolio site should be hosted on the link provided. In this case https://MrChike.github.io/mkdocs-portfolio/
If you have yours set up and working, a huge congratulations!
At this point, you might be wondering: if I can manually deploy my site from my local machine, why bother automating it?
Honestly, I donโt even know why I decided to take it a step further. But this is when I finally understood what Nagato meant when he said to Naruto: "And now... You shall know pain." ๐ตโ๐ซ
๐ Create a Personal Access Token (PAT)
Head to your Github account and create your personal access token at https://github.com/settings/personal-access-tokens
Fill in the details as needed. Under Repository access, select your preference (either all repos or just specific ones).
Most importantly, under Permissions, youโll see two sections: Repository permissions and Account permissions. Go ahead and give everything under both sections read/write access.
Once thatโs done, scroll down and hit Generate token.
it's important that you copy this token and save somewhere because once you leave that page the only way to use it if forgotten is to regenerate it.
ย
๐ NB: It took me a while to figure this one out because without it, youโll keep running into errors when deploying with GitHub Actions. At some point, I was really losing patience, so I just gave everything under both permission sections read/write access. When you have time, feel free to go back and untick anything you donโt actually need.
ย
๐คซ Add the PAT as a GitHub Secret
Head to your repo โ Settings โ Secrets and variables โ Actions, and create a new repository secret for your token.
Populate the following fields:
- Name:
ACCESS_TOKEN
- Secret: Paste the personal access token you just generated and copied Then click Save.
This gives GitHub Actions access for automated deployments
๐ค Automated Deployment using GitHub Actions
To wrap things up, we'll automate deployment to run daily at 12:00 AM, ensuring any updates to your portfolio are always live.
But first, letโs give credit where itโs due.
A huge shoutout to peaceiris
for simplifying what could have been a tedious process. Check out the repo when you have time, it's worth it!
Now, update your deploy.yml file with the following configuration
.
๐ The inline comments explain each section, but here are a few key points to emphasize:
branches:
Update this to match the branch you're deploying from (master
,main
, or multiple branches if needed). The workflow will only trigger on changes to the specified branch(es).personal_token:
Do not change this key name. It must be exactlypersonal_token
, thatโs what the GitHub Action expects.
However, the repository secret name (i.eACCESS_TOKEN
) can be whatever you like, just make sure the name you use inSecrets and variables โ Actions
matches what you reference in the workflow.
commit and push your changes to the repo
You can monitor your deployment runs under the Actions tab in your GitHub repo. Each run will show success/failure logs and scheduling history as displayed in the screenshot below..
And that's all folks. It's been an interest ride so far and if you have any blockers I'm open to mentor and assist.
Would you like a deeper dive on this topic? ๐ Cast your vote
๐ก Enjoyed this article? Connect with me on:
Your support means a lot, if youโd like to buy me a coffee โ๏ธ to keep me fueled, feel free to check out this link
. Your generosity would go a long way in helping me continue to create content like this.
Until next time, happy coding! ๐จ๐พโ๐ป๐
Previously Written Articles:
Top comments (0)