Create your own Certificate Authority

This how-to is based on jamielinux.com.

Attachments can be downloaded here

Steps described in this document:

  • Creating a new, self-signed root CA from scratch
  • Create an intermediate CA using the root CA
  • Sign a server certificate
  • Sign a client certificate
  • Create a certificate revocation list (CRL)
  • Setup an OCSP responder behind an Apache proxy
  • Deploy certificates onto Apache webserver
  • Perform a number of tests using a browser

Setup Root CA

The root CA certificate only to sign other certificate authority certificates.

Prepare the Root CA directory

Setup a directory where everything related to the CA is managed.

mkdir -p /root/DemoCA/root
cd /root/DemoCA/root
mkdir certs csr crl newcerts private
chmod 700 private
touch index.txt
echo 1000 > serial
wget -O openssl.cnf " https://andre.bytesare.us/ca-demo-files/root-openssl.cnf "

Self-sign the root ca certificate

Using our openssl.cnf’s [ v3_ca ] extension:

cd /root/DemoCA/root
openssl genrsa -aes256 -out private/ca.key.pem 4096
openssl req -config openssl.cnf -key private/ca.key.pem -new -x509 -days 7300 -sha256 -extensions v3_ca -out certs/ca.cert.pem
# Subject: `C = AT, ST = Vienna, O = BytesAreUs GmbH, OU = BytesAreUs GmbH Certificate Authority, CN = BytesAreUs GmbH Root CA`

# Check:
openssl x509 -noout -text -in certs/ca.cert.pem

Setup an intermediate CA

Used for signing end-user certs.
Prepare the intermediate CA directory as below.

mkdir /root/DemoCA/intermediate-1
cd /root/DemoCA/intermediate-1
mkdir certs crl csr newcerts private
chmod 700 private
touch index.txt
touch index.txt.attr 
echo 1000 > serial
echo 1000 > crlnumber
wget -O openssl.cnf " https://andre.bytesare.us/ca-demo-files/intermediate-openssl.cnf "

Add/Modify these lines to the [ server_cert ] section in /root/ca/intermediate/openssl.cnf to specify CRL and OCSP Urls.

crlDistributionPoints = URI: http://ca-demo.bytesare.us/intermediate-1.crl.pem 
authorityInfoAccess   = OCSP;URI: http://ca-demo.bytesare.us/ocsp/intermediate-1 

Create the intermediate certificate

Using our openssl.cnf’s [ v3_intermediate_ca ] extension:

# Create csr:
cd /root/DemoCA/intermediate-1
openssl genrsa -aes256 -out private/intermediate-1.key.pem 4096
openssl req -config openssl.cnf -new -sha256 -key private/intermediate-1.key.pem -out csr/intermediate-1.csr.pem
# Subject: `C = AT, ST = Vienna, O = BytesAreUs GmbH, OU = BytesAreUs GmbH Certificate Authority, CN = BytesAreUs GmbH Intermediate CA 1`

# Sign csr with the root CA:
cd /root/DemoCA/root
openssl ca -config openssl.cnf -extensions v3_intermediate_ca -days 3650 -notext -md sha256 -in ../intermediate-1/csr/intermediate-1.csr.pem -out ../intermediate-1/certs/intermediate-1.cert.pem

# Check:
cd /root/DemoCA/intermediate-1
openssl x509 -noout -text -in certs/intermediate-1.cert.pem # check manually
openssl verify -CAfile ../root/certs/ca.cert.pem certs/intermediate-1.cert.pem
cat certs/intermediate-1.cert.pem ../root/certs/ca.cert.pem > certs/ca-chain.cert.pem

Create a server certificate

Using our openssl.cnf’s [ server_cert ] extension:

cd /root/DemoCA/intermediate-1
openssl genrsa -aes256 -out private/ca-demo.bytesare.us.key.pem 2048
openssl req -config openssl.cnf -key private/ca-demo.bytesare.us.key.pem -new -sha256 -out csr/ca-demo.bytesare.us.csr.pem
# Subject: `C = AT, ST = Vienna, O = BytesAreUs GmbH, OU = Web Services, CN = ca-demo.bytesare.us`
openssl ca -config openssl.cnf -extensions server_cert -days 375 -notext -md sha256 -in csr/ca-demo.bytesare.us.csr.pem -out certs/ca-demo.bytesare.us.cert.pem
# Check:
openssl x509 -noout -text -in certs/ca-demo.bytesare.us.cert.pem
openssl verify -CAfile certs/ca-chain.cert.pem certs/ca-demo.bytesare.us.cert.pem

(Optional) Create and revoke another server certificate

For testing purposes, create a new server certificate with the same
name like the existing one. It is needed later to test the OCSP responder.

cd /root/DemoCA/intermediate-1
openssl genrsa -aes256 -out private/revoked.ca-demo.bytesare.us.key.pem 2048
openssl req -config openssl.cnf -key private/revoked.ca-demo.bytesare.us.key.pem -new -sha256 -out csr/revoked.ca-demo.bytesare.us.csr.pem
# Subject: `C = AT, ST = Vienna, O = BytesAreUs GmbH, OU = Web Services, CN = ca-demo.bytesare.us`
openssl ca -config openssl.cnf -extensions server_cert -days 375 -notext -md sha256 -in csr/revoked.ca-demo.bytesare.us.csr.pem -out certs/revoked.ca-demo.bytesare.us.cert.pem
# Check:
openssl x509 -noout -text -in certs/revoked.ca-demo.bytesare.us.cert.pem
openssl verify -CAfile certs/ca-chain.cert.pem certs/revoked.ca-demo.bytesare.us.cert.pem

Revoke the server cert:

cd /root/DemoCA/intermediate-1
openssl ca -config openssl.cnf -revoke certs/revoked.ca-demo.bytesare.us.cert.pem

Sign a client certificate

The client cert should be created in three steps without sending the key over the wire:

  1. Client creates a CSR:

    # mkdir /home/carl
    cd /home/carl
    openssl genrsa -out This email address is being protected from spambots. You need JavaScript enabled to view it. 2048 
    openssl req -new -key This email address is being protected from spambots. You need JavaScript enabled to view it. -out This email address is being protected from spambots. You need JavaScript enabled to view it.
    Subject: `C= AT, ST = Tirol, L = Innsbruck, CN = Carl the tester, emailAddress = This email address is being protected from spambots. You need JavaScript enabled to view it.`
    cp This email address is being protected from spambots. You need JavaScript enabled to view it. /tmp/
    
  2. Then, client sends the CSR to the intermediate CA, who signs it.

    Using our openssl.cnf’s [ usr_cert ] extension:

    cd /root/DemoCA/intermediate-1
    cp /tmp/This email address is being protected from spambots. You need JavaScript enabled to view it. csr/
    openssl ca -config openssl.cnf -extensions usr_cert -notext -md sha256 -in csr/This email address is being protected from spambots. You need JavaScript enabled to view it. -out certs/This email address is being protected from spambots. You need JavaScript enabled to view it.
    cp certs/This email address is being protected from spambots. You need JavaScript enabled to view it. certs/ca-chain.cert.pem /tmp/
    
    # Check:
    openssl verify -CAfile certs/ca-chain.cert.pem certs/This email address is being protected from spambots. You need JavaScript enabled to view it.   
    
  3. CA returns certificate and chain to client

    Who converts it into pkcs12 format to import it to his browser:

    cd /home/carl
    cp /tmp/ca-chain.cert.pem /tmp/This email address is being protected from spambots. You need JavaScript enabled to view it. .
    cat This email address is being protected from spambots. You need JavaScript enabled to view it. ca-chain.cert.pem > This email address is being protected from spambots. You need JavaScript enabled to view it.
    openssl pkcs12 -export -inkey This email address is being protected from spambots. You need JavaScript enabled to view it. -in This email address is being protected from spambots. You need JavaScript enabled to view it. -out This email address is being protected from spambots. You need JavaScript enabled to view it.
    
    

(Optional) Create and revoke another client cert

For negative testing the CRL later, sign another client cert and revoke it.

# mkdir /home/luzifer
cd /home/luzifer
openssl genrsa -out This email address is being protected from spambots. You need JavaScript enabled to view it. 2048 
openssl req -new -key This email address is being protected from spambots. You need JavaScript enabled to view it. -out This email address is being protected from spambots. You need JavaScript enabled to view it.
Subject: `C= AT, ST = Tirol, L = Innsbruck, CN = Luzifer the Evil, emailAddress = This email address is being protected from spambots. You need JavaScript enabled to view it.`
cp This email address is being protected from spambots. You need JavaScript enabled to view it. /tmp/

cd /root/DemoCA/intermediate-1
cp /tmp/This email address is being protected from spambots. You need JavaScript enabled to view it. csr/
openssl ca -config openssl.cnf -extensions usr_cert -notext -md sha256 -in csr/This email address is being protected from spambots. You need JavaScript enabled to view it. -out certs/This email address is being protected from spambots. You need JavaScript enabled to view it.
cp certs/This email address is being protected from spambots. You need JavaScript enabled to view it. certs/ca-chain.cert.pem /tmp/

