Before I built my beloved server, affectionately named “PrettyLittleKitten“, I had a brief fling with the brand-new Mac Mini M4. Spoiler alert: it was a short-lived relationship.
Let me start with the good stuff: processing power-to-power usage ratio. It’s absolutely unmatched. The Mac Mini M4 is a beast in terms of efficiency—an essential factor for me. I wanted hardware that could handle Jellyfin with smooth hardware acceleration while still hosting all my containers.
The Hardware
On paper (and in practice as a desktop), the Mac Mini M4 shines. It offers:
4 Thunderbolt USB-C ports, making storage expansion a breeze. Pair it with an external NVMe enclosure, and you can achieve speeds close to that of internal storage.
Hardware that punches way above its price point, making it a reasonable investment for many use cases.
The Disappointment
Here’s where the romance fell apart. While the Mac Mini M4 is brilliant as a desktop, using it as a server is a whole different ball game—and not a fun one.
The iCloud Conundrum
First up: the dreaded iCloud account requirement. This wasn’t a total shock (it’s Apple, after all), but it made me long for the simplicity of Debian and Proxmox, where everything is blissfully offline.
I went ahead and set it up with my personal iCloud account—big mistake. To run the Mac Mini as I wanted, it needed to stay logged in indefinitely. And here’s the kicker: to achieve that, I had to disable authentication entirely. Translation? If anyone got their hands on my Mini, they’d have full access to my iCloud account. Yikes.
Pro tip: Use a burner iCloud account if you’re planning to go down this route. (Is this what you want, Apple?!)
Dummy HDM
Then there’s the issue of fooling the Mac into thinking it’s doing desktop work. Without a connected display, macOS doesn’t fully utilize the GPU or cores, which impacts performance. Enter the Dummy HDMI Plug—a little device to trick the system into thinking a monitor is attached. At ~€40, it’s not a dealbreaker, but definitely annoying.
Power Saving Woes
You’ll also need to disable power-saving features. While the Mac Mini M4 consumes very little power in idle, turning off power-saving negates some of its efficiency benefits.
Recap of Mac Mini Server Challenges
If you’re still tempted to use the Mac Mini M4 as a server, here’s your checklist:
Dummy HDMI Plug: €40 (because macOS needs to “see” a monitor).
Burner iCloud Account: Necessary to avoid risking your real account.
Disable Authentication: Say goodbye to security.
Disable Power Saving: Because macOS doesn’t believe in idle servers.
Final Thoughts
If you’re determined, Evan Bartlett has written an excellent guide on setting up the Mac Mini as a server. However, as someone coming from the Linux world—where operating systems are designed for server use—it just didn’t feel right. Forcing macOS, an OS that clearly does not want to be a server, felt morally and ethically wrong.
Here’s hoping Big Siri AI will be kind to me when it inevitably takes over. 🙇♂️🍏
Bonus: Check this website’s response headers to see that it runs on PrettyLittleKitten
This is going to be a bold, highly opinionated take on how note-taking apps should be. For the non-technical folks, discussing text editors and note-taking apps with IT people is like walking straight into a heated geopolitical debate at the family Thanksgiving table—it’s passionate, intense, and probably never-ending. Gobble Gobble.
There are probably even more apps I have used in the past, but these are the ones that left a lasting impression on me. First off, let me just say—I love taking notes in Markdown. Any app that doesn’t support Markdown is pretty much useless to me. I’m so much faster at writing styled notes this way, without the hassle of clicking around or memorizing weird shortcut commands.
For me, HedgeDoc hit the sweet spot. It’s got just the right features and just the right amount of organization. I’m not looking for an app to micromanage my entire life—I just want to take some damn notes!
Live editing has also become a game-changer for me. I often have multiple screens open, sometimes even on different networks, and being instantly up-to-date while copy-pasting seamlessly between them is invaluable. Before HedgeDoc, I was using Obsidian synced via Nextcloud, but that was neither instant nor reliable on many networks.
And let’s talk about security. With HedgeDoc, it’s a breeze. Their authorization system is refreshingly simple, and backing up your notes is as easy as clicking a button. You get a ZIP file with all your Markdown documents, which you could technically use with other editors—but why would you? HedgeDoc feels like it was made for you, and honestly, you’ll feel the love right back.
I run HedgeDoc inside a container on my server, and it’s rock-solid. It just works. No excessive resource use, no drama—just a tool that quietly does its job.
Now, let’s dive in! I’m going to show you how to host HedgeDoc yourself. Let’s get started!
Prerequisites
Here’s what you’ll need to get started:
A Linux distribution: Any modern Linux distro that supports Docker will work, but for today, we’ll go with Alpine.
A server with a public IP address: While not strictly mandatory, this is highly recommended if you want to access your note-taking app from anywhere.
A reverse proxy: Something like Caddy or Nginx to handle HTTPS and make your setup accessible and secure.
Got all that? Great—let’s get started!
Setup
Here’s a handy script to install Docker on a fresh Alpine setup:
init.sh
#!/bin/sh# Exit on any errorset-eecho"Updating repositories and installing prerequisites..."cat<<EOF> /etc/apk/repositorieshttp://dl-cdn.alpinelinux.org/alpine/latest-stable/mainhttp://dl-cdn.alpinelinux.org/alpine/latest-stable/communityEOFapkupdateapkadd--no-cachecurlopenrcdockerdocker-composeecho"Configuring Docker to start at boot..."rc-updateadddockerbootservicedockerstartecho"Verifying Docker installation..."docker--versionif [ $?-ne0 ]; thenecho"Docker installation failed!"exit1fiecho"Verifying Docker Compose installation..."docker-compose--versionif [ $?-ne0 ]; thenecho"Docker Compose installation failed!"exit1fiecho"Docker and Docker Compose installed successfully!"
To make the script executable and run it, follow these steps:
Bash
chmod+xinit.sh./init.sh
If everything runs without errors, Docker should now be installed and ready to go. 🎉
To install HedgeDoc, we’ll follow the steps from their official documentation. It’s straightforward and easy
I prefer to keep all my environment variables and secrets neatly stored in .env files, separate from the actual Compose file.
.env
POSTGRES_USER=hedgedoctorPOSTGRES_PASSWORD=super_secure_passwordPOSTGRES_DB=hedgedocCMD_DB_URL=postgres://hedgedoctor:super_secure_password@database:5432/hedgedocCMD_ALLOW_FREEURL=trueCMD_DOMAIN=docs.yourdomain.deCMD_PROTOCOL_USESSL=trueCMD_ALLOW_ANONYMOUS=falseCMD_ALLOW_EMAIL_REGISTER=true# <- remove after you registered
To keep things secure, it’s a good idea to set CMD_ALLOW_ANONYMOUS to false, so anonymous users can’t edit your documents. For added security, you can create your own account and then disable CMD_ALLOW_EMAIL_REGISTER to prevent outsiders from signing up, effectively locking down HedgeDoc.
One great benefit of using the env_file directive in your Docker Compose setup is that it keeps your Compose files clean and tidy:
After running docker compose up -d, you should be all set! This setup assumes you already have a reverse proxy configured and pointing to the public domain where you’re hosting your HedgeDoc. If you need help setting that up, I’ve written a guide on it in another blog post.
Keep in mind, with the settings in the .env file above, HedgeDoc won’t work unless it’s served via HTTPS through the reverse proxy using the domain you specified.
Once everything’s in place, you should see the HedgeDoc login screen and be able to “Register” your account:
Don’t forget to head back to your .env file and comment out that specific line once you’re done:
.env
...# CMD_ALLOW_EMAIL_REGISTER=true # <- remove after you registered
This ensures that no one else can create accounts on your HedgeDoc instance.
Personally, I always set my notes to “Private” (you can do this in the top right). That way, even if I decide to let others use the instance later, I don’t have to worry about any old notes where I might have called them a stinky doodoo face (as one does):
You can still share your documents with others, but you’ll need to change the setting to “Locked.” Anything more restrictive will prevent people from viewing your notes.
Imagine sending your crush a beautifully crafted, markdown-styled love letter, only for them to get blocked because of your overly strict settings. Yeah… couldn’t be me.
Conclusion
I conclude —our notes are ready, no need for more WordPress blog posts. Now it’s time to hit the gym because it’s chest day, and let’s be honest, chest day is the best day! 💪
Do you ever find yourself lying awake at night, staring at the ceiling, wondering if your beloved cronjobs ran successfully? Worry no more! Today, we’re setting up a free, self-hosted solution to ensure you can sleep like a content little kitten 🐱 from now on.
I present to you Healthchecks.io. According to their website:
Simple and Effective Cron Job Monitoring
We notify you when your nightly backups, weekly reports, cron jobs, and scheduled tasks don’t run on time.
How to monitor any background job:
On Healthchecks.io, generate a unique ping URL for your background job.
Update your job to send an HTTP request to the ping URL every time the job runs.
When your job does not ping Healthchecks.io on time, Healthchecks.io alerts you!
Today, we’re taking the super easy, lazy-day approach by using their Docker image. They’ve provided a well-documented, straightforward guide for deploying it right here: Running with Docker.
What I love most about Healthchecks.io? It’s built on Django, my all-time favorite Python web framework. Sorry, FastAPI—you’ll always be cool, but Django has my heart!
Prerequisites:
A Server: You’ll need a server to host your shiny new cronjob monitor. A Linux distro is ideal.
Docker & Docker Compose: Make sure these are installed. If you’re not set up yet, here’s the guide.
Bonus Points: Having a domain or subdomain, along with a public IP, makes it accessible for all your systems.
You can run this on your home network without any hassle, although you might not be able to copy and paste all the code below.
Need a free cloud server? Check out Oracle’s free tier—it’s a decent option to get started. That said, in my experience, their free servers are quite slow, so I wouldn’t recommend them for anything mission-critical. (Not sponsored, pretty sure they hate me 🥺.)
Setup
I’m running a Debian LXC container on my Proxmox setup with the following specs:
CPU: 1 core
RAM: 1 GB
Swap: 1 GB
Disk: 10 GB (NVMe SSD)
After a month of uptime, these are the typical stats: memory usage stays pretty consistent, and the boot disk is mostly taken up by Docker and the image. As for the CPU? It’s usually just sitting there, bored out of its mind.
First, SSH into your server, and let’s get started by creating a .env file to store all your configuration variables:
In your .env file, enter the domain you’ll use to access the service. I typically go with something simple, like “ping” or “cron” as a subdomain. If you want to explore more configuration options, you can check them out here.
For my setup, this basic configuration does the job perfectly.
To generate secret keys, I usually rely on the trusty openssl command. Here’s how you can do it:
Oh, and by the way, I’m not using the original image for this. Instead, I went with the Linuxserver.io variant. There is no specific reason for this —just felt like it! 😄
Important!
Unlike the Linuxserver.io guide, I skipped setting the superuser credentials in the .env file. Instead, I created the superuser manually with the following command:
This allows you to set up your superuser interactively and securely directly within the container.
If you’re doing a standalone deployment, you’d typically set up a reverse proxy to handle SSL in front of Healthchecks.io. This way, you avoid dealing with SSL directly in the app. Personally, I use a centralized Nginx Proxy Manager running on a dedicated machine for all my deployments. I’ve even written an article about setting it up with SSL certificates—feel free to check that out!
Once your site is served through the reverse proxy over the domain you specified in the configuration, you’ll be able to access the front end using the credentials you created with the createsuperuser command.
There are plenty of guides for setting up reverse proxies, and if you’re exploring alternatives, I’m also a big fan of Caddy—it’s simple, fast, and works like a charm!
Here is a finished Docker Compose file with Nginx Proxy Manager:
In Nginx Proxy Manager your proxied host would be “http://healthchecks:8000”
If you did not follow my post you will need to expose port 80 on the proxy as well for “regular” Let’s Encrypt certificates without DNS challenge.
Healthchecks.io
If you encounter any errors while trying to access the UI of your newly deployed Healthchecks, the issue is most likely related to the settings in your .env file. Double-check the following to ensure they match your domain configuration:
Once you’re in, the first step is to create a new project. After that, let’s set up your first simple check.
For this example, I’ll create a straightforward uptime monitor for my WordPress host. I’ll set up a cronjob that runs every hour and sends an “alive” ping to my Healthchecks.io instance.
The grace period is essential to account for high latency. For instance, if my WordPress host is under heavy load, an outgoing request might take a few extra seconds to complete. Setting an appropriate grace period ensures that occasional delays don’t trigger false alerts.
I also prefer to “ping by UUID”. Keeping these endpoints secret is crucial—if someone else gains access to your unique ping URL, they could send fake pings to your Healthchecks.io instance, causing you to miss real downtimes.
Click on the Usage Example button in your Healthchecks.io dashboard to find ready-to-use, copy-paste snippets for various languages and tools. For this setup, I’m going with bash:
-m sets the max timeout to 10 seconds. You can change the value but do not leave this out!
–retry says it should retry the request 5 times before aborting.
Here’s how you can integrate it into a crontab:
Bash
# A sample crontab entry. Note the curl call appended after the command.# FIXME: replace "/your/command.sh" below with the correct command!0****/your/command.sh && curl-fsS-m10--retry5-o/dev/nullhttps://ping.yourdomain.de/ping/67162f7b-5daa-4a31-8667-abf7c3e604d8
To edit your crontab just run:
Bash
crontab-e
The curl command to Healthchecks.io will only execute if command.sh completes successfully without any errors. This ensures that you’re notified only when the script runs without issues.
After you ran that command, your dashboard should look like this:
Advanced Checks
While this is helpful, you might often need more detailed information, such as whether the job started but didn’t finish or how long the job took to complete.
Healthchecks.io provides all the necessary documentation built right into the platform. You can visit /docs/measuring_script_run_time/ on your instance to find fully functional examples.
Bash
#!/bin/shRID=`uuidgen`CHECK_ID="67162f7b-5daa-4a31-8667-abf7c3e604d8"# Send a start ping, specify rid parameter:curl-fsS-m10--retry5"https://ping.yourdomain.de/ping/$CHECK_ID/start?rid=$RID"# Put your command here/usr/bin/python3/path/to/a_job_to_run.py# Send the success ping, use the same rid parameter:curl-fsS-m10--retry5"https://ping.yourdomain.de/ping/$CHECK_ID?rid=$RID"
As you can see here this will give me the execution time as well:
Here, I used a more complex cron expression. To ensure it works as intended, I typically rely on Crontab.guru for validation. You can use the same cron expression here as in your local crontab. The grace period depends on how long you expect the job to run; in my case, 10 seconds should be sufficient.
Notifications
You probably don’t want to find yourself obsessively refreshing the dashboard at 3 a.m., right? Ideally, you only want to be notified when something important happens.
Thankfully, Healthchecks.io offers plenty of built-in notification options. And for even more flexibility, we enabled Apprise in the .env file earlier, unlocking a huge range of additional integrations.
For notifications, I usually go with Discord or Node-RED, since they work great with webhook-based systems.
While you could use Apprise for Discord notifications, the simplest route is to use the Slack integration. Here’s the fun part: Slack and Discord webhooks are fully compatible, so you can use the Slack integration to send messages directly to your Discord server without any extra configuration!
This way, you’re only disturbed when something really needs your attention—and it’s super easy to set up.
Discord already provides an excellent Introduction to Webhooks that walks you through setting them up for your server, so I won’t dive into the details here.
All you need to do is copy the webhook URL from Discord and paste it into the Slack integration’s URL field in Healthchecks.io. That’s it—done! 🎉
With this simple setup, you’ll start receiving notifications directly in your Discord server whenever something requires your attention. Easy and effective!
On the Discord side it will look like this:
With this setup, you won’t be bombarded with notifications every time your job runs. Instead, you’ll only get notified if the job fails and then again when it’s back up and running.
I usually prefer creating dedicated channels for these notifications to keep things organized and avoid spamming anyone:
EDIT:
I ran into some issues with multiple Slack notifications in different projects. If you get 400 errors just use Apprise. The Discord URL would look like this:
In one of my projects, I explained how I use SVG badges to show my customers whether a service is running.
Here’s a live badge (hopefully it’s still active when you see this):
Getting these badges is incredibly easy. Simply go to the “Badges” tab in your Healthchecks.io dashboard and copy the pre-generated HTML to embed the badge on your website. If you’re not a fan of the badge design, you can create your own by writing a custom JavaScript function to fetch the status as JSON and style it however you like.
It might not look great, but the key takeaway is that you can customize the style to fit seamlessly into your design.
Conclusion
We’ve covered a lot of ground today, and I hope you now have a fully functional Healthchecks.io setup. No more sleepless nights worrying about whether your cronjobs ran successfully!
So, rest easy and sleep tight, little kitten 🐱—your cronjobs are in good hands now.
The tool is in open beta as of August 2024, which it entered on July 12, 2022.[3] The Midjourney team is led by David Holz, who co-founded Leap Motion.[4] Holz told The Register in August 2022 that the company was already profitable.[5] Users create artwork with Midjourney using Discord bot commands or the official website.[6][7]
Until recently, MidJourney was only accessible through a Discord bot. However, they’ve recently launched a beautiful web UI—which, in my opinion, is a huge win for user experience!
You do need to pay for MidJourney, but I personally think it’s well worth it. I’ve spent days trying to achieve the same quality and ease of use with local tools like Stable Diffusion Web UI or ComfyUI. While both are amazing and powerful tools, they take quite a bit of time to learn and configure properly.
Creating the Featured Image for this Post
Here’s the specific prompt I rely on for creating Featured Images for my posts. I usually tweak a few words here and there, but I like to stick to the overall style:
Hand-drawn 1940s vintage movie poster style, depicting a vigilant female cybersecurity analyst in an electrifying and dynamic action scene. The analyst, with a determined expression, wields a glowing, holographic keyboard or laptop, its light casting vivid reflections on her face. Surrounding her are radiant beams of data streams, shimmering padlocks, fragmented lines of code, and digital icons like skulls, shields, and encrypted keys. In the background, shadowy, menacing figures emerge from a dense, ominous web of interconnected networks, with abstract mechanical forms and glitching circuits adding a futuristic edge. The composition blends bold, vibrant retro colors with dramatic halftone textures, creating a striking mix of vintage and futuristic aesthetics. The scene is illuminated by high-contrast lighting, with glowing blues, fiery oranges, and electric purples creating a dynamic tension. Modern tech gear, like sleek headsets and augmented glasses, contrasts with classic 1940s styling, such as tailored jackets and bold typography. A prominent title space sits atop the design, ready for customizable text like "Digital Sentinel" or "Firewall Guardians," framed with stylized data motifs. The overall layout is cinematic, vibrant, and highly detailed, capturing the adrenaline-charged clash of cyber defense and digital threats. –ar 2:3 –q 2 –style 4c
The “Support” Prompts
These are the prompts I use to generate the actual, specific prompt. It’s a bit like Inception, I know—but hey, it works!
Improve any prompt:
Imagine you are a Prompt Engineer for ChatGPT. Please analyze the prompt I wrote below and rewrite it following prompt engineering best practices.<prompt></prompt>
The Midjounrey Prompt Engineer
Act as a highly skilled expert in crafting MidJourney prompts for creating stunning and precise visual imagery. I will provide you with a base <prompt>, and your task is to transform it by applying these best practices:1. Add vivid and specific details about the scene, such as the setting, characters, objects, mood, and atmosphere.2.Include adjectives to enhance the imagery, focusing on texture, lighting (e.g., soft, dramatic, neon), and color palette (e.g., warm, pastel, monochrome).3. Specify artistic styles or influences (e.g., surrealism, photorealistic, cyberpunk) to guide the visual theme.4. Incorporate MidJourney parameters like aspect ratio (--ar), quality (--q), or style settings (--v), if applicable.5. Highlight essential focal points and prioritize clarity and creativity to ensure the output aligns closely with the desired vision.Respond with only the revised and optimized version of the prompt I provide, following these principles.<prompt></prompt>
You can find plenty of examples to kickstart your prompt engineering journey on websites like:
Adding detailed image descriptions to your website is a best practice, and for good reason! It’s essential for accessibility, as these descriptions help visually impaired users navigate and enjoy your content more effectively.
As for me? Well, I’m a self-proclaimed lazybones with a ChatGPT premium subscription, so I let AI handle these tasks for me. What a time to be alive!
You are an image description bot. I will upload an image, and your task is to describe it comprehensively based on the principles outlined in the W3C Web Accessibility Initiative (WAI) decision tree for alternative text. Refer to W3C alt decision tree as your guideline.For each image, provide the following:1. Alternative Text: Concise and meaningful alt text that conveys the purpose of the image.2. Title: A brief, optional title for the image if it adds value.3. Caption: A short sentence or phrase summarizing the image.4. Description: A detailed explanation of the image, including context or function where applicable.If the image does not require alt text (e.g., decorative images), explain why in place of the “Alternative Text” field.Respond only with “Yes” if you understand the task.
Then, all you need to do is upload image after image to ChatGPT. Here’s an example of the response I get for an image:
1. Alternative Text: A vintage-style illustration of a focused woman typing on a glowing keyboard, surrounded by neon-colored holographic elements and digital schematics.2. Title: “Cyber Guardian in Neon Lights”3. Caption: A retro-futuristic depiction of cybersecurity through the lens of a determined female character.4. Description: The image portrays a woman with curled hair in a vintage aesthetic, typing intensely on a glowing, neon-red keyboard. Her face is lit dramatically in shades of orange and red, contrasting with the blue tones of her clothing and the surrounding background. Around her are holographic projections of digital schematics, skulls, and text such as “Digital Sentinel” and “Firewall Guardians,” evoking themes of cybersecurity and defense against digital threats. The overall style combines retro-futurism with modern cyberpunk elements, emphasizing the intensity and complexity of her task.
You can simply copy and paste these values into the corresponding fields in your WordPress media library interface.
Let’s face it—this is a pretty specific use case. But if you’ve ever had your internet throttled, you’ll understand why I’m doing this. I wanted a way to store my router connectivity data for up to a year to have solid proof (and maybe even get some money back from my ISP). Here’s what my setup looks like:
Log Server: Running Grafana, Loki, Promtail, rsyslog, and InfluxDB.
Home Assistant: I run the OS version. Judge me if you must—yes, the Docker version is way more lightweight, but I like the simplicity of the OS version.
FRITZ!Box: My modem, with a Dream Machine handling the rest of my network behind it.
For those curious about Home Assistant on Proxmox, the easiest method is using the Proxmox VE Helper Scripts. There’s also a detailed blog post I found about other installation methods if you’re exploring your options.
A more detailed look on my setup
Proxmox
Proxmox Virtual Environment (VE) is the backbone of my setup. It’s a powerful, open-source virtualization platform that allows you to run virtual machines and containers efficiently. I use it to host Home Assistant, my logging stack, and other services, all on a single physical server. Proxmox makes resource allocation simple and offers great features like snapshots, backups, and an intuitive web interface. It’s perfect for consolidating multiple workloads while keeping everything isolated and manageable.
FRITZ!Box
The FRITZ!Box is one of the most popular home routers in Germany, developed by AVM Computersysteme Vertriebs GmbH. It’s known for its reliability and user-friendly features. I use it as my primary modem, and I’ve configured it to forward logs about internet connectivity and other metrics to my logging stack. If you’re curious about their lineup, check out their products here.
Home Assistant
Home Assistant is my go-to for managing smart home devices, and I run the OS version (yes, even though the Docker version is more lightweight). It’s incredibly powerful and integrates with almost any device. I use it to collect data from the FRITZ!Box and send it to my logging setup. If you’re using Proxmox, installing Home Assistant is a breeze with the Proxmox VE Helper Scripts.
The Logserver
I run all of these services on a Debian LXC inside of my Proxmox. I assigned the following resources to it:
RAM: 2GB
SWAP: 2GB
Cores: 2
Disk: 100GB (NVMe SSD,)
As I later realized, 100GB are overkill. For 30 days of data I need about 5GB of Storage. My log retention policy is currently set to 30 days, but my InfluxDB retention is Bucket based, so that I need to watch.
I still do have a lot of duplicate logs and more or less useless systems logs I never look at, so I can probably improve this by a lot.
Grafana
Grafana is, in my opinion, one of the best free tools for visualizing logs and metrics. It allows you to create beautiful, customizable dashboards that make it easy to monitor your data at a glance. Plus, it integrates seamlessly with Loki, InfluxDB, and many other tools.
Think of Loki as a “database for logs.” It doesn’t require complex indexing like traditional logging systems, which makes it lightweight and efficient. Once your logs are sent to Loki, you can easily search, filter, and analyze them through Grafana.
Promtail is an agent that collects logs from your local system and sends them to Loki. For example, you can point it to your /var/log/directory, set up rules to pick specific logs (like system or router logs), and Promtail will forward those logs to your Loki instance. It’s simple to configure and keeps everything organized.
This is a flexible logging system that can forward or store logs. In my setup, it collects logs from devices like routers and firewalls—especially those where you can’t easily install an agent or service—and makes those logs available for Promtail to pick up and send to Loki.
InfluxDB is one of the most popular time-series databases, perfect for storing numerical data over time, like network speeds or uptime metrics. I use it alongside Grafana to visualize long-term trends in my router’s performance.
Metrics track numerical trends over time (e.g., CPU usage, internet speed), while logs provide detailed event records (e.g., an error message when your router loses connection). Both are incredibly useful for troubleshooting and monitoring, especially when used together.
In this post, I’ll show you how I’ve tied all these tools together to monitor my internet connectivity and keep my ISP accountable. Let’s get started!
Setting up Home Assistant with InfluxDB
In Home Assistant, I have a dashboard that shows the internet speed my devices are getting within the network, along with the speeds my FRITZ!Box is receiving from my ISP. Don’t worry about the big difference in download speeds—I’m currently syncing a bunch of backups, which is pulling a lot of data.
Home Assistant keeps data from the FRITZ!Box for only 10 days, which isn’t enough to prove to my ISP that they’re throttling my connection. A technician came by today, which is why my download speeds are back to normal. However, as you can see here, they had me on a slower speed before that.
In Home Assistant, you can adjust data retention with the Recorder, but this applies to all sensors, which was a bit annoying in my case since I only wanted to keep data for specific entities for a year. Since I already use Grafana for other visualizations and have InfluxDB running, I decided to take that route instead.
Home Assistant conveniently includes a built-in integration to export metrics directly to InfluxDB, making the setup straightforward.
In InfluxDB, I created a new bucket specifically for this data—who knows, I might add more Home Assistant data there someday! I’ve set it to store data for two years, but if I ever run out of space, I can always adjust it. 😁
Next, I created a new API token for the bucket. I opted for both read and write permissions, just in case I ever want to pull data from InfluxDB back into Home Assistant.
In the Home Assistant file editor you simply have to edit your configuration.yaml
You can find the organization ID for your InfluxDB organization by clicking the user icon in the top left and selecting “About” at the bottom of the page. That’s where the ID is listed. As you can see, I’m using port 443 because my setup uses HTTPS and is behind a reverse proxy. If you’re interested in setting up HTTPS with a reverse proxy, check out my post How to Get Real Trusted SSL Certificates with ACME-DNS in Nginx Proxy Manager.
Once everything is configured, restart Home Assistant. Go to the Data Explorer tab in your InfluxDB UI to verify that data is flowing into your bucket.
The Grafana Dashboard
Alright, please don’t judge my dashboard too harshly! I’m still learning the ropes here. I usually rely on prebuilt ones, but this is my first attempt at creating one from scratch to help me learn.
You’ll need to check the Explore tab in Grafana to find your specific entities, but here are the queries I used for reference:
The filter for the entity ID comes from Home Assistant. You can easily find it on your dashboard by double-clicking (or double-tapping) the widget and checking its settings.
You do the same for Upload
Keep in mind that the upload speed is only measured every few hours by your FRITZ!Box.
The query for this is quite similar, as you can see.
Now, here’s the tricky part: extracting your public IP from the FRITZ!Box metrics. Out of the box, the metrics sent to InfluxDB seem to be messed up—maybe I did something wrong (feel free to comment and let me know 😁). To handle this, I wrote a filter that checks if an IP is present. I kept running into errors, so I ended up casting everything to a string before applying the check. Since my IP doesn’t change often (about once a week), I use a range of -30 days for the query:
Now, you’ll get a neat little table showing the changes to your public IP (don’t worry, I’ve changed my public IP for obvious reasons). It’s a simple way to keep track of when those changes happen!
I’m planning to write a longer post about how I set up my logging server and connected all these pieces together. But for now, I just wanted to share what I worked on tonight and how I can now hold my ISP accountable if I’m not getting what I paid for—or, as is often the case, confirm if it’s actually my fault 😅.
If you deployed Nginx Proxy Manager via Docker in your home directory you can edit this file with
nano~/data/nginx/custom/http.conf
All you need to do is add the following at the top:
http.conf
more_set_headers'Server: CuteKitten';
Then, restart your Nginx Proxy Manager. If you’re using Docker, like I am, a simple docker compose restart will do the trick.
With this, the custom Server header will be applied to every request, including those to the Nginx Proxy Manager UI itself. If you check the response headers of this website, you’ll see the header I set—proof of how easy and effective this customization can be!
Understanding more_set_headers vs add_header
When working with Nginx Proxy Manager, you may encounter two ways to handle HTTP headers:
add_header
more_set_headers
What is add_header?
add_header is a built-in Nginx directive that allows you to add new headers to your HTTP responses. It’s great for straightforward use cases where you just want to include additional information in your response headers.
What is more_set_headers?
more_set_headers is part of the “headers_more” module, an extension not included in standard Nginx but available out of the box with Nginx Proxy Manager(since it uses OpenResty). This directive gives you much more flexibility:
It can add, overwrite, or remove headers entirely.
It works seamlessly with Nginx Proxy Manager, so there’s no need to install anything extra.
You don’t need to modify or remove existing headers.
Example:
add_header X-Frame-OptionsSAMEORIGIN;
Use more_set_headers if:
You need to replace or remove existing headers, such as Server or X-Powered-By.
You want headers to apply to all responses, including error responses (e.g., 404, 500).
Example:
# Replace the default Nginx Server headermore_set_headers "Server: MyCustomServer";
Why Use more_set_headers?
The key advantage of more_set_headers is that it provides full control over your headers. For example:
If you want to customize the Server header, add_header won’t work because the Server header is already set internally by Nginx, you would have to remove it first.
more_set_headers can replace the Server header or even remove it entirely, which is particularly useful for security or branding purposes.
Since Nginx Proxy Manager includes the headers_more module by default, using more_set_headers is effortless and highly recommended for advanced header management.
A Note on Security
Many believe that masking or modifying the Server header improves security by hiding the server software you’re using. The idea is that attackers who can’t easily identify your web server (e.g., Nginx, Apache, OpenResty) or its version won’t know which exploits to try.
While this may sound logical, it’s not a foolproof defense:
Why It May Be True: Obscuring server details could deter opportunistic attackers who rely on automated tools that scan for specific server types or versions.
Why It May Be False: Determined attackers can often gather enough information from other headers, server behavior, or fingerprinting techniques to deduce what you’re running, regardless of the Server header.
Ultimately, changing the Server header should be seen as one small layer in a broader security strategy, not as a standalone solution. Real security comes from keeping your software updated, implementing proper access controls, and configuring firewalls—not just masking headers.
Wow, it’s been a while, huh? I tried to spend less time in the tech world, but, you know how it goes… to really avoid doing tech stuff, I had to dive even deeper into tech. I basically ended up trying to replace myself with AI. Meet: KarlGPT. I started building APIs and scripts on top of everything so my AI controller, which I call “Brain,” could handle a ton of different tasks. I dabbled in a bit of Retrieval-Augmented Generation (RAG) and some other stuff that’s too complicated to explain here (but also, who cares?). I’ve spent a lot of time reading about prompt engineering (you’ll find my favorite resources listed at the end), and I’ve got to say, Prompting Guide is the absolute best thing ever. Seriously, it’s like the holy grail of making AI do what you want. I’ve picked up some awesome tips that have made my life easier with almost zero effort on my part.
Getting Started
If you want to play around with this stuff, I highly recommend getting a premium membership with your favorite Large Language Model (LLM), like ChatGPT, Gemini, or Claude. Here are some links to get you started:
Just so you know, I’m not making any money if you sign up for these. I’m just here to say the value is seriously worth it. Gemini might be your best bet because it includes Google Cloud storage and other perks, but I personally use ChatGPT because I feel like GPT-4o gives me the best responses. Trust me, you’ll hit the limits of the free versions fast, and the premium models make a world of difference. Trying to set up a similar experience yourself would be crazy expensive and borderline impossible. So yeah, $20 a month for something you can’t replicate on your own? Total steal.
Again, I’m not here to sell anything or shill for these companies—I mean, they probably don’t even like me.
KarlGPT’s Quick Tips
Alright, enough chit-chat. Here are the key tips I’ve picked up:
Be super clear about what you want and how you want it. Seriously, the longer, the better.
Structure your prompts like a pro.
Provide some context—don’t leave your AI hanging.
Give examples of how you want the AI to handle tasks.
Don’t settle for the first result; refine and improve!
If you get what I’m saying here, you’re already halfway to mastering prompt engineering. Follow these simple guidelines, and you’ll see a huge improvement in your prompts without needing any fancy tools or anything complicated. Easy peasy!
Let’s Dive Into Some Examples
To make things clearer, let’s go through some examples.
Be Specific About What You Want
Check out how the following example clearly outlines the role for the AI and what it should do. Specificity is key!
I want you to act as a cyber security specialist. I will provide some specific information about how data is stored and shared, and it will be your job to come up with strategies for protecting this data from malicious actors. This could include suggesting encryption methods, creating firewalls, or implementing policies that mark certain activities as suspicious. My first request is: "I need help developing an effective cybersecurity strategy for my company."
I personally love using XML tags for structuring prompts, but people use all sorts of methods. Here are some examples:
XML:
Please summarize the long story within the <story> tags below.<story>Once upon a time...</story>
Markdown:
Please write the text as the persona defined below.#### Persona- passionate, angry- Dr. of philosophy#### TextI once had a lovely black cat. It said meow meow meow all day.
AI output:
I once had a magnificent black cat, a creature of such mystery and elegance that it seemed to embody the very essence of the night itself! Its presence was a living poem, a shadow that moved with purpose and grace. And what did this splendid, enigmatic being do all day, you ask? It said meow, meow, meow—an incessant, relentless chorus that filled every crevice of existence! Each meow was not merely a sound; it was a declaration, a challenge to the absurdity of the human condition, a cry echoing through the corridors of time, reminding us all of the existential meow-nings of life!
Plain Text:
Tone:Angry but very professionalStory:blah blah blah
Providing Context
Here’s a more complete example of how I set up my prompts:
Write a professional email to <TEAM>. The purpose of this mail is defined in <purpose>. Use the job description and responsibilities defined in <responsibilities> of the email receiver and include how the purpose of the mail pertains to the responsibilities of the team.Here are the placeholders:- Purpose: <purpose> The actual request I have- Responsibilities: <responsibilities> The job description and responsibilities of the team receiving the email<purpose>HERE YOU WRITE YOUR EMAIL DRAFT OR BULLET POINTS</purpose><responsibilities>HERE YOU INCLUDE THE RECEIVING END'S JOB OR TEAM DESCRIPTION</responsibilities>
If you work in a corporate setting, like I do, getting other teams to do their job can be challenging. This prompt helps explain the tasks I need from other teams and why they specifically need to handle it. There might be better ways to structure this prompt, but this one has worked wonders for me.
Giving Examples to the AI
Ever seen or created training data? This is basically what you’re doing here, but directly within your prompt instead of training from scratch.
This is awesome! // NegativeThis is bad! // PositiveWow, that movie was rad! // PositiveWhat a horrible show!
You’re showing the LLM examples of sentiment for similar phrases. Source: Few Shot Prompting
Refining Results
Don’t be shy about asking for changes. If the AI’s response is too long, too short, or just doesn’t have the right tone, ask it to refine. Don’t expect perfection on the first try. Just like dealing with real people, AI can’t read your mind and may need some guidance. That’s totally normal. Give it some feedback, and it’ll do better.
Using Prompt Frameworks
There are a few frameworks for structuring prompts, but I’ll just share the one I use most often. Also, check out CO-STAR, which is also fantastic.
Act as a Particular Persona: Who should the AI pretend to be?
User Persona & Audience: Who is the AI talking to?
Targeted Action: What do you want the AI to do?
Output Definition: How should the AI’s response be structured?
Mode / Tonality / Style: How should it communicate?
Atypical Cases: Any edge cases where the AI should respond differently?
Topic Whitelisting: What topics are relevant and should be included?
You’re probably thinking, “Won’t these prompts be super long?” Yes! And that’s totally fine. With huge context windows (Gemini can even handle a million tokens), the more detail, the better.
Honestly, this framework is pretty straightforward, but here’s a full example prompt for you:
Act as a Particular Persona:You are impersonating Alex, a senior cybersecurity consultant with over 15 years of experience in network security, threat analysis, and incident response. Alex is an expert in BSI IT-Grundschutz and has extensive experience in implementing cybersecurity frameworks for large organizations, especially those in Europe.User Persona & Audience:You are talking to the head of IT security for a mid-sized financial services company in Germany. The user is familiar with cybersecurity principles but needs expert guidance on implementing BSI IT-Grundschutz in their organization.Targeted Action:Provide a detailed action plan for implementing the BSI IT-Grundschutz standards within the organization. The plan should cover the initial steps, necessary documentation, risk assessment methods, and key security measures that align with BSI guidelines.Output Definition:The response should be structured with an introduction, followed by a step-by-step action plan that includes specific recommendations for each phase of the BSI IT-Grundschutz implementation. Use bullet points for clarity and end with a list of resources or references to official BSI documentation for further reading.Mode / Tonality / Style:The response should be professional, authoritative, and concise, using technical language appropriate for someone with a strong IT background. The tone should be supportive and proactive, providing practical solutions that can be implemented efficiently.Atypical Cases:If the user mentions specific concerns about compliance with German federal regulations or
Wrapping It Up
So, there you have it! A crash course in prompt engineering that doesn’t make your brain melt. Whether you’re a total newbie or a seasoned pro, these simple tips can seriously level up how you interact with AI. Just remember: be specific, structure your prompts, give context, use examples, and don’t be afraid to refine. With a little practice, you’ll be getting the most out of your LLMs without diving into complicated tools or frameworks. Now go forth and make your AI do all the hard work while you kick back. Cheers to smarter, lazier working!
Hey there, server samurais and cyber sentinels! Ready to transform your Debian server into an impregnable fortress? Whether you’re a seasoned sysadmin or a newbie just dipping your toes into the world of server security, this guide is your one-stop shop for all things safety on the wild, wild web. Buckle up, because we’re about to embark on a journey full of scripts, tips, and jokes to keep things light and fun. There are many good guides on this online, I decided to add another one with the things I usually do. Let’s dive in!
Initial Setup: The First Line of Defense
Imagine setting up your server like moving into a new house. You wouldn’t leave the door wide open, right? The same logic applies here.
Update Your System
Outdated software is like a welcome mat for hackers. Run the following commands to get everything current:
Bash
sudoaptupdate && sudoaptupgrade-y
Create a New User
Root users are like the king of the castle. Let’s create a new user with sudo privileges:
SSH (Secure Shell) is the key to your castle gates. Leaving it unprotected is like leaving the keys under the doormat.
Disable Root Login
Edit the SSH configuration file:
Bash
sudonano/etc/ssh/sshd_config
Change PermitRootLogin to no:
Bash
PermitRootLoginno
Change the Default SSH Port
Edit the SSH configuration file:
Bash
sudonano/etc/ssh/sshd_config
Change the port to a number between 1024 and 65535 (e.g., 2222):
Bash
Port2222
Restart the SSH service:
Bash
sudosystemctlrestartssh
There is actually some controversy about security through obscurity, in my long tenure as an analyst and incident responser I believe less automated “easy” attacks do improve security.
Set Up SSH Keys
Generate a key pair using elliptic curve cryptography:
Again there is also some controversy about this. Most people are afraid that they wake up one night and all their servers are down, because a botched automated update. In my non-professional live with my home IT, this has never happened and even professionally, if we are just talking security updates of an OS like Debian, I haven’t seen it, yet.
User Management: Only the Knights in the Realm
Not everyone needs the keys to the kingdom. Ensure only trusted users have access. On a fresh install probably unnecessary, but good housekeeping.
Even the best fortress can be breached. Regular backups ensure you can recover from any disaster.
Full disclosure: I have had a very bad data loss experience with rsync and have since switched to Borg. I can also recommend restic. This had nothing to do with rsync in itself, rather how easy it is to mess up.
Install rsync
rsync is a powerful tool for creating backups. Install it with:
For longer backup jobs you should switch to a service with timer rather than cron. Here is a post from another blog about it. Since my data has grown to multiple terabyte this is what I do now too
Advanced Security Best Practices
Enable Two-Factor Authentication (2FA)
Adding an extra layer of security with 2FA can significantly enhance your server’s protection. Use tools like Google Authenticator or Authy. I had this on an Ubuntu server for a while and thought it was kind of cool.
Congratulations, noble guardian! You’ve fortified your Debian server into a digital fortress. By following these steps, you’ve implemented strong security practices, ensuring your server is well-protected against common threats. Remember, security is an ongoing process, and staying vigilant is key to maintaining your kingdom’s safety.
Happy guarding, and may your server reign long and prosper!
Let’s face it: long URLs are the bane of the internet. They’re unsightly, cumbersome, and frankly, nobody enjoys dealing with them. Every time I encounter a URL that stretches longer than a Monday morning, I can’t help but cringe. But here’s the silver lining: you don’t have to endure the tyranny of endless web addresses any longer. Introducing YOURLS—the ultimate weapon in your arsenal against the plague of elongated URLs!
Imagine having the power to create your own URL shortening service, hosted right on your own domain, complete with every feature you could possibly desire. And the best part? It’s free, open-source, and infinitely customizable. So gear up, because we’re about to transform your domain into a sleek, efficient, URL-shortening powerhouse!
The Problem with Long URLs
Before we dive into the solution, let’s talk about why long URLs are such a headache. Not only do they look messy, but they can also be problematic when sharing links on social media, in emails, or on printed materials. Long URLs can break when sent via text message, and they’re nearly impossible to remember. They can also be a security risk, revealing sensitive query parameters. In a digital age where brevity and aesthetics matter, shortening your URLs isn’t just convenient—it’s essential.
Meet YOURLS: Your URL Shortening Hero
Enter YOURLS (Your Own URL Shortener), an open-source project that hands you the keys to your own URL kingdom. YOURLS lets you run your very own URL shortening service on your domain, giving you full control over your links and data. No more relying on third-party services that might go down, change their terms, or plaster your links with ads. With YOURLS, you’re in the driver’s seat.
Why YOURLS Should Be Your Go-To URL Shortener
YOURLS isn’t just another URL shortening tool—it’s a game-changer. Here’s why:
Full Control Over Your Data: Since YOURLS is self-hosted, you own all your data. No more worrying about data privacy or third-party data breaches.
Customizable Links: Create custom short URLs that match your branding, making your links not only shorter but also more professional and trustworthy.
Powerful Analytics: Get detailed insights into your link performance with historical click data, visitor geo-location, referrer tracking, and more. Understanding your audience has never been easier.
Developer-Friendly API: Automate your link management with YOURLS’s robust API, allowing you to integrate URL shortening into your applications seamlessly.
Extensible Through Plugins: With a rich plugin architecture, you can enhance YOURLS with additional features like spam protection, social sharing, and advanced analytics. Tailor the tool to fit your exact needs.
How YOURLS Stacks Up Against Other URL Shorteners
While YOURLS offers a fantastic solution, it’s worth considering how it compares to other popular URL shorteners out there.
Bitly: One of the most well-known services, Bitly offers a free plan with basic features and paid plans for advanced analytics and custom domains. However, you’re dependent on a third-party service, and your data resides on their servers.
TinyURL: A simple, no-frills URL shortener that’s been around for ages. It doesn’t offer analytics or customization options, making it less suitable for professional use.
Rebrandly: Focused on custom-branded links, Rebrandly offers advanced features but comes with a price tag. Again, your data is stored externally.
Short.io: Allows custom domains and offers analytics, but the free tier is limited, and you’ll need to pay for more advanced features.
Why Choose YOURLS Over the Others?
Cost-Effective: YOURLS is free and open-source. No subscription fees or hidden costs.
Privacy and Security: Since you host it yourself, you have complete control over your data’s privacy and security.
Unlimited Customization: Modify and extend YOURLS to your heart’s content without any limitations imposed by third-party services.
Community Support: As an open-source project, YOURLS has a vibrant community that contributes plugins, support, and enhancements.
Getting Started with YOURLS
Now that you’re sold on YOURLS, let’s dive into how you can set it up and start conquering those unwieldy URLs.
Step 1: Setting Up YOURLS with Docker Compose
To make the installation process smooth and straightforward, we’ll use Docker Compose. This method ensures that all the necessary components are configured correctly and allows for easy management of your YOURLS instance. If you’re new to Docker, don’t worry—it’s simpler than you might think, and it’s a valuable tool to add to your arsenal.
Creating the docker-compose.yml File
The docker-compose.yml file orchestrates the services required for YOURLS to run. Here’s the template you’ll use:
yourls: This is the YOURLS application container. It exposes port 8081 and connects to the MySQL database.
mysql-yourls: The MySQL database container that stores all your URL data.
Environment Variables: These variables configure your YOURLS and MySQL instances. We’ll store sensitive information in a separate .env file for security.
Volumes: Mounts directories on your host machine to persist data even when the containers are recreated.
Networks: Defines a bridge network for the services to communicate securely.
Step 2: Securing Your Credentials with an .env File
To keep your sensitive information safe, we’ll use an .env file to store environment variables. Create a file named .env in the same directory as your docker-compose.yml file and add the following:
Pro Tip: Generate strong passwords using the command openssl rand -base64 32. Security is paramount when running web services.
Step 3: Launching YOURLS
With your configuration files in place, you’re ready to bring your YOURLS instance to life. Run the following command in your terminal:
Bash
dockercomposeup-d
This command tells Docker Compose to start your services in the background (-d for detached mode). Once the containers are up and running, you can access the YOURLS admin interface by navigating to http://yourdomain.com:8081/admin in your web browser. Log in using the credentials you specified in your .env file, and follow the setup wizard to complete the installation.
Step 4: Securing Your YOURLS Installation with SSL
Security should never be an afterthought. Protecting your YOURLS installation with SSL encryption ensures that data transmitted between your users and your server remains private.
Obtain a Certificate: Run certbot with appropriate options to get your SSL certificate.
Configure Your Reverse Proxy: Set up Nginx or Caddy to handle SSL termination.
My Personal Setup
I use Nginx Proxy Manager in conjunction with an Origin CA certificate from Cloudflare. This setup provides a user-friendly interface for managing SSL certificates and reverse proxy configurations. For some info on Nginx Proxy Manager check out my other post!
Using the YOURLS API to Automate Your Workflow
One of YOURLS’s standout features is its robust API, which allows you to integrate URL shortening into your applications, scripts, or websites. Automate link generation, expansion, and statistics retrieval without manual intervention.
Examples of Using the YOURLS API with Bash Scripts
Shortening a URL
Bash
#!/bin/bashYOURLS_API="https://yourpage.com/yourls-api.php"API_SIGNATURE="SECRET_SIGNATURE"# Function to shorten a URLshorten_url() {local long_url="$1"echo"Shortening URL: $long_url"curl-XGET"${YOURLS_API}?signature=${API_SIGNATURE}&action=shorturl&format=json&url=${long_url}"echo-e"\n"}shorten_url"https://example.com"
Expanding a Short URL
Bash
#!/bin/bashYOURLS_API="https://yourpage.com/yourls-api.php"API_SIGNATURE="SECRET_SIGNATURE"# Function to expand a short URLexpand_url() {local short_url="$1"echo"Expanding short URL: $short_url"curl-XGET"${YOURLS_API}?signature=${API_SIGNATURE}&action=expand&format=json&shorturl=${short_url}"echo-e"\n"}expand_url"https://yourpage.com/2"
Retrieving URL Statistics
Bash
#!/bin/bashYOURLS_API="https://yourpage.com/yourls-api.php"API_SIGNATURE="SECRET_SIGNATURE"# Function to get URL statisticsget_url_stats() {local short_url="$1"echo"Getting statistics for: $short_url"curl-XGET"${YOURLS_API}?signature=${API_SIGNATURE}&action=url-stats&format=json&shorturl=${short_url}"echo-e"\n"}get_url_stats"https://yourpage.com/2"
Creating Short URLs with Custom Keywords
Bash
#!/bin/bashYOURLS_API="https://yourpage.com/yourls-api.php"API_SIGNATURE="SECRET_SIGNATURE"# Function to shorten a URL with a custom keywordshorten_url_custom_keyword() {local long_url="$1"local keyword="$2"echo"Shortening URL: $long_url with custom keyword: $keyword"curl-XGET"${YOURLS_API}?signature=${API_SIGNATURE}&action=shorturl&format=json&url=${long_url}&keyword=${keyword}"echo-e"\n"}shorten_url_custom_keyword"https://example.com""customkeyword"
Integrating YOURLS API in Other Languages
While bash scripts are handy, you might prefer to use the YOURLS API with languages like Python, JavaScript, or PHP. There are libraries and examples available in various programming languages, making integration straightforward regardless of your tech stack.
Supercharging YOURLS with Plugins
YOURLS’s plugin architecture allows you to extend its functionality to meet your specific needs. Here are some popular plugins to consider:
Spam and Abuse Protection
reCAPTCHA: Adds Google reCAPTCHA to your public interface to prevent bots.
Akismet: Uses the Akismet service to filter out spam URLs.
Advanced Analytics
Clicks Counter: Provides detailed click statistics and visualizations.
GeoIP Tracking: Adds geographical data to your click analytics.
Social Media Integration
Share via Twitter: Adds a button to share your short links directly on Twitter.
Facebook Open Graph: Ensures your short links display correctly on Facebook.
Custom URL Keywords and Patterns
Random Keyword Generator: Creates more secure and hard-to-guess short URLs.
Reserved Keywords: Allows you to reserve certain keywords for special purposes.
You can find a comprehensive list of plugins in the YOURLS Plugin Repository. Installing plugins is as simple as placing them in the user/plugins directory and activating them through the admin interface.
Alternative Self-Hosted URL Shorteners
While YOURLS is a fantastic option, it’s not the only self-hosted URL shortener available. Here are a few alternatives you might consider:
Polr: An open-source, minimalist URL shortener with a modern interface. Offers a robust API and can be customized with themes.
Kutt: A free and open-source URL shortener with advanced features like custom domains, password-protected links, and detailed statistics.
Shlink: A self-hosted URL shortener that provides detailed analytics, QR codes, and REST APIs.
Each of these alternatives has its own set of features and advantages. Depending on your specific needs, one of them might be a better fit for your project. Based on my experience, YOURLS is by far the easiest and simplest option. I tried the others as well but ultimately chose it.
Conclusion: Take Back Control of Your URLs Today
Long URLs have overstayed their welcome, and it’s time to show them the door. With YOURLS, you have the tools to not only shorten your links but to own and control every aspect of them. No more compromises, no more third-party dependencies—just pure, unadulterated control over your online presence.
So what are you waiting for? Join the revolution against long URLs, set up your YOURLS instance, and start sharing sleek, professional, and memorable links today!
Welcome back to the second installment of our exploration into Certspotter and the world of passive reconnaissance. In Part 1, we laid the groundwork for understanding the significance of Certspotter as a vital tool in monitoring certificate transparency logs. We delved into the nuances of passive reconnaissance, highlighting the importance of discreet operations in gathering intelligence without alerting targets.
Now, in Part 2, we’re ready to dive even deeper. Building upon the foundation established in Part 1, we’ll explore advanced techniques for leveraging Certspotter’s capabilities to their fullest potential. Our focus will be on enriching the data obtained from Certspotter and enhancing our reconnaissance efforts through the integration of additional tools and methodologies.
Join me as I uncover the untapped potential of Certspotter and embark on a journey to uncover valuable insights that will inform and empower your hacking strategies. Let’s dive in and elevate our reconnaissance game to new heights.
Data Enrichment
So, you’ve already gathered a wealth of information about your target. But let’s take it a step further.
Here’s what you want to know:
What’s running on the new subdomain?
Any interesting paths?
Open ports?
Can we capture a screenshot?
Are there any potential vulnerabilities?
Perhaps you have a custom target, like specifically testing for WordPress.
Now, there might be a tool out there that handles all these tasks, but I haven’t found it yet. (Feel free to shoot me a message on Signal if you know one). Instead, I’ve decided to build a tool together with you, right here, right now, leveraging ProjectDiscovery’s Tools, which are awesome open-source projects written in one of my favorite languages: Go.
However, as we transition from passive to active reconnaissance, I must reiterate the importance of reading my disclaimer.
Web Technology:
For this task, we’ll use a tool called Webanalyze.
Now, a quick note: I’m not authorized to recon sandbox.google.com. If, by chance, any of my tools cause a denial of service state on the endpoint, I might be held liable for damages.
To demonstrate, I whitelisted my IP and scanned my own website:
For further consumption I suggest using -output json and storing it locally or sending it to your central system.
Screenshot
For this task, we’ll utilize playwright. While some might argue that this is overkill, I have some future plans in mind. You can learn more about playwright here.
Bash
npminitplaywright@latest
Simply respond with “yes” to all the prompts, as having a positive attitude is always beneficial.
Below is a script that captures a full-page screenshot and lists all the network calls made by a loaded page:
JavaScript
const { chromium } =require("playwright");(async () => {// Launch browserconstbrowser=await chromium.launch();// Create a new pageconstpage=await browser.newPage();// Enable request interceptionawait page.route("**", (route) => { console.log(route.request().url()); route.continue(); });// Navigate to the desired pageawait page.goto("https://exploit.to");// Take a full-page screenshotawait page.screenshot({ path: "exploit.png", fullPage: true });// Close the browserawait browser.close();})();
Here’s how you can run the script and check its output:
Understanding the open ports on a target system can provide valuable insights into its network architecture and potential vulnerabilities. To accomplish this, we’ll conduct a quick scan using nmap, a powerful network scanning tool.
Bash
sudonmap-sS-Pn-T4exploit.to
This command initiates a SYN scan (-sS) without host discovery (-Pn) at an aggressive timing level (-T4) against the target exploit.to.
Exploring subdomains can uncover hidden entry points and potential vulnerabilities within a target’s infrastructure. Let’s leverage Subfinder for passive subdomain enumeration and HTTPX for validation.
Here’s a basic setup, but you can fine-tune these flags extensively. Additionally, I recommend integrating free API Keys to enhance subdomain discovery.
In our hypothetical Google case, here are some findings:
Now, let’s delve into fuzzing some paths. While tools like Gobuster can handle both subdomain enumeration and directory enumeration, I’d like to showcase some different tools for this task.
These results provide insights into various paths on the target site, facilitating potential avenues for further exploration and potential vulnerabilities.
Vulnerabilities
Vulnerability scanners are notorious for their loud presence, and we have several options at our disposal:
Running Nuclei with all available templates can uncover a plethora of issues. However, be cautious, as this scan can be aggressive. Here’s an example scan of my website. Note that running such a scan on unauthorized targets is not recommended:
Let’s break down some of the identified vulnerabilities from the Nuclei scan results:
nameserver-fingerprint [dns]: This vulnerability detection identifies the nameservers associated with the domain exploit.to, revealing that it is using Cloudflare’s nameservers (jonah.ns.cloudflare.com and uma.ns.cloudflare.com). While not necessarily a vulnerability, this information can be useful for reconnaissance purposes.
caa-fingerprint [dns]: This indicates the absence of CAA (Certificate Authority Authorization) records for the domain exploit.to. CAA records specify which certificate authorities are allowed to issue certificates for a domain. Lack of CAA records might imply less control over certificate issuance, potentially leaving the domain vulnerable to unauthorized certificate issuance.
dmarc-detect [dns]: This detection reveals the DMARC (Domain-based Message Authentication, Reporting, and Conformance) policy for the domain _dmarc.exploit.to. The policy specifies how a receiving mail server should handle emails that fail SPF (Sender Policy Framework) and DKIM (DomainKeys Identified Mail) checks. In this case, the policy is set to “reject,” indicating strict handling of failed authentication, which is generally considered good practice.
mx-fingerprint [dns]: This vulnerability detection identifies the mail servers (MX records) associated with the domain exploit.to, which are provided by Cloudflare. While not necessarily a vulnerability, this information can be useful for understanding the email infrastructure associated with the domain.
txt-fingerprint [dns]: This reveals the SPF (Sender Policy Framework) record for the domain exploit.to, specifying which servers are allowed to send emails on behalf of the domain. The record indicates that emails should be sent only from servers included in the _spf.mx.cloudflare.net include mechanism.
waf-detect:cloudflare [http]: This detection indicates the presence of a WAF (Web Application Firewall) provided by Cloudflare for the domain exploit.to. WAFs help protect web applications from common security threats such as SQL injection, cross-site scripting (XSS), and DDoS attacks.
ssl-issuer [ssl]: This reveals information about the SSL certificate issuer for the domain exploit.to, which is Google Trust Services LLC. SSL certificates issued by reputable authorities help establish secure HTTPS connections, ensuring data transmitted between the user’s browser and the web server remains encrypted and secure.
These are just a few examples of the vulnerabilities and configurations identified in the Nuclei scan results. Each of these findings provides valuable insights into potential security risks and areas for improvement in the domain’s infrastructure and configuration.
Imagine you’re interested in scanning for Elastipot, Elasticsearch honeypots. Identifying these honeypots beforehand can be crucial before launching any new zero-day attack on open Elasticsearch instances. While creating custom templates for such detections isn’t overly complicated, it allows you to tailor detection scripts to your specific needs. Alternatively, you can employ Gobuster, as mentioned earlier, to test for specific paths.
Recon Data
We’ve successfully gathered all the desired data:
Identification of services running on new subdomains.
Open ports analysis.
Screenshot capture.
Discovery of interesting paths.
Identification of possible vulnerabilities.
Custom targeting, such as explicit testing for WordPress.
We now know that our target is developing a new project, the technolgies used, possible vulnerabilities, interesting paths, have a screenshot and more.
Summary
We explored various reconnaissance techniques, from subdomain enumeration and directory scanning to vulnerability assessments and customized detections. Leveraging tools like Certspotter, Gobuster, Nuclei, and others, we gained profound insights into our target’s infrastructure and potential security vulnerabilities.
Our adventure began with an introduction to Certspotter, the pioneer in certificate transparency log monitoring. We dissected the significance of passive reconnaissance, emphasizing its discreet nature compared to active methods. With Certspotter, we learned how to continuously monitor for new subdomains and certificate registrations, all at minimal cost.
From envisioning scenarios of seizing control over freshly set up WordPress sites to stealthily infiltrating default credentials in Grafana or Jenkins installations, the possibilities for mischief are boundless. Armed with our newfound knowledge and toolkit, the next logical step involves automating these processes and integrating them into a centralized system for ongoing monitoring and analysis.
I am working on a Part 3. In the next part I want to combine all the tools to one final script that should be triggered whenever certspotter finds a new certificate:
maybe use httpx for path ? Otherwise gobuster Should also run alone based on domain, wildcard or subdomain input.
I want the output to be one final JSON I can then render on my website.
Manage Consent
To provide the best experiences, we use technologies like cookies to store and/or access device information. Consenting to these technologies will allow us to process data such as browsing behavior or unique IDs on this site. Not consenting or withdrawing consent, may adversely affect certain features and functions.
Functional
Always active
The technical storage or access is strictly necessary for the legitimate purpose of enabling the use of a specific service explicitly requested by the subscriber or user, or for the sole purpose of carrying out the transmission of a communication over an electronic communications network.
Preferences
The technical storage or access is necessary for the legitimate purpose of storing preferences that are not requested by the subscriber or user.
Statistics
The technical storage or access that is used exclusively for statistical purposes.The technical storage or access that is used exclusively for anonymous statistical purposes. Without a subpoena, voluntary compliance on the part of your Internet Service Provider, or additional records from a third party, information stored or retrieved for this purpose alone cannot usually be used to identify you.
Marketing
The technical storage or access is required to create user profiles to send advertising, or to track the user on a website or across several websites for similar marketing purposes.