<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0">
<channel>
<title>Coder Legion - Recent posts tagged file-server</title>
<link>https://coderlegion.com/tag/file-server</link>
<description>Powered by Question2Answer</description>
<item>
<title>How to Deploy a Production-Ready File Server on a VPS for Free</title>
<link>https://coderlegion.com/14585/how-to-deploy-a-production-ready-file-server-on-a-vps-for-free</link>
<description>&lt;p&gt;Deploying a file server sounds simple.&lt;/p&gt;
&lt;p&gt;Making it production-ready is where most developers struggle.&lt;/p&gt;
&lt;p&gt;You don’t just need to run the app.&lt;br&gt;
You need to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;keep it running&lt;/li&gt;
&lt;li&gt;secure it&lt;/li&gt;
&lt;li&gt;handle traffic properly&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In this guide, you’ll deploy a real file server using Spring Boot, Nginx, and a VPS.&lt;/p&gt;
&lt;h3 id=&quot;start-with-a-ready-backend&quot;&gt;Start with a ready backend&lt;/h3&gt;
&lt;p&gt;Instead of building everything from scratch, you can start with a ready file server backend.&lt;/p&gt;
&lt;p&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://buildbasekit.com/boilerplates/filora-fs-lite/&quot;&gt;https://buildbasekit.com/boilerplates/filora-fs-lite/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;It already includes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;file upload APIs&lt;/li&gt;
&lt;li&gt;clean project structure&lt;/li&gt;
&lt;li&gt;production-ready setup&lt;/li&gt;
&lt;li&gt;easy deployment flow (used in this guide)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You can follow this tutorial directly using this boilerplate.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;what-you-ll-build&quot;&gt;What you’ll build&lt;/h3&gt;
&lt;p&gt;By the end, you’ll have a file server that:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;accepts file uploads  &lt;/li&gt;
&lt;li&gt;runs continuously with systemd  &lt;/li&gt;
&lt;li&gt;serves traffic via Nginx  &lt;/li&gt;
&lt;li&gt;uses HTTPS (SSL)  &lt;/li&gt;
&lt;li&gt;is protected with a firewall  &lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id=&quot;prerequisites&quot;&gt;Prerequisites&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;VPS (Ubuntu recommended)  &lt;/li&gt;
&lt;li&gt;Java installed  &lt;/li&gt;
&lt;li&gt;your Spring Boot jar ready  &lt;/li&gt;
&lt;li&gt;domain (optional but needed for HTTPS)  &lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id=&quot;1-prepare-your-app&quot;&gt;1. Prepare your app&lt;/h3&gt;
&lt;p&gt;Do not hardcode configs.&lt;/p&gt;
&lt;p&gt;Use environment variables instead.&lt;/p&gt;
&lt;p&gt;Example:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;
spring.application.name=filorafs
server.port=8080
storage.local.path=/opt/filora/uploads

&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h3 id=&quot;2-connect-to-your-vps&quot;&gt;2. Connect to your VPS&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;
ssh -i your-key.key ubuntu@your-ip

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Install dependencies:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;
sudo apt update &amp;amp;&amp;amp; sudo apt upgrade -y
sudo apt install openjdk-21-jdk nginx ufw -y

&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h3 id=&quot;3-setup-app-directory&quot;&gt;3. Setup app directory&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;
sudo mkdir -p /opt/filora
sudo chown -R $USER:$USER /opt/filora

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Upload your jar:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;
scp target/app.jar ubuntu@your-ip:/opt/filora/

&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h3 id=&quot;4-add-environment-variables&quot;&gt;4. Add environment variables&lt;/h3&gt;
&lt;p&gt;Create &lt;code&gt;.env&lt;/code&gt; file:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;
DB_PASSWORD=your_password
SERVER_PORT=8080
STORAGE_PATH=/opt/filora/uploads

&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h3 id=&quot;5-run-app-manually&quot;&gt;5. Run app manually&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;
cd /opt/filora
source .env
java -jar app.jar

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If it works → move forward.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;6-setup-systemd-important-&quot;&gt;6. Setup systemd (important)&lt;/h3&gt;
&lt;p&gt;Create service:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;
sudo nano /etc/systemd/system/app.service

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Paste:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;
[Unit]
Description=File Server
After=network.target

[Service]
User=ubuntu
WorkingDirectory=/opt/filora
EnvironmentFile=/opt/filora/.env
ExecStart=/usr/bin/java -jar /opt/filora/app.jar
Restart=always

[Install]
WantedBy=multi-user.target

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Start service:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;
sudo systemctl daemon-reload
sudo systemctl enable app
sudo systemctl start app

&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h3 id=&quot;7-setup-nginx&quot;&gt;7. Setup Nginx&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;
sudo nano /etc/nginx/sites-available/app

&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;
server {
listen 80;
server_name yourdomain.com;

client_max_body_size 100M;

location / {
    proxy_pass http://localhost:8080;
}

}

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Enable:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;
sudo ln -s /etc/nginx/sites-available/app /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx

&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h3 id=&quot;8-add-https&quot;&gt;8. Add HTTPS&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;
sudo apt install certbot python3-certbot-nginx -y
sudo certbot --nginx -d yourdomain.com

&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h3 id=&quot;9-secure-server&quot;&gt;9. Secure server&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;
sudo ufw allow OpenSSH
sudo ufw allow 'Nginx Full'
sudo ufw enable

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Do NOT expose port 8080 publicly.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;10-test-everything&quot;&gt;10. Test everything&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;upload file  &lt;/li&gt;
&lt;li&gt;check logs  &lt;/li&gt;
&lt;li&gt;verify HTTPS  &lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Logs:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;
journalctl -u app -f

