Department of Physics and Astronomy

The Forbes Group

Docker

$\newcommand{\vect}[1]{\mathbf{#1}} \newcommand{\uvect}[1]{\hat{#1}} \newcommand{\abs}[1]{\lvert#1\rvert} \newcommand{\norm}[1]{\lVert#1\rVert} \newcommand{\I}{\mathrm{i}} \newcommand{\ket}[1]{\left|#1\right\rangle} \newcommand{\bra}[1]{\left\langle#1\right|} \newcommand{\braket}[1]{\langle#1\rangle} \newcommand{\op}[1]{\mathbf{#1}} \newcommand{\mat}[1]{\mathbf{#1}} \newcommand{\d}{\mathrm{d}} \newcommand{\pdiff}[3][]{\frac{\partial^{#1} #2}{\partial {#3}^{#1}}} \newcommand{\diff}[3][]{\frac{\d^{#1} #2}{\d {#3}^{#1}}} \newcommand{\ddiff}[3][]{\frac{\delta^{#1} #2}{\delta {#3}^{#1}}} \DeclareMathOperator{\erf}{erf} \DeclareMathOperator{\Tr}{Tr} \DeclareMathOperator{\order}{O} \DeclareMathOperator{\diag}{diag} \DeclareMathOperator{\sgn}{sgn} \DeclareMathOperator{\sech}{sech} $

Docker

Some notes about using Docker to host various applications like Heptapod, Discourse, CoCalc etc. on Linux and AWS.

Docker

Several packages (such as Heptapod and CoCalc) require a rather complete system, so are easiest to install using Docker containers. Here we discuss how to set these up. Where possible, we try to use Rootless mode, which prevents the need for providing docker with root access, but has limitations. Currently, Rootless works for Heptapod, but causes problems with CoCalc.

Docker Account

We generally work with a docker user, and keep all docker-specific files for this account:

sudo useradd -m docker
sudo usermod -aG sudo docker         # Enable sudo for docker.
sudo su docker
chsh -s /bin/bash
bash
curl -fsSL https://get.docker.com/rootless | sh

On my machine, I then add a swandocker alias to my ~/.ssh/config file, e.g.:

# ~/.ssh/config

Host *docker
  User docker
  ForwardAgent yes
  SetEnv LC_EDITOR=vi

Host swan*
  HostName swan.physics.wsu.edu

Host penguin*
  HostName penguin.physics.wsu.edu

Host *
  ForwardAgent yes
  SendEnv LC_HG_USERNAME
  SendEnv LC_GIT_USERNAME
  SendEnv LC_GIT_USEREMAIL
  AddressFamily inet
  # Force IPv4
  # https://www.electricmonk.nl/log/2014/09/24/
  #         ssh-port-forwarding-bind-cannot-assign-requested-address/

All of the following is done in this account:

ssh ssh-copy-id swandocker
ssh swandocker
...

Installing Docker (With Root Access)

ssh swandocker
sudo apt-get update
sudo apt-get upgrade   # Optional
sudo apt-get install uidmap dbus-user-session
sudo apt-get purge docker docker.io  # Remove old root-version of docker.
sudo apt-get autoremove --purge
sudo apt-get install docker docker.io nvidia-docker2
sudo systemctl start docker
sudo systemctl stop docker docker.sock

Installing Docker Rootless

Note: Be sure to completely purge any previous root-enabled version of Docker before proceeding.

ssh swandocker
sudo apt-get update
sudo apt-get upgrade
sudo apt-get install uidmap dbus-user-session
sudo apt-get purge docker docker.io  # Remove old root-version of docker.
sudo apt-get autoremove --purge

To actually install rootless, run the following script, downloaded with curl:

curl -fsSL https://get.docker.com/rootless | sh

This will put everything in ~/bin

This allows the docker user to add processes to start services that will start at login.

sudo loginctl enable-linger docker
systemctl --user start docker

Add the appropriate environmental variables to ~docker/.bashrc:

...
# Docker install (rootless)
export PATH=/home/docker/bin:$PATH
export DOCKER_HOST=unix:///run/user/1017/docker.sock

Docker Cheatsheet

Here are some useful commands:

  • docker pull: Pulls an image.
  • docker create: Creates a container from an image.
  • docker start: Starts running a container.
  • docker stop: Stops ...
  • docker attach: Attach to a running container.
  • docker log: See logs for specified container.
  • docker ps -a: List all containers (both running and stopped).
  • docker images: List all images.
  • docker rm: Remove a container.
  • docker rmi: Remove an image.
  • docker inspect: Lots of information about a container.
  • docker exec -it <name> /bin/bash: Connect to the specified container and run bash (like ssh-ing into the VM).
  • docker info: Information about the install. You can use this to see if the overlay2 storage driver is used, for example.

These appear in documentation, but I do not use them:

  • docker run: This is equivalent to docker create + docker start + docker attach. This can only be executed once. After the container is created, one cannot use subsequent calls to run to change, for example, port assignments. It is probably most useful for short foreground processes in conjunction with the --rm option.

Issues: I originally had a bunch of errors because of interference with the previously installed docker version (not rootless). These went away once I did sudo apt-get purge docker docker.io.

  • Aborting because rootful Docker is running and accessible. Set FORCE_ROOTLESS_INSTALL=1 to ignore.
  • Failed to start docker.service: Unit docker.socket failed to load: No such file or directory.

So I stopped the root docker service (from a previous install) and removed this file:

sudo service docker stop
sudo systemctl disable docker
sudo apt-get remove docker 
#sudo rm /var/run/docker.sock /lib/systemd/system/docker.service

After resolving these issues, I was having the following issue when trying to run the server with systemctl:

$ systemctl --user start docker
$ docker run hello-world
docker: Cannot connect to the Docker daemon at unix:///tmp/docker-1017/docker.sock. Is the docker daemon running?.
See 'docker run --help'.

Limiting Resouces

It can be useful to limit the resources available to Docker containers. To do this, you must enable cgroup swapping. This can be done by adding the following to /etc/default/grub:

# /etc/default/grub
...
GRUB_CMDLINE_LINUX_DEFAULT="swapaccount=1"
...

then running sudo update-grub. Once this is done, you can limit the resources used by Docker containers with flags like:

--memory=4g --cpus=1

etc.

Docker Compose

Sometimes you must run several processes and have them interact. For example, heptapod generally requires a mail-server like sendmail, but the omnibus docker image does not contain sendmail. To combine two containers in a single environment, one typically uses docker compose... but this does not seem to work with rootless.

Heptapod

Heptapod is a service providing Mercurial access to GitLab CE. When running the public server, we host it here:

Here we describe how to run Heptapod in a Docker container. This is a service based on GitLab CE that provides a backend with issue tracking etc. for Mercurial. As above, I have created a docker user account on swan. First I login to this, then make some directories for the server data in /data2/docker/heptapod. Then I pull the docker image.

ssh docker@swan                         # Login to swan as docker
echo 'export GITLAB_HOME="${HOME}/srv/heptapod' >> ~/.bashrc
sudo mkdir -p /data2/docker             # Make the data directory for docker
sudo chown docker /data2/docker         # Change owner...
sudo chmod a-wrx,u+rwxs /data2/docker   # ...and give appropriate permissions
mkdir -p /data2/docker/heptapod         # Now create the heptapod directory.
sudo ln -s /data2/docker/heptapod /srv/ # Link it to /srv/heptapod...
ln -s /data2/docker ~docker/srv         # ...and to the docker home directory.

Now we pull the heptapod image and start a couple of containers:

  • heptapod-local: Only listens on local ports. To use this, users must login with ssh and forward ports appropriately so they can connect (see below).
  • heptapod-public: Listens on public ports. This exposes Heptapod to the world, which may be a security risk. We do this to allow "weak" collaborators access, or to enable transferring repositories from Bitbucket.
docker pull octobus/heptapod
docker create                                            \
       --name heptapod-local                             \
       --restart always                                  \
       --hostname localhost                              \
       --publish 127.0.0.1:11080:80                       \
       --publish 127.0.0.1:11443:443                      \
       --publish 127.0.0.1:11022:22                       \
       --volume ${GITLAB_HOME}/config:/etc/gitlab        \
       --volume ${GITLAB_HOME}/logs:/var/log/gitlab      \
       --volume ${GITLAB_HOME}/data:/var/opt/gitlab      \
       octobus/heptapod

docker create                                            \
       --name heptapod-public                            \
       --restart always                                  \
       --hostname swan.physics.wsu.edu                   \
       --publish 11080:80                                 \
       --publish 11443:443                                \
       --publish 11022:22                                 \
       --volume ${GITLAB_HOME}/config:/etc/gitlab        \
       --volume ${GITLAB_HOME}/logs:/var/log/gitlab      \
       --volume ${GITLAB_HOME}/data:/var/opt/gitlab      \
       octobus/heptapod

Now we can run whichever one we want:

docker start heptapod-local       # Use this in general.
#docker start heptapod-public      # Use this when needed.

Once started, I initialized a mercurial repository in the configuration directory so I can keep track of configuration changes:

cd ~/srv/heptapod
# For some reason, the following file is given rw permission only
# for the user in the docker image, so we can't back it up...
sudo chgrp docker config/heptapod.hgrc
sudo chmod g+rw config/heptapod.hgrc
hg init
cat > .hgignore <<EOF
syntax: glob

data/
logs/
EOF
hg add
hg com -m "Initial commit"

Debugging

Look at the current logs with the following:

docker exec -it heptapod-public gitlab-ctl tail

Heptapod Backup (incomplete)

The recommended way to transfer a Heptapod/GitLab server is backup/restore.

To do this:

  1. Login to your host and find the name of your heptapod container:

    ssh aws-hg
    docker ps
    heptapod_id=ecs-heptapod-11-heptapod-f0effff7e3cddbc38001
    

    or

    ssh swandocker
    docker ps
    heptapod_id=heptapod-public
    
  2. First make sure both instances are running the same version:

    docker exec -t ${heptapod_id} gitlab-rake gitlab:env:info

    If not, update and migrate until they match, converting the database as needed.

  3. Create the backup on the source:

    `bash docker exec -t ${heptapod_id} gitlab-backup create

    This will put a file on the image which we exported:

    • /var/opt/gitlab/backups/1593678341_2020_07_02_12.10.11_gitlab_backup.tar
    • ~/srv/heptapod/data/backups/1593678341_2020_07_02_12.10.11_gitlab_backup.tar

    Optionally, the backup program can upload this to a remote storage location.

  4. Backup the configuration files:

    tar -czvf heptapod-config-2020-12-13.tgz ~/srv/heptapod/config
    
  5. Copy everything over to new server:

    backup=1607073575_2020_12_04_13.3.5_gitlab_backup.tar
    mkdir heptapod_backup
    cd heptapod_backup
    scp -r swandocker:srv/heptapod/config .
    
    # Need to change owner of this file first on swan with sudo
    scp -r swandocker:srv/heptapod/data/backup/${backup} .
    cd ..
    scp -r heptapod_backup/ aws-hg:
    ssh aws-hg
    heptapod_id=ecs-heptapod-11-heptapod-f0effff7e3cddbc38001
    docker cp heptapod_backup ${heptapod_id}:heptapod_backup
    docker exec -it bash ${heptapod_id}
    cd heptapod_backup
    cp -r /etc/gitlab /etc/gitlab-backup
    cp -r /heptapod_backup/config/* /etc/gitlab/
    cp /etc/gitlab-backup/gitlab.rb /etc/gitlab/
    mv 1607073575_2020_12_04_13.3.5_gitlab_backup.tar /var/opt/gitlab/backups/
    chown git.git /var/opt/gitlab/backups/1607073575_2020_12_04_13.3.5_gitlab_backup.tar
    gitlab-ctl reconfigure
    gitlab-ctl stop unicorn
    gitlab-ctl stop puma
    gitlab-ctl stop sidekiq
    gitlab-ctl status
    gitlab-backup restore BACKUP=1607073575_2020_12_04_13.3.5
    gitlab-ctl reconfigure
    gitlab-ctl restart
    gitlab-rake gitlab:check SANITIZE=true
    

    Another option is to backup the repositories, I use rclone to copy these to my Google Drive to a remote called gwsu_backups from my docker account on swan using the root_folder_id corresponding to a folder My Drive/backups/RClone/swan/repo_backup.

screen -S RCloneBackup
rclone sync -Pl repo_backups gwsu_backups:
$ ssh swandocker

docker@swan:~$ docker ps
CONTAINER ID        IMAGE ...         PORTS                                                                          NAMES
638b8e2d6535        octobus/heptapod  0.0.0.0:11022->22/tcp, 0.0.0.0:11080->80/tcp, 0.0.0.0:11443->443/tcp   heptapod-public
docker@swan:~$ export heptapod_id=heptapod-public
docker@swan:~$ docker exec -t ${heptapod_id} gitlab-rake gitlab:env:info

System information
System:     
Current User:   git
Using RVM:  no
Ruby Version:   2.6.6p146
Gem Version:    2.7.10
Bundler Version:1.17.3
Rake Version:   12.3.3
Redis Version:  5.0.9
Git Version:    2.28.0
Sidekiq Version:5.2.9
Go Version: unknown

GitLab information
Version:    13.4.6
Revision:   7ea571d2b76a
Directory:  /opt/gitlab/embedded/service/gitlab-rails
DB Adapter: PostgreSQL
DB Version: 11.9
URL:        http://swan.physics.wsu.edu
HTTP Clone URL: http://swan.physics.wsu.edu/some-group/some-project.git
SSH Clone URL:  ssh://git@swan.physics.wsu.edu:11022/some-group/some-project.git
Using LDAP: no
Using Omniauth: yes
Omniauth Providers: bitbucket

GitLab Shell
Version:    13.7.0
Repository storage paths:
- default:  /var/opt/gitlab/git-data/repositories
GitLab Shell path:      /opt/gitlab/embedded/service/gitlab-shell
Git:        /opt/gitlab/embedded/bin/git
docker@swan:~$ docker exec -t ${heptapod_id} gitlab-backup create
docker@swan:~$ docker exec -t ${heptapod_id} gitlab-backup create
2020-12-04 08:17:52 +0000 -- Dumping database ... 
Dumping PostgreSQL database gitlabhq_production ... [DONE]
2020-12-04 08:17:57 +0000 -- done
2020-12-04 08:17:57 +0000 -- Dumping namespaces (Mercurial specific) ...
Calling tar czf /var/opt/gitlab/backups/namespaces.tar.gz -C /var/opt/gitlab/backups/namespaces .
output=, status=0
2020-12-04 08:17:59 +0000 -- done
2020-12-04 08:17:59 +0000 -- Dumping repositories ...
 * mforbes/pymmf (@hashed/6b/...) ... 
 * mforbes/pymmf (@hashed/6b/...) ... [DONE]
 * mforbes/pymmf (@hashed/6b/...) ... [DONE] Wiki
 * mforbes/kzsolve (@hashed/d4/...) ... 
...
 * mforbes/zdk_phys_final_eos_fast (@hashed/52/...) ... 
 * mforbes/zdk_phys_final_eos_fast (@hashed/52/...) ... [DONE]
 * mforbes/zdk_phys_final_eos_fast (@hashed/52/...) ... [SKIPPED] Wiki
2020-12-04 08:25:57 +0000 -- done
2020-12-04 08:25:57 +0000 -- Dumping uploads ... 
2020-12-04 08:25:58 +0000 -- done
2020-12-04 08:25:58 +0000 -- Dumping builds ... 
2020-12-04 08:25:58 +0000 -- done
2020-12-04 08:25:58 +0000 -- Dumping artifacts ... 
2020-12-04 08:25:58 +0000 -- done
2020-12-04 08:25:58 +0000 -- Dumping pages ... 
2020-12-04 08:25:58 +0000 -- done
2020-12-04 08:25:58 +0000 -- Dumping lfs objects ... 
2020-12-04 08:25:58 +0000 -- done
2020-12-04 08:25:58 +0000 -- Dumping container registry images ... 
2020-12-04 08:25:58 +0000 -- [DISABLED]
Creating backup archive: 1607070358_2020_12_04_13.4.6_gitlab_backup.tar ... done
Uploading backup archive to remote storage  ... skipped
Deleting tmp directories ... done
done
...
Deleting old backups ... skipping
Warning: Your gitlab.rb and gitlab-secrets.json files contain sensitive data 
and are not included in this backup. You will need these files to restore a backup.
Please back them up manually.
Backup task is done.
$ ssh aws-hg
[ec2-user@ip-10-147-105-73 ~]$ docker ps
CONTAINER ID ... PORTS                                             NAMES
650311e25626 ... 0.0.0.0:80->80/tcp, 22/tcp, 0.0.0.0:443->443/tcp  ecs-heptapod-11-heptapod-f0effff7e3cddbc38001
...
[ec2-user@... ~]$ export heptapod_id="ecs-heptapod-11-heptapod-f0effff7e3cddbc38001"
[ec2-user@... ~]$ docker exec -it ${heptapod_id} gitlab-rake gitlab:env:info

System information
System:     
Current User:   git
Using RVM:  no
Ruby Version:   2.6.6p146
Gem Version:    2.7.10
Bundler Version:1.17.3
Rake Version:   12.3.3
Redis Version:  5.0.9
Git Version:    2.28.0
Sidekiq Version:5.2.9
Go Version: unknown

GitLab information
Version:    13.3.5
Revision:   11c5a0a148c9
Directory:  /opt/gitlab/embedded/service/gitlab-rails
DB Adapter: PostgreSQL
DB Version: 11.7
URL:        http://650311e25626
HTTP Clone URL: http://650311e25626/some-group/some-project.git
SSH Clone URL:  ssh://git@650311e25626/some-group/some-project.git
Using LDAP: no
Using Omniauth: yes
Omniauth Providers: 

GitLab Shell
Version:    13.6.0
Repository storage paths:
- default:  /var/opt/gitlab/git-data/repositories
GitLab Shell path:      /opt/gitlab/embedded/service/gitlab-shell
Git:        /opt/gitlab/embedded/bin/git

HTTP Redirect

Note: SSL does not yet work with non-standard ports... so I am using HTTP only. I have randomly chosen ports 11080, 11443 and 11022 for HTTP, HTTPS, and SSH access. These are not very memorable, so it would be nice to redirect https://swan.physics.wsu.edu/heptapod to https://swan.physics.wsu.edu:11443. To do this, we simply add a Redirect /heptapod https://swan.physics.wsu.edu:11443/ statement to one of the Apache config files:

#/etc/apache2/sites-enabled/000-default.conf 
<Virtualhost *:80>
    ...
    Redirect /heptapod http://swan.physics.wsu.edu:11080/
    Redirect /discourse http://swan.physics.wsu.edu:10080/    
</VirtualHost>
#/etc/apache2/sites-enabled/000-default-le-ssl.conf 
<Virtualhost *:443>
    ...
    Redirect /heptapod https://swan.physics.wsu.edu:11443/
    Redirect /discourse https://swan.physics.wsu.edu:10443/    
</VirtualHost>

Don't forget to restart the server:

sudo service apache2 restart

Bitbucket Import

  1. Enable OAuth2 integration on Bitbucket. I used my public settings http://swan.physics.wsu.edu/heptapod/users/sign_in.

    Note: I had issues resulting in redirect_uri issue because I was using my alias http://swan.physics.wsu.edu/heptapod/users/auth but in my configuration, I used the http://swan.physics.wsu.edu:9080/users/auth form. If you look at the URL sent, it includes the redirect_uri which must match.

  2. Edit the /etc/gitlab/gitlab.rb file on the server. Since we mapped /etc/gitlab to ~docker/srv/config, we can edit it there without connecting.

    vi ~docker/srv/heptapod/config/gitlab.rb
    
    #/etc/gitlab/gitlab.rb
    gitlab_rails['omniauth_enabled'] = true
    ...
    gitlab_rails['omniauth_providers'] = [
     {
       "name" => "bitbucket",
       "app_id" => "Rc...",
       "app_secret" => "hA...",
       "url" => "https://bitbucket.org/",
     }
    ]
    
  3. Start the public server, or reconfigure GitLab:

    ssh docker@swan
    docker start heptapod-public
    

    or

    docker exec -it heptapod-public gitlab-ctl reconfigure
    
  4. Register for an account on our Heptapod instance.
  5. Login.
  6. Import new project from Bitbucket Cloud.

References

Issues

  • Some imports are broken.
  • Cloning links are incorrect: http://swan.physics.wsu.edu/mforbes/mmfutils mmfutils_heptapod. Probably need to update the hostname to include the port and/or the /heptapode alias.
  • Cloning from http://swan.physics.wsu.edu:9080/mforbes/mmfutils mmfutils_heptapod does not work.
  • Cloning from ssh://git@swan.physics.wsu.edu:9022/mforbes/mmfutils works on swan but not from outside.
  • Cloning from ssh://git@localhost:9022/mforbes/mmfutils works with SSH tunnel.
Password Changes

On swan, we do not have a mail server setup, so if you want to recover a password, then you need to follow this procedure:

ssh swandocker
docker exec -it heptapod-local /bin/bash
gitlab-rails console -e production
user = User.where(id: 2).first    # Play with the number to find the user you want
user.password = 'secret_pass'
user.password_confirmation = 'secret_pass'
user.admin = true  # If you want user to be admin.
user.save!
Upgrades/Migration

GitLab does not allow you to jump to much between versions, so you might need to specify an upgrade path. This means you should recreate the container with a sequence of images, then let the backend migration take place. Here is an example:

  1. First find out which tags are available:
$ wget -q https://registry.hub.docker.com/v1/repositories/octobus/heptapod/tags -O -  | sed -e 's/[][]//g' -e 's/"//g' -e 's/ //g' | tr '}' '\n'  | awk -F: '{print $3}'
latest
...
0.16.0               # <<<<<<<<<< This matched our aws instance
0.16.0-py2
0.16.0-py3
0.16.0rc1
0.16.0rc1-py2
0.16.0rc1-py3
0.16.1
0.16.1-py2
0.16.1-py3
0.16.2
0.16.2-py2
0.16.2-py3
0.17.0
0.17.0rc1
0.17.1
0.17.2
...

To see if the migration is done:

ssh swandocker
docker exec -it heptapod-local gitlab-rails runner -e production 'puts Gitlab::BackgroundMigration.remaining'

Discourse

ssh docker@swan
mkdir repositories
cd repositories
git clone https://github.com/discourse/discourse_docker.git
cd discourse_docker

Edit the generated containers/app.yml file. I am trying to use Gmail with a custom alias michael.forbes+discourse@gmail.com which I registered under my Gmail account settings.

DISCOURSE_DEVELOPER_EMAILS: 'michael.forbes+discourse@gmail.com'
  DISCOURSE_SMTP_ADDRESS: in-v3.mailjet.com
  DISCOURSE_SMTP_USER_NAME: ******
  DISCOURSE_SMTP_PASSWORD: *********

## The Docker container is stateless; all data is stored in /shared
volumes:
  - volume:
      host: /home/docker/srv/discourse/shared/standalone
      guest: /shared
  - volume:
      host: /home/docker/srv/discourse/shared/standalone/log/var-log
      guest: /var/log

...
  ## If you want to set the 'From' email address for your first registration, uncomment and change:
  ## After getting the first signup email, re-comment the line. It only needs to run once.
  - exec: rails r "SiteSetting.notification_email='m.forbes@wsu.edu'"

Mailjet: I managed to

Notes:

  • I could not use michael.forbes+discourse@gmail.com as the SMTP user here since I cannot login to gmail with this.
  • Gmail did not work: probably have to use an App password since two-factor authentication is enabled.
  • I had to use an absolute path for the host /home/docker: ~ did not work.
  • I also tried using Mailjet with - exec: rails r "SiteSetting.notification_email='m.forbes@wsu.edu'" but this did not seem to activate either (I was expecting Mailjet to send me an activation email to make sure...)

After editing these, I was able to continue after making these directories:

rm -rf ~/srv/discourse
mkdir ~/srv/discourse
./launcher rebuild app

Not Working: Discourse is running, but not able to send emails.

HTTP Redirect

I have randomly chosen ports 10080 and 10433 for HTTP and HTTPS access. These are not very memorable, so it would be nice to redirect https://swan.physics.wsu.edu/discourse to https://swan.physics.wsu.edu:10443. To do this, we simply add a Redirect /discourse https://swan.physics.wsu.edu:10443/ statement to one of the Apache config files:

#/etc/apache2/sites-enabled/000-default.conf 
<Virtualhost *:443>
    ...
    Redirect /heptapod https://swan.physics.wsu.edu:11443/
    Redirect /discourse https://swan.physics.wsu.edu:10443/    
</VirtualHost>

Don't forget to restart the server:

sudo service apache2 restart

CoCalc

CoCalc can also be installed with docker. I created the images with the following file:

#!/bin/bash
# initialize_cocalc.sh
docker create                                            \
       --name cocalc                                     \
       --restart always                                  \
       --hostname localhost                              \
       --publish 127.0.0.1:9443:443                      \
       --publish 127.0.0.1:9022:22                       \
       --volume ~/srv/cocalc:/projects                   \
       sagemathinc/cocalc

These listen on port 9443. Note: you must connect with https://localhost:9443, not with HTTP.

Launch with:

$ ssh swandocker
$ docker ps -a
...
c54a50cbac06        sagemathinc/cocalc   ...  cocalc
... 
$ docker start cocalc

Now you can connect with appropriately forwarded ports. Make sure you have something like this in your ~/.ssh/config file:

# ~/.ssh/config
...
Host swand
  Host swan.physics.wsu.edu
  User mforbes
  ForwardAgent yes
  # CoCalc https access
  LocalForward 9443 localhost:9443

Start this connection:

$ ssh swand

Now visit the server on your local computer with https://localhost:9443.

Toubleshooting

See the logs:

(Laptop)$ ssh swandocker
(Swan)$ docker logs cocalc -f       # Sometimes does not work... if not, try
(Swan)$ docker exec -it cocalc tail -f /var/log/hub.log

Make a user Admin:

(Laptop) $ ssh swandocker
(Swan)$ docker exec -it cocalc make-user-admin m.forbes@wsu.edu

Issues

  • New project stuck on "Loading..." when running Rootless. Works when running Docker as root. See:
  • The Docker interface does not have GUI support for setting SSH keys, so you must manually create them in each project. (Use a Linux Terminal for example.)

    cd ~
    mkdir .ssh
    chmod 700 .ssh
    vi .ssh/authorized_keys
    ... paste in contents of ~/.ssh/id_cocalc.pub from host computer ...
    chmod 600 .ssh/authorized_keys
    

    In our initialize_cocalc.sh we forward the SSH port 22 on the container to port 9022 on the host (but only listen locally for security), so you can connect in two ways:

    1. Connect to the host with SSH, forwarding ports 9443 and 9022 to your local machine. Then you can connect to the web interface from your computer at https://localhost:9443 and you can SSH to the container by connecting to your local computer on port 9022. (Tested and works.)
    2. Connect to the container by using SSH directly to connect first to the host, then to the container. (Not tested yet.)

Nextcloud (incomplete)

Open source replacement for Google Cloud etc. There is a docker image.

Incomplete because this needs MySQL etc. and I don't want to figure this out yet.

ssh swandocker

Let's Encrypt and Certbot

Let's Encrypt uses Certbot as a tool for enabling free site certification. This requires using a supported Ubuntu release.

sudo apt update
sudo apt install software-properties-common
sudo add-apt-repository universe
#sudo add-apt-repository ppa:certbot/certbot
sudo apt update
sudo apt install certbot python3-certbot-apache
sudo certbot --apache
#sudo apt-add-repository -r ppa:certbot/certbot

The commented out commands were needed earlier (pre Ubuntu 19.10) but should no longer be needed. Without removing this repo I ran into the following error) during apt update:

E: The repository 'http://ppa.launchpad.net/certbot/certbot/ubuntu focal Release' does not have a Release file.

With BitBucket "sunsetting" their support for Mercurial, we needed to find a new option. Here we explore options for self-hosting.

Version Control Hosting

Kallithea (incomplete)

Kallithea needs a database, so we make a directory for this in /data/kalithea and store it there.

sudo apt-get install npm
su admin
sudo apt-get install build-essential git python-pip python-virtualenv libffi-dev python-dev
hg clone https://kallithea-scm.org/repos/kallithea
cd kallithea
conda create -n kallithea python=2
conda activate kallithea
pip install --upgrade .
mkdir -p "${CONDA_PREFIX}/etc/conda/activate.d"
echo "export LC_ALL='C.UTF-8'" >> "${CONDA_PREFIX}/etc/conda/activate.d/env_vars.sh"
su admin
conda activate kallithea
mkdir /data/kallithea
cd /data/kallithea
kallithea-cli config-create my.ini
kallithea-cli db-create -c my.ini  #Created with root path `/data/kallithea`, user `mforbes` etc.
kallithea-cli front-end-build
gearbox serve -c my.ini

This runs Kallithea on port 5000 which could be accessed by users with ssh tunelling.

Another alternative is Heptapod. This is a mercurial interface to a friendly fork of GitLab CE intended to ultimately bring mercurial support to GitLab. This can be installed with Docker as discussed below.

As of 1 July 2020: This is my primary alternative to Bitbucket hosted as discussed below. We will probably ultimately host this on an AWS instance.

As of 14 March 2020:

Podman

An alternative to Docker is Podman. This behaves very similarly to Docker, but runs rootless natively.

In [ ]: