[{"content":"","date":"16 May 2026","externalUrl":null,"permalink":"/tags/automation/","section":"Tags","summary":"","title":"Automation","type":"tags"},{"content":"","date":"16 May 2026","externalUrl":null,"permalink":"/tags/beginning/","section":"Tags","summary":"","title":"Beginning","type":"tags"},{"content":"","date":"16 May 2026","externalUrl":null,"permalink":"/tags/ci/cd/","section":"Tags","summary":"","title":"Ci/Cd","type":"tags"},{"content":"","date":"16 May 2026","externalUrl":null,"permalink":"/tags/github-actions/","section":"Tags","summary":"","title":"Github-Actions","type":"tags"},{"content":"","date":"16 May 2026","externalUrl":null,"permalink":"/tags/gitops/","section":"Tags","summary":"","title":"Gitops","type":"tags"},{"content":"","date":"16 May 2026","externalUrl":null,"permalink":"/tags/hugo/","section":"Tags","summary":"","title":"Hugo","type":"tags"},{"content":" Why? # Easy answer - to make my life easier :) My current workflow is that I would\nmake changes on my webside run hugo build locally to generate the static files commit and push the changes to github github workflow would then run and deploy the changes to AWS S3 I would check if the changes are live on the website And what keeps happening is that I forget to run hugo build before pushing the changes, which results in the website not being updated until I realize the mistake and push again after running hugo build. I am no content creator and this is a very manual process, so I want to automate it as much as possible and make it easier for myself.\nHow? # I just need to update the github workflow to run hugo build as part of the workflow before deploying the changes to AWS S3.\nThis is the current workflow file:\nname: Deploy to S3 on: push: branches: [ main ] workflow_dispatch: jobs: deploy: runs-on: ubuntu-latest environment: production steps: - uses: actions/checkout@v4 with: fetch-depth: 0 - name: Configure AWS Credentials uses: aws-actions/configure-aws-credentials@v4 with: aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} aws-region: eu-west-1 - name: Deploy to S3 run: | aws s3 sync ./public s3://mplexia.com --delete and I just need to add the hugo build command before the aws s3 sync command:\nname: Deploy to S3 on: push: branches: [ main ] workflow_dispatch: jobs: deploy: runs-on: ubuntu-latest environment: production steps: - uses: actions/checkout@v4 with: fetch-depth: 0 submodules: true - name: Setup Hugo uses: peaceiris/actions-hugo@v2 with: hugo-version: \u0026#39;0.161.1\u0026#39; extended: true - name: Build with Hugo run: hugo --minify - name: Configure AWS Credentials uses: aws-actions/configure-aws-credentials@v4 with: aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} aws-region: eu-west-1 - name: Deploy to S3 run: | aws s3 sync ./public s3://mplexia.com --delete and after that I just need to commit and push the changes to github and the workflow will run and deploy the changes to AWS S3, and I can check if the changes are live on the website.\nIsn\u0026rsquo;t that much easier? Automation is great, it saves time and reduces the chances of human error. Now I can focus on creating content and let the workflow take care of the rest.\n","date":"16 May 2026","externalUrl":null,"permalink":"/posts/updating-github-workflow/","section":"Posts","summary":"","title":"Making my life easier - updating github workflow","type":"posts"},{"content":"","date":"16 May 2026","externalUrl":null,"permalink":"/tags/markup/","section":"Tags","summary":"","title":"Markup","type":"tags"},{"content":"","date":"16 May 2026","externalUrl":null,"permalink":"/","section":"Mplexia","summary":"","title":"Mplexia","type":"page"},{"content":"","date":"16 May 2026","externalUrl":null,"permalink":"/tags/","section":"Tags","summary":"","title":"Tags","type":"tags"},{"content":"","date":"7 May 2026","externalUrl":null,"permalink":"/tags/linux/","section":"Tags","summary":"","title":"Linux","type":"tags"},{"content":"","date":"7 May 2026","externalUrl":null,"permalink":"/tags/multicast/","section":"Tags","summary":"","title":"Multicast","type":"tags"},{"content":"","date":"7 May 2026","externalUrl":null,"permalink":"/tags/networking/","section":"Tags","summary":"","title":"Networking","type":"tags"},{"content":"","date":"7 May 2026","externalUrl":null,"permalink":"/tags/socat/","section":"Tags","summary":"","title":"Socat","type":"tags"},{"content":" Introduction # Yesterday, I referenced http://www.dest-unreach.org/socat/doc/socat.html#EXAMPLES\nwith examples and one of those is actually a multicast! If you remember, a network connection (TCP or UDP) is like a phone call, well, IP multicast is like TV Broadcast - a single source sent the data (stream of bytes) and others consume it (or not if not interested). IP multicast is well known for being fairly difficult to set up (and troubleshoot) but with socat, it is actually quite easy to do. Do you remember that almost-no-sense example with ssh over UDP? Here we go again!\nScenario # Imagine following scenario - the box s1 on the left hand side is the source of the multicast (multicast is technically an unidirectional stream of UDP packets to \u0026lsquo;whoever is interested\u0026rsquo;) and the box s2 is the consumer of the multicast. The source s1 sends the stream of bytes to the multicast group and s2 \u0026lsquo;somewhat announced\u0026rsquo; to the network that it\u0026rsquo;s interested in the multicast group and then consumes the stream of bytes. Boxes s3 and s4 are also interested but the \u0026lsquo;I want to listen too\u0026rsquo; announcement doesn\u0026rsquo;t work due to lack of multicast support between s1, and s3 and s4.\nLet\u0026rsquo;s demonstrate:\non s1\nsocat -u - UDP4-DATAGRAM:224.1.2.3:12345,range=10.0.0.0/8 on s2\nsocat -u UDP4-RECVFROM:12345,ip-add-membership=224.1.2.3:10.0.1.12,fork - on s3\nsocat -u UDP4-RECVFROM:12345,ip-add-membership=224.1.2.3:10.0.2.13,fork - on s4\nsocat -u UDP4-RECVFROM:12345,ip-add-membership=224.1.2.3:10.0.2.14,fork - And sent a message from s1:\n[lab@s1 ~]$ socat -u - UDP4-DATAGRAM:224.1.2.3:12345,range=10.0.0.0/8 Good evening! the message is received on s2:\n[lab@s2 ~]$ socat UDP4-RECVFROM:12345,ip-add-membership=224.1.2.3:10.0.1.12,fork - Good evening! but not on s3 nor s4\n[lab@s3 ~]$ socat UDP4-RECVFROM:12345,ip-add-membership=224.1.2.3:10.0.2.13,fork - [lab@s4 ~]$ socat UDP4-RECVFROM:12345,ip-add-membership=224.1.2.3:10.0.2.14,fork - So what now? do we need to implement underlay/overlay network? Setup some GRE somewhat somewhere and route it through it? Or do we need to buy an expensive appliance? Do we need to bypass all firewalls? Well\u0026hellip; let me repurpose some of our servers in the scenario - I want server s2 to work like a proxy - on one side, it will listen for the incoming multicast and on the other it will sent the exact byte stream into direct UDP connection over the part of network which doesn\u0026rsquo;t support multicast. On the other side, s3 will listen for inbound UDP traffic from s2, and all byte stream will be broadcasted sent as multicast so server s4 can consume it (as multicast). (I am going to change the used addresses and ports to make everything working as intended)\nand let\u0026rsquo;s demonstrate it again: on s1\nsocat -u - UDP4-DATAGRAM:224.1.2.3:12345,range=10.0.0.0/8 on s2\nsocat UDP4-RECVFROM:12345,ip-add-membership=224.1.2.3:10.0.1.12,fork UDP:10.0.2.13:23456 on s3\nsocat UDP-L:23456,fork UDP4-DATAGRAM:224.1.2.4:34567,range=10.0.0.0/8 on s4\nsocat UDP4-RECVFROM:34567,ip-add-membership=224.1.2.4:10.0.2.14,fork - Quick test: on s1\n[lab@s1 ~]$ socat -u - UDP4-DATAGRAM:224.1.2.3:12345,range=10.0.0.0/8 Good morning!! and received on s4\n[lab@s4 ~]$ socat UDP4-RECVFROM:34567,ip-add-membership=224.1.2.4:10.0.2.14,fork - Good morning!! Technically, s1 act as the \u0026lsquo;broadcaster which is usually out of our control\u0026rsquo;, and s4 on the other side is just a \u0026lsquo;dummy\u0026rsquo; application which is out of our control as well, but s2 and s3 are \u0026lsquo;under our control\u0026rsquo; and we can use them to \u0026lsquo;bridge\u0026rsquo; the multicast stream between s1 and s4. Isn\u0026rsquo;t it cool?\n","date":"7 May 2026","externalUrl":null,"permalink":"/posts/003-socat-and-multicast/","section":"Posts","summary":"","title":"Socat and Multicast","type":"posts"},{"content":"","date":"7 May 2026","externalUrl":null,"permalink":"/tags/tcp/","section":"Tags","summary":"","title":"Tcp","type":"tags"},{"content":"","date":"7 May 2026","externalUrl":null,"permalink":"/tags/udp/","section":"Tags","summary":"","title":"Udp","type":"tags"},{"content":" I Wanted to Talk About Cool Stuff… But First, socat # Today I really wanted to jump into more advanced topics, but I realised I first need to address something fundamental.\nTCP connections are actually very simple.\nThink of them like a phone call:\nYou dial → connect You talk and listen You hang up Applications basically do the same thing: they open a socket and just read/write data. Everything else (handshakes, retransmissions, congestion control) is handled by the kernel.\nBut what if we could treat a network connection exactly like a Unix pipe?\nThat’s where socat comes in.\nsocat = cat Over the Network # socat (short for SOcket CAT) lets you create bidirectional byte streams between almost anything: TCP, UDP, files, serial ports, etc.\nSimple File Copy Over TCP # On the receiving side (remotehost):\nsocat TCP-LISTEN:12345,fork,reuseaddr - \u0026gt; file2 On the sending side (localhost):\ncat file1 | socat - TCP:remotehost:12345 That’s it. You just copied a file over the network as easily as cat file1 \u0026gt; file2. More Advanced: UDP → TCP Proxy # On the receiving side (remotehost) - that\u0026rsquo;s the same as previous:\nsocat TCP-LISTEN:12345,fork,reuseaddr - \u0026gt; file2 On the proxy (middleman):\nsocat -u UDP-LISTEN:54321,fork TCP:remotehost:12345 And finally on the sending side (localhost):\ncat file1 | socat -u - UDP:proxy:54321 That\u0026rsquo;s it - we just sent the file over UDP and TCP glued together by the TCP-to-UDP proxy. Real-World Example: SSH Over UDP # # On remotehost (forward UDP 2222 → local SSH) socat UDP-LISTEN:2222,reuseaddr,fork TCP:localhost:22 # On localhost (forward local TCP 2222 → remote UDP) socat TCP-LISTEN:2222,reuseaddr,fork UDP:remotehost:2222 and then just:\nssh -p2222 localhost !SSH OVER UDP! 🎉 # Why This Matters # socat proves that at the end of the day, most network communication is just streams of bytes. Once you understand that, you can:\nForward ports creatively Build quick proxies and tunnels Debug tricky connectivity issues Create powerful one-liners It really is the Swiss Army knife of networking.\nMany other official examples: http://www.dest-unreach.org/socat/doc/socat.html#EXAMPLES\nI’ll be showing more advanced socat use cases in future posts (port forwarding, TLS tunnels, relay chains, etc.).\n","date":"6 May 2026","externalUrl":null,"permalink":"/posts/002-i-wanted-but-socat/","section":"Posts","summary":"","title":"socat: The Swiss Army Knife of Networking","type":"posts"},{"content":"","date":"5 May 2026","externalUrl":null,"permalink":"/tags/aws/","section":"Tags","summary":"","title":"Aws","type":"tags"},{"content":"","date":"5 May 2026","externalUrl":null,"permalink":"/tags/aws-cli/","section":"Tags","summary":"","title":"Aws Cli","type":"tags"},{"content":"… and just like that, here we are.\nWhy This Website? # A few months ago I decided to leave my corporate job and go fully independent as a contractor, specialising in AWS Cloud Networking, Terraform, and GitOps.\nMy plan was simple: there must be plenty of companies struggling with hybrid cloud connectivity — surely they need help, right?\nReality check: nothing happened.\nI updated my LinkedIn, reached out to recruiters, refreshed my CV, created profiles on specialist platforms… and got almost zero traction. After talking to AI and a few friends, the message was crystal clear:\n“Nobody cares about the cool stuff you did behind corporate walls. You need a portfolio.” This would basically mean to re-built and re-document everything I did in the last 10 years, which is a bit of a nightmare, but at least I can start with something simple: this website.\nSo I decided to build one — publicly.\nPhase 1: The Quick \u0026amp; Dirty Static Site # I already had a personal AWS account, so:\nRegistered mplexia.com Created an S3 bucket Uploaded a simple index.html (manual clicks, ugh) and pointed the DNS to the bucket.\nA quick chat with Grok gave me a decent-looking single-page site + Calendly integration. A few more clicks and the site was live. (single index.html, but hey, it’s a start!)\nBut manually uploading files via the AWS Console felt painful.\nEnter AWS CLI # Instead of click-ops, I started using the command line:\naws s3 cp index.html s3://mplexia.com/ This was a game-changer. I could update the site with a simple command, no more manual uploads.\nPhase 2: Adding Automation (GitOps Style) # I wanted several things:\nA proper way to manage content An option to see previous version of the site (version control) Ability to work from any computer Full automation (no more manual uploads) So I added:\nGitHub as the source of truth GitHub Actions to automatically deploy to S3 on every git push Here\u0026rsquo;s the workflow:\nname: Deploy to S3 on: push: branches: [ main ] workflow_dispatch: jobs: deploy: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Configure AWS Credentials uses: aws-actions/configure-aws-credentials@v4 with: aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} aws-region: eu-west-1 - name: Deploy to S3 run: aws s3 sync ./public s3://mplexia.com --delete just to be added into .github/workflows/some.yaml and we are good to go.\nI must admit, the idea of uploading \u0026lsquo;some code\u0026rsquo; and my private AWS keys somewhere on the internet made me a bit nervous at first, but after reading GitHub’s documentation and testing it out, I felt comfortable enough to proceed. ( I doublechecked the github action logs, when the keys are not leaked if handled properly as environmental variables )\nBut OIDC is definitely on the menu for future improvements to avoid any potential risks with static keys.\nPhase 3: Moving to Hugo + Blowfish # Manually editing index.html is not sustainable if I want to write articles. After some research (hey grok) I chose:\nHugo — extremely fast static site generator Blowfish — modern, clean, and highly customizable theme Installation was straightforward (sudo port install hugo on macOS), and after a short learning curve I migrated the whole site to Markdown. (ugh it looks so ugly at first, but it’s just a matter of getting used to it)\nNow publishing a new article is as simple as:\nWrite in Markdown git add . git commit -m \u0026ldquo;Add new article\u0026rdquo; git push\n…and GitHub Actions does the rest \u0026hellip; well it worked with single file, why it shouldn\u0026rsquo;t work with multiple files, right?\nTo be done later # Well, I really hate there\u0026rsquo;s no TLS/SSL - I guess I can add CloudFront in front of S3 (static website using S3 can\u0026rsquo;t do SSL natively) and get free TLS certs from AWS Certificate Manager, right? I created many things manually, this needs to be terraformed all the way around - at least the S3 bucket and the DNS record, right? (what about git repository, the IAM role , the github action \u0026hellip; ) The built of the website ( hugo build ) should be part of the github action, not something I do locally and then push the generated files to git - that\u0026rsquo;s just wrong, right? Can Github Actions do OIDC to get temporary AWS credentials instead of using static keys? I guess it can, but I need to learn how to do it - that\u0026rsquo;s definitely on the menu for future improvements. Conclusion # This was a fun and educational project to get my website up and running. It’s not perfect, but it’s a start — and it’s fully automated with GitOps principles. And most importantly, it’s a platform to share my knowledge and experience with the world, and hopefully attract some interesting projects along the way. So stay tuned for more articles about AWS, Terraform, GitOps, and all things cloud networking!\nGit repo # and as some people would say - show me your code - here you are: https://github.com/lrozehnal/mplexia.com\nLessons Learned # Going independent is harder than I expected. A strong public portfolio really matters. Once you taste proper GitOps automation, you never want to go back to manual work. Hugo + Blowfish seems like an excellent combo for technical blogs. ","date":"5 May 2026","externalUrl":null,"permalink":"/posts/001-how-i-built-this-website/","section":"Posts","summary":"","title":"How I Built This Website","type":"posts"},{"content":"","date":"5 May 2026","externalUrl":null,"permalink":"/tags/s3/","section":"Tags","summary":"","title":"S3","type":"tags"},{"content":"","date":"1 January 2026","externalUrl":null,"permalink":"/posts/","section":"Posts","summary":"","title":"Posts","type":"posts"},{"content":"","externalUrl":null,"permalink":"/about/","section":"Mplexia","summary":"","title":"","type":"page"},{"content":"","externalUrl":null,"permalink":"/authors/","section":"Authors","summary":"","title":"Authors","type":"authors"},{"content":"","externalUrl":null,"permalink":"/categories/","section":"Categories","summary":"","title":"Categories","type":"categories"},{"content":"","externalUrl":null,"permalink":"/series/","section":"Series","summary":"","title":"Series","type":"series"}]