DevProxy allows you to connect your localhost projects temporarily to the internet
DevProxies works by giving you a unique subdomain on the public API server. All requests to this subdomain will then be forwarded to the locally running DevProxy Client which then will call your local service, returning the results to the API. The Client will open an outgoing WebSocket to the API so no port-forwarding on the client side is necessary
Since this project was built as a weekend project security wasn't my primary concern. Internally the client uses the local URL as the BaseURL in the .NETs HttpClient, I don't know if there are any escapes where one can circumvent this (maybe by setting custom headers) If you know more about this or want to help me improve the security open an issue or contact me at [email protected]
First, install .Net 8 SDK Install Instructions
Then just run dotnet publish -c Release
inside the root folder
To install the client either copy the compilation output of AwoDevProxy.Client to your /bin folder on Linux or C:\Windows\system32 on Windows.
For Linux also an install script install-client-linux
is included in the repo which updates/installs the client into ~/.local/bin/devprxy
devprxy --proxy wss:https://devproxy-public-api.com --name my-subdomain --local http:https://localhost:1302 --key api_key-1234 --server-timeout 0:1:30 --try-reopen
The client supports the following arguments (also available under devprxy --help
)
Shorthand | Argument | Description |
---|---|---|
-s | --proxy | Address of the public API the client should connect to |
-l | --local | Address of the local service the client should proxy requests to |
-n | --name | The name of the subdomain the client should be accessible under |
-k | --key | Api key for the public API |
-t | --server-timeout | After how much time the public API should handle the request as timed out |
-r | --try-reopen | Automatically try to reopen the connection to the API when it was lost |
-b | --buffer-size | How large the local read buffer should be, defaults to 8kb |
-f | --force | Forcefully disconnects existing client with the same name from server |
-p | --password | Password for the resource which the server enforces |
-h | --help | Shows the help message |
If the client passes a password to the server with the --password
parameter, the server will redirect all requests to a password page. Once the password is entered the server will issue an auth cookie.
In Environments where cookies are not supported the server will also accept the password as a query parameter. The name of the auth parameter can be set with AuthParamName
in the server config, the default is devprxy-auth
.
The cookie can also be gained programmatically by performing a post request against the subdomain with the password set as a form field named after AuthParamName
The cookie is generated by the server using the following algorithm
- A 16-byte Fingerprint for the client is generated by concatenating Name and Password with a '#' sign and hashed using MD5
- The Api Fingerprint from the
CookieConfig
is read - An 8-byte Timestamp is generated from DateTime.UtcNow.Ticks
- The Api Fingerprint, The Client Fingerprint, and the Timestamp are written to an array in this order
- The array gets encrypted using AES ECB with the
SigningKey
andSigningIV
from theCookieConfig
and then base64 encoded - The encrypted array gets Base64 encoded and returned as the cookie
The cookie is only seen as valid if the following conditions are met
- The Cookie can be decrypted
- The Server Fingerprints are matching
- The Client Fingerprints are matching
- The Timestamp is older than the current UTC time
For Server deployment use the supplied Dockerfile in AwoDevProxy.Api
or the supplied compose file
The API will also use Environment Variables as configuration parameters with the default asp.net mapping (ProxyConfig.FixedKey -> PROXYCONFIG__FIXEDKEY)
The API understands the following config parameters
{
"ProxyConfig": {
"FixedKey": "3@rkRdrki^v@aB^@pDF6LgGgC%^6X9UU",
"MaxTimeout": "0:5:00",
"DefaultTimeout": "0:0:30",
"Domains": [
"my-domain.com",
"sudomain.other-domain.com"
]
},
"CookieConfig": {
"SigningKey": "2^F$9y#GuHfT!sf8H%bapZU9oTR7#Pj7",
"SigningIV": "GM6qudkIsv8U6W173xDPTA==",
"FingerPrint": "DEVPRXY!",
"AesBlockSize": 128
}
}
Config | Parameter | Description |
---|---|---|
ProyxConfig | FixedKey | This parameter sets the API key the client is requested to send on connection |
ProyxConfig | MaxTimeout | The maximum allowed timeout a client can request, if the client requests a longer value MaxTimeout is used instead |
ProyxConfig | DefaultTimeout | The default timeout which is used when the client doesn't specify |
ProyxConfig | Domains | Array of domains that the server should use for forwarding, if the domain contains a subdomain, the server expects the client name to be the first parameter (client-name.subdomain.exmaple.com) |
ProyxConfig | AuthParamName | The name of the Authentication parameter which must be passed for clients setting a password |
CookieConfig | SigningKey | The AES key used for cookie encryption, internally this value gets MD5 hashed before usage |
CookieConfig | SigningIV | The aes IV used for cookie encryption, encoded in Base64, if the IV is longer than the AesBlockSize it gets truncated if it's shorter it gets padded with zeroes |
CookieConfig | FingerPrint | The fingerprint used for the API, this value is used to identify the cookie being generated by this server instance |
CookieConfig | AesBlockSize | The block size used for the AES encryption, the default is 128. (I don't know why anyone would want to alter this, afaik 128 is the only option supported by .Net 8 AesCng) |
- install docket Docker Guide
- adjust the settings in
docker-copmose.override.yml
- run
docker compose build
- run
docket compose up -d
I know Microsoft DevTunnels exists, allowing greater flexibility. Although Microsoft's tools are required to use it, and you can't lock it to one service specifically. This Project aims to be a self-hostable alternative focusing on easy access to services in environments where one can't easily forward or open ports.