Background: #fff
Foreground: #000
PrimaryPale: #8cf
PrimaryLight: #18f
PrimaryMid: #04b
PrimaryDark: #014
SecondaryPale: #ffc
SecondaryLight: #fe8
SecondaryMid: #db4
SecondaryDark: #841
TertiaryPale: #eee
TertiaryLight: #ccc
TertiaryMid: #999
TertiaryDark: #666
Error: #f88
/*{{{*/
body {background:[[ColorPalette::Background]]; color:[[ColorPalette::Foreground]];}

a {color:[[ColorPalette::PrimaryMid]];}
a:hover {background-color:[[ColorPalette::PrimaryMid]]; color:[[ColorPalette::Background]];}
a img {border:0;}

h1,h2,h3,h4,h5,h6 {color:[[ColorPalette::SecondaryDark]]; background:transparent;}
h1 {border-bottom:2px solid [[ColorPalette::TertiaryLight]];}
h2,h3 {border-bottom:1px solid [[ColorPalette::TertiaryLight]];}

.button {color:[[ColorPalette::PrimaryDark]]; border:1px solid [[ColorPalette::Background]];}
.button:hover {color:[[ColorPalette::PrimaryDark]]; background:[[ColorPalette::SecondaryLight]]; border-color:[[ColorPalette::SecondaryMid]];}
.button:active {color:[[ColorPalette::Background]]; background:[[ColorPalette::SecondaryMid]]; border:1px solid [[ColorPalette::SecondaryDark]];}

.header {background:[[ColorPalette::PrimaryMid]];}
.headerShadow {color:[[ColorPalette::Foreground]];}
.headerShadow a {font-weight:normal; color:[[ColorPalette::Foreground]];}
.headerForeground {color:[[ColorPalette::Background]];}
.headerForeground a {font-weight:normal; color:[[ColorPalette::PrimaryPale]];}

.tabSelected{color:[[ColorPalette::PrimaryDark]];
	background:[[ColorPalette::TertiaryPale]];
	border-left:1px solid [[ColorPalette::TertiaryLight]];
	border-top:1px solid [[ColorPalette::TertiaryLight]];
	border-right:1px solid [[ColorPalette::TertiaryLight]];
}
.tabUnselected {color:[[ColorPalette::Background]]; background:[[ColorPalette::TertiaryMid]];}
.tabContents {color:[[ColorPalette::PrimaryDark]]; background:[[ColorPalette::TertiaryPale]]; border:1px solid [[ColorPalette::TertiaryLight]];}
.tabContents .button {border:0;}

#sidebar {}
#sidebarOptions input {border:1px solid [[ColorPalette::PrimaryMid]];}
#sidebarOptions .sliderPanel {background:[[ColorPalette::PrimaryPale]];}
#sidebarOptions .sliderPanel a {border:none;color:[[ColorPalette::PrimaryMid]];}
#sidebarOptions .sliderPanel a:hover {color:[[ColorPalette::Background]]; background:[[ColorPalette::PrimaryMid]];}
#sidebarOptions .sliderPanel a:active {color:[[ColorPalette::PrimaryMid]]; background:[[ColorPalette::Background]];}

.wizard {background:[[ColorPalette::PrimaryPale]]; border:1px solid [[ColorPalette::PrimaryMid]];}
.wizard h1 {color:[[ColorPalette::PrimaryDark]]; border:none;}
.wizard h2 {color:[[ColorPalette::Foreground]]; border:none;}
.wizardStep {background:[[ColorPalette::Background]]; color:[[ColorPalette::Foreground]];
	border:1px solid [[ColorPalette::PrimaryMid]];}
.wizardStep.wizardStepDone {background::[[ColorPalette::TertiaryLight]];}
.wizardFooter {background:[[ColorPalette::PrimaryPale]];}
.wizardFooter .status {background:[[ColorPalette::PrimaryDark]]; color:[[ColorPalette::Background]];}
.wizard .button {color:[[ColorPalette::Foreground]]; background:[[ColorPalette::SecondaryLight]]; border: 1px solid;
	border-color:[[ColorPalette::SecondaryPale]] [[ColorPalette::SecondaryDark]] [[ColorPalette::SecondaryDark]] [[ColorPalette::SecondaryPale]];}
.wizard .button:hover {color:[[ColorPalette::Foreground]]; background:[[ColorPalette::Background]];}
.wizard .button:active {color:[[ColorPalette::Background]]; background:[[ColorPalette::Foreground]]; border: 1px solid;
	border-color:[[ColorPalette::PrimaryDark]] [[ColorPalette::PrimaryPale]] [[ColorPalette::PrimaryPale]] [[ColorPalette::PrimaryDark]];}

#messageArea {border:1px solid [[ColorPalette::SecondaryMid]]; background:[[ColorPalette::SecondaryLight]]; color:[[ColorPalette::Foreground]];}
#messageArea .button {color:[[ColorPalette::PrimaryMid]]; background:[[ColorPalette::SecondaryPale]]; border:none;}

.tiddlerPopupButton {color:[[ColorPalette::Foreground]]; background:[[ColorPalette::PrimaryPale]]; border: 1px solid [[ColorPalette::PrimaryLight]];}
.tiddlerPopupButton:hover {color:[[ColorPalette::Background]]; background:[[ColorPalette::PrimaryMid]];}
.tiddlerPopupButton:active {color:[[ColorPalette::Background]]; background:[[ColorPalette::Foreground]];}
.tiddlerPopupButton.highlight {color:[[ColorPalette::Foreground]]; background:[[ColorPalette::Background]];}
.popupTiddler {background:[[ColorPalette::TertiaryPale]]; border:2px solid [[ColorPalette::TertiaryMid]];}

.popup {background:[[ColorPalette::TertiaryPale]]; color:[[ColorPalette::TertiaryDark]]; border-left:1px solid [[ColorPalette::TertiaryMid]]; border-top:1px solid [[ColorPalette::TertiaryMid]]; border-right:2px solid [[ColorPalette::TertiaryDark]]; border-bottom:2px solid [[ColorPalette::TertiaryDark]];}
.popup hr {color:[[ColorPalette::PrimaryDark]]; background:[[ColorPalette::PrimaryDark]]; border-bottom:1px;}
.popup li.disabled {color:[[ColorPalette::TertiaryMid]];}
.popup li a, .popup li a:visited {color:[[ColorPalette::Foreground]]; border: none;}
.popup li a:hover {background:[[ColorPalette::SecondaryLight]]; color:[[ColorPalette::Foreground]]; border: none;}
.popup li a:active {background:[[ColorPalette::SecondaryPale]]; color:[[ColorPalette::Foreground]]; border: none;}
.popupHighlight {background:[[ColorPalette::Background]]; color:[[ColorPalette::Foreground]];}
.listBreak div {border-bottom:1px solid [[ColorPalette::TertiaryDark]];}

.tiddler .defaultCommand {font-weight:bold;}

.shadow .title {color:[[ColorPalette::TertiaryDark]];}

.title {color:[[ColorPalette::SecondaryDark]];}
.subtitle {color:[[ColorPalette::TertiaryDark]];}

.toolbar {color:[[ColorPalette::PrimaryMid]];}
.toolbar a {color:[[ColorPalette::TertiaryLight]];}
.selected .toolbar a {color:[[ColorPalette::TertiaryMid]];}
.selected .toolbar a:hover {color:[[ColorPalette::Foreground]];}

.tagging, .tagged {border:1px solid [[ColorPalette::TertiaryPale]]; background-color:[[ColorPalette::TertiaryPale]];}
.selected .tagging, .selected .tagged {background-color:[[ColorPalette::TertiaryLight]]; border:1px solid [[ColorPalette::TertiaryMid]];}
.tagging .listTitle, .tagged .listTitle {color:[[ColorPalette::PrimaryDark]];}
.tagging .button, .tagged .button {border:none;}

.footer {color:[[ColorPalette::TertiaryLight]];}
.selected .footer {color:[[ColorPalette::TertiaryMid]];}

.sparkline {background:[[ColorPalette::PrimaryPale]]; border:0;}
.sparktick {background:[[ColorPalette::PrimaryDark]];}

.error, .errorButton {color:[[ColorPalette::Foreground]]; background:[[ColorPalette::Error]];}
.warning {color:[[ColorPalette::Foreground]]; background:[[ColorPalette::SecondaryPale]];}
.lowlight {background:[[ColorPalette::TertiaryLight]];}

.zoomer {background:none; color:[[ColorPalette::TertiaryMid]]; border:3px solid [[ColorPalette::TertiaryMid]];}

.imageLink, #displayArea .imageLink {background:transparent;}

.annotation {background:[[ColorPalette::SecondaryLight]]; color:[[ColorPalette::Foreground]]; border:2px solid [[ColorPalette::SecondaryMid]];}

.viewer .listTitle {list-style-type:none; margin-left:-2em;}
.viewer .button {border:1px solid [[ColorPalette::SecondaryMid]];}
.viewer blockquote {border-left:3px solid [[ColorPalette::TertiaryDark]];}

table {border:2px solid [[ColorPalette::TertiaryDark]];}
th, thead td {background:[[ColorPalette::SecondaryMid]]; border:1px solid [[ColorPalette::TertiaryDark]]; color:[[ColorPalette::Background]];}
td, tr {border:1px solid [[ColorPalette::TertiaryDark]];}

.viewer pre {border:1px solid [[ColorPalette::SecondaryLight]]; background:[[ColorPalette::SecondaryPale]];}
.viewer code {color:[[ColorPalette::SecondaryDark]];}
.viewer hr {border:0; border-top:dashed 1px [[ColorPalette::TertiaryDark]]; color:[[ColorPalette::TertiaryDark]];}

.highlight, .marked {background:[[ColorPalette::SecondaryLight]];}

.editor input {border:1px solid [[ColorPalette::PrimaryMid]];}
.editor textarea {border:1px solid [[ColorPalette::PrimaryMid]]; width:100%;}
.editorFooter {color:[[ColorPalette::TertiaryMid]];}

#backstageArea {background:[[ColorPalette::Foreground]]; color:[[ColorPalette::TertiaryMid]];}
#backstageArea a {background:[[ColorPalette::Foreground]]; color:[[ColorPalette::Background]]; border:none;}
#backstageArea a:hover {background:[[ColorPalette::SecondaryLight]]; color:[[ColorPalette::Foreground]]; }
#backstageArea a.backstageSelTab {background:[[ColorPalette::Background]]; color:[[ColorPalette::Foreground]];}
#backstageButton a {background:none; color:[[ColorPalette::Background]]; border:none;}
#backstageButton a:hover {background:[[ColorPalette::Foreground]]; color:[[ColorPalette::Background]]; border:none;}
#backstagePanel {background:[[ColorPalette::Background]]; border-color: [[ColorPalette::Background]] [[ColorPalette::TertiaryDark]] [[ColorPalette::TertiaryDark]] [[ColorPalette::TertiaryDark]];}
.backstagePanelFooter .button {border:none; color:[[ColorPalette::Background]];}
.backstagePanelFooter .button:hover {color:[[ColorPalette::Foreground]];}
#backstageCloak {background:[[ColorPalette::Foreground]]; opacity:0.6; filter:'alpha(opacity:60)';}
/*}}}*/
/*{{{*/
* html .tiddler {height:1%;}

body {font-size:.75em; font-family:arial,helvetica; margin:0; padding:0;}

h1,h2,h3,h4,h5,h6 {font-weight:bold; text-decoration:none;}
h1,h2,h3 {padding-bottom:1px; margin-top:1.2em;margin-bottom:0.3em;}
h4,h5,h6 {margin-top:1em;}
h1 {font-size:1.35em;}
h2 {font-size:1.25em;}
h3 {font-size:1.1em;}
h4 {font-size:1em;}
h5 {font-size:.9em;}

hr {height:1px;}

a {text-decoration:none;}

dt {font-weight:bold;}

ol {list-style-type:decimal;}
ol ol {list-style-type:lower-alpha;}
ol ol ol {list-style-type:lower-roman;}
ol ol ol ol {list-style-type:decimal;}
ol ol ol ol ol {list-style-type:lower-alpha;}
ol ol ol ol ol ol {list-style-type:lower-roman;}
ol ol ol ol ol ol ol {list-style-type:decimal;}

.txtOptionInput {width:11em;}

#contentWrapper .chkOptionInput {border:0;}

.externalLink {text-decoration:underline;}

.indent {margin-left:3em;}
.outdent {margin-left:3em; text-indent:-3em;}
code.escaped {white-space:nowrap;}

.tiddlyLinkExisting {font-weight:bold;}
.tiddlyLinkNonExisting {font-style:italic;}

/* the 'a' is required for IE, otherwise it renders the whole tiddler in bold */
a.tiddlyLinkNonExisting.shadow {font-weight:bold;}

#mainMenu .tiddlyLinkExisting,
	#mainMenu .tiddlyLinkNonExisting,
	#sidebarTabs .tiddlyLinkNonExisting {font-weight:normal; font-style:normal;}
#sidebarTabs .tiddlyLinkExisting {font-weight:bold; font-style:normal;}

.header {position:relative;}
.header a:hover {background:transparent;}
.headerShadow {position:relative; padding:4.5em 0em 1em 1em; left:-1px; top:-1px;}
.headerForeground {position:absolute; padding:4.5em 0em 1em 1em; left:0px; top:0px;}

.siteTitle {font-size:3em;}
.siteSubtitle {font-size:1.2em;}

#mainMenu {position:absolute; left:0; width:10em; text-align:right; line-height:1.6em; padding:1.5em 0.5em 0.5em 0.5em; font-size:1.1em;}

