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.
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.*
The requirements depend on the version you choose to download.
This version is lightweight but you'll need to install the ASP.NET Core Runtime 8.X.X before running the server.
No requirements but heavyweight.
- Unzip the desired distribution to a location of your choice
- Create a TinfoilWebServer.config.json according to your needs
- 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.
Run
TinfoilWebServer.exe
Run
./TinfoilWebServer
Run
dotnet TinfoilWebServer.dll
-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.
- Launch Tinfoil
- Go to File Browser
- Press [-] button to add a new server
- Set Protocol to HTTP or HTTPS according to the server configuration
- Set Host to any host pointing to your server (or the server IP address)
The server IP address is logged at server startup. - If authentication is enabled, set Username and Password to one of the allowed users
- 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.
{
"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 welcome message displayed when Tinfoil successfully contacts the server
"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
"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.
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
}
File format is text, one line per blacklisted IP. Empty lines will be ignored. Use # to write comments.
A fingerprint consists in a unique Nintendo Switch device identifier. Tinfoil emits a fingerprint only when requesting the index, but not when requesting files. Thus specifying fingerprints in configuration will not prevent a user from downloading files.
When fingerprints are both allowed globally and at user level, server will check for a valid fingerprint among allowed user fingerprints and globally allowed fingerprints.
You can specify a custom log format using keywords between braces.
Some keywords accept options in the format of {SomeKeyword:SomeOptions}.
Example:
"Format" : "> {Date:yyyy-MM-dd@HH:mm:ss}-{LogLevel:U}-{Category}: {Message}{NewLine}{Exception}"
- {Date:<Option>}: the log date, optional option: a valid date format
- {NewLine}: appends a new line according to the current system (\r, \n or \r\n)
- {Message}: the log message
- {Category}: the log category (.NET Namespace)
- {EventId}: the log event ID
- {LogLevel:<Option>}: the log level. Optional options:
- SU: short log level upper case
- SL: short log level lower case
- U: log level upper case
- L: log level lower case
- {Exception}: the exception formatted according to the ExceptionFormat field
- {Date:<Option>}: same as {Date} keyword of Format field
- {NewLine}: same as {NewLine} keyword of Format field
- {Message}: the exception message
- {Type}: the exception type name
- {StackTrace}: the exception stack trace
Server can be run as a Windows service. To to this, service must first be registered using sc.exe, PowerShell New-Service cmdlet or any other method.
Don't forget to specify the --winService
command line parameter when registering the service.
Note: by default, Windows services are run in %WinDir%\System32, you can change the current directory using --currentDir command line parameter.
# PowerShell service registration example
New-Service TinfoilWebServer -BinaryPathName "<FullPathToExe> --winService --config ""<SomePathToConfigJson>"" --currentDir ""<SomePathToCurrentDir>"""
TinfoilWebServer can serve game saves by allowing "zip" file extension (by default).
To share your own saves, copy Tinfoil saves from SDCard/switch/tinfoil/saves/**/*.zip
to any of the served directories, preserving original file name.
If you plan to open your server to the Internet network (WAN) instead of local network (LAN) only, I would highly recommend you to:
- Setup HTTPS only
- Enable authentication to restrict access to some specific users
- Serve directories containining only Nintendo Switch files (without personal data)
- Restrict served file extensions to Nintendo Switch files
- Setup StripDirectoryNames setting to true to hide your personal folder tree organization
- Enable IP blacklistng feature
- Enable fingerprints filter feature
- Set Authentication.PwdType to "Sha256" to avoid storing plaintext user passwords in your config file
If you want to create your personal NSP Shop then check out these other similar projects: