Khurram

Dell OptiPlex 5060 Batocera Build: PS3 & Xbox 360 Emulation – Part 1: The Project

Part 1: The Project, The Hardware and Why I Chose the OptiPlex 5060 Can an old Dell OptiPlex 5060 SFF be turned into a serious retro gaming PC capable of going well beyond the usual emulation systems and into PlayStation 3 and Xbox 360? That’s what I’m hoping to find out. I’ve been wanting to build a proper retro gaming machine for a while. I’m an avid gamer and have built up a pretty good collection of retro technology over the years, so this isn’t my first attempt at creating a dedicated retro gaming system. However, this time I wanted to do something a little different. Rather than buying a brand-new gaming PC and spending hundreds of pounds on components, I wanted to see how far I could push hardware I already had sitting around my office and homelab. The result is this project: turning a Dell OptiPlex 5060 Small Form Factor into a dedicated Batocera retro gaming machine. And there is one more important part of the plan. I’ve already picked up an MSI GeForce RTX 3050 Low Profile to go into it. That GPU could completely change what this little OptiPlex is capable of. Before getting it installed, though, I wanted to establish exactly what the machine could do on integrated graphics alone. A Note on Games and ROMs Before going any further, a quick note on something that comes up with any article like this. Every title covered across this series is one I own — a mix of games from my own physical collection, built up over years, and digital purchases. I’m not going to get into the specifics of ROM or ISO acquisition anywhere in this series; if you’re following along and building something similar, dumping your own discs is the approach I’d point you toward. What Is This Project About? The idea behind this project is quite simple: Take hardware I already own, upgrade it where necessary and build the best retro gaming machine I can without spending a fortune. I’m not trying to build the most powerful gaming PC possible. I’m also not interested in simply buying the latest hardware and putting it into a case. The challenge is making something useful from what I already have. The OptiPlex 5060 is a particularly interesting starting point because it is a business desktop rather than a gaming machine. It’s compact, relatively inexpensive and has a Small Form Factor (SFF) chassis. That immediately introduces some limitations. There isn’t a huge amount of room inside the case, cooling is more restricted than on a conventional desktop and the original SFF configuration was designed around a modest power supply. Dell’s specifications list a 200 W PSU for the OptiPlex 5060 SFF; I’ve upgraded my particular machine to a 240 W PSU as part of this project. Those limitations make the project considerably more interesting. I’m essentially trying to turn an office PC into a console-sized emulation machine. My Previous Retro Gaming Projects This isn’t my first attempt at building a retro gaming system. I’ve previously built a RetroPie system using a Raspberry Pi 4, which I installed inside a NESPi 4 case. The NESPi 4 is a fantastic little case for creating something that looks and feels much more like a traditional games console. I also used a removable SSD, which made managing the system and game collection much easier. However, the Raspberry Pi 4 has its limits. It’s an excellent platform for older systems and lightweight emulation, but once you start pushing towards more demanding consoles, the hardware becomes the limiting factor. I’ve also spent some time with inexpensive handheld devices such as the R36 Ultra and TrimUI Smart Pro. These have been great little devices and are perfect for portable retro gaming. But again, you’re ultimately restricted by the hardware inside the device. That’s what makes this project different. With the OptiPlex, I have considerably more CPU performance, more storage options, desktop-class hardware and, importantly, the possibility of adding a dedicated graphics card. Why the Dell OptiPlex 5060? The OptiPlex 5060 wasn’t purchased specifically for this project. That’s actually one of the things I like about it. It was already hardware I had available, and I started looking at whether it could be repurposed as a serious emulation machine. The SFF chassis is particularly attractive for a retro gaming PC. Dell’s specifications put the SFF chassis at approximately 29.0 × 9.26 × 29.2 cm, so it has a relatively small footprint compared with a conventional desktop PC. The motherboard also provides a half-height PCIe slot for a discrete GPU — which, as I’ll get into in Part 3, turned out to come with some interesting limitations of its own once I actually tried to fit a card in it. The small footprint means the finished machine should be easy to tuck underneath a TV or monitor without looking like a traditional desktop gaming PC. The downside is that I’m going to have to work within some fairly strict hardware limitations. Every component has to be considered carefully. The Starting Hardware The machine originally came with an Intel Core i5 processor, but one of the first things I decided to change was the CPU. I’ve now upgraded it to an Intel Core i7-8700. The system also has 16 GB of RAM, a 512 GB Samsung NVMe drive and a 4 TB Seagate IronWolf that I had available as secondary storage. I’ve also upgraded the power supply from the original 200 W configuration to a 240 W PSU. Current Specification Component Specification System Dell OptiPlex 5060 SFF Operating System Batocera Linux Architecture x86_64 CPU Intel Core i7-8700 CPU Cores 6 CPU Threads 12 Maximum Frequency 4.6 GHz Memory 16 GB Primary Storage 512 GB Samsung NVMe Secondary Storage 4 TB Seagate IronWolf Power Supply 240 W Graphics Intel UHD Graphics 630 – currently Additional Cooling Front exhaust fan Controllers GameSir Cyclone 2 / EasySMX D05 Future GPU MSI RTX 3050 Low Profile Batocera currently reports the

Dell OptiPlex 5060 Batocera Build: PS3 & Xbox 360 Emulation – Part 1: The Project Read More »

Building a Paper-Trading Bot, Part 3: A Live Dashboard on Apache

