diff --git a/.dockerignore b/.dockerignore
new file mode 100644
index 0000000..bf79e22
--- /dev/null
+++ b/.dockerignore
@@ -0,0 +1,11 @@
+bin/
+obj/
+*.user
+*.suo
+*.log
+.vs/
+.vscode/
+.git/
+.gitignore
+Dockerfile
+.dockerignore
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
index 35063fc..caed449 100644
--- a/.gitignore
+++ b/.gitignore
@@ -51,4 +51,5 @@ CodeCoverage/
# NUnit
*.VisualState.xml
TestResult.xml
-nunit-*.xml
\ No newline at end of file
+nunit-*.xml
+.DS_Store
diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 0000000..101e03d
--- /dev/null
+++ b/Dockerfile
@@ -0,0 +1,23 @@
+FROM mcr.microsoft.com/dotnet/sdk:9.0 AS build
+WORKDIR /src
+
+# Copy csproj and restore dependencies
+COPY Meshtastic.Mqtt.csproj ./
+RUN dotnet restore
+
+# Copy the rest of the code
+COPY . ./
+RUN dotnet publish -c Release -o /app
+
+# Build runtime image
+FROM mcr.microsoft.com/dotnet/runtime:9.0
+WORKDIR /app
+COPY --from=build /app ./
+
+# Expose ports
+EXPOSE 1883 8883
+
+# Set environment variable to control SSL mode
+# ENV SSL=true # Uncomment to enable SSL by default
+
+ENTRYPOINT ["dotnet", "Meshtastic.Mqtt.dll"]
\ No newline at end of file
diff --git a/Meshtastic.Mqtt.csproj b/Meshtastic.Mqtt.csproj
new file mode 100644
index 0000000..f46a74b
--- /dev/null
+++ b/Meshtastic.Mqtt.csproj
@@ -0,0 +1,30 @@
+
+
+
+ Exe
+ net9.0
+ enable
+ enable
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ PreserveNewest
+
+
+
+
diff --git a/Meshtastic.Mqtt.sln b/Meshtastic.Mqtt.sln
new file mode 100644
index 0000000..ce050c9
--- /dev/null
+++ b/Meshtastic.Mqtt.sln
@@ -0,0 +1,24 @@
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio Version 17
+VisualStudioVersion = 17.5.2.0
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Meshtastic.Mqtt", "Meshtastic.Mqtt.csproj", "{7467C293-5E7D-1ADF-451D-7E36BDAC9410}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|Any CPU = Debug|Any CPU
+ Release|Any CPU = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {7467C293-5E7D-1ADF-451D-7E36BDAC9410}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {7467C293-5E7D-1ADF-451D-7E36BDAC9410}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {7467C293-5E7D-1ADF-451D-7E36BDAC9410}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {7467C293-5E7D-1ADF-451D-7E36BDAC9410}.Release|Any CPU.Build.0 = Release|Any CPU
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {62FE50C6-004E-4C4D-BE74-89E28A6A1064}
+ EndGlobalSection
+EndGlobal
diff --git a/Program.cs b/Program.cs
new file mode 100644
index 0000000..c6af7ac
--- /dev/null
+++ b/Program.cs
@@ -0,0 +1,178 @@
+using MQTTnet.Server;
+using Meshtastic.Protobufs;
+using Google.Protobuf;
+using Serilog;
+using MQTTnet.Protocol;
+using System.Runtime.Loader;
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.Hosting;
+using Serilog.Formatting.Compact;
+using Meshtastic.Crypto;
+using Meshtastic;
+using System.Security.Authentication;
+using System.Security.Cryptography.X509Certificates;
+using System.Reflection;
+
+var mqttFactory = new MqttServerFactory();
+
+// #if SSL
+var currentPath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)!;
+#pragma warning disable SYSLIB0057 // Type or member is obsolete
+var certificate = new X509Certificate2(Path.Combine(currentPath, "certificate.pfx"), "large4cats", X509KeyStorageFlags.Exportable);
+#pragma warning restore SYSLIB0057 // Type or member is obsolete
+
+var mqttServerOptions = new MqttServerOptionsBuilder()
+ .WithoutDefaultEndpoint() // This call disables the default unencrypted endpoint on port 1883
+ .WithEncryptedEndpoint()
+ .WithEncryptedEndpointPort(8883)
+ .WithEncryptionCertificate(certificate.Export(X509ContentType.Pfx))
+ .WithEncryptionSslProtocol(SslProtocols.Tls12)
+ .Build();
+ Log.Logger.Information("Using SSL certificate for MQTT server");
+
+// If you want to use a non-encrypted MQTT server, you can uncomment the following lines instead of the above
+// var mqttServerOptions = new MqttServerOptionsBuilder()
+// .WithDefaultEndpoint()
+// .WithDefaultEndpointPort(1883)
+// .Build();
+// Log.Logger.Information("Using unencrypted MQTT server");
+// #endif
+
+Log.Logger = new LoggerConfiguration()
+ .MinimumLevel.Debug()
+ .WriteTo.Console(new RenderedCompactJsonFormatter())
+ // .WriteTo.File(new RenderedCompactJsonFormatter(), "log.json", rollingInterval: RollingInterval.Hour) // File logging can be enabled if needed
+ .CreateLogger();
+
+using var mqttServer = mqttFactory.CreateMqttServer(mqttServerOptions);
+
+static Data? DecryptMeshPacket(ServiceEnvelope serviceEnvelope)
+{
+ var nonce = new NonceGenerator(serviceEnvelope.Packet.From, serviceEnvelope.Packet.Id).Create();
+
+ var decrypted = PacketEncryption.TransformPacket(serviceEnvelope.Packet.Encrypted.ToByteArray(), nonce, Resources.DEFAULT_PSK);
+ var payload = Data.Parser.ParseFrom(decrypted);
+
+ if (payload.Portnum > PortNum.UnknownApp && payload.Payload.Length > 0)
+ return payload;
+
+ // Was not able to decrypt the payload
+ return null;
+}
+
+mqttServer.InterceptingPublishAsync += async (args) =>
+{
+ try
+ {
+ if (args.ApplicationMessage.Payload.Length == 0)
+ {
+ Log.Logger.Warning("Received empty payload on topic {@Topic} from {@ClientId}", args.ApplicationMessage.Topic, args.ClientId);
+ args.ProcessPublish = false; // This will block empty packets
+ return;
+ }
+ var serviceEnvelope = ServiceEnvelope.Parser.ParseFrom(args.ApplicationMessage.Payload);
+
+ // Block malformed service envelopes / packets
+ if (
+ String.IsNullOrWhiteSpace(serviceEnvelope.ChannelId) ||
+ String.IsNullOrWhiteSpace(serviceEnvelope.GatewayId) ||
+ serviceEnvelope.Packet == null ||
+ serviceEnvelope.Packet.Id < 1 ||
+ serviceEnvelope.Packet.From < 1 ||
+ serviceEnvelope.Packet.Encrypted == null ||
+ serviceEnvelope.Packet.Encrypted.Length < 1 ||
+ serviceEnvelope.Packet.Decoded != null)
+ {
+ Log.Logger.Warning("Service envelope or packet is malformed. Blocking packet on topic {@Topic} from {@ClientId}", args.ApplicationMessage.Topic, args.ClientId);
+ args.ProcessPublish = false;
+ return;
+ }
+
+ var data = DecryptMeshPacket(serviceEnvelope);
+ // If we were not able to decrypt the packet, it is likely encrypted with an unknown PSK
+ // Uncomment the following lines if you want to block these packets
+ // if (data == null)
+ // {
+ // Log.Logger.Warning("Service envelope does not contain a valid packet. Blocking packet");
+ // args.ProcessPublish = false; // This will block packets that are not valid protobuf packets
+ // return;
+ // }
+
+ if (data?.Portnum == PortNum.TextMessageApp)
+ {
+ Log.Logger.Information("Received text message on topic {@Topic} from {@ClientId}: {@Message}",
+ args.ApplicationMessage.Topic, args.ClientId, data.Payload.ToStringUtf8());
+ }
+ else
+ {
+ Log.Logger.Information("Received packet on topic {@Topic} from {@ClientId} with port number: {@Portnum}",
+ args.ApplicationMessage.Topic, args.ClientId, data?.Portnum);
+ }
+
+ // Any further validation logic to block a packet can be added here
+ args.ProcessPublish = true;
+ }
+ catch (InvalidProtocolBufferException)
+ {
+ Log.Logger.Warning("Failed to decode presumed protobuf packet. Blocking");
+ args.ProcessPublish = false; // This will block packets encrypted on unknown PSKs
+ }
+ catch (Exception ex)
+ {
+ Log.Logger.Error("Exception occured while attempting to decode packet on {@Topic} from {@ClientId}: {@Exception}", args.ApplicationMessage.Topic, args.ClientId, ex.Message);
+ args.ProcessPublish = false; // This will block packets that caused us to encounter an exception
+ }
+};
+
+mqttServer.InterceptingSubscriptionAsync += (args) =>
+{
+ args.ProcessSubscription = true; // Subscription filtering logic can be added here to only allow certain topics
+
+ return Task.CompletedTask;
+};
+
+mqttServer.ValidatingConnectionAsync += (args) =>
+{
+ args.ReasonCode = true ? // Authentication logic can be added here
+ MqttConnectReasonCode.Success : MqttConnectReasonCode.BadUserNameOrPassword;
+
+ // You can block connections based on client ID, username, ip, etc.
+ return Task.CompletedTask;
+};
+
+static IHostBuilder CreateHostBuilder(string[] args)
+{
+ return Host.CreateDefaultBuilder(args)
+ .UseConsoleLifetime()
+ .ConfigureServices((hostContext, services) =>
+ {
+ services
+ .AddSingleton(Console.Out);
+ });
+}
+
+
+using var host = CreateHostBuilder(args).Build();
+await host.StartAsync();
+var lifetime = host.Services.GetRequiredService();
+await mqttServer.StartAsync();
+
+var ended = new ManualResetEventSlim();
+var starting = new ManualResetEventSlim();
+
+AssemblyLoadContext.Default.Unloading += ctx =>
+{
+ starting.Set();
+ Log.Logger.Debug("Waiting for completion");
+ ended.Wait();
+};
+
+starting.Wait();
+
+Log.Logger.Debug("Received signal gracefully shutting down");
+await mqttServer.StopAsync();
+Thread.Sleep(1000);
+ended.Set();
+
+lifetime.StopApplication();
+await host.WaitForShutdownAsync();
diff --git a/README.md b/README.md
index 4d495b9..2d4548e 100644
--- a/README.md
+++ b/README.md
@@ -1,2 +1,71 @@
-# mqtt
-A meshtastic native packet aware MQTT broker
+# Meshtastic MQTT Broker Boilerplate
+
+This project provides an MQTT broker boilerplate specifically designed for Meshtastic device networks. It handles encrypted mesh packets, validates messages, and can be configured to run with or without SSL.
+
+## Features
+
+- MQTT server implementation for Meshtastic devices
+- Support for encrypted mesh packet handling and validation
+- SSL support for secure MQTT connections
+- Configurable logging with Serilog
+- Packet filtering and validation logic
+
+## Docker Setup
+
+### Prerequisites
+
+- Docker installed on your system
+- Certificate file (if using SSL mode)
+
+### Docker Installation
+
+1. Clone the repository:
+ ```bash
+ git clone https://github.com/meshtastic/mqtt
+ cd mqtt
+ ```
+
+2. Build the Docker image:
+ ```bash
+ docker build -t meshtastic-mqtt-broker .
+ ```
+
+#### SSL Mode (Port 8883)
+
+To run with SSL enabled:
+
+1. Place your certificate file (`certificate.pfx`) in the project directory. (see [MQTTnet Server Wiki](https://github.com/dotnet/MQTTnet/wiki/Server))
+2. Run the container with the SSL environment variable:
+
+```bash
+docker run -p 8883:8883 -v $(pwd)/certificate.pfx:/app/certificate.pfx meshtastic-mqtt-broker
+```
+
+### Docker Compose Example
+
+```yaml
+version: '3'
+services:
+ mqtt-broker:
+ build: .
+ ports:
+ - "1883:1883" # Standard MQTT port
+ # - "8883:8883" # SSL port (uncomment if using SSL)
+ # environment:
+ # - SSL=true # Uncomment to enable SSL
+ # volumes:
+ # - ./certificate.pfx:/app/certificate.pfx # Mount certificate if using SSL
+ restart: unless-stopped
+```
+
+## Configuration Options
+
+- **SSL**: Set environment variable `SSL=true` to enable SSL mode
+- **Certificate**: Mount your PFX certificate file to `/app/certificate.pfx` in the container
+- **Ports**: The application uses port 1883 for standard MQTT and 8883 for SSL MQTT
+
+## Troubleshooting
+
+- Ensure proper network access to the Docker container
+- Check that certificates are correctly formatted (for SSL mode)
+- Review logs using `docker logs [container-id]`
diff --git a/cert.pem b/cert.pem
new file mode 100644
index 0000000..d0983bc
--- /dev/null
+++ b/cert.pem
@@ -0,0 +1,31 @@
+-----BEGIN CERTIFICATE-----
+MIIFazCCA1OgAwIBAgIUAiOTlcvZA8d3i1YXISMcn+B4+PowDQYJKoZIhvcNAQEL
+BQAwRTELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoM
+GEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDAeFw0yNTA0MTYwMTQwNThaFw0yNjA0
+MTYwMTQwNThaMEUxCzAJBgNVBAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEw
+HwYDVQQKDBhJbnRlcm5ldCBXaWRnaXRzIFB0eSBMdGQwggIiMA0GCSqGSIb3DQEB
+AQUAA4ICDwAwggIKAoICAQC5qV6+hqXx9g3dEAWZ9ZfBL8K5s2M1JvPakRu4MW9l
+My1Ugf6mAB/7FkY168STGU3/8r0a+E743eTaPGWrlhBY1tEfCYwXLi2+xiL3yOB1
++6uzla7+THOM3G3CN/Hoq0zw6IB2PJQF2ZT8rDLbmYdvv8i4hWSHjxNU/cEK2/aP
+rMhKv8uWieEmstDCoF8AKxpFvh9JYhyeDTF5w/2cPEP+LcR36F8rVr9EbiieJ27U
+GDvfgDe+Vdjm4YDVPVswf8/goN+TehjAOMQx1BHQLEFEij9KBmYdl6+mQ2mMnlwK
+YjZJ36133QolH00x/yYGEak/DS21gECMBbTUw3Y6hs6wdWmV/cHRV7tIrBKGkMxG
+0RSdqgukDfXRzi7kPO7TuMu5ju2ifS7JKhhNrh0IbuHFKSNjFYW8tTaXNHBuumKo
+GUH51XjlONN43kTDzKMHkPznDImrKKL3PhRqFXUdgiwSoRNHY6/XHPAW6ecJ7Jla
+hctnLQFjf4zsRkgTQjlj+fz9JPQTljhFQUkQyotnnp2eC23ceX/dnKG4hz350GkP
+zL31vQ62f2BPOHacaLVCJrLBffOJjyAqfvR2J0oGPUo+7iuvjurC2pq9wgKaLLbQ
+Y3ncHaBD3bLZk/KzrirX8Rn8cPbCs1Q1Ehe+F2mbarRjSsGuOlEqatns3gYeIZSd
+SwIDAQABo1MwUTAdBgNVHQ4EFgQUczeKEnJEd8rhlPzTSDhNUircBvUwHwYDVR0j
+BBgwFoAUczeKEnJEd8rhlPzTSDhNUircBvUwDwYDVR0TAQH/BAUwAwEB/zANBgkq
+hkiG9w0BAQsFAAOCAgEAWTroM00DTyqsxj/SSAM9jx1XZXfEi5ebqCDawROmTdhF
+ZnmoQ2wqtRU/B6en2GTah/RKOcAyby/Pgtd3X3/x+J1W1D2uH5wNlhCxlH8X+GbW
+2Br4nRKlMxcg1TbHVowPybV5loAcGjiCuIsmk0Iq4M1WUn/Ex6SZENT6MxT3yYVS
+neQ5NZhk6luUCpjxgY3XT2tclagM2i5YVVWT8kYQakmtRteBZmK4ZrFfc486/rNj
+4hLX8kwhRriz6U2mCtNCLB1kMF5imDHnIBH2winOEmqnN2pEzC15PDFOvRMoJzIl
+lXk3Odnv3BXIHosLJQheTsAMFrTDf82itVwoYFMx8QL/0jvYrVkdhzbZMJEcN6Bi
+PeOcji3mqcOm1JKsYNPz9V/U0faoixOekG7y7PnW8cEsag9lrGPxr0rGJ9Y431O2
+GIV9D79WY25WWn23+R3VGZWrnOUY33UHl3ZngXnBSvyLMHP6ZSb/SuTM6hMPbqaB
+uauhTqdXUc1P90hTToBz1wtbKwoYBYIM7sGZP8IFiFdCSaxX1Kckks6YELFxZWFN
+1AWOG5GFT4xOGDgcBnbHcldejKEO6fRa+D0SSucyJ84EK1tvhKAMxPXnp73t4eE/
+gwnGZ/9oLm5RRjAFZeCFCjNgbA2bRTML8MqGYuaBSKMQX4cG2dSeJDH29vvj5tg=
+-----END CERTIFICATE-----
diff --git a/certificate.pfx b/certificate.pfx
new file mode 100644
index 0000000..5b9c42c
Binary files /dev/null and b/certificate.pfx differ
diff --git a/key.pem b/key.pem
new file mode 100644
index 0000000..6cb088a
--- /dev/null
+++ b/key.pem
@@ -0,0 +1,54 @@
+-----BEGIN ENCRYPTED PRIVATE KEY-----
+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
+rH1xuKTR/w3KS06Rjacob21XXWL8FRkS
+-----END ENCRYPTED PRIVATE KEY-----