TeamViewer on Raspberry Pi 3

During the summer we moved from an apartment to a house. Among many other things, this meant changes to the Internet connectivity. Our old place had VDSL, but now I got to choose what I want. Fiber optics would’ve been an option (fast and reliable), but it’s rather expensive compared to the other alternatives. In the end, I ended up with a 50/50 Mbit/s 4G mobile broadband connection which is shared through a 4G router (which I already owned). This was by far the most bang for the buck. We also happen to live quite near a 4G base station, so regular speeds reach about 40Mbit/s+. Not bad. Not bad at all. I’m not a gamer either, so no need for low ping times. On the negative side, all Finnish 4G mobile broadband connections are NAT:ed on the ISP side (exception is enterprise/business subscribers). This dilemma is also the subject of this post, in other words how to “bypass” dual NAT using TeamViewer. (I had to ditch my fancy old VPN stuff  😦 )

Well, moving along to the subject, TeamViewer. TeamViewer is by no means a new technology, but the possibility to use it on the RPi is limited. When googling you’ll most certainly find a solution named ExaGear Desktop. ExaGear Desktop enables x86 programs to be run (or “emulated”) on the RPi. While this is a good idea, it’ll most certainly be slow. A RPi running Raspbian is already quite slow, so doing x86 emulation on top of that is even slower. You’ll also find people telling you it’s impossible to run TeamViewer on the RPi altogether (which is untrue).

Why would you need TeamViewer on the RPi you ask? Isn’t there already SSH and port forwarding and such? Yes, BUT port forwarding won’t work with (double) NAT:ed 3G/4G connections. (NAT at the ISP level and NAT behind the router). As stated before, my main Internet connection at home is a 4G mobile broadband connection (without a public IP) connected to a 4G router. This combination doesn’t allow me to remote connect to my LAN using the “normal methods” (VPN, port forwarding and so on). The reason for this is that you can’t configure the ISP NAT rules (obviously). Some similar information about this dilemma can be found here for example:

http://www.austech.info/showthread.php/80948-Mobile-Broadband-with-a-Public-IP
http://superuser.com/questions/397606/why-a-3g-router-wont-do-port-forwarding-when-on-3g-interface
http://serverfault.com/questions/738979/how-to-get-around-double-nat-from-the-isp
https://yescrowd.optus.com.au/t5/Broadband-Telephony/Mobile-Broadband-gt-gt-gt-Public-Ip-changed-to-Private-without/td-p/103653
https://elisa.fi/asiakaspalvelu/aihe/mobiililaajakaista/ohje/ip-osoitteet/ (in Finnish)

 

Luckily there’s a solution to this dilemma (and luckily I’m here to minimize your googling):

The TeamViewer IoT contest: https://www.teamviewer.com/iotcontest  🙂

Just download and install it in Raspbian (with a simple double click). After that have a look at the Frequently Asked Questions and the General Questions & Answers + Troubleshooting Questions and Answers on the same download page. The only settings I changed were:

  • Sat an unattended fixed password and disabled random password (via the GUI).
  • Edited /boot/config.txt and commented out framebuffer_width and framebuffer_height lines. I left them at 1280×720 which worked OK for me. (I did this because I’m running the RPi headless and the resolution would therefore be screwed up (too tiny) if connecting without a monitor attached to the RPi).
  • Added the RPi to the “My Computers”-list in the TeamViewer client (from Windows)
  • Voilà!

 

…and some screenshots:

teamviewer_rpi1

Fig 1. Connected, yey  🙂

 

teamviewer_rpi2

Fig 2. Having a look at the doggycam remotely

 

 

Alternative solutions

  • Pay a slightly more expensive monthly fee for your mobile broadband connection, and in return get a public IP address. This is true for almost all ISP’s here in Finland at least.
  • Some ISP’s provide public IP’s on 4G mobile broadband connections using IPv6. This only works with a couple of mobile broadband sticks/routers however (they have to fully support IPv6). I wouldn’t buy a new stick (or router) only for this feature. (They’re rather expensive after all).
  • Use TeamViewer on a x86 computer instead of a RPi. Yes, why not. Then again it consumes much more energy than a RPi when in use 24/7. It’s also noisy. And hey, everything is always much more cool and hip with a RPi 🙂

 

That’s it! This was just a short little post that hopefully will make your life a whole lot easier when dealing with the evil NAT:ed 4G connections 🙂

Advertisements

ownCloud 9 on Raspberry Pi 2 with mounted Buffalo NAS

The Linux nerd inside me was screaming for a new RPi project. What to build? What to do? You can’t read any modern IT literature nowadays without stumbling upon the word “cloud”. Well, cloud it is. Owncloud in my case. I guess almost everyone is familiar with this open source cloud software, but for those of you that aren’t you can find information at:

https://owncloud.org/features/

The idea was to access my trusty old Buffalo NAS remotely, without having the need to map network drives etc. Buffalo is actually offering some sort of cloud solution also, but hey, it’s much more fun configuring your own stuff 🙂 The idea is quite simple – The RPi is a front-end for the NAS. Clients are connecting to the RPi, which in turn mount network storage from the NAS. Here’s the setup:

owncloud_buffalo_rpi

Fig 1. RPi + Buffalo NAS

 

Initial questions and ideas

  • Should Raspberry Pi / ownCloud be visible on the Internet? If so, how to secure it properly?
      • Port forwarding with restrictions / reverse proxy?
  • If not visible on the Internet, how should one connect from the outside world?
      • VPN?

I actually decided to go with option 2, not visible on the Internet. My decision is based on the fact that I’m already running a VPN server. It’s one more extra step before getting/synchronizing the files, but I think it’s worth it in the end. Besides, all my other services are behind VPN also.

That said, I STILL configured ownCloud to be “future-proof” even if the server won’t be Internet-facing (with port forwarding etc.) right now. (See the securing ownCloud chapter). Better safe than sorry 🙂

 

Installation

As with almost every project, I usually follow an existing guide. ownCloud is quite a mainstream product, so there are tons and tons of documentation available. The guide that I used as my baseline this time was: http://www.htpcguides.com/install-owncloud-8-x-raspberry-pi-for-personal-dropbox/ . Thanks to the author 🙂 Steps:

  • Followed the guide down to “Now make your ownCloud directory adjust your path as necessary to your mounted hard drive folder..”. As I’ll be using a NAS, it was time for another guide:
    • http://sharadchhetri.com/2013/10/23/how-to-mount-nas-storage-in-owncloud-to-keep-all-users-data/
    • created a share on the NAS (named owncloud). Gave the share read/write access for a user also named “owncloud”.
    • mounted the share on the RPi. The guide uses backslash, but it should be forward slash:
      • e.g. mount -t cifs //192.168.10.20/owncloud /mnt -o username=owncloud,password=owncloud
    • Did not follow step 3 completely because there was no data-directory created during the installation (yet). The installer GUI will look for a data directory though, so this is the time to create and mount it properly.
    • Got the uid of www-data or apache user by using id command:
      • root@owncloud:~# id www-data
        uid=33(www-data) gid=33(www-data) groups=33(www-data),1000(pi)
      • OK. ID is 33
    • Created a local data-directory which will mount the owncloud share (from the NAS).
    • mkdir -p /var/www/owncloud/data
      • changed ownership and permission on the data directory;
        • chmod -R 770 /var/www/owncloud/data ; chown -R www-data:www-data /var/www/owncloud/data
      • Added the following line to /etc/fstab (bottom of file) to make the data directory available in owncloud (setup):
        • //192.168.10.20/owncloud /var/www/owncloud/data cifs user,uid=33,rw,suid,username=owncloud,password=owncloud,file_mode=0770,dir_mode=0770,noperm 0 0
    • Ran mount –a and checked if the NAS got properly mounted. For me it did. In other words the “local” /var/www/owncloud/data was now actually living on the NAS.
    • Finished the configuration via ownClouds own GUI setup. Everything went fine…
    • …however, after a reboot the share was NOT auto mounted 😦
    • I got an error when trying to access owncloud over the web interface: Please check that the data directory contains a file “.ocdata” in its root
      • Scratched my head and wondered what the hell went wrong. I was quite sure it had to do with permissions. Turned out I was right. Short version:
      • http://htyp.org/Please_check_that_the_data_directory_contains_a_file_%22.ocdata%22_in_its_root
        • created an empty .ocdata –file (after I had manually mounted /var/www/owncloud/data directory from the NAS).
        • chmodded that file and the data-directoy with “new rights” ;
          • chmod 777 .ocdata ; chmod 777  /var/www/owncloud/data
          • success, the NAS now got automounted after a RPi-reboot 🙂
    • Everything worked, so moving over to the (optional) security part.

 

Securing ownCloud

Owncloud’s own Security & setup warnings will warn you about things to fix. Here’s a screenshot with almost no security measurements taken. (Actual screenshot is not mine, it’s “borrowed” from the Internet):

owncloud_setup_security_warnings

Fig 2. Before fixing Security & Setup warnings. I’ll write about memory cache in the next chapter (Optimizing ownCloud).

 

… and here’s a screenshot with fixed security (also memcached fixed):

owncloud_setup_security_no_warnings

Fig 3. No security & setup warnings 🙂

 

Basic security

The initial setup guide I followed had already done some basic security measurements (luckily):

  • Redirected all unencrypted traffic to HTTPS (in /etc/nginx/sites-available/owncloud):
      server {
        listen 80;
        server_name htpcguides.crabdance.com 192.168.40.135;
        return 301 https://$server_name$request_uri;  # enforce https
      }
  • Used SSL certificates for https (self-signed):
      ssl_certificate /etc/nginx/ssl/owncloud.crt;
      ssl_certificate_key /etc/nginx/ssl/owncloud.key;
  • Created a virtual host for owncloud, not using “default”.
  • Protected the data directory and files from the internet (outside world):
       # Protecting sensitive files from the evil outside world
        location ~ ^/owncloud/(data|config|\.ht|db_structure.xml|README) {
                 deny all;
  • After this, there were still some things to take care of. Although not visible in Fig 2 above, I also got a warning saying that HTTP Strict Transport Security wasn’t used. Well, a quick googling fixed this. All that was needed was a parameter in the same configuration file as above (/etc/nginx/sites-available/owncloud):

More information about security can be found in ownClouds own Hardening and Security Guidance:

https://doc.owncloud.org/server/8.0/admin_manual/configuration_server/harden_server.html

 

Advanced security

If you are going to deploy a server that’s facing the Internet you have to think about security. The basic security measurements are a must, but what if you want to secure it even more? You certainly want your site protected against DDOS and brute-force attacks, don’t you? Well, here’s where one of my favorites come into play – fail2ban. If you have no idea what I’m talking about I suggest that you read at least the following:

http://www.fail2ban.org/wiki/index.php/Main_Page
https://www.techandme.se/fail2ban-owncloud/ (<- Specifically THIS link)
https://snippets.aktagon.com/snippets/554-how-to-secure-an-nginx-server-with-fail2ban
https://easyengine.io/tutorials/nginx/fail2ban/

If you’re lazy, just follow the above guides and setup accordingly. However, use common sense and double check that everything seems to be in order before going production. I myself created the following jail-files and configuration files, and restarted fail2ban. Everything was working as expected 🙂 My configuration files:

root@owncloud:/etc/fail2ban/filter.d#  ls -la ngin*.*
-rw-r–r– 1 root root 345 May 23 09:28 nginx-auth.conf
-rw-r–r– 1 root root 422 Mar 15  2014 nginx-http-auth.conf
-rw-r–r– 1 root root 280 May 23 09:29 nginx-login.conf
-rw-r–r– 1 root root 300 May 23 09:28 nginx-noscript.conf
-rw-r–r– 1 root root 230 May 23 09:28 nginx-proxy.conf
-rw-r–r– 1 root root 282 May 24 09:53 nginx-req-limit.conf

and

root@owncloud:/etc/fail2ban/filter.d# ls -la own*
-rw-r–r– 1 root root 146 May 23 09:08 owncloud.conf

(Contents of these files can be found in the links above)

…and jail-files:

root@owncloud:/etc/fail2ban# cat jail.local

[owncloud]
enabled = true
filter  = owncloud
port    = https
bantime  = 3000
findtime = 600
maxretry = 3
logpath = /var/www/owncloud/data/owncloud.log

[nginx-auth]
enabled = true
filter = nginx-auth
action = iptables-multiport[name=NoAuthFailures, port=”http,https”]
logpath = /var/log/nginx*/*error*.log
bantime = 600 # 10 minutes
maxretry = 6

[nginx-login]
enabled = true
filter = nginx-login
action = iptables-multiport[name=NoLoginFailures, port=”http,https”]
logpath = /var/log/nginx*/*access*.log
bantime = 600 # 10 minutes
maxretry = 6

[nginx-badbots]
enabled  = true
filter = apache-badbots
action = iptables-multiport[name=BadBots, port=”http,https”]
logpath = /var/log/nginx*/*access*.log
bantime = 86400 # 1 day
maxretry = 1

[nginx-noscript]
enabled = false
action = iptables-multiport[name=NoScript, port=”http,https”]
filter = nginx-noscript
logpath = /var/log/nginx*/*access*.log
maxretry = 6
bantime  = 86400 # 1 day

[nginx-proxy]
enabled = true
action = iptables-multiport[name=NoProxy, port=”http,https”]
filter = nginx-proxy
logpath = /var/log/nginx*/*access*.log
maxretry = 0
bantime  = 86400 # 1 day

[nginx-req-limit]
enabled = true
filter = nginx-req-limit
action = iptables-multiport[name=ReqLimit, port=”http,https”, protocol=tcp]
logpath = /var/log/nginx/*error*.log
findtime = 600
bantime = 7200
maxretry = 10

 

After you’ve created the jails and the configuration files you should restart the fail2ban service, “sudo service fail2ban restart”. You can then have a look in the log file, /var/log/fail2ban.log to see if everything looks ok. For me it did:

2016-05-24 09:55:53,094 fail2ban.jail   [4778]: INFO    Jail ‘ssh’ started
2016-05-24 09:55:53,136 fail2ban.jail   [4778]: INFO    Jail ‘owncloud’ started
2016-05-24 09:55:53,162 fail2ban.jail   [4778]: INFO    Jail ‘nginx-auth’ started
2016-05-24 09:55:53,190 fail2ban.jail   [4778]: INFO    Jail ‘nginx-login’ started
2016-05-24 09:55:53,223 fail2ban.jail   [4778]: INFO    Jail ‘nginx-badbots’ started
2016-05-23 10:28:13,243 fail2ban.jail   [1350]: INFO    Jail ‘nginx-noscript’ started
2016-05-24 09:55:53,249 fail2ban.jail   [4778]: INFO    Jail ‘nginx-proxy’ started
2016-05-24 09:55:53,281 fail2ban.jail   [4778]: INFO    Jail ‘nginx-req-limit’ started

All this configuration is a bit overkill for me as I’m not going to expose the ownCloud server on the Internet. Instead I’m using VPN + ownCloud. This is however a great opportunity to learn about ownCloud and it’s security so it would be a shame NOT to configure it as secure as possible 🙂 (The ssh-jail is a very nice bonus if you’re also forwarding that port towards the Internet).

 

Optimizing ownCloud

After all the security hardening stuff it was time to look at optimization. The initial guide includes some optimization and it installs all the PHP modules needed for memory caching. I’m quite sure I could optimize ownCloud much more, but there’s no need to overdo it in such a small home environment. In other words, memory caching is enough in my case. More info about memory caching can be found in ownClouds own documentation: https://doc.owncloud.org/server/8.1/admin_manual/configuration_server/caching_configuration.html

Even though this topic is already covered at the bottom in the initial guide (http://www.htpcguides.com/install-owncloud-8-x-raspberry-pi-for-personal-dropbox/), I’ll write a summary here:

  • Edit /var/www/owncloud/config/config.php
  • At the bottom of the file, add:
    'memcache.local' => '\OC\Memcache\Memcached',
    'memcache.distributed' => '\OC\Memcache\Memcached',
    'memcached_servers' => 
    array (     0 => 
    array (     0 => '127.0.0.1',     1 => 11211,     ),     ),
  • Check that memcached is running:

      root@owncloud:# netstat -nap | grep memcached
      tcp        0      0 127.0.0.1:11211         0.0.0.0:*               LISTEN      457/memcached
      udp        0      0 127.0.0.1:11211         0.0.0.0:*                           457/memcached
      unix  3      [ ]         STREAM     CONNECTED     7961     457/memcached
      unix  3      [ ]         STREAM     CONNECTED     7955     457/memcached
      unix  3      [ ]         STREAM     CONNECTED     7753     457/memcached
      unix  3      [ ]         STREAM     CONNECTED     7967     457/memcached
      unix  3      [ ]         STREAM     CONNECTED     7960     457/memcached
      unix  3      [ ]         STREAM     CONNECTED     7954     457/memcached
      unix  3      [ ]         STREAM     CONNECTED     7966     457/memcached
      unix  3      [ ]         STREAM     CONNECTED     7964     457/memcached
      unix  3      [ ]         STREAM     CONNECTED     7958     457/memcached
      unix  3      [ ]         STREAM     CONNECTED     7963     457/memcached
      unix  3      [ ]         STREAM     CONNECTED     7957     457/memcached

      Source: http://stackoverflow.com/questions/1690882/how-do-i-see-if-memcached-is-already-running-on-my-chosen-port

  • Done. You should now have a pretty safe (and optimized) environment to play with 🙂

 

ownCloud works pretty much the same way as Dropbox and others. Here’s a screenshot from a Mac client and one test-file synchronized:

owncloud_screenshot_mac_client

Fig 4. ownCloud + Mac.

 

Useful configuration paths

I’ll finish this blog post with a short summary of useful configuration paths. Here you go:

/var/www/owncloud/config/config.php (https://doc.owncloud.org/server/8.1/admin_manual/configuration_server/config_sample_php_parameters.html)
/var/www/owncloud/data
/var/www/owncloud/data/owncloud.log
/etc/nginx/sites-available/owncloud
/etc/fstab

/etc/fail2ban/jail.local
/etc/fail2ban/filter.d/*.conf
/var/log/fail2ban.log

Raspberry Pi Puppy Cam v.2.0

I promised to write an updated post about the Raspberry Pi Puppy cam v.1.0. I’m a man of my words so here’s the story. The nice part about this project was that so much of the material was available online (both hardware and software). I didn’t put the words “Rather secure” in the topic anymore, as all my RPi’s are secure from now on due to the Raspberry Pi OpenVPN-server project I wrote about earlier. The earlier camera was pretty useless so it was updated to Raspberry Pi’s own camera module. I also wanted servos so I could move the camera around (remotely).

Hardware:

        picamv2_2

        Fig 1. Raspberry Pi with camera module attached to Pi-Pan.

          picamv2_3

          Fig 2. Same thing, another view.

 

Software:

 

Basic steps:

  • Assembled the Pi-Pan and fitted it to the case (Fig 1), http://www.openelectrons.com/index.php?module=pagemaster&PAGE_user_op=view_page&PAGE_id=20
  • Installed the controller board on the GPIO pins, and the servo wires to the controller board, http://www.openelectrons.com/index.php?module=pagemaster&PAGE_user_op=view_page&PAGE_id=24 
  • Configured Raspbian (from raspi-config)
    • Expanded Filesystem (to fill the whole SD card)
    • Changed user password
    • Changed Internationalisation Options according to my needs
    • Enabled Camera
    • Advanced options:
      • Changed hostname
      • Enabled SSH
      • Enabled I2C (needed for servos)
  • Updated the Pi:
    • sudo rpi-update (firmware)
    • sudo apt-get update && sudo apt-get upgrade –y (software)
  • Installed necessary software for Pi-Pan (servoblaster), http://www.openelectrons.com/index.php?module=pagemaster&PAGE_user_op=view_page&PAGE_id=24
    • checked that the servos were working – they worked just fine.
  • Installed the amazing RPi Cam Web Interface. Just followed instructions from http://www.raspberrypi.org/forums/viewtopic.php?f=43&t=63276. Everything worked “out of the box”.
  • “Installed” the Pi-Pan addon for RPi Cam Web Interface, http://www.raspberrypi.org/forums/viewtopic.php?f=43&t=63276
    • modified it a bit; commented out everything that had to do with Pi-Light as I don’t use that. (If you’re reading this you probably know how to comment code so I won’t go into that).
  • My Camera is hanging upside down, so the Web Interface controllers had to be inverted. Easy task, just change the code below <input id=”halt_button” type=”button”>” in /var/www/index.php (not index.html) to:
    <input type="button" value="up" onclick="servo_down();"><br>
    <input type="button" value="left" onclick="servo_right();">
    <input type="button" value="down" onclick="servo_up();">
    <input type="button" value="right" onclick="servo_left();">
    • Up now inverts to down and left inverts to right (and so on).
  • That’s it for the software part! I did a test run a noticed that the Pi won’t work properly with the default settings (records in Full HD). If there’s “too much” movement while the video is saving/processing, and you also play with the servos, the Pi will freeze. I don’t need Full HD so I just changed the default resolution/recording resolution to a lower one (720p). This is done from /etc/raspimjpeg. My changes:

      #
      # Video Options
      #
      video_width 1280
      video_height 720
      video_fps 15
      video_bitrate 17000000
      MP4Box true
      MP4Box_fps 15

  • This is much smoother and the videos won’t be silly large either (like ~40MB for 15 seconds in Full HD). Now 30 seconds of video is about 10MB on disk.

 

Enhancements

I noticed that the servos go back to neutral position if you touch the action buttons after you’ve viewed your saved videos and return to the main page. This is very frustrating – when you hit a movement button (left, right, down, up), the servos will go to neutral and not continue where they left off before you went to download videos (same if you refresh the page). You can change the coordinates default position in the file /var/www/pipan.js. Trial and error will get your desired position.

Another thing you should change is the start-up behaviour of motion;

[warn] Not starting motion daemon, disabled via /etc/default/motion … (warning).

Just change this to “yes” and you are good to go;

# set to ‘yes’ to enable the motion daemon
start_motion_daemon=yes

 

I also decided to do some modifications to the index.php file regarding the pull-down menu with resolutions. As I already mentioned, I don’t like Full HD as it gets slow. The options are quite self-explanatory: 

/var/www/index.php: (original)

<td>Resolutions:</td>
          <td>
            Load Preset: <select onclick=”set_preset(this.value)”>
              <option value=”1920 1080 25 25 2592 1944″>Select option…</option>
              <option value=”1920 1080 25 25 2592 1944″>Std FOV</option>
              <option value=”1296 0730 25 25 2592 1944″>16:9 wide FOV</option>
              <option value=”1296 0976 25 25 2592 1944″>4:3 full FOV</option>
              <option value=”1920 1080 01 30 2592 1944″>Std FOV, x30 Timelapse</option>
            </select><br>

 

/var/www/index.php: (modified)

<td>Resolutions:</td>
          <td>
            Load Preset: <select onclick=”set_preset(this.value)”>
              <option value=”1280 0720 15 15 2592 1944″>Select option…</option>
              <option value=”1280 0720 15 15 2592 1944″>16:9, 720p, HD-ready</option>
              <option value=”1920 1080 25 25 2592 1944″>Std FOV</option>
              <option value=”1296 0730 25 25 2592 1944″>16:9 wide FOV</option>
              <option value=”1296 0976 25 25 2592 1944″>4:3 full FOV</option>
              <option value=”1920 1080 01 30 2592 1944″>Std FOV, x30 Timelapse</option>
            </select><br>

 

The value 15 15 is actually the frame rate. 15 is more than enough for a cam like this and the videos will be much smaller in size. You won’t choke the Pi with the encodings either.

 

Finally here’s a picture of the whole thing in action at home 🙂

picamv2_1

Fig 3. RPi Cam v.2.0 in action (mounted under a shelf).

 

…and here’s a picture of the webcam interface (unfortunately not mine, and the Pi-Pan addon controls are missing)

rpi-cam-control

Fig 4. RPi Cam Control (Source: http://www.sweetpi.de/blog/783/raspberry-pi-kamera-als-live-webcam-mit-aufnahmefunktion)

Running an OpenVPN Server on the Raspberry Pi

Time for a nice little Raspberry Pi project again, this time an OpenVPN Server! 🙂 My router at home is a bit oldish and can’t handle custom firmwares like DD-WRT or OpenWrt. It most certainly can’t handle VPN connections either. With these facts in mind, I thought I’d build my own vpn server with a Raspberry Pi. It was a little bit more complex than I thought, but I actually got it up ‘n running in a few days. It’s better to be safe than sorry, so please do some reading before you build. Here are a couple of good starting points which helped me in the right direction:

http://readwrite.com/2014/04/10/raspberry-pi-vpn-tutorial-server-secure-web-browsing (Mine is a modified version of this guide using server-bridge from the next link)
http://www.emaculation.com/doku.php/bridged_openvpn_server_setup
http://readwrite.com/2014/04/11/building-a-raspberry-pi-vpn-part-two-creating-an-encrypted-client-side#awesm=~oB89WBfWrt21bV
https://community.openvpn.net/openvpn/wiki/323-i-want-to-set-up-an-ethernet-bridge-on-the-1921681024-subnet-existing-dhcp
https://openvpn.net/index.php/open-source/documentation/miscellaneous/76-ethernet-bridging.html
https://openvpn.net/index.php/open-source/documentation/howto.html#config

My goals: Build a VPN Server using an existing DHCP server (router) on my internal LAN. (This is done by bridging btw). Port forwarding is used on the router so the vpn server is exposed to the Internet/WAN. Other goals was to keep the server rather secure. I built the server on top of Raspbian, which I’ll assume you can install by now. So here goes – the steps for building an OpenVPN server on a Raspberry Pi. Note: This is a VERY short guide, there are urls to longer explanations in my text. (I don’t feel like re-writing existing information).

  • Update the Pi to the newest version;
    • sudo apt-get update && sudo apt-get upgrade –y (for software)
    • sudo rpi-update (for kernel and firmware)
  • Install OpenVPN and bridge utils; sudo apt-get install openvpn bridge-utils –y
  • Become root: sudo –s
  • Generate keys:
  • Copy openvpn examples from /usr/share/doc/openvpn/examples/easy-rsa/2.0 to /etc/openvpn/easy-rsa
    • cp –r /usr/share/doc/openvpn/examples/easy-rsa/2.0 /etc/openvpn/easy-rsa
    • edit /etc/openvpn/easy-rsa/vars file
      • find and change EASY_RSA variable to export EASY_RSA=”/etc/openvpn/easy-rsa
  • Build CA Certificate and Root CA Certificate:
    • change dir to /etc/openvpn/easy-rsa
    • source ./vars –file: source ./vars
    • remove previous keys if necessary; ./clean-all
    • build your CA: ./build-ca
    • Create server credentials: ./build-key-server server
  • Create Diffie-Hellman key exchange: ./build-dh
  • Use OpenVPN’s built in DoS attack protection (generate a static HMAC key): openvpn –-genkey –-secret keys/ta.key
  • That’s it for the server, now we will create keys for the clients:
    • ./build-key jocke (leave challenge password blank and sign the certificate)
    • go to the keys directory: cd /etc/openvpn/easy-rsa/keys
    • (optional) use des3 encryption on the key: openssl rsa -in jocke.key -des3 -out jocke.3des.key

Until now, I’ve been following the guide from http://readwrite.com/2014/04/10/raspberry-pi-vpn-tutorial-server-secure-web-browsing. I’m going to use bridging however, so step 9 and forward aren’t suitable for me. Instead I followed the guide from http://www.emaculation.com/doku.php/bridged_openvpn_server_setup , and the “VPN Setup” –part. It worked really well, I just changed the IP’s to match my own network configuration/subnet. Also remember to change the settings mentioned in the “Final Settings in the VM” –part. My server.conf is a mix of both guides. Here it is:

port 1194
proto udp
dev tap0
ca /etc/openvpn/easy-rsa/keys/ca.crt
cert /etc/openvpn/easy-rsa/keys/xxxx.crt # SWAP WITH YOUR CRT NAME
key /etc/openvpn/easy-rsa/keys/xxxx.key # SWAP WITH YOUR KEY NAME
dh /etc/openvpn/easy-rsa/keys/dh1024.pem # If you changed to 2048, change that here!
remote-cert-tls client
ifconfig-pool-persist ipp.txt
server-bridge 192.168.11.1 255.255.255.0 192.168.11.201 192.168.11.254
client-to-client
keepalive 10 120
tls-auth /etc/openvpn/easy-rsa/keys/ta.key 0
cipher AES-128-CBC
comp-lzo
persist-key
persist-tun
status /var/log/openvpn-status.log 20
log /var/log/openvpn.log
verb 3

You should now have created the user keys following the above commands/guides. Instead of copying multiple key files to the clients, I prefer using the script from http://readwrite.com/2014/04/11/building-a-raspberry-pi-vpn-part-two-creating-an-encrypted-client-side#awesm=~oB89WBfWrt21bV. It’s very convenient and produces an .ovpn file which you can import in different OpenVPN clients. I’m too lazy to copy/paste, all I can say is that the default.txt –file should match the server.conf (use the same options).

Also remember to set up the Linux firewall to permit packets to flow freely over the newly created tap0 and br0 interfaces:

iptables -A INPUT -i tap0 -j ACCEPT
iptables -A INPUT -i br0 -j ACCEPT
iptables -A FORWARD -i br0 -j ACCEPT

and to make this information persistent/permanent:

  • sudo bash -c ‘iptables-save > /etc/network/iptables’
    • add a line to /etc/network/interfaces so the changes will become persistent;
      • pre-up iptables-restore < /etc/network/iptables (add it after the line iface eth0 inet dhcp)

 

The configuration part is now done. It’s always a good idea to look at the log files for better understanding and to check that everything is working. In my case everything looks (almost) fine:

cat /var/log/openvpn.log

Looking at the log when VPN-server starts (Nevermind the dates. Username and IPs also censored):

Tue Dec  2 12:21:02 2014 OpenVPN 2.2.1 arm-linux-gnueabihf [SSL] [LZO2] [EPOLL] [PKCS11] [eurephia] [MH] [PF_INET6] [IPv6 payload 20110424-2 (2.2RC2)] built on Oct 12 2013
Tue Dec  2 12:21:02 2014 NOTE: when bridging your LAN adapter with the TAP adapter, note that the new bridge adapter will often take on its own IP address that is different from what the LAN adapter was previously set to
Tue Dec  2 12:21:02 2014 NOTE: OpenVPN 2.1 requires ‘–script-security 2’ or higher to call user-defined scripts or executables
Tue Dec  2 12:21:02 2014 Diffie-Hellman initialized with 1024 bit key
Tue Dec  2 12:21:02 2014 Control Channel Authentication: using ‘/etc/openvpn/easy-rsa/keys/ta.key’ as a OpenVPN static key file
Tue Dec  2 12:21:02 2014 Outgoing Control Channel Authentication: Using 160 bit message hash ‘SHA1’ for HMAC authentication
Tue Dec  2 12:21:02 2014 Incoming Control Channel Authentication: Using 160 bit message hash ‘SHA1’ for HMAC authentication
Tue Dec  2 12:21:02 2014 TLS-Auth MTU parms [ L:1590 D:166 EF:66 EB:0 ET:0 EL:0 ]
Tue Dec  2 12:21:02 2014 Socket Buffers: R=[163840->131072] S=[163840->131072]
Tue Dec  2 12:21:02 2014 TUN/TAP device tap0 opened
Tue Dec  2 12:21:02 2014 TUN/TAP TX queue length set to 100
Tue Dec  2 12:21:02 2014 Data Channel MTU parms [ L:1590 D:1450 EF:58 EB:135 ET:32 EL:0 AF:3/1 ]
Tue Dec  2 12:21:02 2014 UDPv4 link local (bound): [undef]
Tue Dec  2 12:21:02 2014 UDPv4 link remote: [undef]
Tue Dec  2 12:21:02 2014 MULTI: multi_init called, r=256 v=256
Tue Dec  2 12:21:02 2014 IFCONFIG POOL: base=192.168.11.201 size=54, ipv6=0
Tue Dec  2 12:21:02 2014 ifconfig_pool_read(), in=’xxxxx,192.168.11.201′, TODO: IPv6
Tue Dec  2 12:21:02 2014 succeeded -> ifconfig_pool_set()
Tue Dec  2 12:21:02 2014 IFCONFIG POOL LIST
Tue Dec  2 12:21:02 2014 xxxxx,192.168.11.201
Tue Dec  2 12:21:02 2014 Initialization Sequence Completed

Looking at the (same) log when a client connects:

Mon Dec  1 15:52:13 2014 MULTI: multi_create_instance called
Mon Dec  1 15:52:13 2014 x.x.x.x:51208 Re-using SSL/TLS context
Mon Dec  1 15:52:13 2014 x.x.x.x:51208 LZO compression initialized
Mon Dec  1 15:52:13 2014 x.x.x.x:51208 Control Channel MTU parms [ L:1590 D:166 EF:66 EB:0 ET:0 EL:0 ]
Mon Dec  1 15:52:13 2014 x.x.x.x:51208 Data Channel MTU parms [ L:1590 D:1450 EF:58 EB:135 ET:32 EL:0 AF:3/1 ]
Mon Dec  1 15:52:13 2014 x.x.x.x:51208 Local Options hash (VER=V4): ‘xxxxxx’
Mon Dec  1 15:52:13 2014 x.x.x.x:51208 Expected Remote Options hash (VER=V4): ‘xxxxxx’
Mon Dec  1 15:52:13 2014 x.x.x.x:51208 TLS: Initial packet from [AF_INET]x.x.x.x:51208, sid=40186f54 2801328f
Mon Dec  1 15:52:13 2014 x.x.x.x:51208 VERIFY OK: depth=1, /C=XX/ST=XX/L=XXX/O=XXXXXXXXX/OU=xxx/CN=xxxxx/name=XX/emailAddress=mail@host.domain
Mon Dec  1 15:52:13 2014 x.x.x.x:51208 Validating certificate key usage
Mon Dec  1 15:52:13 2014 x.x.x.x:51208 ++ Certificate has key usage  0080, expects 0080
Mon Dec  1 15:52:13 2014 x.x.x.x:51208 VERIFY KU OK
Mon Dec  1 15:52:13 2014 x.x.x.x:51208 Validating certificate extended key usage
Mon Dec  1 15:52:13 2014 x.x.x.x:51208 ++ Certificate has EKU (str) TLS Web Client Authentication, expects TLS Web Client Authentication
Mon Dec  1 15:52:13 2014 x.x.x.x:51208 VERIFY EKU OK
Mon Dec  1 15:52:13 2014 x.x.x.x:51208 VERIFY OK: depth=0, /C=XX/ST=XX/L=XXX/O=XXXXXXXXX/OU=xxx/CN=xxxxx/name=XX/emailAddress=mail@host.domain
Mon Dec  1 15:52:13 2014 x.x.x.x:51208 Data Channel Encrypt: Cipher ‘AES-128-CBC’ initialized with 128 bit key
Mon Dec  1 15:52:13 2014 x.x.x.x:51208 Data Channel Encrypt: Using 160 bit message hash ‘SHA1’ for HMAC authentication
Mon Dec  1 15:52:13 2014 x.x.x.x:51208 Data Channel Decrypt: Cipher ‘AES-128-CBC’ initialized with 128 bit key
Mon Dec  1 15:52:13 2014 x.x.x.x:51208 Data Channel Decrypt: Using 160 bit message hash ‘SHA1’ for HMAC authentication
Mon Dec  1 15:52:13 2014 x.x.x.x:51208 Control Channel: TLSv1, cipher TLSv1/SSLv3 DHE-RSA-AES256-SHA, 1024 bit RSA
Mon Dec  1 15:52:13 2014 x.x.x.x:51208 [xxxxx] Peer Connection Initiated with [AF_INET]x.x.x.x:51208
Mon Dec  1 15:52:13 2014 xxxxx/x.x.x.x:51208 MULTI_sva: pool returned IPv4=192.168.11.201, IPv6=bccd:800:8ced:200:14c2:700:8427:5201
Mon Dec  1 15:52:16 2014 xxxxx/x.x.x.x:51208 PUSH: Received control message: ‘PUSH_REQUEST’
Mon Dec  1 15:52:16 2014 xxxxx/x.x.x.x:51208 send_push_reply(): safe_cap=960
Mon Dec  1 15:52:16 2014 xxxxx/x.x.x.x:51208 SENT CONTROL [xxxxx]: ‘PUSH_REPLY,route-gateway 192.168.11.1,ping 10,ping-restart 120,ifconfig 192.168.11.201 255.255.255.0’ (status=1)
Mon Dec  1 15:52:16 2014 xxxxx/x.x.x.x:51208 MULTI: Learn: 7e:0a:47:c6:2a:76 -> xxxxx/x.x.x.x:51208
Mon Dec  1 15:52:29 2014 read UDPv4 [ECONNREFUSED]: Connection refused (code=111)
Mon Dec  1 15:52:39 2014 read UDPv4 [ECONNREFUSED]: Connection refused (code=111)
Mon Dec  1 15:52:49 2014 read UDPv4 [ECONNREFUSED]: Connection refused (code=111)
Mon Dec  1 15:53:20 2014 read UDPv4 [ECONNREFUSED]: Connection refused (code=111)
Mon Dec  1 15:53:30 2014 read UDPv4 [ECONNREFUSED]: Connection refused (code=111)
Mon Dec  1 15:56:16 2014 read UDPv4 [EHOSTUNREACH]: No route to host (code=113)

I was wondering what the ECONNREFUSED was all about. A little bit of googling got me on the right track. The solution was to add the line

push “explicit-exit-notify 3” to the server.conf.

After this trick the errors went away.

Source: https://forums.openvpn.net/topic10674.html

 

Finally I thought I’d read about server hardening so I won’t leave any holes open for hackers:

https://community.openvpn.net/openvpn/wiki/Hardening
https://openvpn.net/index.php/open-source/documentation/howto.html#security
http://darizotas.blogspot.fi/2014/04/openvpn-hardening-cheat-sheet.html

Most of these options are already in use so I’m feeling safe enough. This is after all only a little hobby server and not a big company server. I’ve learned tons and tons of stuff and I now have a working OpenVPN server at home 🙂

(A rather secure) Raspberry Pi Puppy Cam

My girlfriend recently got a puppy (Fig 2), so I decided to build a puppy cam (Fig 1) for her/us 🙂 I already had a spare Raspberry Pi with all the needed hardware laying around.

RaspberryPi

Fig 1. Raspberry Pi with Logitech QuickCam Fusion

minni2

Fig 2. The camera victim (Flat-Coated Retriever)

 

Components:

  • Raspberry Pi Model B
  • Clear Raspberry Pi Case from www.modmypi.com
  • 16GB SD card
  • Logitech QuickCam Fusion (old crap capable of 640×480)
  • D-Link DWA-121 802.11n Wireless N 150 Pico Wi-Fi-adapter
  • Deltaco AC adapter, 230V – 5V, 1A, Micro USB, 1.8m
  • Raspbian (Wheezy), Release 2014-01-07
  • (for setup: HDMI-to-DVI adapter, usb hub, usb mouse + keyboard)

 

Steps:

  • Installed Raspbian on a 16GB SD-card following the guide from https://www.andrewmunsell.com/blog/getting-started-raspberry-pi-install-raspbian
  • Configured some default options like password, system locale and so on after first start-up. Also enabled SSH (and disabled root login over ssh in /etc/ssh/sshd_config, (PermitRootLogin no)).
  • Followed a nice guide from http://www.codeproject.com/Articles/665518/Raspberry-Pi-as-low-cost-HD-surveillance-camera, with some modifications;
    • I’m not using the Raspberry Pi camera module, instead an old Logitech QuickCam Fusion, http://www.logitech.com/en-us/support/278?crid=405
    • updated the Raspberry Pi, sudo rpi-update
    • updated all packages, sudo apt-get update, sudo apt-get upgrade
    • Configured Wi-Fi following http://mattluurocks.com/index.php/raspbmc-dlink-dwa121-usb-pico-adapter
    • Checked that camera was detected (it was):

        root@xxx: /home/xxxx# lsusb
        Bus 001 Device 002: ID 0424:9512 Standard Microsystems Corp.
        Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub
        Bus 001 Device 003: ID 0424:ec00 Standard Microsystems Corp.
        Bus 001 Device 004: ID 046d:08c1 Logitech, Inc. QuickCam Fusion
        Bus 001 Device 005: ID 2001:3308 D-Link Corp. DWA-121 802.11n Wireless N 150 Pico

    • Installed the motion detection software:
      • sudo apt-get install motion
    • enabled motion deamon so it auto-starts in /etc/default/motion. Changed the line to: start_motion_daemon=yes
    • chmodded the files according to the above mentioned guide.
    • also edited /etc/motion/motion.conf following the guide, but managed to brake my own configuration 🙂 (motion process killed itself after a couple of seconds…)
      • A bit of detective work in /var/log/messages revealed:

          motion: [1] cap.card: “UVC Camera (046d:08c1)”
          motion: [1] cap.bus_info: “usb-bcm2708_usb-1.2”
          motion: [1] cap.capabilities=0x84000001
          motion: [1] – VIDEO_CAPTURE
          motion: [1] – STREAMING
          motion: [1] Config palette index 8 (YU12) doesn’t work.
          motion: [1] Supported palettes:
          motion: [1] 0: MJPG (MJPEG)
          motion: [1] 1: YUYV (YUV 4:2:2 (YUYV))
          motion: [1] Selected palette YUYV

      • changed the value to v4l2_palette 2 in motion.conf. Success! Motion now keeps running.
    • Made a directory for captures, mkdir /home/xxxx/captures , and pointed the configuration to that dir, “target_dir /home/xxxx/captures”
    • Had a look at http://www.lavrsen.dk/foswiki/bin/view/Motion/ConfigFileOptions
      • my own changes if someone is interested (along with the other changes above):
        • daemon on
        • width 640, height 480
        • framerate 5
        • pre_capture 2
        • post_capture 2
        • max_mpeg_time 600
        • output_normal off (I don’t need saved pictures, only videos)
        • ffmpeg_video_codec msmpeg4
        • webcam_port 8080
        • webcam_localhost off
        • control_port 8081
        • control_localhost off
        • control_authentication xxx:xxx

Setting up a cron job for motion:

I don’t want to have the cam running 24/7 so I decided to setup a cron job to fix that. Steps:

  • changed to root user instead of “xxxx” user, “sudo –s”
  • edited the crontab file, “crontab –e”
    • pasted the following:

      30 8 * * * /usr/bin/motion
      30 15 * * * /usr/bin/killall motion

    • Check the file/cron list with “crontab –l”

This will start motion at 8.30AM and shut it down at 3.30PM (daily)

Cron source: http://superuser.com/questions/169654/how-to-schedule-motion-detection

 

Securing (SSH on) the RPi

Because I forward the SSH port to the WAN side, I want to stay safe. (Yes, allowing to connect only with ssh keys is the safest method, I know, but a bit over the top for this project. Instead I’ll focus on securing ssh overall). Raspbian doesn’t seem to understand TCP wrappers (hosts.allow & hosts.deny), so I decided to use iptables instead. (Yes, I could have used another port than 22 also, but if some hacker want to get it in… they will anyhow). After a bit of fiddling I got it working.

At first, I installed a package called fail2ban (www.fail2ban.org), sudo apt-get install fail2ban. It automatically bans IP addresses that are failing to authenticate over SSH too many times. (The default fail2ban-options for SSH are OK for me, maxRetry = 6). This is the first layer of protection. After this I added some iptable rules for additional protection:

root@xxx:/home/xxx
iptables -A INPUT -j ACCEPT -m state –state ESTABLISHED,RELATED (read comment in sources below, first link)
iptables -A INPUT -p tcp –dport 80 -m state –state NEW -j ACCEPT (open up port 80 for nginx web server)
iptables -A INPUT -p tcp –dport 8080 -m state –state NEW -j ACCEPT (open up port 8080 for motion’s own web server)
iptables -A INPUT -p icmp -m icmp –icmp-type 8 -j ACCEPT (open up for ping)
iptables -I INPUT -p tcp -m tcp -s xxxx.xxx.xxx.xx –dport 22 -j ACCEPT (SSH: my work pc)
iptables -I INPUT -p tcp -m tcp -s xxxx.xxx.xxx.xx –dport 22 -j ACCEPT (SSH: another linux login server)
iptables -I INPUT -p tcp -m iprange –src-range 192.168.0.100-254 –dport 22 -j ACCEPT (SSH: access from internal network)
iptables -I INPUT -p tcp -m tcp -s 0.0.0.0/0 –dport 22 -j DROP (SSH: deny all the rest)
iptables -P INPUT DROP (block all inbound traffic not accepted by a rule)

Sources:
http://virtualitblog.blogspot.fi/2013/05/installing-iptables-on-raspberry-pi.html
http://blog.self.li/post/63281257339/raspberry-pi-part-1-basic-setup-without-cables
http://www.skullbox.net/iptables-specific-ip.php
http://serverfault.com/questions/161401/how-to-allow-a-range-of-ips-with-iptables

Then we should save the rules so they become persistent:
  • sudo bash -c ‘iptables-save > /etc/network/iptables’
  • then adding a line to /etc/network/interfaces so the changes will be persistent:
    • pre-up iptables-restore < /etc/network/iptables (add it after the line iface eth0 inet dhcp for ethernet connection or after iface wlan0 inet dhcp if on wlan)
  • Changes are now permanent

Source: http://www.simonthepiman.com/how_to_setup_your_pi_for_the_internet.php

We can check what the current iptables look like by looking at the (auto-created) file /etc/network/iptables:

root@xxxx:/home/xxxx# cat /etc/network/iptables
# Generated by iptables-save v1.4.14 on Tue Jun  3 15:53:59 2014
*filter
:INPUT DROP [27:4572]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [90:10559]
:fail2ban-ssh – [0:0]
-A INPUT -p tcp -m multiport –dports 22 -j fail2ban-ssh
-A INPUT -s xxxx.xxx.xxx.xx/32 -p tcp -m tcp –dport 22 -j ACCEPT
-A INPUT -p tcp -m iprange –src-range 192.168.0.100-254.0.0.0 -m tcp –dport 22 -j ACCEPT
-A INPUT -s xxxx.xxx.xxx.xx/32 -p tcp -m tcp –dport 22 -j ACCEPT
-A INPUT -p tcp -m tcp –dport 22 -j DROP
-A INPUT -m state –state RELATED,ESTABLISHED -j ACCEPT
-A INPUT -p tcp -m tcp –dport 80 -m state –state NEW -j ACCEPT
-A INPUT -p tcp -m tcp –dport 8080 -m state –state NEW -j ACCEPT
-A INPUT -p icmp -m icmp –icmp-type 8 -j ACCEPT
-A fail2ban-ssh -j RETURN
COMMIT
# Completed on Tue Jun  3 15:53:59 2014

and the same with iptables –L command:

root@xxx:/home/xxxx# iptables -L
Chain INPUT (policy DROP)
target     prot opt source                    destination
fail2ban-ssh  tcp  —  anywhere          anywhere             multiport dports ssh
fail2ban-ssh  tcp  —  anywhere          anywhere             multiport dports ssh
ACCEPT     tcp  —  xxxxx.xxx.fi             anywhere             tcp dpt:ssh (my workstation)
ACCEPT     tcp  —  anywhere               anywhere             source IP range 192.168.0.100-254.0.0.0 tcp dpt:ssh
ACCEPT     tcp  —  xxxxx.xxx.fi             anywhere             tcp dpt:ssh (another linux login server)
DROP       tcp  —  anywhere                anywhere             tcp dpt:ssh
ACCEPT     all  —  anywhere                anywhere             state RELATED,ESTABLISHED
ACCEPT     tcp  —  anywhere               anywhere             tcp dpt:http state NEW
ACCEPT     tcp  —  anywhere               anywhere             tcp dpt:http-alt state NEW
ACCEPT     icmp —  anywhere             anywhere             icmp echo-request

Chain FORWARD (policy ACCEPT)
target     prot opt source               destination

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination

Chain fail2ban-ssh (2 references)
target     prot opt source               destination
RETURN     all  —  anywhere             anywhere
RETURN     all  —  anywhere             anywhere

 

Installing NGINX Web Server (for HTTP Authentication)

As the basic installation of motion doesn’t support authentication for the stream, I needed some other way of protecting it. My solution was to use NGINX Web server for authentication. I won’t use a reverse proxy to redirect directly to the stream, as I need a “middle page” with some html code (so I can watch the stream in any browser). More of that in the chapter “Motion MJPEG “fix” for any browser”.

To be able to watch the puppy cam from anywhere on the Internet and not only from your own LAN, you have to use port forwarding on your router. I won’t go into the details here as there are many different guides available on the net. That said, I forwarded port 80, 8080 and 22 from the internal network to the external network. (Yes, I’m using these default ports as a hacker will find the correct ports to hack anyway). I’ve also registered a  (free) dynamic-to-static dns address on www.noip.com. You can enter this noip-information into the routers configuration, but the configuration is different on different router brands. (It’s probably called something like “Dynamic DNS” though). With all this done I can now watch the puppy cam from any computer or device by just entering the web address http://(censored).noip.me (and login+password) in a browser. Anyways, here are the steps for installing and configuring nginx:

  • sudo apt-get install nginx
    • (Auto)start nginx service:  service nginx start
  • sudo apt-get install lynx (terminal based browser for testing). Linux curl-command can also be used.
  • Testing that it works: lynx 127.0.0.1 – response: Welcome to nginx! (It works!)
  • Install apache utils to generate htpasswd files for authentication, sudo apt-get install apache2-utils
  • took a backup of /etc/nginx/sites-available/default –file. Then edited it:
    • changed root /usr/share/nginx/www; to root /home/xxx/www; (easier and more logical to edit and manage the webpage from /home).
    • created a htpasswd, sudo htpasswd –c /home/xxx/.htpasswd xxxxx
    • configured root dir on website to use htpasswd, under location / {
      • auth_basic “Restricted”;
      • auth_basic_user_file /home/xxx/.htpasswd;
  • The whole (tiny) configuration now looks like:

server {
        listen   80

        root /home/xxx/www;
        index index.html index.htm;

        location / {
                try_files $uri $uri/ /index.html;
                auth_basic “Restricted”;
             auth_basic_user_file /home/xxx/.htpasswd;

    }
}

and my fancy index.html file looks like:

<html>
<head>
<title>Welcome to xxxxxxxcam!</title>
</head>
<body bgcolor=”white” text=”black”>
<center><h1>This is the xxxxx webcam stream!</h1></center><br>
<center>
<h3><a href=”http://censored.noip.me:8080″>Firefox link</a></h3><br>
<h3><a href=”index2.html”>IE/Chrome/Mobile link</a></h3><br>
</center>
</body>
</html>

and in a screenshot:

nginx_index_page1

Fig 3. Main page (after I’ve entered login & password)

The Firefox-link links directly to the motion stream, as Firefox natively supports MJPEG. The IE/Chrome-link links to another webpage which uses java to display the mjpeg stream (see the chapter: Motion MJPEG “fix” for any browser). That page (Index2.html) looks like this:

<html>
<head>
<title>Welcome to xxxxxcam!</title>
</head>
<body bgcolor=”white” text=”black”>
<center><h1>This is the xxxxxx webcam stream!</h1></center><br>
<center>
<applet code=com.charliemouse.cambozola.Viewer
archive=cambozola.jar width=”640″ height=”480″ style=”border-width:1; border-color:gray; border-style:solid;”> <param name=url value=”http://censored.noip.me:8080″></applet&gt;
</center>
</body>
</html>

So basically what I’ve done is setup a password protected login page from which you can choose the method of displaying the stream.

 

Setting up a cron job for nginx:

Same principle as with motion, except:

35 8 * * * /etc/init.d/nginx start
35 15 * * * /etc/init.d/nginx stop

This will start nginx at 8.35AM and shut it down at 3.35PM (daily)

Useful nginx file locations:

/etc/nginx/sites-available and the default file
/etc/nginx and the nginx.conf file
/var/log/nginx and the error.log & access.log files

Starting and stopping the webserver:

service nginx start
service nginx stop

Sources:

http://www.ducky-pond.com/posts/2013/Sep/setup-a-web-server-on-rpi/
https://gist.github.com/mcfadden/7063035
http://nginx.org/en/docs/beginners_guide.html

 

Motion MJPEG “fix” for any browser

The problem is that Internet Explorer (and other browsers as well) doesn’t support multipart jpeg (MJPEG). There’s a fix available at:

http://www.lavrsen.dk/foswiki/bin/view/Motion/WebcamServer 

This assumes that you create a html page in which you include a bit of code. From the webpage:

The webserver generates a stream in “multipart jpeg” format (mjpeg). You cannot watch the stream with most browsers. Only certain versions of Netscape works. Mozilla and Firefox brosers can view the mjpeg stream but you often have to refresh the page once to get the streaming going. Internet Explorer cannot show the mjpeg stream. For public viewing this is not very useful. There exists a java applet called Cambozola which enabled any Java capable browser to show the stream. To enable the feature to a broad audience you should use this applet or similar.”

 

Securing NGINX with Fail2Ban

Well, I didn’t even have the server online for a long time before someone started probing/bombing for usernames and passwords (looking in the access and error logs). Sample from /var/log/nginx/error.log:

2014/06/09 15:38:12 [error] 4925#0: *24 user “manager” was not found in “/home/xxxx/.htpasswd”, client: 208.109.87.x, server: , request: “GET /manager/html HTTP/1.1”, host: “x.x.x.x”
2014/06/09 15:38:13 [error] 4925#0: *24 user “manager” was not found in “/home/xxxx/.htpasswd”, client: 208.109.87.x, server: , request: “GET /manager/html HTTP/1.1”, host: “x.x.x.x”
2014/06/09 15:38:14 [error] 4925#0: *24 user “user” was not found in “/home/xxxx/.htpasswd”, client: 208.109.87.x, server: , request: “GET /manager/html HTTP/1.1”, host: “x.x.x.x”
2014/06/09 15:38:16 [error] 4925#0: *24 user “user” was not found in “/home/xxxx/.htpasswd”, client: 208.109.87.x, server: , request: “GET /manager/html HTTP/1.1”, host: “x.x.x.x”

and from access.log:

208.109.87.x – manager [09/Jun/2014:15:38:12 +0300] “GET /manager/html HTTP/1.1” 401 194 “-” “-“
208.109.87.x – manager [09/Jun/2014:15:38:13 +0300] “GET /manager/html HTTP/1.1” 401 194 “-” “-“
208.109.87.x – user [09/Jun/2014:15:38:14 +0300] “GET /manager/html HTTP/1.1” 401 194 “-” “-“
208.109.87.x – user [09/Jun/2014:15:38:16 +0300] “GET /manager/html HTTP/1.1” 401 194 “-” “-“

Apparently “they” are trying to access /manager/html (Tomcat probing?) which doesn’t even exist on my site… oh well, this is not acceptable so I’ll have to block or ban these bastards. Of course I could try using https with certificates instead of http but it’s a bit overkill for this little server/hobby project 🙂

I started with a DDOS attack filter, info here: https://rtcamp.com/tutorials/nginx/fail2ban/

I then followed http://snippets.aktagon.com/snippets/554-how-to-secure-an-nginx-server-with-fail2ban to:

  • Block anyone trying to run scripts (.pl, .cgi, .exe, etc)
  • Block anyone trying to use the server as a proxy
  • Block anyone failing to authenticate using nginx basic authentication
  • Block anyone failing to authenticate using our application’s log in page
  • Block bad bots
  • Limit the number of connections per session

After this was done I ran:

root@xxx:/home/xxx# tail /var/log/fail2ban.log

2014-06-10 10:21:04,342 fail2ban.jail   : INFO   Jail ‘ssh’ started
2014-06-10 10:21:04,516 fail2ban.jail   : INFO   Jail ‘nginx-req-limit’ started
2014-06-10 10:21:04,618 fail2ban.jail   : INFO   Jail ‘nginx-auth’ started
2014-06-10 10:21:04,837 fail2ban.jail   : INFO   Jail ‘nginx-login’ started
2014-06-10 10:21:04,964 fail2ban.jail   : INFO   Jail ‘nginx-badbots’ started
2014-06-10 10:21:05,100 fail2ban.jail   : INFO   Jail ‘nginx-noscript’ started
2014-06-10 10:21:05,227 fail2ban.jail   : INFO   Jail ‘nginx-proxy’ started

(iptables –L now also lists a longer list with all these new fail2ban-rules. Won’t paste here as it’s a bit long…)

Luckily I did apply these filters, because the next day I got bombed by a ZmEu attack. Information about ZmEu:

http://ensourced.wordpress.com/2011/02/25/zmeu-attacks-some-basic-forensic/
http://support.scalr.net/discussions/questions/1841-should-i-be-worried-about-w00tw00tatblackhatsromaniananti-sec
http://stackoverflow.com/questions/13897993/am-i-being-hacked

Probably nothing to worry about as ISP’s are doing their own penetration testing all the time. Fail2Ban blocked it however (fail2ban.log):

2014-06-11 13:33:34,301 fail2ban.actions: WARNING [nginx-noscript] Ban 89.248.160.x
2014-06-11 13:43:34,409 fail2ban.actions: WARNING [nginx-noscript] Unban 89.248.160.x

 

With all this done, I now feel rather safe. After all, this is not a production server in Redmond 🙂

(If I do feel like experimenting with more security one day, I’ll compile my own Nginx with ModSecurity.  (http://www.modsecurity.org/projects/modsecurity/nginx/))

And there you have it – a rather nice and secure puppy cam. Enjoy! 🙂

 

Update: Version 2.0 of the Puppy Cam available here