


[{"content":"","date":"28 March 2025","externalUrl":null,"permalink":"/tags/","section":"","summary":"","title":"","type":"tags"},{"content":"","date":"28 March 2025","externalUrl":null,"permalink":"/tags/deployment/","section":"","summary":"","title":"Deployment","type":"tags"},{"content":"","date":"28 March 2025","externalUrl":null,"permalink":"/tags/devops/","section":"","summary":"","title":"Devops","type":"tags"},{"content":"","date":"28 March 2025","externalUrl":null,"permalink":"/","section":"Felipe's website","summary":"","title":"Felipe's website","type":"page"},{"content":" Introduction # Let\u0026rsquo;s continue with the series of blog posts about moving from Docker to Podman.\nToday I\u0026rsquo;ll cover a short issue which might help you with your transition:\nWhy --restart unless-stopped doesn\u0026rsquo;t work??\nLet\u0026rsquo;s say you read that Podman\u0026rsquo;s command line API is 1:1 compatible with Docker\u0026rsquo;s and you ran your container as always, but you realised that it didn\u0026rsquo;t boot up automatically after a reboot of the system as it was happening when using Docker. Well, this was something to be expected as we moved from a container manager that runs as a daemon to another that runs as a regular process.\nDocker vs Podman at System\u0026rsquo;s Boot # When our system boots up, we have a systemd service that handles starting Docker. Then, Docker itself is in charge of starting all those containers marked to be started automatically. Kind of magic to us, as we only need to specify the argument --restart unless-stopped when running a container.\nBut Podman doesn\u0026rsquo;t work that way. There\u0026rsquo;s no service running Podman in background. A disadvantage? I don\u0026rsquo;t think so. Why to place Docker\u0026rsquo;s service in the middle if we can write our own systemd service to trigger our target container. That would be cleaner, wouldn\u0026rsquo;t it?\nOur New Best Friend: systemd # Podman doesn\u0026rsquo;t reinvent the wheel, there\u0026rsquo;s an excellent piece of SW that already handles services in our OS: systemd. So instead of duplicating features, it relies on systemd to handle the life-cycle of our containers.\nIf you\u0026rsquo;re not very familiar with systemd, I\u0026rsquo;d suggest you to have a look at this great book: Linux Service Management Made Easy with systemd by Donald Al Tevault.\nThis section covers how to achieve the same feature we had when using --restart unless-stopped while running our containers.\nUnderstanding The New Deployment Schema # This diagram from the book Podman in Action by Daniel J. Walsh depicts how all the pieces will be put together:\nWe\u0026rsquo;ll need to define a systemd unit file that describes how do we expect to run our container. Then systemd will use it to trigger our container when required. What if you don\u0026rsquo;t know how to write a unit file? No worries, as Podman devs have been really kind providing a tool that generates such file on behalf of us. But a brief understanding of unit files would be good anyway. Remember that you have man systemd.unit at hand if you need to clarify any option from the future unit file.\nLet\u0026rsquo;s get our hands dirty and make an example of it.\nBooting a Container at Boot # For the sake of the tutorial, I\u0026rsquo;ll use one image of my own: La Coctelera Backend, this image is the one that I use to deploy the backend service of La Coctelera.\nFirst, we need either to create a container or use a running one. This will be used by Podman to detect what settings are needed when the unit file gets made.\n$ podman create \\ --restart unless-stopped \\ --network host \\ --env-file /home/user/.local/share/coctelera/coctelera.env \\ -v coctelera:/app/config \\ ghcr.io/felipet/lacoctelera_backend:main Remember to include the restart policy!\nNow, we can use podman generate systemd to generate a systemd unit file. I usually don\u0026rsquo;t provide names to the containers as I enjoy using the automatic funny names that are generated. If you are like me, you\u0026rsquo;ll need to get the name that was assigned to your container (podman ps -a).\npodman generate systemd --new amazing_feistel \u0026gt; ~/.config/systemd/user/lacoctelera_backend.service I intend to run my service as a regular user, that\u0026rsquo;s why I place the unit file in the user\u0026rsquo;s local storage. Let\u0026rsquo;s take a look at the file that was generated:\n[Unit] Description=La Coctelera backend service Wants=network-online.target After=network-online.target RequiresMountsFor=%t/containers [Service] Environment=PODMAN_SYSTEMD_UNIT=%n Restart=always TimeoutStopSec=70 ExecStart=/usr/bin/podman run \\ --cidfile=%t/%n.ctr-id \\ --cgroups=no-conmon \\ --rm \\ --sdnotify=conmon \\ -d \\ --network host \\ --env-file /home/user/.local/share/coctelera/coctelera.env \\ -v coctelera:/app/config ghcr.io/felipet/lacoctelera_backend:main ExecStop=/usr/bin/podman stop \\ --ignore -t 10 \\ --cidfile=%t/%n.ctr-id ExecStopPost=/usr/bin/podman rm \\ -f \\ --ignore -t 10 \\ --cidfile=%t/%n.ctr-id KillSignal=SIGINT Type=notify NotifyAccess=all [Install] WantedBy=default.target I only made a few minor changes to it: I modified the description, and added KillSignal as my application expects Ctrl + c as the signal to stop the service gracefully. Pretty painless, wasn\u0026rsquo;t it?\nWe only need a few more shell commands before we call it a day. We can test running our container using systemctl:\n$ systemctl --user start lacoctelera_backend.service $ systemctl --user status lacoctelera_backend.service If everything went fine, we shall see that our service is active (running). Now, it\u0026rsquo;s time to enable our service at boot using this command:\n$ systemctl --user enable lacoctelera_backend.service And that\u0026rsquo;s it! Our service will be trigger at boot the next time.\nFinal Thoughts # At this point you might think: such a hassle, I have to write a unit file and learn about how to use systemd while I only needed a simple option when I was using Docker. And this is sort of true. But the bottom line is that we can benefit from the other interesting features that are provided by systemd.\nThe combination of systemd + Podman leads to a more secure and reliable deployment. We\u0026rsquo;ll delve deeper into the security options that we can use from now in future posts.\nAlso, learning how to use systemd is never a waste of time. We can use this knowledge for many other things, as systemd is a core component of our OS.\nAnd a final remark, did you like how Docker handled logs? I personally don\u0026rsquo;t. The command docker logs \u0026lt;container\u0026gt; simply sucks. Then you have to write your logs to a file, and place it in a volume for example, if you aim to access them easily from the host. OK, but what happens when that log grows? And it will, believe me.\nBy using systemd we can make use of journald to handle our log messages. One of the greatest advantages is that journald makes an automatic log rotation of our logs, and it also keeps logs in binary which saves space. And stores our logs independently of our container, so even if our container is down, we can check the logs. That\u0026rsquo;s a nice feature.\nThat\u0026rsquo;s all for today, stay tuned for more posts of the series!\n","date":"28 March 2025","externalUrl":null,"permalink":"/posts/podman-containers-at-sysboot/","section":"Posts","summary":"Introduction # Let’s continue with the series of blog posts about moving from Docker to Podman.\nToday I’ll cover a short issue which might help you with your transition:\nWhy --restart unless-stopped doesn’t work??\nLet’s say you read that Podman’s command line API is 1:1 compatible with Docker’s and you ran your container as always, but you realised that it didn’t boot up automatically after a reboot of the system as it was happening when using Docker. Well, this was something to be expected as we moved from a container manager that runs as a daemon to another that runs as a regular process.\n","title":"How To Start Containers with Podman At System's Boot","type":"posts"},{"content":"","date":"28 March 2025","externalUrl":null,"permalink":"/tags/hugo/","section":"","summary":"","title":"Hugo","type":"tags"},{"content":"","date":"28 March 2025","externalUrl":null,"permalink":"/tags/podman/","section":"","summary":"","title":"Podman","type":"tags"},{"content":"","date":"28 March 2025","externalUrl":null,"permalink":"/posts/","section":"Posts","summary":"","title":"Posts","type":"posts"},{"content":" Introduction # In this blog post, I\u0026rsquo;ll explain the steps that I followed to migrate from Docker to Podman. Whether you are a sysadmin or a regular developer, I\u0026rsquo;m quite sure that you\u0026rsquo;ve heard of Docker before. It\u0026rsquo;s a great piece of software, and it really helped to improve and simplify software delivering. Believe me, I was there before Docker exists, and it was quite chaotic.\nThen, why to move away from Docker? Well, if you\u0026rsquo;re after better integration with the system, like using systemd, or if you\u0026rsquo;re after more security options, or if you prefer software that doesn\u0026rsquo;t use daemons, then Podman is definitely worth a try!\nPodman is an alternative container management tool developed as open source by Red Hat. It was developed after Docker and that meant Podman\u0026rsquo;s developers could learn a lot of lessons from it. Moreover, they dared to improve it, specially targeting the weakest point of Docker: security. They were very clever: they realised it would be hard to take market share of a well established software, so they made Podman fully compatible with Docker\u0026rsquo;s API. To me, this is a key to success because regardless on whether they offer a better piece of software or not, there\u0026rsquo;s a lot of inertia towards Docker and reverting it would be almost impossible, unless you make an offer that you can\u0026rsquo;t refuse: use Podman as you were using Docker. So simple, so brilliant.\nI\u0026rsquo;m not going to get into the nitty-gritty or compare them side-by-side, as there are already some articles out there doing that. I\u0026rsquo;ll just point you to the e-book Podman in Action by Daniel J. Walsh. As of today, it is free to download, and it is really well written. If you\u0026rsquo;re interested in Podman, you should definitely check it out.\nToday\u0026rsquo;s blog post focuses on the migration from Docker to Podman. We\u0026rsquo;ll take advantage of the compatible API, and we\u0026rsquo;ll dare to seamless restart our containers using the same command that we were using with Docker with an single change: replace docker by podman.\nHence, no fancy stuff today, just a straightforward migration. I think it\u0026rsquo;s best to keep it simple, as we\u0026rsquo;re about to touch an important part of your system, and we need to feel confident enough before moving forward. What would be better than proving that we can run Podman as we were doing with Docker, let\u0026rsquo;s get started!\nSave Your Containers # You might be reluctant to move because you have several containers running, and you can\u0026rsquo;t afford losing the content of those. Many images are prepared to place modifiable content in a particular path, this way you could use the option --volume to specify a host folder in which data can outlive the container.\nBut, what if you forgot to use an external volume? Or, what if your particular image keeps many modifications within the running container? If you\u0026rsquo;re in this situation, don\u0026rsquo;t panic! There\u0026rsquo;s a simple procedure to save all the content, and prepare the containers to be loaded into Podman.\nHow To Save a Running Container # First, we\u0026rsquo;ll get the hash identifier or the name of the containers that we aim to migrate. If there are stopped containers, we\u0026rsquo;ll need docker ps --all.\nWe\u0026rsquo;ll use docker commit for the purpose of saving a running container into an image that we can later import into Podman. The process is simple, just use:\n$ docker commit \u0026lt;container id or name\u0026gt; \u0026lt;image name\u0026gt; If the container is running, that command will pause it for a while, so keep that in mind in case you can\u0026rsquo;t interrupt your underlying service.\nOnce we\u0026rsquo;ve made an image of a container, we need to export it this way:\n$ docker save \u0026lt;image name\u0026gt; | gzip \u0026gt; \u0026lt;image name\u0026gt;.tar.gz Repeat that process for each container that you need to migrate, and you\u0026rsquo;ll be ready to start using Podman.\nTip: If you were running docker as superuser, the images that you\u0026rsquo;ll export will be owned by root. As we\u0026rsquo;ll run Podman as a regular user, remember to change the permissions of those images before proceeding with the following steps.\nImport Your Saved Images Into Podman # At this stage, we\u0026rsquo;re ready to start running our containers using Podman instead of Docker. Just a heads-up: you might want to stop your running containers under Docker now, otherwise ports being used by your running containers in Docker would avoid running your containers with Podman using exactly the same configuration.\nFirst, we\u0026rsquo;ll import all the images that from the previous step using:\n$ podman load \u0026lt; \u0026lt;image name\u0026gt;.tar.gz When you are done, go and check everything went OK using podman image ls. You shall see your images listed. Now, it\u0026rsquo;s time to fire up a few containers using those images. One of the greatest things of Podman is that its command line API is 100% compatible with Docker\u0026rsquo;s. So take the command that you used before to run your containers with Docker: docker run [...], and replace docker by podman, that\u0026rsquo;s it!\nFinal Steps # There\u0026rsquo;s not much else to do. We saved all our beloved Docker containers and imported them into Podman. We made a big jump but we had a great safety net. Something didn\u0026rsquo;t go as expected? Just start your stopped container in Docker and you lost nothing but time. However, I hope everything ran smoothly and you faced no big issues during the process.\nKeeping Docker won\u0026rsquo;t harm you, so don\u0026rsquo;t be forced to clean it up before you feel comfortable using Podman. But if you reached this point, you are more than ready to free some space and remove Docker from your system.\nSo far, we made no use of any special feature, as we are using Podman as a 1:1 replacement for Docker. However, Podman offers many interesting features to improve security. I\u0026rsquo;ll cover some interesting features that Podman includes in following blog posts, so keep an eye on my blog!\n","date":"13 March 2025","externalUrl":null,"permalink":"/posts/migration-from-docker-to-podman/","section":"Posts","summary":"Introduction # In this blog post, I’ll explain the steps that I followed to migrate from Docker to Podman. Whether you are a sysadmin or a regular developer, I’m quite sure that you’ve heard of Docker before. It’s a great piece of software, and it really helped to improve and simplify software delivering. Believe me, I was there before Docker exists, and it was quite chaotic.\nThen, why to move away from Docker? Well, if you’re after better integration with the system, like using systemd, or if you’re after more security options, or if you prefer software that doesn’t use daemons, then Podman is definitely worth a try!\n","title":"How To Migrate From Docker To Podman","type":"posts"},{"content":"","date":"19 February 2025","externalUrl":null,"permalink":"/categories/","section":"Categories","summary":"","title":"Categories","type":"categories"},{"content":"","date":"19 February 2025","externalUrl":null,"permalink":"/tags/finance/","section":"","summary":"","title":"Finance","type":"tags"},{"content":"","date":"19 February 2025","externalUrl":null,"permalink":"/tags/ibex35/","section":"","summary":"","title":"Ibex35","type":"tags"},{"content":"","date":"19 February 2025","externalUrl":null,"permalink":"/tags/programming/","section":"","summary":"","title":"Programming","type":"tags"},{"content":"","date":"19 February 2025","externalUrl":null,"permalink":"/categories/shortbot/","section":"Categories","summary":"","title":"Shortbot","type":"categories"},{"content":"","date":"19 February 2025","externalUrl":null,"permalink":"/tags/shortbot/","section":"","summary":"","title":"Shortbot","type":"tags"},{"content":" Introduction # The IbexShortBot was a stateless bot. A stateless bot doesn\u0026rsquo;t keep any sort of information of the users. It just replies to the user\u0026rsquo;s requests, one at a time. Despite that design decision made the bot very restricted on its features, it helped me to focus on delivering a solution as quickly as I could, to attract investor\u0026rsquo;s interest on using the bot.\nThe bot has been used for six months and the user\u0026rsquo;s feedback is positive. That\u0026rsquo;s enough for me to decide to take it a step further.\nIt\u0026rsquo;s time for the bot to meet databases.\nNew features # I ran a survey between the users of the bot, and by far, the most requested feature is related to following stocks and receiving updates when any short position changes.\nCompared to the current flow, in which an user has to select the stock every time she/he aims to check whether the position changed or not, the subscription-based flow would heavily simplify the user\u0026rsquo;s experience, and it would avoid missing any update in a position.\nIt seems a simple change: add an SQLite database, keep user\u0026rsquo;s subscriptions and run a timed-service to inform users when a change occurred.\nBut this time, I want to think big. That flow was in my mind since the beginning, but I considered that it was more interesting to deliver a simple solution quickly, than a full solution that would have required more development time.\nA Fully Integrated Stock Market Data Information System # One year ago, I started to work on the idea of having a Rust-based ecosystem for investment analysis and trading tools. The overall idea is having all the data centralised in a local database system that would feed my analysis tools.\nInformation about investment and trading is everywhere these days. One just needs to choose an investment strategy and follow it. However, what if I\u0026rsquo;d like to explore and implement my own financial models, or design custom trading oscillators? What if I rather make my own way than follow someone else\u0026rsquo;s? Most would say, that\u0026rsquo;s stupid, as only a few can beat the market. I\u0026rsquo;ll say that mostly true when you look where most of people do. But I\u0026rsquo;m convinced that it is possible to beat inefficient markets.\nI won\u0026rsquo;t enter in what is an efficient market, and what is not. It would be a pretty long explanation (it would well deserve it\u0026rsquo;s own blog entry). Let\u0026rsquo;s say, very very briefly, that an efficient market would find a fair price for a stock pretty quickly, whilst an inefficient market wouldn\u0026rsquo;t do it. It means that inefficient markets include both under valuated and over valuated stocks in higher proportions than efficient markets. Here\u0026rsquo;s where one can beat the market.\nMy market of choice is the IBEX35, and I do believe it is an inefficient market. Why do you tell me all this nonsense, you\u0026rsquo;d ask. The answer is related to what I said in the second paragraph of this section: inefficient markets don\u0026rsquo;t offer the market information as easily as efficient markets do, and that\u0026rsquo;s why it is so important for me to develop a fully integrated stock market data information system.\nAnd a (small) part of this information system is the IbexShortBot.\nIbexShortBot and The Finance Data Harvesting Library # A few days ago, I posted an entry in the blog talking about a new library that I wrote in Rust for collecting financial data from several sources and centralise it in a local database. You can read more about it in this entry: A Finance Data Harvesting Library.\nThe library along a CLI tool that makes use of it are in production now, and the bot simply needs to connect to the DB, and retrieve the active positions for the chosen ticker by the user. That meant I had to remove all the code related to collecting and processing data from the external source (CNMV\u0026rsquo;s page) and write a simple handler for the database. The changes are included in the PR-11 of the repository.\nImprovements Achieved # The most obvious improvement is the huge reduction in the latency of an user request: from tens of seconds to nearly zero! Short positions are cached now in my local database, so the bot just needs to issue a query rather than a complex procedure to collect and parse data from an external website (which is pretty slow, by the way).\nOnly that would have been worth the changes and the effort. It\u0026rsquo;s a change that heavily improves user\u0026rsquo;s experience.\nOther improvements are not so obvious to end users, but equally important as they leverage more important changes to come: positions are kept in a database, so the bot will not only access current short positions (as it happened before) but an entire registry with the evolution of the positions. Further analyses will be possible such as tendency of the overall short position against a company, track the activity of a particular hedge fund, or get notified when a company starts getting short positions. There are endless possibilities!\nAside from that, the project is better structured now because the logic related to the data harvesting is taken to a different library, which means the bot repository only tracks code related to the bot itself.\nFinally, the usage of the external website with the data (CNMV\u0026rsquo;s) is fairer now as the requests are centralised from a single place which scans the web a few times per day. Before, the website was requested every time an user of the bot asked for a list of positions. Also, if multiple users requested the same data, it meant that multiple requests were made rather than sharing the results as it happens now. I find it important as well, as I prefer not to abuse of external free services, specially when it is obvious that they suffer from performance issues.\nFuture Plans # The new feature means a considerable step forward for the bot. It is no longer a stateless bot: short positions are kept and an historical record is available. However, the only current benefit of having such record is the latency reduction for the access to the current positions. There is no logic that makes use of past positions.\nIncluding further features that make use of the historical record of short positions scores high in my todo list. Many possible analyses are available now. Also, it will be possible to detect changes: new positions, positions that got removed, \u0026hellip; And notify users, which means a huge change: from a request-based flow to a subscription-based flow.\nWhile including new features related to analysis is sort of easy, going from a request-based flow to a subscription-based flow is not. The architecture of Teloxide bots (the framework in which is based the IbexShortBot) makes it rather difficult if possible. Thus, it will require a lot of analysis and effort, anyway I am keen to see this feature working, so I will take the challenge!\n","date":"19 February 2025","externalUrl":null,"permalink":"/posts/shortbot-meets-db/","section":"Posts","summary":"Introduction # The IbexShortBot was a stateless bot. A stateless bot doesn’t keep any sort of information of the users. It just replies to the user’s requests, one at a time. Despite that design decision made the bot very restricted on its features, it helped me to focus on delivering a solution as quickly as I could, to attract investor’s interest on using the bot.\nThe bot has been used for six months and the user’s feedback is positive. That’s enough for me to decide to take it a step further.\n","title":"Shortbot Meets DBs","type":"posts"},{"content":"","date":"10 January 2025","externalUrl":null,"permalink":"/tags/apache/","section":"","summary":"","title":"Apache","type":"tags"},{"content":" Overview # In this entry, I\u0026rsquo;ll explain how to achieve an automated deployment after a change in a website built with Hugo, and deployed on Ubuntu Server with Apache thanks to Webhook.\nThere are many hosting services in which a page built with Hugo can be deployed for free. This is already covered by the official docs. Using an external hosting service is the way to go for most people, but what if you already have a server?\nMy plan was to host my new personal site on my server: Nubecita. It runs Ubuntu Server 24.04 and Apache as web server. One of the most common combinations for hosting stuff on the Internet. Aside from that, I push my website to a repository hosted in GitHub. My goal was to automate the process of deployment, so whenever I push a new change to the repository, it gets deployed into the production web server.\nThis guide is tailored for such a setup. I hope someone will find it useful.\nFirst Things First # Before we start configuring services and writing scripts, we\u0026rsquo;ll set up our system. We\u0026rsquo;ll need to install Webhook. I\u0026rsquo;ll opt for the packaged version from the repositories, rather than the one from the Snap Store:\nsudo apt install webhook Update: You\u0026rsquo;ll need Webhook \u0026gt;= 2.8.2, as that version includes all the changes to run under Systemd.\nAlso, I wouldn\u0026rsquo;t recommend using Hugo from the Snap Store, as it would restrict you to having your deployment scripts in a system directory rather than your home directory. But that\u0026rsquo;s up to you, so bear in mind that you can\u0026rsquo;t use Hugo from the Snap Store to follow this guide.\nWrite a Deployment Script # Once we\u0026rsquo;ve got our system ready, we can start with the interesting part. We\u0026rsquo;re going to need a deployment script, which is nothing more that a script that automates all the steps that you\u0026rsquo;d do if you were doing a manual deployment. For the sake of this guide, I\u0026rsquo;ll include the script that I use, but you\u0026rsquo;ll need to modify it to suit your needs.\n#!/bin/bash echo \u0026#34;Retrieve new content from the repo...\u0026#34; git clone https://github.com/felipet/personal-site.git --depth 1 cd personal-site echo \u0026#34;Build the static page\u0026#34; hugo cd public echo \u0026#34;Deploy the new content\u0026#34; rsync -r ./ /var/www/html/felipe-site chown -R www-data:www-data /var/www/html/felipe-site systemctl reload apache2 echo \u0026#34;Wiping temporal data...\u0026#34; cd ../../ rm -rf personal-site Remarkable items from the script:\nAdd --depth 1 to the clone command, this would save time in case your repository contains a significant amount of images, and other heavy items. After synchronising with rsync, I change the owner of the new data. The user www-data is often used in Apache deployments. Consider whether that user and group are the best option in your deployment. I reload the apache2 service after the deployment, thus this script needs to be run by a privileged user. Place that script wherever you\u0026rsquo;d like. I chose the path /var/scripts for which I assigned as owner of the directory the www-data user \u0026amp; group. Also, give it a try, and make sure it works as expected.\nSet Up Webhook # Our deployment script is ready now, but how do we bring it to life? Here it is where Webhook comes into scene. We\u0026rsquo;ll add a new Systemd service to manage Webhook, and we\u0026rsquo;ll write the configuration file that tells Webhook what hook shall be deployed for our purpose.\nRunning Webhook As a Systemd Service # We\u0026rsquo;ll configure Webhook to run as a Systemd service. This is well explained in the official documentation, so I\u0026rsquo;ll just mention the minor modifications that I made.\nIn brief, this is the socket descriptor:\n[Unit] Description=Webhook server socket [Socket] ## Listen on one specific interface only ListenStream=127.0.0.1:9191 [Install] WantedBy=multi-user.target As you can see, I wrote that the socket will only listen to requests coming from the local address. I\u0026rsquo;m planning to use a reverse proxy, which adds an extra layer of security because I don\u0026rsquo;t want to expose it to the public. If you\u0026rsquo;re planning to skip the reverse proxy, you\u0026rsquo;ll have to listen to 0.0.0.0:9191 but remember that you\u0026rsquo;ll need to set up some extra security layer.\nAnd the service descriptor:\n[Unit] Description=Webhook server [Service] Type=exec ExecStart=/usr/bin/webhook -nopanic -hooks /var/webhooks/hooks.json -verbose -port 9191 StandardOutput=append:/var/log/webhook StandardError=append:/var/log/webhook User=root Group=root Very important: the listening port and the port that is passed as an argument to Webhook are the same. It might seem like basic advice, but when you don\u0026rsquo;t use the standard ports, you might accidentally miss a port specification somewhere, which can waste time.\nAs I said, you need to run this service as root in order to have enough privileges to run systemctl reload apache2.\nSet Up a New Webhook # You might have noticed that we passed as argument to Webhook the file /var/webhooks/hooks.json. Now, we\u0026rsquo;ll pay some attention to such file.\nI chose the path /var/webhooks but you can put it anywhere you like. I also gave www-data permissions to read and write on that path, as I aim to deploy my repository right there every time the service is called.\nThis is the content of the file hooks.json:\n[ { \u0026#34;id\u0026#34;: \u0026#34;deploy_felipe_site\u0026#34;, \u0026#34;execute-command\u0026#34;: \u0026#34;/var/scripts/deploy_felipe-site.bash\u0026#34;, \u0026#34;command-working-directory\u0026#34;: \u0026#34;/var/webhooks\u0026#34;, \u0026#34;trigger-rule\u0026#34;: { \u0026#34;match\u0026#34;: { \u0026#34;type\u0026#34;: \u0026#34;payload-hmac-sha256\u0026#34;, \u0026#34;secret\u0026#34;: \u0026#34;SOME_SECRET_STRING!!!\u0026#34;, \u0026#34;parameter\u0026#34;: { \u0026#34;source\u0026#34;: \u0026#34;header\u0026#34;, \u0026#34;name\u0026#34;: \u0026#34;X-Hub-Signature-256\u0026#34; } } } } ] The value for execute-command shall be the path to your deployment script. The values for the match field are explained in the official GitHub\u0026rsquo;s documentation. Don\u0026rsquo;t forget to replace the value for secret. Generate some random strong string and put it there. Keep it for a while, as you\u0026rsquo;ll need to introduce the secret string while configuring our Webhook in GitHub.\nFinal Steps # Ready to go? Then run these commands:\nsudo systemctl enable webhook.socket sudo systemctl start webhook.socket And check that everything is working fine:\nsystemctl status webhook.socket You should get something alike to this output:\n● webhook.socket - Webhook server socket Loaded: loaded (/etc/systemd/system/webhook.socket; enabled; preset: enabled) Active: active (listening) since Tue 2025-01-14 10:39:37 UTC; 6s ago Triggers: ● webhook.service Listen: 127.0.0.1:9191 (Stream) Tasks: 0 (limit: 37781) Memory: 8.0K (peak: 256.0K) CPU: 820us CGroup: /system.slice/webhook.socket Jan 14 10:39:37 nubecita.eu systemd[1]: Listening on webhook.socket - Webhook server socket. Using Apache As Reverse Proxy # Here, you might diverge from the path I followed. If you are not fond of using a reverse proxy, go straight to open a port in your firewall and offer your service straight to the the public. In that case, I\u0026rsquo;d recommend you to follow Webhook\u0026rsquo;s docs to enable HTTPS.\nI use Apache to serve several websites, and as a reverse proxy for some web services that I offer. For me, it was an obvious choice. I avoid opening another port in my firewall, and the SSL stuff is managed by Apache, a win-win.\nTo forward requests to Webhook\u0026rsquo;s socket, add a new virtual host using the ProxyPass command:\nProxyPass /webhook http://127.0.0.1:9191/hooks ProxyPassReverse /webhook http://127.0.0.1:9191/hooks This will redirect a request to https://nubecita.eu/webhook/deploy_felipe_site to the local Webhook socket. If you made a new virtual host, enable it. In any case, reload the Apache service:\nsudo systemctl reload apache2 Our backend is ready at this point, let\u0026rsquo;s make a simple request to check that it responds, fingers crossed!\nWe can use Curl to send a POST request to the endpoint in which we installed our webhook:\ncurl -X \u0026#39;POST\u0026#39; \\ \u0026#39;https://nubecita.eu/webhook/deploy_felipe_site\u0026#39; Hook rules were not satisfied.% As we didn\u0026rsquo;t send our credentials nor any further information along the request, our service tells us that we didn\u0026rsquo;t satisfy the rules that we defined in hooks.json. That\u0026rsquo;s great, our backend responds, and blocks dummy requests. Let\u0026rsquo;s complete our deployment process with the last step.\nCreate a Webhook in GitHub # We reached the last needed step. We need to configure a webhook in our repository in GitHub.\nThe process is explained in this page. However, let\u0026rsquo;s summarise the steps:\nGo the settings section of the repository that keeps your web site content. Open Webhooks from the left panel, and click on Add webhook. Input the URL of your endpoint in the Payload URL, and choose application/json as Content type. Do you remember the secret string? Now it\u0026rsquo;s time to use it again. Add it in the Secret box. Of course, set Enable SSL verification. And finally, choose when do you aim to run the webhook. I selected Pushes and Releases. Save it and navigate to the Recent deliveries tab. You shall see that a ping job was launched. If that succeeded, congrats! Your deployment process is ready.\nMake any change to the content of the repository, and push the changes. You shall see that the changes get deployed in your production web site.\n","date":"10 January 2025","externalUrl":null,"permalink":"/posts/website-deployment/","section":"Posts","summary":"This blog post is a recap of all the steps needed to set up a deployment pipeline for a Hugo-based website hosted in GitHub.","title":"Automated Website Deployment","type":"posts"},{"content":"","date":"10 January 2025","externalUrl":null,"permalink":"/tags/github/","section":"","summary":"","title":"Github","type":"tags"},{"content":"","date":"10 January 2025","externalUrl":null,"permalink":"/categories/nubecita/","section":"Categories","summary":"","title":"Nubecita","type":"categories"},{"content":"","date":"10 January 2025","externalUrl":null,"permalink":"/tags/reverse-proxy/","section":"","summary":"","title":"Reverse-Proxy","type":"tags"},{"content":"","date":"10 January 2025","externalUrl":null,"permalink":"/tags/webhook/","section":"","summary":"","title":"Webhook","type":"tags"},{"content":"When I decided to start this blog, I considered two main options: Wordpress and Hugo. I have some experience with the former, as I already host some websites at Nubecita, and I had a personal page before using Wordpress (a simple profile page).\nHowever, I wanted something easy and simple. After all, my purpose for the site was to add some information about myself and a few blog posts. So why bother with all the overhead of Wordpress?\nLet\u0026rsquo;s walk through some of the tips I wish I\u0026rsquo;d known before.\nMake a List With Your Needs # It\u0026rsquo;s important to have a clear idea of what you want your website to do.\nDo you just need a simple profile page? Or do you want to become a blogger? Do you intend to write in more than one language? These are important questions because not all Hugo themes offer all the features you might need.\nSo, it\u0026rsquo;s important to have a quick list of your needs as a starting point, as this will affect your next decision, which is choosing a theme.\nSelect a Theme According To Your Needs # One of the first decisions you need to take when you aim to deploy a website using Hugo is choosing a theme.\nThere are some great themes out there, and you can find them on this page. But there\u0026rsquo;s no standard set of features that all themes should have. I really liked the look of one theme, but it didn\u0026rsquo;t have some features I needed.\nWhen you\u0026rsquo;re starting out, the last thing you\u0026rsquo;d want to do is modify a theme, or write one. So you need to find a theme that has as many of the features on your initial list as possible. Then you can start from there.\nI made the mistake of trying to configure the website with all the features I wanted right from the start. It\u0026rsquo;s unlikely you\u0026rsquo;ll find a theme that covers all your needs. So choose a theme, start from something, and build your page step by step.\nDeploy The Example Website # Sometimes, you don\u0026rsquo;t realise a theme doesn\u0026rsquo;t work as expected or meet your needs until you actually deploy it. And when I mean deploy, I mean to put it on a web server so that people can access it through the Internet.\nWhy is that? I spent a lot of time working on my website and when I hosted it, I realised the theme had troubles with CORS. After a bit of search, it seemed that it was something the author was already aware of, but she claimed to have solved it. Could I be bothered opening an issue in GitHub or trying to fix it myself? Not at that stage. The theme was nice, but not perfect, and I rather choose another theme than spending to much time fixing it.\nSo my best advice is: go to your themes\u0026rsquo;s project, and find the demo site. Most themes do include such thing. Deploy it by yourself, and test it. That would be the best way to go before taking the final decision which theme to choose.\nAutomate Your Deployment # It might seem like overkill, but trust me, it saves you loads of time. What do you prefer: using the site every time you want to publish content, or letting a script do the job for you? If you want the second option but are worried about the difficulty, don\u0026rsquo;t worry! Just read my post about it:\nAutomated Deployment ","date":"10 January 2025","externalUrl":null,"permalink":"/posts/hugo-website/","section":"Posts","summary":"Some hints about publishing a website using Hugo","title":"How to Publish Your Website Using Hugo and Survive to the Process","type":"posts"},{"content":"La Coctelera is a project to create a collaborative open database for cocktail recipes.\nProject Incepcion # This project was born in 2024 and it was inspired by the AeroPrecipe web site. On that site, people can post their own recipes for making delicious coffee using an AeroPress brewer. The recipes are organised into categories and voted on, which makes the site a great place to share and learn about coffee and try out new recipes from other users.\nMany web sites and blogs offer cocktail recipes, but there is no such a place like AeroPrecipe for cocktails as of today. This project aims to fill that gap, and foster an open community behind the passion of preparing and drinking cocktails.\nTip La Coctelera aims to become for cocktails what AeroPrecipe is for AeroPress recipes.\nGoals # The main goal of the project is to deliver a web site alike to AeroPrecipe, in which users can post their recipes, and develop together a data base for cocktail recipes.\nRecipes will be organised, based on categories, ingredients and so on, so it will be easy for people to find recipes based on types of liquors, types of glass or any other attributes. Also, a voting system will be used to help highlight the recipes that most of the people enjoy.\nFrom a more technical point of view, the project aims to deliver a segregated back-end service from the main front-end that people would use to access the information of the database. This way, people with programming skills can develop their own clients for specific platforms, such as Android, simply connecting to the back-end service.\nFront-end # The main access point to the data base will be a web page that people could use to simply access cocktail recipes, or they could register and post their own recipes.\nThe development of the front-end is still in an early stage. If you are interested in it, please visit this repository in GitHub:\nfelipet/lacoctelera_frontend Frontend for La Coctelera web service JavaScript 1 0 Back-end # An open back-end service is developed to allow other interested people to connect their own clients to the open database. Despite developing a segregated solution requires more work, we believe this would encourage programmers to develop clients for other platforms in the future.\nThe back-end offers a REST API whose documentation can be accessed at the projects page:\nDocumentación de la API The API includes several resources that allow accessing data regarding ingredients, authors and recipes. Resources to access data are open, however resources to push or modify data of the data base require an authentication token to be provided. Tokens can be freely requested (see the link included in the API docs), and the main purpose of such security measure is to prevent spamming or malicious usage of the data base.\nDevelopment # The back-end service is close to reach the first stable version. If you are interested in the development or the source code, it is open source and available at:\nfelipet/lacoctelera_backend Backend for La Coctelera web service Rust 1 0 The service is temporally deployed at nubecita.eu. The data base only contains a few example recipes at the moment, but it could start to be used for testing purposes.\nIf you visit the API docs page, a Swagger UI is delivered that works as demo of the allowed operations with the API.\nFor instance, it is possible to issue a request to check if there is any recipe about how to prepare a Cosmopolitan using curl as follows:\ncurl -X \u0026#39;GET\u0026#39; \\ \u0026#39;https://nubecita.eu/coctelera/api/v0/recipe?name=cosmopolitan\u0026#39; \\ -H \u0026#39;accept: application/json\u0026#39; ","date":"9 January 2025","externalUrl":null,"permalink":"/projects/lacoctelera/","section":"Selected Projects","summary":"La Coctelera is a project to create a collaborative open database for cocktail recipes.","title":"La Coctelera","type":"projects"},{"content":"","date":"9 January 2025","externalUrl":null,"permalink":"/projects/","section":"Selected Projects","summary":"","title":"Selected Projects","type":"projects"},{"content":"The Ibex ShorBot is a Telegram Bot that helps investor to watch short positions against companies included in the Ibex35 index (Spanish\u0026rsquo;s main stock index).\nShort positions tend to increase the volatility of the price, and most of the times, it ends in a big price drop. Regular buy\u0026amp;hold investors are greatly exposed to these type of movements.\nShort positions are legal, an useful, despite many investors think about them. Keeping track of these positions can leverage big returns either trying to catch a potential downtrend, or avoiding to buy stocks of a company with a big load of short positions, and waiting to buy when funds start to withdraw short positions.\nThe bot helps investors to access that information in a simple and quick way, straight from the interface of Telegram, using a regular chat interface.\nIbex ShortBot is an open source project of public access: just add the bot to your Telegram chat searching for @IbexShortBot. A public chat group is also available (Spanish \u0026amp; English). Questions and proposals are welcome.\nfelipet/shortbot A Telegram bot that analises CNMV\u0026rsquo;s page to find short positions Rust 1 0 ","date":"9 January 2025","externalUrl":null,"permalink":"/projects/shortbot/","section":"Selected Projects","summary":"A Telegram bot that monitors short positions in the IBEX35","title":"Shortbot","type":"projects"},{"content":"Here it is! After many years of thinking about starting to write a personal blog, the time has come, and the proof is in this blog post.\nWhy now? Why didn\u0026rsquo;t you start it before?\nI was reluctant to start a new blog because I felt that the internet was already overcrowded with content and that my modest writing wouldn\u0026rsquo;t add anything of value to the vast world wide web. However, about a year ago I started to spend more time working on some personal projects that I think are worth sharing. Moreover, they might need some more details than those provided by the developer\u0026rsquo;s docs and other (more formal) sources of information.\nSo the main purpose of this blog is this: to share updates and further information about my personal side projects. I expect to add more stuff about my hobbies in the future, specially about investment and finance (does it qualify as a hobby?), but I can\u0026rsquo;t promise that because it all depends on how much free time I have.\n","date":"9 January 2025","externalUrl":null,"permalink":"/posts/first-post/","section":"Posts","summary":"The very first post of my new blog!","title":"My Fancy New Blog","type":"posts"},{"content":"","externalUrl":null,"permalink":"/authors/","section":"Authors","summary":"","title":"Authors","type":"authors"},{"content":"","externalUrl":null,"permalink":"/series/","section":"Series","summary":"","title":"Series","type":"series"}]