Let’s Encrypt SSL certificate without root or sudo privileges

Five days ago we had to renew a number of SSL certificates using free Let’s Encrypt SSL authority to a few Apache servers which were installed in Jelastic PaaS environment. The Apache servers were installed in an environment where:

  1. We did have SSH access.
  2. We did not have any root privileges or sudo command permission.
  3. The SSH access was done using a limited apache user.
  4. The underlying operating system was CentOS release 6.6 (Final) . (found out about it by running: cat /etc/centos-release)

Thus we could not use the official Let’s Encrypt client as it requires root privileges. After 3 hours of searching and striving to use multiple client implementations, we stumbled upon letsencrypt.sh. With the guidance of a tutorial written in German!! we finally managed to create our SSL certificates. So today, at last, we will show you how!!!

In this example, we assume that our domain name is bobos.org. We want to create a certificate for bobos.org and www.bobos.org. Note that Let’s Encrypt does not generate wildcard certificates yet!!.

Prerequisites

  1. No root access or sudo is required.
  2. We Obtain an A record for bobos.org and http://www.bobos.org which points to the IP of the server you are using.
  3. Inside the aforementioned server we have to run a web server which listens to port 80. Listening to port 443 is optional.
  4. Shell access to the server.

If you want to have a thourough understanding of why we are going to perform the following steps, you can refer to How it works official article. Few! It is high time we started. Shall we?

  1. Know thy environment.
  2. Clone letsecrypt.sh script.
  3. Configure the script.
  4. Configure your web server.
  5. Run the script.
  6. Find the certificates.
  7. Configure your web server to use the certificates
  8. Upload SSL certificates to Jelastic Administration Panel
  9. Reload or restart web server and test configuration

Know thy environment

After login via SSH we are in /var/www/ directory:

apache@apache2 ~ $ pwd
/var/www

Then we check CentOS version, because we can!

apache@apache2 ~ $ cat /etc/centos-release 
CentOS release 6.6 (Final)

Clone letsecrypt.sh script

While being in that directory we clone letsencrypt.sh:

apache@apache2 ~ $ git clone https://github.com/lukas2511/letsencrypt.sh.git
Cloning into 'letsencrypt.sh'...
remote: Counting objects: 873, done.
remote: Total 873 (delta 0), reused 0 (delta 0), pack-reused 873
Receiving objects: 100% (873/873), 223.44 KiB | 0 bytes/s, done.
Resolving deltas: 100% (530/530), done.
Checking connectivity... done.
apache@apache2 ~ $ chown -R apache:apache letsencrypt.sh
apache@apache2 ~ $ cd letsencrypt.sh
apache@apache2 ~ $ pwd
/var/www/etsencrypt.sh

Configure the script

