Balthazar - self-hostinghttps://blog.balthazar-rouberol.com/2022-01-17T00:00:00+01:00Sending a webhook from Synology DSM to Discord2022-01-17T00:00:00+01:002022-01-17T00:00:00+01:00Balthazar Rouberoltag:blog.balthazar-rouberol.com,2022-01-17:/sending-a-webhook-from-synology-dsm-to-discord<p>Given the fact that running a Datadog agent on a Synology Play NAS is not obvious, I wanted to enable Discord webhooks push notifications (as this is where my Datadog alerts are already being sent). This way, I'd get plenty of alerts "for free" without having to configure new Datadog …</p><p>Given the fact that running a Datadog agent on a Synology Play NAS is not obvious, I wanted to enable Discord webhooks push notifications (as this is where my Datadog alerts are already being sent). This way, I'd get plenty of alerts "for free" without having to configure new Datadog monitors.</p>
<p>While sending webhooks notifications from a Synology NAS to Discord is technically possible, the DSM UI somehow seems to prevent us from doing so, as documented in this <a href="https://www.synoforum.com/threads/webhooks-to-post-alerts-messages-on-to-discord.6725/#post-32618">forum thread</a>. Somehow, we <em>have</em> to include a <code>hello world</code> message in the notification, as part of the message content, without which, the UI won't allow us to save the webhook configuration.</p>
<p>You can however circumvent the issue by <code>ssh</code>-ing into the NAS and edit the <code>/usr/syno/etc/synowebhook.conf</code> into this:</p>
<div class="highlight"><pre><span></span><code><span class="p">{</span>
<span class="w"> </span><span class="nt">"Discord"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="nt">"needssl"</span><span class="p">:</span><span class="w"> </span><span class="kc">false</span><span class="p">,</span>
<span class="w"> </span><span class="nt">"port"</span><span class="p">:</span><span class="w"> </span><span class="mi">8090</span><span class="p">,</span>
<span class="w"> </span><span class="nt">"prefix"</span><span class="p">:</span><span class="w"> </span><span class="s2">"A new system event occurred on your %HOSTNAME%"</span><span class="p">,</span>
<span class="w"> </span><span class="nt">"req_header"</span><span class="p">:</span><span class="w"> </span><span class="s2">""</span><span class="p">,</span>
<span class="w"> </span><span class="nt">"req_method"</span><span class="p">:</span><span class="w"> </span><span class="s2">"post"</span><span class="p">,</span>
<span class="w"> </span><span class="nt">"req_param"</span><span class="p">:</span><span class="w"> </span><span class="s2">"{\"username\":\"Synology\", \"avatar_url\": \"https://play-lh.googleusercontent.com/HjbYWbXJ-6e6Cia-mBbHDSdontW1yE6MHMaXqlHW80CQegDOEPQ1HGACxvEpnqCUHgo\", \"embeds\": [{\"description\": \"@@TEXT@@\", \"title\": \"@@PREFIX@@\"}]}"</span><span class="p">,</span>
<span class="w"> </span><span class="nt">"sepchar"</span><span class="p">:</span><span class="w"> </span><span class="s2">" "</span><span class="p">,</span>
<span class="w"> </span><span class="nt">"template"</span><span class="p">:</span><span class="w"> </span><span class="s2">"$webhook_url"</span><span class="p">,</span>
<span class="w"> </span><span class="nt">"type"</span><span class="p">:</span><span class="w"> </span><span class="s2">"custom"</span><span class="p">,</span>
<span class="w"> </span><span class="nt">"url"</span><span class="p">:</span><span class="w"> </span><span class="s2">"$webhook_url"</span>
<span class="w"> </span><span class="p">}</span>
<span class="p">}</span>
</code></pre></div>
<div class="Note">
<p><b>Note</b>: replace <code>$webhook_url</code> by your Discord webhook URL.</p>
</div>
<p>When this is done, you should see a <code>Discord</code> webhook in your Webhook Push Services, and you should now be able to send a test message to Discord!</p>
<p><picture>
<source srcset="https://balthazar-rouberol-blog.s3.eu-west-3.amazonaws.com/syno-discord/dark/discord-notif.webp" media="(prefers-color-scheme: dark)">
<img alt="" decoding="async" loading="lazy" src="https://balthazar-rouberol-blog.s3.eu-west-3.amazonaws.com/syno-discord/light/discord-notif.webp">
</picture></p>
<p>Now, any warning or alert generated from DSM will automatically be sent to Discord as well!</p>Managing my infra like it's 20192019-07-22T00:00:00+02:002019-07-22T00:00:00+02:00Balthazar Rouberoltag:blog.balthazar-rouberol.com,2019-07-22:/managing-my-infra-like-its-2019<p>I recently realized that I was routinely managing thousands of servers and petabytes of data in my daily job, but was still managing my own personal infrastructure like I was living in 1999.</p>
<p><img alt="my-infra" decoding="async" loading="lazy" src="https://balthazar-rouberol-blog.s3.eu-west-3.amazonaws.com/managing-infra/infra.png"></p>
<hr>
<p>With the advent of configuration management tools such as <a href="https://docs.ansible.com/">Ansible</a>, <a href="https://www.chef.io/">Chef</a>, and the like, it became easier …</p><p>I recently realized that I was routinely managing thousands of servers and petabytes of data in my daily job, but was still managing my own personal infrastructure like I was living in 1999.</p>
<p><img alt="my-infra" decoding="async" loading="lazy" src="https://balthazar-rouberol-blog.s3.eu-west-3.amazonaws.com/managing-infra/infra.png"></p>
<hr>
<p>With the advent of configuration management tools such as <a href="https://docs.ansible.com/">Ansible</a>, <a href="https://www.chef.io/">Chef</a>, and the like, it became easier to configure instances in a reproducible manner by defining said configuration as code. <a href="http://terraform.io/">Terraform</a> made it easier to codify and provision cloud resources: instances, but also security groups, permissions, storage, load balancers, etc.</p>
<p>It's easy to simply think of a cloud infrastructure as a pool of compute resource. It is however often so much more than that. When executed right, The Cloud is a set of meshed services, interacting and communicating with each other (possibly with compute resources sitting in the middle). That applies for vast and complex infrastructures such as the one I work on at <a href="https://datadoghq.com">Datadog</a>, but it also applies to my ridiculously tiny personal one. Realizing this got me thinking. Why wasn't I using the same tools and techniques to manage my small infrastructure than the ones I'm using daily?</p>
<h2 id="my-infrastructure">My infrastructure</h2>
<p>My personal infrastructure consists of (drumrolls...) 3 servers:</p>
<ul>
<li>a VPS running in Scaleway, hosting my personal services (personal website, blog, git repositories, <a href="https://radicale.org/documentation/">CalDAV server</a>, <a href="https://usefathom.com/">traffic analytics</a>, <a href="https://thelounge.chat/">IRC client</a>, <a href="https://www.wallabag.org/en">Read-it-later service</a>, etc)</li>
<li>a VPS running in OVH, hosting my mother's website</li>
<li>a Raspberry Pi, running in my living room, hosting private services (<a href="https://kresus.org/en/index.html">Kresus</a>)</li>
</ul>
<p>Until now, each of these servers were managed in an <em>ad-hoc</em> fashion, sometimes with scripts, sometimes without. All the cloud resources on which my services (S3 buckets, DNS zones, etc) were managed manually, using the cloud provider web console.</p>
<p>I manage my DNS zones with OVH, I use the AWS S3 bucket free tier for the blog images, and Datadog for monitoring.</p>
<p><img alt="ssl-expiry-monitoring" decoding="async" loading="lazy" src="https://balthazar-rouberol-blog.s3.eu-west-3.amazonaws.com/managing-infra/datadog-monitors.png"></p>
<h2 id="improving-the-setup">Improving the setup</h2>
<p>I had several objectives in mind to improve the current setup:</p>
<ul>
<li>define all instances configuration and state in <a href="https://docs.ansible.com/ansible/latest/user_guide/playbooks.html">ansible playbooks</a></li>
<li>re-use and share instances configuration by leveraging <a href="https://docs.ansible.com/ansible/latest/user_guide/playbooks_reuse_roles.html">ansible roles</a></li>
<li>define and manage all cloud resources using <a href="https://terraform.io">terraform</a> to never have to log into a cloud web console again</li>
<li>secure all web-services with an automatically renewed SSL certificate provided by Let's Encrypt</li>
<li>run all services behind a reverse-proxy, using a docker container or a <a href="https://www.brendanlong.com/systemd-user-services-are-amazing.html">userland systemd service</a> with minimal permissions and privileges</li>
<li>monitor the hosts and services using <a href="https://datadoghq.com">Datadog</a> (free for 5 hosts or less) , with monitors define in terraform</li>
<li>secure the SSH connections of the internet-facing hosts via <a href="https://duo.com/">Duo</a> (free for 10 users or less)</li>
<li>be able to SSH into all hosts from my personal and work laptop, as well as from my <a href="https://play.google.com/store/apps/details?id=org.connectbot&hl=en_US">phone</a></li>
<li>monitor my daily backups</li>
</ul>
<h2 id="show-me-the-code">Show me the code</h2>
<p>You can have a look at the code <a href="https://github.com/brouberol/infrastructure">here</a>. I've purposefully omitted the <code>terraform/global_vars/main.tf</code> file, credentials are obviously encrypted, API keys are defined in my home directory, but everything else is readable openly. My hope is that that readers might either learn something or point out where I'm doing something silly or insecure.</p>
<h2 id="what-now">What now?</h2>
<p>I'm now confident that I can open some of these services to friends, if they want to. I measure and monitor my own SLIs, the expiry of the SSL certificates, and can intervene from anywhere if something breaks.</p>
<p><img alt="ssl-expiry-monitoring" decoding="async" loading="lazy" src="https://balthazar-rouberol-blog.s3.eu-west-3.amazonaws.com/managing-infra/ssl-expiry-monitoring.png"></p>
<p>My infrastructure is now more secure, and has been audited by fellow peers <sup id="fnref:review"><a class="footnote-ref" href="#fn:review">1</a></sup>. I'm now confident I can restore the services in the face of an instance loss (which is very important for my mother, as her website has a fair amount of traffic and brings her regular new customers).</p>
<p>I'm also dogfooding Datadog features, which got to me suggest a couple of improvements to the Datadog <a href="https://www.terraform.io/docs/providers/datadog/index.html">terraform provider</a> which will be worked on next quarter.</p>
<div class="footnote">
<hr>
<ol>
<li id="fn:review">
<p>Thanks to Mehdi and Thomas for the thorough playbook review. Any remaining mistake or silliness is my own. <a class="footnote-backref" href="#fnref:review" title="Jump back to footnote 1 in the text">↩</a></p>
</li>
</ol>
</div>