The simple and flexible portfolio template written with Go, with a modern, dark-mode-ready design out of the box. Build your portfolio with simple yaml files!
See the live example on bossm8.ch or GitHub Pages
This template can be used for either hosting a static webpage with e.g. GitLab / GitHub pages. Or if you like, with a server written in go, this server brings benefits like a contact form to send emails directly to you via the portfolio page.
(For more detailed information see below)
- Create a directory containing two folders:
configsandcustom - Add your own images into the directory
custom - Copy the example yaml configurations into the
configsdirectory and adjust them (for images use the path/static/img/custom/<your-image>) - Use the prebuilt docker container to host the portfolio (the command is being run in the directory containing the two folders):
(make sure the files have the right permissions (container uses 100:82) or run the container as a different user)
docker run -it --rm \ --name portfoli.go \ -p 127.0.0.1:8080:8080 \ -v ${PWD}/configs:/var/www/portfoli.go/configs:ro \ -v ${PWD}/content:/var/www/portfoli.go/public/img/custom:ro \ ghcr.io/bossm8/portfoli-go:latest - This command will mount your configs and custom images in the expected location inside the docker container and start the portfolio with your content.
- Do steps 1-2 of the dynamic approach
- Run the following commands to build your static webpage with the prebuilt docker container:
# create the directory for the static build mkdir dist # render the html content docker run -it --rm \ --name portfoli.go \ -v ${PWD}/configs:/var/www/portfoli.go/configs:ro \ -v ${PWD}/dist:/var/www/portfoli.go/dist \ -e DIST_PATH=/var/www/portfoli.go/dist \ -e CONF_PATH=/var/www/portfoli.go/configs \ --entrypoint portfoli-go-static.sh \ ghcr.io/bossm8/porfoli-go:latest # move your custom images into the static build mv ${PWD}/custom dist/static/img/custom
- Host the build with any fileserver of your choice (see for example the nginx configuration below)
The portfolio template expects its content to come from yaml configuration files.
Those files need to be in a single directory and their names must be the same as the
content type they represent (with the .yml extension). They are loaded each time
the page is requested, meaning you can edit them on the fly without having to restart
the server (when not using the static version).
The following content types are currently supported:
- experience
- education
- projects
- certifications
- bio
Each of them might support a different configuration, for possible values and explanaiton see examples/configs.
NOTE Any HTML content in the configurations may
also contain go templates, it will be passed through
the templating engine when loaded. You might want to use the Assemble function, which
adds the configured base path to relative paths from /static, i.e. you can reference your custom images like this:
{{ "/static/custom/avatar.jpg" | Assemble }}So you do not have to adjust the configurations should the base path ever change.
You can optionally cache remote images referenced in the image fields of the content configs by
enabling images.cache in config.yml. When enabled, remote images are downloaded into
public/img/cache and the generated HTML uses the local cached path. Set images.force to true
to re-download cached images on startup. You can override the cache directory with the
-images.cache.dir CLI flag (relative to static.dir).
I recommend putting your custom content into a subdirectory of public/img (e.g. custom), and referncing
this directory in the yaml configurations when specifying images. This makes it easier for the usage with e.g. Docker.
You are able to use a relative path starting with /static i.e. /static/img/custom/avatar.jpg the rendering process will
make sure that any base path (specified with -srv.base) of your server is prepended to this path (e.g. when hosing on GitLab pages).
The page follows the visitor's system light/dark preference automatically, and also offers a manual toggle (top right of the navigation bar) which overrides the system preference and is remembered on the visitor's device.
If your existing YAML content contains raw HTML with Bootstrap-style classes
(e.g. btn btn-primary, row/col-*, text-muted, fs-4, img-fluid,
bi-* icons), it will keep rendering without any changes to your
configuration - those class names are still supported and automatically pick
up the new color palette and dark mode.
Fields that accept HTML content (description on experience/education/
certifications/projects entries, me on the bio page, and the profile's
heading/subheading) can also contain a <style> block for one-off custom
styling - see examples/configs/projects.yml's "Gopher Artwork" entry for a
worked example. Keep in mind a <style> block isn't scoped to just that
entry - it applies to the whole page - so prefix your class names (e.g.
.my-project-badge) to avoid clashing with styles from other entries.
An optional top-level seo: block in config.yml controls the page
<title>, the default meta description, and social share previews (Open
Graph/Twitter Card tags), plus a JSON-LD Person block for richer search
results built from your profile automatically. All fields are optional -
omit the whole section, or any field within it, to keep the current
defaults. See examples/configs/config.yml for the available fields
(sitename, description, image, siteurl). A page can still override
just its own description (as the about page does) without touching this
site-wide default.
There are different approaches on how to use this template, select the one which might fit you the most.
(Live means you use the binary to serve the portfolio, which enables the contact form.)
Get started easily by pulling this repository and running make run, this will
start the portfolio with the example configuration (go is required).
The portfoli-go binary can be built with make build, then use
the help message to see available options:
portfoli-go -helpThere exists a pre-build Docker image which you can use to host the portfolio website just mount your custom content and configurations to use: (make sure the files have the right permissions (container uses 100:82) or run the container as a different user)
docker run -it --rm \
--name portfoli.go \
-p 127.0.0.1:8080:8080 \
-v ${PWD}/configs:/var/www/portfoli.go/configs:ro \
-v ${PWD}/content:/var/www/portfoli.go/public/img/custom:ro \
ghcr.io/bossm8/portfoli-go:latestThere is also a sample docker-compose.yml in the examples directory.
As stated earlier, you are able to build the portfolio for being hosted as a static website. The static build can be used on e.g. GitLab or GitHub pages.
It can be built by using the -dist flag with the binary or locally with make dist, this will output
the content for being served with a static file server in the specified output directory.
However, when using the binary you need to make sure to also copy over the contents of the directory
public into the dist path (see for example the script in examples/.gitlab-ci.yml).
As described in the config section, I recommend putting
custom images into a subdirectory of public/img and specifying the corresponding path in the yaml configs.
For building with GitLab or GitHub you may use the Docker image of portfoli.go (ghcr.io/bossm8/portfoligo:latest)
as there is everything prepared inside, just have a repository with your custom content and yaml configuration
which you can use to build the static website. There are pipeline configurations examples for bothin the examples directory.
Just copy one them over to your repository containing configuration files and custom content and run the pipeline
(some adjustemts might be needed though - e.g. BASE_PATH).
For running locally, there is an example nginx configuration which shows how the dist build may be used.
The command below starts this configuration with the nginx Docker container -
it assumes you have run make dist before and that you have copied your custom content into the dist directory.
docker run -it --rm -p 8080:80 \
--name porfoli.go \
-v ${PWD}/dist:/usr/share/nginx/html:ro \
-v ${PWD}/examples/nginx.conf:/etc/nginx/conf.d/default.conf:ro \
nginx:latestThere is a devcontainer
setup (which can also be used for building the binary). Simply fork (or clone) this repository,
open the devcontainer with VSCode and run make setup.
- Write tests
Here are some gopher images I created for this page: