Simple Web-App and HowTo for setting up a Raspberry Pi with Camera for Time-lapse Photography
Clone or download
Pull request Compare This branch is 15 commits ahead, 6 commits behind not-implemented:master.
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Type Name Latest commit message Commit time
Failed to load latest commit information.

Descrption of the forked project

Most of the code here is displayed and explained on


Simple Web-App and complete HowTo for setting up a Raspberry Pi with Camera for Time-lapse Photography.

  • Node.js based Web-App for controlling and monitoring the camera and the Raspberry Pi
  • Reverse-SSH-Tunnel to another server - reach your Raspberry Pi behind firewalls (optional)
  • Dynamic-DNS-Client - find your Raspberry Pi easier in your local network (optional)
  • Wi-Fi autoconnect - if you have a USB Wi-Fi Adapter (optional)
  • Network-Watchdog - reset network and maybe emergency-reboot if connection is broken (optional)
  • BitTorrent-Sync - as sync-solution to get the photos out of the Pi (optional)
  • Sync-Script - via rsync as alternative to BitTorrent-Sync (optional)
  • Prerequisites: Raspberry Pi + Power + SD-Card, RaspiCam, LAN Cable, USB Wi-Fi Adapter (optional)


Table of Contents generated with DocToc


Setup SD-Card

  • Download current Raspbian ("Jessie" or newer - "Lite" is enough)
  • Write extracted ".img"-file to SD-Card - see OS specific instructions
  • Attach the camera to the Raspberry Pi - see instructions
  • Put the SD-Card into your Raspberry Pi, Connect to your LAN (DHCP server needed), Power on
  • Login via SSH (maybe use local IP): ssh raspberrypi (Login: pi / Password: raspberry)
  • Make complete SD-Card usable: sudo raspi-config - 1 Expand Filesystem - Finish - Reboot

Setup Raspbian + Raspberry Pi Camera

  • Install updates: sudo apt-get update, sudo apt-get dist-upgrade and sudo apt-get clean
  • For some helpful optional customizations of your Raspberry Pi - see here
  • Enable camera: sudo raspi-config - 6 Enable Camera - Enable - Finish
    (this also sets Memory Split to 128 MB)
  • Disable camera LED when taking pictures (optional):
    sudo sh -c 'echo "disable_camera_led=1" >> /boot/config.txt'
  • Reboot for the camera settings to take effect: sudo reboot

Setup RaspiCam-Timelapse