This is Part 3 of a 3-part series. Part 1 tells the story of building this bot and what went wrong along the way. Part 2 is the step-by-step setup and full working code for the bot itself — read that first if you don’t have the base project running yet, since this post builds directly on top of it. By the end of Part 2, the bot is trading and logging every trade and daily equity snapshot to CSV files. That’s fine if you’re comfortable reading raw CSVs over SSH, but it gets old fast. This post adds a proper dashboard: a self-updating web page showing your strategy’s performance against simple buy-and-hold, served over Apache on the same Linux box the bot is already running on. What we’re building No server-side app, no database — Apache just serves whatever static HTML file was most recently generated. Simple to set up, simple to reason about, nothing to keep running besides the bot itself. Prerequisites Step 1: A console report script (optional but useful) Before building the HTML version, here’s a simpler console-only report script — useful for a quick check over SSH without needing a browser at all: Save this as report.py in your project directory. Run it anytime: It prints your total return, a buy-and-hold comparison, max drawdown, recent trades, and saves a matplotlib chart (equity_curve_ACN.png) you can pull off the server if you want a quick visual without setting up the full dashboard. Step 2: The HTML dashboard generator This is the main piece — a script that builds a complete, self-contained HTML report from your log files. It’s a long file because the HTML/CSS/JavaScript for the chart is embedded directly in the Python script as a template, which keeps the whole dashboard to a single generated file with no separate assets to manage. Save this as generate_html_report.py. A few things worth understanding about what it does: Generate your first report: This creates a web/ACN/index.html file inside your project directory. Open it locally first (copy it to your own machine, or just cat it) to confirm it looks right before wiring up Apache. Step 3: Point Apache at the report The simplest approach is an Apache Alias, which maps a URL path directly to your project’s web/ folder without needing to copy files into /var/www/html or mess with permissions there. Create a new Apache config file: Replace YOUR_USERNAME with your actual Linux username. Then enable the config and reload Apache: Visit http://your-server-ip/tradingbot/ACN/ in a browser — you should see the dashboard. If you get a 403 Forbidden error This is the most common snag, and it’s almost always permissions. Apache runs as the www-data user, and it needs traversal permission on every directory in the path to your file — not just the final folder. Home directories are often locked down by default, which blocks www-data even though the Apache config itself is correct. Check the whole permission chain: If any directory in that list is missing execute (x) permission for “others,” grant just enough to allow traversal — not full access: This only allows Apache to pass through those directories to reach the specific file — it doesn’t let it list or read anything else inside them. Step 4: Keep the report fresh with cron Right now the dashboard only shows whatever was true the moment you ran the generator script. Set up a cron job to regenerate it automatically: Add a line to regenerate the report every 15 minutes (matching the bot’s default polling interval): Two details that matter here: Step 5: Running more than one symbol If you’re paper-trading multiple symbols (see Part 2 for running two main.py instances at once), generate a report per symbol into its own subfolder: With the Apache Alias from Step 3, these become reachable at /tradingbot/ACN/ and /tradingbot/SPY/ respectively. Add a second cron line for the second symbol, same pattern as Step 4. A note on security This setup has no authentication — anyone who can reach the URL can see your (paper) trading performance. That’s a reasonable trade-off on a private home network, but not something to expose directly to the public internet. If you need external access, put it behind a reverse proxy with basic auth, or at minimum restrict by IP address directly in the Apache config: Replace the example IP range with whatever network you actually trust. Wrapping up the series That’s the full build: a modular trading bot with a tested strategy and real risk management (Part 2), built on the lessons from actually running it and hitting real bugs (Part 1), now with a live dashboard to watch it work (this post). The whole project — bot, backtester, and dashboard — is maybe 1,500 lines of Python, and every part of it earned its place by something that broke during actual use, not by anticipating problems in advance. That’s probably the biggest lesson of the whole series: build the smallest version that works, run it for real, and let what actually breaks tell you what to build next.

Building a Paper-Trading Bot, Part 3: A Live Dashboard on Apache Read More »

Building a Paper-Trading Bot, Part 2: Full Setup and Code on Linux

