bee.gdn

Adding SSL Certs via CertBot

A few weeks ago I posted about my website configuration using docker and nginx. The one piece I needed to complete for this was adding SSL certificates.

This process proved to be quite a feat during my capstone project in the masters program I was in last year. We had nginx templates to serve different ports depending on if cert files existed or not, ( start_nginx.sh ) and another script which would generate a cert for you:

https://github.com/beedawn/scrapescholar/blob/main/scrapescholar_docker/nginx/ssl_generation_run_from_virtualmachine.sh

This whole process used a certbot docker container, and long story short is we may have let the cart get away from the horse with this approach. It seems overly complicated, but it did teach me a lot about docker and certbot work.

Moving back to the original subject, I began to work on adding certs to my portfolio and a few other web applications I have hosted, and nginx acts as a reverse proxy to direct the requests:


┌───────────────────────────────────────────────┐
│                     VPS                       │
│  ┌─────────────────────────────────────────┐  │
│  │                 Docker                  │  │
│  │  ┌─────────┐     ┌────────┐              │  │
│  │  │ Nginx   │───▶ │ App1   │              │  │
│  │  │         │───▶ │ App2   │              │  │
│  │  │         │───▶ │ App3   │              │  │
│  │  └─────────┘     └────────┘              │  │
│  └─────────────────────────────────────────┘  │
└───────────────────────────────────────────────┘
      ▲
      │
    User

This graph from my earlier post shows the inital set up, and this would ultimately be my final set up after much confusion. I will briefly cover a few of my approaches, and my failures with them. I decided I would explore options other than certbot to install the certificates, this turned out to be a mistake.

My first approach was to use SWAG. My understanding was I needed to put a SWAG container, between nginx and each application for each domain.

 ┌──────────────────────────────────────────────┐
│                    VPS                       │
│  ┌────────────────────────────────────────┐  │
│  │                Docker                 │  │
│  │  ┌─────────┐   ┌────────────┐         │  │
│  │  │  Nginx  │─▶ │   SWAG1    │─▶ App1  │  │
│  │  │         │   └────────────┘         │  │
│  │  │         │   ┌────────────┐         │  │
│  │  │         │─▶ │   SWAG2    │─▶ App2  │  │
│  │  │         │   └────────────┘         │  │
│  │  │         │   ┌────────────┐         │  │
│  │  │         │─▶ │   SWAG3    │─▶ App3  │  │
│  │  └─────────┘   └────────────┘         │  │
│  └────────────────────────────────────────┘  │
└──────────────────────────────────────────────┘
       ▲
       │
     User
 

These SWAG containers stand up a nginx instance on port 80, and use that to verify with Let's Encrypt that you actually own the domain. After much back and forth, I got SWAG to generate some certs, but when going to the sites I was put in a redirect loop that would eventually time out.

To this day I am not entirely sure what benefit SWAG provides over the regular certbot container, and my use cases have not really justified the use of SWAG either.

Anyways, I eventually grew frustrated troubleshooting the redirect loop. The certs seemed good, and my nginx routing seemed to make sense. I think the certs SWAG generated were not entirely aligned with my domain names, and thus the http requests would route from http to https, then back to http, and eventually time out.

My next attempt was to try to use Cloudflare, Cloudflare always seems to be on bleeping computer for some kind of vulnerability or problem, but I am interested in using their tunnels, so I figured I'd dip my toes into the shallow end with some SSL certs.

Cloudflare is pretty slick and offers a lot of analytics. I was surprised my portfolio page seems to get 100+ “unique visitors” a day. I am not sure how this data is aggregated, or what the privacy trade off is. Anyways, it's extremely easy to add cloudflare as a dns record, and have them as middleware. Since cloudflare receives the initial request, you can simply click radio button to enable a partial SSL connection. This will encrypt the request from the end user, to cloud flare, but not encrypt the request from cloudflare, to my VPS. This seemed pretty nice, but also seemed like a hack and not what I wanted. I toyed around with it for a while, and could also not get “Cloudflare origin” certs to work, these would encrypt the last leg of the request.