# Check:
openssl verify -CAfile certs/ca-chain.cert.pem certs/This email address is being protected from spambots. You need JavaScript enabled to view it.   

cd /home/luzifer
cp /tmp/ca-chain.cert.pem /tmp/This email address is being protected from spambots. You need JavaScript enabled to view it. .
cat This email address is being protected from spambots. You need JavaScript enabled to view it. ca-chain.cert.pem > This email address is being protected from spambots. You need JavaScript enabled to view it.
openssl pkcs12 -export -inkey This email address is being protected from spambots. You need JavaScript enabled to view it. -in This email address is being protected from spambots. You need JavaScript enabled to view it. -out This email address is being protected from spambots. You need JavaScript enabled to view it.

Now, revoke luzifer’s certificate:

cd /root/DemoCA/intermediate-1
openssl ca -config openssl.cnf -revoke certs/This email address is being protected from spambots. You need JavaScript enabled to view it.

Create a CRL

CRL files are used to check if a certificate has been revoked (offline).

cd /root/DemoCA/intermediate-1
openssl ca -config openssl.cnf -gencrl -out crl/intermediate-1.crl.pem

# Check:
openssl crl -in crl/intermediate-1.crl.pem -text
cat certs/ca-chain.cert.pem crl/intermediate-1.crl.pem > /tmp/chain+crl.pem
openssl verify -crl_check -CAfile /tmp/chain+crl.pem certs/ca-demo.bytesare.us.cert.pem
openssl verify -crl_check -CAfile /tmp/chain+crl.pem certs/revoked.ca-demo.bytesare.us.cert.pem

Create an OCSP responder certificate

OCSP is used for online checking the revocation status of a certificate.
Create a signer certificate to sign the OCSP responses:

cd /root/DemoCA/intermediate-1
openssl genrsa -aes256 -out private/ocsp.key.pem 4096
openssl req -config openssl.cnf -new -sha256 -key private/ocsp.key.pem -out csr/ocsp.csr.pem
# Subject: `C = AT, ST = Vienna, O = BytesAreUs GmbH, OU = BytesAreUs GmbH Certificate Authority, CN = BytesAreUs OCSP Signer CA 1`
openssl ca -config openssl.cnf -extensions ocsp -days 375 -md sha256 -in csr/ocsp.csr.pem -out certs/ocsp.cert.pem

# Check:
openssl verify -CAfile certs/ca-chain.cert.pem certs/ocsp.cert.pem
openssl ocsp -url  http://localhost :2560/ocsp -text -rmd sha256 -index index.txt -CA certs/ca-chain.cert.pem -rkey private/ocsp.key.pem -rsigner certs/ocsp.cert.pem -nrequest 2 |  grep -e "Serial Number:" -e "Cert Status:" -e "Update:"

# (using a 2nd terminal)
cd /root/DemoCA/intermediate-1
openssl ocsp -CAfile certs/ca-chain.cert.pem -url  http://localhost :2560/ocsp -issuer certs/intermediate-1.cert.pem -cert certs/ca-demo.bytesare.us.cert.pem
openssl ocsp -CAfile certs/ca-chain.cert.pem -url  http://localhost :2560/ocsp -issuer certs/intermediate-1.cert.pem -cert certs/revoked.ca-demo.bytesare.us.cert.pem

Deploy and test the setup

To demonstrate the use of our CA, setup Apache with

  • the server certificate
  • an OCSP responder proxy for checking the server certificate
  • a location that requires a client certificate
  • a CRL file to check client certificates

Apache Configuration

Copy certificate material to a directory that apache user can access.

cd /root/DemoCA/intermediate-1
mkdir /etc/ssl/test-certs
cp certs/ca-chain.cert.pem certs/ca-demo.bytesare.us.cert.pem certs/revoked.ca-demo.bytesare.us.cert.pem private/ca-demo.bytesare.us.key.pem private/revoked.ca-demo.bytesare.us.key.pem crl/intermediate-1.crl.pem /etc/ssl/test-certs/

Apache needs the private key converted without a password,
otherwise the password has to be entered at every start.

cd /etc/ssl/test-certs/
openssl rsa -in ca-demo.bytesare.us.key.pem  -out ca-demo.bytesare.us.nopass.key.pem
openssl rsa -in revoked.ca-demo.bytesare.us.key.pem -out revoked.ca-demo.bytesare.us.nopass.key.pem
chown root:www-data -R .
chmod 640 *
cp intermediate-1.crl.pem /var/www/html/

Setup your local system

We pretend to be ca-demo.bytesare.us, and try it on the local machine.
Add the following line to your hosts file:

127.0.0.1 ca-demo.bytesare.us

Setup Apache