This is Part 2 of a 3-part series. Part 1 is the story of what went wrong and what I learned building this — worth reading first for context. This post is the step-by-step build: Linux setup and the complete working code. Part 3 covers adding a live performance dashboard served over Apache. This is a complete walkthrough for building a paper-trading bot in Python using the Alpaca API, running on a Linux server. By the end you’ll have a bot that pulls market data, generates buy/sell signals from a trend-following strategy, manages risk with a volatility-scaled stop-loss, executes paper trades automatically, and logs everything for review. Everything below is real, working code — this is the actual project I run in production (well, paper-production) on my own Ubuntu server. What you’ll end up with Prerequisites Step 1: Get free Alpaca paper trading API keys Paper trading uses simulated money against real market data, so you can test everything safely before ever considering real funds. Step 2: Set up the project directory and virtual environment That last command activates the virtual environment — you should see (venv) appear at the start of your terminal prompt. You’ll need to run source venv/bin/activate again every time you open a new terminal session to work on this project; it only applies to the current shell. Step 3: Install dependencies Create a requirements.txt file: Then install: Step 4: Store your API keys securely Create a .env file in the project root: Replace the placeholders with the keys from Step 1. Never commit this file to version control — if you’re using git, add .env to your .gitignore. Step 5: Build the project, file by file Here’s the full project structure we’re building: config.py — central settings Everything the rest of the project needs is configured here: API keys, strategy parameters, and risk settings. A few of the defaults worth understanding before you change them: data_feed.py — pulling market data This wraps Alpaca’s data API so the rest of the code doesn’t need to know the API details. strategy.py — the actual trading logic This is the heart of the bot: turning price data into a BUY, SELL, or HOLD decision. A quick note on the design here, since it’s easy to get subtly wrong: signals are evaluated as a current state (is the short average above the long average right now, and does ADX confirm a trend right now) rather than only firing on the exact bar a crossover happens. An earlier version of this logic only fired on the crossing bar itself — which sounds equivalent but isn’t: if ADX takes a few days to confirm a trend after the crossover already happened, an event-based check misses the entry entirely, since the “crossing” moment has already passed by the time confirmation arrives. Checking the state fresh on every bar avoids that. risk.py — position sizing and stop-loss The stop-loss uses ATR (Average True Range) instead of a flat percentage. Here’s why that matters: a flat 2% stop sounds reasonable until you apply it to a volatile stock — a 2% intraday swing can be completely normal noise for a volatile name, so a flat stop just gets you shaken out repeatedly by nothing. Scaling the stop to each symbol’s own recent volatility means a calm stock gets a tight stop and a volatile one gets appropriately more room. executor.py — talking to Alpaca Two things worth calling out: trade_logger.py — recording everything This logs to per-symbol CSV files (trade_log_ACN.csv, equity_log_SPY.csv, etc.) so you can run multiple symbols from the same project directory without their logs overwriting each other. Step 6: Backtest before running anything live This is the step I’d encourage you not to skip, whatever strategy you end up using. Here’s the backtesting script: backtest.py Run it like this: The most important line in that output is the buy-and-hold comparison. A strategy can show a positive return and still be a bad idea — the only way to know is to compare it against what you’d have gotten just buying and holding the same stock over the same period. Don’t skip this comparison; it’s the single most useful sanity check in the whole project. You can also tune the strategy’s parameters directly from the command line without touching the code: Step 7: Run the live paper-trading loop Once you’re comfortable with the backtest results, here’s the live trading script: main.py Run it with: This polls every 15 minutes by default, checks the strategy’s signal, and submits paper orders through Alpaca when conditions are met. Each cycle prints the current indicator values (moving averages, ADX, current position) so you can watch it work in real time instead of guessing what it’s doing. Step 8: Keep it running with tmux SSH sessions die, laptops sleep — you don’t want the bot to stop just because your terminal disconnected. tmux solves this: Detach with Ctrl+B then D (press and release Ctrl+B, then press D separately — it’s a two-step sequence, not a single chord). The bot keeps running in the background. Reattach anytime with: Step 9: Check in on it periodically A few habits worth building once this is running unattended: A couple of hard-earned lessons Don’t gate your stop-loss on the same trend filter as your entry. I initially removed the ADX confirmation from the exit condition, reasoning the ATR stop already handled downside risk. Backtesting showed this let the strategy bail on ordinary pullbacks within an otherwise healthy trend, then re-buy shortly after — generating more whipsaw losses than it prevented. Requiring trend confirmation on both entry and exit, symmetrically, fixed it. Always check for pending orders, not just filled positions, before submitting a new one. This is the bug that cost me fourteen unintended paper trades in one morning. If an order is submitted while the market is closed, it sits queued rather than executing — and a polling loop that only checks “do I already hold a position” has no

Building a Paper-Trading Bot, Part 2: Full Setup and Code on Linux Read More »

Building a Paper-Trading Bot, Part 1: What I Learned From Getting It Wrong Three Times

This is Part 1 of a 3-part series on building a paper-trading bot from scratch. This post is the story — what I built and what went wrong along the way. Part 2 is a step-by-step tutorial with the full working code if you want to build it yourself. Part 3 covers adding a live performance dashboard served over Apache. I set out to build a trading bot. I ended up learning more about testing discipline, benchmark comparisons, and the subtle ways “correct-looking” code can still be wrong than I did about trading itself. This is the story of that build — the architecture, the backtests that punctured my assumptions, and two live bugs that only showed up once real automation was running unattended. If you’re thinking about building something similar, I’d rather show you where it actually went sideways than pretend it was smooth from commit one. The starting point The goal was modest on purpose: get a Python bot paper-trading on Alpaca, with a strategy simple enough to reason about — a moving-average crossover. Before writing a line of strategy logic, I laid out the pipeline as separate, swappable pieces: Keeping these separate turned out to matter a lot more than I expected. Every bug I hit later was isolated to one module, and I could reason about (and fix) each one without touching the others. The first version of the strategy was a plain SMA crossover: buy when a 20-day moving average crosses above a 50-day average, sell on the reverse. Dead simple, and a reasonable scaffold to prove the plumbing worked end to end. Backtest #1: humbled by buy-and-hold The first backtest ran fine — positive return, plausible-looking trades. It felt like a win right up until I added one more line of output: what would buy-and-hold have returned over the same period? That single comparison changed everything. On AAPL over a 730-day window, the strategy returned about 25%. Buy-and-hold returned nearly 47%. The strategy wasn’t just “okay” — it was leaving almost half its potential return on the table, entirely because it sat in cash during a strong bull run, waiting for confirmation signals that a buy-and-hold investor never needed. Lesson: a backtest without a benchmark isn’t really a backtest — it’s just a number. Positive returns feel good in isolation, but “good” is only meaningful relative to the simplest alternative: doing nothing. Adding a trend filter — and testing it honestly The obvious next step was gating the crossover on trend strength, using ADX (Average Directional Index) — only trust a crossover if ADX confirms the market is actually trending, not just noisy. That cut down on whipsaw trades in choppy periods. But here’s the thing about a filter like this: it has a real cost as well as a real benefit, and you only see the cost by testing it somewhere it’s supposed to hurt. So instead of only testing on one stock, I ran the same strategy across four very different regimes: The pattern that emerged was completely coherent, and completely different from what a single-symbol test would have shown: the strategy underperformed buy-and-hold by 20-30 percentage points on AAPL and SPY (the cost of waiting for confirmation in a market that just kept going up), but beat buy-and-hold by over 25 percentage points on ACN — it correctly stepped aside during the worst of a real decline. That’s not a strategy that “works” or “doesn’t work.” It’s a strategy with a specific, identifiable regime it’s good for. Knowing that is worth infinitely more than a single aggregate number from one stock. The stop-loss that made things worse Position risk was still an open problem — a naive flat 2% stop-loss sounded reasonable on paper. It was not reasonable in practice. Backtesting it on COIN revealed why: nine stop-loss exits in under a year, several just days apart. A 2% move is ordinary daily noise for a stock as volatile as COIN — the stop wasn’t protecting against real reversals, it was getting shredded by the stock’s normal breathing room, forcing repeated re-entries at worse prices each time. The fix was to scale the stop distance to each symbol’s own volatility using ATR (Average True Range) instead of a flat percentage — entry_price – (2.5 × ATR at entry). A volatile stock naturally gets a wider stop; a calm one gets a tighter one. Re-running the same COIN backtest after the change: stop-loss exits dropped from nine to two, and the damage from each was cut by more than half. Lesson: risk parameters that “feel” reasonable in isolation can be actively harmful without accounting for the asset’s own behavior. Test the thing you added, not just the thing you started with. Going live surfaced a bug backtesting couldn’t catch Backtesting works because you’re replaying finalized, settled data. Live trading exposed a class of bug that simply doesn’t exist in that world: timing. The original signal logic only fired a BUY on the exact bar a crossover happened, gated by whether ADX confirmed a trend on that same bar. In backtesting, this looked fine. Live, it quietly broke: ADX often takes a few days to climb above the trend threshold after a price move starts. If the crossover happened while ADX was still catching up, the strategy correctly held off — and then never revisited the decision, because the “crossing” moment had already passed by the time ADX confirmed anything. I only caught this because I was watching the live indicator values directly and noticed SMA20 sitting comfortably above SMA50, with ADX freshly past the trend threshold — every condition for a buy, and yet nothing fired. The fix was switching from event-based signals (“did the cross happen on this exact bar?”) to state-based signals (“is the market currently in a qualifying state?”) — evaluated fresh every cycle instead of only at the moment of crossing. Re-running backtests after the fix produced a nuance worth sitting with: the fix helped one symbol

