Django MEZZANINE Blog Setup


In the previous post, I wrote how to set up django zinnia blog.
However, django-zinnia-blog documentation is not really intended for django beginners and you have read the source to know how it works.
I only know the basic, I could not properly override urls and templates, because it seemed django-zinnia-blog apps depend on each other and it was difficult to just deploy the app I want from it.
Mezzanine is a CMS but has a blog functionality as well. And most importantly it has very rich documentation. It's got even FAQ! It also explains how to override templates.:) I think it comes with caching functionality, too because it performs a lot faster than zinnia with demo setup.
A following note is how to have mezzaine running on arch linux with nginx and postgresql and uwsgi. I choose arch linux, because it is the simplest distribution I know and it's bleeding edge which I think makes the OS more secure. Systemd works wonderfully as well. Nginx and postgresql are chosen just because I feel they are a lot lighter than other alternatives. I alway choose uwsgi because it is simple enough and people say it performs the best among python application servers.

1. Nesessary packages. (from Arch linux repository and pip)
pacman -S python-pip libjpeg-turbo gcc nginx postgresql
pip install mezzanine
pip install uwsgi

2. DB (btrfs)
su - postgres
initdb --locale en_GB.UTF-8 -E UTF8 -D '/var/lib/postgres/data/'
chattr +C /var/lib/postgres/data

su -
systemctl start postgresql
systemctl enable postgresql

su - postgres
createuser --interactive
createdb myblogdb

psql
GRANT ALL ON DATABASE myblogdb TO root;
\q

3. uwsgi
mkdir -p /etc/uwsgi/vassals

vim /etc/uwsgi/emperor.ini
#--------------------------#
[uwsgi]
emperor = /etc/uwsgi/vassals
uid = http
gid = http
#--------------------------#

vim /etc/systemd/system/emperor.uwsgi.service
#--------------------------#
[Unit]
Description=uWSGI Emperor
After=syslog.target

[Service]
ExecStart=/usr/bin/uwsgi --ini /etc/uwsgi/emperor.ini
ExecReload=/bin/kill -HUP $MAINPID
ExecStop=/bin/kill -INT $MAINPID
Restart=always
Type=notify
StandardError=syslog
NotifyAccess=all
KillSignal=SIGQUIT

[Install]
WantedBy=multi-user.target
#--------------------------#

4. MEZZANINE
mkdir /opt/mezzanine
cd /opt/mezzanine
mezzanine-project myblog
cd myblog

vim myblog/local_settings.py
#--------------------------#

DATABASES = {
    'default': {
    'ENGINE': 'django.db.backends.postgresql',
    'NAME': 'myblogdb',
    'USER': 'root',
    'HOST': 'localhost',
    'PORT': '5432',
    }
}
#--------------------------#

cp -p /usr/lib/python3.5/site-packages/mezzanine/utils/html.py /usr/lib/python3.5/site-packages/mezzanine/utils/html.py.ori

vim /usr/lib/python3.5/site-packages/mezzanine/utils/html.py
#--------------------------#
remove ,HTMLParseError from the forth line.
#--------------------------#

mkdir -p static/media
python manage.py collectstatic
python manage.py migrate

5. nginx conf for mezzanine. (Example. I recommend going full ssl.)
vim /opt/mezzanine/myblog/myblog_nginx.conf
#--------------------------#
upstream django {
    server 127.0.0.1:8001;
}

