<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0">
<channel>
<title>Coder Legion - Recent posts tagged port</title>
<link>https://coderlegion.com/tag/port</link>
<description>Powered by Question2Answer</description>
<item>
<title>How to Expose Localhost to the Public Using Nginx and SSH Tunnels</title>
<link>https://coderlegion.com/16117/how-to-expose-localhost-to-the-public-using-nginx-and-ssh-tunnels</link>
<description>
&lt;p&gt;Hello, I'm Ganesh. I'm building &lt;em&gt;git-lrc&lt;/em&gt;, an AI code reviewer that runs on every commit. It is free, unlimited, and source-available on Github. &lt;a href=&quot;https://github.com/HexmosTech/git-lrc&quot; rel=&quot;noopener noreferrer nofollow&quot;&gt;Star Us&lt;/a&gt; to help devs discover the project. Do give it a try and share your feedback for improving the product.&lt;/p&gt;

&lt;p&gt;As a developer, you&amp;rsquo;ve likely faced this hurdle: You are building a complex application on your local machine, and you need to show it to a client or test a webhook of your application. &lt;/p&gt;

&lt;p&gt;You could deploy it to a staging server, but that's slow. &lt;br&gt;
You could use Ngrok, but the free tier has limits and dynamic URLs. &lt;/p&gt;

&lt;p&gt;Today, I&amp;rsquo;ll show you how to build your own &lt;strong&gt;&quot;Unlimited&quot; Reverse Proxy&lt;/strong&gt; using &lt;strong&gt;Nginx&lt;/strong&gt;, &lt;strong&gt;Autossh&lt;/strong&gt;, and a small VPS.&lt;/p&gt;
&lt;h2&gt;
  
  
  The Architecture
&lt;/h2&gt;

&lt;p&gt;The goal is to route traffic from a professional URL (like &lt;code&gt;test1.yourdomain.com&lt;/code&gt;) directly to a port on your local machine (like localhost:3000).&lt;/p&gt;

&lt;p&gt;We use three layers of technology to make this happen:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;Nginx:&lt;/strong&gt; Acts as the entry point and handles SSL (HTTPS).&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;SSH Reverse Tunnel:&lt;/strong&gt; Creates a secure &quot;pipe&quot; from your VPS back to your laptop.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Autossh:&lt;/strong&gt; Ensures that if your internet flickers, the &quot;pipe&quot; automatically reconnects.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;
  
  
  Step 1: The Remote Server (Nginx)
&lt;/h2&gt;

&lt;p&gt;On your server, you need an Nginx configuration that listens for HTTPS traffic and passes it to a local port.&lt;br&gt;
&lt;/p&gt;

&lt;div class=&quot;highlight js-code-highlight&quot;&gt;
&lt;pre class=&quot;highlight nginx&quot;&gt;&lt;code&gt;&lt;span class=&quot;k&quot;&gt;server&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;kn&quot;&gt;listen&lt;/span&gt; &lt;span class=&quot;mi&quot;&gt;443&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;ssl&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;http2&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;kn&quot;&gt;server_name&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;test1.yourdomain.com&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;kn&quot;&gt;ssl_certificate&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;/etc/letsencrypt/live/your-domain/fullchain.pem&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;kn&quot;&gt;ssl_certificate_key&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;/etc/letsencrypt/live/your-domain/privkey.pem&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

    &lt;span class=&quot;kn&quot;&gt;location&lt;/span&gt; &lt;span class=&quot;n&quot;&gt;/&lt;/span&gt; &lt;span class=&quot;p&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;c1&quot;&gt;# Proxy traffic to the SSH-forwarded port&lt;/span&gt;
        &lt;span class=&quot;kn&quot;&gt;proxy_pass&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;&lt;a href=&quot;http://127.0.0.1:6540&quot; rel=&quot;nofollow&quot;&gt;http://127.0.0.1:6540&lt;/a&gt;&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;

        &lt;span class=&quot;c1&quot;&gt;# Keep the original user's info&lt;/span&gt;
        &lt;span class=&quot;kn&quot;&gt;proxy_set_header&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;Host&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$host&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;kn&quot;&gt;proxy_set_header&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;X-Real-IP&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$remote_addr&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;kn&quot;&gt;proxy_set_header&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;X-Forwarded-For&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;$proxy_add_x_forwarded_for&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;kn&quot;&gt;proxy_set_header&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;X-Forwarded-Proto&lt;/span&gt; &lt;span class=&quot;s&quot;&gt;https&lt;/span&gt;&lt;span class=&quot;p&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;p&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Step 2: The Local Bridge