Building a Paper-Trading Bot, Part 1: What I Learned From Getting It Wrong Three Times Read More »

Zyxel NWA50BE PRO Review: Upgrading from Cisco 240AC to Wi-Fi 7

After several years of running a three-pack of Cisco Business CBW240AC 802.11ac access points, I decided it was time for an upgrade. The Cisco 240ACs had served me well. They were reliable, offered good coverage throughout the house and, for their generation, delivered a solid wireless experience. However, wireless technology has moved on considerably since I installed them. My old Cisco access points were based on Wi-Fi 5 (802.11ac), whereas my replacement is the Zyxel NWA50BE PRO, a Wi-Fi 7 access point capable of up to BE6500 / 6.5Gbps of aggregate wireless throughput and equipped with a 2.5GbE Ethernet interface. Zyxel NWA50BE Pro Wi-Fi 7 Access Point This is the access point I purchased and installed as part of my upgrade from the Cisco 240AC to Wi-Fi 7. If you’re interested in the NWA50BE Pro, you can check the current price and availability on Amazon UK. Check Price on Amazon UK Affiliate Disclosure: This post contains Amazon affiliate links. If you purchase a product through one of these links, I may earn a small commission at no additional cost to you. I only recommend products that I have personally used or believe are worth considering. But there was another reason this particular upgrade was interesting for me. Stepping outside my comfort zone As an Infrastructure Engineering professional, I’ve spent much of my career working with enterprise networking and infrastructure products. Cisco, HPE, Aruba and other established enterprise vendors are the names I’m familiar with and, more importantly, the platforms I’ve trusted. So when I started looking for a replacement for my Cisco access points, moving to Zyxel wasn’t an obvious decision for me. I’ll be honest — I was nervous about it. Zyxel is a brand I’d obviously come across before, but it wasn’t a vendor I had personally relied on in the same way I had relied on Cisco and HPE in professional environments. I therefore spent quite a bit of time researching the NWA50BE PRO before making the decision. I looked at the specifications, management platform, firmware support, security features, VLAN capabilities, PoE requirements, cloud management and, importantly, what the real-world experience was like for people actually using the hardware. I also wanted to make sure that it would integrate properly with the network architecture I already had at home. That meant considering how it would work alongside my pfSense firewall, my network segmentation, multiple SSIDs and existing PoE switching infrastructure. There was a certain amount of hesitation before pressing the order button. Would it feel like a step backwards coming from Cisco? Would the management platform be good enough? Would the firmware and support be there? Would it actually perform as advertised? These were all questions I had before making the switch. As it turned out, I needn’t have worried. The Zyxel NWA50BE PRO has genuinely surprised me. In fact, after installing and configuring the three access points, I was amazed by how capable the product is. The hardware feels well thought out, the management experience is straightforward and the performance has been excellent. Most importantly, it doesn’t feel like I compromised by moving away from the enterprise vendors I’m accustomed to using. If anything, the experience has made me reconsider where Zyxel fits into the networking market. My Home Network Setup Before looking at the access points themselves, it’s worth explaining how I’ve built my home network. I’m a big believer in keeping the network properly segmented, even at home. Rather than putting every device onto a single flat network, I’m using my own custom pfSense firewall as the core of the network. The wireless network is separated into two distinct environments: These are presented to wireless clients using two separate SSIDs. My wireless setup SSID 1 – Trusted My primary wireless network for trusted devices. SSID 2 – Guest A separate guest network with restricted access to my trusted network. The Zyxel access points are therefore not simply providing wireless connectivity. They are sitting within a properly segmented network architecture, with pfSense handling the routing, firewalling and network separation. This is one of the reasons I particularly like using business-oriented networking equipment at home. It gives me the flexibility to build the network in the way I want rather than relying entirely on whatever functionality happens to be built into a consumer router. What You Need for a Similar Home Network Setup If you’re considering building something similar to my home network, here’s a rough idea of the equipment I’m using — or, more accurately, the type of equipment you would need. It’s important to point out that my own hardware has been in use for several years, and some of the exact models I have are no longer readily available. Rather than recommending obsolete hardware, I’ve included links to current alternatives that are similar in terms of functionality and capability. I’ve also deliberately gone for equipment that sits towards the higher end of what you might consider for a home network. You absolutely don’t need to spend this much to get good Wi-Fi at home. There are plenty of cheaper alternatives available, particularly if you don’t need VLANs, multiple SSIDs, PoE or advanced firewall functionality. However, if you’re interested in building a network similar to mine, these are the types of components I’d look at. 🛜 Wi-Fi Access Points The most important part of my upgrade is the three Zyxel NWA50BE PRO Wi-Fi 7 access points. I’m using three APs to provide coverage throughout my home, with the APs connected back to my wired network using Ethernet and powered via PoE. Zyxel NWA50BE PRO BE6500 Wi-Fi 7 Access Point Check Price on Amazon UK As an Amazon Associate, I earn from qualifying purchases. The three APs are configured to provide both my trusted and guest SSIDs, with the underlying network segmentation handled by pfSense. 🔥 Firewall / Router For the firewall, I’m using my own custom pfSense installation. This is probably the component that makes my setup more advanced than a typical home

