diff --git a/content/System Administration/streaming-webcam-raspi.md b/content/System Administration/streaming-webcam-raspi.md
new file mode 100644
index 0000000000000000000000000000000000000000..d4fe5dd2c3ea024137ea6304cd04f2db7236a7f7
--- /dev/null
+++ b/content/System Administration/streaming-webcam-raspi.md	
@@ -0,0 +1,180 @@
+Title: Livestreaming with a Raspberry Pi
+Description: Broadcast video privately, cheaply, and without ads.
+Date: June 30, 2017
+Cover: /media/raspi-webcam.jpg
+Featured_Project: true
+
+These are my notes on broadcasting a USB camera to a webpage. A Raspberry Pi streams
+from the camera, and a server running nginx distributes the stream to
+many viewers at once.
+
+## Server setup
+
+These instructions assume you are using [Debian](https://www.debian.org/), but
+should work on just about any Linux. While the Raspberry Pi can be on a private
+network, this server needs a public IP address to be accessible from the internet.
+
+**Note:** Streaming video can use a lot of bandwidth. Do the math to ensure
+adequate capacity and avoid billing surprises.
+
+### nginx
+
+[Build nginx with the RTMP module](https://github.com/arut/nginx-rtmp-module/wiki/Getting-started-with-nginx-rtmp). Install and configure it, using the config below as an example.
+
+**Note:** If `./configure` complains about missing zlib, install `zlib1g-dev`.
+
+
+```
+:::nginx
+worker_processes  1;
+error_log logs/error.log debug;
+
+events {
+  worker_connections  1024;
+}
+
+
+http {
+  include mime.types;
+  default_type application/octet-stream;
+  sendfile on;
+  keepalive_timeout 65;
+
+  server {
+    listen 80;
+    server_name streamer.example.com;
+
+    # Uncomment if you have an SSL cert.
+    # listen     443 ssl;
+    # ssl_certificate /etc/ssl/certs/streamer.example.com.crt;
+    # ssl_certificate_key /etc/ssl/private/streamer.example.com.key;
+
+    # Configure HLS playback
+    location /hls {
+      add_header Cache-Control no-cache;
+
+      # CORS header (allow embedding on other domains)
+      add_header 'Access-Control-Allow-Origin' '*' always;
+
+      # MIME types for HLS playlist and video files
+      types {
+        application/vnd.apple.mpegurl m3u8;
+        video/mp2t ts;
+      }
+
+      # See hls_path below.
+      root /tmp;
+    }
+
+  }
+
+}
+
+rtmp {
+  server {
+    listen 1935;
+    ping 30s;
+    notify_method get;
+    application video {
+      live on;           # Enable live streaming
+      hls on;            # Enable HLS output
+      hls_path /tmp/hls; # Where to write HLS files
+    }
+  }
+}
+```
+
+See [the nginx-rtmp-module wiki](https://github.com/arut/nginx-rtmp-module/wiki/Directives)
+for details on these settings.
+
+
+## Raspberry Pi Setup
+
+**Note:** The original Raspberry Pi lacks hardware acceleration for video transcoding, making it unsuitable
+for this project. I used a Raspberry Pi 2.
+
+Install [Raspbian](https://www.raspberrypi.org/downloads/raspbian/) on your Raspberry Pi.
+It will need a network connection (eg.
+ [WiFi](https://wiki.debian.org/WiFi/HowToUse#WPA-PSK_and_WPA2-PSK))
+to access the server.
+
+Plug in your camera, and make sure it is detected.
+
+```
+:::bash hl_lines="2"
+ls /dev/video*
+/dev/video0
+```
+
+You will need **avconv**, a fork of **ffmpeg**.
+
+```
+apt update
+apt install avconv
+```
+
+Finally, you can start the stream. These settings worked well for me.
+
+```
+:::bash
+avconv
+    -f video4linux2   \  # Input format
+    -i /dev/video0    \  # Path to your webcam.
+    -c:v libx264      \  # Use H.264 encoding.
+    -pix_fmt yuv420p  \  # Some browsers (eg. Safari) need this.
+    -an               \  # No audio (I don't need it).
+    -f flv            \  # Output format
+    rtmp://streamer.example.com/video/example-stream  # see below
+```
+
+* `video` corresponds with the nginx rtmp application name.
+* `example-stream` will be the name of your stream, change as desired.
+
+
+## Set up the viewer
+
+Using [hls.js](https://github.com/video-dev/hls.js) for cross-browser HLS support, create
+a page for viewing the video.
+
+```
+:::html
+<script src="https://cdn.jsdelivr.net/npm/hls.js@latest"></script>
+<video id="live-stream"></video>
+<script>
+  if(Hls.isSupported()) {
+    var source_url = 'http://streamer.example.com/hls/example-stream';
+    var video_element = document.getElementById('live-stream');
+    var hls = new Hls();
+    hls.loadSource(source_url);
+    hls.attachMedia(video_element);
+    hls.on(Hls.Events.MANIFEST_PARSED, function() {
+      video.play();
+    });
+  }
+</script>
+```
+
+## Live demo
+
+Here's a live stream using this setup.
+
+<script src="/theme/lib/hls/hls.js"></script>
+<video id="video" src='https://live.ant.sr/hls/fridgecast.m3u8'
+    autoplay muted playsinline
+    style="width: 100%;"></video>
+<script>
+  if(Hls.isSupported()) {
+    var cfg = {
+        fragLoadingTimeOut: 500,
+    };
+    var src = 'https://streamer.ant.sr/hls/fridgecast.m3u8';
+    var video = document.getElementById('video');
+    var hls = new Hls(cfg);
+    hls.loadSource(src);
+    hls.attachMedia(video);
+    hls.on(Hls.Events.MANIFEST_PARSED,function() {
+      video.play();
+  });
+ }
+</script>
+
diff --git a/content/media/raspi-stream.png b/content/media/raspi-stream.png
new file mode 100644
index 0000000000000000000000000000000000000000..c40dbbd7040851755cf1d3dfea64ac61af07da19
Binary files /dev/null and b/content/media/raspi-stream.png differ
diff --git a/content/media/raspi-webcam.jpg b/content/media/raspi-webcam.jpg
new file mode 100755
index 0000000000000000000000000000000000000000..86b0602b3b0d1178a52ae3e49371ebaee5a2bf73
Binary files /dev/null and b/content/media/raspi-webcam.jpg differ