server {
    listen 80;
    server_name 0.0.0.0;
    charset utf-8;

    location /static {
        alias /opt/mezzanine/myblog/static;
    }

    location / {
        uwsgi_pass django;
        include /etc/nginx/uwsgi_params;
    }
#--------------------------#

mkdir /etc/nginx/sites-enabled/
ln -s /opt/mezzanine/myblog/myblog_nginx.conf /etc/nginx/sites-enabled/

6. uwsgi conf for mezzanine

vim /opt/mezzanine/myblog/myblog_uwsgi.ini
#--------------------------#
[uwsgi]
chdir = /opt/mezzanine/myblog/
module = myblog.wsgi
master = true
processes = 4
socket = 127.0.0.1:8001
#--------------------------#

ln -s /opt/mezzanine/myblog/myblog_uwsgi.ini /etc/uwsgi/vassals/

7. http directive main nginx conf.
vim /etc/nginx/nginx.conf
#--------------------------#
include /etc/nginx/sites-enabled/*;
#--------------------------#

8. change local_settings.py to
DEBUG = False
ALLOWED_HOSTS = ['*']

9. Create admin user for the django project, resync the db just in case.
python manage.py createsuperuser
python manage.py migrate

10. start service
systemctl restart nginx
systemctl restart postgresql
systemctl restart emperor.uwsgi
systemctl reenable nginx
systemctl reenable postgresql
systemctl reenable emperor.uwsgi

Starting Python Django Zinnia Blog

Python Django Zinnia is a great alternative for WordPress, especially for those who don’t want to use PHP but Python for web development.
It uses Django which is a web application framework for python web app development. Django comes with a little web server and uses sqlite for backend database server by default. Here, I leave a note on how to set up django zinnia on top of postgresql, nginx and python3 on Arch Linux

 1. install necessary packages from repo.

pacman -S python python-pip nginx postgresql  python-psycopg2
pacman -S libjpeg-turbo gcc

 

2. install python modules.  don’t use uwsi from aur as it depends on python2 and some other unnecessary packages.

pip3 install django-blog-zinnia
pip3 install uwgsi

 

3. setup postgresql.

# Initialise DB
initdb --locale en_GB.UTF-8 -E UTF8 -D '/var/lib/postgres/data'

# disble cow (for btrfs filesystem)
chattr +C /var/lib/postgres/data

# start the service
exit
systemctl start postgresql
systemctl enable postgresql

# create user and db and grant privileges
createuser –interactive
createdb mydjangodb

# login to db
GRANT ALL PRIVILEGES ON DATABASE mydjangodb TO username;
\q

# change db config according to your needs
# default listen port is localhost:5432
/var/lib/postgres/data/postgresql.conf

 

3. Setup uwsgi.

# create directory

mkdir -p /etc/uwsgi/vassals

# Create emperor file (for managing multiple instances)

vim /etc/uwsgi/emperor.ini
[uwsgi]
emperor = /etc/uwsgi/vassals
uid = http
gid = http

# Create systemd unit file

vim /etc/systemd/system/emperor.uwsgi.service

[Unit]
Description=uWSGI Emperor
After=syslog.target

[Service]
ExecStart=/usr/bin/uwsgi –ini /etc/uwsgi/emperor.ini
ExecReload=/bin/kill -HUP $MAINPID
ExecStop=/bin/kill -INT $MAINPID
Restart=always
Type=notify
StandardError=syslog
NotifyAccess=all
KillSignal=SIGQUIT

[Install]
WantedBy=multi-user.target

 

3. change django db setting.

# Create django project under opt/django
mkdir -p /opt/django
cd /opt/django
django-admin.py startproject mysite

# Edit django a setting file, and change database setting.
vi mysite/mysite/settings.py

# DATABASES = {
# ‘default’: {
# ‘ENGINE’: ‘django.db.backends.sqlite3’,
# ‘NAME’: os.path.join(BASE_DIR, ‘db.sqlite3’),
# }
# }

Comment out like above and add lines below.
DATABASES = {
‘default’: {
‘ENGINE’: ‘django.db.backends.postgresql’,
‘NAME’: ‘mydjangodb’,
‘USER’: ‘username’,
‘HOST’: ‘localhost’,
‘PORT’: ‘5432’,
}
}

 

4. set django and nginx

 # Copy nginx uwsgi parameter files to django project directory.

cp /etc/nginx/uwsgi_params /opt/django/mysite/

# Create nginx config file under django project directory, and add the following.

vim /opt/django/mysite/mysite_nginx.conf

 

upstream django {
#server unix:///path/mysite.sock; # for using unix socket
server 127.0.0.1:8001;
}

server {
listen 8000;
server_name 127.0.0.1;
charset utf-8;

location /static {
alias /opt/django/mysite/static;
}

location / {
uwsgi_pass django;
include /opt/django/mysite/uwsgi_params;
}

}

# add below to http directive of nginx main config file

vim /etc/nginx/nginx.conf

include /etc/nginx/sites-enabled/*;

 

# Create nginx include config directory and link symbolically.
mkdir /etc/nginx/sites-enabled/
ln -s /opt/django/mysite/mysite_nginx.conf /etc/nginx/sites-enabled/

# Create uwsgi config file under django directory and link symbolically.

vim /opt/django/mysite/mysite_uwsgi.ini
[uwsgi]

chdir = /opt/django/mysite/
module = mysite.wsgi
master = true
processes = 4
socket = 127.0.0.1:8001

ln -s /opt/django/mysite/mysite_uwsgi.ini /etc/uwsgi/vassals/

cp -R /usr/lib/python3.5/site-packages/django/contrib/admin/static /opt/django/mysite/

 

5. Start the services

 

systemctl start emperor.uwsgi
systemctl start nginx

Now, you should be able to access to http://127.0.0.1:8000/admin/

 

6. Set up django-zinnia-blog

Trying to figure out…
adding ‘tagging’ to INSTALLED APPS fails the program.
without adding ‘tagging’ app, i cannot load zinnia…

python is failing to load the following module. get_model method is not included in the source from the first place!
‘from django.db.models import get_model’

OK. I found a solution.

# back up the original python module.
cp -p /usr/lib/python3.5/site-packages/tagging/templatetags/tagging_tags.py /usr/lib/python3.5/site-packages/tagging/templatetags/tagging_tags.py.ori# Rewrite the module.
Comment the following line
# from django.db.models import get_modelAnd add the following lines.
from django.apps import apps
get_model = apps.get_model# Copy the static files
cp -Rp /usr/lib/python3.5/site-packages/zinnia/static/zinnia /opt/django/mysite/static/

mysite-nginx.conf look like this.

upstream django {
#server unix:///path/mysite.sock; # for using unix socket
server 127.0.0.1:8001;
}

server {
listen 80;
server_name 0.0.0.0;
charset utf-8;

location /static {
alias /opt/django/mysite/static;
}

location / {
uwsgi_pass django;
include /opt/django/mysite/uwsgi_params;
}

}

setting.py looks like this.

import os

gettext = lambda s: s

DEBUG = False

DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'NAME': 'mydjangodb',
'USER': 'username',
'HOST': 'localhost',
'PORT': '5432',
}
}

TIME_ZONE = 'Asia/Tokyo'

STATIC_URL = '/static/'
STATIC_ROOT = '/opt/django/mysite/static/'

MEDIA_URL = '/media/'

SECRET_KEY = 'jo-1rzm(%sf)3#n+fb7h955yu$3(pt63abhi12_t7e^^5q8dyw'

USE_TZ = True
USE_I18N = True
USE_L10N = True

SITE_ID = 1

LANGUAGE_CODE = 'en'

ALLOWED_HOSTS = ('*')

LANGUAGES = (
('en', gettext('English')),
('fr', gettext('French')),
('de', gettext('German')),
('es', gettext('Spanish')),
('it', gettext('Italian')),
('nl', gettext('Dutch')),
('sl', gettext('Slovenian')),
('bg', gettext('Bulgarian')),
('hu', gettext('Hungarian')),
('cs', gettext('Czech')),
('sk', gettext('Slovak')),
('lt', gettext('Lithuanian')),
('ru', gettext('Russian')),
('pl', gettext('Polish')),
('eu', gettext('Basque')),
('he', gettext('Hebrew')),
('ca', gettext('Catalan')),
('tr', gettext('Turkish')),
('sv', gettext('Swedish')),
('is', gettext('Icelandic')),
('hr_HR', gettext('Croatian')),
('pt_BR', gettext('Brazilian Portuguese')),
('fa_IR', gettext('Persian')),
('fi_FI', gettext('Finnish')),
('uk_UA', gettext('Ukrainian')),
('zh-hans', gettext('Simplified Chinese')),
)

MIDDLEWARE_CLASSES = (
'django.middleware.common.CommonMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.middleware.locale.LocaleMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
'django.contrib.admindocs.middleware.XViewMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
)

ROOT_URLCONF = 'mysite.urls'

TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.contrib.auth.context_processors.auth',
'django.template.context_processors.i18n',
'django.template.context_processors.request',
'django.contrib.messages.context_processors.messages',
'zinnia.context_processors.version',
]
}
}
]

INSTALLED_APPS = (
'django.contrib.auth',
'django.contrib.sitemaps',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.sites',
'django.contrib.admin',
'django.contrib.admindocs',
'django.contrib.staticfiles',
'django_comments',
'django_xmlrpc',
'mptt',
'tagging',
'zinnia'
)

from zinnia.xmlrpc import ZINNIA_XMLRPC_METHODS
XMLRPC_METHODS = ZINNIA_XMLRPC_METHODS


urls.py looks like this.

"""Urls for the demo of Zinnia"""
from django.conf import settings
from django.contrib import admin
from django.conf.urls import url
from django.conf.urls import include

# from django.views.static import serve
from django.views.defaults import bad_request
from django.views.defaults import server_error
from django.views.defaults import page_not_found
from django.views.defaults import permission_denied
from django.views.generic.base import RedirectView
from django.contrib.sitemaps.views import index
from django.contrib.sitemaps.views import sitemap

from django_xmlrpc.views import handle_xmlrpc

from zinnia.sitemaps import TagSitemap
from zinnia.sitemaps import EntrySitemap
from zinnia.sitemaps import CategorySitemap
from zinnia.sitemaps import AuthorSitemap

urlpatterns = [
url(r'^$', RedirectView.as_view(url='/blog/', permanent=True)),
url(r'^blog/', include('zinnia.urls', namespace='zinnia')),
url(r'^comments/', include('django_comments.urls')),
url(r'^xmlrpc/$', handle_xmlrpc),
url(r'^i18n/', include('django.conf.urls.i18n')),
url(r'^admin/doc/', include('django.contrib.admindocs.urls')),
url(r'^admin/', include(admin.site.urls)),
]

sitemaps = {
'tags': TagSitemap,
'blog': EntrySitemap,
'authors': AuthorSitemap,
'categories': CategorySitemap
}

urlpatterns += [
url(r'^sitemap.xml$',
index,
{'sitemaps': sitemaps}),
url(r'^sitemap-(?P<section>.+)\.xml$',
sitemap,
{'sitemaps': sitemaps}),
]

urlpatterns += [
    url(r'^400/$', bad_request),
    url(r'^403/$', permission_denied),
    url(r'^404/$', page_not_found),
    url(r'^500/$', server_error),
]

if settings.DEBUG:
    urlpatterns += [
    url(r'^media/(?P<path>.*)$', serve,
    {'document_root': settings.MEDIA_ROOT})
    ]


 

7. Sync DB and Restart the uwsgi service and access the site.
Now you should build your website and webapps. Change urls according to your needs.

python manage.py migrate
systemctl restart emperor.uwsgi

Access http://127.0.0.1:8000/blog

 

8. Restrict access to admin page

Chrooting to Arch Linux ARM from Arch Linux

Yesterday, after updating my Arch Linux ARM on my raspberry pi 2, I could not no longer log in to the OS.
The culprit was libtirpc-1.0.1-2-armv7h.pkg.tar.xz. After downgrading it to libtirpc-0.3.2-2-armv7h.pkg.tar.xz, I could log in again.
However, to downgrade the package I had to chroot to my microsd card in which Arch Linux ARM is saved, from my Arch Linux.
Chrooting to a machine of different architecture required extra steps.
Here’s how I have done it.

1. Install qemu-user-static and binfmt-support from AUR
yaourt qemu-user-static
yaourt binfmt-support

2. Copy qemu-arm to the sdcard.
cp -p /usr/bin/qemu-arm-static /mnt/usr/bin/

3. Chroot!
chroot /mnt qemu-arm-static /bin/bash

4. Downgrade the package.
qemu-arm-static /usr/bin/pacman -U /var/cache/pacman/pkg/libtirpc-0.3.2-2-armv7h.pkg.tar.xz

Basic configuration by command on BIGIP 11

Big IP command notes. Some of the commands might be mistaken, you should check the configuration from GUI or show command after applying a command.

###### For resetting bigip config.

load sys config default

###### Disable dhcp on mgmt interface.

modify sys global-settings mgmt-dhcp disabled

###### Set IP address on management interface.

create sys management-ip 192.168.200.245/24

###### Set hostname

modify sys global-settings hostname bigip01.local

###### Set timezone

modify sys ntp timezone "Your location"

###### Specify a NTP server to synchronise to.

modify sys ntp servers add { 192.168.200.1 }

###### Set snmp trap

modify sys snmp traps add { MyCommunity { community MyCommunity port 162 version 2c host 192.168.200.1 } }

###### Set syslog

I forgot.

###### Create vlan interface.

create net vlan external interfaces add { 1.1 }

###### Assign IP address to a vlan interface.
###### Specify which protocol to allow at the same time (I am allowing big ip defualt protocols in the following)
###### Also specify with traffic group to participate.

create net self 10.0.0.1/24 allow-service default traffic-group traffic-group-local-only vlan external description external

###### Create a node which will be participated to pool
###### Also specify how to monitor the node.

create ltm node web-server01 address 192.168.0.1 monitor icmp

###### Create monitor profile for a pool

create ltm monitor http MyHttp send "GET /test.html HTTP/1.1\\r\\nHost: \\r\\nConnection: Close\\r\\n\\r\\n"

###### Create a pool and add a member
###### You can specify multiple members inside bracket separated by white space.
###### Also specify load-balancing method.
###### Also specify monitor profile

create ltm pool MyPool members add { web-server01:http } load-balancing-mode least-connections-member monitor MyHttp

###### Create a virtual server
###### Specify ip address or network range to listen for the virtual server.
# Specify a pool to load balance to.

create ltm virtual virtual-server01 destination 10.0.0.10:80 mask 255.255.255.255 ip-protocol tcp pool MyPool

###### Create cookie persistence profile

create ltm persistence cookie MyCookie cookie-name MyCookie expiration 30:00

###### Modify existing virtual server enable cookie persistence with the profile above.
modify ltm virtual virtual-server01 persist replace-all-with { cookie MyCookie }

###### If you encounter error saying that the virtual server must be associated with http profile.

modify ltm virtual vs01 persist replace-all-with { cookie MyCookie } profiles replace-all-with { tcp http }

###### Create a iRule

create ltm rule MyiRule

###### Associate the irule to the existing virtual server

modify ltm virtual virtual-server01 rules { MyiRule }

###### Create self signed ssl certificate and private key.
###### You have to get out of tmsh.

cd /root
openssl req -new -sha256 -newkey rsa:2048 -days 365 -nodes -x509 -keyout MySSL.key -out MySSL.crt

#### If you want to create csr and new private key. sha256 fingerprint

openssl req -new -sha256 -newkey rsa:2048 -nodes -keyout MySSL.key -out MySSL.csr

#### If you want to create csr from a existing private key.

openssl req -new -sha256 -key "YOUR KEY" -out MySSL.csr

###### Installing a SSL private key and a certificate from local volume.

install sys crypto key MySSL.key from-local-file /root/MySSL.key
install sys crypto cert MySSL.crt from-local-file /root/MySSL.crt

###### Create SSL profile (client side and insecure ssl such as self-signed cert allowed)

create ltm profile client-ssl MySSL key MySSL.key cert MySSL.crt defaults-from clientssl-insecure-compatible

###### Associate SSL profile with a existing virtual-server.
###### Note that virtual server service port must be set to https.

modify ltm virtual virtual-server01 profiles add { MySSL }

# Save config

save sys config

Windows 10 font on Arch

Japanese font for Linux is quite limited. It is always easier to just install windows font to have all the font needed to view websites pretty. Here is how to install windows font on Linux.
# Please note, that usage of Microsoft fonts outside running Windows
# system is prohibited by EULA (although in certain countries EULA is invalid).
# Please consult Microsoft license before using fonts.

1. Install following necessary packages for building
sudo pacman -S fontconfig xorg-fonts-encodings xorg-mkfontscale xorg-mkfontdir

2. Get the font from windows. In my case, I make a tar ball of C:\Windows\Fonts directory and send to Linux and untar by “tar xf Fonts.tar” command.

3. Run “ls -1 | grep -e ttf -e ttc” command in the font directory and copy the output.

2. Get ttf-ms-win10 tar.gz from AUR, and extract it and copy all font files to the extracted directory.

3. Edit PKGBUILD
i. Commend out _package() section’s second install command.

ii. Remeve all the font variables and pasted the previously copied clipboard.
_ttf_ms_win10=(
)

iii. Remove all functions excluding package_ttf-ms-win10() and _package()

iv. pkgname variable should be changed to the following.
pkgname=$pkgbase

4. Edited PKGBUILD looks like the following snippet .
pkgbase=ttf-ms-win10
pkgname=$pkgbase
pkgver=10.0.10240
pkgrel=3
arch=(any)
url='http://www.microsoft.com/typography/fonts/product.aspx?PID=164'
license=(custom)
depends=(fontconfig xorg-fonts-encodings xorg-mkfontscale xorg-mkfontdir)
provides=(ttf-font)
conflicts=(ttf-{vista,win7}-fonts)
install=$pkgbase.install

_ttf_ms_win10=(
arialbd.ttf
.
.
)

source=(${_ttf_ms_win10[@]/#/file://}

sha256sums=(…
)

_package() {
conflicts+=(${pkgname/10/8})

for font in $@; do
install -Dm644 $font -t “$pkgdir/usr/share/fonts/TTF”
done
}

package_ttf-ms-win10() {
pkgdesc=’Microsoft Windows 10 TrueType fonts’
provides+=(ttf-tahoma ttf-ms-fonts)
conflicts+=(ttf-tahoma ttf-ms-fonts)
_package ${_ttf_ms_win10[@]}
}

# vim: ts=4 sw=4 et

5. Leave .install file as it is.
post_install() {
fc-cache -s
mkfontscale usr/share/fonts/TTF
mkfontdir usr/share/fonts/TTF
}

post_upgrade() {
post_install
}

post_remove() {
post_install
}

5. Build the package by running the command below.
makepkg --skipinteg

6. Install the package.
sudo pacman -U *.pkg.tar.xz

7. Install infinality from aur (the both fontconfig and freetype)
and run fc-presets set and choose ms.

For blue-man haters

cat ../bin/btspeaker
#!/bin/bash

expect -c ”
spawn sudo bluetoothctl
expect #
send power\ on\ \n
expect Changing\ power\ on\ succeeded
expect #
send connect\ BLUETOOTH PHYSICAL ADDRESS\ \n
expect Connection\ successful
expect #
send quit\n
interact

exit

cat ../bin/disbtspeaker
#!/bin/bash

expect -c "
spawn sudo bluetoothctl
expect #
send power\ on\ \n
expect #
send disconnect\ MAC\ \n
expect #
send quit\n
interact
"

exit

Running Big IP virtual editon trial on KVM

Big IP for KVM only works for certain versions of KVM, and it won’t even lets you go into tmsh for other KVM version. Here is a workaround.
Since we can’t access to tmsh, you might won’t to add ip address to eth0 interface via “ip addr add “ipaddr/mask” dev eth0″ command, if you want to ssh to bigip.

First rewrite /bin/qp script which is executed on boot.
This just echoes platform infomation to /PLATFORM file.
The platform infomation is copied from BIG IP Virtual edition for vmware.

# vim /bin/qp

#!/bin/sh

echo "Z100"

if [ ! -f /PLATFORM ] ; then
echo "platform=Z99
family=0xC0000000
host=Z99
systype=0x76" > /PLATFORM
fi

Also rewrite the PLATFORM file directly. I am not sure this step is necessary.
Some of the guidance out there say it should be done, so I am just doing it just in case.

vim /PLATFORM

platform=Z99
family=0xC0000000
host=Z99
systype=0x76

And then, reboot. It should come up with no error.

my minimal zshrc and bashrc with completion

Install grml-zsh-config from repository, if you don’t want it minimal.

More minimal version is posted in the following link.
https://tech.wildduck.xyz/post/minimal-zshrc/

## Aliases
alias ls='ls --color=auto'
alias vi='vim'
alias ssh='TERM=xterm-256color ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null'

# Paths
export PATH=$PATH:~/bin

# Prompt
PROMPT=[%n@%m\ %c\]%(!.#.$)\

# History
HISTFILE=.zsh_history
HISTSIZE=1000
SAVEHIST=1000
setopt EXTENDED_HISTORY
setopt HIST_FIND_NO_DUPS
setopt INC_APPEND_HISTORY

# Keybind
# For the control code, open your terminal and press ctrl+v and press whatever key you want to assign.
# Keybind
bindkey '^[OC' forward-word
bindkey '^[Oc' forward-word
bindkey '^[[1;5C' forward-word
bindkey '^[OD' backward-word
bindkey '^[Od' backward-word
bindkey '^[[1;5D' backward-word
bindkey '^[[1~' beginning-of-line
bindkey '^[[7~' beginning-of-line
bindkey '^[OH' beginning-of-line
bindkey '\033[H' beginning-of-line
bindkey '^[[1;6D' beginning-of-line
bindkey '^[[8~' end-of-line
bindkey '^[[4~' end-of-line
bindkey '^[OF' end-of-line
bindkey '\033[F' end-of-line
bindkey '^[[1;6C' end-of-line
bindkey '^[[3~' delete-char

# Completion
autoload -Uz compinit
compinit
# Spelling correction
setopt correct
# Auto cd
setopt autocd

bashrc


# History
HISTTIMEFORMAT="%d/%m/%Y %T "

# Bash-completion options
shopt -s autocd
shopt -s cdspell
shopt -s extglob
shopt -s histappend
shopt -s lithist
shopt -s dotglob
shopt -s nocaseglob
shopt -s nocasematch

IPSEC over L2TP access from Arch Linux (With Strongswan and xl2tpd)

The setup will differ by the destination VPN server’s configuration.
It is much easier if you know the endpoint configuration. If you don’t,
you will have to capture packets on a client that is able to establish an
ipsec connection.
In my opinion, Windows implementation of IPSEC/L2TP client
is pretty thorough and also common, so it should be a good client to test.

In my case, I captured packets on Windows and got the server side’s setting of IKE
parameters of ISAKMP packets.

Here is my configuration.

1.
I had to add “send_vendor_id = yes” to “/etc/strongswan.conf” in order to
initiate Quicki mode( phase 2 ) communication.
Most of the IPSEC/L2TP implementation requires vendor ID to be sent…

charon {
load_modular = yes
send_vendor_id = yes
plugins {
include strongswan.d/charon/*.conf
}
}

2.
Next thing to set up is ipsec.conf.
I had to change ike and esp parameters according to
the packets from server which I got on Windows.
Make your “right” is IP address of VPN server(Global IP)
In my case IKE key exchange failed due to it.
ikelifetime may have to be changed, too.

There may be a way to set strongswan to accept
any encryption and hash methods. But I did not bother.

conn name will be used later, so name it cool.


config setup
charondebug=”ike 4, knl 4, cfg 2″

conn l2tp-psk
authby = secret
auto = add
keyexchange = ikev1
type = transport
left = %any
leftprotoport=17/1701
right = "VPN SERVER's IP ADDRESS. NOT A DOMAIN NAME!"
rightprotoport=17/1701
ike = aes256-sha1-modp2048
ikelifetime = 8h
esp = aes256-sha1-modp2048

3.
Next thing to set up is ipsec.secrets.
%any should be changed according to your needs.

%any %any : PSK "Presharekey-passphrase"

4.
Configure xl2tpd

/etc/xl2tpd/xl2tpd.conf
[lac l2tp-psk]
lns = "Same as "right" in ipsec.conf"
ppp debug = yes
pppoptfile = /etc/ppp/options.l2tpd
length bit = yes

/etc/ppp/options.l2tpd

ipcp-accept-local
ipcp-accept-remote
refuse-eap
require-mschap-v2
noccp
noauth
idle 1800
mtu 1410
mru 1410
defaultroute
usepeerdns
debug
lock
connect-delay 5000
name "Username"
password "user's password"

5.
Connect to the VPN Server

ipsec start
ipsec up l2tp-psk
systemctl start xl2tpd
echo "c l2tp-psk" > /var/run/xl2tpd/l2tp-control

Add routing and you are done!

Snapshot with BTRFS (On remote volume)

Run the bash script below.
Change the srcdir, dstdir, mt (mount point), old (for deleting 365 days older backups) variable to your preference.

#!/bin/bash

## Variable declaration
# date string for the subvolume name of a remote backup
datetime=`date +%d-%h-%Y_%H-%M`
# Local snapshot subvolume
srcdir="/snapshot"
# Remote snapshot subvolume
dstdir="/mnt/2tbhdd/Snapshot"

# Check if whether the destination Volume is mounted. If not, exit the script
if [ `df | grep -c 2tbhdd` -eq 0 ]; then
printf "backup destination is not mounted\n"
exit 1
fi

# Check if there is an original snapshot locally for creating an inceremental backup. If not, start the initial backup
if [ ! -d "$srcdir" ]; then
printf "Issuing an initial backup\n"
btrfs subvolume snapshot -r / ${srcdir}
printf "Copy snapshot to remote destinatioin"
btrfs send ${srcdir} | btrfs receive ${dstdir}
sync
fi

# Start incremental backup from the local snapshot subvolume
printf "Creating a local snapshot\n"
btrfs subvolume snapshot -r / ${srcdir}_${datetime}
sync
printf "Copying incremental snapshot to remote destination\n"
btrfs send -p ${srcdir} ${srcdir}_$datetime | btrfs receive ${dstdir}

# Replace the original subvolume with the snapshot newly created snapshot
printf "Replace the original subvolume with the snapshot newly created snapshot\n"
btrfs subvolume delete ${srcdir}
printf "Renaming the subvolume"
mv ${srcdir}_$datetime ${srcdir}

# Delete snapshots older than a year on remote volume.
old=`find ${dstdir} -maxdepth 1 -mtime +365`
if [ -z "$old" ]; then
printf "no older backups\n"
else
printf "Deleting snapshot more than one year old."
find ${dstdir} -maxdepth 1 -mtime +365 -exec btrfs subvolume delete {} \;
fi