Zyxel NWA50BE PRO Review: Upgrading from Cisco 240AC to Wi-Fi 7 Read More »

How to Export a PFX Certificate from Azure Key Vault

Azure Key Vault is a convenient place to store and manage SSL/TLS certificates, but there are times when you need to take a certificate out of Key Vault and use it somewhere else. For example, you may need to export a certificate as a PFX (.pfx) file so that it can be installed on a Windows server, imported into IIS, configured on another application, or transferred to a system that cannot retrieve certificates directly from Azure Key Vault. In this guide, I’ll show you how to export a certificate from Azure Key Vault using PowerShell, including how to protect the resulting PFX file with a password. Before you start There is an important limitation to be aware of before attempting to export a certificate. The certificate’s private key must have been created as exportable. When a certificate is created in Azure Key Vault, its certificate policy determines whether the private key can be exported. If the certificate was created with a non-exportable private key, you cannot simply change the setting later and export the private key. Microsoft also notes that exportable keys are supported for RSA and EC keys, while HSM-backed keys are non-exportable. This distinction is important because downloading the certificate itself is not necessarily the same as exporting the private key. A certificate without its private key is generally not sufficient when you need to install it on another server. What is stored in Azure Key Vault? When you create a certificate in Azure Key Vault, Key Vault maintains several related objects. The certificate contains the X.509 certificate information, while an associated secret contains the certificate value. When the certificate is exportable, the secret can contain the certificate together with its private key. This is why the PowerShell method below retrieves the secret rather than simply downloading the certificate. What you will need You’ll need: If you are using a workstation with the Az PowerShell modules installed, you can first authenticate with: If you have multiple Azure subscriptions, make sure you are working in the correct one: You can change subscriptions with: Export the certificate as a PFX The simplest approach is to retrieve the certificate’s associated secret, decode the Base64 value and write it to a .pfx file. For example: Microsoft documents this approach for exporting the certificate and private key from Key Vault. At this point you should have: However, there is an important detail with this method. The exported PFX may not have the password you want The certificate value stored by Key Vault can be retrieved as a PFX, but if you need to provide the certificate to another administrator or application, you may want to create a new password-protected PFX. That’s where the following approach is useful. Export the certificate and apply a new PFX password The following script retrieves the certificate from Key Vault, loads it with its private key and then exports it again as a password-protected PFX. This produces a PFX file protected by the password you specify. Why retrieve the secret instead of the certificate? This is one of the slightly confusing aspects of Azure Key Vault. If you run: you are retrieving the Key Vault certificate object and its metadata. That includes information such as: The private key isn’t exposed directly through the certificate object. The associated Key Vault secret is what contains the certificate value that can include the private key when the certificate is exportable. That’s why the export process ultimately uses: rather than only: Verify the PFX file Before copying the certificate to another server, it’s a good idea to verify that the PFX contains the private key. On Windows, you can use PowerShell: You want: for: You can also inspect the certificate using the Windows certificate import wizard. Right-click the .pfx file and select Install PFX. During the import process, Windows will ask for the password you assigned to the PFX. Exporting through the Azure Portal You don’t necessarily need PowerShell. Azure Key Vault also provides certificate download options through the Azure portal. Navigate to: Azure Portal → Key Vault → Certificates → Your Certificate → Current Version Depending on the certificate and configuration, you can use the download option to obtain the certificate in formats such as CER or PFX/PEM. The portal is convenient for a one-off export, while PowerShell is much more useful if you need to repeat the process or incorporate it into an administrative workflow. One thing to be aware of is that Azure Key Vault does not retain a certificate import password for later export. Microsoft states that when a certificate is exported from Key Vault, the export password is blank; if you need a PFX protected with a specific password, you can re-export it with PowerShell as shown above. What if the private key is missing? If the resulting certificate doesn’t contain a private key, the first thing to check is whether the Key Vault certificate was created as exportable. You can inspect the certificate in the Azure portal and review its configuration. If the certificate was created with a non-exportable private key, Azure Key Vault will not provide the private key when the certificate is retrieved as a secret. Unfortunately, you cannot turn a non-exportable private key into an exportable one after the fact. In that situation, you may need to create or import a new certificate with an exportable private key, depending on your security requirements. Security considerations A PFX file containing a private key should be treated as a sensitive credential. Once you export it from Key Vault: This is particularly important because one of the advantages of Azure Key Vault is that applications can use certificates without requiring administrators to distribute private-key files manually. Microsoft recommends limiting who can export certificates containing private keys and auditing certificate access and export operations. Azure CLI alternative If you prefer Azure CLI, you can retrieve the certificate’s public portion with: However, that downloads the public portion of the certificate. To retrieve the certificate including its private