Anyways, after many failed Cloudflare attempts I decided to go back to certbot. This time I did not use a certbot container, and installed it on the host machine. This seemed much simpler than the approach we used for the capstone project. I downloaded certbot and ran:

certbot certonly --standalone -d bee.engineer

And it made a cert in /etc/letsencrypt, then linked the let's encrypt folder to the nginx container as such:

    volumes:
        – /etc/letsencrypt:/config:ro

I then modified nginx's default.conf so that it new to serve the cert and redirect requests for port 80 to 443:

server {
    listen 80;
    server_name bee.engineer www.bee.engineer;

    location / {
        return 301 https://$host$request_uri;
    }
}

server {
    listen 443 ssl;
    server_name bee.engineer www.bee.engineer;

    ssl_certificate /config/live/bee.engineer/fullchain.pem;
    ssl_certificate_key /config/live/bee.engineer/privkey.pem;

    location / {
        proxy_pass http://portfolio:3000;  # Forward requests to the Next.js server
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection 'upgrade';
        proxy_set_header Host $host;
        proxy_cache_bypass $http_upgrade;
    }
}
 

This approach worked perfectly, after I changed the dns records to not direct traffic to cloudflare.

Now all the requests to my sites get that spiffy lock.

To renew the certs is quite easy too, you just turn off the nginx server and run

certbot renew

The ultimate test will be in November when the certs expire. I think setting up a cron job to stop the docker containers, run the certbot renew command, and bring the containers back up will be the final solution.

I will also say that it is critical to remember to clear your cookies and cache when working with certs. Even though I work professionally with certs at work, I always seem to forget when I am working on my own projects.

Until next time.

I recently finished Effective C++. This was a great book. This book lead me to the realization of the beauty of header files, and the elegance of the differentiation of interface and implementation. There are also some great topics which cover the idea of turning all of a classes attributes to functions, ie Number.int() instead of Number.int. By using this approach, you have an interface between the client and the attribute, which allows modification, if needed, without effecting the API.

I would highly recommend this book to any software engineer who is interested about C++, encapsulation, or object oriented programming. This would pair well with Clean Code, though that book focuses on Java, the concepts translate across any object oriented design approach.

It's been a few months! I've been busy working on some home repairs. Some plumbing, replacing a “Pressure Reducing Valve”, and the expansion tank for a water heater. We have also been working on tiling the walls in our kitchen, as well as replacing the cooktop, sink, garbage disposal and microwave. The induction cooktop is quite nice compared to the electric one we had before that was from 2007 (the year I graduated high school). If you are in the market for a new cook top, and can afford an induction one, I recommend it.

In other news I will begin the PhD program at Robert Morris in less than 2 weeks. I am quite excited and have been working on putting together my 3 introduction slides to present to the community there.

Lastly, I don't think I have mentioned thus far, that we are expecting our first child! The due date is in January, and we are anxiously awaiting their arrival.

Anyways, now time for some technical talk. I made this post on LinkedIn a few weeks ago, and intend to expound on it a bit.

Here is the original post:

