<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom"><title>Unstable Muffin</title><link href="https://blog.unstablemuffin.com/" rel="alternate"/><link href="https://blog.unstablemuffin.com/feeds/atom.xml" rel="self"/><id>https://blog.unstablemuffin.com/</id><updated>2026-04-25T00:00:00-07:00</updated><entry><title>Top Chef S23E04 - Pick a Side</title><link href="https://blog.unstablemuffin.com/top-chef-s23e04-pick-a-side.html" rel="alternate"/><published>2026-04-25T00:00:00-07:00</published><updated>2026-04-25T00:00:00-07:00</updated><author><name>Michael</name></author><id>tag:blog.unstablemuffin.com,2026-04-25:/top-chef-s23e04-pick-a-side.html</id><summary type="html">&lt;p&gt;Food crimes, fashion crimes, making cream out of things that should not be creamed, and an unjustified&amp;nbsp;elimination.&lt;/p&gt;</summary><content type="html">&lt;p&gt;I&amp;rsquo;m so deeply behind on posting these reactions posts, but I guarantee the reactions are still fresh because I write them down in my notebook as I watch the episode. Writing this post will just be me reliving the episode with you through my notes. Should be&amp;nbsp;fun!&lt;/p&gt;
&lt;p&gt;This episode, we recovered from the flop-tastrophe from last week and into another week of the chefs all performing pretty well! We&amp;rsquo;ve got some awkward cross-promotion in the quick fire, Justin committing fashion crimes, and an elimination challenge brief that just doesn&amp;rsquo;t make any sense and seems to be judged wildly inconsistently. There&amp;rsquo;s also a major cooking disaster that the edit desperately tries to make us blame the chef for, but is so clearly not their fault that it comes off incredibly disingenuous. This week, drama is the main&amp;nbsp;course.&lt;/p&gt;
&lt;h3 id="quick-fire"&gt;Quick&amp;nbsp;Fire&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Okay miss try-too-hard. Cheering for the guest judge like a teacher&amp;rsquo;s pet. Idk if you think you&amp;rsquo;re being clever but everyone can plainly see you&amp;rsquo;re sucking&amp;nbsp;up.&lt;/li&gt;
&lt;li&gt;I wrote this in my notes: &amp;ldquo;&amp;lsquo;Big Josh fan&amp;rsquo; – girl same&amp;rdquo; but I have no idea what that was supposed to mean. But it feels important, so I&amp;rsquo;m leaving it&amp;nbsp;in.&lt;/li&gt;
&lt;li&gt;They&amp;rsquo;re talking up Josh wines as if it&amp;rsquo;s this super exclusive, premium wine, which makes sense since they&amp;rsquo;re the sponsor for this episode. But my association with Josh wines is watching the same ad fifty billion times on Hulu and seeing it on the cheap end of the Safeway wine aisle, so something&amp;rsquo;s not matching up&amp;nbsp;here.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;span class="caps"&gt;SNEEZE&lt;/span&gt;-&lt;span class="caps"&gt;GATE&lt;/span&gt;&lt;/strong&gt;&amp;nbsp;🚨🚨🚨&lt;/li&gt;
&lt;li&gt;Dang, there&amp;rsquo;s a lot of money flowing this season. Can&amp;rsquo;t say the chefs don&amp;rsquo;t deserve it though, so I&amp;rsquo;m happy about&amp;nbsp;it.&lt;/li&gt;
&lt;li&gt;How many different &amp;ldquo;ways&amp;rdquo; are there to do cheese? It&amp;rsquo;s just&amp;nbsp;cheese!&lt;/li&gt;
&lt;li&gt;Eggs just don&amp;rsquo;t seem like a star ingredient to me. Idk how they&amp;rsquo;re going to make a stand-out dish with eggs. What are you going to do, fry it in truffle oil? Scramble it with a gold&amp;nbsp;leaf?&lt;/li&gt;
&lt;li&gt;Justin looks like he&amp;rsquo;s either bored out of his mind or on the verge of falling asleep. Possibly&amp;nbsp;both.&lt;/li&gt;
&lt;li&gt;Okay, the twins have been officially added to the hate-list. Not above Justin, but definitely in the &amp;ldquo;egregious&amp;rdquo;&amp;nbsp;tier.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;span class="caps"&gt;MOCHI&lt;/span&gt;-&lt;span class="caps"&gt;GATE&lt;/span&gt;&lt;/strong&gt;&amp;nbsp;🚨🚨🚨&lt;/li&gt;
&lt;li&gt;Soft scrambled eggs are just undercooked eggs. Fight&amp;nbsp;me.&lt;/li&gt;
&lt;li&gt;I want to try Tomme cheese ☹️ It looks and sounds so delicious for some reason. Maybe I&amp;rsquo;m just&amp;nbsp;hungry.&lt;/li&gt;
&lt;li&gt;&lt;span class="dquo"&gt;&amp;ldquo;&lt;/span&gt;You just cook whatever you want and I will pair the wine to your food, instead of the other way around.&amp;rdquo; – So, the literal exact opposite of this&amp;nbsp;challenge?&lt;/li&gt;
&lt;li&gt;Oof, these mochi balls are looking crusty&amp;nbsp;af.&lt;/li&gt;
&lt;li&gt;Boo Justin, yay&amp;nbsp;Jennifer&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="elimination-challenge"&gt;Elimination&amp;nbsp;Challenge&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;span class="dquo"&gt;&amp;ldquo;&lt;/span&gt;There&amp;rsquo;s no catch&amp;rdquo; Kristen says, looking slyly at the camera. She&amp;rsquo;s in her villain era and the chefs know it&amp;nbsp;lol&lt;/li&gt;
&lt;li&gt;I don&amp;rsquo;t understand this &amp;ldquo;make a side dish a main dish&amp;rdquo; nonsense. What even is the difference between a main dish an a side dish? The show never explains. Jonathan even said &amp;ldquo;you can&amp;rsquo;t just make a bigger plate of collard greens and throw a protein on it and call it a day&amp;rdquo; which is exactly what I would have done if given this challenge, but then nobody ever explains what you &lt;em&gt;should&lt;/em&gt; do&amp;nbsp;instead.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;span class="caps"&gt;CABBAGE&lt;/span&gt;-&lt;span class="caps"&gt;GATE&lt;/span&gt;&lt;/strong&gt; 🚨🚨🚨 Where&amp;rsquo;s the brotherly love now,&amp;nbsp;twins?!?&lt;/li&gt;
&lt;li&gt;What is this okra play? Seems unwise to me. Literally two of the judges have openly said they don&amp;rsquo;t like it. Why would you take that on, they&amp;rsquo;re literally giving you an&amp;nbsp;out.&lt;/li&gt;
&lt;li&gt;It&amp;rsquo;s never easy on Top Chef. Of &lt;em&gt;course&lt;/em&gt; you&amp;rsquo;re also serving an entire diner full of guests. For some&amp;nbsp;reason.&lt;/li&gt;
&lt;li&gt;I must admit, I don&amp;rsquo;t understand the staggered service here. You get ninety minutes to cook for the judges, and then ninety more to cook for the rest of the restaurant? What&amp;rsquo;s the incentive to not phone it in for the restaurant cook? The judges have already tried your food, you&amp;rsquo;re not going to get docked points if your food tastes like crap to the rest of the diners. This one doesn&amp;rsquo;t make sense to&amp;nbsp;me.&lt;/li&gt;
&lt;li&gt;Jonathan hates turkeys? &lt;span class="caps"&gt;HE&lt;/span&gt;&amp;rsquo;S A &lt;span class="caps"&gt;TURKEY&lt;/span&gt; &lt;span class="caps"&gt;RACIST&lt;/span&gt;??? He loses Thanksgiving privileges. Get him out of&amp;nbsp;here.&lt;/li&gt;
&lt;li&gt;&lt;span class="dquo"&gt;&amp;ldquo;&lt;/span&gt;Main Dish Energy&amp;rdquo; is very funny, ngl&amp;nbsp;😆&lt;/li&gt;
&lt;li&gt;&lt;span class="dquo"&gt;&amp;ldquo;&lt;/span&gt;Maybe I can fool Tom into thinking he likes okra&amp;rdquo; – Stop. You can&amp;rsquo;t fool Tom. You&amp;rsquo;re embarrassing&amp;nbsp;yourself.&lt;/li&gt;
&lt;li&gt;Did anyone else see Brittany just drop some greens on the grocery store floor, and then just &lt;em&gt;pick them back up again and put them in her cart&lt;/em&gt;??? Where is my fainting couch, I think I caught the&amp;nbsp;vapors.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;&lt;span class="caps"&gt;SHE&lt;/span&gt;&amp;rsquo;S &lt;span class="caps"&gt;NOT&lt;/span&gt; &lt;span class="caps"&gt;YOUR&lt;/span&gt; &lt;span class="caps"&gt;BABY&lt;/span&gt;?!?!?!?!?!?&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;The little video messages between Sherry and her son are so sweet ❤️ Sometimes the &amp;ldquo;messages from home&amp;rdquo; segment can feel really forced and awkward, but these are really organic and really bring the viewers into the world of the chefs. I really like it. It highlights the sacrifices the chefs have to make to be on this show, and makes the whole competition feel that much more real and the stakes that much&amp;nbsp;higher.&lt;/li&gt;
&lt;li&gt;&lt;span class="caps"&gt;WHAT&lt;/span&gt;?!? &lt;span class="caps"&gt;DAISY&lt;/span&gt; &lt;span class="caps"&gt;DUKES&lt;/span&gt;?!?! &lt;span class="caps"&gt;WHY&lt;/span&gt;?!? &lt;span class="caps"&gt;WHY&lt;/span&gt; &lt;span class="caps"&gt;ARE&lt;/span&gt; &lt;span class="caps"&gt;YOU&lt;/span&gt; &lt;span class="caps"&gt;CUTTING&lt;/span&gt; &lt;span class="caps"&gt;THEM&lt;/span&gt; &lt;span class="caps"&gt;WHILE&lt;/span&gt; &lt;span class="caps"&gt;YOU&lt;/span&gt;&amp;rsquo;&lt;span class="caps"&gt;RE&lt;/span&gt; &lt;span class="caps"&gt;WEARING&lt;/span&gt; &lt;span class="caps"&gt;THEM&lt;/span&gt;?!?! &lt;span class="caps"&gt;WHY&lt;/span&gt; &lt;span class="caps"&gt;IS&lt;/span&gt; &lt;span class="caps"&gt;THIS&lt;/span&gt; &lt;span class="caps"&gt;HAPPENING&lt;/span&gt;. &lt;span class="caps"&gt;WHY&lt;/span&gt; &lt;span class="caps"&gt;ARE&lt;/span&gt; &lt;span class="caps"&gt;THE&lt;/span&gt; &lt;span class="caps"&gt;PRODUCERS&lt;/span&gt; &lt;span class="caps"&gt;LETTING&lt;/span&gt; &lt;span class="caps"&gt;THIS&lt;/span&gt; &lt;span class="caps"&gt;HAPPEN&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;This is teleporting me back to the shaved head incident from season&amp;nbsp;1.&lt;/li&gt;
&lt;li&gt;Bacon milk? Who&amp;rsquo;s out here milking bacon? Someone call &lt;span class="caps"&gt;PETA&lt;/span&gt;.&lt;/li&gt;
&lt;li&gt;What is this cooking lamp thing? It&amp;rsquo;s freaking me&amp;nbsp;out&lt;/li&gt;
&lt;li&gt;Justin is half-Indian,&amp;nbsp;whole-idiot.&lt;/li&gt;
&lt;li&gt;Justin was not bullied enough through middle school and high school, and it shows. Society should have never let these booty shorts happen on&amp;nbsp;him.&lt;/li&gt;
&lt;li&gt;Justin is a horse confirmed? (This is way too many bullet points about Justin; it is becoming right on the verge of&amp;nbsp;cyber-bullying)&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;span class="caps"&gt;NO&lt;/span&gt; &lt;span class="caps"&gt;STEAM&lt;/span&gt;-&lt;span class="caps"&gt;GATE&lt;/span&gt;&lt;/strong&gt;&amp;nbsp;🚨🚨🚨&lt;/li&gt;
&lt;li&gt;Genuinely, what do you do in this situation though? The ovens are supposed to be pre-heated before the chefs start cooking, so it&amp;rsquo;s obvious that Brittany thought the steamer would be on already when she put in her food. But clearly it wasn&amp;rsquo;t on, whether that was an oversight or technical restriction (I have no idea how a steamer works, but maybe it can&amp;rsquo;t be turned on before it&amp;rsquo;s used for some reason) so it doesn&amp;rsquo;t really feel like this flub is the fault of Brittany&amp;rsquo;s which makes it all the more tragic that her dish is essentially ruined because of&amp;nbsp;it.&lt;/li&gt;
&lt;li&gt;Is it me or is the fashion off the charts this season? That&amp;rsquo;s not something I typically notice but every time somebody&amp;rsquo;s not in a chef&amp;rsquo;s coat (besides Justin&amp;rsquo;s ridiculous shorts) I&amp;rsquo;m like &amp;ldquo;damn that&amp;rsquo;s a sharp&amp;nbsp;outfit&amp;rdquo;&lt;/li&gt;
&lt;li&gt;&lt;span class="dquo"&gt;&amp;ldquo;&lt;/span&gt;Justin&amp;rsquo;s [dish] is a little lackluster&amp;rdquo; – That&amp;rsquo;s because Justin is&amp;nbsp;lackluster.&lt;/li&gt;
&lt;li&gt;&lt;span class="dquo"&gt;&amp;ldquo;&lt;/span&gt;Scallion Cream&amp;rdquo; sounds horrendous, I&amp;rsquo;m sorry. What is it, whipped cream with scallions in it?&amp;nbsp;Eugh.&lt;/li&gt;
&lt;li&gt;Brittany &lt;strong&gt;&lt;em&gt;&lt;span class="caps"&gt;PUSH&lt;/span&gt;&lt;/em&gt;&lt;/strong&gt;!!!&lt;/li&gt;
&lt;li&gt;It feels insulting to be judged and then turn around and have to cook some more for some other nobodies that won&amp;rsquo;t affect your score at&amp;nbsp;all.&lt;/li&gt;
&lt;li&gt;&lt;span class="caps"&gt;WHERE&lt;/span&gt; &lt;span class="caps"&gt;IS&lt;/span&gt; &lt;span class="caps"&gt;THE&lt;/span&gt; &lt;span class="caps"&gt;POT&lt;/span&gt; &lt;span class="caps"&gt;LICKER&lt;/span&gt;??? I see the fritter but &lt;span class="caps"&gt;WHERE&lt;/span&gt;&amp;rsquo;S &lt;span class="caps"&gt;THE&lt;/span&gt; &lt;span class="caps"&gt;POT&lt;/span&gt; &lt;span class="caps"&gt;LICKER&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;Honestly, Tristan whispering &amp;ldquo;never admit that&amp;rdquo; when she was talking about her cooking woes really irked me. She had some disasters when creating her dish, and hiding them from the judges will only make them think that the dish she served was the way she &lt;em&gt;intended&lt;/em&gt; to serve it, which is not at all the case. Plus, why lie to the judges? That will only make them mad at you trying and failing to lie to them, or them eventually figuring out you lied and they hold that against you. It&amp;rsquo;s just a bad idea all around, and makes me majorly cringe that Tristan implied that you should lie to them. The only thing I would have done differently from Brittany is being upfront that the cooking instrument that you thought was on was not on, but I feel like I remember in past seasons Tom responding to that with &amp;ldquo;why didn&amp;rsquo;t you double check then&amp;rdquo; which really just skirts around the whole issue of production supposed to be having those machines turned on and pre-heating already. This feels like a massive run-on sentence but I will not be editing&amp;nbsp;it.&lt;/li&gt;
&lt;li&gt;There&amp;rsquo;s that frickin&amp;rsquo; bacon cream again. Why are people making savory whipped creams? &lt;span class="caps"&gt;LEAVE&lt;/span&gt; &lt;span class="caps"&gt;IT&lt;/span&gt; &lt;span class="caps"&gt;ALONE&lt;/span&gt;!!!&lt;/li&gt;
&lt;li&gt;Is Duyen the new&amp;nbsp;frontrunner???&lt;/li&gt;
&lt;li&gt;Duyen: &amp;ldquo;hmm. cool.&amp;rdquo; lol what a way to react to someone saying they thought their dish was great. She new he&amp;nbsp;flopped&lt;/li&gt;
&lt;li&gt;Sieger looks like such a douchebag in every era. Every single one of his childhood photos, he looked like the quintessential douchebag of that decade lol Including this one! I might&amp;nbsp;add&lt;/li&gt;
&lt;li&gt;There is nothing more cringe-y than somebody complimenting themselves on how they&amp;nbsp;look.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Fromager D&amp;rsquo;Affinois&lt;/em&gt; is the most pretentious sounding ingredient I&amp;rsquo;ve ever heard. And I&amp;rsquo;ve watched 23 seasons of Top&amp;nbsp;Chef.&lt;/li&gt;
&lt;li&gt;At this point in the episode I made a note that I was literally falling asleep as I watched, so the quality of the remaining reactions may falter. I don&amp;rsquo;t know if they&amp;rsquo;ll get shorter or exponentially more unhinged. Let&amp;rsquo;s find out&amp;nbsp;together.&lt;/li&gt;
&lt;li&gt;Pause for the Voss glamour shot. Not in any way distracting from the episode flow at&amp;nbsp;all.&lt;/li&gt;
&lt;li&gt;Kinda peeved that the okra gamble paid off. But that feels like a personal&amp;nbsp;grudge.&lt;/li&gt;
&lt;li&gt;&lt;span class="caps"&gt;SHE&lt;/span&gt; &lt;span class="caps"&gt;ONLY&lt;/span&gt; &lt;span class="caps"&gt;HAD&lt;/span&gt; &lt;span class="caps"&gt;TWENTY&lt;/span&gt; &lt;span class="caps"&gt;MINUTES&lt;/span&gt; &lt;span class="caps"&gt;TO&lt;/span&gt; &lt;span class="caps"&gt;COMPLETELY&lt;/span&gt; &lt;span class="caps"&gt;REINVENT&lt;/span&gt; &lt;span class="caps"&gt;AND&lt;/span&gt; &lt;span class="caps"&gt;RECOOK&lt;/span&gt; &lt;span class="caps"&gt;HER&lt;/span&gt; &lt;span class="caps"&gt;ENTIRE&lt;/span&gt; &lt;span class="caps"&gt;DISH&lt;/span&gt;!!! &lt;span class="caps"&gt;STOP&lt;/span&gt; &lt;span class="caps"&gt;BLAMING&lt;/span&gt; &lt;span class="caps"&gt;BRITTANY&lt;/span&gt; &lt;span class="caps"&gt;FOR&lt;/span&gt; &lt;span class="caps"&gt;THIS&lt;/span&gt;!!! &amp;ldquo;Didn&amp;rsquo;t know how to pivot&amp;rdquo; my&amp;nbsp;ass&lt;/li&gt;
&lt;li&gt;oh no :( poor&amp;nbsp;brittany&lt;/li&gt;
&lt;li&gt;I feel like she could do really well in Last Chance Kitchen. She can build her confidence&amp;nbsp;there.&lt;/li&gt;
&lt;/ul&gt;</content><category term="Personal"/><category term="tv"/><category term="top-chef"/></entry><entry><title>How To: Migrate a PostgreSQL database</title><link href="https://blog.unstablemuffin.com/how-to-migrate-a-postgresql-database.html" rel="alternate"/><published>2026-04-21T00:00:00-07:00</published><updated>2026-04-21T00:00:00-07:00</updated><author><name>Michael</name></author><id>tag:blog.unstablemuffin.com,2026-04-21:/how-to-migrate-a-postgresql-database.html</id><summary type="html">&lt;p&gt;How to migrate a PostgreSQL database from one server to&amp;nbsp;another&lt;/p&gt;</summary><content type="html">&lt;p&gt;This article will show you how to migrate a database from one PostgreSQL server to&amp;nbsp;another.&lt;/p&gt;
&lt;p&gt;Before starting the database migration, stop the service that is accessing the database to prevent a corrupt backup and/or missing data. This should also flush any cached data to the&amp;nbsp;disk.&lt;/p&gt;
&lt;h3 id="on-the-old-server"&gt;On the old&amp;nbsp;server&lt;/h3&gt;
&lt;p&gt;Dump the database contents from the old database to a&amp;nbsp;file.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;pg_dump&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;-h&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;ip_address&amp;gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-U&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;user&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;-d&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;database&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;-f&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;backup_file&amp;gt;.sql
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;pg_dump&lt;/code&gt; &amp;ndash; This is a PostgreSQL utility command that dumps all the data from a PostgreSQL database to a file. This includes not only the data but also indexes, schema, autoincrement states, and everything else that represents the state of the database at the time the backup was&amp;nbsp;made.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-h &amp;lt;ip_address&amp;gt;&lt;/code&gt; &amp;ndash; This specifies where to find the PostgreSQL database to dump from. If this command is run on the same machine as the database, it can be omitted and will default to the current&amp;nbsp;machine. &lt;/li&gt;
&lt;li&gt;&lt;code&gt;-U &amp;lt;user&amp;gt;&lt;/code&gt; &amp;ndash; This is the username of the &lt;span class="caps"&gt;SQL&lt;/span&gt; user to access the database. Make sure it has permissions to access the&amp;nbsp;database.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-d &amp;lt;database&amp;gt;&lt;/code&gt; &amp;ndash; The name of the database to&amp;nbsp;backup.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-f &amp;lt;backup_file&amp;gt;.sql&lt;/code&gt; &amp;ndash; This specifies the name of the file to dump the database to. Note that the output of this command is plaintext &lt;span class="caps"&gt;SQL&lt;/span&gt; statements, so the file extension should&amp;nbsp;be &lt;code&gt;.sql&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The contents of the backup file is plaintext &lt;span class="caps"&gt;SQL&lt;/span&gt;, so you can view and modify the backup if desired. This can be helpful to adjust usernames, database names, and permissions if you want them to be different on the new server than the old one. When the backup is restored, it will execute every line in the file one-by-one to recreated the database. Any changes to the backup will be executed as&amp;nbsp;well.&lt;/p&gt;
&lt;h3 id="on-the-new-server"&gt;On the new&amp;nbsp;server&lt;/h3&gt;
&lt;p&gt;First, connect to the new&amp;nbsp;database.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;-u&lt;span class="w"&gt; &lt;/span&gt;postgres&lt;span class="w"&gt; &lt;/span&gt;psql
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Create the database&amp;nbsp;user.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;USER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;db_user&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;WITH&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;PASSWORD&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;&amp;lt;password&amp;gt;&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Create the&amp;nbsp;database.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;DATABASE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;db_name&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;OWNER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;db_user&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Finally, grant the new user all permissions and privileges on the newly created&amp;nbsp;database.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;GRANT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ALL&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;ON&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;SCHEMA&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;public&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TO&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;db_user&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Once the user and database are created in the new server, you can exit the PostgreSQL command line&amp;nbsp;(&lt;code&gt;\q&lt;/code&gt;). The next step is to configure PostgreSQL to allow access to the new database for this user. Open the access configuration file for PostgreSQL in any&amp;nbsp;editor.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;nano&lt;span class="w"&gt; &lt;/span&gt;/etc/postgresql/&amp;lt;version&amp;gt;/main/pg_hba.conf
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;And add a line like the&amp;nbsp;following:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;TYPE&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="nx"&gt;DATABASE&lt;/span&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;USER&lt;/span&gt;&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;ADDRESS&lt;/span&gt;&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nx"&gt;METHOD&lt;/span&gt;
&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="k"&gt;type&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;database&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;db_user&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;ip_address&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nx"&gt;auth_type&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;type&amp;gt;&lt;/code&gt; &amp;ndash; This specifies the type of connection. Valid options&amp;nbsp;include &lt;code&gt;local&lt;/code&gt;, &lt;code&gt;host&lt;/code&gt;, &lt;code&gt;hostssl&lt;/code&gt;,&amp;nbsp;and &lt;code&gt;hostnossl&lt;/code&gt;. &lt;code&gt;local&lt;/code&gt; is for connections over the PostgreSQL Unix&amp;nbsp;socket. &lt;code&gt;host&lt;/code&gt; is for &lt;span class="caps"&gt;TCP&lt;/span&gt;/&lt;span class="caps"&gt;IP&lt;/span&gt; connections (either remote or via&amp;nbsp;localhost). &lt;code&gt;hostssl&lt;/code&gt; and &lt;code&gt;hostnossl&lt;/code&gt; are for specifically &lt;span class="caps"&gt;TCP&lt;/span&gt;/&lt;span class="caps"&gt;IP&lt;/span&gt; conections that are required to have &lt;span class="caps"&gt;SSL&lt;/span&gt; encryption or&amp;nbsp;not. &lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;database&amp;gt;&lt;/code&gt; &amp;ndash; This is the name of the database this record allows access&amp;nbsp;to.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;db_user&amp;gt;&lt;/code&gt; &amp;ndash; This is the user that is being allowed access to the above&amp;nbsp;database.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;ip_address&amp;gt;&lt;/code&gt; &amp;ndash; This is the &lt;span class="caps"&gt;IP&lt;/span&gt; address from which the specified user is allowed to connect to the specified database. The format should be &lt;span class="caps"&gt;IP&lt;/span&gt; address and subnet. A subnet&amp;nbsp;of &lt;code&gt;/32&lt;/code&gt; corresponds to a single &lt;span class="caps"&gt;IP&lt;/span&gt; address, so something&amp;nbsp;like &lt;code&gt;127.0.0.1/32&lt;/code&gt; would correspond to only allowing connections from localhost over IPv4. For access from Docker containers, which have dynamic &lt;span class="caps"&gt;IP&lt;/span&gt; addresses, you should whitelist the entire Docker&amp;nbsp;subnet: &lt;code&gt;172.22.0.0/16&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;auth_type&amp;gt;&lt;/code&gt; &amp;ndash; This is the type of authentication required for this method of access. Options&amp;nbsp;include &lt;code&gt;trust&lt;/code&gt;, &lt;code&gt;reject&lt;/code&gt;, &lt;code&gt;md5&lt;/code&gt;, &lt;code&gt;password&lt;/code&gt;, &lt;code&gt;scram-sha-256&lt;/code&gt;,&amp;nbsp;and &lt;code&gt;peer&lt;/code&gt;, among&amp;nbsp;others.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;trust&lt;/code&gt; will implicitly trust this connection and not require any authentication at&amp;nbsp;all. &lt;/li&gt;
&lt;li&gt;&lt;code&gt;reject&lt;/code&gt; will reject this connection. This is useful in conjuction with other records, which allow you to fine tune access. Records are evaluated from top to bottom and terminate on the first match, so you can reject a specific &lt;span class="caps"&gt;IP&lt;/span&gt; address at the top of the file, and then accept a broader range of &lt;span class="caps"&gt;IP&lt;/span&gt; addresses lower in the&amp;nbsp;file. &lt;/li&gt;
&lt;li&gt;&lt;code&gt;md5&lt;/code&gt; will accept a password with &lt;span class="caps"&gt;SCRAM&lt;/span&gt;-&lt;span class="caps"&gt;SHA&lt;/span&gt;-256 &lt;em&gt;or&lt;/em&gt; &lt;span class="caps"&gt;MD5&lt;/span&gt; hashing algorithm. &lt;span class="caps"&gt;MD5&lt;/span&gt; is easily cracked with modern machines and is not considered secure. This authentication method is deprecated and will be removed in future version of&amp;nbsp;PostgreSQL.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;password&lt;/code&gt; requires the client to send their password unencrypted to the server. The password is transmitted in cleartext, so this authentication method is not recommended on untrusted&amp;nbsp;networks. &lt;/li&gt;
&lt;li&gt;&lt;code&gt;scram-sha-256&lt;/code&gt; will required strong encryption for the&amp;nbsp;password. &lt;/li&gt;
&lt;li&gt;&lt;code&gt;peer&lt;/code&gt; authentication will check if the user connecting has an &lt;span class="caps"&gt;OS&lt;/span&gt; account that matches the name of a database user. If so, it will allow the connection. This authentication method is only valid&amp;nbsp;on &lt;code&gt;local&lt;/code&gt; connection&amp;nbsp;types.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you intend to allow connections from other devices or networks, you must change PostgreSQL&amp;rsquo;s configuration to bind to all network interfaces. By default it is only bound to localhost, and connections from another network (e.g. another computer or even Docker running on the same machine) will&amp;nbsp;fail. &lt;/p&gt;
&lt;p&gt;To configure PostgreSQL to bind to all available interfaces, modify the config file&amp;nbsp;at &lt;code&gt;/etc/postgresql/&amp;lt;version&amp;gt;/main/postgresql.conf&lt;/code&gt; and change the following&amp;nbsp;line:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nx"&gt;listen_addresses&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="sc"&gt;&amp;#39;*&amp;#39;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;After saving the changes to the configuration, trigger a reload to force PostgreSQL to update its configuration. If you changed&amp;nbsp;the &lt;code&gt;listen_addresses&lt;/code&gt; config, you&amp;nbsp;must &lt;code&gt;restart&lt;/code&gt; the PostgreSQL service instead of just reloading&amp;nbsp;it.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;systemctl&lt;span class="w"&gt; &lt;/span&gt;reload&lt;span class="w"&gt; &lt;/span&gt;postgresql
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Finally, restore the database backup to the new&amp;nbsp;database.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;psql&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;-h&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;ip_address&amp;gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-U&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;user&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;-d&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;database&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;-f&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;backup_file&amp;gt;.sql
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;psql&lt;/code&gt; &amp;ndash; This is the command that connects to a PostgreSQL&amp;nbsp;server.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-h &amp;lt;ip_address&amp;gt;&lt;/code&gt; &amp;ndash; Host of the new database server. If the backup file was copied to the new server and this command is being run on the same device as the database being restored to, this can be&amp;nbsp;omitted.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-U &amp;lt;user&amp;gt;&lt;/code&gt; &amp;ndash; The username to connect with. Should be the same as the old&amp;nbsp;one.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-d &amp;lt;database&amp;gt;&lt;/code&gt; &amp;ndash; The database name. Should be the same as the old&amp;nbsp;one.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-f &amp;lt;backup_file&amp;gt;.sql&lt;/code&gt; &amp;ndash; The file containing the backed up data created&amp;nbsp;from &lt;code&gt;pg_dump&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Now the data should be restored to the new database. Point the service to the new database and start it up, and it should connect and appear that nothing has&amp;nbsp;changed.&lt;/p&gt;</content><category term="Technical"/><category term="how-to"/></entry><entry><title>Top Chef S23E03 - True Colors</title><link href="https://blog.unstablemuffin.com/top-chef-s23e03-true-colors.html" rel="alternate"/><published>2026-03-29T00:00:00-07:00</published><updated>2026-03-29T00:00:00-07:00</updated><author><name>Michael</name></author><id>tag:blog.unstablemuffin.com,2026-03-29:/top-chef-s23e03-true-colors.html</id><summary type="html">&lt;p&gt;Lackluster liver, color controversies, and incidental&amp;nbsp;injuries.&lt;/p&gt;</summary><content type="html">&lt;p&gt;It&amp;rsquo;s episode three, and the gloves are coming off. We were riding high last episode, but everything that goes up must come down. We had a deeply unappetizing quick fire, and barely anyone met the brief for the elimination challenge. The judges are fed slop and are mad about it. Jennifer has fallen out of a tree prior to filming and now has to compete with an injury. It&amp;rsquo;s a flop-fest for the ages, and I&amp;rsquo;m&amp;nbsp;living. &lt;/p&gt;
&lt;h3 id="quick-fire"&gt;Quick&amp;nbsp;Fire&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;span class="dquo"&gt;&amp;ldquo;&lt;/span&gt;You poor thing.&amp;rdquo; – She is not a wounded animal, Justin. Have some freaking empathy for your&amp;nbsp;wife.&lt;/li&gt;
&lt;li&gt;Shout out to Rhoda killing it&amp;nbsp;👏👏👏&lt;/li&gt;
&lt;li&gt;These brothers are gay af. Hiding their cooking show like it&amp;rsquo;s some sort of deep rooted shame. I don&amp;rsquo;t care if they have wives, we know the&amp;nbsp;truth.&lt;/li&gt;
&lt;li&gt;Livermush? Really? Talk about an unappetizing challenge. And I wouldn&amp;rsquo;t call it &amp;ldquo;iconic&amp;rdquo;; I&amp;rsquo;ve never heard of&amp;nbsp;it.&lt;/li&gt;
&lt;li&gt;One of my favorite moments from this episode is Emeril Lagousky being shocked at how much money the winner of the Quick Fire will win lol He&amp;rsquo;s been on Top Chef since 2009, so he knows how much previous &lt;em&gt;winners&lt;/em&gt; walked home with&amp;nbsp;😆&lt;/li&gt;
&lt;li&gt;&lt;span class="caps"&gt;SCRAPPLE&lt;/span&gt;?!? That&amp;rsquo;s not real. You cannot convince me that&amp;rsquo;s&amp;nbsp;real.&lt;/li&gt;
&lt;li&gt;&lt;span class="caps"&gt;NO&lt;/span&gt;, &lt;span class="caps"&gt;NOT&lt;/span&gt; &lt;span class="caps"&gt;JENNIFER&lt;/span&gt;&amp;nbsp;😩😩😩&lt;/li&gt;
&lt;li&gt;Justin is totally unbothered by his wife&amp;rsquo;s condition. He is continuing to cook&amp;nbsp;unperturbed. &lt;/li&gt;
&lt;li&gt;Why is there a monopoly on wins this season? Laurence winning both quick fires are Rhoda winning both elimination&amp;nbsp;challenges?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img alt="Conspiracy" src="https://media3.giphy.com/media/v1.Y2lkPTc5MGI3NjExc2pyM211MGVvbHl4dHlsNno3bDZvNWxib213dXoyaTkwY2JncXJwNiZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/tmJYNJLNSkfI0JcEho/giphy.gif" class="img-fluid mx-auto shadow-lg" width=200&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;If you ate a &amp;ldquo;liver spread&amp;rdquo; growing up, I think that qualifies as child&amp;nbsp;abuse.&lt;/li&gt;
&lt;li&gt;&lt;span class="dquo"&gt;&amp;ldquo;&lt;/span&gt;I hope you all de-liver!&amp;rdquo; – That was a weak-ass pun. Up your pun game,&amp;nbsp;people.&lt;/li&gt;
&lt;li&gt;Nana is failing again.&amp;nbsp;🤦‍♂️&lt;/li&gt;
&lt;li&gt;&lt;span class="dquo"&gt;&amp;ldquo;&lt;/span&gt;I got stuff on the plate 😃&amp;rdquo; – Never change, Nana. Never&amp;nbsp;change.&lt;/li&gt;
&lt;li&gt;What is everyone laughing at? There was no&amp;nbsp;joke.&lt;/li&gt;
&lt;li&gt;At least Laurence&amp;rsquo;s reign of terror is over for the Quick&amp;nbsp;Fire.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="elimination-challenge"&gt;Elimination&amp;nbsp;Challenge&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Edible garment challenge&amp;nbsp;when???&lt;/li&gt;
&lt;li&gt;I love a competitor that immediately chooses to ignore the brief and do something else. That always works out for them,&amp;nbsp;definitely.&lt;/li&gt;
&lt;li&gt;I actually love this challenge! It&amp;rsquo;s like if Instagram food had to taste&amp;nbsp;good.&lt;/li&gt;
&lt;li&gt;My poor Jennifer&amp;nbsp;☹️&lt;/li&gt;
&lt;li&gt;Justin seems annoyed that his injured wife is calling him, and it&amp;rsquo;s up to the other contestants to fill her in on what the challenge is. Are we sure he even likes his&amp;nbsp;wife???&lt;/li&gt;
&lt;li&gt;&lt;span class="dquo"&gt;&amp;ldquo;&lt;/span&gt;Psychedelic ceviche. We&amp;rsquo;re going acid trip.&amp;rdquo; – More drugs. This season is obsessed with&amp;nbsp;drugs.&lt;/li&gt;
&lt;li&gt;Nana? Not good with time management skills? Say it isn&amp;rsquo;t&amp;nbsp;so.&lt;/li&gt;
&lt;li&gt;I love Oscar&amp;rsquo;s minigame at the checkout register! I feel like it should be integrated into the show&amp;nbsp;somehow.&lt;/li&gt;
&lt;li&gt;Justin was bad at school? No wonder he&amp;rsquo;s dumb&amp;nbsp;af&lt;/li&gt;
&lt;li&gt;Black pork? There&amp;rsquo;s a reason nobody has ever heard of&amp;nbsp;that.&lt;/li&gt;
&lt;li&gt;Whole Foods does not sell chlorophyll. Where is he getting these potions and&amp;nbsp;tinctures?&lt;/li&gt;
&lt;li&gt;None of the jokes this episode are funny. If the chefs are this unfunny we should just edit it all out at this&amp;nbsp;point.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;span class="caps"&gt;BAO&lt;/span&gt;-&lt;span class="caps"&gt;GATE&lt;/span&gt;&lt;/strong&gt;&amp;nbsp;🚨🚨🚨&lt;/li&gt;
&lt;li&gt;What &lt;em&gt;is&lt;/em&gt; activated charcoal? Which begs the question, what is &lt;em&gt;un&lt;/em&gt;activated charcoal? How does one activate&amp;nbsp;charcoal?&lt;/li&gt;
&lt;li&gt;We all know Jennifer&amp;rsquo;s dough is not going to rise&amp;nbsp;tomorrow.&lt;/li&gt;
&lt;li&gt;Matching pajamas? Face masks? Mean&amp;nbsp;Girls.&lt;/li&gt;
&lt;li&gt;He&amp;rsquo;s finger&amp;nbsp;painting&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;span class="caps"&gt;STUFFING&lt;/span&gt;-&lt;span class="caps"&gt;GATE&lt;/span&gt;&lt;/strong&gt;&amp;nbsp;🚨🚨🚨&lt;/li&gt;
&lt;li&gt;Love Brittany&amp;nbsp;❤️&lt;/li&gt;
&lt;li&gt;Why is there so much grunting this&amp;nbsp;episode?!?&lt;/li&gt;
&lt;li&gt;Nana &lt;span class="amp"&gt;&amp;amp;&lt;/span&gt; cooking everything twice; name a more iconic duo. I&amp;rsquo;ll&amp;nbsp;wait.&lt;/li&gt;
&lt;li&gt;&lt;span class="dquo"&gt;&amp;ldquo;&lt;/span&gt;Take your time. Food is good.&amp;rdquo; – Girl you don&amp;rsquo;t &lt;em&gt;have&lt;/em&gt; time, that&amp;rsquo;s your&amp;nbsp;problem!&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;span class="caps"&gt;CHINESE&lt;/span&gt; &lt;span class="caps"&gt;ROCK&lt;/span&gt; &lt;span class="caps"&gt;BAND&lt;/span&gt;?!?!?!?&lt;/strong&gt; Badass alert.&amp;nbsp;🚨🚨🚨&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;span class="caps"&gt;SABOTAGE&lt;/span&gt;?!?&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;oh no, nana&amp;nbsp;:/&lt;/li&gt;
&lt;li&gt;She only gets so many changes,&amp;nbsp;though.&lt;/li&gt;
&lt;li&gt;&lt;span class="dquo"&gt;&amp;ldquo;&lt;/span&gt;She stresses me out&amp;rdquo;&amp;nbsp;–Aaron&lt;/li&gt;
&lt;li&gt;&lt;span class="dquo"&gt;&amp;ldquo;&lt;/span&gt;It&amp;rsquo;s not the first time. 😐&amp;rdquo; –&amp;nbsp;Ouch.&lt;/li&gt;
&lt;li&gt;Brandon is trying his best to salvage the situation, but what is there to really say when the chef puts themself into this position over and over and over&amp;nbsp;again.&lt;/li&gt;
&lt;li&gt;That pork looks shat&amp;nbsp;upon&lt;/li&gt;
&lt;li&gt;That mole looks beautiful&amp;nbsp;😍&lt;/li&gt;
&lt;li&gt;&lt;span class="dquo"&gt;&amp;ldquo;&lt;/span&gt;Hopefully it&amp;rsquo;s edible&amp;rdquo; – I&amp;rsquo;ll take &amp;ldquo;Things You Shouldn&amp;rsquo;t Say to the Judges When Presenting Your Dish&amp;rdquo; for 600,&amp;nbsp;Alex.&lt;/li&gt;
&lt;li&gt;Isn&amp;rsquo;t mole something you eat with something else? Like a tortilla or something? It looks like they have to eat it like a soup, which doesn&amp;rsquo;t sound&amp;nbsp;appealing.&lt;/li&gt;
&lt;li&gt;If Nana gets a free pass because Jennifer has to leave the competition due to her injury, I&amp;rsquo;m gonna freak out. Not like a cute little freak out, like &lt;strong&gt;&lt;em&gt;&lt;span class="caps"&gt;FREAK&lt;/span&gt;. &lt;span class="caps"&gt;OUT&lt;/span&gt;.&lt;/em&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;The color lady is correct,&amp;nbsp;unfortunately. &lt;/li&gt;
&lt;li&gt;I demand Jennifer come back for another&amp;nbsp;season.&lt;/li&gt;
&lt;li&gt;&lt;span class="dquo"&gt;&amp;ldquo;&lt;/span&gt;This is my cochinita pork&amp;rdquo; – What did he just call&amp;nbsp;me?&lt;/li&gt;
&lt;li&gt;&lt;span class="dquo"&gt;&amp;ldquo;&lt;/span&gt;Bao. Bao bao bao. Bao bao bao. Bao bao.&amp;rdquo; –&amp;nbsp;&amp;hellip;what.&lt;/li&gt;
&lt;li&gt;Oh, I suppose the chlorophyll may have been provided to the contestants for this particular challenge. That makes&amp;nbsp;sense.&lt;/li&gt;
&lt;li&gt;That is a beautiful&amp;nbsp;scallop.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;span class="caps"&gt;COLOR&lt;/span&gt;-&lt;span class="caps"&gt;GATE&lt;/span&gt;&lt;/strong&gt;&amp;nbsp;🚨🚨🚨&lt;/li&gt;
&lt;li&gt;&lt;span class="dquo"&gt;&amp;ldquo;&lt;/span&gt;That thing is white as white can be&amp;rdquo; – Wow, they&amp;rsquo;re talking about me&amp;nbsp;🤩&lt;/li&gt;
&lt;li&gt;&lt;span class="dquo"&gt;&amp;ldquo;&lt;/span&gt;Very hot! And I&amp;rsquo;m not talking about the pot!&amp;rdquo; – Heck yes, Sherry can &lt;strong&gt;&lt;span class="caps"&gt;GET&lt;/span&gt; &lt;span class="caps"&gt;IT&lt;/span&gt;&lt;/strong&gt;!&lt;/li&gt;
&lt;li&gt;What the actual heck, is that a pot of bloody&amp;nbsp;fingers?!?&lt;/li&gt;
&lt;li&gt;&lt;span class="dquo"&gt;&amp;ldquo;&lt;/span&gt;It looks like an ice cream sandwich and puked up code slaw.&amp;rdquo; –Aaron (And I can&amp;rsquo;t disagree with&amp;nbsp;him)&lt;/li&gt;
&lt;li&gt;&lt;span class="dquo"&gt;&amp;ldquo;&lt;/span&gt;Lamb and clams&amp;rdquo; needs to die a horrific death. It&amp;rsquo;s like if Surf &amp;lsquo;n&amp;rsquo; turf had an uglier, stupider&amp;nbsp;sister.&lt;/li&gt;
&lt;li&gt;She &lt;span class="caps"&gt;KISSED&lt;/span&gt; it on the grill?!? Is that&amp;nbsp;sanitary?!?!?&lt;/li&gt;
&lt;li&gt;&lt;span class="dquo"&gt;&amp;ldquo;&lt;/span&gt;Every single thing tasted really good.&amp;rdquo; – Did it&amp;nbsp;though?&lt;/li&gt;
&lt;li&gt;Last week everyone did so well, and this week everyone is flopping. Like, &lt;strong&gt;&lt;span class="caps"&gt;MAJOR&lt;/span&gt;&lt;/strong&gt;&amp;nbsp;flop-ageddon.&lt;/li&gt;
&lt;li&gt;&lt;span class="dquo"&gt;&amp;ldquo;&lt;/span&gt;Don&amp;rsquo;t say that please&amp;rdquo;&amp;nbsp;😬&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;span class="caps"&gt;OVERTHINKING&lt;/span&gt;-&lt;span class="caps"&gt;GATE&lt;/span&gt;&lt;/strong&gt;&amp;nbsp;🚨🚨🚨&lt;/li&gt;
&lt;li&gt;oh no, Tom is getting grumpy&amp;nbsp;☹️&lt;/li&gt;
&lt;li&gt;What on earth was Oscar&amp;rsquo;s movie reference? That made literally no&amp;nbsp;sense.&lt;/li&gt;
&lt;li&gt;&lt;span class="dquo"&gt;&amp;ldquo;&lt;/span&gt;Rhoda&amp;rsquo;s dish looks like an oil spill&amp;rdquo;&amp;nbsp;–Aaron&lt;/li&gt;
&lt;li&gt;&lt;span class="dquo"&gt;&amp;ldquo;&lt;/span&gt;That might be the least colorful ceviche I&amp;rsquo;ve ever seen in my life&amp;rdquo; – Savage. Accurate, but&amp;nbsp;savage.&lt;/li&gt;
&lt;li&gt;&lt;span class="dquo"&gt;&amp;ldquo;&lt;/span&gt;Gray parsnip&amp;rdquo; is my new favorite&amp;nbsp;insult.&lt;/li&gt;
&lt;li&gt;The judges want blood, and I want to see them have&amp;nbsp;it.&lt;/li&gt;
&lt;li&gt;Laurence has to stop winning. Somebody stop&amp;nbsp;him.&lt;/li&gt;
&lt;li&gt;They want to talk to &lt;strong&gt;&lt;em&gt;&lt;span class="caps"&gt;EVERYONE&lt;/span&gt; &lt;span class="caps"&gt;ELSE&lt;/span&gt;?!?&lt;/em&gt;&lt;/strong&gt; Hot&amp;nbsp;diggity.&lt;/li&gt;
&lt;li&gt;Eliminate them&amp;nbsp;all.&lt;/li&gt;
&lt;li&gt;It was&amp;nbsp;flaccid.&lt;/li&gt;
&lt;li&gt;&lt;span class="caps"&gt;NANA&lt;/span&gt; &lt;span class="caps"&gt;HAS&lt;/span&gt; &lt;span class="caps"&gt;DIED&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;That was&amp;nbsp;abrupt.&lt;/li&gt;
&lt;li&gt;She&amp;rsquo;s going to fail miserably in Last Chance Kitchen. She can&amp;rsquo;t time anything, and that&amp;rsquo;s a major component of &lt;span class="caps"&gt;LCK&lt;/span&gt;.&lt;/li&gt;
&lt;/ul&gt;</content><category term="Personal"/><category term="tv"/><category term="top-chef"/></entry><entry><title>Top Chef S23E02 - Puckerbutt</title><link href="https://blog.unstablemuffin.com/top-chef-s23e02-puckerbutt.html" rel="alternate"/><published>2026-03-23T00:00:00-07:00</published><updated>2026-03-23T00:00:00-07:00</updated><author><name>Michael</name></author><id>tag:blog.unstablemuffin.com,2026-03-23:/top-chef-s23e02-puckerbutt.html</id><summary type="html">&lt;p&gt;Spicy food, spicy editing, and Justin still makes me want to set myself on&amp;nbsp;fire.&lt;/p&gt;</summary><content type="html">&lt;p&gt;We&amp;rsquo;re back with another episode of Top Chef. Things are heating up (literally and figuratively) and personalities are starting to clash. The bonds that were once so tightly knit are starting to fray in the heat of the kitchen. (I&amp;rsquo;m going full cliché, deal with it.) Favorites are beginning to emerge from the pack, while others are starting to feel like they&amp;rsquo;re running out of runway. The editing has gone avant-garde, for some reason. Despite my best efforts, Justin is still here. Let&amp;rsquo;s jump into&amp;nbsp;it.&lt;/p&gt;
&lt;h3 id="quick-fire"&gt;Quick&amp;nbsp;Fire&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Could you imagine growing up on a psychedelic milk farm? Feels like the premise of a horror&amp;nbsp;game.&lt;/li&gt;
&lt;li&gt;They&amp;rsquo;re &lt;span class="caps"&gt;COMMITTED&lt;/span&gt; to elevating the gelato experience. &lt;strong&gt;&lt;em&gt;&lt;span class="caps"&gt;COMMITTED&lt;/span&gt;!!!&lt;/em&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;I still &lt;span class="caps"&gt;HATE&lt;/span&gt; the married couple.&amp;nbsp;*retch*&lt;/li&gt;
&lt;li&gt;Please don&amp;rsquo;t call the other contestants &amp;ldquo;babe&amp;rdquo;. It&amp;rsquo;s making everyone uncomfortable. Now is not the time to try out your gay friends&amp;rsquo; slang. This is not allyship; it is&amp;nbsp;appropriation.&lt;/li&gt;
&lt;li&gt;Guys, he feels &lt;em&gt;good&lt;/em&gt; about it. Time doesn&amp;rsquo;t matter because he feels &lt;em&gt;&lt;span class="caps"&gt;GOOD&lt;/span&gt;&lt;/em&gt; about&amp;nbsp;it.&lt;/li&gt;
&lt;li&gt;If there&amp;rsquo;s anything I&amp;rsquo;ve learned from watching 22 seasons of Top Chef, it&amp;rsquo;s that a lingering shot of the grill means there&amp;rsquo;s gonna be some drama later. Mark my&amp;nbsp;words. &lt;/li&gt;
&lt;li&gt;Okay, I&amp;rsquo;m about to say something controversial. Yes, I still hate the couple. &lt;em&gt;~But~&lt;/em&gt;&amp;hellip; Jennifer (the wife) is starting to grow on me a little bit? She seems cool. I &lt;span class="caps"&gt;KNOW&lt;/span&gt; I &lt;span class="caps"&gt;KNOW&lt;/span&gt; &lt;span class="caps"&gt;PLEASE&lt;/span&gt; &lt;span class="caps"&gt;PUT&lt;/span&gt; &lt;span class="caps"&gt;THE&lt;/span&gt; &lt;span class="caps"&gt;PITCHFORKS&lt;/span&gt; &lt;span class="caps"&gt;DOWN&lt;/span&gt; I&amp;rsquo;M &lt;span class="caps"&gt;SOR&lt;/span&gt;–&lt;/li&gt;
&lt;li&gt;Called it. That pork tenderloin is &lt;span class="caps"&gt;TOAST&lt;/span&gt; (pun abso-freaking-lutely&amp;nbsp;intended)&lt;/li&gt;
&lt;li&gt;&lt;span class="caps"&gt;NO&lt;/span&gt; &lt;span class="caps"&gt;STOP&lt;/span&gt; &lt;span class="caps"&gt;IT&lt;/span&gt; &lt;span class="caps"&gt;WITH&lt;/span&gt; &lt;span class="caps"&gt;THE&lt;/span&gt; &amp;ldquo;my boo 😘&amp;rdquo; &lt;span class="caps"&gt;AUTOMATIC&lt;/span&gt; &lt;span class="caps"&gt;DISQUALIFICATION&lt;/span&gt;, &lt;span class="caps"&gt;CUE&lt;/span&gt; &lt;span class="caps"&gt;THE&lt;/span&gt; &lt;span class="caps"&gt;SNIPERS&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span class="caps"&gt;HE&lt;/span&gt; &lt;span class="caps"&gt;DJS&lt;/span&gt;?!?!?!?!?&lt;/li&gt;
&lt;li&gt;The pork was too thick&amp;nbsp;=(&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;span class="caps"&gt;RAW&lt;/span&gt; &lt;span class="caps"&gt;PORK&lt;/span&gt;-&lt;span class="caps"&gt;GATE&lt;/span&gt;&lt;/strong&gt;&amp;nbsp;🚨🚨🚨&lt;/li&gt;
&lt;li&gt;&lt;span class="dquo"&gt;&amp;ldquo;&lt;/span&gt;I plated up!&amp;rdquo; – God I love Nana so much, she&amp;rsquo;s a fighter and I will die for her. &lt;span class="caps"&gt;SHE&lt;/span&gt; &lt;span class="caps"&gt;BETTER&lt;/span&gt; &lt;span class="caps"&gt;MAKE&lt;/span&gt; &lt;span class="caps"&gt;IT&lt;/span&gt; &lt;span class="caps"&gt;FAR&lt;/span&gt;, &lt;span class="caps"&gt;DON&lt;/span&gt;&amp;rsquo;T &lt;span class="caps"&gt;LET&lt;/span&gt; &lt;span class="caps"&gt;ME&lt;/span&gt; &lt;span class="caps"&gt;DOWN&lt;/span&gt; &lt;span class="caps"&gt;NANA&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;I don&amp;rsquo;t think I understand what a &amp;ldquo;garnish&amp;rdquo; is, because I thought it was a little inedible thing that sat on the side of the plate to make it prettier. But these people are calling entire components of the dish &amp;ldquo;garnish&amp;rdquo; and I am severely confused. Parsley is a garnish, not a custom made coffee-chili pickle that contains &lt;em&gt;the&lt;/em&gt; highlight ingredient of your&amp;nbsp;dish.&lt;/li&gt;
&lt;li&gt;&lt;span class="dquo"&gt;&amp;ldquo;&lt;/span&gt;Oh, gelato in the sauce? 🤨&amp;rdquo; – When will these people learn to &lt;strong&gt;&lt;span class="caps"&gt;FOLLOW&lt;/span&gt; &lt;span class="caps"&gt;THE&lt;/span&gt; &lt;span class="caps"&gt;BRIEF&lt;/span&gt;!!!&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;span class="dquo"&gt;&amp;ldquo;&lt;/span&gt;Mostarda&amp;rdquo; sounds like a&amp;nbsp;slur&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="elimination-challenge"&gt;Elimination&amp;nbsp;Challenge&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;I cannot believe they&amp;rsquo;re allowed to say &amp;ldquo;pucker butt&amp;rdquo; on national television. This has to be an&amp;nbsp;oversight.&lt;/li&gt;
&lt;li&gt;No spice fam represent! Thank you Jassi, I see you. Except, you know, I&amp;rsquo;m almost offensively white so nobody questions it when I order -1 out of 5 spiciness. But regardless, it&amp;rsquo;s nice to see my spice-intolerance represented on a culinary&amp;nbsp;show.&lt;/li&gt;
&lt;li&gt;I do like the concept of this challenge a lot, where each dish has to be spicier than the last. It really forces the competitors to work together at each step of the competition from menu creation to execution to plating to make sure each dish is spicier than the last. It&amp;rsquo;d be so incredibly easy for a dish to get way too spicy, and then you have to choose between having a dish out of order or to ramp up the rest of the dishes spiciness at the last second, risking getting too spicy or throwing the dish out of balance. There&amp;rsquo;s a lot to think about in this one and I don&amp;rsquo;t think the editing does it&amp;nbsp;justice.&lt;/li&gt;
&lt;li&gt;Surprise twin appearance! I don&amp;rsquo;t blame him; I, too, combine them into a single person when they&amp;rsquo;re not on screen together. There&amp;rsquo;s simply nothing to differentiate them&amp;nbsp;yet.&lt;/li&gt;
&lt;li&gt;This editing is so over the top lol I don&amp;rsquo;t hate it but it&amp;rsquo;s so out of left field for Top Chef. I can&amp;rsquo;t tell if they&amp;rsquo;re trying to court the TikTok generation with some loony edits, or if they&amp;rsquo;re just trying out a looser, less serious editing style for this season. I guess only time will tell which one they&amp;rsquo;re going for and if it works or&amp;nbsp;not.&lt;/li&gt;
&lt;li&gt;Why is this episode so drug heavy??? First the psychedelic milk farm, and now pepper induced hallucinations! What&amp;rsquo;s next, a Quick Fire challenge with&amp;nbsp;marijuana???&lt;/li&gt;
&lt;li&gt;What on earth is she crab soup?? Has feminism finally gone too far? It&amp;rsquo;s just a crab, why you gotta gender it? Did you ever think it could be they/them crab soup? Of course not. You only think of&amp;nbsp;yourself.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;span class="caps"&gt;GROCERY&lt;/span&gt; &lt;span class="caps"&gt;PRICE&lt;/span&gt;-&lt;span class="caps"&gt;GATE&lt;/span&gt;&lt;/strong&gt;&amp;nbsp;🚨🚨🚨&lt;/li&gt;
&lt;li&gt;Red team is totally going to run out of ingredients. They&amp;rsquo;re all kumbaya about sharing ingredients now but when they&amp;rsquo;re in the kitchen fighting over the last arugula they&amp;rsquo;re not going to be so Mother Theresa about&amp;nbsp;it.&lt;/li&gt;
&lt;li&gt;Guest appearance by my husband when Justin was totally unbothered during grocery price-gate: &amp;ldquo;Sounds like somebody has&amp;nbsp;kids&amp;rdquo;&lt;/li&gt;
&lt;li&gt;The music supervisor is really popping off this episode with that sick transition between classical and rock music. Emmy&amp;nbsp;material.&lt;/li&gt;
&lt;li&gt;&lt;span class="dquo"&gt;&amp;ldquo;&lt;/span&gt;Emulsion&amp;rdquo; is such a sexless word. You can&amp;rsquo;t say it without really deflating the entire&amp;nbsp;room.&lt;/li&gt;
&lt;li&gt;Somebody just called &amp;ldquo;spicy boy Oscar&amp;rdquo; sexy and I want to vomit. What is wrong with these&amp;nbsp;sickos?&lt;/li&gt;
&lt;li&gt;Chicken wings, Justin? This man is such a&amp;nbsp;child.&lt;/li&gt;
&lt;li&gt;Motherly = bully?&amp;nbsp;Lol &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;span class="caps"&gt;RESPICE&lt;/span&gt;-&lt;span class="caps"&gt;GATE&lt;/span&gt;&lt;/strong&gt;&amp;nbsp;🚨🚨🚨&lt;/li&gt;
&lt;li&gt;&lt;span class="dquo"&gt;&amp;ldquo;&lt;/span&gt;I&amp;rsquo;m not going to re-season it again 😤&amp;rdquo; – How very &lt;em&gt;motherly&lt;/em&gt; of&amp;nbsp;her&lt;/li&gt;
&lt;li&gt;Tom Colicchio is immortal and you can&amp;rsquo;t change my mind about&amp;nbsp;it.&lt;/li&gt;
&lt;li&gt;&lt;span class="dquo"&gt;&amp;ldquo;&lt;/span&gt;I don&amp;rsquo;t sous vide often, but &amp;#8230; I don&amp;rsquo;t want to just sear any fish.&amp;rdquo; – I&amp;rsquo;m calling it: this is going to be one of the most fucked up fish we&amp;rsquo;ve ever&amp;nbsp;seen.&lt;/li&gt;
&lt;li&gt;I do not understand the critique where they call something &amp;ldquo;boring but delicious&amp;rdquo;. What are you going for here? Was it bad or was it&amp;nbsp;good?&lt;/li&gt;
&lt;li&gt;Jassi is just so happy to be here and I love that for him&amp;nbsp;lol&lt;/li&gt;
&lt;li&gt;Please stop saying &amp;ldquo;butt pucker&amp;rdquo; I&amp;rsquo;m begging you&amp;nbsp;😭😭😭&lt;/li&gt;
&lt;li&gt;Everyone is doing so well! I love to see it. It&amp;rsquo;s always a good episode when the judges have to nitpick between the top and the bottom because everyone did so&amp;nbsp;well.&lt;/li&gt;
&lt;li&gt;Oh, I get it. This is just Top Chef Hot&amp;nbsp;Ones.&lt;/li&gt;
&lt;li&gt;Did I call it or did I call it?! &lt;span class="caps"&gt;THE&lt;/span&gt; &lt;span class="caps"&gt;FISH&lt;/span&gt; &lt;span class="caps"&gt;IS&lt;/span&gt; &lt;span class="caps"&gt;NOT&lt;/span&gt; &lt;span class="caps"&gt;COOKED&lt;/span&gt; &lt;span class="caps"&gt;PROPERLY&lt;/span&gt;! &lt;strong&gt;&lt;span class="caps"&gt;STOP&lt;/span&gt; &lt;span class="caps"&gt;SABOTAGING&lt;/span&gt; &lt;span class="caps"&gt;YOURSELF&lt;/span&gt; &lt;span class="caps"&gt;NANA&lt;/span&gt;!!!&lt;/strong&gt;
&lt;img alt="I Was Rooting For You! We Were All Rooting For You! - America&amp;#39;S Next Top Model GIF" src="https://media0.giphy.com/media/v1.Y2lkPTc5MGI3NjExZW8zNDh6ZG4zZW1ud3ZhcHUzc290eTVpN3FmZWIyODk2ZGJyNWh3dSZlcD12MV9pbnRlcm5hbF9naWZfYnlfaWQmY3Q9Zw/tLRifcvQNJIic/giphy.gif"&gt;&lt;/li&gt;
&lt;li&gt;&lt;span class="dquo"&gt;&amp;ldquo;&lt;/span&gt;This is where you start sucking in the air&amp;rdquo; – Really? This episode is the Yucky Words Hall of Fame. They&amp;rsquo;re going to start describing dishes as&amp;nbsp;moist.&lt;/li&gt;
&lt;li&gt;I don&amp;rsquo;t know how many more ways I can say this, but Justin is the&amp;nbsp;worst.&lt;/li&gt;
&lt;li&gt;They just described Justin&amp;rsquo;s dish as &amp;ldquo;flabby&amp;rdquo; which I think describes his personality as&amp;nbsp;well.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Elimination prediction:&lt;/strong&gt; Bye bye&amp;nbsp;Jassi&lt;/li&gt;
&lt;li&gt;Although Nana has to stop fucking up because thin ice doesn&amp;rsquo;t even begin to describe what she&amp;rsquo;s skating&amp;nbsp;on.&lt;/li&gt;
&lt;/ul&gt;</content><category term="Personal"/><category term="tv"/><category term="top-chef"/></entry><entry><title>Top Chef S23E01 - Carolina Roots</title><link href="https://blog.unstablemuffin.com/top-chef-s23e01-carolina-roots.html" rel="alternate"/><published>2026-03-22T00:00:00-07:00</published><updated>2026-03-22T00:00:00-07:00</updated><author><name>Michael</name></author><id>tag:blog.unstablemuffin.com,2026-03-22:/top-chef-s23e01-carolina-roots.html</id><summary type="html">&lt;p&gt;Featuring hush puppy drama, an oven that was never on, and a freak-out that ends in a heartwarming&amp;nbsp;glow.&lt;/p&gt;</summary><content type="html">&lt;p&gt;Welcome to the personal section of my blog, where I write about things I care about with zero regard for facts or feelings. We&amp;rsquo;re kicking it off with a series I&amp;rsquo;ve decided to call Top Chef Reactions. No recaps, no analysis, just a real-time, unfiltered stream of consciousness from the dark recesses of my brain as words and pictures flash in front of my face. We&amp;rsquo;re starting with the currently airing season 23. There is drama. There is heartbreak. There&amp;rsquo;s somebody I want to hit over the head with a crudités. Let&amp;rsquo;s get into&amp;nbsp;it.&lt;/p&gt;
&lt;h3 id="quick-fire"&gt;Quick&amp;nbsp;Fire&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;&lt;span class="dquo"&gt;&amp;ldquo;&lt;/span&gt;I&amp;rsquo;m not here to play patty cake!&amp;rdquo;&lt;/strong&gt; – Well thank god somebody said it. I was starting to think everyone was here to play patty cake. Could you imagine? A season of all patty cakes?&amp;nbsp;Disgusting.&lt;/li&gt;
&lt;li&gt;Has it been too long since I&amp;rsquo;ve watched Top Chef or does there seem to be an unusually high amount of unearned confidence in this season&amp;rsquo;s cast? So many people are sure they&amp;rsquo;re gonna win. Like, relax. You&amp;rsquo;re all going to fail soon&amp;nbsp;enough.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;span class="dquo"&gt;&amp;ldquo;&lt;/span&gt;Five star, five diamond [restaurant]&amp;rdquo;&lt;/strong&gt; – Okay, hold on, record scratch. Five star five diamond? I don&amp;rsquo;t think we&amp;rsquo;re talking about Michelin stars anymore, because I think those only go up to three. Are you just bragging about your restaurant&amp;rsquo;s particularly good Yelp rating? And don&amp;rsquo;t piss me off with this &amp;ldquo;five diamond&amp;rdquo; bull crap. You&amp;rsquo;re just making stuff up&amp;nbsp;now.&lt;/li&gt;
&lt;li&gt;Hate the couple already. Annoyance meter is through the&amp;nbsp;roof.&lt;/li&gt;
&lt;li&gt;I just feel like I need to address the elephant in the room: Kristen is a baddie and Gail still makes me question my sexuality. There is no reason these women need to go so hard and yet here we are. Bravo continues to bless us with women who eat (literally) and leave no crumbs&amp;nbsp;(figuratively).&lt;/li&gt;
&lt;li&gt;Some challenges on Top Chef can be quite heavy handed and (dare I say it) a little forced, but I really love the twist for this first Quick Fire. Not having a real clock and having to time your cook based on cars racing around the track is a great way to test the chefs&amp;rsquo; ability to stay flexible with timing. I&amp;rsquo;m not sure if they were given a rough estimate of how much time it would take, but I hope they weren&amp;rsquo;t and had to speed up and/or slow down based on how much they over/underestimated the speed of the cars. I&amp;rsquo;ve always preferred these types of &amp;ldquo;time twist&amp;rdquo; challenges to come later in the season once the contestants have gotten accustomed to the time crunch, but for the first Quick Fire right out of the gate, this was pretty fun to&amp;nbsp;watch. &lt;/li&gt;
&lt;li&gt;Of course Justin, the dunce of the season, falls immediately as soon as the game begins. Incredibly on&amp;nbsp;brand.&lt;/li&gt;
&lt;li&gt;The YouTube chef is incredibly awkward on camera. Maybe I can give him the benefit of the doubt and assume the producers got one of the worst clips they could find of him, but dang. For someone who&amp;rsquo;s job it is to be charismatic on camera, he made me cringe so hard I folded in on&amp;nbsp;myself.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;span class="caps"&gt;HUSH&lt;/span&gt; &lt;span class="caps"&gt;PUPPY&lt;/span&gt;-&lt;span class="caps"&gt;GATE&lt;/span&gt;!!! &lt;span class="caps"&gt;HUSH&lt;/span&gt; &lt;span class="caps"&gt;PUPPIES&lt;/span&gt; &lt;span class="caps"&gt;ARE&lt;/span&gt; &lt;span class="caps"&gt;TOO&lt;/span&gt; &lt;span class="caps"&gt;SHRIMPY&lt;/span&gt;!!!&lt;/strong&gt;&amp;nbsp;🚨🚨🚨&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;span class="caps"&gt;HUSH&lt;/span&gt; &lt;span class="caps"&gt;PUPPY&lt;/span&gt;-&lt;span class="caps"&gt;GATE&lt;/span&gt; &lt;span class="caps"&gt;UPDATE&lt;/span&gt;:&lt;/strong&gt; Flour has saved the hush puppies. We have narrowly avoided our first Top Chef&amp;nbsp;disaster.&lt;/li&gt;
&lt;li&gt;I am deeply confused on why they can&amp;rsquo;t plate until the final lap. That seems like producer shenanigans to me, trying to force timing drama on the contestants when it doesn&amp;rsquo;t need to be&amp;nbsp;there. &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;span class="caps"&gt;KALE&lt;/span&gt;-&lt;span class="caps"&gt;GATE&lt;/span&gt;!!! &lt;span class="caps"&gt;KALE&lt;/span&gt;-&lt;span class="caps"&gt;GATE&lt;/span&gt;!!! &lt;span class="caps"&gt;WE&lt;/span&gt; &lt;span class="caps"&gt;ARE&lt;/span&gt; &lt;span class="caps"&gt;MISSING&lt;/span&gt; &lt;span class="caps"&gt;KALE&lt;/span&gt; &lt;span class="caps"&gt;ON&lt;/span&gt; &lt;span class="caps"&gt;SOME&lt;/span&gt; &lt;span class="caps"&gt;PLATES&lt;/span&gt;!!!&lt;/strong&gt;&amp;nbsp;🚨🚨🚨&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;span class="caps"&gt;RAW&lt;/span&gt; &lt;span class="caps"&gt;FISH&lt;/span&gt;-&lt;span class="caps"&gt;GATE&lt;/span&gt;!!! &lt;span class="caps"&gt;RAW&lt;/span&gt; &lt;span class="caps"&gt;FISH&lt;/span&gt;-&lt;span class="caps"&gt;GATE&lt;/span&gt;!!! &lt;span class="caps"&gt;WE&lt;/span&gt; &lt;span class="caps"&gt;HAVE&lt;/span&gt; &lt;span class="caps"&gt;RAW&lt;/span&gt; &lt;span class="caps"&gt;FISH&lt;/span&gt; &lt;span class="caps"&gt;AT&lt;/span&gt; &lt;span class="caps"&gt;THE&lt;/span&gt; &lt;span class="caps"&gt;JUDGE&lt;/span&gt;&amp;rsquo;S &lt;span class="caps"&gt;TABLE&lt;/span&gt;!!!&lt;/strong&gt;&amp;nbsp;🚨🚨🚨&lt;/li&gt;
&lt;li&gt;Oh look, Justin is on the losing team. Raise your hand if you&amp;rsquo;re surprised. Oh look! No&amp;nbsp;hands.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="elimination-challenge"&gt;Elimination&amp;nbsp;Challenge&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Ugh, I hate sweet potatoes. Truly &lt;em&gt;&lt;span class="caps"&gt;THE&lt;/span&gt;&lt;/em&gt; disappointment of the potato family. Let&amp;rsquo;s get this over&amp;nbsp;with.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;&lt;span class="caps"&gt;ONE&lt;/span&gt; &lt;span class="caps"&gt;HOUR&lt;/span&gt;?!?&lt;/em&gt; That&amp;rsquo;s&amp;#8230;.not enough time to do anything! I can&amp;rsquo;t even get all the ingredients out of my cupboard to prep for dinner in an hour! Is this the fast food season of Top Chef? Make it make&amp;nbsp;sense.&lt;/li&gt;
&lt;li&gt;Also, what&amp;rsquo;s up with this no-Last-Chance-Kitchen-for-the-first-two-eliminated-chefs business? They need two eliminated chefs to compete, so does that mean no Last Chance Kitchen until episode 4? Why do they suddenly hate Last Chance Kitchen so much? Is Tom Colicchio tired? Get him a co-host! There are solutions to these problems people! &lt;span class="caps"&gt;WE&lt;/span&gt; &lt;span class="caps"&gt;WANT&lt;/span&gt; &lt;span class="caps"&gt;LAST&lt;/span&gt; &lt;span class="caps"&gt;CHANCE&lt;/span&gt; &lt;span class="caps"&gt;KITCHEN&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;Okay so there&amp;rsquo;s definitely some relationship issues going on with Justin and Jennifer? Justin is saying she &amp;ldquo;won&amp;rsquo;t let him put a ring on it&amp;rdquo; and Jennifer is saying &amp;ldquo;I&amp;rsquo;d say yes if he proposed&amp;rdquo;? This is either some crazy editing or there is major trouble for these &amp;ldquo;life partners&amp;rdquo; ahead. I cannot wait for this to explode on live television. Either way, they&amp;rsquo;re still pissing me&amp;nbsp;off.&lt;/li&gt;
&lt;li&gt;I still think it&amp;rsquo;s crazy that these chefs are let loose in a public Whole Foods on a time limit with random civilians just trying to buy groceries for their families. Laurence literally body slammed a random lady with his cart. Let the people shop in peace! They didn&amp;rsquo;t ask to have a reality competition thrust upon them on a random Tuesday afternoon! At least close down the store for an hour or something. It seems&amp;nbsp;extreme.&lt;/li&gt;
&lt;li&gt;My gosh, these people are cutting and chopping potatoes with reckless abandon. &lt;span class="caps"&gt;PLEASE&lt;/span&gt; &lt;span class="caps"&gt;DON&lt;/span&gt;&amp;rsquo;T &lt;span class="caps"&gt;CUT&lt;/span&gt; &lt;span class="caps"&gt;YOUR&lt;/span&gt; &lt;span class="caps"&gt;HANDS&lt;/span&gt; &lt;span class="caps"&gt;OFF&lt;/span&gt;&amp;nbsp;😭😭😭&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;span class="caps"&gt;BLOW&lt;/span&gt; &lt;span class="caps"&gt;TORCH&lt;/span&gt; &lt;span class="caps"&gt;BITCH&lt;/span&gt; &lt;span class="caps"&gt;COMING&lt;/span&gt; &lt;span class="caps"&gt;THROUGH&lt;/span&gt; &lt;span class="caps"&gt;ANYBODY&lt;/span&gt; &lt;span class="caps"&gt;GOT&lt;/span&gt; A &lt;span class="caps"&gt;BLOWTORCH&lt;/span&gt;???&lt;/strong&gt;&amp;nbsp;🔥🔥🔥&lt;/li&gt;
&lt;li&gt;&lt;span class="caps"&gt;YAAAAAS&lt;/span&gt; Nana with the 30 minutes dance! More of this&amp;nbsp;please&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;span class="caps"&gt;THE&lt;/span&gt; &lt;span class="caps"&gt;OVEN&lt;/span&gt; &lt;span class="caps"&gt;WAS&lt;/span&gt; &lt;span class="caps"&gt;NEVER&lt;/span&gt; &lt;span class="caps"&gt;ON&lt;/span&gt;-&lt;span class="caps"&gt;GATE&lt;/span&gt;!!! &lt;span class="caps"&gt;THE&lt;/span&gt; &lt;span class="caps"&gt;OVEN&lt;/span&gt; &lt;span class="caps"&gt;WAS&lt;/span&gt; &lt;span class="caps"&gt;NEVER&lt;/span&gt; &lt;span class="caps"&gt;ON&lt;/span&gt;&lt;/strong&gt;&amp;nbsp;🚨🚨🚨&lt;/li&gt;
&lt;li&gt;The judges power-walking to the restaurant as a group was one of the hottest things I&amp;rsquo;ve ever seen. It&amp;rsquo;s doing to me what The Fast and the Furious franchise probably does for straight&amp;nbsp;men.&lt;/li&gt;
&lt;li&gt;Ice cream? When it&amp;rsquo;s a thousand degrees out? Bold. Reckless, but&amp;nbsp;bold.&lt;/li&gt;
&lt;li&gt;I finally looked up what &lt;em&gt;~~herbs de Provence~~&lt;/em&gt; was, only to find out it&amp;rsquo;s just pretentious Italian&amp;nbsp;seasoning. &lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;span class="caps"&gt;TIME&lt;/span&gt;-&lt;span class="caps"&gt;GATE&lt;/span&gt; &lt;span class="caps"&gt;TIME&lt;/span&gt;-&lt;span class="caps"&gt;GATE&lt;/span&gt; &lt;span class="caps"&gt;TIME&lt;/span&gt;-&lt;span class="caps"&gt;GATE&lt;/span&gt;&lt;/strong&gt;&amp;nbsp;🚨🚨🚨&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;span class="caps"&gt;OH&lt;/span&gt; &lt;span class="caps"&gt;NOOOOOOOOOOOOOOOOOOOOO&lt;/span&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;She didn&amp;rsquo;t finish on time&amp;nbsp;☹️&lt;/li&gt;
&lt;li&gt;Babes, relax. It&amp;rsquo;s just a &lt;span class="caps"&gt;TV&lt;/span&gt; show. Take some deep&amp;nbsp;breaths.&lt;/li&gt;
&lt;li&gt;Okay, look. I&amp;rsquo;m going to be real with you. One of the main reasons I love reality competition shows is to watch people have complete mental breakdowns on my &lt;span class="caps"&gt;TV&lt;/span&gt;. It&amp;rsquo;s why I love The Traitors. But I give huge props to Nana for having her freak-out moment, and then pulling herself together and presenting her dish to the judges. The show is designed to make you fail. It&amp;rsquo;s designed to be a pressure cooker of stress and emotions, with cameras everywhere looking for the cracks to begin to show in your facade. Many a chef has had a major blow-out on Top Chef. It&amp;rsquo;s part of the game. But Nana really rallied herself, with the support of Kristen and the other chefs, and did her best to present her dish, flaws and all. She didn&amp;rsquo;t give up and she didn&amp;rsquo;t shrink away. And that&amp;rsquo;s what I will eventually remember her for. Not the mistakes, but how she pulled through and came out a better person and chef. It&amp;rsquo;s made me really like her and want to root for her for the rest of the&amp;nbsp;show.&lt;/li&gt;
&lt;li&gt;Who&amp;rsquo;s out here inventing new potatoes? We have enough potatoes. Leave the potatoes&amp;nbsp;alone.&lt;/li&gt;
&lt;li&gt;&lt;span class="dquo"&gt;&amp;ldquo;&lt;/span&gt;It was just a &lt;strong&gt;&lt;em&gt;crazy-brazy&lt;/em&gt;&lt;/strong&gt; kind of dish&amp;rdquo; – Automatic&amp;nbsp;elimination.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;em&gt;&lt;span class="caps"&gt;BOTH&lt;/span&gt;&lt;/em&gt;&lt;/strong&gt; of the twins in the top? Stop torturing&amp;nbsp;me.&lt;/li&gt;
&lt;li&gt;I really hate Justin on a deep, personal&amp;nbsp;level.&lt;/li&gt;
&lt;li&gt;She&amp;rsquo;s serving under-cooked pork? Couldn&amp;rsquo;t that literally kill people? Girl microwave it or something, my&amp;nbsp;god.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;span class="caps"&gt;PORK&lt;/span&gt;-&lt;span class="caps"&gt;GATE&lt;/span&gt; &lt;span class="caps"&gt;PORK&lt;/span&gt;-&lt;span class="caps"&gt;GATE&lt;/span&gt;&lt;/strong&gt;&amp;nbsp;🚨🚨🚨&lt;/li&gt;
&lt;li&gt;Medium-rare? Girl, be&amp;nbsp;serious.&lt;/li&gt;
&lt;li&gt;I ❤️&amp;nbsp;Rhoda&lt;/li&gt;
&lt;li&gt;What the hell is &lt;em&gt;cane vinegar&lt;/em&gt;?&lt;/li&gt;
&lt;li&gt;I ❤️&amp;nbsp;Duyen&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&lt;span class="caps"&gt;YAY&lt;/span&gt; &lt;span class="caps"&gt;ROHDA&lt;/span&gt;&amp;nbsp;❤️❤️❤️&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Still mad about no Last Chance Kitchen. Budget cuts? There&amp;rsquo;s like a thousand spin-offs of Top Chef, you can afford two episodes of &lt;span class="caps"&gt;LCK&lt;/span&gt;.&lt;/li&gt;
&lt;li&gt;Sad for Day ☹️ It&amp;rsquo;s hard to see her go, especially when I don&amp;rsquo;t think she did particularly awful for a first episode. But when it comes right down to it, none of her components were really successful or even necessarily good, so the decision seems&amp;nbsp;justified. &lt;/li&gt;
&lt;/ul&gt;</content><category term="Personal"/><category term="tv"/><category term="top-chef"/></entry><entry><title>How To: Install Steam mods on Linux</title><link href="https://blog.unstablemuffin.com/how-to-install-steam-mods-on-linux.html" rel="alternate"/><published>2026-03-18T00:00:00-07:00</published><updated>2026-03-18T00:00:00-07:00</updated><author><name>Michael</name></author><id>tag:blog.unstablemuffin.com,2026-03-18:/how-to-install-steam-mods-on-linux.html</id><summary type="html">&lt;p&gt;How to install mods for Steam games on&amp;nbsp;Linux&lt;/p&gt;</summary><content type="html">&lt;p&gt;When you install a mod for a Steam game on Linux, it may not work correctly in the game. In many cases this is due to the differences in the way Windows and Linux interpret file names. In Windows, file names are case-insensitive,&amp;nbsp;meaning &lt;code&gt;MyFile.txt&lt;/code&gt; and &lt;code&gt;myfile.txt&lt;/code&gt; refer to the same file on the disk. In contrast, on Linux file names are case sensitive, so those two file names would refer to different&amp;nbsp;files.&lt;/p&gt;
&lt;p&gt;Since Windows dominates the gaming scene, most mods are developed on Windows computers, where the casing of file names doesn&amp;rsquo;t matter. This leads to modders getting lazy with their filenames and often using a different casing than the game uses. While the mod might work without issue on Windows, on Linux the mod will fail in unexpected ways when it tries to reference files that may or may not exist (at least, as Linux sees&amp;nbsp;them).&lt;/p&gt;
&lt;p&gt;The solution to this problem is to install a virtual file system on your Linux computer that will emulate a Windows file system with case insensitive filenames. When the mod loads files from this virtual file system, it loads files with any casing correctly while the game itself continues natively on Linux. The steps below will show you how to create the virtual file system and then mount it for use with your games. You don&amp;rsquo;t have to reinstall your mods this way either; they can be copied over to the new file system and should start working&amp;nbsp;immediately.&lt;/p&gt;
&lt;h2 id="create-the-virtual-file-system"&gt;Create the virtual file&amp;nbsp;system&lt;/h2&gt;
&lt;p&gt;To start with, you need to create the virtual file system. We will be using the vFAT file system for this purpose. vFAT is a lightweight, Windows-compatible file system with native support in the Linux kernel. It&amp;rsquo;s significantly faster to use compared with a full &lt;span class="caps"&gt;NTFS&lt;/span&gt; file system, since &lt;span class="caps"&gt;NTFS&lt;/span&gt; provides a bunch of features that are not needed for a small virtual file system and it requires additional driver support in&amp;nbsp;Linux.&lt;/p&gt;
&lt;p&gt;To create the virtual file system, run this&amp;nbsp;command:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;mkfs.vfat&lt;span class="w"&gt; &lt;/span&gt;-C&lt;span class="w"&gt; &lt;/span&gt;-F&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;32&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;/opt/steam-workshop.img&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2097152&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;mkfs.vfat&lt;/code&gt; - This command creates a virtual file system using the &lt;span class="caps"&gt;FAT&lt;/span&gt; file system&amp;nbsp;format.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-C&lt;/code&gt; - This option specifies that the command should create a file instead of using an existing physical device like a &lt;span class="caps"&gt;USB&lt;/span&gt;&amp;nbsp;stick.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-F 32&lt;/code&gt; - This option specifies using &lt;span class="caps"&gt;FAT32&lt;/span&gt; format, allowing the largest file sizes in the &lt;span class="caps"&gt;FAT&lt;/span&gt;&amp;nbsp;family.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/opt/steam-workshop.img&lt;/code&gt; - This specifies the file where you want to file system to be stored. This can be any place and any name you want. If you use a different path or name, be sure to change in the rest of the commands&amp;nbsp;below.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;2097152&lt;/code&gt; - This is the size of the file system you want to create. This number is the number of file system blocks, which&amp;nbsp;the &lt;code&gt;mkfs.vfat&lt;/code&gt; command defaults to 1024 bytes each, or 1 &lt;span class="caps"&gt;KB&lt;/span&gt;. So this number should be how many kilobytes the file should be. E.g. 1 &lt;span class="caps"&gt;MB&lt;/span&gt; is 1024 &lt;span class="caps"&gt;KB&lt;/span&gt;, and 1 &lt;span class="caps"&gt;GB&lt;/span&gt; is 1048576 &lt;span class="caps"&gt;KB&lt;/span&gt;. I chose 2097152 blocks for mine, which equates to 2 &lt;span class="caps"&gt;GB&lt;/span&gt;. You can adjust this value depending on how many mods you want to be able to install at one&amp;nbsp;time.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Run this command as root on your system and verify it created a new file at the specified path. It is already formatted with the &lt;span class="caps"&gt;FAT32&lt;/span&gt; file system, so next we need to use&amp;nbsp;it.&lt;/p&gt;
&lt;h2 id="mounting-the-virtual-file-system"&gt;Mounting the virtual file&amp;nbsp;system&lt;/h2&gt;
&lt;p&gt;You can&amp;rsquo;t access the virtual file system directly through the file we created in the last step; it must be mounted to the local file system as a virtual block device so it can be used by the operating system. To do that, we&amp;rsquo;ll use a loopback&amp;nbsp;device. &lt;/p&gt;
&lt;h3 id="choosing-a-loopback-device"&gt;Choosing a loopback&amp;nbsp;device&lt;/h3&gt;
&lt;p&gt;Loopback devices typically use the naming&amp;nbsp;convention &lt;code&gt;/dev/loopXX&lt;/code&gt; where &lt;span class="caps"&gt;XX&lt;/span&gt; is any numeric digit. To see if you have any loopback devices in use already, you can run the&amp;nbsp;command &lt;code&gt;losetup -l&lt;/code&gt;. If you don&amp;rsquo;t see loopback devices listed, then you are free to pick any number, or start at 0. If you do see any loopback devices, just choose a number that&amp;rsquo;s not in use. You can either use the next available number, or choose an arbitrary higher number to leave room for other programs creating loopback&amp;nbsp;devices.&lt;/p&gt;
&lt;p&gt;To create the loopback device, run the following&amp;nbsp;command:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;losetup&lt;span class="w"&gt; &lt;/span&gt;/dev/loopXX&lt;span class="w"&gt; &lt;/span&gt;/opt/steam-workshop.img
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;losetup&lt;/code&gt; - This is the name of the program that creates, manages, and deletes loopback devices on your&amp;nbsp;system. &lt;/li&gt;
&lt;li&gt;&lt;code&gt;/dev/loopXX&lt;/code&gt; - This is the loopback device to create. Replace&amp;nbsp;the &lt;code&gt;XX&lt;/code&gt; with number you chose&amp;nbsp;previously.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/opt/steam-workshop.img&lt;/code&gt; - This is the path to the virtual file system you created in the previous&amp;nbsp;section.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If the command ran successfully, the virtual file system file is now running as a block device on your system. The next step is to mount it so your operating system can access the files in&amp;nbsp;it.&lt;/p&gt;
&lt;h3 id="manually-mounting-the-virtual-file-system"&gt;Manually mounting the virtual file&amp;nbsp;system&lt;/h3&gt;
&lt;p&gt;Next, you can mount the virtual file system by running the following&amp;nbsp;command:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;mount&lt;span class="w"&gt; &lt;/span&gt;-o&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;uid&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&amp;lt;user&amp;gt;,gid&lt;span class="o"&gt;=&lt;/span&gt;users,fmask&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;113&lt;/span&gt;,dmask&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;002&lt;/span&gt;,iocharset&lt;span class="o"&gt;=&lt;/span&gt;iso8859-1&lt;span class="w"&gt; &lt;/span&gt;/dev/loopXX&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;/path/to/steam/steamapps/workshop/content&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;sudo mount&lt;/code&gt; - This command mounts file systems into your root file system for the operating system to use. It must always be run as the root&amp;nbsp;user.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-o uid=&amp;lt;user&amp;gt;,gid=users,fmask=113,dmask=002,iocharset=iso8859-1&lt;/code&gt; - This specifies the options for the file system to be mounted.&amp;nbsp;Replace &lt;code&gt;&amp;lt;user&amp;gt;&lt;/code&gt; with your username.&amp;nbsp;The &lt;code&gt;uid&lt;/code&gt; and &lt;code&gt;gid&lt;/code&gt; options specify the user and group that the file system should be mounted with.&amp;nbsp;The &lt;code&gt;fmask&lt;/code&gt; and &lt;code&gt;dmask&lt;/code&gt; options set the file permissions. And&amp;nbsp;finally &lt;code&gt;iocharset&lt;/code&gt; sets the character encoding for&amp;nbsp;filenames.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/dev/loopXX&lt;/code&gt; - This is the loopback device you created previously.&amp;nbsp;Replace &lt;code&gt;XX&lt;/code&gt; with the number of the loopback device you&amp;nbsp;created.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;"/path/to/steam/steamapps/workshop/content"&lt;/code&gt; - This is the path to the workshop content (mods + other downloadable content from Steam) on your computer. It can vary from system to system and the way Steam was installed. But once you find the directory steam is installed at, inside you should find&amp;nbsp;the &lt;code&gt;steamapps/workshop/content&lt;/code&gt; folder where any current mods for any game are installed. Note the double quotes around the path. &lt;strong&gt;If there&amp;rsquo;s already content inside this folder, be sure to back it up before mounting this directory!&lt;/strong&gt; It&amp;rsquo;s as simple&amp;nbsp;as &lt;code&gt;cp -r content/ content_old/&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;After running this command, the virtual file system should be mounted in Steam&amp;rsquo;s content directory, meaning any files the Steam workshop downloads to your computer will be stored in the virtual file system instead of on your&amp;nbsp;disk. &lt;/p&gt;
&lt;p&gt;If you backed up existing files from the content directory, you can use this command to restore those&amp;nbsp;files:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;cp&lt;span class="w"&gt; &lt;/span&gt;-a&lt;span class="w"&gt; &lt;/span&gt;content_old/*&lt;span class="w"&gt; &lt;/span&gt;content/
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The &lt;code&gt;-a&lt;/code&gt; flag will recursively copy all files, preserving file permissions, ownership, timestamps, and extended attributes. Just make sure&amp;nbsp;the &lt;code&gt;content/&lt;/code&gt; directory is empty, as this command will overwrite any files with the same&amp;nbsp;name. &lt;/p&gt;
&lt;h3 id="automatically-mounting-the-file-system"&gt;Automatically mounting the file&amp;nbsp;system&lt;/h3&gt;
&lt;p&gt;If you followed the instructions previously to manually mount the virtual file system, you will notice that it will become unmounted every time you turn off the computer. You can create a systemd service to automatically mount the file system at&amp;nbsp;boot. &lt;/p&gt;
&lt;p&gt;First, create the service file using your favorite text editor. I&amp;rsquo;m using nano because it&amp;rsquo;s objectively the best. The file can be named whatever you want, as long as it ends&amp;nbsp;with &lt;code&gt;.service&lt;/code&gt; and can be found in&amp;nbsp;the &lt;code&gt;/etc/systemd/system/&lt;/code&gt; directory. If you use a different service name, be sure to change the name in the rest of the&amp;nbsp;commands.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;nano&lt;span class="w"&gt; &lt;/span&gt;/etc/systemd/system/steam-workshop.service
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;And add the following content to&amp;nbsp;it:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;[Unit]&lt;/span&gt;
&lt;span class="na"&gt;Description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;Steam Workshop virtual drive device and mount&lt;/span&gt;
&lt;span class="na"&gt;After&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;local-fs.target&lt;/span&gt;
&lt;span class="na"&gt;Before&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;graphical.target&lt;/span&gt;

&lt;span class="k"&gt;[Service]&lt;/span&gt;
&lt;span class="na"&gt;Type&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;oneshot&lt;/span&gt;
&lt;span class="na"&gt;ExecStart&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;/bin/bash -c &amp;#39;/sbin/losetup /dev/loopXX /opt/steam-workshop.img &amp;amp;&amp;amp; /bin/mount -o uid=&amp;lt;usr&amp;gt;,gid=users,fmask=113,dmask=002,iocharset=iso8859-1 /dev/loopXX &amp;quot;/path/to/steam/steamapps/workshop/content&amp;quot;&amp;#39;&lt;/span&gt;
&lt;span class="na"&gt;ExecStop&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;/bin/bash -c &amp;#39;/bin/umount &amp;quot;/path/to/steam/steamapps/workshop/content&amp;quot; &amp;amp;&amp;amp; /sbin/losetup -d /dev/loopXX&amp;#39;&lt;/span&gt;
&lt;span class="na"&gt;RemainAfterExit&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;yes&lt;/span&gt;

&lt;span class="k"&gt;[Install]&lt;/span&gt;
&lt;span class="na"&gt;WantedBy&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;multi-user.target&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Here are the important things to note about this service&amp;nbsp;file:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Description=&lt;/code&gt; - The description for this systemd service. You can put anything&amp;nbsp;here.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;After=local-fs.target&lt;/code&gt; - This will prevent this service from starting until after the local file system has been initialized. This is important because we are loading from an existing file on the local file system, so we have to make sure the local file system is fully initialized before mounting the virtual file&amp;nbsp;system.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Before=graphical.target&lt;/code&gt; - This specifies that the graphical subsystem should not start until this service completes. That means the virtual file system should be mounted before the graphics system is initialized. This is helpful if you have Steam set to start at system startup: it will prevent Steam from auto-starting before the virtual file system has been mounted, causing Steam to see an&amp;nbsp;empty &lt;code&gt;content/&lt;/code&gt; directory.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Type=oneshot&lt;/code&gt; - This specifies that this command will run a single command and terminate (as opposed to a daemon that runs forever). This informs systemd how to manage and report the status of this&amp;nbsp;service.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ExecStart=&lt;/code&gt; - This is what systemd will run when it starts your service. It should look similar to the steps to manually mount the virtual file system. &lt;strong&gt;Things to note about this command:&lt;/strong&gt;&lt;ul&gt;
&lt;li&gt;It combines both the creation of the loopback device and mounting it into one command, joined&amp;nbsp;by &lt;code&gt;&amp;amp;&amp;amp;&lt;/code&gt;. The whole thing is wrapped in a call&amp;nbsp;to &lt;code&gt;/bin/bash -c '...'&lt;/code&gt; because systemd can only run one command. Note the single quotes; since the command uses double quotes around the file path, we use single quotes here to not interfere with&amp;nbsp;those.&lt;/li&gt;
&lt;li&gt;We use the full path&amp;nbsp;to &lt;code&gt;/sbin/losetup&lt;/code&gt; instead of just the command name itself. Since this is running early on in the boot process, it&amp;rsquo;s safer to refer to the executable directly instead of relying on the &lt;span class="caps"&gt;PATH&lt;/span&gt; environment variable being set up&amp;nbsp;correctly.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ExecStop=&lt;/code&gt; - This is the command that&amp;rsquo;s run when systemd attempts to stop this service; either automatically or when you&amp;nbsp;run &lt;code&gt;systemctl stop steam-workshop.service&lt;/code&gt; (or whatever you named the service). It&amp;rsquo;s the same steps&amp;nbsp;in &lt;code&gt;ExecStart&lt;/code&gt; but opposite and in reverse order: unmounting the virtual file system and destroying the loopback device. This allows systemd to cleanly shutdown and free those resources either during system shutdown or if you manually specify it on the command line. Without this step you may be stuck with leftover resources not cleaned up preventing you from remounting&amp;nbsp;things.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;RemainAfterExit=yes&lt;/code&gt; - This tells systemd that the service will exit after starting but to mark it as still active (as long as it ran the startup command successfully). This will cause systemd to report the status of this service correctly, as well as making sure&amp;nbsp;the &lt;code&gt;ExecStop&lt;/code&gt; command is run during shutdown. Without this command systemd would consider this service inactive after it finishes&amp;nbsp;running &lt;code&gt;ExecStart&lt;/code&gt; and wouldn&amp;rsquo;t&amp;nbsp;run &lt;code&gt;ExecStop&lt;/code&gt; later.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;WantedBy=multi-user.target&lt;/code&gt; - This indicates to systemd when to run this script during boot&amp;nbsp;up.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;After creating the service, enable and start it&amp;nbsp;with &lt;code&gt;sudo systemctl enable --now steam-workshop.service&lt;/code&gt;. Now the virtual file system will be created and mounted automatically when the computer boots up, ready for Steam to use. Since it&amp;rsquo;s mounted in the directory Steam expects workspace content to be, any newly subscribed content will automatically be added to the virtual file&amp;nbsp;system.&lt;/p&gt;</content><category term="Technical"/><category term="how-to"/></entry><entry><title>How To: Set up a reverse proxy</title><link href="https://blog.unstablemuffin.com/how-to-set-up-a-reverse-proxy.html" rel="alternate"/><published>2026-03-16T00:00:00-07:00</published><updated>2026-03-16T00:00:00-07:00</updated><author><name>Michael</name></author><id>tag:blog.unstablemuffin.com,2026-03-16:/how-to-set-up-a-reverse-proxy.html</id><summary type="html">&lt;p&gt;How to set up public access to services on your home&amp;nbsp;network&lt;/p&gt;</summary><content type="html">&lt;p&gt;Setting up external access to servers inside your home network is possible by setting up reverse tunnels behind a reverse&amp;nbsp;proxy.&lt;/p&gt;
&lt;p&gt;You will need an external server that is publicly accessible by the Internet. This server can serve any number of private servers inside your network via a reverse proxy. I personally use a basic DigitalOcean droplet that costs $6 per month. You don&amp;rsquo;t need a lot of power for this server, but you want something that won&amp;rsquo;t max out your bandwidth or &lt;span class="caps"&gt;CPU&lt;/span&gt; limits, as that will introduce a lot of latency to your &lt;span class="caps"&gt;SSH&lt;/span&gt; tunnels and ultimately your&amp;nbsp;applications.&lt;/p&gt;
&lt;p&gt;You will need to configure two components to enable access to your home network. First, set up the reverse tunnel to tunnel traffic from the remote server to the local server. Then, configure the reverse proxy on the remote server to direct traffic to the reverse&amp;nbsp;tunnel.&lt;/p&gt;
&lt;h2 id="definitions"&gt;Definitions&lt;/h2&gt;
&lt;dl&gt;
&lt;dt&gt;External/Remote&amp;nbsp;server&lt;/dt&gt;
&lt;dd&gt;This is the server that is running outside of your network and is publicly accessible from the&amp;nbsp;Internet.&lt;/dd&gt;
&lt;dt&gt;Local/Private&amp;nbsp;server&lt;/dt&gt;
&lt;dd&gt;This is a server running inside of your home network. You can have multiple local servers, in which you would follow these instructions for each tunnel on each&amp;nbsp;server.&lt;/dd&gt;
&lt;dt&gt;Reverse&amp;nbsp;tunnel&lt;/dt&gt;
&lt;dd&gt;This is an &lt;span class="caps"&gt;SSH&lt;/span&gt; tunnel that is established from the server that the traffic is being forwarded to. This is the opposite of a traditional tunnel which is initiated from the server sending the traffic, hence the name reverse tunnel. Reverse tunnels are useful when the destination of the traffic is inaccessible from the source of the traffic, such as a home network that has inbound traffic blocked by an &lt;span class="caps"&gt;ISP&lt;/span&gt;.&lt;/dd&gt;
&lt;dt&gt;Reverse&amp;nbsp;proxy&lt;/dt&gt;
&lt;dd&gt;This is a web server that listens for &lt;span class="caps"&gt;HTTP&lt;/span&gt;/s traffic and redirects (i.e. proxies) that traffic to a different endpoint. In this setup, the reverse proxy helps isolate your network and tunnel from potentially dangerous traffic on the Internet. A traditional proxy is a web server that processes outbound traffic, hence why one that processes inbound traffic is called a reverse&amp;nbsp;proxy.&lt;/dd&gt;
&lt;/dl&gt;
&lt;h2 id="reverse-ssh-tunnel"&gt;Reverse &lt;span class="caps"&gt;SSH&lt;/span&gt;&amp;nbsp;Tunnel&lt;/h2&gt;
&lt;p&gt;The reverse tunnel creates an &lt;span class="caps"&gt;SSH&lt;/span&gt; session to a remote machine and tunnels traffic from the remote machine to the local machine. You will need one reverse tunnel for each port you want to forward traffic to. You can have as many tunnels as you need from the same&amp;nbsp;machine.&lt;/p&gt;
&lt;h3 id="setting-up-the-reverse-tunnel"&gt;Setting up the reverse&amp;nbsp;tunnel&lt;/h3&gt;
&lt;p&gt;Use the following ssh command from the local server to create the reverse ssh&amp;nbsp;tunnel:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;/usr/bin/ssh&lt;span class="w"&gt; &lt;/span&gt;-N&lt;span class="w"&gt; &lt;/span&gt;-o&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;ServerAliveInterval&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;60&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-o&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;ServerAliveCountMax&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;3&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-o&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;ExitOnForwardFailure&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;yes&lt;span class="w"&gt; &lt;/span&gt;-R&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;remote-listening-port&amp;gt;:&amp;lt;local-forwarding-server&amp;gt;:&amp;lt;local-forwarding-port&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;-i&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;path-to-private-key&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;remote-username&amp;gt;@&amp;lt;remote-server&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;-N&lt;/code&gt;: This option tells &lt;span class="caps"&gt;SSH&lt;/span&gt; not to set up a full shell session for this connection. This will only establish the &lt;span class="caps"&gt;SSH&lt;/span&gt; connection for the&amp;nbsp;tunnel.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-o ServerAliveInterval=60&lt;/code&gt;: This option sends a keep-alive signal through the tunnel every 60 seconds. You may need this option if the tunnel is closed due to&amp;nbsp;inactivity.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-o ServerAliveCountMax=3&lt;/code&gt;: This option tells the connection to terminate when 3 keep-alive signals are not responded to. This will automatically close the tunnel if the remote machine has disconnected or crashed without closing the connection. Without this option, the tunnel may stay open but unconnected and will need to be manually restarted in order to reconnect to the remote server. In addition, when used in a systemd service (&lt;a href="#creating-a-service-for-the-tunnel"&gt;covered in a later section&lt;/a&gt;), this allows the tunnel to automatically restart&amp;nbsp;itself.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-o ExitOnForwardFailure=yes&lt;/code&gt;: This option tells &lt;span class="caps"&gt;SSH&lt;/span&gt; to exit with a failure if it can&amp;rsquo;t establish the connection. This allows it to automatically retry when inside of a systemd&amp;nbsp;service.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-R &amp;lt;remote-listening-port&amp;gt;:&amp;lt;local-forwarding-server&amp;gt;:&amp;lt;local-forwarding-port&amp;gt;&lt;/code&gt;: This is the option for establishing the reverse tunnel.
The tunnel will be set up to listen on&amp;nbsp;port &lt;code&gt;&amp;lt;remote-listening-port&amp;gt;&lt;/code&gt; on the remote server, and all traffic that arrives at that port will be forwarded&amp;nbsp;to &lt;code&gt;&amp;lt;local-forwarding-server&amp;gt;&lt;/code&gt; on&amp;nbsp;port &lt;code&gt;&amp;lt;local-forwarding-port&amp;gt;&lt;/code&gt; in your home network. &lt;br&gt;&lt;br&gt;
Note that by default, the remote port is bound to localhost, so it is not accessible to the Internet. You can choose to bind it to a public address by specifying a remote server address to bind to (for&amp;nbsp;example, &lt;code&gt;-R 0.0.0.0:&amp;lt;remote-listening-port&amp;gt;:&amp;lt;local-forwarding-server&amp;gt;:&amp;lt;local-forwarding-port&amp;gt;&lt;/code&gt; would allow any traffic to access the tunnel) but this is generally highly discouraged because you&amp;rsquo;re opening a direct connection from the Internet into your home network. There are bots constantly scanning the Internet for open ports to exploit, and then once an application is compromised they will move laterally inside your home network to compromise the rest of your devices. It&amp;rsquo;s recommended to keep the tunnels bound to localhost and run them behind a reverse proxy, which will be covered in the &lt;a href="#reverse-proxy"&gt;next section&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-i &amp;lt;path-to-private-key&amp;gt;&lt;/code&gt;: This option specifies the path to the private key file to use to authenticate the connection. You can use a different form of authentication if you want, for example username and password, but it&amp;rsquo;s highly recommended not to have your username or password hard coded, and key pair authentication is easier to use for unattended&amp;nbsp;services.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;&amp;lt;remote-username&amp;gt;@&amp;lt;remote-server&amp;gt;&lt;/code&gt;: Finally, this is the username and server (either &lt;span class="caps"&gt;IP&lt;/span&gt; address or domain name) of the remote server. The user should be a special user used just for your &lt;span class="caps"&gt;SSH&lt;/span&gt; tunnels and have all other permissions and logon rights disabled for security. Instruction on how to set this user up will be covered in a &lt;a href="#creating-a-user-for-the-tunnel"&gt;later section&lt;/a&gt;. However, you can also use just a regular logon user for this, it&amp;rsquo;s just less&amp;nbsp;secure.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This is an example that I am currently using to create a tunnel from port 3001 on a public DigitalOcean droplet to an instance of Jellyfin running on the same machine on port&amp;nbsp;8096:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;/usr/bin/ssh&lt;span class="w"&gt; &lt;/span&gt;-N&lt;span class="w"&gt; &lt;/span&gt;-o&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;ServerAliveInterval&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;60&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-o&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;ServerAliveCountMax&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;3&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-o&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;ExitOnForwardFailure&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;yes&lt;span class="w"&gt; &lt;/span&gt;-R&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;3001&lt;/span&gt;:localhost:8096&lt;span class="w"&gt; &lt;/span&gt;-i&lt;span class="w"&gt; &lt;/span&gt;/home/sshtunnel/.ssh/tunnel_rsa&lt;span class="w"&gt; &lt;/span&gt;sshtunnel@cloud.michaelhumphrey.dev
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3 id="creating-a-service-for-the-tunnel"&gt;Creating a service for the&amp;nbsp;tunnel&lt;/h3&gt;
&lt;p&gt;If you run the reverse tunnel from the command line, it will only stay running as long as the command is running. If you close the terminal it&amp;rsquo;s running in, the reverse tunnel will terminate. You can always start the command and run it in the background, but then you may not notice if the tunnel shuts down, and is difficult to restart. To fix these issues, you can configure a systemd service to manage the tunnel for you. Below is a template you can use to create the&amp;nbsp;service:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;[Unit]&lt;/span&gt;
&lt;span class="na"&gt;Description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;lt;service-name&amp;gt;&lt;/span&gt;
&lt;span class="na"&gt;After&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;network-online.target&lt;/span&gt;

&lt;span class="k"&gt;[Service]&lt;/span&gt;
&lt;span class="na"&gt;User&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;&amp;lt;username&amp;gt;&lt;/span&gt;
&lt;span class="na"&gt;ExecStart&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;/usr/bin/ssh -N -o ServerAliveInterval=60 -o ServerAliveCountMax=3 -o ExitOnForwardFailure=yes -R &amp;lt;remote-listening-port&amp;gt;:&amp;lt;local-forwarding-server&amp;gt;:&amp;lt;local-forwarding-port&amp;gt; -i &amp;lt;path-to-private-key&amp;gt; &amp;lt;remote-username&amp;gt;@&amp;lt;remote-server&amp;gt;&lt;/span&gt;

&lt;span class="na"&gt;RestartSec&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;5&lt;/span&gt;
&lt;span class="na"&gt;Restart&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;always&lt;/span&gt;

&lt;span class="k"&gt;[Install]&lt;/span&gt;
&lt;span class="na"&gt;WantedBy&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;multi-user.target&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;Description=&amp;lt;service-name&amp;gt;&lt;/code&gt;: A short description of this&amp;nbsp;tunnel.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;After=network-online.target&lt;/code&gt;: Wait to start this service until after the network is&amp;nbsp;online.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;User=&amp;lt;username&amp;gt;&lt;/code&gt;: The user this service should run under. Ideally this would be a user that is only used to run the &lt;span class="caps"&gt;SSH&lt;/span&gt; tunnels and have no other permissions and logon rights disabled, but it can also be a regular user. See the &lt;a href="#creating-a-user-for-the-tunnel"&gt;next section&lt;/a&gt; for instructions on how to set up a user for the&amp;nbsp;tunnel.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ExecStart=&amp;lt;ssh-command&amp;gt;&lt;/code&gt;: This is the command to be run when this service is started. See the &lt;a href="#setting-up-the-reverse-tunnel"&gt;previous section&lt;/a&gt; for instruction on how to set up the ssh&amp;nbsp;command.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;RestartSec=5&lt;/code&gt;: This option specifies that if this service stops for any reason, it should wait 5 seconds before restarting. You can set this to whatever you like, but it should be short enough to minimize downtime if the tunnel can be reestablished and long enough to let the network connection shutdown and cleanup its resources before trying again. For less critical application, you can set this upward of 30-60 seconds or more to avoid straining your server if the remote server becomes unavailable for a period of time. Don&amp;rsquo;t set this to anything less than two seconds, otherwise the service may be terminated for starting up too many times too&amp;nbsp;quickly.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Restart=always&lt;/code&gt;: This option specifies that the service should always start up after it stops for any reason. You can also set this option&amp;nbsp;to &lt;code&gt;on-failure&lt;/code&gt; to only start back up if it&amp;nbsp;crashed.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="creating-a-user-for-the-tunnel"&gt;Creating a user for the&amp;nbsp;tunnel&lt;/h3&gt;
&lt;p&gt;To minimize the attack vector of exposing a tunnel to your home network from the Internet, it is recommended to set up a dedicated user with minimal permissions to run the tunnel. This ensures that even if that account is compromised, attackers still don&amp;rsquo;t have access to any other systems. You only need one user for all of your tunnels to use. In these examples, I&amp;rsquo;m&amp;nbsp;using &lt;code&gt;sshtunnel&lt;/code&gt; as the username, but you can use any username you&amp;nbsp;prefer.&lt;/p&gt;
&lt;h4 id="on-the-remote-server"&gt;On the remote&amp;nbsp;server&lt;/h4&gt;
&lt;p&gt;First, create the user and required directories on the remote&amp;nbsp;server:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;useradd&lt;span class="w"&gt; &lt;/span&gt;-m&lt;span class="w"&gt; &lt;/span&gt;-s&lt;span class="w"&gt; &lt;/span&gt;/usr/sbin/nologin&lt;span class="w"&gt; &lt;/span&gt;sshtunnel
sudo&lt;span class="w"&gt; &lt;/span&gt;mkdir&lt;span class="w"&gt; &lt;/span&gt;-p&lt;span class="w"&gt; &lt;/span&gt;/home/sshtunnel/.ssh
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;useradd&lt;/code&gt;: This command creates the user that the tunnel will run&amp;nbsp;under.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-m&lt;/code&gt;: This option creates a home directory for the new user. We will use this directory to store the scripts for running the tunnel and symlinking them to the appropriate system&amp;nbsp;directories.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-s /usr/sbin/nologin&lt;/code&gt;: This option sets the user&amp;rsquo;s login shell&amp;nbsp;to &lt;code&gt;/usr/sbin/nologin&lt;/code&gt;. This is a special shell that disallows this user from logging into the system, but lets it run system services and create tunnels. This prevents this user from being commandeered by an attacker while still allowing us to authenticate with a minimum-permission account for setting up the&amp;nbsp;tunnel.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;mkdir&lt;/code&gt; This command create the directory where the user&amp;rsquo;s ssh credentials will&amp;nbsp;live.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-p&lt;/code&gt;: This option creates all parent directories for this directory if they don&amp;rsquo;t already&amp;nbsp;exist.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Next, ensure that the directories belong to the user we created, not the currently logged in user or&amp;nbsp;root:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;chown&lt;span class="w"&gt; &lt;/span&gt;-R&lt;span class="w"&gt; &lt;/span&gt;sshtunnel:sshtunnel&lt;span class="w"&gt; &lt;/span&gt;~/sshtunnel/.ssh
sudo&lt;span class="w"&gt; &lt;/span&gt;chmod&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;700&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;~/sshtunnel/.ssh
sudo&lt;span class="w"&gt; &lt;/span&gt;chmod&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;600&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;~/sshtunnel/.ssh/authorized_keys
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;chown -R sshtunnel:sshtunnel ~/sshtunnel/.ssh&lt;/code&gt;: This command recursively sets all files and directories&amp;nbsp;in &lt;code&gt;~/sshtunnel/.ssh&lt;/code&gt; to belong to the sshtunnel user and&amp;nbsp;group.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;chmod ...&lt;/code&gt;: These commands set the permissions of the directory to the minimum necessary. The ssh keys for login are stored in these directories, so it&amp;rsquo;s important to keep them&amp;nbsp;secure.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id="on-the-local-server"&gt;On the local&amp;nbsp;server&lt;/h4&gt;
&lt;p&gt;Next, set up the reverse tunnels on the local server to use the newly created&amp;nbsp;user.&lt;/p&gt;
&lt;p&gt;First, create ssh key pair for&amp;nbsp;authentication:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sudo&lt;span class="w"&gt; &lt;/span&gt;mkdir&lt;span class="w"&gt; &lt;/span&gt;-p&lt;span class="w"&gt; &lt;/span&gt;/etc/sshtunnel
sudo&lt;span class="w"&gt; &lt;/span&gt;ssh-keygen&lt;span class="w"&gt; &lt;/span&gt;-qN&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;-f&lt;span class="w"&gt; &lt;/span&gt;/etc/sshtunnel/id_rsa
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;mkdir -p /etc/sshtunnel&lt;/code&gt;: This command creates a new directory for the tunnel credentials to&amp;nbsp;live.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;ssh-keygen&lt;/code&gt;: This command creates a new key pair for&amp;nbsp;authentication.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-q&lt;/code&gt;: This option silences the output of the ssh-keygen command. It is&amp;nbsp;optional.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-N ""&lt;/code&gt;: This option sets the passphrase of the key pair to an empty string, essentially disabling the password requirement to use it. This makes it easier to allow the automated services to use it without prompting for a password. However, it makes it all the more important to keep these keys private, as anyone can use them to gain access to your&amp;nbsp;system.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;-f /etc/sshtunnel/id_rsa&lt;/code&gt;: This option specifies the newly created directory to store the key pair&amp;nbsp;in.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Next, modify the systemd service files for the tunnels to use the new user. Most importantly, that means setting these ssh&amp;nbsp;options:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;-i /etc/sshtunnel/ssh&lt;/code&gt;: This points ssh to the private key we just created for the sshtunnel&amp;nbsp;user.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;sshtunnel@&amp;lt;remote-server&amp;gt;&lt;/code&gt;: Set the username when connecting to the remote server to&amp;nbsp;sshtunnel.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Finally, copy the public&amp;nbsp;key &lt;code&gt;/etc/sshtunnel/id_rsa.pub&lt;/code&gt; to the remote machine and add it to the authorized keys file&amp;nbsp;in &lt;code&gt;~/sshtunnel/.ssh/authorized_keys&lt;/code&gt;. This will allow the remote server to recognize and authenticate the newly created user. Make sure you connect to the remote server with the new credentials manually from the command line so you can whitelist the remote server&amp;rsquo;s public key as&amp;nbsp;well.&lt;/p&gt;
&lt;h2 id="reverse-proxy"&gt;Reverse&amp;nbsp;Proxy&lt;/h2&gt;
&lt;p&gt;The other component needed is a reverse proxy to direct traffic from the Internet into the private &lt;span class="caps"&gt;SSH&lt;/span&gt; reverse tunnel you set up. The reverse proxy can do a lot of useful things for you, including providing a &lt;span class="caps"&gt;HTTPS&lt;/span&gt; endpoint in front of your services, load balancing, authentication,&amp;nbsp;etc.&lt;/p&gt;
&lt;h3 id="configuring-the-reverse-proxy"&gt;Configuring the reverse&amp;nbsp;proxy&lt;/h3&gt;
&lt;p&gt;I use &lt;span class="caps"&gt;NGINX&lt;/span&gt; for my reverse proxy, but you can really do this part with any web server. The configuration options will be different, but the theory is the&amp;nbsp;same.&lt;/p&gt;
&lt;p&gt;Here is how I have my reverse proxy set up to terminate &lt;span class="caps"&gt;HTTPS&lt;/span&gt; connections and forward through the reverse &lt;span class="caps"&gt;SSH&lt;/span&gt;&amp;nbsp;tunnel:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;server&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kn"&gt;server_name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;lt;external-domain-name&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kn"&gt;client_max_body_size&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;500M&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;# Only needed if you&amp;#39;re expecting large payloads&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kn"&gt;location&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;/&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kn"&gt;proxy_pass&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;http://127.0.0.1:&amp;lt;reverse-tunnel-remote-port&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kn"&gt;proxy_set_header&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;Host&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$host&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kn"&gt;proxy_set_header&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;X-Real-IP&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$remote_addr&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kn"&gt;proxy_set_header&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;X-Forwarded-For&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$proxy_add_x_forwarded_for&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kn"&gt;proxy_set_header&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;X-Forwarded-Proto&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$scheme&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kn"&gt;listen&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;443&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;ssl&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;# managed by Certbot&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kn"&gt;ssl_certificate&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;lt;path-to-fullchain.pem&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;# managed by Certbot&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kn"&gt;ssl_certificate_key&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;lt;path-to-privkey.pem&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;# managed by Certbot&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kn"&gt;include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;/etc/letsencrypt/options-ssl-nginx.conf&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;# managed by Certbot&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kn"&gt;ssl_dhparam&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;/etc/letsencrypt/ssl-dhparams.pem&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;# managed by Certbot&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;server&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kn"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$host&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;lt;external-domain-name&amp;gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kn"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;301&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;https://&lt;/span&gt;&lt;span class="nv"&gt;$host$request_uri&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;# managed by Certbot&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kn"&gt;server_name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;lt;external-domain-name&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kn"&gt;listen&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;80&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kn"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;404&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;# managed by Certbot&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The second server block just redirects all &lt;span class="caps"&gt;HTTP&lt;/span&gt; requests for this domain to &lt;span class="caps"&gt;HTTPS&lt;/span&gt;. This makes it easier for any clients attempting to connect with &lt;span class="caps"&gt;HTTP&lt;/span&gt; first to be forced to use &lt;span class="caps"&gt;HTTPS&lt;/span&gt;. This block is automatically added when using the LetsEncrypt&amp;nbsp;client.&lt;/p&gt;
&lt;p&gt;The first server block handles all of the actual&amp;nbsp;proxying.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;server_name &amp;lt;external-domain-name&amp;gt;&lt;/code&gt;: This binds this server block to a particular domain. Different server blocks can be bound to different domains and ran simultaneously; &lt;span class="caps"&gt;NGINX&lt;/span&gt; will just check which domain a request is for and use the configs for the associated server block. If you don&amp;rsquo;t have this label, it will use it for all incoming requests, but then you would only be able to have one server block configuration for&amp;nbsp;everything.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;client_max_body_size 500M&lt;/code&gt;: By default &lt;span class="caps"&gt;NGINX&lt;/span&gt; limits incoming request payloads to 1 megabyte. This is fine for most applications, but if you need to set it to be larger (for example, Nextcloud or other backup solutions) you can use this option to set that limit higher. Note that sending excessively large payloads to overwhelm your server is a common denial-of-service attack and can result in exorbitant server expenses, so only use this option if you need it and set it to the lowest value that you actually expect to&amp;nbsp;use.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;location /&lt;/code&gt;: This block specifies the &lt;span class="caps"&gt;URL&lt;/span&gt; root. Setting the root&amp;nbsp;to &lt;code&gt;/&lt;/code&gt; will make this block handle all requests on the domain. You can specify a &lt;span class="caps"&gt;URL&lt;/span&gt; fragment if you want to run multiple services on the same domain. For example, you can have one service in&amp;nbsp;a &lt;code&gt;location /foo&lt;/code&gt; block and another service in&amp;nbsp;a &lt;code&gt;location /bar&lt;/code&gt; block, and then have different settings in each one. Then requests coming in&amp;nbsp;at &lt;code&gt;mydomain.com/foo&lt;/code&gt; will be sent to a different &lt;span class="caps"&gt;SSH&lt;/span&gt; tunnel than requests coming in&amp;nbsp;to &lt;code&gt;mydomain.com/bar&lt;/code&gt;.&lt;br&gt;&lt;br&gt;
While this configuration will allow &lt;span class="caps"&gt;NGINX&lt;/span&gt; to route subpath requests to different &lt;span class="caps"&gt;SSH&lt;/span&gt; tunnels, the applications running behind those tunnels will have to be configued to support such a configuration, as clients will still end the entire &lt;span class="caps"&gt;URL&lt;/span&gt; with the subpath in their &lt;span class="caps"&gt;HTTP&lt;/span&gt; requests. Not all applications support running on a subpath, so it&amp;rsquo;s up to you to decide which ones, if any, will run that way. I personally prefer to use subdomains to separate my services&amp;nbsp;(e.g. &lt;code&gt;foo.mydomain.com&lt;/code&gt; and &lt;code&gt;bar.mydomain.com&lt;/code&gt;) as it&amp;rsquo;s easier and cleaner to support, but you do need full control over your domain to do&amp;nbsp;so.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;proxy_pass http://127.0.0.1:&amp;lt;reverse-tunnel-remote-port&amp;gt;&lt;/code&gt;: This option specifies where traffic in this block should be forwarded to.&amp;nbsp;The &lt;code&gt;127.0.0.1&lt;/code&gt; specifies it should be forwarded to the localhost, where the reverse tunnel is&amp;nbsp;listening. &lt;code&gt;&amp;lt;reverse-tunnel-remote-port&amp;gt;&lt;/code&gt; should be the same remote port you specified when setting up the reverse tunnel. We are connecting the reverse proxy to the tunnel&amp;nbsp;here.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;proxy_set_header ...&lt;/code&gt;: These configs are to properly pass request headers through the proxy to the application behind the proxy. Many services require these headers to be set properly, especially if you&amp;rsquo;re running security applications. Applications may not work, generate security errors, or report incorrect data if these are headers are not set&amp;nbsp;correctly.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;The remaining headers in the server block are to configure &lt;span class="caps"&gt;HTTPS&lt;/span&gt;. These should be automatically added when requesting a certificate through&amp;nbsp;LetsEncrypt.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id="nginx-configuration-files"&gt;&lt;span class="caps"&gt;NGINX&lt;/span&gt; configuration&amp;nbsp;files&lt;/h3&gt;
&lt;p&gt;The configuration for a reverse proxy should be saved with the filename that matches the domain it&amp;rsquo;s running on. For example, if your reverse proxy is running for the&amp;nbsp;domain &lt;code&gt;foobar.mydomain.com&lt;/code&gt;, then you would save the configuration in a file&amp;nbsp;called &lt;code&gt;foobar.mydomain.com&lt;/code&gt;. The directory for these configurations is by&amp;nbsp;default &lt;code&gt;/etc/nginx/sites-available&lt;/code&gt;. Then, when you&amp;rsquo;re finished editing the configuration file, create a symlink to the file&amp;nbsp;in &lt;code&gt;/etc/nginx/sites-enabled&lt;/code&gt; using the command&amp;nbsp;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;ln&lt;span class="w"&gt; &lt;/span&gt;-s&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;target-path&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;&amp;lt;link-name&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The target path is the full path to the file you want to symlink to (for&amp;nbsp;example, &lt;code&gt;/etc/nginx/sites-available/foobar.mydomain.com&lt;/code&gt;) and the link-name is the name you want the link to have (in most cases, it should be the same). When you are done, you can check the link by&amp;nbsp;typing &lt;code&gt;ls -l&lt;/code&gt; and you should see something like&amp;nbsp;this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;lrwxrwxrwx 1 root root 45 Apr  6  2024 foobar.mydomain.com -&amp;gt; /etc/nginx/sites-available/foobar.mydomain.com
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Once the symlink is created, your reverse proxy configuration is now ready to be used. First run the&amp;nbsp;command &lt;code&gt;nginx -t&lt;/code&gt; to test your configuration files. If there are any errors, fix them now. When the test returns successfully, you can reload the &lt;span class="caps"&gt;NGINX&lt;/span&gt; configs with the&amp;nbsp;command &lt;code&gt;systemctl reload nginx&lt;/code&gt;. Your reverse proxy is now live and directing &lt;span class="caps"&gt;HTTP&lt;/span&gt; traffic to your&amp;nbsp;tunnel.&lt;/p&gt;
&lt;h2 id="alternatives-to-self-hosting"&gt;Alternatives to&amp;nbsp;self-hosting&lt;/h2&gt;
&lt;p&gt;If you don&amp;rsquo;t have a publicly accessible server or don&amp;rsquo;t want to purchase a &lt;span class="caps"&gt;VPS&lt;/span&gt; (virtual public server) to host the external reverse proxy, there are other services that will do the equivalent of these steps for you. I have used &lt;a href="https://packetriot.com/"&gt;Packet Riot&lt;/a&gt; in the past to forward traffic from the internet to my local network. Their free tier offers up to one tunnel, unlimited &lt;span class="caps"&gt;HTTP&lt;/span&gt;/s proxies for that tunnel, 1 &lt;span class="caps"&gt;TCP&lt;/span&gt; proxy for the tunnel, and up to 1 gigabyte of bandwidth per month. The next tier is only $5 / month and allows up to a terabyte of bandwidth. I like this service quite a bit, but ultimately had some intermittent issues that led me to pursue hosting my own reverse proxy since I already paid for a &lt;span class="caps"&gt;VPS&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;Many self-hosters use ngrok as a reverse proxy for their services. It&amp;rsquo;s quite a bit more expensive but can handle almost everything for you. Tailwind is also a great option if you don&amp;rsquo;t need your services to be truly public, but want to access your services from your own devices from anywhere in the world. There&amp;rsquo;s countless other alternatives out there that will all do the same thing, but ultimately under the hood they function the same way as the tools described in this&amp;nbsp;document.&lt;/p&gt;</content><category term="Technical"/><category term="how-to"/></entry></feed>