How to Export a PFX Certificate from Azure Key Vault Read More »

Alcatel OmniSwitch Useful CLI Commands: Practical Guide for Network Administrators

If you work with Alcatel OmniSwitch switches, sooner or later you’ll need to drop into the command line to troubleshoot a port, configure a VLAN, check a stack, manage PoE or investigate a network problem. I’ve put together this list of the Alcatel OmniSwitch CLI commands I find most useful, based on working with OmniSwitch equipment in real-world environments. The commands in this guide have been tested on Alcatel OmniSwitch 6400 and 6850 switches. They may also work on other OmniSwitch models, but command availability and syntax can vary depending on the switch model and AOS version. Important: Always check the command against your particular OmniSwitch model and AOS version before using it on a production switch. Some commands in this guide can be disruptive or destructive. Alcatel OmniSwitch CLI Basics OmniSwitch uses a command-line interface that is slightly different from Cisco IOS, so if you’re more familiar with Cisco switches, some of the syntax may look unfamiliar initially. One of the useful things about OmniSwitch CLI is that commands are generally quite descriptive. Once you become familiar with the structure, day-to-day configuration and troubleshooting becomes relatively straightforward. This guide covers: 1. Reset an OmniSwitch to Factory Defaults Use this with extreme caution. If you need to completely reset an OmniSwitch, the configuration files can be removed from the working and certified directories before rebooting the switch. The switch will reboot and come back without the previous configuration. After the reboot, you can verify that a new configuration has been created with: or: ⚠️ Important This is a destructive operation. Make sure you have a backup of the configuration before doing this. I would strongly recommend confirming that you’re connected to the correct switch before running the commands, particularly when working remotely. 2. Save the Switch Configuration One thing worth understanding with OmniSwitch is the distinction between the Working and Certified configurations. To save the current working configuration: To copy the working configuration to the certified configuration: For a stack containing multiple switches, you can synchronise the configuration across the slots: You can then check the current configuration and synchronisation state with: A healthy switch should show something similar to: Why this matters Saving the configuration to the working configuration isn’t necessarily the same thing as having a certified configuration ready for the next reboot. For production switches, I recommend checking show running-directory after making significant configuration changes. 3. Change the Switch Name Giving switches meaningful names makes life considerably easier when you’re managing multiple devices. For example: Replace Switch1 with whatever naming convention you use. For example: This changes both the system name and the CLI prompt. 4. Configure System Location and Contact Information You can also configure basic information describing where the switch is located and who is responsible for it. Check the configuration with: This is particularly useful in larger environments where a switch may be physically located somewhere different from the person administering it. 5. Configure DNS and NTP Configure a DNS server with: Configure the DNS domain: Configure an NTP server: Enable the NTP client: For production networks, accurate time is particularly important for troubleshooting and log correlation. If you’re investigating an issue across switches, firewalls and servers, having every device using the same time source makes a huge difference. 6. Check System and Hardware Information These are some of the first commands I use when connecting to an unfamiliar OmniSwitch. General system information Chassis information Stack topology CPU health Memory health These commands are particularly useful when troubleshooting performance or unexpected behaviour. 7. VLAN Configuration Create a VLAN To create VLAN 10 and give it a name: This creates VLAN 10 with the description Guest. Delete a VLAN To remove VLAN 10: Be careful: removing a VLAN can immediately affect any ports, interfaces or services using it. Configure an Access/Untagged Port To assign ports 1 through 24 on slot 1 to VLAN 10: This makes those ports untagged/default members of VLAN 10. For example, if VLAN 10 is your guest network, this could be used to place a group of access ports into that VLAN. Configure a Tagged Port To add port 1 on slot 1 to VLAN 10 as an 802.1Q tagged member: This is useful for trunk/uplink-style connections where multiple VLANs need to traverse the same physical interface. Remove VLAN Membership To remove the default VLAN membership: To remove tagged membership: Check a VLAN To display the configuration of VLAN 10: To see the ports associated with the VLAN: These are useful commands when troubleshooting VLAN-related connectivity problems. 8. Interface and Port Configuration Show Port Status To see the status of the switch ports: This is one of the first commands I’d use when troubleshooting a device that cannot connect to the network. Show Detailed Port Information This provides more detailed information about the interfaces. Check a Specific Port OmniSwitch identifies interfaces using a slot/port format. For example: This displays information for port 5 on slot 1. 9. Configure Port Speed and Duplex The following examples use port 1/5. Disable auto-negotiation To enable it again: Set duplex Set interface speed For example: ⚠️ Be careful with manual speed/duplex In modern Ethernet networks, auto-negotiation should generally be preferred unless there is a specific reason to manually configure speed and duplex. A mismatch can result in poor performance, errors or an unreliable connection. 10. Administratively Disable or Enable a Port To shut down port 1/5: To bring it back up: This is useful when troubleshooting a device or deliberately taking a port out of service. 11. Give a Port an Alias Adding a description to a port makes switch management much easier. For example: You could also use something more descriptive: I highly recommend doing this wherever practical. When troubleshooting months later, a useful port description can save a lot of time. 12. Configure a Management Interface You can create an IP interface on a VLAN for switch management. For example: In this example: Check the configured IP interfaces with: To remove the

