--- search: exclude: true --- # CodiMD Installation ![]() In this tutorial we're going to setup a CodiMD instance behind a reverse NGINX proxy: ## **Initial Setup** We're going to setup codimd via Docker, so install it like that: root@docker0:~# apt search docker.io Sorting... Done Full Text Search... Done docker-doc/stable,stable 18.09.1+dfsg1-7.1+deb10u2 all Linux container runtime -- documentation docker.io/stable,stable,now 18.09.1+dfsg1-7.1+deb10u2 amd64 [installed] Linux container runtime python-docker/stable 3.4.1-4 all Python wrapper to access docker.io's control socket python3-docker/stable,now 3.4.1-4 all [installed,automatic] Python 3 wrapper to access docker.io's control socket ruby-docker-api/stable 1.22.2-1 all Ruby gem to interact with docker.io remote API root@docker0:~# apt install docker.io -y OR root@docker0:~# curl -sSL https://get.docker.com/ | CHANNEL=stable bash Once that's done, you can use docker from the commandline: root@docker0:~# docker search codimd NAME DESCRIPTION STARS OFFICIAL AUTOMATED linuxserver/codimd 27 fabiodcorreia/codimd A custom CodiMD image build with Alpine Linux 1 hachikoapp/codimd 0 perspectivedaily/codimd 0 rwthacs/codimd 0 proelbtn/codimd-exporter 0 mbergent/codimd-pandoc Docker Images to transform codimd-Notes with… 0 liquidinvestigations/codimd-server 0 chouhongming/codimd Forked from hackmdio/codimd and build some n… 0 tarlety/codimd codimd/feature-metrics 0 freitagsrunde/codimd 0 jinetes/codimd A codimd's image with arm support and non ro… 0 kishitat/codimd containerized codimd. Thank you, codiMD comu… 0 lsiodev/codimd 0 eoleteam/codimd Adaptation pour apps.education.fr 0 zknt/codimd 0 lspipepr/codimd 0 luzifer/codimd 0 jbonjean/codimd 0 azyobuzin/codimd https://hackmd.azyobuzi.net/ 0 hitochan777/codimd4growi CodiMD image for Growi integration 0 jokebox90/codimd 0 vinado/codimd CodiMD Dockerfile 0 indiehosters/codimd 0 renefritze/codimd_cli docker image for https://github.com/codimd/c… 0 We're going to pick the first one, but instead of pulling the containers with **docker pull containername** we will use the docker-compose yaml file: root@docker0:~# ls -lsh total 12K 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 2 root root 4.0K Apr 18 08:56 neko root@docker0:~# mkdir codimd root@docker0:~# cd codimd/ root@docker0:~/codimd# vim docker-compose.yaml Edit the passwords if you want: version: "3" services: database: image: postgres:11.6-alpine environment: - POSTGRES_USER=codimd - POSTGRES_PASSWORD=change_password - POSTGRES_DB=codimd volumes: - "database-data:/var/lib/postgresql/data" restart: always codimd: image: hackmdio/hackmd:2.3.2 environment: - CMD_DB_URL=postgres://codimd:change_password@database/codimd - CMD_USECDN=false depends_on: - database ports: - "3333:3000" volumes: - upload-data:/home/hackmd/app/public/uploads restart: always volumes: database-data: {} upload-data: {} Here i just changed the 3000 port to be 3333 because i already have another container using port 30000**:wq** to save and quit out of vim, then simply run the **docker-compose up -d** command to get the container running: root@docker0:~/codimd# docker-compose up -d codimd_database_1 is up-to-date Recreating codimd_codimd_1 ... done root@docker0:~/codimd# docker container ls CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 8120b1a3503e hackmdio/hackmd:2.3.2 "/home/hackmd/app/do…" 6 seconds ago Up 4 seconds 0.0.0.0:3333->3000/tcp codimd_codimd_1 cf01b3f17b03 postgres:11.6-alpine "docker-entrypoint.s…" About a minute ago Up About a minute 5432/tcp codimd_database_1 And there you go! We have been able to start a codimd docker instance, let's check it out at port 3333: ![](1.png) ![](2.png) ![](3.png) Once you've registered and signed in, click 'New Note' ![](4.png) ![](5.png) And there you go! you can now share the above link to another local coworker, if you want to use this publicly, you will need to setup a reverse nginx proxy to serve this service (192.168.0.200:3333) publicly, ideally behind a domain name and free TLS1.3 Certificates. ## **Reverse NGINX proxy setup** Right now i'm going to setup a reverse nginx proxy to my codimd docker instance on my main debian node at 10.0.0.101/16 (where port 80 and 443 are publicly accessible): [ 10.0.0.10/16 ] [ /dev/pts/3 ] [blog/servers/codimd] → ssh root@10.0.0.101 root@10.0.0.101's password: Linux home 4.19.0-16-amd64 #1 SMP Debian 4.19.181-1 (2021-03-19) x86_64 The programs included with the Debian GNU/Linux system are free software; the exact distribution terms for each program are described in the individual files in /usr/share/doc/*/copyright. Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent permitted by applicable law. Last login: Sun Apr 18 18:20:35 2021 from 10.0.0.10 root@home:~# vim /etc/nginx/sites-available/codimd.void.yt.conf Doing a reverse nginx proxy is going to make the previously http only service have HTTPS and we can choose to force TLS1.2 or 1.3: upstream codibackend { server 192.168.0.200:3333; } server { listen 80; listen [::]:80; server_name codimd.void.yt; return 301 https://$server_name$request_uri; } server { listen 443 ssl http2; listen [::]:443 ssl http2; server_name codimd.void.yt; ssl_certificate /root/.acme.sh/codimd.void.yt/fullchain.cer; ssl_trusted_certificate /root/.acme.sh/codimd.void.yt/codimd.void.yt.cer; ssl_certificate_key /root/.acme.sh/codimd.void.yt/codimd.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://codibackend; proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "Upgrade"; } } **:wq** to save and quit out of vim, then enable the website like so: root@home:/var/www/void.yt/config# ln -s /etc/nginx/sites-available/codimd.void.yt.conf /etc/nginx/sites-enabled/ root@home:/var/www/void.yt/config# nginx -t nginx: [emerg] BIO_new_file("/root/.acme.sh/codimd.void.yt/fullchain.cer") failed (SSL: error:02001002:system library:fopen:No such file or directory:fopen('/root/.acme.sh/codimd.void.yt/fullchain.cer','r') error:2006D080:BIO routines:BIO_new_file:no such file) nginx: configuration file /etc/nginx/nginx.conf test failed Here you see nginx fail. That's because we need the TLS certificates, and we can use acme.sh to get them: root@home:/var/www/void.yt/config# systemctl stop nginx root@home:/var/www/void.yt/config# acme.sh --issue --standalone -d codimd.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 you got the TLS certificates, enable nginx once again and see the result: root@home:/var/www/void.yt/config# systemctl start nginx ## **Testing CodiMD** See the result: we have TLS encryption! and this time we can collaborate our .md file with other people publicly: ![](7.png) simply give them the URL from where you can collaborate with them: ![](8.png) ![](9.png) And that's it! We have been able to get users to collaborate on .md files online thanks to our codimd instance.