&lt;/h2&gt;

&lt;p&gt;On your local machine, you need to open the tunnel.&lt;/p&gt;

&lt;p&gt;Using a &lt;code&gt;Makefile&lt;/code&gt; or a shell script makes this repeatable. The core command uses the &lt;code&gt;-R&lt;/code&gt; flag, which stands for &lt;strong&gt;Remote Forward&lt;/strong&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class=&quot;highlight js-code-highlight&quot;&gt;
&lt;pre class=&quot;highlight shell&quot;&gt;&lt;code&gt;&lt;span class=&quot;c&quot;&gt;# -R [Remote Port]:[Local Destination]:[Local Port]&lt;/span&gt;
autossh &lt;span class=&quot;nt&quot;&gt;-M&lt;/span&gt; 20000 &lt;span class=&quot;nt&quot;&gt;-R&lt;/span&gt; 6540:localhost:3000 root@your-server &lt;span class=&quot;nt&quot;&gt;-N&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Why this is &quot;Unlimited&quot;
&lt;/h2&gt;

&lt;p&gt;Unlike third-party services, this setup gives you:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Total Control:&lt;/strong&gt; No timeout limits or bandwidth caps (other than your own ISP's speed).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Professionalism:&lt;/strong&gt; You use your own domain and your own SSL certificates.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Security:&lt;/strong&gt; Your local machine is not truly &quot;exposed.&quot; Only the specific port you choose (8081) is bridged through the encrypted SSH tunnel.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Troubleshooting Common Gotchas
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt; &lt;strong&gt;502 Bad Gateway:&lt;/strong&gt; This usually means Nginx is working, but your SSH tunnel isn't running or is on the wrong port.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Port Already in Use:&lt;/strong&gt; If you restart your tunnel quickly, the server might still think the old one is active. 
Use a cleanup script to &lt;code&gt;kill -9 &amp;lt;PID&amp;gt;&lt;/code&gt; any process currently sitting on your remote port before starting a new one.&lt;/li&gt;
&lt;li&gt; &lt;strong&gt;Firewalls:&lt;/strong&gt; Ensure your VPS allows traffic on ports 80 and 443!&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;By combining the stability of Nginx with the flexibility of SSH tunneling, you've created a production-grade development environment. &lt;/p&gt;

&lt;p&gt;You now have a permanent bridge between your local setup and the rest of the world.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/HexmosTech/git-lrc&quot; rel=&quot;noopener noreferrer nofollow&quot;&gt;&lt;img src=&quot;https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fabn6nl3iehrohehnxgje.png&quot; alt=&quot;git-lrc&quot; width=&quot;800&quot; height=&quot;373&quot;&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Any feedback or contributors are welcome! It&amp;rsquo;s online, source-available, and ready for anyone to use. &lt;br&gt;
&amp;#11088; Star it on GitHub: &lt;a href=&quot;https://github.com/HexmosTech/git-lrc&quot; rel=&quot;noopener noreferrer nofollow&quot;&gt;https://github.com/HexmosTech/git-lrc&lt;/a&gt;&lt;/p&gt;


</description>
<category>Other</category>
<guid isPermaLink="true">https://coderlegion.com/16117/how-to-expose-localhost-to-the-public-using-nginx-and-ssh-tunnels</guid>
<pubDate>Sun, 03 May 2026 09:35:44 +0000</pubDate>
</item>
<item>
<title>Porting Test Drive II from SNES to PC, Part 4: Validation, cleanup, and current blockers</title>
<link>https://coderlegion.com/13287/porting-test-drive-ii-from-snes-to-pc-part-4-validation-cleanup-and-current-blockers</link>
<description>&lt;h2 id=&quot;porting-test-drive-ii-from-snes-to-pc-part-4-validation-cleanup-and-current-blockers&quot;&gt;Porting Test Drive II from SNES to PC, Part 4: Validation, cleanup, and current blockers&lt;/h2&gt;
&lt;p&gt;By the second week of this repo, the technical risk had changed.&lt;/p&gt;
&lt;p&gt;The problem was no longer &quot;we do not have enough scripts.&quot; The problem was &quot;we have enough moving pieces that incorrect progress can look convincing.&quot;&lt;/p&gt;
&lt;p&gt;That is why the March 6 to March 19 history matters so much. This is the phase where &lt;code&gt;asmdump&lt;/code&gt; turns archaeology results into contracts, turns renderer bugs into isolated fixtures, and starts cleaning up its own generated noise.&lt;/p&gt;
&lt;h3 id=&quot;validation-became-executable&quot;&gt;Validation became executable&lt;/h3&gt;
&lt;p&gt;Commit &lt;code&gt;c5ec8be&lt;/code&gt; on 2026-03-06 added the first real validation policy layer:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;tools/check_regression_gates.py&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;tools/validate_callback_contracts.py&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;validation/regression_gates_intro.jsonc&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;rom_analysis/docs/callback_state_contracts.jsonc&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;rom_analysis/docs/validation_gates.md&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This is a major change in the repo's engineering model.&lt;/p&gt;
&lt;p&gt;Before that point, progress was mostly tracked through:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;rendered outputs&lt;/li&gt;
&lt;li&gt;trace logs&lt;/li&gt;
&lt;li&gt;prose notes&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;After that point, the repo could encode claims like:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;this frame or transition is allowed to drift only within a known bound&lt;/li&gt;
&lt;li&gt;this callback and state tuple must still be true at this checkpoint&lt;/li&gt;
&lt;li&gt;this promoted scene window has a machine-checkable gate&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;As of the March 19 roadmap snapshot, the current validation baseline is concrete:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;callback contracts: &lt;code&gt;18/18&lt;/code&gt; pass&lt;/li&gt;
&lt;li&gt;regression gates: &lt;code&gt;6/6&lt;/code&gt; pass&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That does not mean the intro is solved. It means the repo now has a protected floor. Future archaeology and runtime work can move without silently breaking the windows that are already understood.&lt;/p&gt;
&lt;h3 id=&quot;renderer-bugs-got-synthetic-fixtures-instead-of-ad-hoc-screenshots&quot;&gt;Renderer bugs got synthetic fixtures instead of ad hoc screenshots&lt;/h3&gt;
&lt;p&gt;The cleanup commit &lt;code&gt;1663f43&lt;/code&gt; on 2026-03-19 is easy to misread as housekeeping. It is more important than that.&lt;/p&gt;
&lt;p&gt;It added focused renderer checks:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;tools/check_obj_vertical_flip.py&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;tools/check_bg_layer_priority.py&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Those scripts generate tiny scenes with one narrow purpose:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;prove the non-square vertically mirrored OBJ path&lt;/li&gt;
&lt;li&gt;prove BG4 and tile-priority ordering&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That is the right kind of renderer test for this project. Large captured frame windows are useful, but they are bad at isolating a single rule. Small synthetic scenes are much better at answering one question at a time.&lt;/p&gt;
&lt;p&gt;The repo now checks those fixtures across multiple renderers:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Python simple path&lt;/li&gt;
&lt;li&gt;Python &lt;code&gt;mode7-ppu&lt;/code&gt; path&lt;/li&gt;
&lt;li&gt;SDL runtime&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That is exactly the kind of cross-checking a port project needs when the same scene can be exercised through more than one implementation.&lt;/p&gt;
&lt;h3 id=&quot;cleanup-was-part-of-the-product-work&quot;&gt;Cleanup was part of the product work&lt;/h3&gt;
&lt;p&gt;The current repo state makes the cleanup motivation obvious.&lt;/p&gt;
&lt;p&gt;The worktree already contains:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;mutable &lt;code&gt;.mesen-config&lt;/code&gt; outputs&lt;/li&gt;
&lt;li&gt;large &lt;code&gt;tools/out&lt;/code&gt; trees&lt;/li&gt;
&lt;li&gt;generated design packs&lt;/li&gt;
&lt;li&gt;probe logs&lt;/li&gt;
&lt;li&gt;frame dumps&lt;/li&gt;
&lt;li&gt;scratch bridge outputs&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Without active cleanup, the difference between a committed result, a disposable intermediate file, and a stale experiment gets blurry fast.&lt;/p&gt;
&lt;p&gt;That is what &lt;code&gt;1663f43&lt;/code&gt; and &lt;code&gt;6076df3&lt;/code&gt; were fixing:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;tighter ignore policy&lt;/li&gt;
&lt;li&gt;generated-artifact cleanup targets&lt;/li&gt;
&lt;li&gt;removal of tracked build and cache artifacts&lt;/li&gt;
&lt;li&gt;pressure to remove hard-coded personal paths from promoted scripts&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This is not cosmetic. Port work slows down badly when the repo stops making it obvious which artifact is authoritative.&lt;/p&gt;
&lt;p&gt;The current roadmap treats that explicitly as a first-class execution track, alongside the ongoing archaeology lanes. That is the correct call.&lt;/p&gt;
&lt;h3 id=&quot;the-remaining-blocker-is-a-composition-problem-not-a-vague-unknown&quot;&gt;The remaining blocker is a composition problem, not a vague unknown&lt;/h3&gt;
&lt;p&gt;Commit &lt;code&gt;31f3ac7&lt;/code&gt; on 2026-03-19 added &lt;code&gt;tools/analyze_oam_delta.py&lt;/code&gt; and promoted late-intro OAM delta diagnostics into the main workflow.&lt;/p&gt;
&lt;p&gt;That matters because the late intro gap is now described with much better precision.&lt;/p&gt;
&lt;p&gt;The repo's current reading is roughly:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;queue-driven and bridge-visible native coverage extends through frame &lt;code&gt;1093&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;frame &lt;code&gt;986&lt;/code&gt; is no longer a generic mismatch; the BG path is close and the remaining error is in the OBJ/composition side&lt;/li&gt;
&lt;li&gt;frame &lt;code&gt;990&lt;/code&gt; behaves similarly when compared against bridge-visible output&lt;/li&gt;
&lt;li&gt;by frame &lt;code&gt;994&lt;/code&gt;, the committed scene variants no longer show a distinct probe-vs-bridge OAM fork&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That last point is important. It rules out one tempting explanation and keeps the next work item honest.&lt;/p&gt;
&lt;p&gt;The repo can now say:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;the bridge-visible path is real through &lt;code&gt;1093&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;the screenshot gap after &lt;code&gt;982&lt;/code&gt; is still open&lt;/li&gt;
&lt;li&gt;the unresolved part is not &quot;some random late intro behavior&quot;&lt;/li&gt;
&lt;li&gt;the unresolved part is mostly in Mode 7 OBJ composition and presentation timing&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That is the kind of blocker description that leads to fixes.&lt;/p&gt;
&lt;h3 id=&quot;what-the-project-looks-like-today&quot;&gt;What the project looks like today&lt;/h3&gt;
&lt;p&gt;From the initial import on 2026-02-26 to the current snapshot on 2026-03-19, this repo has moved from a reverse-engineering base to a working port workbench:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;deterministic Mesen capture and probe scripts&lt;/li&gt;
&lt;li&gt;extraction tooling for palettes, VRAM, chunks, and frame windows&lt;/li&gt;
&lt;li&gt;a modular C/SDL runtime that can replay native and extracted intro slices&lt;/li&gt;
&lt;li&gt;trace-backed provenance tooling for bank 30 and tilemap windows&lt;/li&gt;
&lt;li&gt;deterministic gameplay seed windows&lt;/li&gt;
&lt;li&gt;machine-checkable regression gates and callback contracts&lt;/li&gt;
&lt;li&gt;synthetic renderer fixtures for known correctness bugs&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That is solid progress for 45 commits in just over three weeks.&lt;/p&gt;
&lt;p&gt;It is also still clearly a port in progress.&lt;/p&gt;
&lt;p&gt;The active blockers in the roadmap are sensible and specific:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;close the &lt;code&gt;958..977&lt;/code&gt; bootstrap gap&lt;/li&gt;
&lt;li&gt;resolve the &lt;code&gt;986+&lt;/code&gt; final-screen composition gap&lt;/li&gt;
&lt;li&gt;keep replacing sampled attract windows with native callback/state playback&lt;/li&gt;
&lt;li&gt;continue the bank 30, bank 10, and bank 11 contract work needed for gameplay&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That is where this series leaves the repo for now.&lt;/p&gt;
&lt;p&gt;The important point is that the project is no longer trying to solve all of that with one tool or one style of evidence. It has separate surfaces for:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;extraction&lt;/li&gt;
&lt;li&gt;runtime playback&lt;/li&gt;
&lt;li&gt;archaeology&lt;/li&gt;
&lt;li&gt;validation&lt;/li&gt;
&lt;li&gt;cleanup&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That separation is what makes the current state believable. The repo is not just producing images that look close. It is building a system that can explain why a frame is right, detect when it stops being right, and keep moving when only part of the game is ready for native code.&lt;/p&gt;
</description>
<category>Articles</category>
<guid isPermaLink="true">https://coderlegion.com/13287/porting-test-drive-ii-from-snes-to-pc-part-4-validation-cleanup-and-current-blockers</guid>
<pubDate>Sat, 21 Mar 2026 13:48:16 +0000</pubDate>
</item>
</channel>
</rss>