Alcatel OmniSwitch Useful CLI Commands: Practical Guide for Network Administrators Read More »

Ubuntu 14.04: How to Extend Disk Space on a Physical or Logical Volume

If you have inherited an old Ubuntu 14.04 server or virtual machine and suddenly find that the filesystem is running out of disk space, extending the storage can be a little confusing. This guide walks through the process of increasing disk space on an Ubuntu 14.04 server using LVM, including the steps required after increasing the virtual disk in VMware. Although Ubuntu 14.04 is now a legacy operating system, these systems still exist in production, lab environments and old applications that cannot easily be upgraded. Important: Ubuntu 14.04 reached end of standard support in 2019. Only use this guide for systems that genuinely need to remain on this legacy release. Always take a backup or snapshot before making partition or filesystem changes. The basic process When increasing the storage of an Ubuntu virtual machine, there are several separate layers involved: Depending on how the server is configured, you may need to extend one or more of these layers. For an LVM-based server, the usual process is: 1. Check the current disk layout Before making any changes, find out how the server is currently configured. Start with: This shows the filesystems and how much space they are currently using. For example: In this example, the root filesystem is only 20 GB and is almost full. Next, look at the disks and partitions: You can also use: And, because this is an LVM system, check the physical volumes, volume groups and logical volumes: These commands are extremely useful because they show where the available space actually exists. 2. Increase the virtual disk in VMware If this is a VMware virtual machine, first increase the size of the virtual hard disk in vCenter or the VMware management interface. For example, you might increase: At this point VMware knows about the additional 40 GB, but Ubuntu may still be reporting the original disk size. Depending on the Ubuntu/kernel configuration, a reboot may be required. For a legacy Ubuntu 14.04 server, I would generally recommend scheduling a reboot rather than relying on a storage rescan if the system is not known to support the required hot-rescan workflow. After the reboot, check: You should now see the larger disk. For example: 3. Identify the available space Run: You may see something similar to: If the disk is now 100 GB but the final partition ends at 60 GB, the remaining space is currently unallocated. For example: The exact layout will vary between servers, so do not blindly copy partition numbers from this example. 4. Create a partition using the new space If the additional disk space is outside the existing LVM partition, create a new partition using the available space. On Ubuntu 14.04, fdisk is commonly available: Inside fdisk, use: to create a new partition. Select the default start and end sectors if you want to use all of the available space. Then change the partition type to Linux LVM: and select: Finally, review the changes with: If everything looks correct, write the changes: Be careful fdisk modifies the partition table. Selecting the wrong disk or deleting an existing partition can cause data loss. Always verify the device name with: before making changes. 5. Check that Linux sees the new partition Run: You should now see something similar to: If the new partition does not appear immediately, try: Then check again: On some older systems, a reboot may be required before the kernel recognises the updated partition table. 6. Create an LVM Physical Volume If the new partition is going to be added to LVM, initialise it as a Physical Volume: You should see a message similar to: Confirm it with: You should now see /dev/sda3 listed as an LVM Physical Volume. 7. Add the Physical Volume to the Volume Group Next, identify the existing Volume Group: For example: In this example, the Volume Group is: Add the new Physical Volume: Check the result: The available free space should now have increased. 8. Extend the Logical Volume Now identify the Logical Volume: You might see: The Logical Volume path would therefore be: You can extend it by a specific amount. For example, to add 20 GB: Or, if you want to allocate all remaining free space in the Volume Group: The + is important. For example: means add 20 GB. Without the +, the value represents the new total size of the Logical Volume rather than the amount to add. Ubuntu’s LVM documentation also documents the +100%FREE approach for allocating the remaining free extents. 9. Extend the filesystem At this point the Logical Volume has been increased, but the filesystem may still be the original size. Check: If the filesystem has not grown, it needs to be resized. For an ext3/ext4 filesystem, use: You should see output indicating that the filesystem has been resized. Check again: The additional space should now be available. 10. A simpler LVM approach On versions of LVM that support it, lvextend can resize the Logical Volume and filesystem together using -r: The -r option tells LVM to resize the underlying filesystem as part of the operation. The Xenial/Ubuntu 16.04 lvextend documentation confirms support for –resizefs, although on an old Ubuntu 14.04 server I prefer the explicit two-step approach because it makes it much clearer what is happening. For a legacy server, I would therefore use: Extending an existing LVM partition instead The above example assumes that the additional disk space requires a new partition such as /dev/sda3. There is another common scenario. If you increased the size of a disk and the existing LVM partition itself now has additional space available, you may only need to resize the existing Physical Volume. For example: Then check: If the Volume Group now has additional free space, extend the Logical Volume: Then resize the filesystem: This distinction is important: Verify everything Once the resize is complete, check all the layers. Check the disk Check the Physical Volumes Check the Volume Group Check the Logical Volumes Check the filesystem For example, you should now

Ubuntu 14.04: How to Extend Disk Space on a Physical or Logical Volume Read More »

Cisco 887VA BT VDSL2 / FTTC Configuration