Then, we have perform a little configuration so the script is aware of our environment and the domains for which we want to generate free SSL certificates:

  1. Prepare base and conf directories:
    apache@apache2 ~/letsencrypt.sh $ mkdir conf 
    apache@apache2 ~/letsencrypt.sh $ mkdir base
    apache@apache2 ~/letsencrypt.sh $ cp config.sh.example conf/config.sh
    apache@apache2 ~/letsencrypt.sh $ cp domains.txt.exampleconfig.sh.example conf/domains.txt
    
  2. Edit configuration in /var/www/letsencrypt.sh/conf/config.sh:
    CONFIG_D="/var/www/letsencrypt.sh"
    BASEDIR="/var/www/letsencrypt.sh/base"
    WELLKNOWN="${BASEDIR}/.acme-challenges"
    CONTACT_EMAIL="aValidEmail@whateverServer.com"
    
  3. Add the domain names in /var/www/letsencrypt.sh/conf/domains.txt“`:
    bobos.org www.bobos.org
    

Configure your web server

Now we have to put the following lines in your site’s special apache conf i.e. /etc/httpd/sites-available/bobos.conf or in /etc/httpd/conf/httpd.conf. This will help Let’s Encrypt to access your server, perform domain validation and perform some challenges in order to generate our SSL certificate.

Alias /.well-known/acme-challenge /var/www/letsencrypt.sh/base/.acme-challenges

<Directory /var/www/letsencrypt.sh/base/.acme-challenges>
        Options None
        AllowOverride None
        Order allow,deny
        Allow from all
</Directory>

Run the script

apache@apache2 ~/letsencrypt.sh $ ./letsencrypt.sh --config /var/www/letsencrypt.sh/conf/config.sh -c
# INFO: Using main config file /var/www/letsencrypt.sh/conf/config.sh
# INFO: Using additional config file /var/www/letsencrypt.sh/conf/config.sh
Processing bobos.org with alternative names: www.bobos.org
 + Signing domains...
 + Creating new directory /var/www/letsencrypt.sh/base/certs/bobos.org ...
 + Generating private key...
 + Generating signing request...
 + Requesting challenge for bobos.org...
 + Requesting challenge for www.bobos.org...
 + Responding to challenge for bobos.org...
 + Challenge is valid!
 + Responding to challenge for www.bobos.org...
 + Challenge is valid!
 + Requesting certificate...
 + Checking certificate...
 + Done!
 + Creating fullchain.pem...
 + Done!

Find the certificates

The certificates are created in $BASE/certs// directory:

apache@apache2 ~/letsencrypt.sh $ ls -l base/certs/bobos.org/
total 20
-rw------- 1 apache apache 1655 Jul  7 06:49 cert-1457333387.csr
-rw------- 1 apache apache 2143 Jul  7 06:49 cert-1457333387.pem
lrwxrwxrwx 1 apache apache   19 Jul  7 06:50 cert.csr -> cert-1457333387.csr
lrwxrwxrwx 1 apache apache   19 Jul  7 06:50 cert.pem -> cert-1457333387.pem
-rw------- 1 apache apache 1675 Jul  7 06:50 chain-1457333387.pem
lrwxrwxrwx 1 apache apache   20 Jul  7 06:50 chain.pem -> chain-1457333387.pem
-rw------- 1 apache apache 3818 Jul  7 06:50 fullchain-1457333387.pem
lrwxrwxrwx 1 apache apache   24 Jul  7 06:50 fullchain.pem -> fullchain-1457333387.pem
-rw------- 1 apache apache 3243 Jul  7 06:49 privkey-1457333387.pem
lrwxrwxrwx 1 apache apache   22 Jul  7 06:50 privkey.pem -> privkey-1457333387.pem

Configure your web server to use the certificates

Configure Apache in order to use the created certificates. It might by your site's special conf i.e. /etc/httpd/sites-available/bobos.conf or global /etc/httpd/conf/httpd.conf:

SSLEngine On
SSLCertificateFile      /var/www/letsencrypt.sh/base/certs/bobos.org/cert.pem
SSLCertificateKeyFile   /var/www/letsencrypt.sh/base/certs/bobos.org/privkey.pem
SSLCertificateChainFile /var/www/letsencrypt.sh/base/certs/bobos.org/chain.pem
SSLCACertificateFile    /var/www/letsencrypt.sh/base/certs/bobos.org/fullchain.pem
SSLHonorCipherOrder On
SSLCipherSuite ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA:ECDHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES128-SHA256:DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES256-GCM-SHA384:AES128-GCM-SHA256:AES256-SHA256:AES128-SHA256:AES256-SHA:AES128-SHA:DES-CBC3-SHA:HIGH:!aNULL:!eNULL:!EXPORT:!DES:!MD5:!PSK:!RC4

IMPORTANT NOTE!! The previous configuration will not work in Jelastic Paas environment, as it forces us to add the certificates via Jelastic Administration Panel. Jelastic puts the certificates to /var/lib/jelastic/SSL.

SSLEngine on

SSLProtocol ALL -SSLv2 -SSLv3
SSLHonorCipherOrder On
SSLCipherSuite ECDH+AESGCM:DH+AESGCM:ECDH+AES256:DH+AES256:ECDH+AES128:DH+AES:ECDH+3DES:DH+3DES:RSA+AESGCM:RSA+AES:RSA+3DES:!aNULL:!MD5:!DSS

SSLCertificateFile /var/lib/jelastic/SSL/jelastic.crt
SSLCertificateKeyFile /var/lib/jelastic/SSL/jelastic.key
SSLCACertificateFile /var/lib/jelastic/SSL/jelastic-ca.crt

Upload SSL certificates to Jelastic Administration Panel

Then we have to upload SSL certificates to Jelastic Administration Panel. To achieve that you can use this guide. Otherwise (i.e. putting files via SSH) it will not work.

Reload or restart web server and test configuration

Finally we reload sudo /etc/init.d/apache2 reload or restart (sudo /etc/init.d/apache2 restart) Apache web server and verify that https://bobos.org works.

That is all folks! Greetings from a hot and striving for the best Greece!

Posted in Apache, HTTP, Linux | Tagged , , , , , , , , , , , , , | Leave a comment

Migrate a Gitlab Docker container from version 8.0.4 to 8.2.0

Update 2016-05-13: The following procedure works perfectly for migrations from version 8.0.4 to 8.7.5

A few days ago, I had to migrate a Gitlab instance installed in Docker from version 8.04 to 8.2.0. I followed the exact steps described in GitLab Docker images documentation. But it was not so easy! Of cource, it required some more! Thus, after 4 hours of errors, searching and trials I found the way! Thank god!

In this article we will make the assumption that Gitlab volumes are stored in /home/bob/docker-data/gitlab directory. Here are the exact steps I followed to make a successful migration:

  1. Stop docker container
    docker stop gitlab
    
  2. Backup docker volumes (all gitlab files)
    backupDate=$(date +"%Y%m%d%H%M%S") \
      && cd /home/bob/docker-data/ \
      && sudo tar zvcf gitlab-data-${backupDate}.tar.gz gitlab/
    
  3. Optionally backup docker image
    docker save -o /home/bob/gitlab-ce-image.tar gitlab/gitlab-ce:latest
    
  4. Remove docker container
    docker rm gitlab
    
  5. Download the latest Gitlab docker image
    sudo docker pull gitlab/gitlab-ce:latest
    
  6. After the image is downloaded create and run the container
    docker run -d \
      --hostname 192.168.1.1 \
      --publish 8443:443 --publish 8082:80 --publish 2224:22 \
      --name gitlab \
      --restart always \
      --volume /etc/localtime:/etc/localtime \
      --volume /home/bob/docker-data/gitlab/config:/etc/gitlab \
      --volume /home/bob/docker-data/gitlab/logs:/var/log/gitlab \
      --volume /home/bob/docker-data/gitlab/data:/var/opt/gitlab \
      gitlab/gitlab-ce:latest
    
  7. The container starts and we observer the logs via:
    docker logs -f --tail 10 gitlab
    
  8. The docker container started and we observed in the logs:
    [2015-11-26T15:12:26+02:00] INFO: Retrying execution of execute[create gitlab database user], 19 attempt(s) left
    [2015-11-26T15:12:28+02:00] INFO: Retrying execution of execute[create gitlab database user], 18 attempt(s) left
    ... (some lines omitted) ...
    [2015-11-26T15:13:09+02:00] INFO: Retrying execution of execute[create gitlab database user], 0 attempt(s) left
    
    
    Error executing action `run` on resource 'execute[create gitlab database user]'
    
    
    Mixlib::ShellOut::ShellCommandFailed
    
    Expected process to exit with [0], but received '2'
    ---- Begin output of /opt/gitlab/embedded/bin/psql --port 5432 -h /var/opt/gitlab/postgresql -d template1 -c "CREATE USER gitlab" ----
    STDOUT: 
    STDERR: psql: could not connect to server: No such file or directory
    Is the server running locally and accepting
    connections on Unix domain socket "/var/opt/gitlab/postgresql/.s.PGSQL.5432"?
    ---- End output of /opt/gitlab/embedded/bin/psql --port 5432 -h /var/opt/gitlab/postgresql -d template1 -c "CREATE USER gitlab" ----
    Ran /opt/gitlab/embedded/bin/psql --port 5432 -h /var/opt/gitlab/postgresql -d template1 -c "CREATE USER gitlab" returned 2
    
    Resource Declaration:
    
    # In /opt/gitlab/embedded/cookbooks/cache/cookbooks/gitlab/recipes/postgresql.rb
    
    153:   execute "create #{sql_user} database user" do
    154:     command "#{bin_dir}/psql --port #{pg_port} -h #{postgresql_socket_dir} -d template1 -c \"CREATE USER #{sql_user}\""
    155:     user postgresql_user
    156:     # Added retries to give the service time to start on slower systems
    157:     retries 20
    158:     not_if { !pg_helper.is_running? || pg_helper.user_exists?(sql_user) }
    159:   end
    160: 
    
    Compiled Resource:
    
    # Declared in /opt/gitlab/embedded/cookbooks/cache/cookbooks/gitlab/recipes/postgresql.rb:153:in `block in from_file'
    
    execute("create gitlab database user") do
    action [:run]
    retries 20
    retry_delay 2
    default_guard_interpreter :execute
    command "/opt/gitlab/embedded/bin/psql --port 5432 -h /var/opt/gitlab/postgresql -d template1 -c \"CREATE USER gitlab\""
    backup 5
    returns 0
    user "gitlab-psql"
    declared_type :execute
    cookbook_name "gitlab"
    recipe_name "postgresql"
    not_if { #code block }
    end
    
    

    These are two known permission issues described in official documentation and in issue #9611. In order to overcome them, we execute:

    docker exec -it gitlab update-permissions
    docker exec gitlab chown -R gitlab-redis /var/opt/gitlab/redis
    

    and finally we restart the docker container:

    docker restart gitlab
    
  9. Then we have to check if the database migration was successfull and avoid issue #3255. Thus, we log into bash shell:
    docker exec -t -i gitlab /bin/bash
    

    and we check the db migration status:

    sudo gitlab-rake db:migrate:status
    

    If everything is stated as up, we are OK. However, if we notice down migrations like this

    up     20150920161119  Add line code to sent notification
    down    20150924125150  Add project id to ci commit
    down    20150924125436  Migrate project id for ci commits
    

    we have to rerun the database migration ourserlves:

    sudo gitlab-rake db:migrate
    

    When it finishes we have to check that everything went ok:

    sudo gitlab-rake db:migrate:status
    
  10. While being inside the container bash shell, we reconfigure the installation:
    sudo gitlab-ctl reconfigure
    

    and then check that everything went ok:

    sudo gitlab-rake gitlab:check
    
  11. If everything is OK, then the command:
    sudo gitlab-rake gitlab:env:info RAILS_ENV=production
    

    must return something like this:

    System information
    System:   Ubuntu 14.04
    Current User: git
    Using RVM:  no
    Ruby Version: 2.1.7p400
    Gem Version:  2.2.5
    Bundler Version:1.10.6
    Rake Version: 10.4.2
    Sidekiq Version:3.3.0
    
    GitLab information
    Version:  8.2.0
    Revision: d6bcf44
    Directory:  /opt/gitlab/embedded/service/gitlab-rails
    DB Adapter: postgresql
    URL:    http://192.168.1.1:8082
    HTTP Clone URL: http://192.168.1.1:8082/some-group/some-project.git
    SSH Clone URL:  git@192.168.1.1:some-group/some-project.git
    Using LDAP: yes
    Using Omniauth: no
    
    GitLab Shell
    Version:  2.6.7
    Repositories: /var/opt/gitlab/git-data/repositories
    Hooks:    /opt/gitlab/embedded/service/gitlab-shell/hooks/
    Git:    /opt/gitlab/embedded/bin/git
    
  12. Finally we have to clear Redis cache, or we will face the issue #3619 or issue #3609:
    sudo gitlab-rake cache:clear
    
  13. After that you will be able to login properly to http://localhost:8082

Posted in Docker, Git, Gitlab, Linux, Source control | Tagged , , , , , , | Leave a comment

JSON remove new lines via Linux and use it as string variable and as param in cURL POST request

Today I had to parse a JSON response in a JUnit test and then reuse it in a cURL command line call. Unfortunately I could not read the JSON response from a file or from an HTTP request, so I had to place it inline as a String variable. My JSON looked like this:

{
    "responseHeader": {
        "status": 0,
        "QTime": 193
    },
    "defaultCoreName": "collection1",
    "initFailures": {},
    "status": {
        "jet2pilot_shard1_replica2": {
            "name": "jet2pilot_shard1_replica2",
            "isDefaultCore": false,
            "instanceDir": "/opt/solr-4.8.1/example/solr/jet2pilot_shard1_replica2/",
            "dataDir": "/opt/solr-4.8.1/example/solr/jet2pilot_shard1_replica2/data/",
            "config": "solrconfig.xml",
            "schema": "schema.xml",
            "startTime": "2014-12-31T19:12:41.633Z",
            "uptime": 1350610415
        }
    }
}

1. Use JSON in a Java string variable

In order to parse JSON from a Java String variable, I had to:

  1. remove \t,\n,\r characters and
  2. escape single and double quotes (\’,\”)

Thus, Linux shell came to the rescue! So, write your JSON to a file, for example myresponse.json and execute the following command:

cat myresponse.json | tr '\r' ' ' |  tr '\n' ' ' | sed "s/[']/\\\'/g" | sed 's/\"/\\"/g' | sed 's/ \{3,\}/ /g' | sed 's/   / /g' > onelinejson.txt

Then you can use JSON as a simple Java String variable like the following:

@Test
public void testAktiston(){
	String jsonString = "{ \"responseHeader\": { \"status\": 0, \"QTime\": 193 }, \"defaultCoreName\": \"collection1\", \"initFailures\": {}, \"status\": { \"jet2pilot_shard1_replica2\": { \"name\": \"jet2pilot_shard1_replica2\", \"isDefaultCore\": false, \"instanceDir\": \"/opt/solr-4.8.1/example/solr/jet2pilot_shard1_replica2/\", \"dataDir\": \"/opt/solr-4.8.1/example/solr/jet2pilot_shard1_replica2/data/\", \"config\": \"solrconfig.xml\", \"schema\": \"schema.xml\", \"startTime\": \"2014-12-31T19:12:41.633Z\", \"uptime\": 1350610415 } } }";
	
	// test code
        // parsing and other chaotic code
}

2. Use JSON to perform a POST request using cURL

In order to parse JSON from a Java String variable, I had to:

  1. remove \t,\n,\r characters and

Again, Linux shell makes the world go round! So, write your JSON to a file, for example myresponse.json and execute the following command:

cat myresponse.json | tr '\r' ' ' |  tr '\n' ' ' | sed 's/ \{3,\}/ /g' | sed 's/   / /g' > onelinejson.txt

Then use it in your POST request via cURL command (the command is multilined in order to be legible):

curl -v
-X POST
-H "Cookie: JSESSIONID=00213719A12D07F7E67BE8B580CD9BBC"
-H "Content-Type: multipart/form-data"
-H "Accept: application/json"
-F 'repEx={ "responseHeader": { "status": 0, "QTime": 193 }, "defaultCoreName": "collection1", "initFailures": {}, "status": { "jet2pilot_shard1_replica2": { "name": "jet2pilot_shard1_replica2", "isDefaultCore": false, "instanceDir": "/opt/solr-4.8.1/example/solr/jet2pilot_shard1_replica2/", "dataDir": "/opt/solr-4.8.1/example/solr/jet2pilot_shard1_replica2/data/", "config": "solrconfig.xml", "schema": "schema.xml", "startTime": "2014-12-31T19:12:41.633Z", "uptime": 1350610415 } } }'
"http://192.168.1.89:8080/apios/insertios"

That is all about καρντάσια (kardasia is translated as “folks” in Thessaloniki, Greece)! Have a nice year!

Posted in Java, Linux, Mint, Ubuntu | Tagged , , , , , , , | Leave a comment

Solr fix corrupted index using Lucene

A few days ago, a Solr server in our SolrCloud installation stopped unexpectedly. After examining solr.log file I spotted that it could not start again because index.20140510031827076 file was corrupted. After some searching I found this Lucidworks article which described how to deal with a corrupted index file. So I proceeded to the following steps:

WARNING!!

This procedure may result in unrecoverable data loss. It is vital that you backup your index before performing index checking and repair.

  1. Find the guilty index file containing the corrupted segment. For me it was located in:

    C:/Program Files/apache-solr-4.6.0/example/solr/hellaserver_shard1_replica4/data/index.20140510031827076
    
  2. Find Lucene core .jar file. I work with Apache Solr 4.6.0 so it is a file named lucene-core-4.6.0.jar. It is usually in $SOLR_HOME/example/solr-webapp/webapp/WEB-INF/lib/lucene-core-4.6.0.jar. So, switch to the directory where it exists:

    cd C:/Program Files/apache-solr-4.6.0/example/solr-webapp/webapp/WEB-INF/lib
    
  3. Check the segments of the corrupted index file in order to identify the problematic segment. To accomplish that, run:

    java -cp lucene-core-4.6.0.jar -ea:org.apache.lucene... org.apache.lucene.index.CheckIndex "C:/Program Files/apache-solr-4.6.0/example/solr/hellaserver_shard1_replica4/data/index.20140510031827076"
    

    The check results for a healthy segment look like the following:

      1 of 37: name=_48r7 docCount=3021717
        codec=Lucene46
        compound=false
        numFiles=11
        size (MB)=5,020.87
        diagnostics = {timestamp=1403095380034, os=Windows Server 2012, os.version=6
    .2, mergeFactor=10, source=merge, lucene.version=4.6.0 1543363 - simon - 2013-11
    -19 11:05:50, os.arch=amd64, mergeMaxNumSegments=-1, java.version=1.7.0_51, java
    .vendor=Oracle Corporation}
        has deletions [delGen=170]
        test: open reader.........OK [196 deleted docs]
        test: fields..............OK [135 fields]
        test: field norms.........OK [52 fields]
        test: terms, freq, prox...OK [16644025 terms; 441992389 terms/docs pairs; 39
    0271915 tokens]
        test (ignoring deletes): terms, freq, prox...OK [16646658 terms; 442060892 t
    erms/docs pairs; 390381979 tokens]
        test: stored fields.......OK [107214499 total field count; avg 35.484 fields
     per doc]
        test: term vectors........OK [0 total vector count; avg 0 term/freq vector f
    ields per doc]
        test: docvalues...........OK [0 docvalues fields; 0 BINARY; 0 NUMERIC; 0 SOR
    TED; 0 SORTED_SET]
    
      2 of 37: name=_3b16 docCount=2449309
        codec=Lucene46
        compound=false
        numFiles=11
        size (MB)=3,831.743
        diagnostics = {timestamp=1402370404453, os=Windows Server 2012, os.version=6
    .2, mergeFactor=10, source=merge, lucene.version=4.6.0 1543363 - simon - 2013-11
    -19 11:05:50, os.arch=amd64, mergeMaxNumSegments=-1, java.version=1.7.0_51, java
    .vendor=Oracle Corporation}
        has deletions [delGen=426]
        test: open reader.........OK [20262 deleted docs]
        test: fields..............OK [92 fields]
        test: field norms.........OK [35 fields]
    

    When the index checker encounters a corrupted segment, the output looks like the following:

      37 of 37: name=_4gxr docCount=11
        codec=Lucene46
        compound=false
        numFiles=10
        size (MB)=75.71
        diagnostics = {timestamp=1403212995547, os=Windows Server 2012, os.version=6
    .2, source=flush, lucene.version=4.6.0 1543363 - simon - 2013-11-19 11:05:50, os
    .arch=amd64, java.version=1.7.0_51, java.vendor=Oracle Corporation}
        no deletions
        test: open reader.........FAILED
        WARNING: fixIndex() would remove reference to this segment; full exception:
    org.apache.lucene.index.CorruptIndexException: invalid docCount: 48066 maxDoc: 1
    1 (resource=MMapIndexInput(path="C:\Program Files\apache-solr-4.6.0\example\solr
    \hellasever_shard1_replica4\data\index.20140510031827076\_4gxr_Lucene41_0.ti
    m"))
            at org.apache.lucene.codecs.BlockTreeTermsReader.(BlockTreeTermsRe
    ader.java:166)
            at org.apache.lucene.codecs.lucene41.Lucene41PostingsFormat.fieldsProduc
    er(Lucene41PostingsFormat.java:437)
            at org.apache.lucene.codecs.perfield.PerFieldPostingsFormat$FieldsReader
    .(PerFieldPostingsFormat.java:195)
            at org.apache.lucene.codecs.perfield.PerFieldPostingsFormat.fieldsProduc
    er(PerFieldPostingsFormat.java:244)
            at org.apache.lucene.index.SegmentCoreReaders.(SegmentCoreReaders.
    java:115)
            at org.apache.lucene.index.SegmentReader.(SegmentReader.java:95)
            at org.apache.lucene.index.CheckIndex.checkIndex(CheckIndex.java:554)
            at org.apache.lucene.index.CheckIndex.main(CheckIndex.java:1941)
    
    WARNING: 1 broken segments (containing 11 documents) detected
    WARNING: would write new segments file, and 11 documents would be lost, if -fix
    were specified
    
  4. After the reconnaissance of the corrupted segment, rerun the command with -fix parameter:

    java -cp lucene-core-4.6.0.jar -ea:org.apache.lucene... org.apache.lucene.index.CheckIndex "C:/Program Files/apache-solr-4.6.0/example/solr/hellaserver_shard1_replica4/data/index.20140510031827076" -fix
    

    When the checker fixes the segment, the output will look like the following:

      37 of 37: name=_4gxr docCount=11
        codec=Lucene46
        compound=false
        numFiles=10
        size (MB)=75.71
        diagnostics = {timestamp=1403212995547, os=Windows Server 2012, os.version=6
    .2, source=flush, lucene.version=4.6.0 1543363 - simon - 2013-11-19 11:05:50, os
    .arch=amd64, java.version=1.7.0_51, java.vendor=Oracle Corporation}
        no deletions
        test: open reader.........FAILED
        WARNING: fixIndex() would remove reference to this segment; full exception:
    org.apache.lucene.index.CorruptIndexException: invalid docCount: 48066 maxDoc: 1
    1 (resource=MMapIndexInput(path="C:\Program Files\apache-solr-4.6.0\example\solr
    \hellasever_shard1_replica4\data\index.20140510031827076\_4gxr_Lucene41_0.ti
    m"))
            at org.apache.lucene.codecs.BlockTreeTermsReader.<init>(BlockTreeTermsRe
    ader.java:166)
            at org.apache.lucene.codecs.lucene41.Lucene41PostingsFormat.fieldsProduc
    er(Lucene41PostingsFormat.java:437)
            at org.apache.lucene.codecs.perfield.PerFieldPostingsFormat$FieldsReader
    .<init>(PerFieldPostingsFormat.java:195)
            at org.apache.lucene.codecs.perfield.PerFieldPostingsFormat.fieldsProduc
    er(PerFieldPostingsFormat.java:244)
            at org.apache.lucene.index.SegmentCoreReaders.<init>(SegmentCoreReaders.
    java:115)
            at org.apache.lucene.index.SegmentReader.<init>(SegmentReader.java:95)
            at org.apache.lucene.index.CheckIndex.checkIndex(CheckIndex.java:554)
            at org.apache.lucene.index.CheckIndex.main(CheckIndex.java:1941)
    
    WARNING: 1 broken segments (containing 11 documents) detected
    WARNING: 11 documents will be lost
    
    NOTE: will write new segments file in 5 seconds; this will remove 11 docs from t
    he index. THIS IS YOUR LAST CHANCE TO CTRL+C!
      5...
      4...
      3...
      2...
      1...
    Writing...
    OK
    Wrote new segments file "segments_y5e"
    
  5. Finally, restart Solr server in order to resynchronise with the shard leader.
Posted in Apache, Java, Linux, Lucene, Solr, Windows | Tagged , , , , , , , , , , , , | 1 Comment

Linux: Extract audio and video using ffmpeg

Today I had some mp4 video files and I wanted to extract the audio and video into separate files. So to do that you can do the following:

  • Extract audio from video file and convert it to mp3

    To accomplish that, execute the command:

    ffmpeg -i logothetis-bureaucracy.mp4  -ab 128k -ac 2 -ar 44100 -vn logothetis-bureaucracy.mp3
    
  • Extract only the video segment from a video

    To accomplish that, execute the command:

    ffmpeg -i video.wmv -vcodec copy -an onlyvideo.wmv 
    
Posted in Linux, Uncategorized | Tagged , , , , , , , | Leave a comment

Nginx https reverse proxy to WordPress with Apache, http and different port

Today I had to hide a WordPress 3.8.1 blog behind an Nginx reverse proxy configured to use only https. Nginx was behind an external firewall which forwarded https://bob.org:8080/blog to Nginx using https (port 4443). The difficulty was that whe WordPress blog was installed in an Apache HTTP server in port 80 and it worked using http!. Lets say that my site was https://bob.org and I had to put the blog in https://bob.org:8080/blog. Thus my list of burdens was the following:

  1. Configure Nginx to use only https and redirect http to https.
  2. Reverse proxy in Nginx from bob.org:8080/blog to 192.168.1.10/wordpress in Apache.
  3. Force WordPress links to use port 8080

The following is the diagram summarised my server configuration:

    +--------------+
    |  Firewall    |
    | bob.org:8080 | 
    +------+-------+
           |
           |
           v
     +–––––––––+                  +––––––––––––––+
     |  Nginx  |      http        |  WordPress   |
     | (https) |+---------------->| Apache HTTP  |
     |         |                  | (port 80)    |
     +–––––––––+                  +––––––––––––––+ 

So you will say: “Are you completely insane ??!!”

I was asked to do it! That is my answer!

Finally after one hour of searching I used a combination of two support articles (post1, post2), some PHP knowledge and experience and a little of imagination, I created a solution:

  1. Configure Nginx to reverse proxy all requests to /blog

    This is a fragment of my /etc/nginx/sites-available/default-ssl Nginx configuration file:

    upstream blog-webservers {
        server 192.168.1.10:80;
    }
    
    # redirect http to https
    # http://serverfault.com/a/171238
    server {
        listen 80;
        rewrite ^(.*) https://$host$1 permanent;
    }
    
    server {
        listen *:443;
    
        ssl on;
        ssl_certificate     /etc/nginx/crypto/server.crt;
        ssl_certificate_key /etc/nginx/crypto/server.key;
    
        ssl_client_certificate /etc/nginx/crypto/ca.crt;
        ssl_verify_client optional;
        ssl_verify_depth 10;
    
        # pem key asking for password problem
        # http://pandemoniumillusion.wordpress.com/2008/04/21/nginx-ssl-passphrase-at-startup/
    
        server_name bob.org;
        access_log  /var/log/nginx/ssl.access.log;
        error_log   /var/log/nginx/ssl.error.log;
        error_page  404 /404.html;
    
    
        # reverse proxy to blog web servers
        location /blog { 
            proxy_pass http://blog-webservers/wordpress/;
            proxy_redirect https://server_name http://blog-webservers/wordpress;
    	
            proxy_read_timeout       3500;
            proxy_connect_timeout    3250;
    
            proxy_set_header   X-Real-IP          $remote_addr;
            proxy_set_header   Host               $host;
            proxy_set_header   X-Forwarded-For    $proxy_add_x_forwarded_for;
            proxy_set_header   X-Forwarded-Proto  https;
           
     
            proxy_set_header   SSL_PROTOCOL $ssl_protocol;
            proxy_set_header   SSL_CLIENT_CERT $ssl_client_cert;
            proxy_set_header   SSL_CLIENT_VERIFY $ssl_client_verify;
            proxy_set_header   SSL_SERVER_S_DN $ssl_client_s_dn;
        }
    }
    

  2. Configure WordPress wp-config.php
    I added the following lines on top of wp-config.php file:

    // If WordPress is behind reverse proxy 
    // which proxies https to http
    if ( (!empty( $_SERVER['HTTP_X_FORWARDED_HOST'])) ||
         (!empty( $_SERVER['HTTP_X_FORWARDED_FOR'])) ) { 
    
        // http://wordpress.org/support/topic/wordpress-behind-reverse-proxy-1
        $_SERVER['HTTP_HOST'] = $_SERVER['HTTP_X_FORWARDED_HOST'];
    
        define('WP_HOME', 'https://bob.org:8080/blog');
        define('WP_SITEURL', 'https://bob.org:8080/blog');
    
        // rewrite blog word with wordpress
        $_SERVER['REQUEST_URI'] = str_replace("wordpress", "blog",
        $_SERVER['REQUEST_URI']);
    
        // http://wordpress.org/support/topic/compatibility-with-wordpress-behind-a-reverse-proxy
        $_SERVER['HTTPS'] = 'on';
    }
    

If you want to debug the former PHP code fragment you can print $_SERVER variables before and after configuration changing command inside the if block:

echo '<br>Before:';
echo '<br>$_SERVER[\'HTTP_HOST\'] : ' . $_SERVER['HTTP_HOST'];
echo '<br>$_SERVER[\'HTTP_X_FORWARDED_HOST\']: ' . $_SERVER['HTTP_X_FORWARDED_HOST'];
echo '<br>$_SERVER[\'REQUEST_URI\']: ' . $_SERVER['REQUEST_URI'];
echo '<br>$_SERVER[\'HTTP_X_FORWARDED_SERVER\']: ' . $_SERVER['HTTP_X_FORWARDED_SERVER'];
echo '<br>$_SERVER[\'HTTP_X_FORWARDED_FOR\']: ' . $_SERVER['HTTP_X_FORWARDED_FOR'];
echo '<br>$_SERVER[\'HTTP_X_FORWARDED_FOR\']: ' . $_SERVER['HTTP_X_FORWARDED_FOR'];
echo '<br>$_SERVER[\'HTTPS\']: ' . $_SERVER['HTTPS'];
echo '<br>$_SERVER[\'REMOTE_ADDR\']: ' . $_SERVER['REMOTE_ADDR'];    
echo '<br>$_SERVER[\'SERVER_NAME\']: ' . $_SERVER['SERVER_NAME'];
echo '<br>$_SERVER[\'SERVER_PROTOCOL\']: ' . $_SERVER['SERVER_PROTOCOL'];
echo '<br>WP_HOME: ' . WP_HOME;
echo '<br>WP_SITEURL : ' . WP_SITEURL;

I am exhausted, just writting it down! Be patient!

Posted in Linux, Nginx, Server | Tagged , , , , , , , , | 12 Comments

Export Untracked, modified, moved and deleted files from a Git repository to archive

Today I wanted to export to a .tar.gz archive all unstracked (new) , modified and deleted files from a Git repository. After some searching, I found a StackOverflow post which helped a lot. So after you cd inside your repository and you have two options:

  1. Export modified moved and deleted files

    tar zvcf ~/new-files-cache.tar.gz `git diff --name-only --diff-filter=ACMRT`
    
  2. Export Untracked (new), modified and deleted files

    To achieve that I followed another custom route. If you find something smarter, please inform me!

    tar zvcf ~/new-files-cache.tar.gz ` git status --short | sed 's/^ *[^ ]* \(.*\)/\1/g' `
    

That’s it! Have fun with Git!

Posted in Git, Linux, Source control | Tagged , , , , , , , , , , , | Leave a comment