{"id":13454783,"url":"https://github.com/timo-reymann/yal","last_synced_at":"2025-08-02T03:39:20.255Z","repository":{"id":230244953,"uuid":"778749015","full_name":"timo-reymann/yal","owner":"timo-reymann","description":"A simple link hub, to display and search links. Allows easy branding, runs with the least privileges and is simple to use.","archived":false,"fork":false,"pushed_at":"2025-05-31T11:02:24.000Z","size":6515,"stargazers_count":41,"open_issues_count":1,"forks_count":0,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-05-31T23:17:51.596Z","etag":null,"topics":["dashboard","docker","home","homepage","html","js","links","portal","self-hosted","selfhosted","start"],"latest_commit_sha":null,"homepage":"https://timo-reymann.github.io/yal/","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/timo-reymann.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null},"funding":{"github":["timo-reymann"],"custom":["https://www.buymeacoffee.com/timoreymann","Buy me a coffee"]}},"created_at":"2024-03-28T10:24:25.000Z","updated_at":"2025-05-31T11:02:04.000Z","dependencies_parsed_at":"2024-04-05T16:27:46.697Z","dependency_job_id":"fd4c3d7a-6ff1-44b0-805e-6969f8fc1f8b","html_url":"https://github.com/timo-reymann/yal","commit_stats":null,"previous_names":["timo-reymann/yal"],"tags_count":17,"template":false,"template_full_name":null,"purl":"pkg:github/timo-reymann/yal","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/timo-reymann%2Fyal","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/timo-reymann%2Fyal/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/timo-reymann%2Fyal/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/timo-reymann%2Fyal/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/timo-reymann","download_url":"https://codeload.github.com/timo-reymann/yal/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/timo-reymann%2Fyal/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":268331542,"owners_count":24233283,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-08-02T02:00:12.353Z","response_time":74,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["dashboard","docker","home","homepage","html","js","links","portal","self-hosted","selfhosted","start"],"created_at":"2024-07-31T08:00:57.895Z","updated_at":"2025-08-02T03:39:20.224Z","avatar_url":"https://github.com/timo-reymann.png","language":"Go","funding_links":["https://github.com/sponsors/timo-reymann","https://www.buymeacoffee.com/timoreymann","Buy me a coffee"],"categories":["Go","10、基础服务架构"],"sub_categories":["9、效率工具集合"],"readme":"yal - Yet Another Landingpage\n===\n[![LICENSE](https://img.shields.io/github/license/timo-reymann/yal)](https://github.com/timo-reymann/yal/blob/main/LICENSE)\n[![DockerHub Pulls](https://img.shields.io/docker/pulls/timoreymann/yal)](https://hub.docker.com/r/timoreymann/yal)\n[![Go Report Card](https://goreportcard.com/badge/github.com/timo-reymann/yal)](https://goreportcard.com/report/github.com/timo-reymann/yal)\n[![codecov](https://codecov.io/gh/timo-reymann/yal/graph/badge.svg?token=rsQYV5lODS)](https://codecov.io/gh/timo-reymann/yal)\n[![CircleCI](https://circleci.com/gh/timo-reymann/yal.svg?style=shield)](https://app.circleci.com/pipelines/github/timo-reymann/yal)\n[![GitHub Release](https://img.shields.io/github/v/tag/timo-reymann/yal?label=version)](https://github.com/timo-reymann/yal/releases)\n[![Renovate](https://img.shields.io/badge/renovate-enabled-green?logo=data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAzNjkgMzY5Ij48Y2lyY2xlIGN4PSIxODkuOSIgY3k9IjE5MC4yIiByPSIxODQuNSIgZmlsbD0iI2ZmZTQyZSIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoLTUgLTYpIi8+PHBhdGggZmlsbD0iIzhiYjViNSIgZD0iTTI1MSAyNTZsLTM4LTM4YTE3IDE3IDAgMDEwLTI0bDU2LTU2YzItMiAyLTYgMC03bC0yMC0yMWE1IDUgMCAwMC03IDBsLTEzIDEyLTktOCAxMy0xM2ExNyAxNyAwIDAxMjQgMGwyMSAyMWM3IDcgNyAxNyAwIDI0bC01NiA1N2E1IDUgMCAwMDAgN2wzOCAzOHoiLz48cGF0aCBmaWxsPSIjZDk1NjEyIiBkPSJNMzAwIDI4OGwtOCA4Yy00IDQtMTEgNC0xNiAwbC00Ni00NmMtNS01LTUtMTIgMC0xNmw4LThjNC00IDExLTQgMTUgMGw0NyA0N2M0IDQgNCAxMSAwIDE1eiIvPjxwYXRoIGZpbGw9IiMyNGJmYmUiIGQ9Ik04MSAxODVsMTgtMTggMTggMTgtMTggMTh6Ii8+PHBhdGggZmlsbD0iIzI1YzRjMyIgZD0iTTIyMCAxMDBsMjMgMjNjNCA0IDQgMTEgMCAxNkwxNDIgMjQwYy00IDQtMTEgNC0xNSAwbC0yNC0yNGMtNC00LTQtMTEgMC0xNWwxMDEtMTAxYzUtNSAxMi01IDE2IDB6Ii8+PHBhdGggZmlsbD0iIzFkZGVkZCIgZD0iTTk5IDE2N2wxOC0xOCAxOCAxOC0xOCAxOHoiLz48cGF0aCBmaWxsPSIjMDBhZmIzIiBkPSJNMjMwIDExMGwxMyAxM2M0IDQgNCAxMSAwIDE2TDE0MiAyNDBjLTQgNC0xMSA0LTE1IDBsLTEzLTEzYzQgNCAxMSA0IDE1IDBsMTAxLTEwMWM1LTUgNS0xMSAwLTE2eiIvPjxwYXRoIGZpbGw9IiMyNGJmYmUiIGQ9Ik0xMTYgMTQ5bDE4LTE4IDE4IDE4LTE4IDE4eiIvPjxwYXRoIGZpbGw9IiMxZGRlZGQiIGQ9Ik0xMzQgMTMxbDE4LTE4IDE4IDE4LTE4IDE4eiIvPjxwYXRoIGZpbGw9IiMxYmNmY2UiIGQ9Ik0xNTIgMTEzbDE4LTE4IDE4IDE4LTE4IDE4eiIvPjxwYXRoIGZpbGw9IiMyNGJmYmUiIGQ9Ik0xNzAgOTVsMTgtMTggMTggMTgtMTggMTh6Ii8+PHBhdGggZmlsbD0iIzFiY2ZjZSIgZD0iTTYzIDE2N2wxOC0xOCAxOCAxOC0xOCAxOHpNOTggMTMxbDE4LTE4IDE4IDE4LTE4IDE4eiIvPjxwYXRoIGZpbGw9IiMzNGVkZWIiIGQ9Ik0xMzQgOTVsMTgtMTggMTggMTgtMTggMTh6Ii8+PHBhdGggZmlsbD0iIzFiY2ZjZSIgZD0iTTE1MyA3OGwxOC0xOCAxOCAxOC0xOCAxOHoiLz48cGF0aCBmaWxsPSIjMzRlZGViIiBkPSJNODAgMTEzbDE4LTE3IDE4IDE3LTE4IDE4ek0xMzUgNjBsMTgtMTggMTggMTgtMTggMTh6Ii8+PHBhdGggZmlsbD0iIzk4ZWRlYiIgZD0iTTI3IDEzMWwxOC0xOCAxOCAxOC0xOCAxOHoiLz48cGF0aCBmaWxsPSIjYjUzZTAyIiBkPSJNMjg1IDI1OGw3IDdjNCA0IDQgMTEgMCAxNWwtOCA4Yy00IDQtMTEgNC0xNiAwbC02LTdjNCA1IDExIDUgMTUgMGw4LTdjNC01IDQtMTIgMC0xNnoiLz48cGF0aCBmaWxsPSIjOThlZGViIiBkPSJNODEgNzhsMTgtMTggMTggMTgtMTggMTh6Ii8+PHBhdGggZmlsbD0iIzAwYTNhMiIgZD0iTTIzNSAxMTVsOCA4YzQgNCA0IDExIDAgMTZMMTQyIDI0MGMtNCA0LTExIDQtMTUgMGwtOS05YzUgNSAxMiA1IDE2IDBsMTAxLTEwMWM0LTQgNC0xMSAwLTE1eiIvPjxwYXRoIGZpbGw9IiMzOWQ5ZDgiIGQ9Ik0yMjggMTA4bC04LThjLTQtNS0xMS01LTE2IDBMMTAzIDIwMWMtNCA0LTQgMTEgMCAxNWw4IDhjLTQtNC00LTExIDAtMTVsMTAxLTEwMWM1LTQgMTItNCAxNiAweiIvPjxwYXRoIGZpbGw9IiNhMzM5MDQiIGQ9Ik0yOTEgMjY0bDggOGM0IDQgNCAxMSAwIDE2bC04IDdjLTQgNS0xMSA1LTE1IDBsLTktOGM1IDUgMTIgNSAxNiAwbDgtOGM0LTQgNC0xMSAwLTE1eiIvPjxwYXRoIGZpbGw9IiNlYjZlMmQiIGQ9Ik0yNjAgMjMzbC00LTRjLTYtNi0xNy02LTIzIDAtNyA3LTcgMTcgMCAyNGw0IDRjLTQtNS00LTExIDAtMTZsOC04YzQtNCAxMS00IDE1IDB6Ii8+PHBhdGggZmlsbD0iIzEzYWNiZCIgZD0iTTEzNCAyNDhjLTQgMC04LTItMTEtNWwtMjMtMjNhMTYgMTYgMCAwMTAtMjNMMjAxIDk2YTE2IDE2IDAgMDEyMiAwbDI0IDI0YzYgNiA2IDE2IDAgMjJMMTQ2IDI0M2MtMyAzLTcgNS0xMiA1em03OC0xNDdsLTQgMi0xMDEgMTAxYTYgNiAwIDAwMCA5bDIzIDIzYTYgNiAwIDAwOSAwbDEwMS0xMDFhNiA2IDAgMDAwLTlsLTI0LTIzLTQtMnoiLz48cGF0aCBmaWxsPSIjYmY0NDA0IiBkPSJNMjg0IDMwNGMtNCAwLTgtMS0xMS00bC00Ny00N2MtNi02LTYtMTYgMC0yMmw4LThjNi02IDE2LTYgMjIgMGw0NyA0NmM2IDcgNiAxNyAwIDIzbC04IDhjLTMgMy03IDQtMTEgNHptLTM5LTc2Yy0xIDAtMyAwLTQgMmwtOCA3Yy0yIDMtMiA3IDAgOWw0NyA0N2E2IDYgMCAwMDkgMGw3LThjMy0yIDMtNiAwLTlsLTQ2LTQ2Yy0yLTItMy0yLTUtMnoiLz48L3N2Zz4=)](https://renovatebot.com)\n[![Quality Gate Status](https://sonarcloud.io/api/project_badges/measure?project=timo-reymann_yal\u0026metric=alert_status)](https://sonarcloud.io/summary/new_code?id=timo-reymann_yal)\n[![Security Rating](https://sonarcloud.io/api/project_badges/measure?project=timo-reymann_yal\u0026metric=security_rating)](https://sonarcloud.io/summary/new_code?id=timo-reymann_yal)\n[![Bugs](https://sonarcloud.io/api/project_badges/measure?project=timo-reymann_yal\u0026metric=bugs)](https://sonarcloud.io/summary/new_code?id=timo-reymann_yal)\n\n\u003cp align=\"center\"\u003e\n\t\u003cimg width=\"800\" src=\"https://raw.githubusercontent.com/timo-reymann/yal/main/.github/images/example.png\"\u003e\n    \u003cbr /\u003e\n    A simple link hub, to display and search links. Allows easy branding, runs with the least privileges and is simple to use.\n\u003c/p\u003e\n\n## Demo\n\n[Click here](https://timo-reymann.github.io/yal/)\n\n## Features\n\n- statically generated site\n- single static-compiled go binary\n- runs as non-root by default\n- integrate any search engine\n- simple and intuitive design\n- integrated search\n- inlines external images on start up\n- dependency free\n- fully accessible for blind people \u0026 screen reader users\n\n## Requirements\n\n- any container platform or supported base system\n\n## Installation\n\n### Run server as container\n\nThe container generates the static HTML page on startup, keeps it in memory and serves it using a go webserver.\n\nYou can simply run it using e.g. docker with docker-compose:\n\n```yaml\nversion: \"3.5\"\nservices:\n  yal:\n    image: timoreymann/yal:latest # check for version to use if you would like to pin it\n    restart: always\n    ports:\n      - \u003cpublic-port\u003e:2024\n    volumes:\n      - ./config:/app/config\n      - ./icons:/app/icons # optional in case you want to use local icons\n      - ./images:/app/images # contains favicon etc.\n    environment:\n      # Port to listen\n      YAL_PORT: 2024\n      # page title for html\n      YAL_PAGE_TITLE: My link hub\n      # Path to config files\n      YAL_CONFIG_FOLDER: /app/config\n      # Path to images, see below for available ones\n      YAL_IMAGES_FOLDER: /app/images\n      # Omit file extension as it will be picked up by name automatically\n      # each of the entries is searched like ${YAL_IMAGES_FOLDER}/\u003cicon\u003e{png,jpg,jpeg,svg}\n      # if that does not succeed, an attempt is made to load the path as is and if\n      # there is no such file it tries to load it as an URL.\n      YAL_MASCOT: mascot # the mascot to display on the left\n      YAL_LOGO: logo # logo to display on the right\n      YAL_BACKGROUND: background # background image for page\n      YAL_FAVICON: favicon # favicon to serve\n```\n\n### Generate static HTML file\n\nSpecifying all env vars manually (if you want to customize them) and keeping the directory structure you can also just\ngenerate a static HTML page.\n\n1. Download the [latest release](https://github.com/timo-reymann/yal/releases/latest) for your platform\n2. `./yal --render --output file.html`\n3. Serve `file.html` using any static file server\n\n### Use with your CI provider\n\nInstead of the regular image use the CI version: `timoreymann/yal:ci` or for a versioned\ntag `timoreymann/yal:{version}-ci`.\n\n#### CircleCI\n\n```yaml\nversion: 2.1\n\n# Define the jobs we want to run for this project\njobs:\n  build-page:\n    docker:\n      - image: timoreymann/yal:ci\n    steps:\n      # Checkout repo with yal config and assets\n      - checkout\n      - run:\n          name: Generate page with yal\n          command: yal\n      # Upload the artifact html somewhere\n      - store_artifacts:\n          path: templated.html\n\nworkflows:\n  build_link_hub:\n    jobs:\n      - build-page\n```\n\n#### Gitlab CI\n\n```yaml\nstages:\n  - build\n\nbuild-page:\n  stage: build\n  image:\n    name: timoreymann/yal:ci\n    entrypoint: [\"\"]\n  script:\n    # Build page with yal config and assets from project\n    - yal\n  artifacts:\n    paths:\n      - templated.html\n```\n\n## Configuration\n\nTHe container comes with some demo data by default, while the CLI will fail with an error when you attempt to render the\npage without the corresponding files present.\n\n### Configuration\n\n| Environment variable  | Flag                | Default                                     | Description                                                                                                                                                                                                      |\n|:----------------------|:--------------------|:--------------------------------------------|:-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|\n| YAL_BACKGROUND        | --background        | `background`                                | Basename of a file without extension (searched in images-folder) or an HTTP url of the image to be used as a background image                                                                                    |\n| YAL_BACKGROUND_FILTER | --background-filter | `blur(5px) brightness(0.9)`                 | CSS Filter to apply to the background image. See [MDN docs](https://developer.mozilla.org/en-US/docs/Web/CSS/filter-function) for more information and examples for the filter CSS function for more information |\n| YAL_CONFIG_FOLDER     | --config-folder     | `config`                                    | Relative or absolute path where the configuration files reside                                                                                                                                                   |\n| YAL_FAVICON           | --favicon           | `favicon`                                   | Basename of a file without extension (searched in images-folder) or an HTTP url of the image to be used as favicon for the page                                                                                  |\n| YAL_IMAGES_FOLDER     | --images-folder     | `images`                                    | Relative or absolute path where the images reside                                                                                                                                                                |\n| YAL_LOGO              | --logo              | `logo`                                      | Basename of a file  without extension (searched in images-folder) or an HTTP url of the image to be used as a logo on the right                                                                                  |\n| YAL_MASCOT            | --mascot            | `mascot`                                    | Basename of a file without extension (searched in images-folder) or an HTTP url of the image to be used as a logo on the left                                                                                    |\n| YAL_OUTPUT            | --output            | `templated.html`                            | File to render to if -render is specified, use - to render to stdout                                                                                                                                             |\n| YAL_PAGE_TITLE        | --page-title        | `LinkHub - The place where it just clicks.` | Title of the HTML page generated                                                                                                                                                                                 |\n| YAL_PORT              | --port              | `2024`                                      | The HTTP port of the server when run with serve (default)                                                                                                                                                        |\n| YAL_RENDER            | --render            | `false`                                     | Render to output and exit                                                                                                                                                                                        |\n| YAL_SERVE             | --serve             | `false`                                     | Render and Serve on HTTP                                                                                                                                                                                         |\n| YAL_TEMPLATE_FILE     | --template-file     | `builtin`                                   | Template file to Render, builtin uses the bundled one with yal                                                                                                                                                   |\n\n### Files\n\nBesides the env vars, there are two config files to maintain:\n\n#### searchEngines.json\n\nConfigures the search engines for search box to display as last elements\n\n```json\n[\n  {\n    \"title\": \"Name\",\n    \"urlPrefix\": \"https://my.search?text=\u003chere search term will be appended\u003e\"\n  }\n]\n```\n\n#### items.json\n\nConfigures the links to display.\n\n```json\n[\n  {\n    \"title\": \"\u003cTitle of the section\u003e\",\n    \"entries\": [\n      {\n        \"text\": \"\u003cDisplay text for the link\u003e\",\n        \"link\": \"\u003clink\u003e\",\n        \"description\": \"\u003cshort description for search and hover tooltip\u003e\",\n        \"icon\": \"\u003curl or local path, can be relative; needs to be accessible by container and will be inlined on start up\u003e\"\n      }\n    ]\n  }\n]\n```\n\n## Motivation\n\nThere are a tons of landing pages out there, each has a unique set of features.\n\nSome simply provide a lot of stuff that are not necessary for a simple link hub. Others look too cluttered or are not\nintuitive to use.\n\nThis project aims to fill the gap and provide a link hub with search that is easy to brand and use. Nothing more or\nless.\n\n## Contributing\n\nI love your input! I want to make contributing to this project as easy and transparent as possible, whether it's:\n\n- Reporting a bug\n- Discussing the current state of the configuration\n- Submitting a fix\n- Proposing new features\n- Becoming a maintainer\n\nTo get started please read the [Contribution Guidelines](./CONTRIBUTING.md).\n\n## Development\n\n### Requirements\n\n- [GNU make](https://www.gnu.org/software/make/)\n- [Docker](https://docs.docker.com/get-docker/)\n- [pre-commit](https://pre-commit.com/)\n- Go 1.21\n\n### Test\n\n```shell\nmake test\n```\n\n### Build\n\n```shell\nmake build\n```\n\n### Alternatives\n\n- [Heimdall](https://github.com/linuxserver/Heimdall) - in case you need more powerful features such as widgets etc.\n- [jump](https://github.com/daledavies/jump) - if you want more whitespace and hidden functionality by default\n- [homepage](https://github.com/gethomepage/homepage) - if you want to utilize all the space completely and need widgets\n- [homer](https://github.com/bastienwirtz/homer) - for a bit more bloated UI\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftimo-reymann%2Fyal","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftimo-reymann%2Fyal","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftimo-reymann%2Fyal/lists"}