Compare commits
12 Commits
162fbabd26
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| 37e14f08db | |||
| 76e6219776 | |||
| 02ee9aea80 | |||
| 23ec1fdf80 | |||
| ef8a22d55b | |||
| 5aa3612cdd | |||
| 9adf6f55a2 | |||
| 604d301a1c | |||
| 956b284d4b | |||
| 0a4b1a24f7 | |||
| de2044343d | |||
| b8b7baee0f |
21
LICENSE
Normal file
21
LICENSE
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2026 JirkaBuilds
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
||||||
@@ -13,3 +13,10 @@ hugo new projects/{article_name}.md
|
|||||||
```
|
```
|
||||||
|
|
||||||
Then just edit `*/{article_name}.md` and add content.
|
Then just edit `*/{article_name}.md` and add content.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
## License
|
||||||
|
Unless otherwise stated, the source code of this website (HTML, CSS, JavaScript, Hugo configuration) is licensed under the **MIT License** (see the `LICENSE` file).
|
||||||
|
|
||||||
|
All blog content (article texts in the `/content` directory and photographs/images created by the author) is licensed under the **Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International (CC BY-NC-SA 4.0)**.
|
||||||
|
|||||||
@@ -4,12 +4,16 @@ draft: false
|
|||||||
title: "Let's start a blog!"
|
title: "Let's start a blog!"
|
||||||
author: "Jirka"
|
author: "Jirka"
|
||||||
tags: ["hugo", "idea", "guide", "tutorial"]
|
tags: ["hugo", "idea", "guide", "tutorial"]
|
||||||
categories: ["blog", "idea"]
|
categories: ["Blog setup", "idea"]
|
||||||
description: "Behind the scenes of the idea and setup."
|
description: "Behind the scenes of the idea and setup."
|
||||||
---
|
---
|
||||||
|
|
||||||
This blog has been created as one of my personal projects, first one released on this page. (Actually, this article, about creating this blog, is being written before creation of the blog and this page).
|
This blog has been created as one of my personal projects, first one released on this page. (Actually, this article, about creating this blog, is being written before creation of the blog and this page).
|
||||||
|
|
||||||
|
> [!WARNING]
|
||||||
|
> If you decide to follow my steps, please, be careful and use your head. I do not guarantee they will work for you and do so at your own risk.
|
||||||
|
|
||||||
|
|
||||||
## How it started
|
## How it started
|
||||||
|
|
||||||
The original idea was simple: **I would like to share my projects and knowledge with others.** But how?
|
The original idea was simple: **I would like to share my projects and knowledge with others.** But how?
|
||||||
@@ -36,7 +40,7 @@ This article is just about how to set up the Hugo for my purpose and how the con
|
|||||||
|
|
||||||
## Hugo setup
|
## Hugo setup
|
||||||
|
|
||||||
Work with hugo is super simple, I've start with their official [guide](https://gohugo.io/getting-started/quick-start/), but I will cover basic steps here.
|
Work with Hugo is super simple, I've start with their official [guide](https://gohugo.io/getting-started/quick-start/), but I will cover basic steps here.
|
||||||
|
|
||||||
To create empty Hugo project (after installing Hugo), start with:
|
To create empty Hugo project (after installing Hugo), start with:
|
||||||
```bash
|
```bash
|
||||||
@@ -142,3 +146,6 @@ So I've created `layouts/_default/_markup/render-link.html` will follow content:
|
|||||||
```
|
```
|
||||||
|
|
||||||
It creates correct links just from file links and will warn me if anything will go wrong.
|
It creates correct links just from file links and will warn me if anything will go wrong.
|
||||||
|
|
||||||
|
---
|
||||||
|
This article is one from series about this blog and self-hosting. All connected articles can found [here](categories/blog-setup).
|
||||||
@@ -1,16 +1,19 @@
|
|||||||
---
|
---
|
||||||
date: '2026-03-24T10:17:21+01:00'
|
date: '2026-03-24T10:17:21+01:00'
|
||||||
draft: false
|
draft: false
|
||||||
title: 'Hosting Blog'
|
title: 'How to self-host a blog'
|
||||||
author: "Jirka"
|
author: "Jirka"
|
||||||
tags: ["caddy", "vps", "wireguard", "docker", "guide", "tutorial"]
|
tags: ["caddy", "docker", "wireguard", "vps", "guide", "tutorial", "self-hosted"]
|
||||||
categories: ["blog", "self-hosting"]
|
categories: ["Blog setup"]
|
||||||
description: "How this blog came online."
|
description: "How this blog came online without public IP."
|
||||||
---
|
---
|
||||||
|
|
||||||
In last post [Let's start a blog!](./01-blog.md) I've introduced idea and how-to guide how I will write this blog, but left it offline.
|
In last post [Let's start a blog!](./01-blog.md) I've introduced idea and how-to guide how I will write this blog, but left it offline.
|
||||||
That is going to change in this post.
|
That is going to change in this post.
|
||||||
|
|
||||||
|
> [!WARNING]
|
||||||
|
> If you decide to follow my steps, please, be careful and use your head. I do not guarantee they will work for you and do so at your own risk.
|
||||||
|
|
||||||
## Requirements
|
## Requirements
|
||||||
|
|
||||||
This whole blog/website project is about self-hosting. That said, I will host this page my on server/PC at home. For that, you usually have public IP address.
|
This whole blog/website project is about self-hosting. That said, I will host this page my on server/PC at home. For that, you usually have public IP address.
|
||||||
@@ -183,10 +186,10 @@ Let's start by creating `docker-compose.yml`:
|
|||||||
```yaml docker-compose.yml
|
```yaml docker-compose.yml
|
||||||
# Shared network between containers (for later use)
|
# Shared network between containers (for later use)
|
||||||
networks:
|
networks:
|
||||||
jirkabuilds_proxy_network:
|
proxy_network:
|
||||||
|
|
||||||
services:
|
services:
|
||||||
jirkabuilds_wireguard:
|
wireguard:
|
||||||
image: linuxserver/wireguard:latest
|
image: linuxserver/wireguard:latest
|
||||||
container_name: wireguard
|
container_name: wireguard
|
||||||
cap_add:
|
cap_add:
|
||||||
@@ -199,13 +202,13 @@ services:
|
|||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
# We will add wireguard to this network, but limit access from WG itself
|
# We will add wireguard to this network, but limit access from WG itself
|
||||||
networks:
|
networks:
|
||||||
- jirkabuilds_proxy_network
|
- proxy_network
|
||||||
|
|
||||||
jirkabuilds_caddy:
|
caddy:
|
||||||
image: caddy:latest
|
image: caddy:latest
|
||||||
container_name: jirkabuilds_caddy
|
container_name: caddy
|
||||||
# Caddy shares all networks with WireGuard
|
# Caddy shares all networks with WireGuard
|
||||||
network_mode: "service:jirkabuilds_wireguard"
|
network_mode: "service:wireguard"
|
||||||
volumes:
|
volumes:
|
||||||
- ./caddy/Caddyfile:/etc/caddy/Caddyfile
|
- ./caddy/Caddyfile:/etc/caddy/Caddyfile
|
||||||
- ./site_data:/srv
|
- ./site_data:/srv
|
||||||
@@ -261,3 +264,6 @@ docker compose up -d
|
|||||||
```
|
```
|
||||||
|
|
||||||
And your web should be online.
|
And your web should be online.
|
||||||
|
|
||||||
|
---
|
||||||
|
This article is one from series about this blog and self-hosting. All connected articles can found [here](categories/blog-setup).
|
||||||
@@ -4,7 +4,7 @@ draft: false
|
|||||||
title: 'Time for version control'
|
title: 'Time for version control'
|
||||||
author: "Jirka"
|
author: "Jirka"
|
||||||
tags: ["gitea", "self-hosted", "docker", "guide", "tutorial"]
|
tags: ["gitea", "self-hosted", "docker", "guide", "tutorial"]
|
||||||
categories: ["self-host", "documentation"]
|
categories: ["Blog setup"]
|
||||||
description: "Let's look at how to self host gitea on our infrastructure."
|
description: "Let's look at how to self host gitea on our infrastructure."
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -12,6 +12,9 @@ How would I share my projects with you, if I do not have any git hosting server?
|
|||||||
|
|
||||||
That is a reason, why we need to set up one! You can choose from more variant, but I decided for [Gitea](https://about.gitea.com/).
|
That is a reason, why we need to set up one! You can choose from more variant, but I decided for [Gitea](https://about.gitea.com/).
|
||||||
|
|
||||||
|
> [!WARNING]
|
||||||
|
> If you decide to follow my steps, please, be careful and use your head. I do not guarantee they will work for you and do so at your own risk.
|
||||||
|
|
||||||
## Self-hosting Gitea
|
## Self-hosting Gitea
|
||||||
|
|
||||||
Thanks to our earlier setup, next step is pretty simple.
|
Thanks to our earlier setup, next step is pretty simple.
|
||||||
@@ -37,7 +40,7 @@ mv * web
|
|||||||
Now create new `docker-compose.yml` file with following content:
|
Now create new `docker-compose.yml` file with following content:
|
||||||
```yaml
|
```yaml
|
||||||
networks:
|
networks:
|
||||||
jirkabuilds_proxy_network:
|
proxy_network:
|
||||||
|
|
||||||
include:
|
include:
|
||||||
- web/docker-compose.yml
|
- web/docker-compose.yml
|
||||||
@@ -56,24 +59,24 @@ And you should be back online.
|
|||||||
Create new directory `gitea` for Gitea and it's data an into it create new `docker-compose.yml` file with following content:
|
Create new directory `gitea` for Gitea and it's data an into it create new `docker-compose.yml` file with following content:
|
||||||
```yaml
|
```yaml
|
||||||
networks:
|
networks:
|
||||||
gitea-internal:
|
gitea_internal:
|
||||||
jirkabuilds_proxy_network:
|
proxy_network:
|
||||||
|
|
||||||
services:
|
services:
|
||||||
jirkabuilds_gitea:
|
gitea:
|
||||||
image: docker.gitea.com/gitea:latest
|
image: docker.gitea.com/gitea:latest
|
||||||
container_name: jirkabuilds_gitea
|
container_name: gitea
|
||||||
environment:
|
environment:
|
||||||
- USER_UID=${APP_UID}
|
- USER_UID=${APP_UID}
|
||||||
- USER_GID=${APP_GID}
|
- USER_GID=${APP_GID}
|
||||||
- GITEA__database__DB_TYPE=postgres
|
- GITEA__database__DB_TYPE=postgres
|
||||||
- GITEA__database__HOST=jirkabuilds_gitea_db:5432
|
- GITEA__database__HOST=gitea_db:5432
|
||||||
- GITEA__database__NAME=${DB_NAME}
|
- GITEA__database__NAME=${DB_NAME}
|
||||||
- GITEA__database__USER=${DB_USER}
|
- GITEA__database__USER=${DB_USER}
|
||||||
- GITEA__database__PASSWD=${DB_PASSWORD}
|
- GITEA__database__PASSWD=${DB_PASSWORD}
|
||||||
restart: always
|
restart: always
|
||||||
networks:
|
networks:
|
||||||
- gitea-internal
|
- gitea_internal
|
||||||
volumes:
|
volumes:
|
||||||
- ./gitea:/data
|
- ./gitea:/data
|
||||||
- /etc/timezone:/etc/timezone:ro
|
- /etc/timezone:/etc/timezone:ro
|
||||||
@@ -84,7 +87,7 @@ services:
|
|||||||
depends_on:
|
depends_on:
|
||||||
- db
|
- db
|
||||||
|
|
||||||
jirkabuilds_gitea_db:
|
gitea_db:
|
||||||
image: docker.io/library/postgres:14
|
image: docker.io/library/postgres:14
|
||||||
restart: always
|
restart: always
|
||||||
environment:
|
environment:
|
||||||
@@ -92,7 +95,7 @@ services:
|
|||||||
- POSTGRES_PASSWORD=${DB_PASSWORD}
|
- POSTGRES_PASSWORD=${DB_PASSWORD}
|
||||||
- POSTGRES_DB=${DB_NAME}
|
- POSTGRES_DB=${DB_NAME}
|
||||||
networks:
|
networks:
|
||||||
- gitea-internal
|
- gitea_internal
|
||||||
volumes:
|
volumes:
|
||||||
- ./postgres:/var/lib/postgresql/data
|
- ./postgres:/var/lib/postgresql/data
|
||||||
```
|
```
|
||||||
@@ -122,35 +125,38 @@ When you finish initial setup, we can add Gitea to our stack. Start by editing G
|
|||||||
|
|
||||||
There you should remove line with ports and port definition under Gitea service and add proxy network under networks. Changed part of the file should look like this:
|
There you should remove line with ports and port definition under Gitea service and add proxy network under networks. Changed part of the file should look like this:
|
||||||
```yaml
|
```yaml
|
||||||
jirkabuilds_gitea:
|
gitea:
|
||||||
image: docker.gitea.com/gitea:latest
|
image: docker.gitea.com/gitea:latest
|
||||||
container_name: jirkabuilds_gitea
|
container_name: gitea
|
||||||
environment:
|
environment:
|
||||||
- USER_UID=${APP_UID}
|
- USER_UID=${APP_UID}
|
||||||
- USER_GID=${APP_GID}
|
- USER_GID=${APP_GID}
|
||||||
- GITEA__database__DB_TYPE=postgres
|
- GITEA__database__DB_TYPE=postgres
|
||||||
- GITEA__database__HOST=jirkabuilds_gitea_db:5432
|
- GITEA__database__HOST=gitea_db:5432
|
||||||
- GITEA__database__NAME=${DB_NAME}
|
- GITEA__database__NAME=${DB_NAME}
|
||||||
- GITEA__database__USER=${DB_USER}
|
- GITEA__database__USER=${DB_USER}
|
||||||
- GITEA__database__PASSWD=${DB_PASSWORD}
|
- GITEA__database__PASSWD=${DB_PASSWORD}
|
||||||
restart: always
|
restart: always
|
||||||
networks:
|
networks:
|
||||||
- gitea-internal
|
- gitea_internal
|
||||||
- jirkabuilds_proxy_network
|
- proxy_network
|
||||||
volumes:
|
volumes:
|
||||||
- ./gitea:/data
|
- ./gitea:/data
|
||||||
- /etc/timezone:/etc/timezone:ro
|
- /etc/timezone:/etc/timezone:ro
|
||||||
- /etc/localtime:/etc/localtime:ro
|
- /etc/localtime:/etc/localtime:ro
|
||||||
depends_on:
|
depends_on:
|
||||||
- jirkabuilds_gitea_db
|
- gitea_db
|
||||||
```
|
```
|
||||||
|
|
||||||
Last step is to change `Caddyfile` in `web` folder. All you need to do is add following lines:
|
Last step is to change `Caddyfile` in `web` folder. All you need to do is add following lines:
|
||||||
```
|
```
|
||||||
git.jirkabuilds.dev {
|
git.jirkabuilds.dev {
|
||||||
reverse_proxy jirkabuilds_gitea:3000
|
reverse_proxy gitea:3000
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
If you have set up DNS correctly, after shutting the stack down and up the Gitea should be online.
|
If you have set up DNS correctly, after shutting the stack down and up the Gitea should be online.
|
||||||
|
|
||||||
And that's it!
|
And that's it!
|
||||||
|
|
||||||
|
---
|
||||||
|
This article is one from series about this blog and self-hosting. All connected articles can found [here](categories/blog-setup).
|
||||||
@@ -1,10 +1,10 @@
|
|||||||
---
|
---
|
||||||
date: '2026-03-24T20:36:26+01:00'
|
date: '2026-03-24T20:36:26+01:00'
|
||||||
draft: false
|
draft: false
|
||||||
title: 'Automatic web update release'
|
title: 'Automatic web deployment'
|
||||||
author: "Jirka"
|
author: "Jirka"
|
||||||
tags: ["self-host", "gitea", "automation"]
|
tags: ["self-hosted", "gitea", "automation", "docker"]
|
||||||
categories: ["self-host", "documentation", "automation"]
|
categories: ["Blog setup"]
|
||||||
description: "Last step, how to relase changes to web automatically"
|
description: "Last step, how to relase changes to web automatically"
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -14,6 +14,9 @@ The idea is simple, push changes to `master` branch of repo holding this web and
|
|||||||
|
|
||||||
We will split this problem into two: Building web with Hugo and second, updating files with webhook. Let's start.
|
We will split this problem into two: Building web with Hugo and second, updating files with webhook. Let's start.
|
||||||
|
|
||||||
|
> [!WARNING]
|
||||||
|
> If you decide to follow my steps, please, be careful and use your head. I do not guarantee they will work for you and do so at your own risk.
|
||||||
|
|
||||||
## Set up Gitea runner
|
## Set up Gitea runner
|
||||||
|
|
||||||
Gitea does support actions like GitHub, but you have to provide it runner to execute you tasks. We are going to use the most secured way, runner in docker, which will start another docker container in another docker.
|
Gitea does support actions like GitHub, but you have to provide it runner to execute you tasks. We are going to use the most secured way, runner in docker, which will start another docker container in another docker.
|
||||||
@@ -27,37 +30,37 @@ I will store this token into `.env` file inside my `gitea` directory created in
|
|||||||
Next we modify Gitea `docker-compose.yml` file to look as follows:
|
Next we modify Gitea `docker-compose.yml` file to look as follows:
|
||||||
```yml
|
```yml
|
||||||
networks:
|
networks:
|
||||||
jirka_builds_gitea_internal:
|
gitea_internal:
|
||||||
jirkabuilds_proxy_network:
|
proxy_network:
|
||||||
jirkabuilds_gitea_runner_net: # For runner dind comunication
|
gitea_runner_net: # For runner dind comunication
|
||||||
jirkabuilds_gitea_net: # For runner gitea comunication, isolated from db
|
gitea_net: # For runner gitea comunication, isolated from db
|
||||||
|
|
||||||
|
|
||||||
services:
|
services:
|
||||||
jirkabuilds_gitea:
|
gitea:
|
||||||
image: docker.gitea.com/gitea:latest
|
image: docker.gitea.com/gitea:latest
|
||||||
container_name: jirkabuilds_gitea
|
container_name: gitea
|
||||||
environment:
|
environment:
|
||||||
- USER_UID=${APP_UID}
|
- USER_UID=${APP_UID}
|
||||||
- USER_GID=${APP_GID}
|
- USER_GID=${APP_GID}
|
||||||
- GITEA__database__DB_TYPE=postgres
|
- GITEA__database__DB_TYPE=postgres
|
||||||
- GITEA__database__HOST=jirkabuilds_gitea_db:5432
|
- GITEA__database__HOST=gitea_db:5432
|
||||||
- GITEA__database__NAME=${DB_NAME}
|
- GITEA__database__NAME=${DB_NAME}
|
||||||
- GITEA__database__USER=${DB_USER}
|
- GITEA__database__USER=${DB_USER}
|
||||||
- GITEA__database__PASSWD=${DB_PASSWORD}
|
- GITEA__database__PASSWD=${DB_PASSWORD}
|
||||||
restart: always
|
restart: always
|
||||||
networks:
|
networks:
|
||||||
- jirka_builds_gitea_internal
|
- gitea_internal
|
||||||
- jirkabuilds_proxy_network
|
- proxy_network
|
||||||
- jirkabuilds_gitea_net
|
- gitea_net
|
||||||
volumes:
|
volumes:
|
||||||
- ./gitea:/data
|
- ./gitea:/data
|
||||||
- /etc/timezone:/etc/timezone:ro
|
- /etc/timezone:/etc/timezone:ro
|
||||||
- /etc/localtime:/etc/localtime:ro
|
- /etc/localtime:/etc/localtime:ro
|
||||||
depends_on:
|
depends_on:
|
||||||
- jirkabuilds_gitea_db
|
- gitea_db
|
||||||
|
|
||||||
jirkabuilds_gitea_db:
|
gitea_db:
|
||||||
image: docker.io/library/postgres:14
|
image: docker.io/library/postgres:14
|
||||||
restart: always
|
restart: always
|
||||||
environment:
|
environment:
|
||||||
@@ -65,33 +68,33 @@ services:
|
|||||||
- POSTGRES_PASSWORD=${DB_PASSWORD}
|
- POSTGRES_PASSWORD=${DB_PASSWORD}
|
||||||
- POSTGRES_DB=${DB_NAME}
|
- POSTGRES_DB=${DB_NAME}
|
||||||
networks:
|
networks:
|
||||||
- jirka_builds_gitea_internal
|
- gitea_internal
|
||||||
volumes:
|
volumes:
|
||||||
- ./postgres:/var/lib/postgresql/data
|
- ./postgres:/var/lib/postgresql/data
|
||||||
|
|
||||||
# New
|
# New
|
||||||
dind:
|
dind:
|
||||||
image: docker:dind
|
image: docker:dind
|
||||||
container_name: jirkabuilds-gitea-dind
|
container_name: gitea-dind
|
||||||
restart: always
|
restart: always
|
||||||
privileged: true
|
privileged: true
|
||||||
environment:
|
environment:
|
||||||
- DOCKER_TLS_CERTDIR=/certs
|
- DOCKER_TLS_CERTDIR=/certs
|
||||||
volumes:
|
volumes:
|
||||||
- jirkabuilds_dind_certs:/certs
|
- dind_certs:/certs
|
||||||
- jirkabuilds_dind_data:/var/lib/docker
|
- dind_data:/var/lib/docker
|
||||||
networks:
|
networks:
|
||||||
jirkabuilds_gitea_runner_net:
|
gitea_runner_net:
|
||||||
aliases:
|
aliases:
|
||||||
- docker
|
- docker
|
||||||
|
|
||||||
runner:
|
runner:
|
||||||
image: gitea/act_runner:latest
|
image: gitea/act_runner:latest
|
||||||
container_name: jirkabuilds-gitea-runner
|
container_name: gitea-runner
|
||||||
restart: always
|
restart: always
|
||||||
depends_on:
|
depends_on:
|
||||||
- dind
|
- dind
|
||||||
- jirkabuilds_gitea
|
- gitea
|
||||||
environment:
|
environment:
|
||||||
- GITEA_INSTANCE_URL=https://git.jirkabuilds.dev
|
- GITEA_INSTANCE_URL=https://git.jirkabuilds.dev
|
||||||
- GITEA_RUNNER_REGISTRATION_TOKEN=${RUNNER_TOKEN}
|
- GITEA_RUNNER_REGISTRATION_TOKEN=${RUNNER_TOKEN}
|
||||||
@@ -100,16 +103,16 @@ services:
|
|||||||
- DOCKER_CERT_PATH=/certs/client
|
- DOCKER_CERT_PATH=/certs/client
|
||||||
- DOCKER_TLS_VERIFY=1
|
- DOCKER_TLS_VERIFY=1
|
||||||
volumes:
|
volumes:
|
||||||
- jirkabuilds_runner_data:/data
|
- runner_data:/data
|
||||||
- jirkabuilds_dind_certs:/certs:ro
|
- dind_certs:/certs:ro
|
||||||
networks:
|
networks:
|
||||||
- jirkabuilds_gitea_net
|
- gitea_net
|
||||||
- jirkabuilds_gitea_runner_net
|
- gitea_runner_net
|
||||||
|
|
||||||
volumes:
|
volumes:
|
||||||
jirkabuilds_dind_certs:
|
dind_certs:
|
||||||
jirkabuilds_dind_data:
|
dind_data:
|
||||||
jirkabuilds_runner_data:
|
runner_data:
|
||||||
```
|
```
|
||||||
|
|
||||||
And that is all, after `docker compose up -d`, runner should show up in the registry.
|
And that is all, after `docker compose up -d`, runner should show up in the registry.
|
||||||
@@ -160,11 +163,17 @@ jobs:
|
|||||||
cd public
|
cd public
|
||||||
zip -r ../build.zip ./*
|
zip -r ../build.zip ./*
|
||||||
|
|
||||||
|
# Need to delete old package first, otherwise new will not replace it
|
||||||
|
- name: Delete old package (if exists)
|
||||||
|
run: |
|
||||||
|
curl -X DELETE --user "${{ github.actor }}:${{ secrets.PACKAGE_TOKEN }}" \
|
||||||
|
"https://git.jirkabuilds.dev/api/packages/${{ github.repository_owner }}/generic/hugo-build/latest/web.zip" || true
|
||||||
|
|
||||||
- name: Uploading package back to gitea
|
- name: Uploading package back to gitea
|
||||||
run: |
|
run: |
|
||||||
curl --user "${{ github.actor }}:${{ secrets.PACKAGE_TOKEN }}" \
|
curl -f --user "${{ github.actor }}:${{ secrets.PACKAGE_TOKEN }}" \
|
||||||
--upload-file build.zip \
|
--upload-file build.zip \
|
||||||
"https://git.jirkabuilds.dev/api/packages/${{ github.repository_owner }}/generic/hugo-build/latest/build.zip"
|
"https://git.jirkabuilds.dev/api/packages/${{ github.repository_owner }}/generic/hugo-build/latest/web.zip"
|
||||||
|
|
||||||
# TODO - Webhook
|
# TODO - Webhook
|
||||||
```
|
```
|
||||||
@@ -235,7 +244,7 @@ And last step is to create `docker-compose.yml`:
|
|||||||
services:
|
services:
|
||||||
webhook:
|
webhook:
|
||||||
build: .
|
build: .
|
||||||
container_name: jirkabuilds_release_web_webhook
|
container_name: release_web_webhook
|
||||||
volumes:
|
volumes:
|
||||||
- ./hooks.json:/etc/webhook/hooks.json:ro
|
- ./hooks.json:/etc/webhook/hooks.json:ro
|
||||||
- ./deploy.sh:/app/deploy.sh:ro
|
- ./deploy.sh:/app/deploy.sh:ro
|
||||||
@@ -243,16 +252,16 @@ services:
|
|||||||
command: ["-verbose", "-hooks=/etc/webhook/hooks.json", "-hotreload"]
|
command: ["-verbose", "-hooks=/etc/webhook/hooks.json", "-hotreload"]
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
networks:
|
networks:
|
||||||
- jirkabuilds_proxy_network
|
- proxy_network
|
||||||
|
|
||||||
networks:
|
networks:
|
||||||
jirkabuilds_proxy_network:
|
proxy_network:
|
||||||
```
|
```
|
||||||
|
|
||||||
You can see, we are using the same proxy network as for everything. Next step is to add following block to `Caddyfile`:
|
You can see, we are using the same proxy network as for everything. Next step is to add following block to `Caddyfile`:
|
||||||
```
|
```
|
||||||
hooks.jirkabuilds.dev {
|
hooks.jirkabuilds.dev {
|
||||||
reverse_proxy jirkabuilds_release_web_webhook:9000
|
reverse_proxy release_web_webhook:9000
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -272,3 +281,6 @@ Final last step is to replace #TODO in our workflow with following:
|
|||||||
```
|
```
|
||||||
|
|
||||||
And that is it. On next push, web should update itself automatically.
|
And that is it. On next push, web should update itself automatically.
|
||||||
|
|
||||||
|
---
|
||||||
|
This article is one from series about this blog and self-hosting. All connected articles can found [here](categories/blog-setup).
|
||||||
117
content/blog/05-ikea-fyrtur-repair/index.md
Normal file
117
content/blog/05-ikea-fyrtur-repair/index.md
Normal file
@@ -0,0 +1,117 @@
|
|||||||
|
---
|
||||||
|
date: '2026-04-06T15:54:30+02:00'
|
||||||
|
draft: false
|
||||||
|
title: 'How to repair IKEA FYRTUR Smart blinds'
|
||||||
|
author: "Jirka"
|
||||||
|
tags: ["repair", "3DPrint", "guide", "repair", "fix"]
|
||||||
|
categories: ["fix"]
|
||||||
|
description: "Overview of how to fix IKEA FYRTUR Smart blinds"
|
||||||
|
---
|
||||||
|
|
||||||
|
I do have two IKEA FYRTUR Smart blinds, which I do like a lot. Unfortunately, after 6 years of service, one of them decided to stop working.
|
||||||
|
|
||||||
|
The way it happened was very innocent, one day, after pulling the blind up in the morning, it refused to roll down in the evening. At that moment, I thought that maybe it was just the battery, but after recharge nothing changed. That was the moment I've become suspicion, that something bad happened.
|
||||||
|
|
||||||
|
## First step for saving
|
||||||
|
|
||||||
|
So what now?
|
||||||
|
|
||||||
|
In first place, there is no need to roll the blind by force to cover or uncover the window behind it. In my experience, it will not break anything if you do so, but you can easily lose your attachment to the wall, if you are not careful.
|
||||||
|
|
||||||
|
As first step, I do suggest detaching the blind from the wall. Attachments provided by Ikea are created for quick snap in/out attachment. So just take it down from the wall.
|
||||||
|
|
||||||
|
Now, when you look on the blind itself from the top, there are two screws in place where the frame is splitting into two. Just unscrew them, and it will slide to the side, which will release the cylinder with fabric.
|
||||||
|
Now you can easily roll up the fabric, without need to apply force.
|
||||||
|
|
||||||
|
## Second step, try to resurrect the motor and control board
|
||||||
|
|
||||||
|
I've read on Reddit from several people, that the main cause for blind to stop working was just loosen cable. If this is your case, you are lucky and should be able to fix it in just few minutes.
|
||||||
|
|
||||||
|
Another thing I can confirm is, that even when your motor is starting to fail, it is possible, that it will work again. I really suggest to check out [this YT video](https://www.youtube.com/watch?v=fNQunjjoAAg) and follow the steps in it. It does cover how to disassemble the blind and what to try to get it work.
|
||||||
|
|
||||||
|
Key step for me was plugging the motor directly into the battery. It somehow causes the motor to restart itself. After that, I was able to use my blind for few weeks, before it broke down again.
|
||||||
|
|
||||||
|
> [!NOTE]
|
||||||
|
> One thing to mention. In the video is said, that after plugging the battery in, the blind should try to retract itself. That is true, but I can confirm, that both of my blinds (only one was broken) are unsuccessful to do that when taken apart.
|
||||||
|
>
|
||||||
|
> This can be some indicator of pre fail state, but you should not give up. In my case, after assembling everything together, it started to work again as expected. (It is possible that the motor expect some resistance).
|
||||||
|
|
||||||
|
## Reassembling didn't help, what now?
|
||||||
|
|
||||||
|
Next step should be finding out, what part is broken. You've already got some clues on this from the YT video. If motor is not spinning when connected to the battery directly, it is probably it.
|
||||||
|
|
||||||
|
There are 3 parts which can broke down:
|
||||||
|
|
||||||
|
### Wireless board
|
||||||
|
If the blind is working right by hand (can be controller by buttons on it), but fails to follow wireless commands, than the Wireless board is faulty.
|
||||||
|
|
||||||
|
Great news is, that it is not needed for the blind to work, bad is that you have to touch it by hand anyway.
|
||||||
|
|
||||||
|
Your do have several options from there. You can replace it with Wi-Fi based board, which can be found there on GitHub [mjuhanne/ikea-fyrtur](https://github.com/mjuhanne/ikea-fyrtur/tree/main).
|
||||||
|
|
||||||
|
Or, you can do it your own way. The motor board is communicating via UART, so you can use Arduino or RPi and create the remote board your self. How the communication works and which commands do what is greatly documented in this repository [mjuhanne/fyrtur-motor-board](https://github.com/mjuhanne/fyrtur-motor-board?tab=readme-ov-file#uart-interface-command-structure), which contains custom firmware (but basic command are same for original).
|
||||||
|
|
||||||
|
### Motor control board
|
||||||
|
|
||||||
|
It is tricky to find out if the motor is causing issues or its control board. To be honest, I do not know how to distinguish this two.
|
||||||
|
|
||||||
|
In my case, I've been lucky that I do have two of those blinds, so I just exchanged motor in them and waited for the next broke down.
|
||||||
|
|
||||||
|
If the blind fail after taking motor from another blind, then the control board is broken. If fails the other blind, then the motor itself is bad.
|
||||||
|
|
||||||
|
For motor control board, there is repository on GitHub [daanvdl/fyrtur-motor-board-pcb](https://github.com/daanvdl/fyrtur-motor-board-pcb) which contains whole PCB recreated. You should be able to get manufactured new one with all this information.
|
||||||
|
|
||||||
|
|
||||||
|
### Broken motor
|
||||||
|
|
||||||
|
This case is last one possible and a bit unfortunate. I was not able to find any replacement motor for those blinds. So, if your motor died, you will not be able to get your blind working again as it was originally.
|
||||||
|
|
||||||
|
But, I've come with my own solution for this case. And will cover it down bellow.
|
||||||
|
|
||||||
|
## Replacement
|
||||||
|
|
||||||
|
It will work, you should not be worry, but it will be a bit more work.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
I find this [Zemismart ZM16B Zigbee Smart Roller Shade Blinds Motor](https://www.aliexpress.com/item/1005009985673198.html). Thanks to it, we will be able to retain as much from the original blind as possible and be able to get it working.
|
||||||
|
|
||||||
|
But there are two problems to solve:
|
||||||
|
|
||||||
|
### Original control gate
|
||||||
|
|
||||||
|
If you are still using the original Ikea control gate, which was needed for those blinds to control them via phone, you have to abandon it.
|
||||||
|
|
||||||
|
I've done this step a few months before one of the blinds broke down and was happy with it. You should use Home Assistant with some Zigbee Dongle (like SONOFF Zigbee 3.0 USB Dongle Plus E) instead.
|
||||||
|
|
||||||
|
The advantage is, that all the Ikea ecosystem will work (after setting everything up) the same, plus you can connect it with anything from other manufacturers.
|
||||||
|
|
||||||
|
There are tons of official guides how to do so like [this official one](https://www.home-assistant.io/installation/raspberrypi/) on how to set up HA with RPi and [this one](https://www.home-assistant.io/integrations/zha/) for Zigbee setup.
|
||||||
|
|
||||||
|
ZHA Added support for this specific tubular motor few months ago, so setting everything up was much easier for me, then I initially thought. If you are unable to get it working, make sure your Home Assistant installation is up-to-date.
|
||||||
|
|
||||||
|
### Make it physically compatible
|
||||||
|
|
||||||
|
The Zemismart tubular motor comes with several adapters for different kinds of blinds, but none of them is out of the box compatible with our FYRTUR Ikea blinds.
|
||||||
|
|
||||||
|
For that reason, I've designed adapters in FreeCAD, which can be 3D printed and used. Thanks to them, you should be able to fit the motor into the blind and use it as before.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
As you can see, new motor fitted perfectly!
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
|
||||||
|
All the files for 3D print can found on [Printables](https://www.printables.com/model/1673256-ikea-fyrtur-adapters-for-zemismart-zm16b-motor)
|
||||||
|
|
||||||
|
And all source files (like FreeCAD projects) can be found on my [Gitea](https://git.jirkabuilds.dev/jirka/Zemismart-FYRTUR-adapters).
|
||||||
|
|
||||||
|
## Final words
|
||||||
|
|
||||||
|
I am using this setup for a few weeks and it works great. I am using original Ikea switch and second non modified blind, and it all works happily together.
|
||||||
|
|
||||||
|
One downside of this modification is, that the new motor do have much smaller battery than the original. It is caused by fitting the battery into the tube instead of the original, above placement.
|
||||||
|
|
||||||
|
|
||||||
|
I've decided to compensate that by purchasing the motor with solar panel. I am unable to give verdict if it works or not, because I am not using it long enough, but I can say, it is charging. I will see...
|
||||||
BIN
content/blog/05-ikea-fyrtur-repair/modified_blind.jpg
Normal file
BIN
content/blog/05-ikea-fyrtur-repair/modified_blind.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.5 MiB |
BIN
content/blog/05-ikea-fyrtur-repair/motor.jpg
Normal file
BIN
content/blog/05-ikea-fyrtur-repair/motor.jpg
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 1.4 MiB |
BIN
content/blog/05-ikea-fyrtur-repair/parts_render.png
Normal file
BIN
content/blog/05-ikea-fyrtur-repair/parts_render.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 26 KiB |
19
content/projects/01-blog/index.md
Normal file
19
content/projects/01-blog/index.md
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
---
|
||||||
|
date: '2026-03-25T10:21:48+01:00'
|
||||||
|
draft: false
|
||||||
|
title: 'This webpage'
|
||||||
|
author: "Jirka"
|
||||||
|
tags: ["self-hosted", "docker"]
|
||||||
|
categories: ["projects"]
|
||||||
|
description: "This whole webpage is my project!"
|
||||||
|
git: "https://git.jirkabuilds.dev/jirka/web"
|
||||||
|
---
|
||||||
|
|
||||||
|
This is The first project shared on this webpage, and it is the webpage itself!
|
||||||
|
|
||||||
|
|
||||||
|
There are several articles connected to how this page was build [here](categories/blog-setup).
|
||||||
|
|
||||||
|
Source files for Hugo can be found on my Gitea [here](https://git.jirkabuilds.dev/jirka/web).
|
||||||
|
|
||||||
|
And that is it. Feel free to explore and learn something.
|
||||||
24
content/projects/02-ikea-fyrtur-repair/index.md
Normal file
24
content/projects/02-ikea-fyrtur-repair/index.md
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
---
|
||||||
|
date: '2026-04-06T18:41:36+02:00'
|
||||||
|
draft: False
|
||||||
|
title: 'Ikea FYRTUR blinds repair'
|
||||||
|
author: "Jirka"
|
||||||
|
tags: ["fix", "3Dprint"]
|
||||||
|
categories: ["project"]
|
||||||
|
description: "Fixing Ikea FYRTUR blinds by replacing motor"
|
||||||
|
git: "https://git.jirkabuilds.dev/jirka/Zemismart-FYRTUR-adapters"
|
||||||
|
---
|
||||||
|
|
||||||
|
After 6 year of hard work, my blinds from Ikea finally broke down. As one of my projects, I've decided to fix them and prolong their live.
|
||||||
|
|
||||||
|
This has been done by replacing original motor and logic boards by [Zemismart Zigbee Smart Roller Shade Blinds Motor](https://www.aliexpress.com/item/1005009985673198.html) and making it compatible by 3D printing custom designed adapters.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
All the source files (FreeCAD projects) can be found in repository on my [Gitea](https://git.jirkabuilds.dev/jirka/Zemismart-FYRTUR-adapters). Print files was also shared on [Printables](https://www.printables.com/model/1673256-ikea-fyrtur-adapters-for-zemismart-zm16b-motor).
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
More information about this project can be found in my blog article [How to repair IKEA FYRTUR Smart blinds](./../../blog/05-ikea-fyrtur-repair/index.md), where I've covered more in general know how to diagnose and get working again those blinds.
|
||||||
|
|
||||||
|

|
||||||
12
hugo.toml
12
hugo.toml
@@ -52,8 +52,8 @@ theme = "minimal-black"
|
|||||||
showNowSection = true
|
showNowSection = true
|
||||||
showFeaturedProjects = true
|
showFeaturedProjects = true
|
||||||
showLatestPosts = true
|
showLatestPosts = true
|
||||||
featuredProjectsLimit = 3
|
featuredProjectsLimit = 4
|
||||||
latestPostsLimit = 3
|
latestPostsLimit = 4
|
||||||
projectsTitle = "Latest projects"
|
projectsTitle = "Latest projects"
|
||||||
projectsSubtitle = ""
|
projectsSubtitle = ""
|
||||||
blogTitle = "Latest articles"
|
blogTitle = "Latest articles"
|
||||||
@@ -86,10 +86,10 @@ theme = "minimal-black"
|
|||||||
useDevicon = true
|
useDevicon = true
|
||||||
|
|
||||||
# Social Links
|
# Social Links
|
||||||
# [[params.social]] # TODO
|
[[params.social]]
|
||||||
# label = "Gitea"
|
label = "Gitea"
|
||||||
# url = "https://git.jirkabuilds.dev/jirka"
|
url = "https://git.jirkabuilds.dev/jirka"
|
||||||
# icon = "fa-solid fa-code-branch"
|
icon = "fa-solid fa-code-branch"
|
||||||
|
|
||||||
# Navigation Menu
|
# Navigation Menu
|
||||||
[menu]
|
[menu]
|
||||||
|
|||||||
37
layouts/_default/list.html
Normal file
37
layouts/_default/list.html
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
{{ define "main" }}
|
||||||
|
<section class="layout-page">
|
||||||
|
<div class="page-int section-stack">
|
||||||
|
<header class="space-y-2">
|
||||||
|
<h1 class="heading-page text-2xl sm:text-3xl">{{ .Title }}</h1>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
{{ $paginator := .Paginate .Pages }}
|
||||||
|
|
||||||
|
<div class="grid gap-4 md:grid-cols-2">
|
||||||
|
{{ range $paginator.Pages.ByDate.Reverse }}
|
||||||
|
{{ partial "components/post-card.html" (dict "Page" . "Root" $) }}
|
||||||
|
{{ end }}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{{ if gt $paginator.TotalPages 1 }}
|
||||||
|
<nav class="mt-6 flex items-center justify-between text-xs text-muted">
|
||||||
|
{{ if $paginator.HasPrev }}
|
||||||
|
<a href="{{ $paginator.Prev.URL }}" class="link-underline">
|
||||||
|
← Novější
|
||||||
|
</a>
|
||||||
|
{{ else }}
|
||||||
|
<span></span>
|
||||||
|
{{ end }}
|
||||||
|
|
||||||
|
{{ if $paginator.HasNext }}
|
||||||
|
<a href="{{ $paginator.Next.URL }}" class="link-underline">
|
||||||
|
Starší →
|
||||||
|
</a>
|
||||||
|
{{ else }}
|
||||||
|
<span></span>
|
||||||
|
{{ end }}
|
||||||
|
</nav>
|
||||||
|
{{ end }}
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
{{ end }}
|
||||||
19
layouts/_default/terms.html
Normal file
19
layouts/_default/terms.html
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
{{ define "main" }}
|
||||||
|
<section class="layout-page">
|
||||||
|
<div class="page-int section-stack">
|
||||||
|
<header class="space-y-2">
|
||||||
|
<h1 class="heading-page text-2xl sm:text-3xl">{{ .Title }}</h1>
|
||||||
|
</header>
|
||||||
|
|
||||||
|
<div class="flex flex-wrap gap-2">
|
||||||
|
{{ range .Data.Terms }}
|
||||||
|
<a href="{{ .Page.Permalink }}" class="flex items-baseline gap-1.5 px-3 py-1 bg-white/5 border border-white/10 rounded-full hover:bg-white/10 hover:border-white/20 transition-all text-sm">
|
||||||
|
{{/* Název tagu */}}
|
||||||
|
<span class="font-medium text-white/90">{{ .Page.Title }}</span>
|
||||||
|
<span class="text-xs text-muted">({{ .Count }})</span>
|
||||||
|
</a>
|
||||||
|
{{ end }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
{{ end }}
|
||||||
@@ -25,7 +25,7 @@ html[data-theme="dark"] {
|
|||||||
--color-text: #f9fafb;
|
--color-text: #f9fafb;
|
||||||
--color-text-muted: #9ca3af;
|
--color-text-muted: #9ca3af;
|
||||||
--color-border: #27272a;
|
--color-border: #27272a;
|
||||||
--color-accent: #555555;
|
--color-accent: #707070;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Base Styles */
|
/* Base Styles */
|
||||||
|
|||||||
@@ -1245,7 +1245,7 @@ html[data-theme="dark"] {
|
|||||||
--color-text: #f9fafb;
|
--color-text: #f9fafb;
|
||||||
--color-text-muted: #9ca3af;
|
--color-text-muted: #9ca3af;
|
||||||
--color-border: #27272a;
|
--color-border: #27272a;
|
||||||
--color-accent: #555555;
|
--color-accent: #707070;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Base Styles */
|
/* Base Styles */
|
||||||
|
|||||||
Reference in New Issue
Block a user