A Real Common Lisp Website in 9 Steps


    This introductory article is intended for those who want to try using Common Lisp in web programming tasks. I will not dwell on the advantages of this language, ababo did it for me in my introductory post Developing web applications in Common Lisp (part one)

    I have been working on developing web applications in Common Lisp for a little over a year and have made large Internet on Common Lisp is a store that, it seems to me, will warn the objections of those who believe that the lisp is useless for commercial use.

    Today, my task is to tell in detail about the method I use to deploy all the necessary infrastructure. Using this article as a step-by-step guide, an attentive reader will be able to deploy his own website on Lisp.

    Perhaps my approaches are not ideal - in this case I will be glad to constructive criticism - please do not be shy if you do not like something - one of the goals of this article was to correct your own mistakes.

    For those who like to skip boring installation procedures - at the end of the article there is a little goodness that will probably expand your view on web programming if you haven’t dealt with lisp before. Search by keywords SLIME and SWANK :)

    Install the latest version of SBCL

    I use SBCL as the most convenient, widespread and free implementation of Common Lisp, closely integrated with the Emacs environment, which provides convenient and comfortable work. The repositories, as a rule, do not have the latest version of SBCL, so you can compile it from sources or install a binary for your architecture. The latter is trivial, so in this article I will describe compilation from source.

    To compile fresh SBCL, you can use the old one, which we will immediately install using the package manager:

    $ apt-get install sbcl

    SBCL sources can be obtained here: sbcl.sourceforge.net/platform-table.html

    # Скачиваем
    $ wget http://downloads.sourceforge.net/project/sbcl/sbcl/1.0.45/sbcl-1.0.45-source.tar.bz2
    # Распаковывываем архив:
    $ bzip2 -cd sbcl-1.0.45.tar.bz2 | tar xvf -
    # Заходим внутрь каталога и компилим
    $ cd sbcl-1.0.45/
    $ sh make.sh
    # Удаляем старый SBCL поставленный из репозиториев
    $ apt-get remove sbcl
    # Устанавливаем скомпилированный sbcl
    $ sh install.sh
    # Проверяем, все ли в порядке:
    $ sbcl
    This is SBCL 1.0.45, an implementation of ANSI Common Lisp.
    More information about SBCL is available at .
    SBCL is free software, provided as is, with absolutely no warranty.
    It is mostly in the public domain; some portions are provided under
    BSD-style licenses.  See the CREDITS and COPYING files in the
    distribution for more information.

    Congratulations, you now have a fresh version of sbcl. At the moment, I am deploying it with you on my server to avoid possible inaccuracies, and at the end of the article you can make sure that at least everything worked for me. Well, let's hope it will be so :)

    We put quicklisp

    To manage libraries, two package managers are most often used - ASDF and QuickLisp. The latter is much friendlier, and the former is already preinstalled with SBCL, so now we will install QuickLisp for ourselves. On quicklisp.org posted all the background information, so I will not be repeated and we will proceed directly to the installation:

    $ wget http://beta.quicklisp.org/quicklisp.lisp
    $ sbcl --load quicklisp.lisp
    * (quicklisp-quickstart:install)
    * (ql:add-to-init-file)

    We put hunchentoot

    Now that we have the library manager, we install the
    hunchentoot web server, together with all its dependencies, with one command:

    * (ql:quickload 'hunchentoot)

    We put swank and slime on the server

    “And an even more impressive example of remote debugging occurred at NASA's Deep Space 1 mission in 1998. Six months after the launch of the spacecraft, a small Lisp code was supposed to control the spacecraft for two days to conduct a series of experiments. However, the elusive race condition in the code was not detected during testing on the ground and was already discovered in space. When the error was detected in space (100 million miles from Earth), the team was able to diagnose and correct the working code, which allowed us to complete the experiment. One of the programmers said the following about this:

    “Debugging a program running on $ 100 million worth of equipment that is 100 million miles away is an interesting experience. "REPL, operating on a spaceship, provides invaluable opportunities in finding and fixing problems."

    I heard about this incident long before I began to deal with Lisp myself, and frankly, I took it as a bike that was no longer destined to repeat itself in our modern world of multi-megabyte executable files and no less heavyweight dynamically linked libraries. However, when I became acquainted with the remote control capabilities of the Lisp image, I became convinced that it was no more difficult than working with the code on my machine. And no incremental builds, lengthy compilation or downloading scripts via ftp - with the help of slime I connect to a working system and can see and change almost everything, for example, implement hot-swapping code, or inspect any object, function or macro using powerful introspection tools.

    How it works? - you ask. Inside the lisp image on the remote server, SWANK works - a special library that provides a backend that provides access to all the levers of control of the lisp image. SWANK is written in Common Lisp and communicates with SLIME using a fairly simple text protocol.

    My Emacs-e runs SLIME, written in Emacs Lisp, which allows me to send commands, pieces of code, definitions of objects and structures to a remote Common Lisp image when editing a code file. Thus, you may not even have a copy of the source code on the remote server at all - in which case no attacker could modify it there, for example, to secure a backdoor.

    And given the developed means of code generation, which distinguishes Lisp, you can have almost no code at all - let it be generated by the data itself - it is better than a samurai who does not fight, maybe only a programmer who does not write code ... Hmm, something I got carried away here, back to the installation :)

    So, if you have a remote server, like mine, you can put SWANK on it, and SLIME on your working machine. Or
    to put both that and another both there and there - the main thing then to not mix up. Install SWANK:

    $ sbcl
    * (ql:quickload 'swank)

    ... and SLIME

    $ wget http://common-lisp.net/project/slime/snapshots/slime-current.tgz
    $ tar xvzf slime-current.tgz
    $ cd slime-2011-01-06/

    We carefully read the README in this directory and add the
    following code to our ~ / .emacs / init.el, watching for the correct path

    ;; SBCL
    (setq inferior-lisp-program "/opt/sbcl/bin/sbcl") ; your Lisp system
    (setq slime-lisp-implementations '((sbcl ("sbcl"))))
    (setq slime-startup-animation nil)
    ;; SLIME
    (add-to-list 'load-path "~/.emacs.d/slime") ;; Путь к slime
    (require 'slime)
    (setq slime-net-coding-system 'utf-8-unix)
    (slime-setup '(slime-fancy))
    (setq slime-enable-evaluate-in-emacs t)

    Put screen

    Since my servers never crash (well, yes :) - I use screen to keep an always running copy of SBCL, although, as far as I know, there are better practices (which competent readers will undoubtedly recall in the comments)

    If you have it not worth it yet - it's time to put:

    $ apt-get install screen

    Run sbcl in screen on the server and start the swank server on port 4005

    $ screen -S sbcl
    $ sbcl
    * (require 'asdf)
    * (asdf:oos 'asdf:load-op 'swank)
    * (setq swank:*use-dedicated-output-stream* nil)
    * (swank:create-server :coding-system "utf-8-unix" :dont-close t :port 4005)

    We connect from Emacs-a running on our machine to the lisp image on the server

    In the terminal, we forward the ssh tunnel to the host

    ssh -2 -N -f -L 4005:localhost:4005 user@host.tld

    In Emacs, we connect through this tunnel

    M-x slime-connect

    Or, if your server is your home machine - you don’t need to roll anything and raise SWANK - just type in Emacs-e:

    M-x slime

    Launch the web-server hunchentoot on port 4242

    Now we are ready to lift the hunchentoot web server. I lift it to port 4242 and use nginx as a proxy. Also, nginx gives away statics and does a number of things for which it is designed for the best.

    The nginx config for our test purposes can be very simple:

    server {
       listen 80;
       server_name localhost;
        location / {
          proxy_pass http: // localhost: 4242;
          proxy_redirect off;

    The following code, for the authorship of archimag -a, creates a special class that allows you to immediately forward this error along with the stack trace to a cozy emacs when an error occurs on the remote server, where you can deal with it properly. Thus, if you are connected to the server where your site is running, you will always be aware of errors that occur at the time they occur, unlike a number of other languages ​​used in web programming.

    If there are too many errors, for example, visitors constantly go to the wrong page - you can simply change the * catch-errors-p * value so that you can easily understand what causes the errors that have already arrived to you.

    (defparameter *catch-errors-p* nil)
    (defclass debuggable-acceptor (hunchentoot:acceptor) ())
    (defmethod hunchentoot:acceptor-request-dispatcher ((acceptor debuggable-acceptor))
      (if *catch-errors-p*
    	  (let ((dispatcher (handler-bind ((error #'invoke-debugger))
    		(lambda (request)
    		  (handler-bind ((error #'invoke-debugger))
    			(funcall dispatcher request))))))
    (defun request-dispatcher (request)
    (defparameter *debuggable-acceptor* (make-instance 'debuggable-acceptor
                                                       :request-dispatcher 'request-dispatcher
                                                       :port 4242))
    (hunchentoot:start *debuggable-acceptor*)
    (setf hunchentoot:*handle-http-errors-p* nil)

    The request-dispatcher function is called on every incoming request and in our case simply returns “Hello!” - We will talk about its expansion in the next article.

    If you read up to this place you need to put you a bottle of
    , and even raised a test site on your Lisp - I
    envy you ! Acquaintance with Lisp gave me almost a year and a half to
    enjoy this amazing language - and you have everything
    ahead in this regard . Happy hacking!

    Also popular now: