# Asciinema server setup ![](0.png) In this tutorial we're going to look at how to setup an asciinema server and how to use the commandline utility itself. ## **Initial Setup** Make sure you have docker installed: root@docker0:~# apt install docker.io -y Then you can get the official docker-compose.yml file provided by asciinema on their official github repository: root@docker0:~# ls -lsh total 32K 4.0K drwxr-xr-x 2 root root 4.0K Apr 18 19:16 codimd 4.0K drwxr-xr-x 11 root root 4.0K Apr 18 08:03 dillinger 4.0K drwxr-xr-x 7 root root 4.0K Apr 18 08:03 kutt 4.0K drwxr-xr-x 4 systemd-coredump root 4.0K Apr 18 21:57 mongo_data 4.0K drwxr-xr-x 2 root root 4.0K Apr 18 08:56 neko 4.0K drwxr-xr-x 2 systemd-coredump root 4.0K Apr 19 17:31 redis_data 4.0K drwxr-xr-x 2 root root 4.0K Apr 18 21:01 sharelatex 4.0K drwxr-xr-x 5 root root 4.0K Apr 18 20:46 sharelatex_data root@docker0:~# git clone --recursive https://github.com/asciinema/asciinema-server.git Cloning into 'asciinema-server'... remote: Enumerating objects: 20182, done. remote: Counting objects: 100% (83/83), done. remote: Compressing objects: 100% (63/63), done. remote: Total 20182 (delta 26), reused 42 (delta 19), pack-reused 20099 Receiving objects: 100% (20182/20182), 9.66 MiB | 6.91 MiB/s, done. Resolving deltas: 100% (11987/11987), done. Submodule 'native/vt' (https://github.com/asciinema/vt-rs.git) registered for path 'native/vt' Cloning into '/root/asciinema-server/native/vt'... remote: Enumerating objects: 253, done. remote: Total 253 (delta 0), reused 0 (delta 0), pack-reused 253 Receiving objects: 100% (253/253), 44.38 KiB | 826.00 KiB/s, done. Resolving deltas: 100% (116/116), done. Submodule path 'native/vt': checked out 'ee2a4640569c1ab0c64eae44c0804a4f59f8a9f1' root@docker0:~# cd asciinema-server/ root@docker0:~/asciinema-server# git checkout master M docker-compose.yml Branch 'master' set up to track remote branch 'master' from 'origin'. Switched to a new branch 'master' root@docker0:~/asciinema-server# git checkout -b void.yt master M docker-compose.yml Switched to a new branch 'void.yt' root@docker0:~/asciinema-server# ls assets config CONTRIBUTING.md dev docker docker-compose.yml Dockerfile lib LICENSE mix.exs mix.lock native priv README.md rel test uploads root@docker0:~/asciinema-server# vim docker-compose.yml Let's see what the docker-compose.yml file contains: version: '2' services: postgres: image: postgres:10.6-alpine container_name: asciinema_postgres restart: unless-stopped volumes: - ./volumes/postgres:/var/lib/postgresql/data ### See https://hub.docker.com/_/postgres/ for more ### configuration options for this image. redis: image: redis:4.0-alpine container_name: asciinema_redis restart: unless-stopped volumes: - ./volumes/redis:/data ### See https://hub.docker.com/_/redis/ for more ### configuration options for this image. smtp: image: namshi/smtp container_name: asciinema_smtp restart: unless-stopped env_file: .env.production ### See https://github.com/namshi/docker-smtp for more SMTP configuration ### options for this image. nginx: image: nginx:1.15-alpine container_name: asciinema_nginx restart: unless-stopped links: - phoenix ports: - "8091:80" ### Uncomment for HTTPS: # - "443:443" volumes: - ./docker/nginx/asciinema.conf:/etc/nginx/conf.d/default.conf:ro - ./volumes/cache:/cache ### Uncomment for HTTPS (make sure to add your cert and private key to ./certs): # - ./certs:/app/priv/certs ### See https://hub.docker.com/_/nginx/ for more configuration options for ### this image. phoenix: image: asciinema/asciinema-server container_name: asciinema_phoenix restart: unless-stopped links: - redis - postgres - smtp env_file: .env.production volumes: - ./volumes/uploads:/opt/app/uploads In here i simply changed the default **80:80** port redirection to **8091:80**. That's because i already have a service running on port 80 on that debian node, so i will use port 8091 instead. I leave the rest as default, **:wq** to save and quit out of vim, then edit the **env.production** file: root@docker0:~/asciinema-server# cp .env.production.sample .env.production root@docker0:~/asciinema-server# vim .env.production ### asciinema web app config file ## Settings below that are un-commented are required, the rest is optional. ## Values after "=" sign are taken as-is, so don't use double quotes for strings. ## Base URL of your asciinema web app instance URL_SCHEME=http URL_HOST=asciinema.void.yt URL_PORT=8091 ## Base secret key for signing cookies etc. ## Run `docker-compose run --rm phoenix asciinema gen_secret` ## and copy generated secret here. SECRET_KEY_BASE='X3gqVydBRANDOMSTRING0aWc0WUxX' [...] Edit those to fit your own asciinema instance of course, we will use a separate reverse nginx proxy later on. Once that's done save and quit out of vim, then let's first pull asciinema's official docker container image: root@docker0:~/asciinema-server# docker pull asciinema/asciinema-server:latest latest: Pulling from asciinema/asciinema-server cbdbe7a5bc2a: Already exists 852302012d76: Pull complete c10f35f5e38e: Pull complete 54c64cbd1686: Pull complete adbcd5d252bd: Pull complete Digest: sha256:0e0a517a638da72a3dff54d2f4caacd1457e02a607a9edddb17f6aec6ae240d0 Status: Downloaded newer image for asciinema/asciinema-server:latest Next we're going to start the PostgreSQL container: root@docker0:~/asciinema-server# docker-compose up -d postgres Creating network "asciinema-server_default" with the default driver Pulling postgres (postgres:10.6-alpine)... 10.6-alpine: Pulling from library/postgres 6c40cc604d8e: Pull complete 3ea5fa93d025: Pull complete 146f5c88cacb: Pull complete 9fc5bfa5813c: Pull complete 99fdb8e79d37: Pull complete d0ec5819b579: Pull complete 4c673b065000: Pull complete 4436822af9f8: Pull complete 733c47ccf44e: Pull complete Digest: sha256:113562a23ed3912f0c35fd9c437c007865aec009feccc6b750d74baf46d70551 Status: Downloaded newer image for postgres:10.6-alpine Creating asciinema_postgres ... done Now create the database schema and seed it with initial data: root@docker0:~/asciinema-server# docker-compose run --rm phoenix setup Pulling redis (redis:4.0-alpine)... 4.0-alpine: Pulling from library/redis cbdbe7a5bc2a: Already exists dc0373118a0d: Pull complete cfd369fe6256: Pull complete 152ffd6a3b24: Pull complete 7c01860f13a3: Pull complete aa6ecacd3bee: Pull complete Digest: sha256:aaf7c123077a5e45ab2328b5ef7e201b5720616efac498d55e65a7afbb96ae20 Status: Downloaded newer image for redis:4.0-alpine Pulling smtp (namshi/smtp:)... latest: Pulling from namshi/smtp 376057ac6fa1: Pull complete 4f41e210c366: Pull complete c6481c5521ee: Pull complete be585e548f6c: Pull complete 430c23e8d992: Pull complete Digest: sha256:aa63b8de68ce63dfcf848c56f3c1a16d81354f4accd4242a0086c57dd5a91d77 Status: Downloaded newer image for namshi/smtp:latest Creating asciinema_redis ... done Starting asciinema_postgres ... done Creating asciinema_smtp ... done [...] 17:04:21.590 [info] == Migrated 20200831195118 in 0.0s 17:04:21.599 [info] == Running 20200901164454 Asciinema.Repo.Migrations.ConvertFileToPath.change/0 forward 17:04:21.600 [info] rename column file to filename on table asciicasts 17:04:21.601 [info] alter table asciicasts 17:04:21.607 [info] execute "UPDATE asciicasts SET path=concat('asciicast/file/', id, '/', filename) WHERE filename IS NOT NULL" 17:04:21.611 [info] == Migrated 20200901164454 in 0.0s Running seed script.. Once that's done, create the containers: root@docker0:~/asciinema-server# docker-compose up -d Pulling nginx (nginx:1.15-alpine)... 1.15-alpine: Pulling from library/nginx e7c96db7181b: Pull complete 264026bbe255: Pull complete a71634c55d29: Pull complete 5595887beb81: Pull complete Digest: sha256:57a226fb6ab6823027c0704a9346a890ffb0cacde06bc19bbc234c8720673555 Status: Downloaded newer image for nginx:1.15-alpine asciinema_redis is up-to-date asciinema_smtp is up-to-date asciinema_postgres is up-to-date Creating asciinema_phoenix ... done Creating asciinema_nginx ... done And then just check the status of the containers: root@docker0:~/asciinema-server# docker ps -f 'name=asciinema_' CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 56e0da8221d2 nginx:1.15-alpine "nginx -g 'daemon of…" 34 seconds ago Up 32 seconds 0.0.0.0:8091->80/tcp asciinema_nginx 2fd74f43d7d4 asciinema/asciinema-server "/sbin/tini -- /opt/…" 35 seconds ago Up 34 seconds 4000/tcp asciinema_phoenix a7804b544bee redis:4.0-alpine "docker-entrypoint.s…" 2 minutes ago Up 2 minutes 6379/tcp asciinema_redis 3a3cf6fd58b3 namshi/smtp "/bin/entrypoint.sh …" 2 minutes ago Up 2 minutes 25/tcp asciinema_smtp b78623063995 postgres:10.6-alpine "docker-entrypoint.s…" 3 minutes ago Up 3 minutes 5432/tcp asciinema_postgres Since that's done, let's checkout the service at port 8091: ![](1.png) And that's it ! We managed to install a local instance of asciinema server: ## **Reverse Nginx Proxy** Now we want to make sure that our local asciinema server is accessible from the internet thanks to a nginx proxy, i'm going to use my main nginx node at 10.0.0.101 because i know it's ports 80 and 443 are publicly accessible: root@home:/var/www/void.yt/config# vim /etc/nginx/sites-available/asciinema.void.yt.conf upstream asciibackend { server 192.168.0.200:8091; } server { listen 80; listen [::]:80; server_name asciinema.void.yt; return 301 https://$server_name$request_uri; } server { listen 443 ssl http2; listen [::]:443 ssl http2; server_name asciinema.void.yt; ssl_certificate /root/.acme.sh/asciinema.void.yt/fullchain.cer; ssl_trusted_certificate /root/.acme.sh/asciinema.void.yt/asciinema.void.yt.cer; ssl_certificate_key /root/.acme.sh/asciinema.void.yt/asciinema.void.yt.key; ssl_protocols TLSv1.3 TLSv1.2; ssl_ciphers 'TLS13-CHACHA20-POLY1305-SHA256:TLS13-AES-256-GCM-SHA384:TLS13-AES-128-GCM-SHA256:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256'; ssl_prefer_server_ciphers on; ssl_session_cache shared:SSL:10m; ssl_session_timeout 10m; ssl_session_tickets off; ssl_ecdh_curve auto; ssl_stapling on; ssl_stapling_verify on; resolver 80.67.188.188 80.67.169.40 valid=300s; resolver_timeout 10s; add_header X-XSS-Protection "1; mode=block"; #Cross-site scripting add_header X-Frame-Options "SAMEORIGIN" always; #clickjacking add_header X-Content-Type-Options nosniff; #MIME-type sniffing add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"; location / { proxy_pass http://asciibackend; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "Upgrade"; } } :wq root@home:/var/www/void.yt/config# ln -s /etc/nginx/sites-available/asciinema.void.yt.conf /etc/nginx/sites-enabled/ root@home:/var/www/void.yt/config# nginx -t nginx: [emerg] BIO_new_file("/root/.acme.sh/asciinema.void.yt/fullchain.cer") failed (SSL: error:02001002:system library:fopen:No such file or directory:fopen('/root/.acme.sh/asciinema.void.yt/fullchain.cer','r') error:2006D080:BIO routines:BIO_new_file:no such file) nginx: configuration file /etc/nginx/nginx.conf test failed Now when you test the reverse proxy site config, you see that nginx doesn't like it, that's because we don't have the TLS certificates from LetsEncrypt yet, so let's get them: root@home:/var/www/void.yt/config# systemctl stop nginx root@home:/var/www/void.yt/config# acme.sh --issue --standalone -d asciinema.void.yt -k 4096 root@home:/var/www/void.yt/config# nginx -t nginx: the configuration file /etc/nginx/nginx.conf syntax is ok nginx: configuration file /etc/nginx/nginx.conf test is successful Once that's done, start nginx again, and check the result: ![](2.png) That's it! you managed to install a public asciiserver instance. Now let's use it: ## **Using the CLI Utility** On nearly all Linux-Based distros, asciiserver is available in the repositories, for example in debian-based and arch-based distros:: [ 10.0.0.10/16 ] [ /dev/pts/16 ] [blog/servers/asciinema] → pacman -Ss asciinema ; pacman -S asciinema community/asciinema 2.0.2-5 [installed] Record and share terminal sessions root@home:~# apt search asciinema ; apt install asciinema -y Sorting... Done Full Text Search... Done asciinema/stable 2.0.2-1 all Record and share your terminal sessions, the right way Before we start using asciinema, we need to make sure we use our asciinema instance. By default, asciinema uses [ https://asciinema.org](https://asciinema.org) to send the recorded terminal files to. So we can either change the **ASCIINEMA_API_URL** environnement variable OR we can just edit the **~/.config/asciinema/config** [ 10.0.0.10/16 ] [ /dev/pts/16 ] [blog/servers/asciinema] → echo $ASCIINEMA_API_URL [ 10.0.0.10/16 ] [ /dev/pts/16 ] [blog/servers/asciinema] → ASCIINEMA_API_URL=https://asciinema.void.yt [ 10.0.0.10/16 ] [ /dev/pts/16 ] [blog/servers/asciinema] → echo $ASCIINEMA_API_URL https://asciinema.void.yt OR [ 10.0.0.10/16 ] [ /dev/pts/16 ] [blog/servers/asciinema] → echo '[api]' > ~/.config/asciinema/config [ 10.0.0.10/16 ] [ /dev/pts/16 ] [blog/servers/asciinema] → echo 'url = https://asciinema.void.yt' >> ~/.config/asciinema/config Once that's done, you can start the recording : [ 10.0.0.10/16 ] [ /dev/pts/16 ] [blog/servers/asciinema] → asciinema rec asciinema: recording asciicast to /tmp/tmpnjcc_g63-ascii.cast asciinema: press <****ctrl-d> or type "exit" when you're done [ 10.0.0.10/16 ] [ /dev/pts/17 ] [blog/servers/asciinema] → ls 0.png 1.png 2.png index.html [ 10.0.0.10/16 ] [ /dev/pts/17 ] [blog/servers/asciinema] → ls 0.png 1.png 2.png index.html [ 10.0.0.10/16 ] [ /dev/pts/17 ] [blog/servers/asciinema] → ls 0.png 1.png 2.png index.html [ 10.0.0.10/16 ] [ /dev/pts/17 ] [blog/servers/asciinema] → ls 0.png 1.png 2.png index.html [ 10.0.0.10/16 ] [ /dev/pts/17 ] [blog/servers/asciinema] → exit asciinema: recording finished asciinema: press <****enter> to upload to asciinema.void.yt, <****ctrl-c> to save locally View the recording at: http://asciinema.void.yt:8091/a/FTLJyGAlLi6TKVSEf9JYiisA4 Now we're not done just yet! as you can see the end URL isn't correct, we need to edit the **.env.production** file we edited earlier to fix this, and rebuild the containers: root@docker0:~/asciinema-server# vim .env.production URL_SCHEME=https URL_HOST=asciinema.void.yt URL_PORT=443 [...] :wq Once we're done editing the file, we restart the phoenix container and then use docker-compose to make sure the containers are up then check the result: root@docker0:~/asciinema-server# docker-compose stop phoenix root@docker0:~/asciinema-server# docker-compose up -d phoenix root@docker0:~/asciinema-server# docker-compose up -d asciinema_redis is up-to-date asciinema_smtp is up-to-date asciinema_postgres is up-to-date asciinema_phoenix is up-to-date Starting asciinema_nginx ... done root@docker0:~/asciinema-server# docker ps -f 'name=asciinema_' CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES e037d2364879 nginx:1.15-alpine "nginx -g 'daemon of…" 7 minutes ago Up About a minute 0.0.0.0:8091->80/tcp asciinema_nginx b513c2c6894e asciinema/asciinema-server "/sbin/tini -- /opt/…" 7 minutes ago Up 3 minutes 4000/tcp asciinema_phoenix 4dbb7e9c7588 namshi/smtp "/bin/entrypoint.sh …" 7 minutes ago Up 3 minutes 25/tcp asciinema_smtp a7804b544bee redis:4.0-alpine "docker-entrypoint.s…" 45 minutes ago Up 4 minutes 6379/tcp asciinema_redis b78623063995 postgres:10.6-alpine "docker-entrypoint.s…" About an hour ago Up 3 minutes 5432/tcp asciinema_postgres Now let's test the asciinema recording once more: [ 10.0.0.10/16 ] [ /dev/pts/16 ] [blog/servers/asciinema] → asciinema rec asciinema: recording asciicast to /tmp/tmpob7b68vm-ascii.cast asciinema: press <****ctrl-d> or type "exit" when you're done [ 10.0.0.10/16 ] [ /dev/pts/17 ] [blog/servers/asciinema] → ls 0.png 1.png 2.png index.html [ 10.0.0.10/16 ] [ /dev/pts/17 ] [blog/servers/asciinema] → ls 0.png 1.png 2.png index.html [ 10.0.0.10/16 ] [ /dev/pts/17 ] [blog/servers/asciinema] → exit asciinema: recording finished asciinema: press <****enter> to upload to asciinema.void.yt, <****ctrl-c> to save locally View the recording at: https://asciinema.void.yt/a/DvUyM1xdyysk7MQv30Vl1ACzR That's better! Now let's view the result: ![](3.png) And that's it! Now let's share it: ![](4.png) You can also embed it in HTML: [![](https://asciinema.void.yt/a/DvUyM1xdyysk7MQv30Vl1ACzR.svg)](https://asciinema.void.yt/a/DvUyM1xdyysk7MQv30Vl1ACzR) You can sign up, and get the one-time login link sent to the email address: ![](7.png) ![](5.png) ![](6.png) ![](8.png) And that's it ! We have successfully tested that our asciinema instance works.