#sidebar {position:absolute; right:3px; width:16em; font-size:.9em;}
#sidebarOptions {padding-top:0.3em;}
#sidebarOptions a {margin:0em 0.2em; padding:0.2em 0.3em; display:block;}
#sidebarOptions input {margin:0.4em 0.5em;}
#sidebarOptions .sliderPanel {margin-left:1em; padding:0.5em; font-size:.85em;}
#sidebarOptions .sliderPanel a {font-weight:bold; display:inline; padding:0;}
#sidebarOptions .sliderPanel input {margin:0 0 .3em 0;}
#sidebarTabs .tabContents {width:15em; overflow:hidden;}

.wizard {padding:0.1em 1em 0em 2em;}
.wizard h1 {font-size:2em; font-weight:bold; background:none; padding:0em 0em 0em 0em; margin:0.4em 0em 0.2em 0em;}
.wizard h2 {font-size:1.2em; font-weight:bold; background:none; padding:0em 0em 0em 0em; margin:0.4em 0em 0.2em 0em;}
.wizardStep {padding:1em 1em 1em 1em;}
.wizard .button {margin:0.5em 0em 0em 0em; font-size:1.2em;}
.wizardFooter {padding:0.8em 0.4em 0.8em 0em;}
.wizardFooter .status {padding:0em 0.4em 0em 0.4em; margin-left:1em;}
.wizard .button {padding:0.1em 0.2em 0.1em 0.2em;}

#messageArea {position:absolute; top:2em; right:0em; margin:0.5em; padding:0.5em; z-index:200;}
*[id='messageArea'] {position:fixed !important; z-index:200;}
.messageToolbar {display:block; text-align:right; padding:0.2em 0.2em 0.2em 0.2em;}
#messageArea a {text-decoration:underline;}

.tiddlerPopupButton {padding:0.2em 0.2em 0.2em 0.2em;}
.popupTiddler {position: absolute; z-index:300; padding:1em 1em 1em 1em; margin:0;}

.popup {position:absolute; z-index:300; font-size:.9em; padding:0; list-style:none; margin:0;}
.popup .popupMessage {padding:0.4em;}
.popup hr {display:block; height:1px; width:auto; padding:0; margin:0.2em 0em;}
.popup li.disabled {padding:0.4em;}
.popup li a {display:block; padding:0.4em; font-weight:normal; cursor:pointer;}
.listBreak {font-size:1px; line-height:1px;}
.listBreak div {margin:2px 0;}

.tabset {padding:1em 0em 0em 0.5em;}
.tab {margin:0em 0em 0em 0.25em; padding:2px;}
.tabContents {padding:0.5em;}
.tabContents ul, .tabContents ol {margin:0; padding:0;}
.txtMainTab .tabContents li {list-style:none;}
.tabContents li.listLink { margin-left:.75em;}

#contentWrapper {display:block;}
#splashScreen {display:none;}

#displayArea {margin:1em 17em 0em 14em;}

.toolbar {text-align:right; font-size:.9em;}

.tiddler {padding:1em 1em 0em 1em;}

.missing .viewer,.missing .title {font-style:italic;}

.title {font-size:1.6em; font-weight:bold;}

.missing .subtitle {display:none;}
.subtitle {font-size:1.1em;}

.tiddler .button {padding:0.2em 0.4em;}

.tagging {margin:0.5em 0.5em 0.5em 0; float:left; display:none;}
.isTag .tagging {display:block;}
.tagged {margin:0.5em; float:right;}
.tagging, .tagged {font-size:0.9em; padding:0.25em;}
.tagging ul, .tagged ul {list-style:none; margin:0.25em; padding:0;}
.tagClear {clear:both;}

.footer {font-size:.9em;}
.footer li {display:inline;}

.annotation {padding:0.5em; margin:0.5em;}

* html .viewer pre {width:99%; padding:0 0 1em 0;}
.viewer {line-height:1.4em; padding-top:0.5em;}
.viewer .button {margin:0em 0.25em; padding:0em 0.25em;}
.viewer blockquote {line-height:1.5em; padding-left:0.8em;margin-left:2.5em;}
.viewer ul, .viewer ol {margin-left:0.5em; padding-left:1.5em;}

table {border-collapse:collapse; margin:0.8em 1.0em;}
.viewer th, .viewer td, .viewer tr,.viewer caption {padding:3px;}
table.listView {font-size:0.85em; margin:0.8em 1.0em;}
table.listView th, table.listView td, table.listView tr {padding:0px 3px 0px 3px;}

.viewer pre {padding:0.5em; margin-left:0.5em; font-size:1.2em; line-height:1.4em; overflow:auto;}
.viewer code {font-size:1.2em; line-height:1.4em;}

.editor {font-size:1.1em;}
.editor input, .editor textarea {display:block; width:100%; font:inherit;}
.editorFooter {padding:0.25em 0em; font-size:.9em;}
.editorFooter .button {padding-top:0px; padding-bottom:0px;}

.fieldsetFix {border:0; padding:0; margin:1px 0px 1px 0px;}

.sparkline {line-height:1em;}
.sparktick {outline:0;}

.zoomer {font-size:1.1em; position:absolute; overflow:hidden;}
.zoomer div {padding:1em;}

* html #backstage {width:99%;}
* html #backstageArea {width:99%;}
#backstageArea {display:none; position:relative; overflow: hidden; z-index:150; padding:0.3em 0.5em 0.3em 0.5em;}
#backstageToolbar {position:relative;}
#backstageArea a {font-weight:bold; margin-left:0.5em; padding:0.3em 0.5em 0.3em 0.5em;}
#backstageButton {display:none; position:absolute; z-index:175; top:0em; right:0em;}
#backstageButton a {padding:0.1em 0.4em 0.1em 0.4em; margin:0.1em 0.1em 0.1em 0.1em;}
#backstage {position:relative; width:100%; z-index:50;}
#backstagePanel {display:none; z-index:100; position:absolute; margin:0em 3em 0em 3em; padding:1em 1em 1em 1em;}
.backstagePanelFooter {padding-top:0.2em; float:right;}
.backstagePanelFooter a {padding:0.2em 0.4em 0.2em 0.4em;}
#backstageCloak {display:none; z-index:50; position:absolute; width:100%; height:100px;}

.whenBackstage {display:none;}
.backstageVisible .whenBackstage {display:block;}
/*}}}*/
/***
StyleSheet for use when a translation requires any css style changes.
This StyleSheet can be used directly by languages such as Chinese, Japanese and Korean which use a logographic writing system and need larger font sizes.
***/

/*{{{*/
body {font-size:0.8em;}

#sidebarOptions {font-size:1.05em;}
#sidebarOptions a {font-style:normal;}
#sidebarOptions .sliderPanel {font-size:0.95em;}

.subtitle {font-size:0.8em;}

.viewer table.listView {font-size:0.95em;}

.htmlarea .toolbarHA table {border:1px solid ButtonFace; margin:0em 0em;}
/*}}}*/
/*{{{*/
@media print {
#mainMenu, #sidebar, #messageArea, .toolbar {display: none ! important;}
#displayArea {margin: 1em 1em 0em 1em;}
/* Fixes a feature in Firefox 1.5.0.2 where print preview displays the noscript content */
noscript {display:none;}
}
/*}}}*/
<!--{{{-->
<div class='header' macro='gradient vert [[ColorPalette::PrimaryLight]] [[ColorPalette::PrimaryMid]]'>
<div class='headerShadow'>
<span class='siteTitle' refresh='content' tiddler='SiteTitle'></span>&nbsp;
<span class='siteSubtitle' refresh='content' tiddler='SiteSubtitle'></span>
</div>
<div class='headerForeground'>
<span class='siteTitle' refresh='content' tiddler='SiteTitle'></span>&nbsp;
<span class='siteSubtitle' refresh='content' tiddler='SiteSubtitle'></span>
</div>
</div>
<div id='mainMenu' refresh='content' tiddler='MainMenu'></div>
<div id='sidebar'>
<div id='sidebarOptions' refresh='content' tiddler='SideBarOptions'></div>
<div id='sidebarTabs' refresh='content' force='true' tiddler='SideBarTabs'></div>
</div>
<div id='displayArea'>
<div id='messageArea'></div>
<div id='storyDisplay'></div>
</div>
<!--}}}-->
<!--{{{-->
<div class='toolbar' macro='toolbar closeTiddler closeOthers +editTiddler > fields syncing permalink references jump'></div>
<div class='title' macro='view title'></div>
<div class='subtitle'><span macro='view modifier link'></span>, <span macro='view modified date'></span> (<span macro='message views.wikified.createdPrompt'></span> <span macro='view created date'></span>)</div>
<div class='tagging' macro='tagging'></div>
<div class='tagged' macro='tags'></div>
<div class='viewer' macro='view text wikified'></div>
<div class='tagClear'></div>
<!--}}}-->
<!--{{{-->
<div class='toolbar' macro='toolbar +saveTiddler -cancelTiddler deleteTiddler'></div>
<div class='title' macro='view title'></div>
<div class='editor' macro='edit title'></div>
<div macro='annotations'></div>
<div class='editor' macro='edit text'></div>
<div class='editor' macro='edit tags'></div><div class='editorFooter'><span macro='message views.editor.tagPrompt'></span><span macro='tagChooser'></span></div>
<!--}}}-->
To get started with this blank TiddlyWiki, you'll need to modify the following tiddlers:
* SiteTitle & SiteSubtitle: The title and subtitle of the site, as shown above (after saving, they will also appear in the browser title bar)
* MainMenu: The menu (usually on the left)
* DefaultTiddlers: Contains the names of the tiddlers that you want to appear when the TiddlyWiki is opened
You'll also need to enter your username for signing your edits: <<option txtUserName>>
These InterfaceOptions for customising TiddlyWiki are saved in your browser

Your username for signing your edits. Write it as a WikiWord (eg JoeBloggs)

<<option txtUserName>>
<<option chkSaveBackups>> SaveBackups
<<option chkAutoSave>> AutoSave
<<option chkRegExpSearch>> RegExpSearch
<<option chkCaseSensitiveSearch>> CaseSensitiveSearch
<<option chkAnimate>> EnableAnimations

----
Also see AdvancedOptions
* ''Apache appliance on a laptop inside a LAN''
** Proppy wants to run a new online service available to the general public.
** Proppy creates a vlan on his GNU/Linux laptop and name it eth0.2.
** The eth0.2 interface is assigned a permanent private IP address range of 192.168.50.0/24.
**  Proppy adds shorewall rules to NAT all outgoing packets from eth0.2 and route them to eth0 or eth1 (the wifi interface).
** The 37000:38000 port range is abitrarily DNAT to eth0.2.
** Proppy creates a new Debian etch based vserver with address 192.168.50.10 on eth0.2 and names it VOD.
** Apache2 is installed in VOD and bound to 37080 in addtion to the 80 port.
** The laptop is run from inside a ~NATed LAN and and has a fixed DHCP allocated fixed IP based on his MAC address.
** Proppy adds a rule to the firewall ~NATing the LAN so that ports 37000:38000 are redirected to the laptop fixed IP.
* Request for inclusion in debian package http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=425008;repeatmerged=no

