SkillAgentSearch skills...

TinfoilWebServer

Install your packages from your own server

Install / Use

/learn @Myster-Tee/TinfoilWebServer
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

TinfoilWebServer

Description

Build your custom Nintendo Switch shop.

TinfoilWebServer is a simple and efficient cross platform web server application aiming at serving your personal Nintendo Switch packages (NSP, NSZ, XCI, etc.) to Tinfoil.

All served files must have "[titleid]" in the file name to be recognized by Tinfoil to show up in "New Games", "New DLC", and "New Updates".
Official Tinfoil documentation here.

Download

Releases page here.

** If you're downloading using macOS Safari, download your desired package by right-clicking on the link and selecting "Download Linked File", so Safari doesn't unzip the package automatically. Then you can unzip it afterwards using macOS's built-in Archive Utility.*

Requirements

The requirements depend on the version you choose to download.

Framework-Dependent version

This version is lightweight but you'll need to install the ASP.NET Core Runtime 8.X.X before running the server.

Framework-Independent version

No requirements but heavyweight.

Running the server

  1. Unzip the desired distribution to a location of your choice
  2. Create a TinfoilWebServer.config.json according to your needs
  3. Start the server according to the chosen distribution

By default, the TinfoilWebServer.config.json file will be searched in the program's current directory.
A template of TinfoilWebServer.config.json can be downloaded in the assets of the releases page here.

Windows

Run

TinfoilWebServer.exe

Linux and macOS

Run

./TinfoilWebServer

Portable version - Windows, Linux and macOS (Framework required)

Run

dotnet TinfoilWebServer.dll

Command line options

-c, --config        Custom location of the configuration file.
-d, --currentDir    Change the current directory.
-s, --winService    Run the server as a Windows service.
--sha256            Compute SHA256 passwords interactively.
--help              Display this help screen.
--version           Display version information.

Setting up Tinfoil on your Switch

  1. Launch Tinfoil
  2. Go to File Browser
  3. Press [-] button to add a new server
  4. Set Protocol to HTTP or HTTPS according to the server configuration
  5. Set Host to any host pointing to your server (or the server IP address)
    The server IP address is logged at server startup.
  6. If authentication is enabled, set Username and Password to one of the allowed users
  7. Set Title to a name of your choice

Download speed note: having a download/installation speed of ~10MB from Tinfoil is normal.
This low speed is only due to hardware limitation of Nintendo Switch, and is not at all related to some server limitation.

TinfoilWebServer.config.json format

{
  "ServedDirectories": string[],        // ex: ["C:\\SomeDir\\WindowsDirWithPackages", "/dev/sda1/LinuxDirWithPackages", ".", "/Users/yourname/Documents/macOSDirWithPackages"] !!! Don't forget to escape backslashes with another one !!! No need to escape spaces
  "StripDirectoryNames": boolean,       // «true» to remove directories names in URLs of served files, «false» otherwise
  "ServeEmptyDirectories": boolean,     // «true» to serve empty directories, «false» otherwise (has no effect when "StripDirectoryNames" is «true»)
  "AllowedExt": string[],               // List of file extensions to serve (default is ["xci", "nsz", "nsp", "xcz", "zip"])
  "MessageOfTheDay": string,            // The default welcome message displayed when Tinfoil successfully contacts the server
  "ExpirationMessage": string,          // The default displayed message when a user account has expired
  "CustomIndexPath": string,            // The path to a custom JSON file to be merged with the served index
  "Cache": {
    "AutoDetectChanges": boolean,       // «true» to auto-refresh the list of served files when a file system change is detected in the served directories, «false» otherwise
    "PeriodicRefreshDelay": string      // Periodic delay for forcing the refresh of served files, format is «[d'.']hh':'mm':'ss['.'fffffff]», ex: "01:30:15" for 1h30m15s, set «null» to disable
  },
  "Authentication": {
    "Enabled": boolean,                 // «true» to enable authentication, «false» otherwise
    "WebBrowserAuthEnabled": boolean,   // «true» to enable the native Web Browser login prompt when not authenticated (has no effect when "Authentication.Enabled" is «false»)
    "PwdType": string,                  // Defines the format of user passwords. Can be either "Sha256" or "Plaintext". Default is "Sha256".
    "Users": [                          // List of allowed users (use a comma as separator for declaring multiple users)
      {
        "Name": string,                 // The user name
        "Pwd": string,                  // The password
        "MaxFingerprints": number,      // The maximum number of fingerprints allowed for this user (default is 1)
        "MessageOfTheDay": string,      // Custom message for the user
        "ExpirationDate" : string,      // Expiration date in ISO 8601 format, ex: "2022-12-31T23:59:59Z". Set to «null» to disable expiration date.
        "ExpirationMessage" : string,   // Custom message for the user when account has expired
        "CustomIndexPath": string       // The path to a custom JSON file for this user to be merged with the served index
      }
    ]
  },
  "FingerprintsFilter": {
    "Enabled" : boolean,                // «true» to enable fingerprints validation filter, «false» otherwise (default is true)
    "FingerprintsFilePath": string      // The path to the file where to save allowed fingerprints
    "MaxFingerprints" : number          // The maximum number of global fingerprints allowed
  },
  "Blacklist": {
    "Enabled": boolean,                 // Enable or disable the IP blacklisting feature
    "FilePath": string,                 // The path of the file where to save blacklisted IPs
    "MaxConsecutiveFailedAuth": number, // The maximum number of consecutive unauthenticated requests to reach for blacklisting an IP
    "IsBehindProxy": boolean            // When set to true, incoming IP address will be taken fromFo "X-Forwarded-For" header otherwise it will be taken from TCP/IP protocol
  },
  "Kestrel": {                          // Web server configuration, see https://learn.microsoft.com/en-us/aspnet/core/fundamentals/servers/kestrel/endpoints?view=aspnetcore-6.0 for more information
    "Endpoints": {
      "Http": {
        "Url": string                   // The HTTP host (or IP address) and port that the server should listen to (ex: "http://0.0.0.0:80", "http://*:80/", "http://somedomain.com")
      },
      "HttpsInlineCertAndKeyFile": {    // See https://learn.microsoft.com/en-us/aspnet/core/fundamentals/servers/kestrel/endpoints?view=aspnetcore-6.0 for more examples and possibilities
        "Url": string,                  // The HTTPS host (or IP address) and port that the server should listen to (ex: "https://somedomain.com", "https://somedomain.com:8081")
        "Certificate": {
          "Path": string,               // The path to the certificate file (ex: "MyCertificate.cer")
          "KeyPath": string             // The path to the private key file (ex: "MyPrivateKey.key")
        }
      }
    },
    "Limits": {
      "MaxConcurrentConnections": number, // Sets the maximum number of open connection
    }
  },
  "Logging": {                          // See https://docs.microsoft.com/en-us/aspnet/core/fundamentals/logging/?view=aspnetcore-6.0 for more information
    "LogLevel": {
      "Default": string                 // The global log level, can be one of "Trace", "Debug", "Information", "Warning", "Error", "Critical", or "None"
    },
    "Console": {                        // See https://docs.microsoft.com/en-us/aspnet/core/fundamentals/logging/?view=aspnetcore-6.0 for more information
      "LogLevel": {
        "Default": string
      },
      "FormatterOptions": {
        "Format": string,               // The custom log format (see below for more information)
        "ExceptionFormat": string       // The custom exception format (see below for more information)
	  }	
    },
    "File": {                           // See https://github.com/nreco/logging#how-to-use for more information
      "Path": string,
      "Append": boolean,
      "MinLevel": string,
      "FileSizeLimitBytes": number,
      "MaxRollingFiles": number,
      "FormatterOptions": {
        "Format": string,               // The custom log format (see below for more information)
        "ExceptionFormat": string       // The custom exception format (see below for more information)
	  }	
    }
  }
}

When "Kestrel" configuration is omitted, server default listens to http://localhost:5000/ and https://localhost:5001.

Custom Index

Specifying a custom index in the configuration file allows to set (or combine) any extra property described in Tinfoil Custom Index documentation.
For example, using the JSON below, it is possible to enrich the served files with custom files out of served directories.

{
  "files": ["https://some/other/url1", "https://some/gdrive/folder"] // Will be combined with served files
}

IP Blacklisting

File format is text, one line per blacklisted IP. Empty lines will be ignored. Use # to write comments.

Fingerprints

A fingerprint consists in a unique Nintendo Switch device identifier. Tinfoil emits

View on GitHub
GitHub Stars174
CategoryDevelopment
Updated26d ago
Forks31

Languages

C#

Security Score

95/100

Audited on Feb 27, 2026

No findings