The proxy for the OCSP responder is set up on port 80
in /etc/apache2/sites-enabled/000-default.conf:

<VirtualHost *:80>
    ServerName ca-demo.bytesare.us
    DocumentRoot /var/www/html

    LogLevel info
    ErrorLog ${APACHE_LOG_DIR}/demo-ca.http.error.log
    CustomLog ${APACHE_LOG_DIR}/demo-ca.http.access.log combined

    <Location /ocsp/intermediate-1>
        ProxyPass  http://127.0.0.1 :2560/
    </Location>
</VirtualHost>

The server certificate and the client crl and trusted ca is configured
in /etc/apache2/sites-enabled/default-ssl.conf:

<IfModule mod_ssl.c>
<VirtualHost *:443>
    ServerName ca-demo.bytesare.us
    DocumentRoot /var/www/html-ssl

    LogLevel info ssl:debug
    ErrorLog ${APACHE_LOG_DIR}/demo-ca.ssl.error.log
    CustomLog ${APACHE_LOG_DIR}/demo-ca.ssl.access.log combined

    # Server certificate configuration:
    SSLEngine on
    SSLCertificateChainFile /etc/ssl/test-certs/ca-chain.cert.pem
    #SSLCertificateFile      /etc/ssl/test-certs/ca-demo.bytesare.us.cert.pem
    #SSLCertificateKeyFile   /etc/ssl/test-certs/ca-demo.bytesare.us.nopass.key.pem
    SSLCertificateFile     /etc/ssl/test-certs/revoked.ca-demo.bytesare.us.cert.pem
    SSLCertificateKeyFile  /etc/ssl/test-certs/revoked.ca-demo.bytesare.us.nopass.key.pem

    # Client certificate configuration:
    SSLCACertificateFile     /etc/ssl/test-certs/ca-chain.cert.pem
    SSLCARevocationFile      /etc/ssl/test-certs/intermediate-1.crl.pem
    SSLCARevocationCheck     leaf
    # Require a client cert (only) in /protected-area:
    SSLVerifyClient none
    <Location /protected-area>
        SSLVerifyClient require
        SSLVerifyDepth  10
    </Location>

</VirtualHost>
</IfModule>

Restart apache

After the configuration has been changed.

apachectl configtest 
systemctl restart apache2

Start the OCSP Responder process

And test the responder using the ca-demo.bytesare.us domain routed through the Apache listenting on localhost.

cd /root/DemoCA/intermediate-1
openssl ocsp -url  http://localhost :2560/ocsp -text -rmd sha256 -index index.txt -CA certs/ca-chain.cert.pem -rkey private/ocsp.key.pem -rsigner certs/ocsp.cert.pem > /var/log/apache2/demo-ca.ocsp.log

# Check if apache proxies ocsp correctly (in a second terminal)
cd /root/DemoCA/intermediate-1
openssl ocsp -CAfile /etc/ssl/test-certs/ca-chain.cert.pem -url  http://ca-demo.bytesare.us/ocsp/intermediate-1  -issuer /etc/ssl/test-certs/ca-chain.cert.pem -cert /etc/ssl/test-certs/ca-demo.bytesare.us.cert.pem 

Import the Intermediate CA certificate to a browser

In a company environment, the client administrator sets the root CA as trusted,
in our test case we will do this by hand in our browser only.

Copy cert chain to a readable location:

cd /root/DemoCA/intermediate-1
cp certs/ca-chain.cert.pem /tmp/
chmod +r /tmp/ca-chain.cert.pem

In firefox, open Settings, goto Privacy and Security, click on View Certificates and open the tab Authorities.
Then, import the ca-chain.pem file to accept our CA. Check if the Intermediate CA has been added to the list after the import.

Import the client certificate to a browser

Copy client certs to a readable location:

cp /home/carl/This email address is being protected from spambots. You need JavaScript enabled to view it. /home/luzifer/This email address is being protected from spambots. You need JavaScript enabled to view it. /tmp/
chmod +r /tmp/*.cert.p12

In firefox, open Settings, goto Privacy and Security, click on View Certificates and open the tab Your Certificates.
Then, import the This email address is being protected from spambots. You need JavaScript enabled to view it. file. Check if the client cert has been added to the list after the import.
Optionally, import the This email address is being protected from spambots. You need JavaScript enabled to view it. file. Check if the client cert has been added to the list after the import.

Showtime: Perform connection tests with your browser

Look at the Apache logs while doing this:

tail -fn0 /var/log/apache2/demo-ca*.log /var/log/apache2/ocsp.log

1. Check the browser connection to the https page

Open up the test page, it should load without errors.
Check the server certificate next to the address bar visually.

You should see in your apache logs, that the browser has also sent an OCSP request to our responder.

==> /var/log/apache2/demo-ca.http.access.log <==
127.0.0.1 - - [22/Mar/2019:20:11:17 +0100] "POST /ocsp/intermediate-1 HTTP/1.1" 200 2594 "-" "Mozilla/5.0 (X11; Linux x86_64; rv:67.0) Gecko/20100101 Firefox/67.0"

==> /var/log/apache2/demo-ca.ssl.access.log <==
127.0.0.1 - - [22/Mar/2019:20:11:17 +0100] "GET / HTTP/1.1" 200 6163 "-" "Mozilla/5.0 (X11; Linux x86_64; rv:67.0) Gecko/20100101 Firefox/67.0"

2. Check browser connection with client cert

Open up the location that requires client authentication and use the imported client certificate named carl.

The logs show the successful CRL check:

==> /var/log/apache2/demo-ca.ssl.error.log <==
[Fri Mar 22 20:32:09.087400 2019] [ssl:debug] [pid 30421:tid 140481960511232] ssl_engine_kernel.c(1585): [client 127.0.0.1:36704] AH02275: Certificate Verification, depth 0, CRL checking mode: leaf (1) [subject: emailAddress=This email address is being protected from spambots. You need JavaScript enabled to view it.,CN=Carl der Tester,L=Innsbruck,ST=Tirol,C=AT / issuer: CN=BytesAreUs GmbH Intermediate CA 1,OU=BytesAreUs GmbH Certificate Authority,O=BytesAreUs GmbH,ST=Vienna,C=AT / serial: 1001 / notbefore: Mar 22 16:13:37 2019 GMT / notafter: Mar 31 16:13:37 2020 GMT]

==> /var/log/apache2/demo-ca.ssl.access.log <==
127.0.0.1 - - [22/Mar/2019:20:32:06 +0100] "GET /protected-area/ HTTP/1.1" 200 13479 " https://ca-demo.bytesare.us/ " "Mozilla/5.0 (X11; Linux x86_64; rv:67.0) Gecko/20100101 Firefox/67.0"

3. Check browser connection with a revoked client cert

Open up the location that requires client authentication and use the imported client certificate named luzifer.

The Browser refuses access indicating the revocation:

Secure Connection Failed

An error occurred during a connection to ca-demo.bytesare.us.
SSL peer rejected your certificate as revoked.
Error code: SSL_ERROR_REVOKED_CERT_ALERT

The server logs show an error 403 and the revocation error:

==> /var/log/apache2/demo-ca.ssl.error.log <==
[Fri Mar 22 20:36:53.040334 2019] [ssl:info] [pid 30421:tid 140481728079616] [client 127.0.0.1:36716] AH02276: Certificate Verification: Error (23): certificate revoked [subject: emailAddress=This email address is being protected from spambots. You need JavaScript enabled to view it.,CN=Luzifer der Teufel,L=Innsbruck,ST=Tirol,C=AT / issuer: CN=BytesAreUs GmbH Intermediate CA 1,OU=BytesAreUs GmbH Certificate Authority,O=BytesAreUs GmbH,ST=Vienna,C=AT / serial: 1002 / notbefore: Mar 22 16:20:39 2019 GMT / notafter: Mar 31 16:20:39 2020 GMT]

[Fri Mar 22 20:36:53.040622 2019] [ssl:error] [pid 30421:tid 140481728079616] SSL Library Error: error:1417C086:SSL routines:tls_process_client_certificate:certificate verify failed

==> /var/log/apache2/demo-ca.ssl.access.log <==
127.0.0.1 - - [22/Mar/2019:20:36:49 +0100] "GET /protected-area/ HTTP/1.1" 403 11114 " https://ca-demo.bytesare.us/ " "Mozilla/5.0 (X11; Linux x86_64; rv:67.0) Gecko/20100101 Firefox/67.0"

4. Check browser connection to a page with a revoked server cert

If you use the revoked server certificate on apache,
(just uncomment the two revoked. lines in the apache config file and restart the server)
the browser will reject access because of the negative OCSP query.

Secure Connection Failed

An error occurred during a connection to ca-demo.bytesare.us.
Peer’s Certificate has been revoked.
Error code: SEC_ERROR_REVOKED_CERTIFICATE

The server logs show the start of a TLS handshake, then the negative OCSP Response.
No actual https response shows up, because the browser terminated the handshake:

==> /var/log/apache2/demo-ca.ssl.error.log <==
[Fri Mar 22 20:50:17.207959 2019] [ssl:info] [pid 32219:tid 140240362641152] [client 127.0.0.1:36828] AH01964: Connection to child 8 established (server ca-demo.bytesare.us:443)

[Fri Mar 22 20:50:17.224830 2019] [ssl:debug] [pid 32219:tid 140240362641152] ssl_engine_kernel.c(2067): [client 127.0.0.1:36828] AH02041: Protocol: TLSv1.2, Cipher: ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)

==> /var/log/apache2/demo-ca.http.access.log <==
127.0.0.1 - - [22/Mar/2019:20:50:17 +0100] "POST /ocsp/intermediate-1 HTTP/1.1" 200 2612 "-" "Mozilla/5.0 (X11; Linux x86_64; rv:67.0) Gecko/20100101 Firefox/67.0"

==> /var/log/apache2/demo-ca.ocsp.log <==
OCSP Response Data:
    Produced At: Mar 22 19:50:17 2019 GMT
    Certificate ID:
      Serial Number: 1003
    Cert Status: revoked
    Revocation Time: Mar 22 16:25:49 2019 GMT

==> /var/log/apache2/demo-ca.ssl.error.log <==
[Fri Mar 22 20:50:17.262845 2019] [ssl:debug] [pid 32219:tid 140240362641152] ssl_engine_io.c(1103): [client 127.0.0.1:36828] AH02001: Connection closed to child 8 with standard shutdown (server ca-demo.bytesare.us:443)

Create your own dyndns for your home computer

Setup

Some people want to reach their home computer from the internet but find themselves in the following setup:

  • A home computer with a public IP address that can change/is unreliable.
  • A host reachable by a reliable public IP address or even better: a domain name.
  • A router at home that supports port forwarding.
  • No want to register or pay for a dyndns providers.

In such scenarios, we can make the home computer accessible through the public host:

  1. Setup port forwarding on public host so traffic of a port goes to the home computers.
  2. Configure home router to forward traffic of one port to the home computer in the LAN.
  3. Ensure that the system is aware of a public IP address change of the home computer.

Home computer setup

This script is stored on the home computer we want to reach from the public internet, it will update the IP address on the remote computer (which performs the port forwarding).

/home/andre/bin/update-my-ip.sh

#!/bin/bash

# ensures a remote computer gets to know this computer's ip
# to implement an ip forwarding.
#
# this script determines this computer's public ip and compate it
# to an ip address stored in a file on a remote computer.
# if the stored ip is different to the current public ip,
# the new ip will be written into the file on the remote computer.

# configuration of ssh connections to remote host
REMOTE_SSH_USER="remoteUsername"
REMOTE_SSH_PORT="22"
REMOTE_SSH_HOST="example.com"

REMOTE_IP_FILE="ssh-forwarding-ip.txt" # assuming file is in home directory
REMOTE_EXEC="ssh $REMOTE_SSH_USER@$REMOTE_SSH_HOST -p $REMOTE_SSH_PORT"

check_ip() {
    if (echo "$1" | grep -qE '[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}'); then
        return 0
    fi
    echo "ERROR: invalid ip: '$1'"
    return 1
}

# resolve public ip and see what is configured on the remote host:
current_ip="$( dig +short myip.opendns.com @resolver1.opendns.com )"
remote_ip="$( $REMOTE_EXEC "cat ~/$REMOTE_IP_FILE" )"
echo -n "$(date '+%F %T') current_ip: $current_ip remote_ip: $remote_ip "
check_ip $current_ip || exit 10 # quit if ip does not look valid
check_ip $remote_ip || exit 20 # quit if ip does not look valid

# compare ips, quit if no change is necessary:
if [ "$current_ip" = "$remote_ip" ]; then
    echo "Nothing to do, remote IP matches current."
    exit 0
fi

# writing new ip to remote file:
$REMOTE_EXEC "
    cp -v $REMOTE_IP_FILE .$REMOTE_IP_FILE-until-$(date +%F_%T) \
    && echo $current_ip > $REMOTE_IP_FILE \
    && echo $REMOTE_IP_FILE written"

To make sure the IP stored on the remote computer is always up to date,
create a cronjob that invokes the script above once a minute on the home computer:

andre@nairobi ~ % crontab -e
# once per minute: maintain the IP of this computer on bytesare.us, for the port forwarding:
* * * * * bash /home/andre/bin/update-my-ip.sh 2>&1 >> /home/andre/log/update-my-ip.log

Public computer setup

<

p>After almost every holiday i find myself in the same problem:

<

p>

I have made pictures with multiple cameras, phones and maybe there are some pics sent by friends.
Every camera has its own pattern how the files are named, if you want to watch them chronologically, you can sort them by hand or you use the jpeg timestamp and some lines of shell code:

#!/bin/bash

TARGET="/tmp/chronosort-`date +%F`-$RANDOM"
mkdir "$TARGET"
echo "target directory: $TARGET"


find . -type f | while read PIC; do
    echo PIC: ${PIC}
    if [ -f "$PIC" ]; then # see if PIC is a file
        if [[ "$(file -b --mime-type "$PIC" )" == "image/jpeg" ]]; then
            TIMESTAMP_STRING=$(exiv2 "$PIC" | grep -i timestamp | grep -Eo "[0-9].*[0-9]")
#            echo "timestamp string from exif data: $TIMESTAMP_STRING"

            # convert the exif string to a date:
            DATE="$(
                date -d "$(
                    echo ${TIMESTAMP_STRING} \
                    | sed 's|\([0-9]*\):\([0-9]*\):\([0-9]*\) \([0-9]*\):\([0-9]*\):\([0-9]*\)|\1/\2/\3 \4:\5:\6|g'
                )"
            )"

            # apply offset for specific camera model (optional)
            if ( exiv2 "$PIC" | grep "Camera" | grep -qi "casio" ); then
                echo modifying time for casio camera...
#                DATE="$( date -d "$DATE -31 minutes" )"
            fi
            echo "DATE: ${DATE}"


            DATE_FILENAME=$( date -d "$DATE" "+%Y-%m-%d_%H:%M:%S" )
            TARGET_NAME="${DATE_FILENAME}__$(basename "$PIC" )"
            TARGET_FILE="$TARGET/$TARGET_NAME"
#            echo TARGET_FILE: $TARGET_FILE

            # create dir if needed:
            mkdir -pv "$(dirname "$TARGET_FILE" )"

            cp -v "$PIC" "$TARGET_FILE"
        else
            echo "Not a file, skipping $PIC....."
        fi
        echo
    fi
done

PROBLEM

in terminals, the home and end keys are not working when zsh is the shell. for bash it works in the same terminal, so must be possible to use those keys. must have been something that does bash differently than zsh.

INVESTIGATION

the documentation says zsh uses "terminfo" to configure its keybindings:

andre@nairobi ~ % vim /etc/zsh/zshrc
key=(
    Home     "${terminfo[khome]}"
    End      "${terminfo[kend]}"
    Insert   "${terminfo[kich1]}"
    Delete   "${terminfo[kdch1]}"
    Up       "${terminfo[kcuu1]}"
    Down     "${terminfo[kcud1]}"
    Left     "${terminfo[kcub1]}"
    Right    "${terminfo[kcuf1]}"
    PageUp   "${terminfo[kpp]}"
    PageDown "${terminfo[knp]}"
    BackTab  "${terminfo[kcbt]}"
)

on my system, the khome and kend variables are not set:

andre@nairobi ~ % for k in "${(@k)terminfo}"; do echo $k; done | sort | grep -E '(khome|kend|kich1|kbs|kdch1|kcuu1|kcud1|kcub1|kcuf1|kpp|knp)'
kbs
kcub1
kcud1
kcuf1
kcuu1
kdch1
kich1
knp
kpp

but why? lets see how the terminfo database is built.

andre@nairobi /etc/terminfo % cat README
This directory is for system-local terminfo descriptions. By default,
ncurses will search ${HOME}/.terminfo first, then /etc/terminfo (this
directory), then /lib/terminfo, and last not least /usr/share/terminfo.

let's see what terminfo applies currently. that one we will try to fix.

andre@nairobi /lib/terminfo % echo $TERM
xterm-color

find the config file:

andre@nairobi /lib/terminfo % for i in ${HOME}/.terminfo /etc/terminfo /lib/terminfo /usr/share/terminfo; do echo; echo "$i"; find $i -type f -name "xterm-color" -ls; done

/home/andre/.terminfo
find: `/home/andre/.terminfo': No such file or directory

/etc/terminfo

/lib/terminfo
1049857    4 -rw-r--r--   1 root     root         1569 Sep 17  2014 /lib/terminfo/x/xterm-color

/usr/share/terminfo

check what is set in this terminfo entry:
we can see the same keys as they are listed above.

andre@nairobi ~ % infocmp
============ xterm-color | grep -Eo '(khome|kend|kich1|kbs|kdch1|kcuu1|kcud1|kcub1|kcuf1|kpp|knp)=[^,]*,' | sort
kbs=\177,
kcub1=\EOD,
kcud1=\EOB,
kcuf1=\EOC,
kcuu1=\EOA,
kdch1=\E[3~,
kich1=\E[2~,
knp=\E[6~,
kpp=\E[5~,

SOLUTION

lets see if we can add the missing capability into the terminfo database.
as shown here: https://www.jbase.com/r5/knowledgebase/howto/general/common/CreateTerminfo/modify.htm

we can start with a copy in ${HOME}/.terminfo dir to start experimenting, without modifying system files.

but first we need to find out what are the proper sequences we add.
when pressing left-arrow, right-arrow, bild-auf, bild-ab, home and end using showkey -a, i get this output:

andre@nairobi ~/tmp % showkey -a
Press any keys - Ctrl-D will terminate this program
^[[D     27 0033 0x1b    # left-arrow
^[[C     27 0033 0x1b    # right-arrow
^[[5~    27 0033 0x1b    # page up
^[[6~    27 0033 0x1b    # page down
^[[H     27 0033 0x1b    # home
^[[F     27 0033 0x1b    # end

looks like we can add the entries of home and end like this.
e.g. Left-Arrow cursor key:

output of showkey -a:              "^[[D"
corresponding entry in dump: "kcub1=\EOD,"

i guess we can replace the "^[[" by "\EO" to obtain the correct values for khome and kend. lets dump the entry and modify it:

andre@nairobi ~ % cd ~/tmp/
andre@nairobi ~/tmp % infocmp xterm-color > xterm-color.ti
andre@nairobi ~/tmp % cp xterm-color.ti xterm-color.ti.orig
andre@nairobi ~/tmp % vim xterm-color.ti

the keys in the dump file are sorted, lets add it in order:

for Home: add "khome=\EOH, " between "kfnd=\E[1~, kich1=\E[2~":
for End:  and "kend=\EOF, "  between "kdch1=\E[3~, kf1=\E[11~,":

in my case, the modifications were:

andre@nairobi ~/tmp % diff xterm-color.ti xterm-color.ti.orig
15c15
<       kdch1=\E[3~, kend=\EOF, kf1=\E[11~, kf10=\E[21~, kf11=\E[23~,
---
>       kdch1=\E[3~, kf1=\E[11~, kf10=\E[21~, kf11=\E[23~,
20c20
<       kfnd=\E[1~, khome=\EOH, kich1=\E[2~, kmous=\E[M, knp=\E[6~, kpp=\E[5~,
---
>       kfnd=\E[1~, kich1=\E[2~, kmous=\E[M, knp=\E[6~, kpp=\E[5~,

compile the .ti file and check if it was created in the users terminfo:

andre@nairobi ~/tmp % mkdir -p ${HOME}/.terminfo/x
andre@nairobi ~/tmp % tic xterm-color.ti
andre@nairobi ~/tmp % find ~/.terminfo -type f -ls
1329052    4 -rw-r--r--   1 andre    andre        1443 Mar 18 13:20 /home/andre/.terminfo/x/xterm-color

make sure you have this in your .zshrc or /etc/zsh/zshrc:

# put cursor to end of line when end is pressed
bindkey "${key[End]}" end-of-line

# put cursor to start of line when home is pressed
bindkey "${key[Home]}" beginning-of-line

start a new xterm (! note, not only a new shell in the same terminal) and check if the keys are now present:

andre@nairobi ~ % infocmp xterm-color | grep -Eo '(khome|kend|kcub1)=[^,]*,' | sort
kcub1=\EOD,
kend=\EOF,
khome=\EOH,

now, check if your home and end keys are finally working!

!!!!! YES, AFTER SO MANY YEARS !!!!!

Acer TravelMate 290 - How to install acerhk to make the wlan switch working in ubuntu?

http://wiki.ubuntuusers.de/Acer_Hotkeys

lets try this with 10.04/10.10:

http://forum.ubuntuusers.de/topic/acer-travelmate-291lci-funknetzwerk-nicht-akti/2/#post-2670605

install ubuntu 10.04, then follow these steps:

add-apt-repository ppa:gruenertee/acerhk apt-get install --reinstall linux-headers-$(uname -r) build-essential acerhk-source tar -xvjf acerhk.tar.bz2 vim /usr/src/linux-headers-$(uname -r)/Makefile

look for this near line 564:

ifdef CONFIG_FUNCTION_TRACER # KBUILD_CFLAGS += -pg <------ comment this line endif cd /usr/src/modules/acerhk make cp -v acerhk.ko /lib/modules/$(uname -r)/kernel/ubuntu/ depmod -a

a good idea is to look at the log files in a second terminal during next step:

find /var/log -type f | grep -v -e ".gz$" -e ".[0-9]*$" | xargs tail -fqn

enable wifi module

modprobe acerhk force_series=290 usedritek=1 verbose=1 echo 1 > /proc/driver/acerhk/wirelessled