This summer, alongside various home improvement projects, I spent a few days porting my personal website to docker and nginx setup. Some folks have asked me in the past how I set up my portfolio page ( http://bee.engineer ). This website has been quite an evolution over the years from about 2008 when I was working on my BS in Graphic Design. The website initially started as a adobe flash actionscript application which emulated the Macintosh user interface. Flash got depreciated and I then ported the website to HTML, and now in its current iteration it is a React/Next.js application that only serves as a front end user interface. Throughout the years I also utilized various hosting philosophies, primarily using "shared web hosting", and some flavor of CPanel - a pretty easy way to host static HTML pages - which you can generate from a Next.js project if you are so inclined. This approach has worked great for years, the web hosting company provides and configures an apache instance and I can change things quite easily through CPanel. However, shared hosting can cost a fair amount of money, especially for a pretty simple webpage. Usually the first year or so is pretty cheap($2-3 a month), then afterwards the price nearly doubles. I have a similar contract which expires within the next year. In the past, I would change hosting companies to exploit these promotions. The project this summer has been to end this song and dance, and I have achieved a cost effective solution which maintains that cheaper window, give me more control, and foster better mobility between providers. The solution, for now, has been to build a docker container for each piece of the website/application (as the portfolio website is a website of websites), and stand an nginx container in front of them to route the requests. Instead of shared hosting, I have found a fairly cheap VPS to deploy my containers to. This post is getting quite long, and perhaps I will write a blog post with more details about building such a website. Anyways, the next step is to get Let's Encrypt involved with some automations to issue and respond to requests utilizing SSL certs - much like we did during the capstone project last fall. Thank you for reading!

I also had an image along with the post...I will loosely translate it to text, as adding images here add's another complication

┌───────────────────────────────────────────────┐ │ VPS │ │ ┌─────────────────────────────────────────┐ │ │ │ Docker │ │ │ │ ┌─────────┐ ┌────────┐ │ │ │ │ │ Nginx │───▶ │ App1 │ │ │ │ │ │ │───▶ │ App2 │ │ │ │ │ │ │───▶ │ App3 │ │ │ │ │ └─────────┘ └────────┘ │ │ │ └─────────────────────────────────────────┘ │ └───────────────────────────────────────────────┘ ▲ │ User

I used ChatGPT to generate this ASCII art, as my attempts looked promising, but failed in practice.

Basically, I have a VPS with docker and it has a docker-compose file which builds an nginx container, that takes all incoming requests, checks the headers to see which domain they are trying to get to, and routes the request to the container holding each web application.

Each web application has its own docker compose file, which builds each application.

I worked on this a while ago, and some of the next steps are migrating this blog page over, and actually incorporating this blog into my website. I also need to work on the SSL portion, though none of my sites aside from this blog, which gets its own SSL cert, actually accept user data, so SSL is probably overkill, but its nice to see that lock in the top right corner of your browser.

I've continued my path of learning C++ as well, and am working with makefiles and trying to understand CMake and all of the capabilities. I think C++ is a great language. Header files seem like a great way to learn a libraries interface without trying to figure out what each function/class do, assuming the names are easy to understand. Templates and Template metaprogramming also seem very interesting. I am wrapping up reading “Effective C++”, and have been toying with a calendar application. I would like to eventually make it a web application, and might be bringing a fire hose to a water gun fight. Most internet sources do not recommend using C++ for such tasks and instead something like Python, Go or Ruby are likely better fits. But my previous experience building a web app with Rust really helped my understanding of how the internals work, and I think that is valuable experience. Plus I am learning C++ and want something to work on so why would I use another language?

Anyways, next time I might have some info about SSL and Let's encrypt, or porting this blog (Writefreely) to a docker container.

Thanks for reading!

C++ Compilers

Its been a while since I've written on here, nearly a year. In that time I have finished the masters program at Penn State University in software engineering. This fall, I will begin a PhD at Robert Morris University.

I have been spending a fair amount of time fiddling around since I finished the Masters program in December, primarily with ham radio and brushing up on my C++.

A lot has changed since I took a C++ class back in highschool. Back then we were using C++98, and Eclipse. Up until quite recently I recall having a fair amount of trouble getting Eclipse to cooperate with compilers when I wanted to get back into programming. I believe I made a few attempts from 2010-2020. At the time I became quite frustrated that there wasn't “one way” to do things. I also think I would of had an easier time had I not been on a 5+ year old macbook and on a windows machine. As of quite recently I learned that Microsoft's Visual Studio offers a few different benefits, but the primary one is ease of getting started.

In my efforts to get back into C++ recently, I read through A Tour of C++. This text touts a bunch of great new modern features, and that all C++ developers should start using the new features whenever possible. One of the features that has my attention is “modules”. Someday, C++ programs will no longer need header files and they can use modules which allow faster compile time.

Frustrated by all the boilerplate involved with header files, I was eager to try making my own module or two and seeing if it was an improvement. I cracked open my linux laptop and stumbled around the internet for a bit to determine what I needed to do to actually implement a module. From what I mustered I needed a main.cpp file and the module could live in an .ixx file or .cppm file or .mpp file.

Quite a few different options...hm.

After much fiddling on my Linux laptop with both GNU Compiler, and Clang with various IDES including CLion, Eclipse, and CodeBlocks. I could not get a program using a module to compile. I tried various flags, configurations, etc. I did get cmake to build a project via the command line, but my knowledge of CMake is quite novice and I couldn't figure out where to go from there.

After snooping around the internet, I found other folks were able to use modules. They even claimed they could use them with GNU Compiler and Clang. I was, and to some extent, still am perplexed and skeptical of these claims. Further investigation will need done. However, I suspect they are using windows machines.

What I did find to work, quite easily and quite well, was to whip out my neglected Windows 11 machine and download Visual Studio. I had seen whisperings that the “MVSC” (Microsoft Visual Studio Compiler?) aligned with the latest C++ standards, so I figured I'd give it a shot.

After downloading and installing Visual Studio, I had no problem building a small proof of concept program that utilized modules. I put a basic print out “hello world” statement inside of a module and called the function from the main.cpp file.

I was flabbergasted. How had GCC and Clang not implemented this but Microsoft had? Does all modern C++ development take place on Windows? More research is required, but I just tried in XCode on my Mac, and once again I am met with errors such as “Unknown type name 'import'”.

This has me wondering, how can modern C++ proliferate if it is limited to one compiler and ecosystem? Perhaps that is all it needs, but I come from a world of linux machines running web applications. I guess my point is, I hope the other compilers will support more modern C++ practices soon.

Docker on Debian DVD Install

This will be a quick one on how to install docker on Debian 12.

What you will need: A machine with Debian installed (Virtual, or physical) an internet connection

In this example, I am using a physical machine. I would like to try deploying docker within a VM to spec it's performance but that is for another time.

I have a laptop I am putting this on, and connecting via SSH to execute the commands. I installed Debian with only the SSH server and standard system utilities features, with the DVD installer ISO file. I noticed some hiccups.

To connect to the machine, you will need it's IP address, you can find this by running ip addr ssh username@ipaddress where the username is the account you login to your debian instance with, and the ipaddress is the ip you captured when you ran ip addr

The first thing you will need to do is escalate to root to download and install packages, this can be done with the command su

I didn't have any luck installing the packages with apt or apt-get so I made a new directory with mkdir and downloaded the files with wget after cding into that directory. wget https://download.docker.com/linux/debian/dists/bookworm/pool/stable/amd64/containerd.io_1.7.20-1_amd64.deb https://download.docker.com/linux/debian/dists/bookworm/pool/stable/amd64/docker-ce_27.1.2-1~debian.12~bookworm_amd64.deb https://download.docker.com/linux/debian/dists/bookworm/pool/stable/amd64/docker-ce-cli_27.1.2-1~debian.12~bookworm_amd64.deb https://download.docker.com/linux/debian/dists/bookworm/pool/stable/amd64/docker-buildx-plugin_0.16.2-1~debian.12~bookworm_amd64.deb https://download.docker.com/linux/debian/dists/bookworm/pool/stable/amd64/docker-compose-plugin_2.29.1-1~debian.12~bookworm_amd64.deb

After this is finished, you can try to install with dpkg -i ./containerd.io1.7.20-1amd64.deb \ ./docker-ce27.1.2-1~debian.12~bookwormamd64.deb \ ./docker-ce-cli27.1.2-1~debian.12~bookwormamd64.deb \ ./docker-buildx-plugin0.16.2-1~debian.12~bookwormamd64.deb \ ./docker-compose-plugin2.29.1-1~debian.12~bookwormamd64.deb

However, I got an error about 'ldconfig' and 'start-stop-daemon' not found in my path so I needed to update my PATH variable with export PATH=$PATH:/usr/local/sbin:/usr/sbin:/sbin

If you also used the DVD iso installer, it will have the DVD in your sources.list. You can open this file and comment out a line. First open the file with nano nano /etc/apt/sources.list Then on the first line I found what needed commented out change deb cdrom:[Debian GNU/Linux 12.6.0 Bookworm – Official amd64 DVD Binary-1 with firmware 20240629-10:19]/ bookworm main

to

# deb cdrom:[Debian GNU/Linux 12.6.0 Bookworm – Official amd64 DVD Binary-1 with firmware 20240629-10:19]/ bookworm main

Add a hashtag before the line to comment it out, then save with ctrl-x.

Then run apt-get update and apt-get install -f

This will install any missing dependencies and you should be good to install docker now with dpkg -i ./containerd.io1.7.20-1amd64.deb \ ./docker-ce27.1.2-1~debian.12~bookwormamd64.deb \ ./docker-ce-cli27.1.2-1~debian.12~bookwormamd64.deb \ ./docker-buildx-plugin0.16.2-1~debian.12~bookwormamd64.deb \ ./docker-compose-plugin2.29.1-1~debian.12~bookwormamd64.deb

You should see no error messages and can then run service docker start and then a test docker run hello-world

You should see a Hello from Docker! message.

For more information on deploying docker images, please see the Docker website documentation.

Setting up a VM with QEMU on Windows 11

So QEMU has always intimidated me. I see posts on reddit recommending this product. I've always been intimidated by the documentation, maybe just the plethora of information and lack of the quick start have always made me turn away and use other solutions like VirtualBox or Hyper-V which are much more intuitive. If anyone from QEMU reads this, I think what you're doing is great but your docs need a quickstart/cliffnotes because there are plenty of blog posts like this one that try to explain the process, and (maybe) become dated when new versions are released.

Anyways, if you are new to Virtualization or Linux I'd recommend picking up VirtualBox and playing around with installing Ubuntu with a desktop environment. I used to use VirtualBox in a former role to build Windows images to deploy to end-users laptops, and while the performance wasn't always great, it got the job done and taught me a lot about networking, computers, and virtualization.

Onto the meat and potatoes. QEMU seems like a great solution, especially since it is all command line based. This makes it a great candidate to automate Virtual Machine (VM) deployment. Virtualbox also has command line interfaces, but reddit tells me QEMU is much more performant. This is my first rodeo, so time will tell.

What you'll need: Some hard drive space QEMU QEMU Windows Installer A Linux image, I'm using the debian DVD iso https://cdimage.debian.org/debian-cd/current/amd64/iso-dvd/

Once you download each of these, you'll want to verify the SHA-512 hash to ensure the authenticity of the download. On Windows Powershell you can use the command certutil -hashfile “.\path\to\downloaded\exe” SHA512

This will spit out a hash you can verify against the one provided by QEMU and Debian, the hash in the Powershell prompt should match the hash provided in the downloads directory on the site. If it doesn't, delete the download and try another download mirror until one matches. If the hash doesn't match, someone has injected a file into the download link and its probably malware, or at least not authentic.

Once you have both QEMU and a Linux ISO downloaded, you then need to install QEMU. In Windows, its a graphical installer and you can click through the prompts and let the install complete. Once completed you need to locate where it installed. On my machine I located it at C:\Program Files\qemu

You then need to add this to your path variable, to do this you need to go to the Windows Settings, and About. Or you can right click on This PC and go to properties. You'll see an “Advanced System Settings” option, click on that. A window will pop up with System Properties, and under the Advanced tab there is an Environment Variables option. Click on that and a new window will pop up with User Variables and System variables. Under each is a Path option. I selected System Variable's Path option and added C:\Program Files\qemu

As an option. You could add it to the User variables if a bunch of people use your machine and you only want it configured for your account. Anyways, click OK on all the windows to confirm the update, then close any open Powershell/terminal windows and reopen them. You then should be able to run qemu-system-x86_64 -help

And you should see some help information pop up. If you see an error message, then the path variable didn't save and you should try those steps again, or possibly rebooting your machine. In the event you can't get this to work, you can just execute the software directly from it's installation path C:\Program Files\qemu\qemu-system-x86_64.exe

I am using this binary because I am on an x86_64 machine, if you are using a different architecture on your host machine, then you should review the QEMU documentation and select the appropriate binary.

Once you have QEMU installed, its time to get onto building a VM!

If you just want to test that QEMU is working you can run something like qemu-system-x86_64 -boot d -cdrom \path\to\downloaded\linux\iso -m 2048

This boots a vm with 2048 bytes (2gig) of ram, with no hard disk attached. You can use this to see if the ISO loads and for things like a live USB install of ubuntu. For more info on commands see the qemu man page.

However, if you want a disk attached to the VM then we first need to create the disk, then include the disk in the command to launch the VM. To create a disk you can use a command like qemu-img create -f vdi debian_hd.vdi 50G

Where qemu-img creates the disk, -f is the format of the disk, here I am using the VDI format since I am familiar with virtual box, and I am alloting 50gigs of space for the virtual disk.

Once this is created, you then need to boot the VM with the ISO installer as a CD-ROM: qemu-system-x8664.exe -machine type=q35,accel=tcg -m 4096 -cpu qemu64 -smp 4 -drive file=C:\Users\bee\qemuvms\debian\debianhd.vdi,format=vdi,if=virtio -cdrom C:\Users\bee\qemuvms\debian\debian-12.6.0-amd64-DVD-1.iso -boot d -device virtio-net-pci,netdev=unet -netdev user,id=unet,hostfwd=tcp::2222-:22 -serial mon:stdio

This command should boot you to the ISO installer. The -machine flag sets it the type to q35 which is a PCI express-based machine, and accel is set to tcg which is Tiny Code Generator, a software based emulator. -m 4096 sets the ram to 4gigs. -cpu qemu64 is a generic processor to emulate provided by qemu. -smp 4 sets the machine to 4 use 4 cores. -drive is the location of the virtual hard drive we created, with a vdi format and using the virtio interface. -cdrom is the path to your linux iso file. -boot sets the device to boot to the cd-rom drive d. -device virtio-net-pci,netdev=unet sets a virtual network card. -netdev user,id-unet,hostfwd=tcp::2222-:22 forwards tcp traffic from port 2222 to the host port 22 on the virtual machine for SSH access. -serial mon:stdio redirects the virtual machines serial port to the input/output of the console so it can be accessed from the current terminal window.

Once you run this command, and all goes well you should see an installer. I am installing Debian, and I have never had luck with virtualization and setting disk encryption, so do not set that option. Go through the debian installer and disable the Desktop environment and GNOME and enable SSH server and standard system utilities. I left everything else as default. The Graphical installation will eventually complete and then you will need to run a new command to boot the machine without the CD-ROM so it boots to the hard disk qemu-system-x8664.exe -machine type=q35,accel=tcg -m 4096 -cpu qemu64 -smp 4 -drive file=C:\Users\bee\qemuvms\debian\debian_hd.vdi,format=vdi,if=virtio -boot order=c -device virtio-net-pci,netdev=unet -netdev user,id=unet,hostfwd=tcp::2222-:22 -serial mon:stdio

Upon running this, if all went well you will be greeted with a prompt to login and then you have your virtual machine! The next task is to set up a bridged network adapter so other machines on my network can access this machine, as this is certainly much more useful if you can ssh into it.

This post seems to provide some insight into how to set up a TAP adapter to enable this functionality: https://gist.github.com/arvati/546617042fcf2669f330b739075c1c5d

Requirements Domain Name VPS/VM

Optional Requirements Password Manager

The first step is locating a VPS, according to Forbes the top 3 VPS services are IONOS, GoDaddy, and DreamHost. I selected to use IONOS for my project. I chose their cheapest tier, as my blog doesn't get a ton of traffic. If you wanted to use technology that is a little more agile, you could look into Azure or Amazon LightSail. Most of these folks can also sell you a domain name as well, if you need to purchase one of those.

Once you have purchased a VPS and a domain name, you will need to connect to it to configure it. DigitalOcean has a good write up on connecting to a machine via SSH. Tools like PuTTy can be used if you are on a Windows machine.

Once you have connected you will need to create a user account, and disable the root login. This Baeldung article goes into reasoning as to why this should be disabled. Additionally, IBM has a great article on how you can set up RSA keys. Once you have tested and confirmed you can login with your key with the following command:

ssh -i /path/to/private/key user@host

To disable password login you can check your /etc/ssh/sshd_config file, there should be a PasswordAuthentication in that file, or one of its dependencies, that is set to yes and it needs to be set to no.

These commands are for Ubuntu:

$ adduser [username] $ usermod -aG sudo [username] $ passwd username

Before running this command, confirm you can login with the new username and run sudo commands, as this command will lock your root account. However, you may want to hold off on this command until after you are finished configuring WriteFreely, as file permissions between root and your user account can create a headache with automation.

$ sudo passwd -l root

Then set up sql db, I largely used this DigitalOcean article.

$ sudo apt install mysql-server $ sudo systemctl start mysql.service

Then you can open mysql, and set a password for the root account. I recommend using a password manager to keep track of passwords, KeePass, Keeper, and 1Password are great options.Additionally, I would create a service user for WriteFreely to use.

CREATE USER 'writefreely'@'localhost' IDENTIFIED BY 'password'; GRANT CREATE, ALTER, DROP, INSERT, UPDATE, INDEX, DELETE, SELECT, REFERENCES, RELOAD on . TO 'writefreely'@'localhost' WITH GRANT OPTION; COMMIT;

To get Write Freely to run on start up you need to create a service file: nano /etc/system/system/writefreely.service

[Unit] Description=Write Freely Instance After=syslog.target network.target

[Service] Type=simple StandardOutput=syslog StandardError=syslog WorkingDirectory=/var/www/[your.domain]/writefreely ExecStart=/var/www/[your.domain]/writefreely/writefreely Restart=always

[Install] WantedBy=multi-user.target

Then run: sudo systemctl enable writefreely.service sudo systemctl start writefreely.service

If you reboot the VPS, WriteFreely should start after a few minutes. If it does not then you need to make sure root owns both the WriteFreely Binary, and config.ini. You can do this by using the chown command. Additionally you may need to use the chmod command on the WriteFreely binary in order to execute it.

At this point, you should have a working WriteFreely instance. Next time, we’ll explore some ways to use Ansible to automate the process, and some backup solutions for the data.

Thanks for reading!

A few months ago I started working on a PythonOCR python version of this. However, it was slow and more importantly, it was a pain to install on other machines. My primary motivation for writing this software is because I am in graduate school, and we often have long PDF files that we need to read. My eyes aren't what they used to be and sometimes it's nice to be able to change or bold the font, along with the usual benefit of making it bigger that you get with zooming in.

The goal was to create a means to scrape the text from PDF's so I could put them into a text editor and adjust the colors, fonts, etc to be easier to read. As mentioned, the python version of this was able to convert a wide variety of PDFs since it used OpenCV and Tesseract to extract the text from an image file that was created from a page in the pdf. As you can imagine this operation is expensive and it would take a few minutes to process a fairly large pdf. More importantly, I use a few different laptops for school depending on which one wants to cooperate on the given day, so this needed to be portable. The python version required installing python, poppler, and tesseract. You also had to set environment variables.

I began looking for a better portable solution. Initially I began to look into C or possibly C++ as options, primarily since Tesseract is mostly in C++, but then I came across Rust and it seemed interesting, so I began learning more. After reading ”The Book”, going through a few rounds of Rustlings, and banging my head on the wall at a Leptos/Actix app attempt, I decided to go back to this project. This seemed like a great candidate for Rust and for me to learn more, but I needed to find a GUI framework to facilitate my build. For this project I ended up using slint. Which was a fairly enjoyable experience for this simple app. I haven't yet had to worry about converting the pdf's to images or integrating Tesseract.

This currently uses the pdf-extract crate to handle extraction, and rusty file dialog to handle cross platform file prompts. It uses the std::fs crate to write to the file system. In my testing across various environments, it is cross platform, though more particular about pdfs that its python incarnation. It seems to like PDFs where text has been particularly defined, I have not had luck with PDFs which have text that is an unselectable, such as within an image (where OCR would provide benefit). I can use this for now, and if OCR is needed, add that later, or bring out the python version. This rust version takes about 10 seconds to process a 500 page pdf. The python version took considerably longer, though I don't remember exactly, and can add benchmarks later if I build it again.

This app is a GUI, so once you download, run cargo run and it should present you with a window with an Open file button. Once you click that, you can select a file, then it will process the file. Once it's done, you'll be prompted again to save the output.

Here's the repo:

https://github.com/beedawn/spaghetti-pdf

Thanks for reading, and happy new year.

Bee