&lt;/code&gt;&lt;/pre&gt;
&lt;hr&gt;
&lt;h3 id=&quot;common-mistakes&quot;&gt;Common mistakes&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;exposing backend port directly  &lt;/li&gt;
&lt;li&gt;wrong file permissions  &lt;/li&gt;
&lt;li&gt;hardcoded configs  &lt;/li&gt;
&lt;li&gt;skipping HTTPS  &lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;h3 id=&quot;final-thoughts&quot;&gt;Final thoughts&lt;/h3&gt;
&lt;p&gt;A file server is easy to build.&lt;/p&gt;
&lt;p&gt;A production-ready setup is what actually matters.&lt;/p&gt;
&lt;p&gt;Once you understand this flow:&lt;br&gt;
build → deploy → proxy → secure&lt;/p&gt;
&lt;p&gt;you can deploy almost any backend.&lt;/p&gt;
&lt;hr&gt;
&lt;h3 id=&quot;skip-the-setup&quot;&gt;Skip the setup&lt;/h3&gt;
&lt;p&gt;If you don’t want to do all this manually:&lt;/p&gt;
&lt;p&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://buildbasekit.com/boilerplates/filora-fs-lite/&quot;&gt;https://buildbasekit.com/boilerplates/filora-fs-lite/&lt;/a&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;ready backend  &lt;/li&gt;
&lt;li&gt;file upload APIs  &lt;/li&gt;
&lt;li&gt;production structure  &lt;/li&gt;
&lt;li&gt;open source&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Build faster. Focus on features.&lt;/p&gt;
</description>
<category>Tutorials</category>
<guid isPermaLink="true">https://coderlegion.com/14585/how-to-deploy-a-production-ready-file-server-on-a-vps-for-free</guid>
<pubDate>Sun, 12 Apr 2026 16:42:31 +0000</pubDate>
</item>
<item>
<title>DevLog 20250806: &quot;Change Version&quot; - File Changes History-Only Version Control for Binary Assets</title>
<link>https://coderlegion.com/4483/devlog-20250806-change-version-file-changes-history-only-version-control-binary-assets</link>
<description>&lt;h3 id=&quot;overview&quot;&gt;Overview&lt;/h3&gt;
&lt;p&gt;&lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/MethodoxTech/cv&quot;&gt;&lt;code&gt;cv&lt;/code&gt;&lt;/a&gt; is a command-line utility I originally used for personal Unreal Engine projects, where proper version control for binary assets was lacking - but I still wanted to track what had changed, at least at the file-system level. It served its purpose well, but after switching from Unreal Engine to Godot, I haven't needed it as much.&lt;/p&gt;
&lt;p&gt;For &lt;strong&gt;Divooka&lt;/strong&gt;, as our repository grows and more GUI-related work gets involved, we've increasingly run into the issue of syncing assets across different workstations. Perhaps it's time to bring this old tool back to life.&lt;/p&gt;
&lt;h3 id=&quot;demand&quot;&gt;Demand&lt;/h3&gt;
&lt;p&gt;The core requirements are simple:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;View file change history - ideally alongside corresponding Git commit history.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Compare differences&lt;/strong&gt; - similar to Git commits, but focused on files, not content.&lt;/li&gt;
&lt;li&gt;Synchronize files between machines.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Regarding the third point, we’ve made some adjustments to fit our workflow:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Since we generally focus on one PR at a time and aren’t concerned with previous builds, collaborators mainly need the &lt;strong&gt;latest version&lt;/strong&gt; of assets - not their version history.&lt;/li&gt;
&lt;li&gt;Everything must remain &lt;strong&gt;simple, maintainable, and cost zero&lt;/strong&gt;.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;reference-workflow&quot;&gt;Reference Workflow&lt;/h3&gt;
&lt;p&gt;Based on my previous experience at a game company working on AAA titles, our typical flow involved:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Git for source code&lt;/li&gt;
&lt;li&gt;Perforce for asset versioning&lt;/li&gt;
&lt;li&gt;Azure DevOps (ADO) for task tracking&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Each PR included a GitHub pull request, a corresponding Perforce commit, and an ADO task - usually cross-referenced manually. Every Perforce commit needed to mention which GitHub PR it related to.&lt;/p&gt;
&lt;h3 id=&quot;the-implementation&quot;&gt;The Implementation&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Change Version (cv)&lt;/strong&gt; is a CLI tool that provides quick check against a repo's changes without saving any changed contents. It does so by recording only the update time. The outputs is just like git status, without diff.&lt;/p&gt;
&lt;p&gt;This is useful for cases when we DO NOT want to do version control yet would still want the capability to see which files has changed, as in the case of multimedia projects (e.g. game projects).&lt;/p&gt;
&lt;h4 id=&quot;usage&quot;&gt;Usage&lt;/h4&gt;
&lt;p&gt;The utility supports the following key commands:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;init&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;status&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;log&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;commit -m &amp;lt;Message&amp;gt;&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h4 id=&quot;output-folders-amp-files&quot;&gt;Output Folders &amp;amp; Files&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;.cv&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;cv&lt;/strong&gt; saves history inside the &lt;code&gt;.cv&lt;/code&gt; folder. File update time is stored as utc.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;.cvignore&lt;/code&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;cv&lt;/strong&gt; uses a &lt;code&gt;.cvignore&lt;/code&gt; file, which shares the same &lt;code&gt;.gitignore&lt;/code&gt; format as git, this is used to decide which files cv should consider when issuing &lt;code&gt;status&lt;/code&gt; command; Notice we are using a new file name instead of using &lt;code&gt;.gitignore&lt;/code&gt; directly - this is to allow the same place having a git repo.&lt;/p&gt;
&lt;h4 id=&quot;ignore-rules&quot;&gt;Ignore Rules&lt;/h4&gt;
&lt;p&gt;I've decided to follow Git's philosophy: everything is considered &quot;important&quot; by default, unless explicitly ignored.&lt;/p&gt;
&lt;p&gt;Here’s a basic implementation:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;private static string[]? ReadIgnoreRules()
{
string[]? ignoreRules = null;
if (File.Exists(IgnoreFilename))
ignoreRules = File.ReadAllLines(IgnoreFilename)
.Where(l =&amp;gt; !string.IsNullOrWhiteSpace(l) &amp;amp;&amp;amp; !l.Trim().StartsWith('#'))
.ToArray(); // Skip empty lines and comments
return ignoreRules;
}
private static bool ShouldIgnore(string[] rules, string path)
=&amp;gt; rules.Any(path.StartsWith);
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To support more robust wildcard patterns, here’s an upgraded version:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-csharp&quot;&gt;public class IgnoreRule
{
    #region Properties
    private readonly Regex _regex;
    public bool IsNegation { get; }
    #endregion

    #region Construction
    public IgnoreRule(string pattern)
    {
        // Support for !foo to &quot;unignore&quot;
        if (pattern.StartsWith('!'))
        {
            IsNegation = true;
            pattern = pattern[1..];
        }

        // Anchor pattern at repo root if it starts with '/'
        bool anchored = pattern.StartsWith('/');
        if (anchored) 
            pattern = pattern[1..];

        // Convert Git-style glob to regex
        _regex = new Regex(
            &quot;^&quot; +
            Regex.Escape(pattern)
                 .Replace(@&quot;\*\*/&quot;, &quot;(@@SLUG@@/)&quot;)
                 .Replace(@&quot;\*\*&quot;, &quot;.*&quot;)
                 .Replace(@&quot;\*&quot;, @&quot;[^/]*&quot;)
                 .Replace(@&quot;\?&quot;, @&quot;[^/]&quot;)
                 .Replace(&quot;@@SLUG@@&quot;, &quot;.*&quot;) +
            (anchored ? &quot;$&quot; : &quot;(?:$|/)&quot;),
            RegexOptions.Compiled | RegexOptions.IgnoreCase
        );
    }
    #endregion

    #region Methods
    public bool IsMatch(string path, string repoRoot)
    {
        // If anchored, the path is relative to repoRoot already
        return _regex.IsMatch(path);
    }
    #endregion
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;At this stage, creating a &lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/MethodoxTech/cv/commit/c811447b7ed47b5d9d540b4aa16c7a68bb505060&quot;&gt;unit test&lt;/a&gt; feels essential.&lt;/p&gt;
&lt;p&gt;Based on what we have so far, it seems plausible to implement a layer of file transfer service to achieve synching of files between workstations with the help of an intermediate file server.&lt;/p&gt;
&lt;h3 id=&quot;file-transfer&quot;&gt;File Transfer&lt;/h3&gt;
&lt;p&gt;I talked about the &lt;a rel=&quot;nofollow&quot; href=&quot;https://dev.to/methodox/devlog-20250804-simple-file-uploading-service-1g26&quot;&gt;need for a simple file-uploading service&lt;/a&gt; just yesterday. Today’s use case is a bit different, as it's strictly internal - we don’t need to support multi-tenant scenarios and we have a fairly accurate idea of our storage needs. Scalability isn’t a major concern.&lt;/p&gt;
&lt;h4 id=&quot;server-options&quot;&gt;Server Options&lt;/h4&gt;
&lt;p&gt;We’re considering ASP.NET Core vs raw TCP sockets for the server:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;&lt;th&gt;Concern             &lt;/th&gt;&lt;th&gt;Raw TCP / FTP                    &lt;/th&gt;&lt;th&gt;HTTP (ASP.NET Core)&lt;/th&gt;&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Reliability&lt;/strong&gt;     &lt;/td&gt;&lt;td&gt;Requires custom framing, retries &lt;/td&gt;&lt;td&gt;Built-in streaming, timeouts, retries&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Security&lt;/strong&gt;        &lt;/td&gt;&lt;td&gt;Must implement SSH/SSL manually  &lt;/td&gt;&lt;td&gt;HTTPS support out-of-the-box, auth middleware&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Chunking/Resume&lt;/strong&gt; &lt;/td&gt;&lt;td&gt;Reinvent the protocol            &lt;/td&gt;&lt;td&gt;Use &lt;code&gt;Range&lt;/code&gt; headers, &lt;a rel=&quot;nofollow&quot; href=&quot;https://tus.io&quot;&gt;tus.io&lt;/a&gt;, etc.&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Deployment&lt;/strong&gt;      &lt;/td&gt;&lt;td&gt;Requires FTP daemon, ports, etc. &lt;/td&gt;&lt;td&gt;ASP.NET + Kestrel or NGINX&lt;/td&gt;&lt;/tr&gt;
&lt;tr&gt;&lt;td&gt;&lt;strong&gt;Extensibility&lt;/strong&gt;   &lt;/td&gt;&lt;td&gt;Hard to add endpoints            &lt;/td&gt;&lt;td&gt;Minimal APIs, MVC, SignalR, gRPC, DI, etc.&lt;/td&gt;&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Because we plan to expose the server on the internet, &lt;strong&gt;authentication is a must&lt;/strong&gt;, even if it adds some programming overhead.&lt;/p&gt;
&lt;h4 id=&quot;endpoints&quot;&gt;Endpoints&lt;/h4&gt;
&lt;p&gt;To start, simple endpoints suffice for basic usages:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;GET  /files&lt;/code&gt;: Returns a JSON list of all tracked paths.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;GET  /files/{**path}&lt;/code&gt;: Streams the latest copy of a single file.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;PUT  /files/{**path}&lt;/code&gt;: Uploads or overwrites a file.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;DELETE /files/{**path}&lt;/code&gt; Removes a file.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 id=&quot;testing-the-server&quot;&gt;Testing the Server&lt;/h3&gt;
&lt;p&gt;Example usage:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-bash&quot;&gt;# List files
curl -H &quot;X-Api-Key: my-super-secret-key&quot; https://localhost:5001/files

# Upload a file
curl -X PUT -H &quot;X-Api-Key: my-super-secret-key&quot; --data-binary @myfile.txt https://localhost:5001/files/docs/myfile.txt

# Download a file
curl -H &quot;X-Api-Key: my-super-secret-key&quot; https://localhost:5001/files/docs/myfile.txt -o downloaded.txt
&lt;/code&gt;&lt;/pre&gt;
&lt;h3 id=&quot;summary&quot;&gt;Summary&lt;/h3&gt;
&lt;p&gt;Today, I focused on:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Modernizing and refactoring code; upgrading the framework&lt;/li&gt;
&lt;li&gt;Making the program AoT-compatible&lt;/li&gt;
&lt;li&gt;Drafting the setup for file sync and server&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;A few &lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/MethodoxTech/cv/blob/master/TODO.md&quot;&gt;TODO items&lt;/a&gt; still need to be addressed before safe syncing can be implemented.&lt;/p&gt;
&lt;p&gt;Notably, the server doesn’t need to understand &lt;code&gt;cv&lt;/code&gt; or &lt;code&gt;RepoStorage&lt;/code&gt; - its only job is to &lt;strong&gt;store the latest version&lt;/strong&gt; of each file. Maintaining accurate timestamps isn’t practical; instead, &lt;strong&gt;storing an MD5 checksum&lt;/strong&gt; is a better way to avoid unnecessary uploads/downloads.&lt;/p&gt;
&lt;p&gt;In an ideal world, we’d have a tool tailored perfectly to our needs. In reality, we often find ourselves choosing between overengineered tools that don’t quite fit or having no suitable tool at all.&lt;/p&gt;
&lt;p&gt;When the need is real, it’s worth rolling up your sleeves and investing some time in building the right tooling.&lt;/p&gt;
&lt;h3 id=&quot;references&quot;&gt;References&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Wiki: &lt;a rel=&quot;nofollow&quot; href=&quot;https://wiki.methodox.io/en/Utilities/CLI/cv&quot;&gt;https://wiki.methodox.io/en/Utilities/CLI/cv&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Source: &lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/MethodoxTech/cv&quot;&gt;https://github.com/MethodoxTech/cv&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
</description>
<category>CI/CD Pipelines</category>
<guid isPermaLink="true">https://coderlegion.com/4483/devlog-20250806-change-version-file-changes-history-only-version-control-binary-assets</guid>
<pubDate>Wed, 06 Aug 2025 20:37:18 +0000</pubDate>
</item>
<item>
<title>DevLog 20250804: Simple File Uploading Service (A Request Unfulfilled)</title>
<link>https://coderlegion.com/4422/devlog-20250804-simple-file-uploading-service-a-request-unfulfilled</link>
<description>&lt;p&gt;Revision: 001&lt;/p&gt;
&lt;p&gt;&lt;em&gt;(This post identifies a problem and is not generating a solution for it yet.)&lt;/em&gt;&lt;/p&gt;
&lt;h3 id=&quot;the-problem&quot;&gt;The Problem&lt;/h3&gt;
&lt;p&gt;Wouldn’t it be nice if we had a simple way to share our scripts so others could use them immediately?&lt;/p&gt;
&lt;p&gt;Pure attempted this with &lt;a rel=&quot;nofollow&quot; href=&quot;https://github.com/Pure-the-Language/CentralSnippets&quot;&gt;CentralSnippets&lt;/a&gt;, which makes it straightforward on the client side (just call something like &lt;code&gt;Pull(&quot;Markdown/BuildToC&quot;, disableSSL: false)&lt;/code&gt;) while relying on GitHub’s PR-based upload process.&lt;/p&gt;
&lt;p&gt;For Divooka, we want to achieve something similar - perhaps even simpler. But file sharing inevitably raises three unavoidable concerns:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;User authentication&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Content management&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;API or user interface design&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 id=&quot;user-authentication&quot;&gt;User Authentication&lt;/h3&gt;
&lt;p&gt;When we’re logged in, we often take it for granted - but most platforms require an account to access core functions. For a file-uploading service, the question becomes: &lt;em&gt;which&lt;/em&gt; account system should we use?&lt;/p&gt;
&lt;p&gt;OAuth can help, but it doesn’t remove the fact that &lt;em&gt;users still need to create an account with the service&lt;/em&gt;. That, in turn, means there needs to be an account server.&lt;/p&gt;
&lt;p&gt;One possible simplification: GCP’s Firebase Authentication.&lt;/p&gt;
&lt;h3 id=&quot;content-management&quot;&gt;Content Management&lt;/h3&gt;
&lt;p&gt;Once uploaded, files could live on a dedicated file server, or be distributed via a CDN to reduce server load.&lt;/p&gt;
&lt;p&gt;Using a CDN is often the simplest long-term approach. However, you still need an intermediate server to communicate with the CDN - you can’t just expose it directly.&lt;/p&gt;
&lt;p&gt;Some platforms, like AWS and GCP, offer Signed URLs, which allow controlled access without routing through a central server first.&lt;/p&gt;
&lt;h3 id=&quot;api-or-access-interface&quot;&gt;API or Access Interface&lt;/h3&gt;
&lt;p&gt;Users might upload files via:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Web forms&lt;/li&gt;
&lt;li&gt;HTTP APIs&lt;/li&gt;
&lt;li&gt;CLI tools&lt;/li&gt;
&lt;li&gt;Dedicated protocols&lt;/li&gt;
&lt;li&gt;Client-side libraries&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The challenge is deciding which of these methods to support and how to balance simplicity with flexibility.&lt;/p&gt;
&lt;h3 id=&quot;accessing&quot;&gt;Accessing&lt;/h3&gt;
&lt;p&gt;Accessing the files is the easy part: generate a URL, and the file can most likely be downloaded directly over HTTP.&lt;/p&gt;
&lt;h3 id=&quot;the-ideal-picture&quot;&gt;The Ideal Picture&lt;/h3&gt;
&lt;p&gt;So, what would a general-purpose, &lt;em&gt;ideal&lt;/em&gt; file-uploading service look like?&lt;/p&gt;
&lt;p&gt;Key aspects might include:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Quick deployment and re-deployment of multiple dedicated file servers&lt;/li&gt;
&lt;li&gt;Configurable backends for storage and delivery&lt;/li&gt;
&lt;li&gt;Fine-grained access control for uploaded resources&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;All of which sounds like we’re edging into &lt;strong&gt;BaaS (Backend-as-a-Service)&lt;/strong&gt; territory.&lt;/p&gt;
</description>
<category>Web Dev</category>
<guid isPermaLink="true">https://coderlegion.com/4422/devlog-20250804-simple-file-uploading-service-a-request-unfulfilled</guid>
<pubDate>Mon, 04 Aug 2025 19:44:19 +0000</pubDate>
</item>
</channel>
</rss>