Skip to content

Running locally

You may want to host Shuttle.Pigeon locally on a more permanent basis, and without making use of docker-compose.

The container below all make use of the development network. If you'd like to use the below command as-is you can create the network using the following:

cmd
docker network create development

Database

If you do not have a Sql Server instance available you can use the following to create a local docker instance:

(replace <local-sql-data-folder> with a local folder where you'd like you sql data to be stored; else remove the volume mapping)

cmd
docker run ^
  --network development ^
  --restart always ^
  -e "ACCEPT_EULA=Y" ^
  -e "MSSQL_SA_PASSWORD=Pass!000" ^
  -p 1433:1433 ^
  --name sql ^
  --hostname sql ^
  -v <local-sql-data-folder>:/var/opt/mssql/data ^
  -d mcr.microsoft.com/mssql/server:2022-latest
ps
docker run `
  --network development `
  --restart always `
  -e "ACCEPT_EULA=Y" `
  -e "MSSQL_SA_PASSWORD=Pass!000" `
  -p 1433:1433 `
  --name sql `
  --hostname sql `
  -v <local-sql-data-folder>:/var/opt/mssql/data `
  -d mcr.microsoft.com/mssql/server:2022-latest
bash
docker run \
  --network development \
  --restart always \
  -e "ACCEPT_EULA=Y" \
  -e "MSSQL_SA_PASSWORD=Pass!000" \
  -p 1433:1433 \
  --name sql \
  --hostname sql \
  -v <local-sql-data-folder>:/var/opt/mssql/data \
  -d mcr.microsoft.com/mssql/server:2022-latest

In order to create the database you would need to download the relevant efbundle file from the Shuttle.Pigeon releases page and then run it against your database, e.g.:

shell
shuttle-pigeon-efbundle-win-x64.exe --connection "Server=.;Database=Pigeon;User ID=sa;Password=Pass!000;Encrypt=True;TrustServerCertificate=True;Connection Timeout=30;"

Azurite

The server makes use of Azure Storage Queues for messaging. You can use the following to create a local Azurite:

(replace <local-azurite-folder with a local folder where you'd like your azurite data stored; else you could remove the volume mapping)

cmd
docker run -d ^
  --network development ^
  --name azurite ^
  --hostname azurite ^
  -p 10000:10000 ^
  -p 10001:10001 ^
  -v <local-azurite-folder>:/data ^
  mcr.microsoft.com/azure-storage/azurite
ps
docker run -d `
  --network development `
  --name azurite `
  --hostname azurite `
  -p 10000:10000 `
  -p 10001:10001 `
  -v <local-azurite-folder>:/data `
  mcr.microsoft.com/azure-storage/azurite
bash
docker run -d \
  --network development \
  --name azurite \
  --hostname azurite \
  -p 10000:10000 \
  -p 10001:10001 \
  -v <local-azurite-folder>:/data \
  mcr.microsoft.com/azure-storage/azurite

Server

Create a server-appsettings.json file with the following contents:

json
{
  "Serilog": {
    "Using": [
      "Serilog.Sinks.Console",
      "Serilog.Sinks.File"
    ],
    "MinimumLevel": {
      "Default": "Debug",
      "Override": {
        "System.Net.Http": "Error"
      }
    },
    "WriteTo": [
      {
        "Name": "Console"
      },
      {
        "Name": "File",
        "Args": {
          "path": "./logs/.log",
          "rollOnFileSizeLimit": true,
          "retainedFileCountLimit": 30,
          "fileSizeLimitBytes": 1048576,
          "rollingInterval": "Day"
        }
      }
    ]
  },
  "ConnectionStrings": {
    "Pigeon": "server=database;database=Pigeon;user id=sa;password=Pass!000;TrustServerCertificate=true",
    "azure": "UseDevelopmentStorage=true;DevelopmentStorageProxyUri=http://azurite"
  },
  "Shuttle": {
    "Pigeon": {
      "Postmark": {
        "ServerToken": ""
      },
      "SendGrid": {
        "ApiKey": ""
      },
      "MailKit": {
        "Host": "mail.example.com",
        "Username": "noreply@example.com",
        "Password": "",
        "SenderAddress": "noreply@ebenroux.co.za",
        "SenderDisplayName": "(no-reply)"
      },
      "ChannelDefaultMessageSenders": [
        {
          "Channel": "email",
          "Name": "mailkit"
        }
      ]
    },
    "ServiceBus": {
      "Inbox": {
        "WorkQueueUri": "azuresq://azure/pigeon-server-inbox-work",
        "DeferredQueueUri": "azuresq://azure/pigeon-server-inbox-deferred",
        "ErrorQueueUri": "azuresq://azure/pigeon-error",
        "MaximumFailureCount": 8,
        "ThreadCount": 1,
        "DurationToIgnoreOnFailure": [
          "00:00:01",
          "00:00:01",
          "00:00:01",
          "00:00:01",
          "00:00:01",
          "00:00:05",
          "00:00:10",
          "00:00:30"
        ]
      }
    }
  }
}

You will need to remove the Shuttle:Pigeon:{sender} configuration sections that you will not be using, and populate the relevant details on the active one(s).

You can now create the server instance by changing the <settings-folder> to the relevant directory:

cmd
docker run ^
  --network development ^
  --restart always ^
  -e "CONFIGURATION_FOLDER=." ^
  --name pigeon-server ^
  --hostname pigeon-server ^
  -v <settings-folder>\server-appsettings.json:/opt/shuttle.pigeon.server/appsettings.json ^
  -d shuttle/pigeon-server:latest
ps
docker run `
  --network development `
  --restart always `
  -e "CONFIGURATION_FOLDER=." `
  --name pigeon-server `
  --hostname pigeon-server `
  -v <settings-folder>\server-appsettings.json:/opt/shuttle.pigeon.server/appsettings.json `
  -d shuttle/pigeon-server:latest
bash
docker run \
  --network development \
  --restart always \
  -e "CONFIGURATION_FOLDER=." \
  --name pigeon-server \
  --hostname pigeon-server \
  -v <settings-folder>\server-appsettings.json:/opt/shuttle.pigeon.server/appsettings.json \
  -d shuttle/pigeon-server:latest

Web API

Create a webapi-appsettings.json file with the following contents:

json
{
  "Serilog": {
    "Using": ["Serilog.Sinks.Console", "Serilog.Sinks.File"],
    "MinimumLevel": {
      "Default": "Debug",
      "Override": {
        "System.Net.Http": "Error"
      }
    },
    "WriteTo": [
      {
        "Name": "Console"
      },
      {
        "Name": "File",
        "Args": {
          "path": "./logs/.log",
          "rollOnFileSizeLimit": true,
          "retainedFileCountLimit": 30,
          "fileSizeLimitBytes": 1048576,
          "rollingInterval": "Day"
        }
      }
    ]
  },
  "ConnectionStrings": {
    "azure": "UseDevelopmentStorage=true;DevelopmentStorageProxyUri=http://azurite",
    "Access": "Data Source=database;Initial Catalog=Pigeon;user id=sa;password=Pass!000;TrustServerCertificate=true"
  },
  "Shuttle": {
    "Access": {
      "Client": {
        "BaseAddress": "http://localhost:5599"
      }
    },
    "ServiceBus": {
      "MessageRoutes": [
        {
          "Uri": "azuresq://azure/pigeon-server-inbox-work",
          "Specifications": [
            {
              "Name": "StartsWith",
              "Value": "Shuttle.Pigeon.Messages"
            }
          ]
        }
      ]
    }
  }
}

You can now create the web API instance by changing the <settings-folder> to the relevant directory:

cmd
docker run ^
  --network development ^
  --restart always ^
  -e "CONFIGURATION_FOLDER=." ^
  -p 5268:8080 ^
  --name pigeon-webapi ^
  --hostname pigeon-webapi ^
  -v <setting-folder>\webapi-appsettings.json:/opt/shuttle.pigeon.webapi/appsettings.json ^
  -d shuttle/pigeon-webapi:latest
ps
docker run `
  --network development `
  --restart always `
  -e "CONFIGURATION_FOLDER=." `
  -p 5268:8080 `
  --name pigeon-webapi `
  --hostname pigeon-webapi `
  -v <setting-folder>\webapi-appsettings.json:/opt/shuttle.pigeon.webapi/appsettings.json `
  -d shuttle/pigeon-webapi:latest
bash
docker run \
  --network development \
  --restart always \
  -e "CONFIGURATION_FOLDER=." \
  -p 5268:8080 \
  --name pigeon-webapi \
  --hostname pigeon-webapi \
  -v <setting-folder>\webapi-appsettings.json:/opt/shuttle.pigeon.webapi/appsettings.json \
  -d shuttle/pigeon-webapi:latest

Done

To view the web-api endpoints you can browse to the swagger page:

http://localhost:5268/swagger/index.html