By finishing this article you'll install your own production-ready learning management system.
What is open edX?
open edX is an open source alternative to proprietary software such as Blackboard or Udemy. It provides a flexible and scalable learning platform that can be applied in schools, colleges, and universities all around the world. Open edX is being used by 55 million students, all around the world
This article will show you how to install Open edx on your Ubuntu server and start building courses.
You can find more information about open edX on their official website.
What you are going to learn ?
Today I am going to be showing you how to install production ready open edx on your Ubuntu server and start building courses.
I'll show you what is needed for the installation, how to install it, and how your server will look once it's finished.
Requirements
- Ubuntu 20.04 amd64
- Minimum 8GB of memory
- At least one 2.00GHz CPU
- Minimum 50GB recommended for production servers
Installation Steps
First make sure you have SSH access to the server and then SSH to the server.
Install wget if it's not installed already
sudo apt-get install wget
Install open edx
wget https://gist.githubusercontent.com/cubiteDevops/521cbca51ef8fa778418bdeddbd14c8c/raw/6561ba91d280ebcdfa3e6749e83f804d5bda2e89/openedx-installer.sh -O - | sudo bash
The above command downloads and run following script
This script:
- updates and upgrades the Ubuntu packages
- Prepare ansible environment in your server to install open edx
- Create strong passwords for open edx services
- Installs open edx
- Install our theme for open edx
How should it look like
After successful installation your open edx instance should like our demo site here
What is next
We are writing another article to teach you how to generate SSL certs for your instance, set Domain names and create admin users.
Check this tweet to see how we improved open edx default UI by using Nextjs and Strapi
The #monolithic system is a relic of the past with all its pain and drawbacks. Luckily, modern frameworks like #Nextjs and @strapijs can bring the joy back to your developers and users. Read this post on how we did just that for #openedx!
strapi.io/blog/decouple-…17:36 PM - 15 Jul 2021
If you need any help contact us at hello@cubite.io
Top comments (11)
Hi,
Please, is it possible to update this script as this one is not working. When it gets to cd /edx/app/edx_ansible/edx_ansible/playbooks/, the script stops because there is no such location.
Hi @ogezie I check the script but it should work. If you already have a dir called
edx
it doesn't download the playbooks there maybe that's the issue but I test the script and update it if it's needed. Thanks for your feedback.Hi Cubite,
I finally got it to work. Thanks a lot for this. I really appreciate it. How can I generate SSL certs using letsencrypt, and set Domain names and create admin users.
Thanks for you help.
HI @ogezie
Glad it worked. Follow the instructions in dev.to/corpcubite/how-to-install-o... to setup SSL certificate and DNS records
Hi @ogezi
We tested the script and it's working. Before running the script make sure there is no directory called
/edx/
and runwget https://gist.githubusercontent.com/cubiteDevops/521cbca51ef8fa778418bdeddbd14c8c/raw/6561ba91d280ebcdfa3e6749e83f804d5bda2e89/openedx-installer.sh -O - | sudo bash
. We also have a one click installer for digital ocean that installs Open edX in a couple of minutes. You can learn more about it here dev.to/corpcubite/how-to-install-o...Hi,
Thank you for your reply. I have been running this code on a fresh Google Cloud machine without any folder called edx. I have done it again today and I have uploaded an image. Is there something I need to do before running this script? I checked the script and theres a line where it is supposed to download an ansible script but it doesn't. I checked the git link myself and there no such file. I would really love to have this script working. Please, could you kindly check again to be sure that all the links are through and the necessaty files can be downloaded?
Thank you for your time.
Hi @ogezie
Thanks for letting us know. Could you please share the error logs with us here so we can help you better with this issue ?
Yesterday after you reported the error, We tested the script and ran it on a fresh Ubuntu 20.04 server and it worked. We'd like to see what error you are seeing in the logs so we can help you to fix it.
Thank you
Hi,
Thank you again for your reply. I ran the script again, this time on Ubuntu 18.04, and it went past the first error I was getting on Ubuntu 20.04, but still returned an error. I have uploaded a snapshot and pasted the syslog below. Thank you for your help.
Nov 13 10:39:28 cubite systemd[1]: Stopping System Logging Service...
Nov 13 10:39:28 cubite rsyslogd: [origin software="rsyslogd" swVersion="8.32.0" x-pid="3360" x-info="rsyslog.com"] exiting on signal 15.
Nov 13 10:39:28 cubite systemd[1]: Stopped System Logging Service.
Nov 13 10:39:28 cubite systemd[1]: Starting System Logging Service...
Nov 13 10:39:28 cubite systemd[1]: Started System Logging Service.
Nov 13 10:39:28 cubite rsyslogd: command 'SystemLogRateLimitInterval' is currently not permitted - did you already set it via a RainerScript command (v6+ config)? [v8.32.0 try rsyslog.com/e/2222 ]
Nov 13 10:39:28 cubite rsyslogd: imuxsock: Acquired UNIX socket '/run/systemd/journal/syslog' (fd 3) from systemd. [v8.32.0]
Nov 13 10:39:28 cubite rsyslogd: rsyslogd's groupid changed to 106
Nov 13 10:39:28 cubite rsyslogd: rsyslogd's userid changed to 102
Nov 13 10:39:28 cubite rsyslogd: [origin software="rsyslogd" swVersion="8.32.0" x-pid="27661" x-info="rsyslog.com"] start
Nov 13 10:39:29 cubite ansible-stat: Invoked with checksum_algorithm=sha1 get_checksum=True follow=False path=/edx/bin/log-ntp-alerts.sh get_md5=None get_mime=True get_attributes=True
Nov 13 10:39:29 cubite ansible-copy: Invoked with directory_mode=None force=True remote_src=None _original_basename=log-ntp-alerts.sh.j2 owner=root follow=False local_follow=None group=root unsafe_writes=None serole=None content=NOT_LOGGING_PARAMETER setype=None dest=/edx/bin/log-ntp-alerts.sh selevel=None regexp=None validate=None src=/root/.ansible/tmp/ansible-tmp-1636799969.0566099-27678-156460160925537/source checksum=b57dc027d3c64f55bfddc8dd461568ccc49dc244 seuser=None delimiter=None mode=0755 attributes=None backup=False
Nov 13 10:39:29 cubite ansible-file: Invoked with directory_mode=None force=False remote_src=None _original_basename=None path=/etc/update-motd.d/90-updates-available owner=None follow=True group=None unsafe_writes=None setype=None content=NOT_LOGGING_PARAMETER serole=None selevel=None state=absent dest=/etc/update-motd.d/90-updates-available access_time=None access_time_format=%Y%m%d%H%M.%S modification_time=None regexp=None src=None seuser=None recurse=False _diff_peek=None delimiter=None mode=None modification_time_format=%Y%m%d%H%M.%S attributes=None backup=None
Nov 13 10:39:29 cubite ansible-cron: Invoked with name=log-ntp-alerts insertbefore=None state=present cron_file=None reboot=False hour=* month=* disabled=False job=/edx/bin/log-ntp-alerts.sh >/dev/null 2>&1 special_time=None user=None env=None insertafter=None backup=False day=* minute=* weekday=*
Nov 13 10:39:29 cubite crontab[27760]: (root) LIST (root)
Nov 13 10:39:29 cubite crontab[27763]: (root) REPLACE (root)
Nov 13 10:39:30 cubite ansible-stat: Invoked with checksum_algorithm=sha1 get_checksum=True follow=False path=/etc/logrotate.d/ntp get_md5=None get_mime=True get_attributes=True
Nov 13 10:39:30 cubite ansible-copy: Invoked with directory_mode=None force=True remote_src=None _original_basename=ntp.j2 owner=None follow=False local_follow=None group=None unsafe_writes=None setype=None content=NOT_LOGGING_PARAMETER serole=None dest=/etc/logrotate.d/ntp selevel=None regexp=None validate=None src=/root/.ansible/tmp/ansible-tmp-1636799969.9610648-27779-36904483302232/source checksum=cf2586c9ebe41a5689f564c2df526d83e7a50d4e seuser=None delimiter=None mode=None attributes=None backup=False
Nov 13 10:39:30 cubite ansible-user: Invoked with comment=None ssh_key_bits=0 update_password=always non_unique=False force=False skeleton=None create_home=False password_lock=None ssh_key_passphrase=NOT_LOGGING_PARAMETER createhome=False uid=None home=/edx/app/edx_ansible append=False ssh_key_type=rsa ssh_key_comment=ansible-generated on cubite group=None system=False state=present role=None hidden=None local=None authorization=None profile=None shell=/bin/false expires=None ssh_key_file=None groups=None move_home=False password=NOT_LOGGING_PARAMETER name=edx-ansible seuser=None remove=False login_class=None generate_ssh_key=None
Nov 13 10:39:30 cubite ansible-file: Invoked with directory_mode=None force=False remote_src=None _original_basename=None path=/edx/app/edx_ansible owner=edx-ansible follow=True group=www-data unsafe_writes=None state=directory content=NOT_LOGGING_PARAMETER serole=None selevel=None setype=None access_time=None access_time_format=%Y%m%d%H%M.%S modification_time=None regexp=None src=None seuser=None recurse=False _diff_peek=None delimiter=None mode=None modification_time_format=%Y%m%d%H%M.%S attributes=None backup=None
Nov 13 10:39:30 cubite ansible-file: Invoked with directory_mode=None force=False remote_src=None _original_basename=None path=/edx/var/edx_ansible owner=edx-ansible follow=True group=www-data unsafe_writes=None state=directory content=NOT_LOGGING_PARAMETER serole=None selevel=None setype=None access_time=None access_time_format=%Y%m%d%H%M.%S modification_time=None regexp=None src=None seuser=None recurse=False _diff_peek=None delimiter=None mode=None modification_time_format=%Y%m%d%H%M.%S attributes=None backup=None
Nov 13 10:39:30 cubite ansible-file: Invoked with directory_mode=None force=False remote_src=None _original_basename=None path=/edx/app/edx_ansible/venvs owner=edx-ansible follow=True group=www-data unsafe_writes=None state=directory content=NOT_LOGGING_PARAMETER serole=None selevel=None setype=None access_time=None access_time_format=%Y%m%d%H%M.%S modification_time=None regexp=None src=None seuser=None recurse=False _diff_peek=None delimiter=None mode=None modification_time_format=%Y%m%d%H%M.%S attributes=None backup=None
Nov 13 10:39:31 cubite ansible-apt: Invoked with dpkg_options=force-confdef,force-confold autoremove=False force=False force_apt_get=False policy_rc_d=None package=['python-apt', 'libmysqlclient-dev', 'git-core', 'build-essential', 'libxml2-dev', 'libxslt1-dev', 'curl', 'python-yaml', 'python3-pip', 'python3-mysqldb', 'python-pip', 'python-mysqldb', 'python-dev'] autoclean=False install_recommends=None name=['python-apt', 'libmysqlclient-dev', 'git-core', 'build-essential', 'libxml2-dev', 'libxslt1-dev', 'curl', 'python-yaml', 'python3-pip', 'python3-mysqldb', 'python-pip', 'python-mysqldb', 'python-dev'] purge=False allow_unauthenticated=False state=present upgrade=None update_cache=True default_release=None only_upgrade=False deb=None cache_valid_time=0
Nov 13 10:39:41 cubite ansible-git: Invoked with depth=None executable=None force=False track_submodules=False reference=None dest=/edx/app/edx_ansible/edx_ansible recursive=True clone=True accept_hostkey=True update=True ssh_opts=None repo=github.com/edx/configuration.git umask=None version=open-release/lilac.master bare=False verify_commit=False remote=origin key_file=None separate_git_dir=None archive=None refspec=None
Nov 13 10:39:46 cubite ansible-pip: Invoked with virtualenv=/edx/app/edx_ansible/venvs/edx_ansible virtualenv_site_packages=False virtualenv_command=virtualenv chdir=None requirements=/edx/app/edx_ansible/edx_ansible/requirements.txt name=None virtualenv_python=None umask=None editable=False executable=None use_mirrors=True extra_args=-i pypi.python.org/simple state=present version=None
Nov 13 10:40:01 cubite CRON[29339]: (root) CMD (/edx/bin/log-ntp-alerts.sh >/dev/null 2>&1)
Nov 13 10:40:42 cubite ansible-pip: Invoked with virtualenv=/edx/app/edx_ansible/venvs/edx_ansible virtualenv_site_packages=False virtualenv_command=virtualenv chdir=None requirements=/edx/app/edx_ansible/edx_ansible/requirements.txt name=None virtualenv_python=None umask=None editable=False executable=None use_mirrors=True extra_args=-i pypi.python.org/simple state=present version=None
Nov 13 10:40:43 cubite ansible-stat: Invoked with checksum_algorithm=sha1 get_checksum=True follow=False path=/edx/app/edx_ansible/update get_md5=None get_mime=True get_attributes=True
Nov 13 10:40:44 cubite ansible-copy: Invoked with directory_mode=None force=True remote_src=None _original_basename=update.j2 owner=edx-ansible follow=False local_follow=None group=edx-ansible unsafe_writes=None serole=None content=NOT_LOGGING_PARAMETER setype=None dest=/edx/app/edx_ansible/update selevel=None regexp=None validate=None src=/root/.ansible/tmp/ansible-tmp-1636800043.7689393-30607-105450250106334/source checksum=58ff81bd39ae8121664cc6bc1a09b875ba0e9de4 seuser=None delimiter=None mode=0755 attributes=None backup=False
Nov 13 10:40:44 cubite ansible-file: Invoked with directory_mode=None force=False remote_src=None _original_basename=None path=/edx/bin/update owner=None follow=True group=None unsafe_writes=None setype=None content=NOT_LOGGING_PARAMETER serole=None selevel=None state=link dest=/edx/bin/update access_time=None access_time_format=%Y%m%d%H%M.%S modification_time=None regexp=None src=/edx/app/edx_ansible/update seuser=None recurse=False _diff_peek=None delimiter=None mode=None modification_time_format=%Y%m%d%H%M.%S attributes=None backup=None
Nov 13 10:40:44 cubite ansible-stat: Invoked with checksum_algorithm=sha1 get_checksum=True follow=False path=/edx/app/edx_ansible/show-repo-heads get_md5=None get_mime=True get_attributes=True
Nov 13 10:40:44 cubite ansible-copy: Invoked with directory_mode=None force=True remote_src=None _original_basename=show-repo-heads.j2 owner=edx-ansible follow=False local_follow=None group=edx-ansible unsafe_writes=None serole=None content=NOT_LOGGING_PARAMETER setype=None dest=/edx/app/edx_ansible/show-repo-heads selevel=None regexp=None validate=None src=/root/.ansible/tmp/ansible-tmp-1636800044.2798162-30669-7039998019848/source checksum=149874e5c58e3791acf174b6637190e449aa6731 seuser=None delimiter=None mode=0755 attributes=None backup=False
Nov 13 10:40:44 cubite ansible-stat: Invoked with checksum_algorithm=sha1 get_checksum=True follow=False path=/edx/app/edx_ansible/pre-box get_md5=None get_mime=True get_attributes=True
Nov 13 10:40:44 cubite ansible-copy: Invoked with directory_mode=None force=True remote_src=None _original_basename=pre-box.j2 owner=edx-ansible follow=False local_follow=None group=edx-ansible unsafe_writes=None serole=None content=NOT_LOGGING_PARAMETER setype=None dest=/edx/app/edx_ansible/pre-box selevel=None regexp=None validate=None src=/root/.ansible/tmp/ansible-tmp-1636800044.5401018-30669-18848425416495/source checksum=2ed2129ce37f370549310e9a80009d3bd2dd397c seuser=None delimiter=None mode=0755 attributes=None backup=False
Nov 13 10:40:44 cubite ansible-file: Invoked with directory_mode=None force=False remote_src=None _original_basename=None path=/edx/bin/show-repo-heads owner=None follow=True group=None unsafe_writes=None setype=None content=NOT_LOGGING_PARAMETER serole=None selevel=None state=link dest=/edx/bin/show-repo-heads access_time=None access_time_format=%Y%m%d%H%M.%S modification_time=None regexp=None src=/edx/app/edx_ansible/show-repo-heads seuser=None recurse=False _diff_peek=None delimiter=None mode=None modification_time_format=%Y%m%d%H%M.%S attributes=None backup=None
Nov 13 10:40:45 cubite ansible-file: Invoked with directory_mode=None force=False remote_src=None _original_basename=None path=/edx/bin/ansible-playbook owner=None follow=True group=None unsafe_writes=None setype=None content=NOT_LOGGING_PARAMETER serole=None selevel=None state=link dest=/edx/bin/ansible-playbook access_time=None access_time_format=%Y%m%d%H%M.%S modification_time=None regexp=None src=/edx/app/edx_ansible/venvs/edx_ansible/bin/ansible-playbook seuser=None recurse=False _diff_peek=None delimiter=None mode=None modification_time_format=%Y%m%d%H%M.%S attributes=None backup=None
Nov 13 10:40:45 cubite ansible-file: Invoked with directory_mode=None force=False remote_src=None _original_basename=None path=/edx/etc/playbooks owner=None follow=True group=None unsafe_writes=None setype=None content=NOT_LOGGING_PARAMETER serole=None selevel=None state=link dest=/edx/etc/playbooks access_time=None access_time_format=%Y%m%d%H%M.%S modification_time=None regexp=None src=/edx/app/edx_ansible/edx_ansible/playbooks seuser=None recurse=False _diff_peek=None delimiter=None mode=None modification_time_format=%Y%m%d%H%M.%S attributes=None backup=None
Nov 13 10:41:01 cubite CRON[31311]: (root) CMD (/edx/bin/log-ntp-alerts.sh >/dev/null 2>&1)
Nov 13 10:42:01 cubite CRON[31419]: (root) CMD (/edx/bin/log-ntp-alerts.sh >/dev/null 2>&1)
Nov 13 10:43:01 cubite CRON[31523]: (root) CMD (/edx/bin/log-ntp-alerts.sh >/dev/null 2>&1)
Nov 13 10:44:01 cubite CRON[31640]: (root) CMD (/edx/bin/log-ntp-alerts.sh >/dev/null 2>&1)
Nov 13 10:45:01 cubite CRON[31698]: (root) CMD (/edx/bin/log-ntp-alerts.sh >/dev/null 2>&1)
Hi,
Please, is it possible to update this script as this one is not working. When it gets to
bash: line 12: cd: /edx/app/edx_ansible/edx_ansible/playbooks/: No such file or directory
sudo: /edx/app/edx_ansible/edx_ansible/playbooks/: command not found
Hi, I have the problem with Mysql.
I try to add new key "warlord0blog.wordpress.com/2019/05..."
But It not work. Please help me . Thanks
TASK [mysql : add the mysql signing key] ***************************************
fatal: [localhost]: FAILED! => {"changed": false, "id": "8C718D3B5072E1F5", "msg": "key does not seem to have been added"}