Install Node.js (for Node.js >=4.x you need Raspbian "Jessie" or newer - otherwise the native modules won't compile):

tar -xvf node-v4.4.3-linux-armv6l.tar.xz
sudo cp -R node-v4.4.3-linux-armv6l/{bin,include,lib,share} /usr/local/
rm -rf node-v4.4.3-linux-armv6l

Install GIT:

sudo apt-get install git

Check out this repository:

cd ~
git clone
cd raspicam-timelapse
npm install


# Create a self-signed certificate:
openssl req -x509 -days 3650 -sha256 -nodes -newkey rsa:2048 -keyout config/timelapse.key -out config/timelapse.crt
chmod og= config/timelapse.key

# Prepare capture directory:
mkdir ../capture

Start server:

npm start &

... now open your browser - i.e. with https://raspberrypi:4443/ or IP address (Login: timelapse / Password: timelapse) :-)

Enable start on reboot:

crontab -e

# Insert this line into crontab:
@reboot /usr/local/bin/node ~/raspicam-timelapse/server.js &

Reverse SSH-Tunnel (optional)

Be sure, to change the default password before allowing connections from untrusted networks - see here.

Generate SSH-Key on Raspberry Pi (just press ENTER everywhere):

cd ~
ssh-keygen -t rsa

# Show the public key for using later:
cat ~/.ssh/

Allow SSH connections from Raspberry Pi on your remote server:

# Maybe add a new user - i.e. "timelapse" on your remote server (but you can use an existing one):
adduser --gecos Timelapse timelapse
chmod go-rwx /home/timelapse
cd /home/timelapse

# Add the raspberry's key (.ssh/ from above) on your remote server
# to the user and just allow port-forwarding (no login):
mkdir -p .ssh
echo "command=\"echo 'This account can only be used for port-forwarding'\",no-agent-forwarding,no-pty,no-X11-forwarding" \
    "{raspberry-public-key-from-above}" >> .ssh/authorized_keys
chmod -R go-rwx .ssh
chown -R timelapse:timelapse .ssh

# Some global settings:
editor /etc/ssh/sshd_config

# Enable listening on all interfaces for port-forwarding on your remote server
# (otherwise port-forwarding will listen only on localhost):
GatewayPorts yes

# Detect and close dead connections faster and close forwarded ports to reuse them:
ClientAliveInterval 30
ClientAliveCountMax 3

# Restart SSH server:
service sshd restart

Back on Raspberry Pi: Configure tunnels to be established - create a script with editor like the following example to forward port 10022 from your remote server to port 22 on Raspberry Pi - same with port 4443 and 8888:


~/raspicam-timelapse/ssh-reverse-tunnel/ 10022 22 &
~/raspicam-timelapse/ssh-reverse-tunnel/ 4443 4443 &
~/raspicam-timelapse/ssh-reverse-tunnel/ 18888 8888 &
# Make it executable:
chmod +x

# Check SSH-Connection and permanently add the key (type "yes"):
# (... should print "This account can only be used for port-forwarding" and close SSH connection)

# Add script to crontab:
crontab -e

# Insert this lines into crontab:
@reboot ~/
* * * * * ~/

Dynamic-DNS-Client (optional)

# Link script:
sudo ln -snf /home/pi/raspicam-timelapse/dynamic-dns-client/lib_dhcpcd_dhcpcd-hooks_90-dynamic-dns /lib/dhcpcd/dhcpcd-hooks/90-dynamic-dns

# Change config vars in dynamic-dns.conf:
sudo editor ~/raspicam-timelapse/dynamic-dns-client/dynamic-dns.conf

Wi-Fi autoconnect (optional)

sudo editor /etc/wpa_supplicant/wpa_supplicant.conf

Append as many networks as you want - some examples:

# Secure Wi-Fi example:

# Open Wi-Fi example:

Activate Network-Watchdog (optional)

crontab -e

# Insert this line into crontab:
* * * * * sudo timeout -k 120 100 ~/raspicam-timelapse/network-watchdog/

# To enable the watchdog set IPV4_ENABLED=1 and/or IPV6_ENABLED=1 - default ping destination
# is the default gateway - override via IPV4_PING_DEST/IPV6_PING_DEST when needed:
cp ~/raspicam-timelapse/config/check-network.conf.example ~/raspicam-timelapse/config/check-network.conf
editor ~/raspicam-timelapse/config/check-network.conf

Use hardware watchdog with Network-Watchdog (optional)

apt-get install watchdog
sudo editor /etc/default/watchdog


sudo mkdir /etc/watchdog.d

# To enable the watchdog set IPV4_ENABLED=1 and/or IPV6_ENABLED=1 - default ping destination
# is the default gateway - override via IPV4_PING_DEST/IPV6_PING_DEST when needed:
cp ~/raspicam-timelapse/config/check-network.conf.example ~/raspicam-timelapse/config/check-network.conf
editor ~/raspicam-timelapse/config/check-network.conf
sudo ln -s ~/raspicam-timelapse/network-watchdog/ /etc/watchdog.d/

systemctl enable watchdog

Install BitTorrent-Sync (optional)

We currently use BitTorrent-Sync as sync-solution, because Syncthing is very slow on Raspberry Pi.

mkdir btsync && cd btsync
tar -xvzf ../BitTorrent-Sync_arm.tar.gz

# Start BitTorrent-Sync:
./btsync --webui.listen
cd ..

# Enable start on reboot:
crontab -e
@reboot ~/btsync/btsync --webui.listen

Now open Web-Interface via "https://raspberrypi:8888/" and add "/home/pi/capture" folder for sync.

After that disable sync of "latest.jpg":

editor capture/.sync/IgnoreList

# Append to the end:

Install Sync-Script (optional)

Second sync method is a configurable sync script. Currently only tested with rsync.

Setup config file

You have to configure some options in sync/sync.conf (examples) at first


# add sync script to crontab
crontab -e
*/5 * * * * ~/raspicam-timelapse/sync/ ~/capture

less strict ssh restrictions needed on your remote server

You have to modify the authorized_keys line to allow the sync command to be executed

-command="echo 'This account can only be used for port-forwarding'"

Example for


if [[ "$SSH_ORIGINAL_COMMAND" =~ [\&\;] ]] ;
    echo "Error: Invalid character found in command."
    exit 1

        echo "Error: Invalid command over ssh executed."
        exit 1


Use Ramdisk as primary capture folder (optional)

To save SD-Cards life, you can capture to a Ramdisk and sync immediately up. Only when sync does not work for any reason, files are moved to SD-Card and synced up from there.

fstab entry (sudo vim /etc/fstab)

capture_ramdisk /home/pi/capture_ramdisk tmpfs size=30M,uid=1000,gid=1000,mode=755 0 0
mkdir /home/pi/capture_ramdisk
sudo mount /home/pi/capture_ramdisk

Additional crontab entries

# add sync script to crontab
crontab -e
# sync job for ramdisk
* * * * * ~/raspicam-timelapse/sync/ ~/capture_ramdisk
# move files older than 3 minutes to sd card
* * * * * ~/raspicam-timelapse/sync/ ~/capture_ramdisk ~/capture

3G/4G backup connection (optional)

Setup usb-modeswitch to put modem into ethernet mode

sudo apt-get install usb-modeswitch usb-modeswitch-data

add udev rule
# Example values for Huawei E303 (please change for your specific device!):

cat <<EOF | sudo tee /etc/udev/rules.d/70-usb-modeswitch.rules > /dev/null
ACTION=="add", SUBSYSTEM=="usb", ATTRS{idVendor}=="$vendor_id", ATTRS{idProduct}=="$product_id", RUN+="/usr/sbin/usb_modeswitch -v $vendor_id -p $product_id -M $switch_message"

# reload udev:
sudo udevadm control --reload

Setup interfaces and routing

cp ~/raspicam-timelapse/config/interfaces-post-up.conf.example ~/raspicam-timelapse/config/interfaces-post-up.conf
editor ~/raspicam-timelapse/config/interfaces-post-up.conf
sudo editor /etc/network/interfaces

# add these lines:
auto eth1
iface eth1 inet dhcp
    post-up /home/pi/raspicam-timelapse/backup-connection/
# add dhcp configuration to dhcp config file
cat backup-connection/dhcpcd-to_add.conf | sudo tee -a /etc/dhcpcd.conf

Now plug in your UMTS stick.

Add additional tunnels to (replace <stick_local_ip>!)

~/raspicam-timelapse/ssh-reverse-tunnel/ 11022 22 <stick_local_ip> &


  • Switch to Ansible
  • Implement as a systemd service (start on boot, restart on crash, restart raspistill after crash)
  • Use NVM for installing Node.js -
  • Get Dynamic-DNS-Client more stable (trigger on IP adress changes, not just on cable plug)