* One liner that will work on a newly installed apache2 from Debian GNU/Linux etch
{{{
apt-get install patch
cd / ; wget -O - http://hg.nagios.fsffrance.org/raw-rev/22ed4d555572 | patch -p1 
hg commit -m 'Apache x-forwarded-for log when behind a proxy' /etc/apache2
/etc/init.d/apache2 reload
}}}
* Emacs macro
{{{
; C-x e on the CustomLog line
(setq last-kbd-macro "\C-k\C-k\C-y\C-y\C-p\C-p\C-e env=!from_proxy\C-n_forwarded env=from_proxy")
}}}
* Complete patch
{{{
cd /
patch -p1 <<'EOF'
--- a/etc/apache2/apache2.conf	Thu May 03 23:57:15 2007 +0200
+++ b/etc/apache2/apache2.conf	Thu May 03 23:59:07 2007 +0200
@@ -199,9 +199,12 @@ Include /etc/apache2/conf.d/
 # a CustomLog directive (see below).
 #
 LogFormat "%h %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined
+LogFormat "%{X-Forwarded-For}i %l %u %t \"%r\" %>s %b \"%{Referer}i\" \"%{User-Agent}i\"" combined_forwarded
 LogFormat "%h %l %u %t \"%r\" %>s %b" common
 LogFormat "%{Referer}i -> %U" referer
 LogFormat "%{User-agent}i" agent
+
+SetEnvIfNoCase X-Forwarded-For "." from_proxy=1
 
 #
 # ServerTokens
--- a/etc/apache2/sites-available/default	Thu May 03 23:57:15 2007 +0200
+++ b/etc/apache2/sites-available/default	Thu May 03 23:59:07 2007 +0200
@@ -34,7 +34,8 @@ NameVirtualHost *
 	# alert, emerg.
 	LogLevel warn
 
-	CustomLog /var/log/apache2/access.log combined
+	CustomLog /var/log/apache2/access.log combined env=!from_proxy
+	CustomLog /var/log/apache2/access.log combined_forwarded env=from_proxy
 	ServerSignature On
 
EOF
}}}
{{{
diff -r 36c2ae3235c9ea8a3d640b6dba5811ed6a54f9f0 -r b03e45844f4ee52e777288dad5c2cf3a361f92bd bind/db.aminche.com
--- a/bind/db.aminche.com	Mon Apr 02 00:16:32 2007 +0200
+++ b/bind/db.aminche.com	Thu May 17 21:32:08 2007 +0200
@@ -1,6 +1,6 @@
 $ttl 3d
 @       IN      SOA     ns.aminche.com. hostmaster.aminche.com. (
-                        2007040102      ; serial, todays date + todays serial #
+                        2007041602      ; serial, todays date + todays serial #
                         28800           ; refresh, seconds
                         7200            ; retry, seconds
                         604800          ; expire, seconds
@@ -28,4 +28,5 @@ muzine		IN	A 88.191.13.165
 muzine		IN	A 88.191.13.165
 hg		IN	A 88.191.13.165
 zanna		IN	A 88.191.13.165
+*.aminche.com.	IN	A 88.191.13.165
 aminche.com.	IN	A 88.191.13.165

}}}
** Proppy boots the real machine using a live CD
** Proppy installs and run the ssh daemon
** The ssh daemon allows root access and the password is set
** The hard disk is explored using fdisk
** Proppy mounts the file systems in /mnt as if it was / (for instance /dev/sda2 on /mnt and /dev/sda3 on /mnt/home)
** From the vserver host, proppy copies all the files (could also be done using the rsync vserver build method but it would not cross the file system boundaries because of the -x option and would therefore miss files)
{{{
rsync -avH --numeric-ids root@mekensleep.com:/mnt/ /var/lib/vservers/newmachine/
}}}
* The named.conf file //must// include views only. That's the only tricky bit : the top level configuration file may not contain any stanza. When views are used, all must be views. Note that match-clients is on the same line as {{{view}}} so that scripts can easily manipulate it.
{{{
include "/etc/bind/named.conf.options";

view "pokersource.info" { match-clients { 192.168.50.10; };
  zone "conf.tld" {
    type master;
    file "/etc/bind/pokersource.info.view";
  };
  include "/etc/bind/named.conf.zones";
  include "/etc/bind/named.conf.common";
};

view "default" {
  include "/etc/bind/named.conf.zones";
  include "/etc/bind/named.conf.common";
};

include "/etc/bind/named.conf.local";

}}}

* The //named.conf.common// that's included in each view holds what you'd like to include outside the views if bind9 allowed this. It's typically what you find in a named.conf bind9 file when not using views:

{{{
// prime the server with knowledge of the root servers
zone "." {
	type hint;
	file "/etc/bind/db.root";
};

// be authoritative for the localhost forward and reverse zones, and for
// broadcast zones as per RFC 1912

zone "localhost" {
	type master;
	file "/etc/bind/db.local";
};

zone "127.in-addr.arpa" {
	type master;
	file "/etc/bind/db.127";
};

zone "0.in-addr.arpa" {
	type master;
	file "/etc/bind/db.0";
};

zone "255.in-addr.arpa" {
	type master;
	file "/etc/bind/db.255";
};
}}}

* The {{{/etc/bind/named.conf.zones}}} file included in the {{{/etc/bind/named.conf}}} contains the list of supported zones (master, slave and forwarded). Forwarded zones are used to make sure DNS requests for domains under your control refer only to the master server, to [[avoid propagation delays|avoid DNS delays]]. 
{{{
zone "my" {
	type master;
	file "/etc/bind/db.my";
};

zone "pokersource.info."{
   type forward ;
   forward only ;
   forwarders {
       88.191.250.41 ;
   } ;
};
}}}
In the above file, the //my// zone is used to define the .my top level domain that points to the IP of the appliances running on the local machine and unknown to the outside world.
[[Summary]]
[[Rationale]]
[[Use Cases]]
[[Scope]]
[[Design]]
[[Implementation]]
[[Unresolved Issues]]
/***
StyleSheet for use when a translation requires any css style changes.
This StyleSheet can be used directly by languages such as Chinese, Japanese and Korean which use a logographic writing system and need larger font sizes.
***/

/*{{{*/
body {font-size:0.8em;}

#sidebarOptions {font-size:1.05em;}
#sidebarOptions a {font-style:normal;}
#sidebarOptions .sliderPanel {font-size:0.95em;}

.subtitle {font-size:0.8em;}

.viewer table.listView {font-size:0.95em;}

.htmlarea .toolbarHA table {border:1px solid ButtonFace; margin:0em 0em;}
/*}}}*/
<!--{{{-->
<div class='header' macro='gradient vert [[ColorPalette::PrimaryLight]] [[ColorPalette::PrimaryMid]]'>
<div class='headerShadow'>
<span class='siteTitle' refresh='content' tiddler='SiteTitle'></span>&nbsp;
<span class='siteSubtitle' refresh='content' tiddler='SiteSubtitle'></span>
</div>
<div class='headerForeground'>
<span class='siteTitle' refresh='content' tiddler='SiteTitle'></span>&nbsp;
<span class='siteSubtitle' refresh='content' tiddler='SiteSubtitle'></span>
</div>
</div>
<div id='mainMenu' refresh='content' tiddler='MainMenu'></div>
<div id='sidebar'>
<div id='sidebarOptions' refresh='content' tiddler='SideBarOptions'></div>
<div id='sidebarTabs' refresh='content' force='true' tiddler='SideBarTabs'></div>
</div>
<div id='displayArea'>
<div id='messageArea'></div>
<div id='storyDisplay'></div>
</div>
<!--}}}-->
/***
|''Name:''|GenerateRssHijack|
|''Description:''|Generate an RSSFeed with plaintext, html and TiddlyWiki content|
|''Version:''|0.1.4|
|''Date:''|Oct 23, 2006|
|''Source:''|http://tiddlywiki.bidix.info/#GenerateRssHijack|
|''Documentation:''|http://tiddlywiki.bidix.info/#GenerateRssHijackDoc|
|''Author:''|BidiX (BidiX (at) bidix (dot) info)|
|''License:''|[[BSD open source license|http://tiddlywiki.bidix.info/#%5B%5BBSD%20open%20source%20license%5D%5D ]]|
|''~CoreVersion:''|2.0.0|
|''Browser:''|Firefox 1.5; InternetExplorer 6.0; Safari|
|''Include:''|none|
|''Require:''|none|
***/
//{{{
version.extensions.GenerateRssHijack= {
	major: 0, minor: 1, revision: 3, 
	date: new Date(2006,9,29),
	source: 'http://tiddlywiki.bidix.info/#GenerateRssHijack',
	documentation: 'http://tiddlywiki.bidix.info/#GenerateRssHijackDoc',
	author: 'BidiX (BidiX (at) bidix (dot) info',
	license: '[[BSD open source license|http://tiddlywiki.bidix.info/#%5B%5BBSD%20open%20source%20license%5D%5D]]',
	coreVersion: '2.0.0',
	browser: 'Firefox 1.5; InternetExplorer 6.0; Safari'	
};

// Return the tiddlers as a sorted array
TiddlyWiki.prototype.getTiddlersTaggedWith = function(field,includeTag)
{
	var results = [];
	this.forEachTiddler(function(title,tiddler) {
		if(tiddler.tags.find(includeTag) != null)
			results.push(tiddler);
		});
	if(field)
		results.sort(function (a,b) {if(a[field] == b[field]) return(0); else return (a[field] < b[field]) ? -1 : +1; });
	return results;
}

// generate RSS file with tiddlers tagged with toRSS
window.generateRss_ori = window.generateRss;
window.generateRss = function ()
{
	var s = [];
	var d = new Date();
	var u = store.getTiddlerText("SiteUrl",null);
	// Assemble the header 
	s.push("<" + "?xml version=\"1.0\"" + " encoding='UTF-8'" + "?>");
	s.push("<rss version=\"2.0\" xmlns:tiddlywiki=\"http://tiddlywiki.bidix.info/#TiddlyWikiNamespace\" xmlns:content=\"http://purl.org/rss/1.0/modules/content/\">");
	s.push("<channel>");
	s.push("<title>" + wikifyPlain("SiteTitle").htmlEncode() + "</title>");
	if(u)
		s.push("<link>" + u.htmlEncode() + "</link>");
	s.push("<description>" + wikifyPlain("SiteSubtitle").htmlEncode() + "</description>");
	s.push("<language>en-us</language>");
	s.push("<copyright>Copyright " + d.getFullYear() + " " + config.options.txtUserName.htmlEncode() + "</copyright>");
	s.push("<pubDate>" + d.toGMTString() + "</pubDate>");
	s.push("<lastBuildDate>" + d.toGMTString() + "</lastBuildDate>");
	s.push("<docs>http://blogs.law.harvard.edu/tech/rss</docs>");
	s.push("<generator>TiddlyWiki " + version.major + "." + version.minor + "." + version.revision + "</generator>");
	// The body
	var tiddlers = store.getTiddlersTaggedWith("modified","toRSS");
	var n = config.numRssItems > tiddlers.length ? 0 : tiddlers.length-config.numRssItems;
	for (var t=tiddlers.length-1; t>=n; t--)
		s.push(tiddlers[t].saveToRss(u));
	// And footer
	s.push("</channel>");
	s.push("</rss>");
	// Save it all
	return s.join("\n");
}

Tiddler.prototype.getAsInnerHTML = function() {
 var wrapper = createTiddlyElement(document.body,"span",null,null);
 wikify(this.text,wrapper ,null,this);
 var text = wrapper.innerHTML;
 wrapper.parentNode.removeChild(wrapper);
 //replace tddlylink with externallink
 var u = store.getTiddlerText("SiteUrl",null);
var pattern;
var substitution;
 if ((version.major = 2) && (version.minor > 0)) {
 	pattern = /<a\s+tiddlylink="([^"]+)"\s+refresh="link"\s+class=\"([^"]+)\"\s+title=\"([^"]+)\"\s+href="([^"]+)"/mg;
 	substitution = "<a href=\""+u+"#[[$1]]\" class=\"$2\" title=\"$3\" tiddlylink=\"$1\" refresh=\"link\" ";
 }
 else {
	pattern = /<a\s+tiddlylink="([^"]+)"\s+refresh="link"\s+title="([^"]+)"\s+href="([^"]+)"/mg;
	substitution = "<a tiddlylink=\"$1\" refresh=\"link\" title=\"$2\" href=\""+u+"#[[$1]]\"";
 }
 text = text.replace(pattern, substitution);
 return text;
};

Tiddler.prototype.saveToRss = function(url)
{
	var s = [];
	s.push("<item>");
	s.push("<title>" + this.title.htmlEncode() + "</title>");
	//plain text
	s.push("<description>" + this.text.replace(regexpNewLine,"<br />").htmlEncode() + "</description>");
	// html text
	s.push("<content:encoded><![CDATA[	" + this.getAsInnerHTML() +"]]></content:encoded>");
	// tiddler
	s.push("<tiddlywiki:title>" + this.title.htmlEncode() + "</tiddlywiki:title>");
	s.push("<tiddlywiki:wikitext>" + this.text.htmlEncode() + "</tiddlywiki:wikitext>");
	s.push("<tiddlywiki:modifier>" + this.modifier.htmlEncode() + "</tiddlywiki:modifier>");
	s.push("<tiddlywiki:modified>" + this.modified.convertToYYYYMMDDHHMM() + "</tiddlywiki:modified>");
	s.push("<tiddlywiki:created>" + this.created.convertToYYYYMMDDHHMM() + "</tiddlywiki:created>");
	//s.push("<tiddlywiki:links>" + this.text.htmlEncode() + "</tiddlywiki:links>");
	s.push("<tiddlywiki:tags>" + this.getTags().htmlEncode() + "</tiddlywiki:tags>");
	for(var t=0; t<this.tags.length; t++)
		s.push("<category>" + this.tags[t] + "</category>");
	s.push("<link>" + url + "#" + encodeURIComponent(String.encodeTiddlyLink(this.title)) + "</link>");
	s.push("<pubDate>" + this.modified.toGMTString() + "</pubDate>");
	s.push("</item>");
	return(s.join("\n"));
}
//}}}
The context is a Debian etch GNU/Linux distribution.
[[Summary]]
[[Rationale]]
[[Use Cases]]
[[Scope]]
[[Design]]
[[Implementation]]
[[Unresolved Issues]]
[img[Cedre du barouk|images/small/Cedre du barouk.jpg][images/large/Cedre du barouk.jpg]]<<imagebox>>
** Proppy wants the apache appliance to access the ~MySQL appliance.
** Both appliances are on the same LAN.
** Proppy creates a view in the ~BIND9 DNS serving the apache appliance.
** The view is only active for the 192.168.50.0/24 addresses.
** Within this view a new top level domain name is availble : .conf.
** Proppy defines mysql.conf to be the IP address of the mysql software appliance.
** Proppy configures the phpmyadmin available on the apache appliance to use the ~MySQL database from the mysql.conf host.
** When the apache appliance is moved on another LAN, the DNS of this new LAN must bind mysql.conf to the appropriate IP address. 
** Proppy will not have to make changes within the software appliance as long as all references to resources on the LAN are named within the .conf top level domain name.
After {{{NameVirtualHost *}}} add the following so that it catches all unknown hostnames instead of being delivered to the first virtual host.
{{{
<VirtualHost _default_>
ServerName fake
</VirtualHost>
}}}

