[{"content":"In this post, I will share the 3D model for an O-scale model of a BR08 shunting locomotive that can be printed and made to run on battery power.\nSome history The British Rail Class 08 is a class of diesel-electric shunting locomotives introduced in the early fifties and used to be a common sight at major stations and freight yards. Shunting locomotives are specialized low-speed, high traction engines to move and rearrange carriages and wagons to build a complete train. They replaced earlier steam models because the diesel-electric shunters did not need any warm-up time, did not waste fuel when idling, had lower maintenance overhead, led to cleaner environments and were operable by one person. Pictured below is the BR08 911, which can be seen in the National Railway Museum in York.\nVisually, the British Rail Class 08 looks similar to the Dutch NS Class 500 introduced in the late fourties. This is not surprising, because both trace back their roots to London, Midland and Scottish Railway (LMS) and War Department prototypes. In the second World War, the British War Department ordered large numbers of shunting locomotives for military logistics. At the end of the war, many of these were no longer needed and some surplus was transferred to mainland Europe to help in the post-war reconstruction. This is where NS put them in service as the Class 500 shunters in non-electrified yards in a period during which the railway electrification could be restored and expanded again in the Netherlands.\nThese days shunting locomotives are less important as freight trains no longer mix-and-match wagons (wood, steel, coal) and instead switched to single cargo block trains. A block train carries only one type of load from the origin straight to a destination with uniform wagons. Modern wagons are connected with more permanent couplers that also connect airbrakes and electronics systems, which is a big difference compared to old wagons which were only connected with a 3 link chain and relied on a brake van at the end to slow down.\nYou will also no longer see shunting locomotives to build a modern passenger train. Most passenger trains now consist of multiple units with a cabin at both ends that allows it to run in either direction. The size of the train is fixed, but in peak hours multiple trains can be coupled together. This again, is a big difference to how passenger trains were built in the past where there might have been a passenger car, post car, dining car and baggage car.\nToday you can see four shunting locomotives visually similar to the BR08 in the Dutch Railway Museum. Pictured below is the NS512 which is part of their collection. Also, Railpro and Rail Force One employ some modern iterations which are still used to do minor shunting work when needed. For example, I have seen one near the port of Amsterdam.\nWhy I chose to model this I was looking to model a steam locomotive to run on my dad\u0026rsquo;s HO-scale model railroad. After ordering some N20 motors and taking some measurements, I quickly realized that it would be rather difficult to design and print something in this scale. That\u0026rsquo;s why I went with O-scale instead. This scale allows for a model that is large enough to fit some motors, batteries and electronics.\nI opted for the BR08 diesel-electric shunter because of it\u0026rsquo;s rich history and mass appeal. It\u0026rsquo;s also slightly easier to model compared to a steam locomotive, as there are fewer parts and many reference images are available online. I particularlry liked the connecting rod connecting the three wheels together as this enabled me to work a bit with gears and should provide better traction on plastic O-scale track. I would rather have modeled the NS class 500 but I couldn\u0026rsquo;t find accurate measurements online and, in the end, they are basically the same locomotive from the outside.\n3D Model The model consists of a lower chassis and an upper body that fits together with a neat friction fit. The chassis is designed around a mount for an N20 motor that snaps in and can be secured with a small tie-wrap. The motor is connected to each of the wheels using two bevel gears and a series of spur gears. The spur gears are friction fit attached to 3mm rods, just like the wheels. After assembling everything, you can attach the coupling rods to the wheels with small screws, preferably with an unthreaded shank.\nShown below is a closeup of the gearbox connecting the N20 motor to the wheels. The body of the locomotive consists of two 3d-printed parts as shown in the following picture. Putting the upper body onto the lower chassis and assembling all the remaining parts produces the final product as shown below. Parts to print:\n1x lower chassis 1x upper body 6x wheels 2x coupling rods 1x bevel gear 1x bevel gear with spur gear attached 2x spur gear big 2x spur gear small 12x rod spacers I didn\u0026rsquo;t design the tracks myself, but instead reused some existing models on Thingiverse. Depronized has created a nice set of tracks as part of his OS-Railway project. The set includes curves, straights and various other pieces like switches. He also created a whole ecosystem for 3D printed trains, but these models are mostly American and possibly in a slightly different scale.\nElectronics To make the train move, you can add an ESP32, an N20 DC motor, a TB6612fng or DRV8833 motor driver and some batteries. I chose N20 motors with encoders attached so I can build two trains and run them at the same speed. I believe early models of the NS500 or Hippels were sometimes used in tandem to pull a big load of sugar beets over a hill in the south of the Netherlands, but I can\u0026rsquo;t find any reference source anymore.\nThe reason for choosing an ESP32 over an Arduino is the integrated wifi and bluetooth stack. It\u0026rsquo;s relatively easy to run a webpage from the ESP32 with a slider input for speed and a button to start/stop. There are also mobile apps available in the app store that connect to an ESP32 over Bluetooth and act as a gamepad controller. Depending on the app, there will be libraries available online to help read the user inputs, like a button press event.\n","permalink":"https://driftingbits.github.io/posts/scale-model-train/","summary":"\u003cp\u003eIn this post, I will share the 3D model for an O-scale model of a BR08 shunting locomotive that can be printed and made to run on battery power.\u003c/p\u003e\n\u003ch2 id=\"some-history\"\u003eSome history\u003c/h2\u003e\n\u003cp\u003eThe British Rail Class 08 is a class of diesel-electric shunting locomotives introduced in the early fifties and used to be a common sight at major stations and freight yards. Shunting locomotives are specialized low-speed, high traction engines to move and rearrange carriages and wagons to build a complete train. They replaced earlier steam models because the diesel-electric shunters did not need any warm-up time, did not waste fuel when idling, had lower maintenance overhead, led to cleaner environments and were operable by one person. Pictured below is the BR08 911, which can be seen in the National Railway Museum in York.\u003c/p\u003e","title":"BR08 Model Train (O-scale)"},{"content":"There is no cloud, it\u0026rsquo;s just someone else\u0026rsquo;s computer.\nIf you store your data online for free, your data is the product. Big companies are mining your data for targeted advertising, and more recently, to improve their AI models. In this post I will show you how I setup up my home server and how you can do the same to take back control over your data. Do remember though that by taking control of your data, you will also need to take care of your own backups to keep it save.\nArchitecture The diagram below shows a simiplified view of how you can setup your home server by following this blog post. The server running Debian Linux is hosted behind a router and only allows http and https traffic using a firewall. A Caddy reverse proxy accepts the http and https connections and forwards it to sites hosted in Docker containers. Authelia is used to provide authentication and single sign-on to protect the sites, even if they don\u0026rsquo;t support authentication by themselves.\nHardware Online you will see some conflicting opinions regarding the best hardware for you home server. Some people advocate for old used rackservers or other enterprise gear. On the other side, you also have people recommending an ARM-based single-board computer like the Raspberry Pi 5B or a mini pc with x86 architecture.\nHaving tried both, I would consider a mini pc or even a used laptop (\u0026lt;10 years old) to be the best hardware for your home server. They will be an order of magnitude more quiet and energy efficient compared to (older) rack-mounted servers. Especially if you are living somewhere with high energy prices, you should not underestimate the power consumption. As an example, a mini pc with a power consumption of 10W that is left on 24/7 for a whole year will consume 87.6 kWh per year. If you pay €0.25 per kWh, this results in about €21.90 per year. A used enterprise grade dual socket server would idle closer at 100W, resulting in an energy cost of €219.00 yearly instead.\nFor my new home server, I will be using a Soyo M4 Mini which I bought for less than €100 from AliExpress on black friday. It has an Intel N150 processor and 12GB of DDR5 RAM. The processor has four cores and a base power of just 6W. This makes for a very energy efficient server. Some of the other reasons I bought this model include the dual ethernet ports on the back and the USB type-C power port. Unfortunately, I later learned the USB type-C power port requires a special 12V charger and is not compatible with regular chargers.\nOperating System I will run self hosted software in containers using Docker on the Debian operating system. Debian is one of the oldest Linux distributions with a good amount of users. Having many users, there is also a lot of information and documentation around on the internet. I\u0026rsquo;m going with the latest stable release, Debian 13 Trixie. If you are following along, you can take a look at the official installation instructions or look for the most up to date simplified tutorial you can find.\nI used the guided installer and set up full disk encryption. This means your data is encrypted at rest making it unreadable if someone were to get physical access to your machine. At boot time, you enter the encryption password to unlock the data and use the machine as normal. As we are setting up a server, you may not like to connect a keyboard and monitor everytime you restart the server. In a subsequent section we will look into using Dropbear to unlock the machine through SSH. An alternative is setting up another server with Tang/Clevis that will provide your rebooting server with the password to decrypt the data when required.\nOn the last screen of the Debian installer you can choose which software you want to install by default. You can deselect all the graphical environments and select the ssh server if you want to manage your server remotely through ssh. By installing as few packages as needed you also reduce your potential attack service.\nPost installation steps There are some steps we can take to further secure our system. You don\u0026rsquo;t really have to worry about hackers specifically targeting your server, but you will see automated bots trying to break in every day. This means the best defense is using strong passwords and not opening up too many attack surfaces.\nThis is not a full tutorial and only serves as a starting point. I have included some commands from my personal notes should I ever need them again.\nSetting up a static IP address By default your server will probably get a dynamic IP address assigned through DHCP. You can change the network configuration to use a static IP address instead. My preferred way of doing so is through your router\u0026rsquo;s configuration. Most routers can be configured to create a DHCP reservation that maps a device\u0026rsquo;s MAC address to a permanent IP address. The MAC address is the unique hardware-based identifier of a network interface and remains static across reboots or operating system reinstallations.\nTo get your IP address on the server:\n$ ip address 2: enp3s0: \u0026lt;BROADCAST,MULTICAST,UP,LOWER_UP\u0026gt; mtu 1500 qdisc fq_codel state UP group default qlen 1000 link/ether 3c:52:82:9a:4f:1b brd ff:ff:ff:ff:ff:ff inet 192.168.178.42/24 brd 192.168.1.255 scope global dynamic enp3s0 valid_lft 86312sec preferred_lft 86312sec inet6 fe80::3e52:82ff:fe9a:4f1b/64 scope link valid_lft forever preferred_lft forever Setting up SSH public key authentication Instead of using a username and password to login to our server remotely over SSH, we can use public key authentication. This means we create a key pair on our local machine, which consists of a public and private part. We keep the private part on our local machine, but upload the public part to the server. When logging in, the server can use the public key to verify we have the private key and are allowed to login. This is much more secure than a (short) password.\nOn your local machine:\n$ ssh-keygen -t ed25519 -a 100 $ ssh-copy-id -i ~/.ssh/id_ed25519.pub user@your-server-ip As we have uploaded the public key to the server, we can now disable password based authentication. We will also change the default ssh port from port 22 to 2222, as this will ward off a significant number of attackers using automated scripts.\nOn your server:\n$ sudo nano /etc/ssh/sshd_config PasswordAuthentication no PermitRootLogin no UsePAM no Port 2222 $ sudo systemctl restart ssh Setting up a firewall (UFW) Installing a firewall is always a good idea and UFW is by far the easiest solution available. It\u0026rsquo;s best practice to disable all incoming connections by default and only open ports if you need to. Outgoing traffic is usually enabled by default because you trust your system. Your server needs outgoing connectivity to fetch package updates, do DNS lookup etc.\nOn your server:\n$ sudo apt install ufw $ ufw default deny incoming $ ufw default allow outgoing $ ufw allow 2222/tcp comment \u0026#34;Open SSH port\u0026#34; $ ufw allow http $ ufw allow https $ sudo ufw enable $ sudo ufw status verbose Status: active Logging: on (low) Default: deny (incoming), allow (outgoing), disabled (routed) New profiles: skip To Action From -- ------ ---- 2222/tcp ALLOW IN Anywhere # Open SSH port 80/tcp (HTTP) ALLOW IN Anywhere 443/tcp (HTTPS) ALLOW IN Anywhere 2222/tcp (v6) ALLOW IN Anywhere (v6) # Open SSH port 80/tcp (v6) ALLOW IN Anywhere (v6) 443/tcp (v6) ALLOW IN Anywhere (v6) Setting up fail2ban Fail2ban runs in the background and analyzes logs for repeated failed login attempts and temporarily bans the source IP address. Even though we have disabled password based authentication for SSH, malicious brute-force scripts will still attempt to login. Usually, they will try a list of popular passwords like welcome123 and password which can flood our logs. It also helps if we accidentally forgot to disable password based login for SSH and adds a layer of defense.\nOn your server:\n$ sudo apt install fail2ban $ sudo nano /etc/fail2ban/jail.local [DEFAULT] banaction = ufw [sshd] enabled = true port = 2222 logpath = %(sshd_log)s backend = systemd maxretry = 3 findtime = 10m bantime = 1h # Escalate bans for repeat offenders bantime.increment = true bantime.factor = 2 $ sudo systemctl restart fail2ban $ sudo fail2ban-client status sshd Setting up unattended updates When unattended updates are enabled, your server can automatically install critical security updates without user interaction. This means that security vulnerabilities in the software you run will be resolved automatically before you even read about them in the regular news. Usually these updates do not even require a reboot and your system remains available.\nOn your server:\n$ sudo apt install unattended-upgrades $ sudo dpkg-reconfigure unattended-upgrades $ sudo unattended-upgrade -d Setting up Dropbear We have set up full disk encryption, which means you need to enter a password before the operating system boots and your services start running. The environment where you enter your decryption password is the initramfs and is not encrypted. Instead of typing the password on a keyboard connected to your server, you can also enter if over SSH using Dropbear. We will install Dropbear to run in the initramfs environment and use it to host an SSH server that can decrypt our data. It\u0026rsquo;s completely separate from our normal SSH server and UFW firewall setup.\nFirst we configure Dropbear to run an SSH server with port forwarding disabled on port 2221 that runs the cryptroot-unlock command as you log in. We choose a different port than the regular SSH server as you will otherwise run into a known host fingerprint warning later on. On your server:\n$ sudo apt install dropbear-initramfs $ sudo nano /etc/dropbear/initramfs/dropbear.conf DROPBEAR_OPTIONS=\u0026#34;-I 120 -j -k -p 2221 -s -c cryptroot-unlock\u0026#34; Next we copy over our SSH public key from our local machine and add it to the authorized keys. On your local machine:\nscp /home/user/.ssh/id_ed25519.pub user@your-server-ip:~/dropbear_key.pub On your server:\n$ cat dropbear_key.pub \u0026gt;\u0026gt; /etc/dropbear/initramfs/authorized_keys $ rm dropbear_key.pub $ update-initramfs -u $ sudo reboot Next, we verify we can unlock the server over SSH. On your local machine:\n$ ping your-server-ip $ ssh -p 2221 root@your-server-ip $ ssh -p 2222 user@your-server-ip Installing Docker We will use Docker to run our software in containers. You can download it from the Debian repositories, but this version is often out of date. Docker recommends us to add their own APT repository instead to ensure timely access to security updates and new features. The packages are signed with their own Docker GPG signing key, so we will have to add this key to our list of trusted keys. It\u0026rsquo;s best to check the official installation instructions on the Docker website.\nTo trust the Docker GPG signing key on your server:\n$ sudo apt update $ sudo apt install ca-certificates curl $ sudo install -m 0755 -d /etc/apt/keyrings $ sudo curl -fsSL https://download.docker.com/linux/debian/gpg -o /etc/apt/keyrings/docker.asc $ sudo chmod a+r /etc/apt/keyrings/docker.asc Add the Docker repository to the APT sources on your server:\n$ sudo tee /etc/apt/sources.list.d/docker.sources \u0026lt;\u0026lt;EOF Types: deb URIs: https://download.docker.com/linux/debian Suites: $(. /etc/os-release \u0026amp;\u0026amp; echo \u0026#34;$VERSION_CODENAME\u0026#34;) Components: stable Signed-By: /etc/apt/keyrings/docker.asc EOF Install Docker from the newly added Docker repository on your server:\n$ sudo apt update $ sudo apt install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin $ sudo systemctl status docker $ sudo systemctl start docker $ sudo systemctl enable docker $ sudo usermod -aG docker $USER When running a container you can publish a port on your host system to forward traffic to the container. For example, traffic from port 8080 on your host system can be forwarded to a webserver running on port 80 in the container. By default Docker does not respect our previously created firewall rules and will automatically add an entry to allow traffic to port 8080 after publishing it. We don\u0026rsquo;t want this, so we will only publish the ports on the local loopback network interface (127.0.0.1) and run our software behind a reverse proxy.\nInstalling the Caddy reverse proxy We will use Caddy as a reverse proxy. A reverse proxy accepts incoming requests and forwards it to backend webservers, such as our software running in a Docker container. Forwarding is done based on a (sub) domain or URL path and allows us to host multiple websites on a single machine. We choose Caddy instead of Nginx or Apache because it has very simple configuration and built-in support for automatic HTTPS.\nThe installation procedure is comparable to the steps taken for Docker. On your server:\n$ sudo apt install -y debian-keyring debian-archive-keyring apt-transport-https curl $ curl -1sLf \u0026#39;https://dl.cloudsmith.io/public/caddy/stable/gpg.key\u0026#39; | sudo gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg $ curl -1sLf \u0026#39;https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt\u0026#39; | sudo tee /etc/apt/sources.list.d/caddy-stable.list $ chmod o+r /usr/share/keyrings/caddy-stable-archive-keyring.gpg $ chmod o+r /etc/apt/sources.list.d/caddy-stable.list $ sudo apt update $ sudo apt install caddy To allow HTTP (port 80) and HTTPS (port 443) we will update the firewall rules:\nsudo ufw allow http sudo ufw allow https sudo ufw reload You do not need to open up any other ports. In a following section we will configure Caddy to redirect web traffic to our selfhosted sites bound to the local loopback interface (127.0.0.1).\nSelfhosting software This section goes into depth how to install and configure software to selfhost through an example. It details a pattern that can be repeated for (almost) anything you would want to selfhost.\nDocker compose Docker compose can help define (multi) container applications with a yaml file. The file describes everything needed for your application to run, from networking to volume mounts and environment variables. It\u0026rsquo;s easy to put in source control and can be used to start the application with a single command. I generally create a folder for each application I intend to selfhost. Within that folder I create my docker-compose.yml file and some subfolders to store application specific data.\nAs an example we will look at a simple Nginx webserver that hosts the default web page. On your server:\n$ mkdir helloworld $ cd helloworld $ nano docker-compose.yml version: \u0026#34;3.8\u0026#34; services: web: image: nginx:alpine ports: - \u0026#34;127.0.0.1:8080:80\u0026#34; $ docker compose up -d $ curl localhost:8080 $ docker compose down The curl command should print the raw html of the default Nginx web page. Now we will look at how to customize this web page by using a volume mount and writing our own html:\n$ pwd ~/helloworld $ mkdir html $ nano html/index.html \u0026lt;!DOCTYPE html\u0026gt; \u0026lt;html\u0026gt; \u0026lt;head\u0026gt; \u0026lt;title\u0026gt;Hello World\u0026lt;/title\u0026gt; \u0026lt;/head\u0026gt; \u0026lt;body\u0026gt; \u0026lt;h1\u0026gt;Hello World!\u0026lt;/h1\u0026gt; \u0026lt;p\u0026gt;This page is served from a mounted volume.\u0026lt;/p\u0026gt; \u0026lt;/body\u0026gt; \u0026lt;/html\u0026gt; $ nano docker-compose.yml version: \u0026#34;3.8\u0026#34; services: web: image: nginx:alpine ports: - \u0026#34;127.0.0.1:8080:80\u0026#34; volumes: - ./html:/usr/share/nginx/html:ro $ tree . ├── docker-compose.yml └── html └── index.html 1 directory, 2 files $ docker compose up -d $ curl localhost:8080 $ docker compose down The container’s port is bound to 127.0.0.1 to prevent accidental exposure without the reverse proxy. Another thing you need to know about Docker containers is that whatever happens in the container stays in the container, unless you use a volume mount. That means that if your website is accepting file uploads, you need to create a volume mount such that the file uploads are stored on the host file system. Otherwise, you will lose the files as soon as the container is stopped and removed.\nAdding authentication with Authelia You may want to protect your selfhosted software behind a login. As not all selfhosted software implements authentication in the same way, or even at all, you can configure forward authentication. Forward authentication is a simple way to implement single sign-on. The Caddy reverse proxy will forward traffic to an authentication service like Authelia. Authelia will check if the request has a valid session cookie before forwarding the request to the relevant backend. If the request does not have a valid session cookie, the user is presented with a login form instead. Once the user is logged in, the session cookie is set and subsequent requests will not require another login until the session expires.\nAuthelia works with a couple of backends to manage users and credentials. If you don\u0026rsquo;t expect more than a couple of users, using the postgres backend will be overkill. Instead, I will show an example of how to use the simple file-based backend.\nOn your server:\n$ mkdir ~/authelia $ nano ~/authelia/docker-compose.yml version: \u0026#34;3.9\u0026#34; services: authelia: image: authelia/authelia:latest container_name: authelia volumes: - ./config:/config ports: - \u0026#34;127.0.0.1:9091:9091\u0026#34; restart: unless-stopped $ mkdir ~/authelia/config $ nano ~/authelia/config/configuration.yml jwt_secret: \u0026#34;\u0026lt;some long string\u0026gt;\u0026#34; notifier: filesystem: filename: /config/notification.txt authentication_backend: file: path: /config/users.yml access_control: default_policy: deny rules: - domain: \u0026#34;*.yourdomain.com\u0026#34; policy: one_factor session: # This secret can also be set using the env variables AUTHELIA_SESSION_SECRET_FILE secret: \u0026#39;\u0026lt;another long string\u0026gt;\u0026#39; cookies: - name: \u0026#39;authelia_session\u0026#39; domain: \u0026#39;yourdomain.com\u0026#39; # Should match whatever your root protected domain is authelia_url: \u0026#39;https://authelia.yourdomain.com\u0026#39; expiration: \u0026#39;1 hour\u0026#39; inactivity: \u0026#39;5 minutes\u0026#39; default_redirection_url: https://login.yourdomain.com storage: encryption_key: \u0026#39;\u0026lt;yet another long string\u0026gt;\u0026#39; local: path: /config/db.sqlite3 Now we need to generate a hashed password for our user:\n$ docker run --rm authelia/authelia authelia crypto hash generate argon2 --password \u0026lt;user password\u0026gt; Next, let\u0026rsquo;s create the authentication backend file called config/users.yml:\n$ nano ~/authelia/config/users.yml users: yourusername: password: \u0026#34;\u0026lt;your hashed password (output from previous command)\u0026gt;\u0026#34; displayname: \u0026#34;\u0026lt;your username\u0026gt;\u0026#34; email: \u0026lt;your email\u0026gt; Finally, we can start authelia and continue with the reverse proxy configuration.\n$ cd ~/authelia $ docker compose up -d Caddy configuration Caddy is quite easy to configure as a reverse proxy for our needs. There are only two things you need to do before you start. First, you need your own domain name with an A record pointing it to your public IP address. Second, you need to configure port forwarding on your router to forward requests to port 80 and 443 to your server. If your public IP address is not static, you can look into a Dynamic DNS (DDNS) provider that allows you to update the IP address automatically with a (cronjob) script.\nWe will create two sites: one accessible without authentication and another that requires authentication with Authelia hosting the helloworld application from before. On your server:\n$ sudo nano /etc/caddy/Caddyfile insecure.yourdomain.com { respond \u0026#34;Caddy is working\u0026#34; 200 } login.yourdomain.com { reverse_proxy 127.0.0.1:9091 } secure.yourdomain.com { forward_auth 127.0.0.1:9091 { uri /api/verify?rd=https://login.yourdomain.com } reverse_proxy 127.0.0.1:8080 } $ sudo caddy validate --config /etc/caddy/Caddyfile $ sudo systemctl reload caddy That\u0026rsquo;s all we need to really configure. If all went well, you should be able to open a browser and navigate to insecure.yourdomain.com and secure.yourdomain.com. The first one will be accessible without logging in and displays the text \u0026ldquo;Caddy is working\u0026rdquo;. The latter will redirect you to a login form to login, after which a session token is set and you are redirected to the customized helloworld website hosted in an Nginx Docker container.\nThere is no need to manually configure HTTPS. When Caddy is configured with a valid domain name, it automatically enables HTTPS and obtains a TLS certificate from Let’s Encrypt using the ACME protocol. This means it will prove your ownership of the domain by temporarily serving a special token, after which Let\u0026rsquo;s Encrypt will verify the token and generate a certificate. There\u0026rsquo;s no need to setup a renewal job either as the certificate will be automatically renewed before it expires without downtime. By default, HTTP requests are redirected to HTTPS, ensuring that credentials and session cookies are never transmitted over an unencrypted connection.\nWhat to host Below I have included a list of software that might be interesting to host yourself. I have not had the time to test all of it, but I have taken inspiration from online sources and believe it will be a good starting point. All of the mentioned software is open-source.\nAuthelia: Authentication and authorization server that provides single sign-on (SSO) functionality for web applications. In a home server setup it can be used with forward authentication and a file-based user database. If you want more, you can also configure a Postgres user database, access control policies and integrate it with external identity providers.\nBentoPDF: Tool for working with PDF files. It supports all PDF operations like split, merge, redact, and signing.\nBookstack Platform for storing and organizing data. Use it for notes and documentation. Built-in support for diagrams.net and export functionality to PDF.\nCyberchef Tool for encryption, encoding, compression and so forth. My favourite operations are base64 decode, JSON beautify and JWT decode. The operations can even be chained and it\u0026rsquo;s a very useful tool overall.\nForgejo For git repositories, like a selfhosted GitHub or Gitlab. It has integrated support for CI jobs similar to GitHub Actions.\nMealie Manage your recipes and meal plans. I intend to use this for storing family recipes and meal prepping when I move out.\nPaperless-ngx Organize your letters and PDFs using tags. Offers full-text search based on OCR.\nSummary All in all, I think it\u0026rsquo;s a good idea to look into and maybe start with self hosting. It does, however, take away quite a bit of time and I personally still use some cloud providers out of convenience. It\u0026rsquo;s important to keep security in mind from the start and I hope this post helped you discover something new. For me, this post will serve as documentation as there is nothing worse than your services breaking when you least expect it and having no recollection of how you implemented them.\n","permalink":"https://driftingbits.github.io/posts/efficient-homeserver-setup/","summary":"\u003cp\u003eThere is no cloud, it\u0026rsquo;s just someone else\u0026rsquo;s computer.\u003c/p\u003e\n\u003cp\u003eIf you store your data online for free, your data is the product. Big companies are mining your data for targeted advertising, and more recently, to improve their AI models. In this post I will show you how I setup up my home server and how you can do the same to take back control over your data. Do remember though that by taking control of your data, you will also need to take care of your own backups to keep it save.\u003c/p\u003e","title":"Home Server Setup"},{"content":"Today\u0026rsquo;s quick post will give you reproducible steps to create a scale model of your home or apartment. I was inspired to create a few scale models as some of my friends have bought an apartment this year and I was looking for unique secret Santa gifts. Having a scale model with scale furniture helps visualize the space and helps you create a floor plan before you get the keys to your new house or apartment.\nDesign considerations There are a few things you can think about to make the scale model fit your expectations. For example, half height walls will make it easier to put little furniture inside. Also, the way windows and doors are modeled can have an impact on the durability of the model.\nIn my case, I have chosen to model everything at 1/10th the real size. Because a house is significantly larger than a 3D printer print bed, modeling it with real dimensions would result in a scaling factor in the slicing software of around 1%. This is tricky, can lose small details and might make for thin and vulnerable walls.\nI made my first model with walls at a third of the normal height. This is a good height in my opinion, but part of the window frames and front door were not connected at the top. This makes the window frames fragile and I would recommend connecting them at the top to improve the strength of the model. The next models I made also had taller outer walls with complete window frames, which further improved the model rigidity. Increasing the wall height has only little impact on the printing time as the most time is spent making the floor or bottom of the model.\nModeling instructions for Onshape By following these instructions you get a scale model at scale 1:10.\nCreate a new sketch in the XY plane and draw the outer walls. Dimension them using the real measurement divided by 10 to get a model at scale 1:10. Create another sketch in the XY plane and draw the inner walls. Dimension them using the real measurement divided by 10 to get a model at scale 1:10. Use the thin extrude function to extrude the outer walls with thickness 1 set to 26mm. By only setting thickness 1, we ensure the area remains the same as in the floor plan. Use a depth of around 200mm. Use the thin extrude function to extrude all the vertical inner walls with thickness 1 and 2 both set to 5mm. Use a depth of around 160mm. We extrude the inner walls with two operations, because the thin extrude operation can not handle Y or T sections of walls. Use the thin extrude function to extrude all the horizontal inner walls with thickness 1 and 2 both set to 5mm. Use a depth of around 160mm. Create some sketches on the inner walls to create the doors. My doors are 91mm wide. Use the extrude remove operation up to next or blind. Create some sketches on the outer walls to create the windows. You can use a couple extrude remove operations to create the windows, windowsills and frames. You can select a sketch and copy paste it to create more windows. Create a new sketch in the XY plane to create a floor. Use the line or rectangle tool to make sure it covers all the walls. Extrude the floor with a depth of around 12mm. If you have more than one body in the project, you can use the boolean union operation to combine all the parts into a single body. Export the body as a .stl file. Import the .stl file in your slicer. Scale the model to fit your build plate. In my case I went with 16% for a total scale of 1:62.5. You are now ready to print. Below I have included an example of how the Onshape interface will look like after following the steps. Note how the front door and window frames have a solid bar across them to improve the strength of the model. This is another example of how the model can look after 3D printing. Scale model furniture To bring the model to live, I have also modeled and printed some furniture. Most of it is from IKEA, but I also measured some other pieces from other stores. Feel free to take these models and print them. You can click the model and download the .stl directly. Printing is best done with the same scaling percentage as used for the house or apartment itself.\nKing Sized Bed (IDANÄS) Queen Sized Bed (IDANÄS) Small Double Sized Bed (IDANÄS) Dining Table (LISABO) Dining Table (TARSELE) Dining Table Extended (TARSELE) Dining Table (VOXLOV) Dining Table (VIHALS) Dining Chair (type A) Dining Chair (type B) Closet (PAX) Closet (VISTHUS) Closet (BRIMNES) Couch with 2 Seats (KIVIK) Couch with 3 Seats (KIVIK) Couch with Corner Seats (KIVIK) Television Stand Washing Machine When putting it all together, it will look something like this. In the following close up photo, the queen sized bed, Visthus closet and Tarsele table are displayed.\nClosing Thoughts The scale models are a big hit with friends and family and not that hard to make once you get the hang of it. If you print more than one in the same scale, you can reuse the furniture and play around a bit. The printing time can be quite long depending on your model as the first few layers are usually printed at reduced speed and our floor is relatively big and solid.\n","permalink":"https://driftingbits.github.io/posts/scale_model_house/","summary":"\u003cp\u003eToday\u0026rsquo;s quick post will give you reproducible steps to create a scale model of your home or apartment. I was inspired to create a few scale models as some of my  friends have bought an apartment this year and I was looking for unique secret Santa gifts. Having a scale model with scale furniture helps visualize the space and helps you create a floor plan before you get the keys to your new house or apartment.\u003c/p\u003e","title":"Scale Model House"},{"content":"In this post we will look at how we can design our own tracks and 3D print them as a low-cost and made to measure alternative to commercially available options. Tracks on a robot can help distribute the weight across a larger contact area. Along with the ability for the tracks to stretch and deform a bit, this makes the robot able to travel across both softer and rougher terrain.\nDesigning the tracks If you look at a set of tracks they might seem complicated, but in reality you only need to design one segment and a way to connect multiple copies together. It is important to note how much distance you want to have between two segments. We call this distance the pitch and it is the most important measurement to make sure the track will fit on a sprocket. In turn, it also determines the minimum diameter of the sprockets and rollers you will need to get the tracks to turn smoothly. If you go for bigger segments, you will end up with bigger sprockets and possibly more ground clearance.\nI used the spreadsheet functionality within Freecad to make it easy to change the width and tolerance in my design. It is possible to reference the values in the spreadsheet from the Part Design workbench and have your part update it\u0026rsquo;s dimensions everytime you make a change to the spreadsheet. For me, this came in handy as I initially designed the segments to have a 1mm clearance everywhere, but this resulted in a very loose track that easily derails. After halving the value for the clearance in the spreadsheet, I could easily export the modified part as an .stl again and print it.\nTo speed up the printing process, I used the Cura slicer to print a sequence of segments in one go. Since the segments do not have a very large contact area with the print bed, it is possible they pop off. This will ruin your print and the risk increases the more segments you try to print at once. In my case printing 6-12 segments in one go worked best.\nDesigning the sprocket To design the sprocket, we start with drawing an N-point polygon with an even number of sides. Having drawn the polygon, we can constrain the length of the sides to the pitch length. We will also draw a circle around the polygon and extrude it. This will be the size of the desired sprocket. We can now create a new sketch and project one of the points of the polygon to draw the groove where the track will sit and create a pocket. Using the polar array, we can duplicate the grooves in a circular pattern to create the final sprocket.\nUsing the sprocket, it is possible to create a wheel with a sprocket on both sides. You can use this wheel in your design to drive and/or guide your tracks.\nPutting it all together To connect all the track segments together, I used 1mm galvanized steel wire used in gardening. The amount of links you need to connect together depends on the distance between the two sprockets. To cover the distance, you will need at least as many segments as sides of the polygon used to create the sprocket. Then you need to take the distance between the center of the sprockets and divide it by the length of a single segment. By multiplying this number by two and adding the number of sides of the polygon, you get how many segments you will need. If the resulting track is too loose, you can consider adding an additional non-driven guide wheel or removing a link or two.\nClosing thoughts For my demo, I created one driven wheel powered by a yellow TT gear motor. The other wheel is not connected to anything and spins freely. If I decide to create a tracked robot in the future, I would consider increasing the diameter of the sprockets to increase the ground clearance. It would also be beneficial to add some smaller guide sprockets to make sure the track stays aligned well if the distance between the wheels is increased.\n","permalink":"https://driftingbits.github.io/posts/robot-tracks/","summary":"\u003cp\u003eIn this post we will look at how we can design our own tracks and 3D print them as a low-cost and made to measure alternative to commercially available options. Tracks on a robot can help distribute the weight across a larger contact area. Along with the ability for the tracks to stretch and deform a bit, this makes the robot able to travel across both softer and rougher terrain.\u003c/p\u003e","title":"Robot Tracks"},{"content":"In this post, we look at the process of building a Rubik\u0026rsquo;s cube solver. It uses affordable parts in combination with 3D printing and is a good beginner to intermediate project in case you want to build something similar.\nProject goals I noticed I have been spending quite a bit of time online looking at projects done by other people. Sometimes this can give you inspiration, but it is also possible to get stuck doomscrolling. So, I decided to pick up a new project that I can build from start to finish in a few days whilst learning more about 3D modeling.\nIt is important to me to actually finish something. Usually I stop when the interesting parts are done and move on to something new. Not this time, though. To achieve this I will limit the scope and take shortcuts when necessary. There will be no computer vision to recognize the colour of the squares and you will have to enter the scrambled state manually on the command line instead. I also ended up glueing my pieces to a cardboard base instead of screwing them in with the nice countersink holes I designed.\nHardware used 1x Raspberry Pi 2B (1GB RAM) 1x PCA9685 Servo Driver 8x SG90 Analog Servo 1x Moyu RS3M Magnetic Speed Cube For this build I used parts and hardware that I had already laying around. The most expensive part is the Raspberry Pi 2B, but this can also be substituted with a different single-board computer or microcontroller. One good alternative is the Raspberry Pi Zero 2W. It is newer, smaller and cheaper than the full-sized Raspberry Pi 2. During the build, I particularly liked connecting to the Raspberry Pi over wifi using SSH to upload and run new code. When working with microcontrollers and external power sources before, I was always a bit scared to fry a USB port on my laptop trying to flash new software.\nWhen it comes to the SG90 servos, you really do get what you pay for. It is almost impossible to find genuine servos and I\u0026rsquo;m sure I bought knock-offs of knock-offs. From the lot of 20 I bought, about half of them were dead on arrival. Some didn\u0026rsquo;t respond at all and others seemed to have the gears glued together. Also, I don\u0026rsquo;t think the SG90 servos are strong enough to turn an original Rubik\u0026rsquo;s cube. For this project, I am using a magnetic speed cube which has very low friction to turn the sides and can even be turned when the sides are not perfectly aligned.\nDesigning and printing the 3D models Wanting to get better at 3D design and CAD is a big reason why I choose this project. I have very limited prior 3D modeling experience and decided to create all the models in FreeCAD as this is free and open-source software without license restrictions. Earlier in 2024, the 1.0 version of FreeCAD was released which shows how far the project has come. I would consider it quite usable, if not a bit rough around the edges.\nThe design for the rotating and moving mechanism is the same for all four sides of the cube that will be rotated. In total this results in four different models. One gripper, one moving arm, one base and a gear . If you are interested, the .stl files are present in the github repository. Please take a look at the pictures below to see how they are shaped.\nOne of the big challenges was to get all the parts to fit correctly. If you design a hole with a 3mm diameter, the hole may not actually be 3mm after 3D printing. The filament is squished out of the nozzle resulting in slightly inaccurate prints. As a rule of thumb, I designed all holes 7% larger than they had to be and this worked out fine. I also measured the sides of the Rubik\u0026rsquo;s cube for the gripper and scaled this with 7%, but this turned out not so fine. As you may guess, this part was printed way too big.\nMy favourite thing about 3D printing is the rapid prototyping. I\u0026rsquo;m using an Ender 3 v3 SE and it levels itself and prints reasonably fast. By designing small parts to check the dimensions, you can get the fit right and then move on to the actual design. I found this saves me some filament and makes me more confident in the final design.\nMaking the servo motors move Every servo needs to be connected to a power source and a control signal. The control signal is controlled with Pulse-Width Modulation (PWM) and determines the servo\u0026rsquo;s position. The PWM signal is a digital signal created by quickly turning on and off a pin. The Raspberry Pi 2B has only two hardware PWM channels, but it is also possible to write software to generate a slightly less accurate signal on any digital output pin.\nInstead of using software based PWM, we will instead connect an external PCA9685 servo driver. This driver can generate 16 PWM signals and can be connected with our Raspberry Pi using only four wires using the I2C bus. The I2C protocol is a serial communication protocol that connects a master (Raspberry Pi) to multiple slave devices (servos). Every device has it\u0026rsquo;s own address, so we can send our command to move a specific servo to the bus and all the other listening devices will ignore it.\nThe Fritzing diagram below shows how to connect the servos, the PCA9685 servo driver and the Raspberry Pi together:\nThe easiest way to move a servo motor is shown in the following Python snippet. It will rotate a servo motor 90 degrees and back again, like shown in the gif. As we are using a Raspberry Pi running a full Linux operating system, it is possible to use Python instead of C or C++. A Python library to work with the servo driver shield is provided by Adafruit to get us started as quickly as possible. Notice how we initialize the ServoKit with 16 channels, which will give us an array of 16 servos we can individually control. And all that with only four wires connected from the Raspberry Pi to the servo driver!\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 # Sweep a single servo motor back and forth from adafruit_servokit import ServoKit import time STEP_DELAY = 0.005 kit = ServoKit(channels=16) while True: for deg in range(0, 91): kit.servo[0].angle = deg time.sleep(STEP_DELAY) time.sleep(1) for deg in range(90, -1, -1): kit.servo[0].angle = deg time.sleep(STEP_DELAY) time.sleep(1) The Raspberry Pi is quite fast and would be able to execute the code above without sleep statements, but the servo wouldn\u0026rsquo;t be able to keep up. If you tell it to rotate and then switch the rotation direction, it would just jerk from one side to the other without ever reaching the desired end position. To prevent this we added some sleep statements, but admittedly this is a flawed solution.\nThe sleep statements effectively cause the processor to stall. It\u0026rsquo;s not doing anything and we lose cpu cycles that could have been put to better use. To illustrate this, consider we want to make our program interactive and take an angle from user input. If the user input is only read every 10 seconds because we told the processor to sleep, this makes for a very poor user experience with high latency. Similarly, it would be difficult to move more than one or two servos at a time.\nTo remove the sleep statements, we can take inspiration from video games. Video games and graphics are usually updated with 30, 60 or even more frames per second (FPS). If you press the left arrow key to move, your character doesn\u0026rsquo;t just teleport, but usually move smoothly to the left instead. This is exactly the same we want to achieve with our servo motors.\nWe can create a loop and update our desired servo position every iteration. If you have a specific rotation speed in mind, you can use the time an iteration takes as a delta time and multiply it by the speed to get the distance it should move. After the servo has reached it\u0026rsquo;s desired position you stop updating it or set the speed to zero. In the video game industry, the time between iterations is also known as the frame time. In case a refresh rate of 60 FPS is targeted, this would result in 0.0167 seconds to compute all the updates. Any slower and you will start to see frame stuttering or \u0026rsquo;lag\u0026rsquo;, and the same is true with our servos.\nIn the case of my Rubik\u0026rsquo;s cube solver, however, I don\u0026rsquo;t really care if there are any sleep statements as I don\u0026rsquo;t expect any kind of user input. The program will first calculate a solution and then start turning the faces until the cube is solved. If you are fine with a similar approach, you can look at the snippet below. I created a wrapper class that keeps track of the servo position and if it is moving. If it is not moving, we consider it idle or done.\n1 2 3 4 5 # Rotate clockwise rotation_servo.rotate_clockwise() while not rotation_servo.is_idle(): rotation_servo.update() time.sleep(0.005) If we write some more of these blocks, we can rotate any servos in any sequence we want in order to solve the cube. Take for example the snippet and gif below. It shows a method used to tilt the cube forwards to be able to rotate the top face. It consists of a sequence of steps. First, we need to ensure the gripper servos are rotated correctly before the tilting operation. To do this, we need to move an arm away from the cube, then rotate it, and then move the arm back in. Then, we can tilt the cube. Finally, we need to ensure the servos are back in the correct starting orientation.\n1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 def tilt_forward(): # Set up sides for rotation # Move back linServoB.move_backward() while not linServoB.is_idle(): linServoB.update() time.sleep(0.005) time.sleep(0.5) # Rotate counter clockwise rotServoB.rotate_counter_clockwise() while not rotServoB.is_idle(): rotServoB.update() time.sleep(0.005) time.sleep(0.5) # Move forward linServoB.move_forward() while not linServoB.is_idle(): linServoB.update() time.sleep(0.005) time.sleep(0.5) # Move front and back out of the way. linServoA.move_backward() linServoD.move_backward() while not linServoA.is_idle() and not linServoD.is_idle(): linServoA.update() linServoD.update() time.sleep(0.005) time.sleep(0.5) # Rotate both B and C together. B rotates left. C rotates right. rotServoB.rotate_clockwise() rotServoC.rotate_counter_clockwise() while not rotServoB.is_idle() and not rotServoC.is_idle(): rotServoB.update() rotServoC.update() time.sleep(0.005) time.sleep(0.5) # Move front and back in. linServoA.move_forward() linServoD.move_forward() while not linServoA.is_idle() and not linServoD.is_idle(): linServoA.update() linServoD.update() time.sleep(0.005) time.sleep(0.5) # C needs to finish the sequence to end up in the starting position. # Move back linServoC.move_backward() while not linServoC.is_idle(): linServoC.update() time.sleep(0.005) time.sleep(0.5) # Rotate clockwise rotServoC.rotate_clockwise() while not rotServoC.is_idle(): rotServoC.update() time.sleep(0.005) time.sleep(0.5) # Move forward linServoC.move_forward() while not linServoC.is_idle(): linServoC.update() time.sleep(0.005) time.sleep(0.5) One last thing I want to mention here is that 90 degrees in the code is not actually 90 degrees in real life. I created a mapping between the physical degrees and the degrees in the code in order to improve the accuracy. My cheap servos are rated for 180°, but the real range of motion is more like 110°. This is also the reason why my Rubik\u0026rsquo;s cube solver can only rotate a face 90° at a time before it needs to move back the gripper to reset the orientation to rotate the face any further.\nSolving Rubik\u0026rsquo;s cubes Some might call this cheating, but I used a Python library to get the list of moves needed to solve a given Rubik\u0026rsquo;s cube. The library uses the beginner\u0026rsquo;s method to solve the cube and spits out a list of moves like [F (front clockwise), U (up clockwise), R (right clockwise), L\u0026rsquo; (left counter-clockwise)]. The Python code just reads through this list, executes the movement and moves on to the next move until the cube is finished. The solution can be found quickly on a Raspberry Pi, but is not optimal. When executing the movements with the harware we built, it can take up to about two minutes to turn all the faces and solve a scrambled cube.\nThe reason I didn\u0026rsquo;t write a solver from scratch myself now, is that I have already done it three years ago as part of an university assignment for a course in distributed computing. The solver used Iterative Deepening Search (IDS) to find the smallest number of moves needed to solve a randomly scrambled cube of any size. By dividing the search space over multiple compute nodes in a six-cluster wide-area distributed system, it was possible to study how the algorithm scaled with more compute resources. In an ideal world, we want linear or even superlinear scaling: twice the hardware results in half the execution time. Unfortunately this is not always feasible because of overhead. If you are interested, this is one of the speedup graphs to illustrate how distributed algorithms can scale.\nThe first implementation (blue) achieves a higher speedup with more processes. In this version, a dedicated master process distributes the work across the other nodes. With a low amount of processes this means the master is mostly idle. The second implementation (orange) also uses a master process to distribute the work, but the master node itself also does some calculations in between. When running with only two processes, the second implementation is faster. But as the number of processes increases, we see the speedup will plateau because the master can not keep up when doing both the solving and coordination.\nClosing thoughts All in all, I consider this project a success. I\u0026rsquo;m glad I took some shortcuts and managed to finish the project on time and before starting something else. This is my first blog post and I look forward to writing more often to reflect on things I did and things I learned. If you liked it, please share the page with a friend and stay tuned for new posts.\n","permalink":"https://driftingbits.github.io/posts/rubiks-cube-solver/","summary":"\u003cp\u003eIn this post, we look at the process of building a Rubik\u0026rsquo;s cube solver. It uses affordable parts in combination with 3D printing and is a good beginner to intermediate project in case you want to build something similar.\u003c/p\u003e\n\u003ch2 id=\"project-goals\"\u003eProject goals\u003c/h2\u003e\n\u003cp\u003eI noticed I have been spending quite a bit of time online looking at projects done by other people. Sometimes this can give you inspiration, but it is also possible to get stuck doomscrolling. So, I decided to pick up a new project that I can build from start to finish in a few days whilst learning more about 3D modeling.\u003c/p\u003e","title":"Rubik's Cube Solver"}]