If you have a Cisco 887VA sitting around and a BT/Openreach FTTC connection, you can use the Cisco router’s built-in VDSL2 modem to connect directly to the fibre broadband service. Unlike a traditional ADSL connection, BT’s VDSL2 service uses PPPoE over Ethernet, with the broadband service carried over 802.1Q VLAN 101. The Cisco 887VA can handle the VDSL2 connection itself, meaning you don’t necessarily need the separate Openreach modem or a BT Home Hub. This guide shows a practical Cisco IOS configuration for connecting a Cisco 887VA directly to a BT VDSL2/FTTC service. Important: This guide is specifically for VDSL2/FTTC. It does not apply to FTTP, where the WAN connection is presented to your router over Ethernet. What you need For this configuration you will need: The exact interface names and available commands can vary between Cisco 800-series models and IOS releases, so you may need to adjust the configuration for your particular hardware. How BT VDSL works There are three important pieces to the connection: The Cisco router establishes the physical VDSL2 connection using its built-in modem. The broadband traffic is then placed into VLAN 101 on the Ethernet-based VDSL interface. PPPoE runs over that VLAN and creates the PPP session on the Cisco Dialer0 interface. BT’s current documentation confirms that its fibre broadband uses PPPoE, while VLAN 101 is commonly required when configuring third-party equipment directly against the BT/Openreach VDSL service. Configure the VDSL controller Start by configuring the VDSL controller. A typical configuration is: On some Cisco IOS versions, the controller may be named differently. For example, you may see something such as: Use: or, depending on the platform: to identify the correct controller. You can also use the following command to check the current DSL state: The important thing at this stage is that the modem successfully synchronises with the VDSL line. Configure the VDSL Ethernet interface The Cisco 887VA presents the VDSL connection as an Ethernet Layer 2 interface. First configure the physical interface: We then create an 802.1Q subinterface for VLAN 101: The important line here is: This places the PPPoE traffic into VLAN 101. The following command associates the PPPoE client with dialer pool 1: That dialer pool will later be used by Dialer0. Disable the ATM interface The 887VA supports both ADSL and VDSL technologies, so you may see an ATM0 interface in the configuration. For a VDSL2-only configuration it isn’t required: This makes it clear that the router is using the Ethernet-based VDSL interface rather than attempting to establish the broadband session over ATM. Configure the PPPoE Dialer The PPPoE session is terminated on a dialer interface. Create Dialer0: Replace: with the credentials supplied by your ISP. Why MTU 1492? A normal Ethernet frame supports a 1500-byte IP packet. PPPoE introduces an additional 8 bytes of overhead, which normally reduces the usable IP MTU to: Therefore: is a sensible starting point for a standard PPPoE connection. The MSS adjustment: helps prevent TCP packets from being too large for the PPPoE path. Some providers and configurations support larger frames, sometimes referred to as “Baby Jumbo” frames, but there is no reason to introduce that complexity unless your service and downstream equipment support it. Add the default route Once the PPPoE session comes up, traffic needs a default route towards the Internet. You can use: Alternatively, depending on the IOS configuration, ppp ipcp route default can install the default route automatically. I prefer explicitly configuring the route when building a simple configuration because it makes the routing behaviour obvious. Complete basic configuration Putting the important pieces together, a basic BT VDSL configuration looks like this: You will obviously need to adapt this configuration to your own LAN, NAT, DHCP, firewall and routing requirements. Configuring NAT If the Cisco 887VA is also going to act as your Internet router, you will normally need NAT. For example, if your LAN is: configure the LAN interface: Then mark the PPPoE interface as the outside interface: Create a NAT access list: And configure PAT: Your traffic flow is then: Checking the VDSL connection Once the configuration is applied, the first thing to establish is whether the physical VDSL connection is working. Use: You want to see that the modem has trained and is operating in VDSL2 mode. Depending on the IOS version, useful information may include: If the modem hasn’t synchronised, don’t start troubleshooting PPPoE yet. The problem is at the DSL layer. Checking the PPPoE session Once VDSL has synchronised, check the dialer: You should see the interface as up/up and an IP address assigned by the ISP. For example: You can also check the PPPoE session: And check the dialer status: If VDSL is synchronised but Dialer0 isn’t coming up, the problem is likely to be related to PPPoE, VLAN 101 or authentication rather than the physical DSL connection. Useful troubleshooting commands These commands are particularly useful when troubleshooting the connection: For a quick overview of the interfaces: You should expect to see something similar to: VDSL is up but Dialer0 is down This is one of the most common situations. If the router has successfully synchronised with the VDSL line but the PPPoE session isn’t establishing, check the following: 1. Check VLAN 101 Make sure the subinterface contains: VLAN 101 is an important part of many UK BT/Openreach FTTC configurations. 2. Check the PPPoE configuration Make sure the subinterface contains: And make sure Dialer0 contains: These three settings tie the physical VDSL interface, PPPoE client and dialer together. 3. Check your username and password Incorrect PPP credentials will prevent the PPP session from completing. Make sure you haven’t accidentally copied a space or line break into the username or password. 4. Check the PPP negotiation If necessary, PPP debugging can provide more information: Be careful with debugging on a production router because it can generate a significant amount of console/log output. Disable debugging when finished: The VDSL modem won’t synchronise If: shows that the modem is not synchronised, PPPoE configuration is not yet

Cisco 887VA BT VDSL2 / FTTC Configuration Read More »

Create a New Ubuntu Disk Partition Using Parted

If you have added a new disk to an Ubuntu server, you can use parted to create a partition and then format it ready for use. This guide shows how to create a single GPT partition using the entire disk. Warning: Double-check the disk device before partitioning. The commands below will modify the selected disk and can destroy existing data. Identify the New Disk First, list the disks attached to the server: For example: In this example, /dev/sdb is the new 100GB disk. Create the Partition Start parted against the new disk: Create a GPT partition table: Set the unit to GB: Create a single partition using the available space: You can then verify the partition: When everything looks correct, exit: The new partition should now be available as: Format the Partition For a typical Ubuntu data disk, I would recommend ext4: If you specifically need FAT32 instead: The partition is now created and formatted. The next step is to create a mount point and mount it, or add it to /etc/fstab if it needs to be mounted automatically after a reboot.

Create a New Ubuntu Disk Partition Using Parted Read More »