{{{
(03:08:09 PM) dachary: yo
(03:08:50 PM) dachary: un petit tip apache2 ?
(03:10:23 PM) gryzor: y a qu'a demander, mon bon Loic :)
(03:11:52 PM) dachary: alors alors
(03:11:54 PM) dachary: hum
(03:12:02 PM) dachary: mais qui tu me connais toi que je te connais ?
(03:12:43 PM) gryzor: de vue seulement
(03:12:56 PM) dachary: question: apache2 + virtual host : comment faire pour qu'un host qui n'est pas explicitement liste donne une erreur ?
(03:13:07 PM) dachary: ma question est pas hyper claire
(03:13:14 PM) gryzor: il suffit de faire donner une erreur par le 1er virtualhost
(03:13:22 PM) dachary: mais comment ?
(03:13:24 PM) gryzor: (donc, de le dedier a cela)
(03:13:27 PM) dachary: ah
(03:13:28 PM) dachary: ah
(03:13:31 PM) dachary: hum
(03:13:33 PM) dachary: ok
(03:13:40 PM) dachary: j'essaye
(03:13:41 PM) dachary: smart
(03:13:41 PM) fajita: smart is not enabled
(03:13:50 PM) gryzor: ou alors de definir un virtualhost qui s'appelle "_default_"
(03:14:53 PM) dachary: <VirtualHost _default_>
(03:14:57 PM) dachary: genre ca ?
(03:18:01 PM) dachary: hum
(03:18:13 PM) dachary: alors bon ca marche mais ca a des effets zarb
(03:19:52 PM) gryzor: faq1
(03:19:52 PM) fajita: The value of a NameVirtualHost directive has to match the content of <VirtualHost> exactly. For example, NameVirtualHost *:80 must be used with <VirtualHost *:80>
(03:20:47 PM) dachary: ...
(03:20:50 PM) dachary: ok
(03:20:57 PM) dachary: faq0 : url de la faq ?
(03:21:01 PM) dachary: nan j'abuse ;-)
(03:21:37 PM) dachary: <VirtualHost *>
(03:21:42 PM) dachary: ServerName pokersource.info
(03:21:48 PM) dachary: ServerAlias www.pokersource.info
(03:21:56 PM) dachary: et avant j'ai
(03:22:12 PM) dachary: <VirtualHost _default_>
(03:22:27 PM) dachary: et avant j'ai
(03:22:33 PM) dachary: NameVirtualHost *
(03:22:33 PM) fajita: NameVirtualHost * is 6usually what you want, if you only have one ip address
(03:22:43 PM) dachary: j'ai une seule IP
(03:22:58 PM) dachary: j'ai lu la faq mais la logique m'echape
(03:23:03 PM) dachary: *:80 ce n'est pas *exact*
(03:23:10 PM) dachary: pisque y'a un wildcard
(03:23:28 PM) dachary: donc je comprends pas ce que veut dire "exactly" dans ce contexte
(03:23:46 PM) dachary: ou alors il faut que je mette
(03:23:56 PM) dachary: NameVirtualHost pokersource.info:80
(03:23:58 PM) dachary: avant 
(03:24:08 PM) dachary: <VirtualHost pokersource.info:80>
(03:24:21 PM) dachary: je vais essayer ca
(03:24:32 PM) gryzor: non surtout pas
(03:24:41 PM) dachary: y'a un truc qui m'echape
(03:24:47 PM) dachary: ca doit etre enorme
(03:24:54 PM) gryzor: jamais de nom comme parametre a VirtualHost
(03:24:59 PM) gryzor: toujours une IP, ou une *
(03:25:07 PM) gryzor: ou _default&#195;_
(03:25:32 PM) gryzor: donc la conf avec * et _default_ est bonne
(03:25:36 PM) gryzor: tu as quoi comme effet de bord ?
(03:25:41 PM) dachary: ok
(03:26:01 PM) dachary: http://pokersource.info/ -> not found
(03:26:09 PM) dachary: http://www.pokersource.info/ -> ok
(03:26:16 PM) gryzor: ServerAlias
(03:26:16 PM) fajita: ServerAlias is http://httpd.apache.org/docs/2.2/mod/core.html#serveralias or http://httpd.apache.org/docs/1.3/mod/core.html#serveralias
(03:26:17 PM) dachary: j'ajoute le :80
(03:26:31 PM) dachary: je regarde
(03:26:43 PM) dachary: ServerAlias www.pokersource.info
(03:26:49 PM) gryzor: voila
(03:26:54 PM) dachary: j'ai ca deja
(03:26:59 PM) gryzor: et en ServerName
(03:27:03 PM) gryzor: ?
(03:27:52 PM) gryzor: dns www.pokersource.info
(03:27:53 PM) fajita: gryzor: www.pokersource.info is 88.191.250.37
(03:27:55 PM) dachary: ServerName pokersource.info
(03:27:55 PM) gryzor: dns pokersource.info
(03:27:55 PM) fajita: gryzor: pokersource.info is 88.191.250.37
(03:27:59 PM) dachary: voila
(03:28:20 PM) gryzor: aucun des 2 ne fonctionne
(03:28:26 PM) dachary: NameVirtualHost *
(03:28:26 PM) dachary: <VirtualHost _default_>
(03:28:26 PM) dachary: </VirtualHost>
(03:28:26 PM) dachary: <VirtualHost *>
(03:28:26 PM) dachary:         ServerName pokersource.info
(03:28:26 PM) dachary:         ServerAlias www.pokersource.info
(03:28:26 PM) dachary:  
(03:28:27 PM) fajita: NameVirtualHost * is 6usually what you want, if you only have one ip address
(03:28:29 PM) gryzor: The requested URL / was not found on this server.
(03:28:40 PM) gryzor: apc
(03:28:40 PM) fajita: Try using http://apache.pastebin.ca - It's a good pastebin, and is even set up to highlight Apache 'stuff'.
(03:28:44 PM) dachary: www.pokersource.info ne marche pas ??
(03:28:47 PM) gryzor: non
(03:28:52 PM) gryzor: vide ton cache
(03:29:00 PM) dachary: putain de firefox de mes couilles !!!!
(03:29:22 PM) dachary: :-)
(03:29:58 PM) dachary: hum
(03:30:10 PM) dachary: wget http://www.pokersource.info/ ca marche chez moi
(03:30:20 PM) dachary: je regarde les logs
(03:31:25 PM) gryzor: ok, maintenant oui
(03:32:04 PM) dachary: uof
(03:32:04 PM) dachary: ouf
(03:32:06 PM) dachary: :-)
(03:32:18 PM) dachary: par contre wget http://pokersource.info/ marche pas
(03:32:26 PM) dachary: avec la config ci dessus
(03:32:38 PM) gryzor: que dit le journal d'erreurs
(03:32:39 PM) gryzor: ?
(03:33:58 PM) dachary: file does not exist /htdocs
(03:34:10 PM) gryzor: paste config
(03:34:28 PM) gryzor: fajita: paste config
(03:34:28 PM) fajita: gryzor: i'm not following you...
(03:34:37 PM) gryzor: bon, 
(03:34:39 PM) gryzor: stupid bot
(03:34:39 PM) fajita: Dumb human.
(03:34:47 PM) dachary: http://hg.pokersource.info/file/7cde5a08ed7f/etc/apache2/sites-available/default
(03:34:54 PM) dachary: :-)
(03:35:01 PM) dachary: j'ai juste change le debut
(03:35:04 PM) dachary: de la config
(03:35:15 PM) dachary: comme montre ci dessus
(03:36:16 PM) gryzor: tout VirtualHost devrait avoir un ServerName
(03:36:50 PM) dachary: oh
(03:36:56 PM) dachary: y compris le premier _default_ ?
(03:37:07 PM) gryzor: oui
(03:37:14 PM) gryzor: meme si le nom est bidon
(03:37:16 PM) dachary: ah
(03:37:19 PM) dachary: je fais
(03:38:37 PM) dachary: http://hg.pokersource.info/file/a61226fbf24e/etc/apache2/sites-available/default
(03:38:39 PM) dachary: marche mieux
(03:38:41 PM) dachary: :-)
(03:38:52 PM) dachary: j'aurais JAMAIS trouve cette subtilite
(03:39:27 PM) gryzor: disons que c a ca que le support sert :)
(03:39:28 PM) dachary: c'est genial
(03:39:39 PM) dachary: ben bravo les gars
}}}
PasswordOptionPlugin is not compatible TiddlyWiki version 2.1.
See http://tiddlylab.bidix.info/#PasswordOptionPlugin
** Proppy wants to add a forum to the apache appliance.
** Using //hg incoming//, proppy checks if pending modifications from the publicly available apache appliance need to be transfererd to the copy running on his laptop.
** After applying the changes, proppy installs the forum.
** Proppy tests the forum and asks his friends to give it a try using the 37080 port that is being forwarded to his laptop.
** Turns out that the forum is a really bad software that requires too much work. 
** Proppy stops the apache appliance and revert to the state it was before trying the forum software using the //hg revert// command.
** When proppy is satisfied with the forum software installed, he creates a changeset and publishes it to the publicly available appliance. 
** Proppy wants to publish sensitive information as part of the software appliance
** The information is not essential for the appliance to work
** It's not extremely sensitive either, otherwise proppy would not publish it at all
** Proppy installs seahorse, the gnome cryptographic assistant
** Proppy uses nautilus to select the files or directories that he want to encrypt
** When asked by seahorse, proppy crypts the selected files for decryption by himself and a few others
** Proppy creates a skeleton vserver on the OS where a public IP was dedicated to the apache appliance.
** The skeleton vserver has a LAN IP that will receive incoming connections from the public IP.
** Proppy edits the DNS to define the .conf names required by the apache appliance.
** Proppy creates a mercurial repository at the root of the apache appliance.
** Proppy stops the apache appliance on his laptop.
** The apache appliance is rsync'ed from the laptop to the remote OS.
** Proppy starts the appliance on the remote OS and accesses it from the public IP.
When running a < > " & networked service there is a need to experiment with a clone while the original is still available to the public. Virtual machines are easy to setup based on a backup of an existing virtual server. Switches, cables and firewalls are less intuitives to replicate.
** Proppy wants to use his ssh private key from withing the vserver to gain write access to a SVN repository
** Proppy adds the following lines to /etc/vservers/pokerdev/fstab
{{{
/home/proppy /home/proppy	none bind 0 0
}}}
** Proppy mkdir /home/proppy within the vserver
** Proppy adds the following line in /etc/ssh/sshd_config
{{{
X11UseLocalhost no
}}}
** Proppy installs xauth so that X11 forwarding works
{{{
apt-get install xbase-clients
}}}
** Proppy creates the file /etc/hosts with the following content where pokerdev.pokersource.info is the hostname of the vserver and 192.168.70.18 is its IP
{{{
192.168.70.18 pokerdev.pokersource.info
}}}
** Proppy creates the user proppy making sure the uid matches his local machine uid (1000) in this case. He also inserts himself in the users group (100) so that other users of the same appliance can group with him.
{{{
adduser --gecos 'Proppy Aminche' --disabled-password  --uid 1000 --gid 100 proppy
}}}
** Proppy logs in the server using
{{{
ssh -X proppy@pokerdev
}}}
** Proppy apt-get install ssh-askpass or another package providing X11 based passphrase challenge
** Proppy sets the following environment variables when he wants to work as root. Although he prefers to work as himself, his home is not always available when in a remote location.
{{{
export SVN_SSH='ssh -i /home/proppy/.ssh/id_rsa'
export SSH_ASKPASS=/usr/lib/ssh/x11-ssh-askpass
}}}
** Proppy extracts a svn tree in /usr/src, making sure the directory have the setgid bit set to allow editing by other members of the users group
** Proppy installs emacs-snapshot because emacs does not have the svn-status command
** Proppy runs emacs, edit files, run svn-status and when commiting with svn-status gives his passphrase to write the repository
Vritual machines are meant to be used in the context of an online service. Average GNU/Linux system administration skills are required.

No software must be implemented. If a new ~BIND9 feature or a vserver feature is to be implemented, another specification has to be written.
<<search>><<closeAll>><<permaview>><<newTiddler>><<newJournal 'DD MMM YYYY'>><<saveChanges>><<slider chkSliderOptionsPanel OptionsPanel 'options &#187;' 'Change TiddlyWiki advanced options'>>
including OS, cables, switches and firewalls
Software Appliances
http://garden.dachary.org/universe.html
Virtual machines such as vmware, xen instances, vserver or even chroot can be connected using virtual cables  and switches and their access controled by virtual firewalls. 
/***
|''Name:''|TiddlyLightBox|
|''Date:''|Jan 1, 2006|
|''Version:''|1.0 beta|
|''Author:''|Saq Imtiaz|
|''Location:''|http://tw.lewcid.org/#TiddlyLightBoxPlugin|
|''Documentation:''|http://tw.lewcid.org/#TiddlyLightBoxDocs|
|''License:''|[[Creative Commons Attribution-ShareAlike 2.5 License|http://creativecommons.org/licenses/by-sa/2.5/]]|
|''Based on:''|DC3.LightBox<br>Light Box Gone Wild <br>Ibox|

!!Code
***/
//{{{
config.macros.imagebox ={};
config.macros.imagebox.handler = function (place,macroName,params,wikifier,paramString,tiddler)
{
    var e = place.lastChild;
    e.onclick = function(){TiddlyLightBox.initBox('image',this,params[1],params[2],params[0]);return false;};
}

config.macros.divbox ={};
config.macros.divbox.handler = function (place,macroName,params,wikifier,paramString,tiddler)
{
    if (params[0]!=".")
        createTiddlyButton(place,params[0],params[0],function(){TiddlyLightBox.initBox('html',params[1],params[3],params[4],params[2]);return false;});
    else
        {
        var e = place.lastChild;
        e.onclick = function(){TiddlyLightBox.initBox('html',params[1],params[3],params[4],params[2]);return false;};
        }
}

config.macros.tiddlerbox ={}
config.macros.tiddlerbox.handler = function (place,macroName,params,wikifier,paramString,tiddler)
{
    config.macros.divbox.handler(place,macroName,[params[0],"tiddler:"+params[1],params[2],params[3],params[4]]);
    return false;
}

store.addNotification("TiddlyLightBoxStyles",refreshStyles);

if (!window.TiddlyLightBox)
    window.TiddlyLightBox = {};
    var loadingImage = "indicator.gif";
    window.TiddlyLightBox =
    {
    _curBox: null, // [sentinel]

    lightBoxHtml : '<div id="lightBoxOverlay" onclick="TiddlyLightBox.hideBox()" style="display:none"></div><div id="lightboxprogress" style="display:none;"><img src=\''+loadingImage+'\' alt=\'loading\' style="width:128px;height:128px;"></div><div class="lightBox" id="lightBox" style="display:none"><div id="lightBoxContent"></div><div id="lightBoxTitle">This is a title</div><div id="lightBoxClose"><a href:"#" onclick="TiddlyLightBox.hideBox();return false;">Click to close</a></div></div>',

    createBoxWrapper : function()
        {
        var wrapper = createTiddlyElement(document.getElementsByTagName("body")[0],"div","tiddlyLightBoxWrapper");
        wrapper.innerHTML = this.lightBoxHtml;
        },

    initBox : function(contentType,url,w,h,text)
        {
        if (this._curBox)
            return;
        this.showProgress();
        this.hideSelects("hidden");
        this.showBg();
        this._curBox = true;
        this.sizeTheBox(contentType,w,h);
        if (contentType == 'image')
            this.showImage(url,text);
        else if (contentType == 'html')
            this.showHtml(url,text);
        return false;
        },
        
    sizeTheBox : function(contentType,w,h)
        {
        var box = document.getElementById("lightBoxContent");
        if (w && isNaN(parseInt(w)))
            {
            addClass(box,w);
            }
        else if (w ||h || contentType == 'html')
            {
            box.style.width = w? w+ "px" : "450px";
            box.style.height = h? h+ "px" : "280px";
            if (contentType=='image')
                setStylesheet("#lightBoxContent img{height:100%;width:100%;}","lightBoxImageSizeHack");
            }
        },

    showProgress : function()
        {
        var progress = document.getElementById("lightboxprogress");
        progress.style.display='';
        this._center(progress);
        },
    
    hideProgress: function()
        {
        var progress = document.getElementById("lightboxprogress");
        progress.style.display='none';
        },

    //this function lifted from Lightbox Gone Wild
    hideSelects: function(visibility)
        {
        var selects = document.getElementsByTagName('select');
        for(i = 0; i < selects.length; i++)
            {
            selects[i].style.visibility = visibility;
            }
        },

    showBg: function()
        {
        var overlay = document.getElementById('lightBoxOverlay');
        if (config.browser.isIE)
            {
            overlay.style.height = Math.max(document.documentElement.scrollHeight,document.documentElement.offsetHeight);
            overlay.style.width = document.documentElement.scrollWidth;
            }
        overlay.style.display = 'block';
        },

    showImage: function (url,text)
        {
        imgPreloader = new Image();
        imgPreloader.onload = function ()
            {
            var lb = document.getElementById("lightBoxContent");
            lb.innerHTML = "<img src="+url+">";
            lb.onclick = function(){TiddlyLightBox.hideBox();return false;};
            TiddlyLightBox.posBox(text);
            };
        imgPreloader.src = url;
        },
        
    showHtml : function(theID,text)
        {
        var lb = document.getElementById("lightBoxContent");
        if (theID.indexOf("tiddler:")==-1)
             lb.innerHTML = document.getElementById(theID).innerHTML;
        else
            { 
             wikify(store.getTiddlerText(theID.replace("tiddler:","")),lb);
             lb.className='tiddler';
            }
        lb.style.overflow = "auto";
        this.posBox(text);
        },

    posBox: function(text)
       {
       this.setTitle(text);
       this.hideProgress();
       var lb = document.getElementById("lightBox");
       lb.style.display = "";
       lb.style.visibilty = "hidden";
       lb.style.position = "absolute";
       this._center(lb);
       if(!TiddlyLightBox._curBox) return;
       lb.style.visibility = "visible";
       lb.style.display = "block";
       },

     setTitle: function(text)
        {
        document.getElementById("lightBoxTitle").innerHTML=  (text==undefined)? '': text;
        },

    _center: function(lb)
       {
       var lbSize = new TiddlyLightBox.getElementSize(lb);
       lb.style.left = (Math.round(findWindowWidth()/2) - (lbSize.width /2) + findScrollX())+'px';
       lb.style.top = (Math.round(findWindowHeight()/2) - (lbSize.height /2) + findScrollY())+'px';
       },

    //this function lifted from Ibox
    getElementSize : function(elem)
       {
       this.width = elem.offsetWidth || elem.style.pixelWidth;
       this.height = elem.offsetHeight || elem.style.pixelHeight;
       },

     hideBox: function()
         {
         if(!this._curBox)
             return;
         document.getElementById("tiddlyLightBoxWrapper").innerHTML= this.lightBoxHtml;
         setStylesheet("","lightBoxImageSizeHack");
         this._curBox = null;
         return false;
         }
}

TiddlyLightBox.createBoxWrapper();

Story.prototype.findContainingTiddler = function(e)
{
    while(e && (!hasClass(e,"tiddler") || !e.getAttribute("tiddler")))
        e = e.parentNode;
    return(e);
}

config.shadowTiddlers.TiddlyLightBoxStyles="/*{{{*/\n#lightBoxOverlay {\n position:absolute;\n top: 0;\n left: 0;\n width: 100%;\n height: 100%;\n z-index: 90; \n background-color: #000;\n -moz-opacity: 0.75;\n opacity: .75;\n filter: alpha(opacity=75);\n}\n#lightBoxOverlay[id]{ \n position: fixed;\n}\n\n#lightboxprogress { \n margin:0;padding:0;\n position: absolute;\n z-index:95;\n}\n\ndiv.lightBox {\n background: #fff;\n color: #fff;\n border: 4px solid #525252;\npadding:20px 20px 25px 20px; position:absolute; z-index:99;\n}\n\n#lightBoxClose {text-align:right; color:#000; font-size:1.0em; position:absolute; bottom:6px; right:20px;}\n#lightBoxClose a{color:#666; border-bottom:1px solid #666;cursor:pointer;}\n#lightBoxClose a:hover {color:#111; border-bottom:1px solid #666; cursor:pointer; background:transparent;}\n\n#lightBoxContent {border:1px solid #525252;color:#000; background:#fff;}\n#lightBox .tiddler {background:#fff;}\n\n#lightBoxContent img {border:0;margin:0;padding:0;display:block;cursor:pointer;}\n\n#lightBoxTitle {padding:0px; font-weight:bold; position:absolute; left:20px;bottom:6px; font-size:1.1em; color:#000;}\n\n/*}}}*/";
//}}}
* When a package installation spans more than one software appliance (forum installation implying database configuration) the result can't be published with mercurial.
* The content of a database is usualy stored in binary form and text based tools can't be used for backups.
* mercurial does not handle symbolic links or empty directories (0.9.3)
* ''X11 forwarding depends on a match between the IP and the hostname (either from the DNS or from hosts)''
* /etc/resolv.conf must list an IP that depends on the DNS address available on a given vserver host. There is maybe a way to update this globaly from /etc/vserver 
* //hg pull// can't be used in [[Patching the apache appliance]] because the hg protocol transmits too many information and it lasts for ages. This is not going to change any time soon.
| !date | !user | !location | !storeUrl | !uploadDir | !toFilename | !backupdir | !origin |
| 15/3/2007 17:33:58 | loic | [[universe.html|file:///home/loic/local/ports/home.gna.org/pokersource/universe.html]] | [[store.php|file:///home/loic/local/ports/home.gna.org/pokersource/store.php]] |  | universe.html |  |
| 15/3/2007 17:34:39 | loic | [[universe.html|file:///home/loic/local/ports/home.gna.org/pokersource/universe.html]] | [[store.php|file:///home/loic/local/ports/home.gna.org/pokersource/store.php]] |  | universe.html |  |
| 15/3/2007 17:35:54 | loic | [[universe.html|file:///home/loic/local/ports/home.gna.org/pokersource/universe.html]] | [[store.php|http://pokersource.info/developers/specifications/store.php]] |  | universe.html |  | Ok |
| 15/3/2007 17:41:17 | loic | [[universe.html|file:///home/loic/local/ports/home.gna.org/pokersource/universe.html]] | [[store.php|http://pokersource.info/developers/specifications/store.php]] |  | universe.html |  | Ok |
| 15/3/2007 18:22:39 | loic | [[universe.html|file:///home/loic/local/ports/home.gna.org/pokersource/universe.html]] | [[store.php|http://pokersource.info/developers/specifications/store.php]] |  | universe.html |  |
| 1/4/2007 11:29:58 | loic | [[universe.html|http://pokersource.info/developers/specifications/universe.html]] | [[store.php|http://pokersource.info/developers/specifications/store.php]] |  | universe.html |  |
| 7/4/2007 22:47:38 | loic | [[universe.html|http://pokersource.info/developers/specifications/universe.html]] | [[store.php|http://pokersource.info/developers/specifications/store.php]] |  | universe.html |  | Ok |
| 7/4/2007 22:52:35 | loic | [[universe.html|http://pokersource.info/developers/specifications/universe.html]] | [[store.php|http://pokersource.info/developers/specifications/store.php]] |  | universe.html |  |
| 15/4/2007 18:46:25 | loic | [[universe.html|http://pokersource.info/developers/specifications/universe.html]] | [[store.php|http://pokersource.info/developers/specifications/store.php]] |  | universe.html |  |
| 16/4/2007 22:22:54 | loic | [[universe.html|http://pokersource.info/developers/specifications/universe.html]] | [[store.php|http://pokersource.info/developers/specifications/store.php]] |  | universe.html |  |
| 18/4/2007 17:12:34 | loic | [[universe.html|http://pokersource.info/developers/specifications/universe.html]] | [[store.php|http://pokersource.info/developers/specifications/store.php]] |  | universe.html |  |
| 18/4/2007 17:28:34 | loic | [[universe.html|http://pokersource.info/developers/specifications/universe.html]] | [[store.php|http://pokersource.info/developers/specifications/store.php]] |  | universe.html |  | Ok |
| 18/4/2007 17:33:17 | loic | [[universe.html|http://pokersource.info/developers/specifications/universe.html]] | [[store.php|http://pokersource.info/developers/specifications/store.php]] |  | universe.html |  |
| 19/4/2007 12:39:29 | loic | [[universe.html|http://pokersource.info/developers/specifications/universe.html]] | [[store.php|http://pokersource.info/developers/specifications/store.php]] |  | universe.html |  |
| 19/4/2007 14:38:52 | loic | [[universe.html|http://pokersource.info/developers/specifications/universe.html]] | [[store.php|http://pokersource.info/developers/specifications/store.php]] |  | universe.html |  |
| 19/4/2007 21:18:17 | loic | [[universe.html|http://pokersource.info/developers/specifications/universe.html]] | [[store.php|http://pokersource.info/developers/specifications/store.php]] |  | universe.html |  |
| 29/4/2007 10:31:34 | loic | [[universe.html|http://pokersource.info/developers/specifications/universe.html]] | [[store.php|http://pokersource.info/developers/specifications/store.php]] |  | universe.html |  |
!Options used by UploadPlugin
Username: <<option txtUploadUserName>>
Password: <<option pasUploadPassword>>

Url of the UploadService script^^(1)^^: <<option txtUploadStoreUrl 50>>
Relative Directory where to store the file^^(2)^^: <<option txtUploadDir 50>>
Filename of the uploaded file^^(3)^^: <<option txtUploadFilename 40>>
Directory to backup file on webserver^^(4)^^: <<option txtUploadBackupDir>>

^^(1)^^Mandatory either in UploadOptions or in macro parameter
^^(2)^^If empty stores in the script directory
^^(3)^^If empty takes the actual filename
^^(4)^^If empty existing file with same name on webserver will be overwritten

<<upload>> with these options.

!Upload Macro parameters
{{{
<<upload [storeUrl [toFilename [backupDir [uploadDir [username]]]]]>>
	Optional positional parameters can be passed to overwrite 
	UploadOptions. 
}}}



<<<
With a //linux-2.6// kernel, creating a virtual ethernet interface is made easy. 
{{{
apt-get install vlan
}}}
provides the extensions needed for ///etc/network/interfaces//. To create the //eth0.2// interface add the following lines to ///etc/network/interfaces//.
//sources.list// and //resolv.conf// are to be modified when moving the appliance because they are geographicaly dependent.
{{{
auto eth0.2
iface eth0.2 inet static
        address 192.168.50.1
        netmask 255.255.255.0
	pre-up modprobe 8021q
#	up iptables -t nat -A POSTROUTING -o eth1 -j MASQUERADE
#	up iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE
	up echo 0 > /proc/sys/net/ipv4/conf/eth0.2/rp_filter

}}}
Note that once this is done, packets originating from the 192.168.50.0/24 subnet won't be routed because the MASQUERADE lines are commented out. Routing is being dealt with by shorewall. However, if you don't have or don't want shorewall, the MASQUERADE lines will do the work.
<<<
/***
|''Name:''|WebDAVSavingPlugin|
|''Description:''|Saves on a WebDAV server without the need of any ServerSide script.<br>When TiddlyWiki is accessed over http, this plugin permits to save back to the server, using http PUT.|
|''Version:''|0.2.1|
|''Date:''|Apr 21, 2007|
|''Source:''|http://tiddlywiki.bidix.info/#WebDAVSavingPlugin|
|''Author:''|BidiX (BidiX (at) bidix (dot) info)|
|''License:''|[[BSD open source license|http://tiddlywiki.bidix.info/#%5B%5BBSD%20open%20source%20license%5D%5D ]]|
|''~CoreVersion:''|2.2.0 (Beta 5)|
***/
//{{{
version.extensions.WebDAVSavingPlugin = {
	major: 0, minor: 2, revision: 1, 
	date: new Date("Apr 21, 2007"),
	source: 'http://tiddlywiki.bidix.info/#WebDAVSavingPlugin',
	author: 'BidiX (BidiX (at) bidix (dot) info',
	license: '[[BSD open source license|http://tiddlywiki.bidix.info/#%5B%5BBSD%20open%20source%20license%5D%5D]]',
	coreVersion: '2.2.0 (Beta 5)'
};

if (!window.bidix) window.bidix = {};
bidix.WebDAVSaving = {
	orig_saveChanges: saveChanges,
	defaultFilename: 'index.html',
	messages: {
		loadOriginalHttpDavError: "Original file can't be loaded",
		optionsMethodError: "The OPTIONS method can't be used on this ressource : %0",
		webDavNotEnabled: "WebDAV is not enabled on this ressource : %0",
		notHTTPUrlError: "WebDAV saving can be used for http viewed TiddlyWiki only",
		aboutToSaveOnHttpDav: 'About to save on %0 ...'		,
		folderCreated: "Remote folder '%0' created"
	}
};

// Save this tiddlywiki with the pending changes
saveChanges = function(onlyIfDirty,tiddlers)
{
	var originalPath = document.location.toString();
	if (originalPath.substr(0,5) == "file:")
		return bidix.WebDAVSaving.orig_saveChanges(onlyIfDirty,tiddlers);
	else
		return bidix.WebDAVSaving.saveChanges(onlyIfDirty,tiddlers);
}

bidix.WebDAVSaving.saveChanges = function(onlyIfDirty,tiddlers)
{
	var callback = function(status,params,original,url,xhr) {
			url = (url.indexOf("nocache=") < 0 ? url : url.substring(0,url.indexOf("nocache=")-1));
		if (!status)
			displayMessage(bidix.WebDAVSaving.messages.optionsMethodError.format([url]));
		else {
			if (!xhr.getResponseHeader("DAV"))
				alert(bidix.WebDAVSaving.messages.webDavNotEnabled.format([url]));
			else
				bidix.WebDAVSaving.doSaveChanges();
		}
	}	
	if(onlyIfDirty && !store.isDirty())
		return;
	clearMessage();
	var originalPath = document.location.toString();
	// Check we were loaded from a HTTP or HTTPS URL
	if(originalPath.substr(0,4) != "http") {
		alert(bidix.WebDAVSaving.messages.notHTTPUrlError);
		return;
	}	
	// is the server WebDAV enabled ?
	var r = doHttp("OPTIONS",originalPath,null,null,null,null,callback,null,null);
	if (typeof r == "string")
		alert(r);
}
	
bidix.WebDAVSaving.doSaveChanges = function()
{
	var callback = function(status,params,original,url,xhr) {
		if (!status) {
			alert(config.messages.loadOriginalHttpDavError);
			return;
		}
		url = (url.indexOf("nocache=") < 0 ? url : url.substring(0,url.indexOf("nocache=")-1));
		// Locate the storeArea div's 
		var posDiv = locateStoreArea(original);
		if((posDiv[0] == -1) || (posDiv[1] == -1)) {
			alert(config.messages.invalidFileError.format([localPath]));
			return;
		}
		bidix.WebDAVSaving.mkbackupfolder(null,null,params,original,posDiv);
	};
	// get original
	var originalPath = document.location.toString();
	if (originalPath.charAt(originalPath.length-1) == "/")
		originalPath = originalPath + bidix.WebDAVSaving.defaultFilename;
	displayMessage(bidix.WebDAVSaving.messages.aboutToSaveOnHttpDav.format([originalPath]));
	doHttp("GET",originalPath,null,null,null,null,callback,originalPath,null);
};

bidix.WebDAVSaving.mkbackupfolder = function(root,dirs,url,original,posDiv) {
	if (!root || !dirs) {
		root = bidix.dirname(url);
		if (config.options.txtBackupFolder == "")
			dirs = null;
		else
			dirs = config.options.txtBackupFolder.split('/');
	}
	if (config.options.chkSaveBackups && dirs && (dirs.length > 0)) 
		bidix.WebDAVSaving.mkdir(root,dirs.shift(),dirs,url,original,posDiv);
	else
		bidix.WebDAVSaving.saveBackup(url,original,posDiv);
};

bidix.WebDAVSaving.saveBackup = function(url,original,posDiv)
{
	var callback = function(status,params,responseText,url,xhr) {
		if (!status) {
			alert(config.messages.backupFailed);
			return;
		}
		url = (url.indexOf("nocache=") < 0 ? url : url.substring(0,url.indexOf("nocache=")-1));
		displayMessage(config.messages.backupSaved,url);
		bidix.WebDAVSaving.saveRss(params[0],params[1],params[2]);
	};
	if(config.options.chkSaveBackups) {
		var backupPath = getBackupPath(url);
		bidix.httpPut(backupPath,original,callback,Array(url,original,posDiv));
	} else {
		bidix.WebDAVSaving.saveRss(url,original,posDiv);
	}
}

bidix.WebDAVSaving.saveRss = function(url,original,posDiv) 
{
	var callback = function(status,params,responseText,url,xhr) {
		if (!status) {
			alert(config.messages.rssFailed);
			return;
		}
		url = (url.indexOf("nocache=") < 0 ? url : url.substring(0,url.indexOf("nocache=")-1));
		displayMessage(config.messages.rssSaved,url);
		bidix.WebDAVSaving.saveEmpty(params[0],params[1],params[2]);
	};
	if(config.options.chkGenerateAnRssFeed) {
		var rssPath = url.substr(0,url.lastIndexOf(".")) + ".xml";
		bidix.httpPut(rssPath,convertUnicodeToUTF8(generateRss()),callback,Array(url,original,posDiv));
	} else {
		bidix.WebDAVSaving.saveEmpty(url,original,posDiv);
	}
}

bidix.WebDAVSaving.saveEmpty = function(url,original,posDiv) 
{
	var callback = function(status,params,responseText,url,xhr) {
		if (!status) {
			alert(config.messages.emptyFailed);
			return;
		}
		url = (url.indexOf("nocache=") < 0 ? url : url.substring(0,url.indexOf("nocache=")-1));
		displayMessage(config.messages.emptySaved,url);
		bidix.WebDAVSaving.saveMain(params[0],params[1],params[2]);
	};
	if(config.options.chkSaveEmptyTemplate) {
		var emptyPath,p;
		if((p = url.lastIndexOf("/")) != -1)
			emptyPath = url.substr(0,p) + "/empty.html";
		else
			emptyPath = url + ".empty.html";
		var empty = original.substr(0,posDiv[0] + startSaveArea.length) + original.substr(posDiv[1]);
		bidix.httpPut(emptyPath,empty,callback,Array(url,original,posDiv));
	} else {
		bidix.WebDAVSaving.saveMain(url,original,posDiv);
	}
}

bidix.WebDAVSaving.saveMain = function(url,original,posDiv) 
{
	var callback = function(status,params,responseText,url,xhr) {
		if(status) {
			url = (url.indexOf("nocache=") < 0 ? url : url.substring(0,url.indexOf("nocache=")-1));
			displayMessage(config.messages.mainSaved,url);
			store.setDirty(false);
		} else 
			alert(config.messages.mainFailed);
	};	
	// Save new file
	var revised = updateOriginal(original,posDiv);
	bidix.httpPut(url,revised,callback,null);
}

// asynchronous mkdir
bidix.WebDAVSaving.mkdir = function(root,dir,dirs,url,original,posDiv) {
	var callback = function(status,params,responseText,url,xhr) {
		url = (url.indexOf("nocache=") < 0 ? url : url.substring(0,url.indexOf("nocache=")-1));
		if (status == null) {
			alert("Error in mkdir");
			return;
		}
		if (xhr.status == httpStatus.ContentCreated) {
			displayMessage(bidix.WebDAVSaving.messages.folderCreated.format([url]),url);
			bidix.WebDAVSaving.mkbackupfolder(url,params[1],params[2],params[3],params[4]);
		} else {
			if (xhr.status == httpStatus.NotFound)
				bidix.http('MKCOL',url,null,callback,params);
			else
				bidix.WebDAVSaving.mkbackupfolder(url,params[1],params[2],params[3],params[4]);
		}
	};
	if (root.charAt(root.length) != '/')
		root = root +'/';
	bidix.http('HEAD',root+dir,null,callback,Array(root,dirs,url,original,posDiv));
}

bidix.httpPut = function(url,data,callback,params)
{
	return bidix.http("PUT",url,data,callback,params);
}

bidix.http = function(type,url,data,callback,params)
{
	var r = doHttp(type,url,data,null,null,null,callback,params,null);
	if (typeof r == "string")
		alert(r);
	return r;
}

bidix.dirname = function (filePath) {
	if (!filePath) 
		return;
	var lastpos;
	if ((lastpos = filePath.lastIndexOf("/")) != -1) {
		return filePath.substring(0, lastpos);
	} else {
		return filePath.substring(0, filePath.lastIndexOf("\\"));
	}
};
//}}}
* When parts of the universe are in different locations, DNS queries go thru DNS out of control with cache policies that can vary. However, when setting up a new domain name and the monitor (nagios) is not in the same geographical location, it is unpractical to wait for the cache to update. The solution is to instruct the DNS serving a given host to directly ask the primary DNS for a domain on which control is guaranteed. For instance, if pokersource.info is under control, this can be added to named.conf:
{{{
zone "pokersource.info."{
   type forward ;
   forward only ;
   forwarders {
       88.191.250.41 ;
   } ;
};
}}}
* {{{/etc/init.d/bind9 restart}}} because reload is not enough for this kind of change
{{{
qemu-img create -b baseimage.qcow -f qcow workingcopy.qcow
qemu workingcopy.qcow
}}}
* workingcopy.qcow only store the delta from baseimage.qcow
* can be easily automated
* an extra step could be to allow credentials upload to the newly created appliance
use {{{/usr/sbin/qemu-make-debian-root}}} with {{{rsync}}}
or
http://www.rot13.org/~dpavlin/debian-amd64.html
! DNS definition in ns2.fsffrance.org
{{{
set -e
name=markerclock
 cd /etc/bind
 echo "$name                IN      CNAME   dachary.org." >> db.dachary.org
 echo "hg.$name             IN      CNAME   dachary.org." >> db.dachary.org
 /etc/init.d/bind9 reload
 perl -ni -e 'if(/(\d+).*; serial/) { $s = $1; $s++; print "\t\t\t$s\t; serial\n"; } else { print; }' db.dachary.org
 dig @192.168.50.16 $name.dachary.org | grep 'CNAME.*dachary.org'
 dig @192.168.50.16 hg.$name.dachary.org | grep 'CNAME.*dachary.org'
 hg commit -u loic@dachary.org -m 'define $name.dachary.org' /etc/bind/db.dachary.org
}}}
! DNS definition in the vserver host DNS pecho.fsffrance.org
{{{
set -e
#net=192.168.50 # pecho.fsffrance.org
net=192.168.70 # call.dachary.org
reverse=$(echo $net | perl -p -e 's/(\d+).(\d+).(\d+)/$3.$2.$1/')
vserver_realm=call
realm=dachary
domain=$realm.org
name=markerclock
cd /etc/bind
perl -ni -e 'if(/(\d+).*; serial/) { $s = $1; $s++; print "\t\t\t$s\t; serial\n"; } else { print; }' db.192.168 db.$vserver_realm views/$domain.view
ip=$(expr "$(grep available db.192.168 | tail -1)" : '.*available-\([0-9][0-9]*\)')
test "$ip" || echo "NO IP"
perl -pi -e "s/available-$ip/$name.$realm/" db.192.168 db.$vserver_realm
echo -e "$name\t\tIN\tCNAME\t$name.$realm.$vserver_realm.tld." >> views/$domain.view
/etc/init.d/bind9 reload
dig @$net.1 $name.$realm.$vserver_realm.tld | grep $ip
dig @$net.1 -x $net.$ip | grep $name.$realm.$vserver_realm.tld
# ??? how to test that a resolution within a view works ???
hg commit -m "define $name local names in $realm" /etc/bind
perl -pi -e 's/};$/'$net.$ip'; };/ if(/^view "'$realm'/)' /etc/bind/named.conf
grep "$realm.*$net.$ip" /etc/bind/named.conf
}}}
! Create the vserver on the host pecho.fsffrance.org
{{{
apt-get install debootstrap util-vserver
author=loic@dachary.org
ip=254
name=markerclock
vserver_domain=dachary.org
domain=dachary.org
fqdn=$name.$domain
#net=192.168.50 # pecho.fsffrance.org
net=192.168.70 # call.dachary.org
#method='debootstrap -- -d etch -m http://ftp.fr.debian.org/debian'
method=skeleton
eval vserver $name build --hostname $fqdn --interface a$ip=eth0.2:$net.$ip/24 --context 2$ip -m $method
echo default > /etc/vservers/$name/apps/init/mark
hg addremove /etc/vservers
hg commit -u $author -m "create $name vserver" /etc/vservers
cat > /var/lib/vservers/$name/etc/resolv.conf <<EOF
search $vserver_domain
nameserver $net.1
EOF
mkdir -p /var/lib/vservers/$name/proc /var/lib/vservers/$name/sys
env -i TERM=vt100 /usr/sbin/vserver $name start
}}}
! Install mercurial on the vserver as per [[vserver under mercurial]]
{{{
set -e
mercurial_repository=hgcia.conf.tld
#mercurial_repository=hgcia.dachary.org
url=hg.silva.dachary.org
author=loic@dachary.org
if ! grep $mercurial_repository /etc/apt/sources.list > /dev/null 2>&1 ; then
        echo "deb http://$mercurial_repository ./" >> /etc/apt/sources.list
        apt-get update
fi
apt-get install mercurial
cd /
if [ ! -f .hgignore ] ; then
        cat > /.hgignore <<'EOF'
syntax: glob
*~

syntax: regexp
^var/
^sys/
^dev/
^tmp/
^proc
EOF
fi
if [ ! -d .hg ] ; then
        hg init
        hg add
        hg commit -m 'initial'
fi
perl -pi -e 's/.*ACTIVE.*/ACTIVE=yes/' /etc/default/mercurial
perl -pi -e "s|.*URL=.*|URL=$url|" /etc/default/mercurial
/etc/init.d/mercurial start
if ! grep hgc /root/.bashrc ; then
        echo "alias hgc='/usr/bin/hg commit -u $author'" >> /root/.bashrc
fi
}}}
! Define a vhost in dachary.org apache proxy server
{{{
set -e
name=just
domain=pokersource.info
author=loic@dachary.org
cd /etc/apache2/sites-available/
if ! a2enmod proxy_http | grep already ; then
patch -p2 <<'EOF'
diff -r 3af59707ff09 -r 0d1ce41b5522 etc/apache2/mods-available/proxy.conf
--- a/etc/apache2/mods-available/proxy.conf     Sat Apr 21 00:33:04 2007 +0200
+++ b/etc/apache2/mods-available/proxy.conf     Sat Apr 21 00:32:25 2007 +0200
@@ -7,8 +7,8 @@
         <Proxy *>
                 AddDefaultCharset off
                 Order deny,allow
-                #Deny from all
-                Allow from all
+                Deny from all
+                #Allow from .example.com
         </Proxy>

         # Enable/disable the handling of HTTP/1.1 "Via:" headers.
EOF
fi
if [ ! -f template.$domain ] ; then
  cat > template.$domain <<EOF
<VirtualHost *>
    ServerName          template.$domain
    ProxyPass           / http://template.conf.tld/
    ProxyPassReverse    / http://template.conf.tld/
    ServerAdmin         root@$domain
    ErrorLog            /var/log/apache2/template.conf.tld-error.log
    CustomLog           /var/log/apache2/template.conf.tld-access.log common
</VirtualHost>

<VirtualHost *>
    ServerName          hg.template.$domain
    ProxyPass           / http://template.conf.tld:8000/
    ProxyPassReverse    / http://template.conf.tld:8000/
    ServerAdmin         root@$domain
    ErrorLog            /var/log/apache2/template.conf.tld-error.log
    CustomLog           /var/log/apache2/template.conf.tld-access.log common
</VirtualHost>
EOF
fi
sed -e "s/template/$name/g" < template.$domain > $name.$domain
a2ensite $name.$domain
/etc/init.d/apache2 reload
sleep 2
if [ ! -f /var/log/apache2/$name.conf.tld-error.log ] ; then
        echo "/var/log/apache2/$name.conf.tld-error.log does not exist"
        exit 1
fi
hg add $name.$domain
hg commit -u $author -m "define proxy for $name.$domain" $name.$domain
}}}
! Monitor the mercurial server with nagios.fsffrance.org
{{{
set -ex
name=silva ; domain=dachary.org ; parent=pecho.fsffrance.org
cd /etc/nagios2/conf.d
cat >> $domain.cfg <<EOF
define host {
        host_name   hg.$name
        parents     $parent
        alias       $name mercurial
        address     hg.$name.$domain
        hostgroups  http-servers, debian-servers
        use         http-host
        }
EOF
/etc/init.d/nagios2 stop ; sleep 2; /etc/init.d/nagios2 start
hg commit -u loic@dachary.org -m "monitor hg.$name.$domain" $domain.cfg
}}}
! Syndicate the mercurial changes to http://dachary.org/
{{{
name=silva ; fqdn=$name.dachary.org
echo "[http://$name.conf.tld:8000/rss-log]" >> /etc/planet.conf
echo "name = $fqdn" >> /etc/planet.conf
su www-data -c 'planetplanet -v /etc/planet.conf'
}}}
The fam2rss software appliance contains a single spec file. It can be moved to a directory at http://specs.dachary.org/. External links to the spec file can be preserved. RSS feeds need not be changed, except if refering to the obsoleted software appliance with a non routable IP. External links to the corresponding hg repository are redirected to a unique non existent URLs. 
* copy the content over to http://specs.dachary.org/fam2rss/
** in /etc/fstab there is
{{{
http://fam2rss.dachary.org /fam2rss.dachary.org davfs noauto,user,exec 0 0
http://specs.dachary.org /specs.dachary.org davfs noauto,user,exec 0 0
}}}
** copy gently because DAV has issues (see unrelsolved issues in http://garden.dachary.org/)
{{{
cd /fam2rss.dachary.org/
mkdir /specs.dachary.org/fam2rss
cp -a index.html scrapbook /specs.dachary.org/fam2rss/
}}}
* kill the apache proxy pass and redirect it to the new location /etc/apache2/sites-available/fam2rss.dachary.org as shown in http://hg.dachary.org/file/3b64f7ee7716/etc/apache2/sites-available/fam2rss.dachary.org leading to 
{{{
<VirtualHost *>
    ServerName          fam2rss.dachary.org
    RedirectMatch       permanent ^/(.*)        http://specs.dachary.org/fam2rss/$1
</VirtualHost>

<VirtualHost *>
    ServerName          hg.fam2rss.dachary.org
    RedirectMatch       permanent .*    http://specs.dachary.org/fam2rss/#obsolete-hg
</VirtualHost>
}}}
* backup the software appliance and remove it
{{{
vserver fam2rss stop
tar -zcvf var/lib/vservers/specs/home/www/fam2rss/fam2rss.dachar.org-2007-06-07.tar.gz etc/vservers/fam2rss var/lib/vservers/fam2rss 
rm -fr etc/vservers/fam2rss var/lib/vservers/fam2rss
}}}
* free the local IP and name in the local DNS as found at http://hg.pecho.fsffrance.org/rev/4fcf6125f1d1
{{{
--- a/etc/bind/db.192.168	Thu Jun 07 11:31:02 2007 +0200
+++ b/etc/bind/db.192.168	Thu Jun 07 11:34:33 2007 +0200
@@ -4,7 +4,7 @@
 ;
 $TTL	604800
 @	IN	SOA	localhost. root.localhost. (
-                        2007053002      ; serial number
+                        2007060700      ; serial number
 			 604800		; Refresh
 			  86400		; Retry
 			2419200		; Expire
@@ -46,7 +46,7 @@ 34.50	IN	PTR	poker-network-1-0-37.pokers
 34.50	IN	PTR	poker-network-1-0-37.pokersource.fsf.tld.
 35.50	IN	PTR	openscenegraph.dachary.fsf.tld.
 36.50	IN	PTR	jacques.dachary.fsf.tld.
-37.50	IN	PTR	fam2rss.dachary.fsf.tld.
+37.50	IN	PTR	available-37.fsf.tld.
 38.50	IN	PTR	garden.dachary.fsf.tld.
 39.50	IN	PTR	poker-network-1-1-0.pokersource.fsf.tld.
 40.50	IN	PTR	specs.dachary.fsf.tld.

--- a/etc/bind/db.fsf	Thu Jun 07 11:31:02 2007 +0200
+++ b/etc/bind/db.fsf	Thu Jun 07 11:34:33 2007 +0200
@@ -4,7 +4,7 @@
 
 $ORIGIN fsf.tld.
 @                       IN      SOA             ns hostmaster (
-                                2007053001      ; serial number
+                                2007060700      ; serial number
                                 1h              ; refresh - time when the slave will try to refresh the zone from the master (8h)
                                 30m             ; update retry - time between retries if the slave (secondary) (2h)
                                                 ; fails to contact the master when refresh (above) has expired.
@@ -51,7 +51,7 @@ poker-network-1-0-37.pokersource	IN     
 poker-network-1-0-37.pokersource	IN      A	192.168.50.34
 openscenegraph.dachary			IN      A	192.168.50.35
 jacques.dachary				IN      A	192.168.50.36
-fam2rss.dachary				IN      A	192.168.50.37
+available-37				IN      A	192.168.50.37
 garden.dachary				IN      A	192.168.50.38
 poker-network-1-1-0.pokersource		IN      A	192.168.50.39
 specs.dachary				IN      A	192.168.50.40

--- a/etc/bind/named.conf	Thu Jun 07 11:31:02 2007 +0200
+++ b/etc/bind/named.conf	Thu Jun 07 11:34:33 2007 +0200
@@ -29,7 +29,7 @@ view "fsffrance.org" {
 };
 
 view "dachary.org" {
-  match-clients { 192.168.50.13; 192.168.50.14; 192.168.50.17; 192.168.50.19; 192.168.50.20; 192.168.50.22; 192.168.50.23; 192.168.50.27; 192.168.50.28; 192.168.50.33; 192.168.50.35; 192.168.50.37; 192.168.50.38; 192.168.50.40; 192.168.50.41; 192.168.50.43; 88.191.250.36; };
+  match-clients { 192.168.50.13; 192.168.50.14; 192.168.50.17; 192.168.50.19; 192.168.50.20; 192.168.50.22; 192.168.50.23; 192.168.50.27; 192.168.50.28; 192.168.50.33; 192.168.50.35; 192.168.50.38; 192.168.50.40; 192.168.50.41; 192.168.50.43; 88.191.250.36; };
   zone "conf.tld" {
     type master;
     file "/etc/bind/views/dachary.org.view";

--- a/etc/bind/views/dachary.org.view	Thu Jun 07 11:31:02 2007 +0200
+++ b/etc/bind/views/dachary.org.view	Thu Jun 07 11:34:33 2007 +0200
@@ -4,7 +4,7 @@
 
 $ORIGIN conf.tld.
 @                       IN      SOA             ns hostmaster (
-                                2007053005      ; serial number
+                                2007060700      ; serial number
                                 1h              ; refresh - time when the slave will try to refresh the zone from the master (8h)
                                 30m             ; update retry - time between retries if the slave (secondary) (2h)
                                                 ; fails to contact the master when refresh (above) has expired.
@@ -33,7 +33,6 @@ bellinux		IN	CNAME	bellinux.dachary.fsf.
 bellinux		IN	CNAME	bellinux.dachary.fsf.tld.
 openscenegraph		IN	CNAME	openscenegraph.dachary.fsf.tld.
 jacques			IN	CNAME	jacques.dachary.fsf.tld.
-fam2rss			IN	CNAME	fam2rss.dachary.fsf.tld.
 garden			IN	CNAME	garden.dachary.fsf.tld.
 specs			IN	CNAME	specs.dachary.fsf.tld.
 versavant		IN	CNAME	versavant.dachary.fsf.tld.

}}}
* remove firewall redirections to fam2rss.dachary.org as found at http://hg.pecho.fsffrance.org/rev/929ee5ca9e4c
{{{
--- a/etc/shorewall/params	Thu Jun 07 11:34:33 2007 +0200
+++ b/etc/shorewall/params	Thu Jun 07 11:40:25 2007 +0200
@@ -68,7 +68,6 @@ VSRV_DUVAL=192.168.50.25
 VSRV_DUVAL=192.168.50.25
 VSRV_PACKAGING_FARM=192.168.50.20
 VSRV_JACQUES=192.168.50.36
-VSRV_FAM2RSS=192.168.50.37
 VSRV_GARDEN=192.168.50.38
 VSRV_OPENSCENEGRAPH=192.168.50.35
 VSRV_URLCONVERSION=192.168.50.23
@@ -79,7 +78,6 @@ DACHARY_SSH_DUVAL=5022
 DACHARY_SSH_DUVAL=5022
 DACHARY_SSH_PACKAGING_FARM=6022
 DACHARY_SSH_JACQUES=7022
-DACHARY_SSH_FAM2RSS=8022
 DACHARY_SSH_GARDEN=9022
 DACHARY_SSH_OPENSCENEGRAPH=10022
 DACHARY_RSYNC_OPENSCENEGRAPH=10873

--- a/etc/shorewall/rules	Thu Jun 07 11:34:33 2007 +0200
+++ b/etc/shorewall/rules	Thu Jun 07 11:40:25 2007 +0200
@@ -449,7 +449,6 @@ DNAT		net             tld:$VSRV_ECOLE:22
 DNAT		net             tld:$VSRV_ECOLE:22      tcp     ${DACHARY_SSH_ECOLE:-.}     -       ${DACHARY:-.} 
 DNAT		net             tld:$VSRV_DUVAL:22      tcp     ${DACHARY_SSH_DUVAL:-.}     -       ${DACHARY:-.} 
 DNAT		net             tld:$VSRV_JACQUES:22      tcp     ${DACHARY_SSH_JACQUES:-.}     -       ${DACHARY:-.} 
-DNAT		net             tld:$VSRV_FAM2RSS:22      tcp     ${DACHARY_SSH_FAM2RSS:-.}     -       ${DACHARY:-.} 
 DNAT		net             tld:$VSRV_GARDEN:22      tcp     ${DACHARY_SSH_GARDEN:-.}     -       ${DACHARY:-.} 
 DNAT		net             tld:$VSRV_OPENSCENEGRAPH:22      tcp     ${DACHARY_SSH_OPENSCENEGRAPH:-.}     -       ${DACHARY:-.} 
 DNAT		net             tld:$VSRV_OPENSCENEGRAPH:873      tcp     ${DACHARY_RSYNC_OPENSCENEGRAPH:-.}     -       ${DACHARY:-.} 
}}}
http://www.cs.toronto.edu/~andreslc/xen-gl/
<<<
No tricks : plain simple shorewall configuration. The laptop has a wifi connection on eth1 and a ~RJ45 cable on eth0.
///etc/shorewall/interfaces//
{{{
###############################################################################
#ZONE	INTERFACE	BROADCAST	OPTIONS
net     eth0                 detect          routefilter,dhcp,tcpflags,nosmurfs
net     eth1                 detect          routefilter,dhcp,tcpflags,nosmurfs
my	eth0.2		     detect	     dhcp
}}}
///etc/shorewall/masq//
{{{
###############################################################################
#INTERFACE		SUBNET		ADDRESS		PROTO	PORT(S)	IPSEC
eth1			eth0.2
eth0			eth0.2
}}}
///etc/shorewall/params//
{{{
VOD=192.168.50.11
}}}
///etc/shorewall/policy//
{{{
###############################################################################
#SOURCE		DEST		POLICY		LOG		LIMIT:BURST
#						LEVEL
$FW             net             ACCEPT
net             $FW             DROP            info
# my has no filtering
my              all             ACCEPT
all             my              ACCEPT
# The FOLLOWING POLICY MUST BE LAST
all             all             REJECT          info
}}}
///etc/shorewall/rules//
{{{
###############################################################################
#ACTION	SOURCE		DEST		PROTO	DEST	SOURCE		ORIGINAL	RATE		USER/
#						PORT(S)	PORT(S)		DEST		LIMIT		GROUP
#SECTION ESTABLISHED
#SECTION RELATED
SECTION NEW
DNAT:debug	net		my:${VOD:-.} tcp	37000:38000
ACCEPT            net             $FW	tcp	37000:38000
SSH/ACCEPT    net             $FW
HTTP/ACCEPT  net             $FW
ACCEPT            net             $FW	tcp	24800
}}}
Note the {{{${VOD:-.}}}} instead of a simple {{{$VOD}}}. The rationale is that you want to evaluate all the variables using the dot as a default. A typo in the variable name turns a variable into a space which leads to very confusing error messages or even no error message at all. A default value of dot or any other string gives much more readable error messages.
///etc/shorewall/zones
{{{
###############################################################################
#ZONE	TYPE		OPTIONS		IN			OUT
#					OPTIONS			OPTIONS
fw	firewall
my	-
net	ipv4
}}}
<<<
* define the check_ssh_port command
{{{
cat > /etc/nagios2/conf.d/check_ssh_port.cfg <<EOF
define command{
        command_name    check_ssh_port
        command_line    /usr/lib/nagios/plugins/check_ssh -p $ARG1$ $HOSTADDRESS$
        }
EOF
}}}
* monitor the ssh server running on a given port 
{{{
port=15022 ; name=markerclock ; domain=dachary.org
cat >> $domain <<EOF
define service {
  host_name     $name
  service_description $name ssh
  check_command check_ssh_port!$port
  use           generic-service
  }
}}}
* Documentation patch http://sourceforge.net/tracker/index.php?func=detail&aid=1721843&group_id=29880&atid=397599
* Some tests require administration privileges that are not normaly granted in a vserver. Edit bcapabilities in /etc/vservers to add something like (for dhcp test):
{{{
NET_BIND_SERVICE
NET_BROADCAST
NET_ADMIN
NET_RAW
}}}
or check http://svn.linux-vserver.org/svn/util-vserver/trunk/lib/bcaps-v13.c for more.
* Create the test before running the service
* Activate external commands to force the check
{{{
--- a/etc/nagios2/nagios.cfg	Thu May 17 15:01:42 2007 +0200
+++ b/etc/nagios2/nagios.cfg	Thu May 17 16:17:28 2007 +0200
@@ -127,7 +127,7 @@ nagios_group=nagios
 # you will have to enable this.  Setting this value to 0 disables command
 # checking (the default), other values enable it.
 
-check_external_commands=0
+check_external_commands=1

}}}
* Give permissions to www-data
{{{
chmod g+rwxs /var/lib/nagios2/rw 
chgrp -R www-data  /var/lib/nagios2
}}}
* {{{apt-get install nagios-plugins-standard}}}
* Use plugin from the command line on the machine running the service after installing {{{apt-get install nagios-plugins-standard}}} which does not require to install a complete nagios
* Edit /etc/passwd to give shell to nagios user and add the key of the nagios machine that will be probing the service in //.ssh/authorized_keys//. Make sure the access is IP limited because you don't want to deal with nagios security holes.
{{{
from="*.mekensleep.com" ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEAvg8CgXpHpLC5L/335GObQk/JSwdJBt5p118+f9b0YwOajHbxcThPDQatg/urnaR9HFmrj03DIvCBYylaoAPnC59lEmv/nUW4U558EFGyvECldudbmscHYudGAkKs4+ctfHTTVUTNv8JyEiZnII5bWn8uApUbQCojfGHfv11lQrPmFj88GcXwLdx+TD3DoEqdMrnKQIjpIYDAEhat8sy8eS2ZFVzwdz20iOVe8+aHkKzU6f85jTg7uT3Z2z/gwz/6tvh6r5UebUPiJVmmuZ6sIG35LjFUrCWkve/tYy6FWYUP40xP5VRH4nw5fji1AQjJyHcSR80B7xn7W7UwVHbVnQ== root@mon2.dmz.free.tld
}}}
* On the nagios host, create a ssh key without password that will be exclusively used for querying nagios
* On the nagios host create a new service as follows:
{{{
define command{
        command_name    money_counter
        command_line    /usr/lib/nagios/plugins/check_by_ssh -i /home/nagios/.ssh/id_rsa -C '/usr/lib/nagios/plugins/check_mysql_query -q s\
elect\ count\(serial\)\ from\ counter -u nagios -d pokernetwork -H localhost -c 0:0' -l nagios -H gw.host.xs4all.mekensleep.net -p 42002 -t\
 20
        }
define service {
  host_name     poker-db-03
  service_description money:counter
  check_command money_counter
  use           generic-service
}
}}}
{{{
pecho:/etc/shorewall# ssh=15022 ; name=MARKERCLOCK ; ip=192.168.50.254
pecho:/etc/shorewall# echo "VSRV_$name=$ip" >> params
pecho:/etc/shorewall# echo "DACHARY_SSH_$name=$ssh" >> params
pecho:/etc/shorewall# perl -pi -e 's/^#LAST LINE.*//;' params
pecho:/etc/shorewall# echo '#LAST LINE - ADD YOUR ENTRIES ABOVE THIS ONE - DO NOT REMOVE' >> params
pecho:/etc/shorewall# perl -pi -e 's/#PATCH_DACHARY/DNAT\t\tnet\ttld:\$VSRV_'$name':22\ttcp\t\${DACHA\
RY_SSH_'$name':-.}\t-\t\${DACHARY:-.}\n#PATCH_DACHARY/' rules
pecho:/etc/shorewall#
pecho:/etc/shorewall# perl -pi -e 's/#PATCH_DACHARY/ACCEPT\tnet\t\$FW:\${VSRV_'$name':-.}\n#PATCH_DAC\
HARY/' rules
pecho:/etc/shorewall# shorewall restart
*** output flushed ***
pecho:/etc/shorewall# # missing check
pecho:/etc/shorewall# hg commit -m "add $name ssh port $ssh to shorewall" /etc/shorewall
No username found, using 'root@pecho.fsffrance.org' instead
}}}
* follow the steps described at  [[running xorg inside a vserver]] because although you may not plan to run a xorg within a vserver, these modifications allow you to get access to the resources that your application needs to run accelerated
* for the vserver named markerclock
{{{
name=markerclock
echo "/tmp /tmp       none bind 0 0" >> /etc/vservers/$name/fstab
}}}
* restart the vserver and try it with
{{{
apt-get install mesa-utils
DISPLAY=:0 glxinfo
DISPLAY=:0 glxgears
}}}
* There may be problems if the versions of the vserver and the host are different.
Before installing xorg system inside a vserver you need to make the following changes (replace *desktop* with the vserver name):
* Enable following capabilities
{{{
diff -r 511190dd513b -r 0620f9b04fbf etc/vservers/desktop/bcapabilities
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/etc/vservers/desktop/bcapabilities	Wed May 09 14:18:48 2007 +0200
@@ -0,0 +1,7 @@
+CAP_IPC_LOCK
+CAP_IPC_OWNER
+CAP_SYS_RAWIO
+CAP_SYS_ADMIN
+CAP_NET_ADMIN
+CAP_NET_RAW
+CAP_MKNOD
}}}
* Unhide following /proc entries
{{{
diff -r 511190dd513b -r 0620f9b04fbf usr/lib/util-vserver/defaults/vprocunhide-files
--- a/usr/lib/util-vserver/defaults/vprocunhide-files	Wed May 09 14:13:15 2007 +0200
+++ b/usr/lib/util-vserver/defaults/vprocunhide-files	Wed May 09 14:18:48 2007 +0200
@@ -28,3 +28,5 @@
 /proc/uptime
 -/proc/cmdline
 /proc/version
+/proc/mtrr
+/proc/bus/
}}}
* Copy following devices inside the vserver
{{{
name=makerclock
rsync --devices /dev/psaux /var/lib/vservers/$name/dev/
rsync --devices /dev/input/mice /var/lib/vservers/$name/dev/input/
}}}
* On a low end server with a single interface to the net
* Assuming a [[VLAN interface]]eth0.2 was added
{{{
cp /usr/share/doc/shorewall/examples/two-interfaces/* /etc/shorewall
gzip -d /etc/shorewall/*.gz
perl -pi -e 's/eth1/eth0.2/' /etc/shorewall/*
}}}
* Make sure ssh is allowed from net in rules
{{{
markerclock:/usr/src# app=openssh-server ; apt-get install $app && hg addremove && hg commit -u loic@\
dachary.org -m "apt-get install $app"
markerclock:/usr/src# perl -pi -e 's/^UsePAM/#UsePAM/' /etc/ssh/sshd_config
markerclock:/usr/src# grep '#UsePAM' /etc/ssh/sshd_config
#UsePAM yes
markerclock:/usr/src# perl -pi -e 's/^X11UseLocalhost.*/X11UseLocalhost no/' /etc/ssh/sshd_config
markerclock:/usr/src# if grep 'X11UseLocalhost no' /etc/ssh/sshd_config ; then perl -pi -e 's/^X11Use\
Localhost.*/X11UseLocalhost no/' /etc/ssh/sshd_config ; else echo 'X11UseLocalhost no' >> /etc/ssh/ss\
hd_config ; fi
markerclock:/usr/src# grep X11UseLocalhost /etc/ssh/sshd_config
X11UseLocalhost no
markerclock:/usr/src# app=xbase-clients ; apt-get install $app && hg addremove && hg commit -u loic@d\
achary.org -m "apt-get install $app"
markerclock:/usr/src# ip=$(ifconfig | grep 'inet add' | tail -1 | sed -e 's/.*addr:\(.*\) Bcast.*/\1/\
')
markerclock:/usr/src# echo "$ip $(hostname)" >> /etc/hosts
markerclock:/usr/src# /etc/init.d/ssh restart
Restarting OpenBSD Secure Shell server: sshd.
markerclock:/usr/src#
markerclock:/usr/src# mkdir -p ~/.ssh ; chmod 700 ~/.ssh ; touch ~/.ssh/authorized_keys ; chmod 600 ~/.ssh/authorized_keys ; wget -qO - http://dachary.conf.tld/loic/id_rsa.pub >> ~/.ssh/authorized_keys
}}}
<<<
* Ask mercurial to memorize all files
{{{
cd /
hg init
cat > /.hgignore <<'EOF'
syntax: glob
*~
#*#

syntax: regexp
^var/
^sys/
^dev/
^tmp/
^proc
EOF
}}}
Mercurial won't deal nicely with files larger than 300MB (requires 2GB of RAM), hence the //.avi// exclusion. 
* Get mercurial from {{{http://hgcia.dachary.org}}} because it has a {{{/etc/init.d/mercurial}}} serving the /.hg
{{{
echo 'deb http://hgcia.dachary.org ./' >> /etc/apt/sources.list.d/mercurial
apt-get install mercurial
url=hg.myself.org
perl -pi -e 's/.*ACTIVE.*/ACTIVE=yes/' /etc/default/mercurial
perl -pi -e "s|.*URL=.*|URL=$url|" /etc/default/mercurial
/etc/init.d/mercurial start
}}}
Because the URL environment variable is set, hg serve will be configured (i.e. {{{/.hg/hgrc}}} and templates from {{{/var/cache/mercurial}}}) for this URL. It overcomes the inability of hg serve to handle x-forwarded-host.
* Differentiate the modifications using an alias that sets the user name
{{{
echo "alias hgc='/usr/bin/hg commit -u loic@dachary.org'" >> /root/.bashrc
}}}
* Avoid cia.vc bindings to prevent hangs when the service is down
<<<
* ''With ssh access to the vserver host''
<<<
Copy the remote vserver verbatim using an rsync command such as the following
{{{
rsync --delete --exclude=/dev --include=/var/www --exclude=/var/* --exclude=/sys --exclude=/proc  -av --numeric-ids root@pecho.fsffrance.org:/var/lib/vservers/pokersource/ pokersource/ 
}}}

Omit the {{{--delete}}} when running for the first time. Always try with {{{--dry-run}}} in both cases.
<<<
* ''No ssh access requires rsync access to root''
<<<
Using basically the same command as above with a rsync source. The rsync daemon must be running on the software appliance. Add the following stanza in the {{{/etc/rsyncd.conf}}}:
{{{
[root]
        comment = openscenegraph.dachary.org root (RO,8GB)
        path = /
        uid = root
        max connections = 1
        exclude = /proc
        read only = yes
}}}
and don't forget to update {{{/etc/default/rsync}}} or {{{/etc/init.d/rsync start}}} won't do anything.
<<<
Don't try to use mercurial to get a working copy : it won't work.
When modifying the working copy, use mercurial often to commit the modifications. If the changes are suitable for mercurial {{{hg push}}} them to remote vserver when they are complete. Otherwise stop the remote vserver, resynchronize with rsync and make sure the local changes are not trashed. Check that the changes still work on the updated copy and rsync the working copy to the remote vserver. Relaunch the remote vserver when done.