Here is a list of platforms that can be used permanently for free, excluding those that require payment such as Heroku, and also excluding platforms like Azure/AWS that only offer a free trial for a limited time.
This GitHub repository heroku-free-alternatives lists some platforms similar to Heroku. If you're interested, you can try them out yourself.
Create a project
Open google cloud and create a new project.
Shell deployment
On the same page, in the top right corner, there is an icon labeled "Activate Cloud Shell". Click on it to open the cloud shell. Copy and paste the following commands (Please keep the multi-line format), and follow the prompts by pressing "y" continuously to complete the deployment.
Deployment and updating are both done with the same command.
rm -rf kindleear && \
git clone --depth 1 https://github.com/cdhigh/kindleear.git && \
chmod +x kindleear/tools/gae_deploy.sh && \
kindleear/tools/gae_deploy.sh
Note 1: The default configuration is B2 instance, 1 worker process, 2 worker threads, and a 20-minute timeout. If you need a different configuration, you can modify the last line of code, for example:
#instance_class: B1 (384MB/600MHz)
#max_instances: 1
#threads: 2 (2 thread per instance)
#idle_timeout: 15m (minutes)
kindleear/tools/gae_deploy.sh B1,1,t2,15m
Download the latest version of KindleEar from the GitHub page. In the bottom right corner of the page, there's a button labeled "Download ZIP". Clicking it will download a ZIP document containing all the source code. Then, unzip it to a directory of your choice, such as D:\KindleEar.
Install gloud CLI, and then execute:
gcloud components install app-engine-python app-engine-python-extras # Run as Administrator
gcloud init
gcloud auth login
gcloud auth application-default set-quota-project your_app_id
gcloud config set project your_app_id
python kindleear/tools/update_req.py gae
gcloud beta app deploy --version=1 app.yaml worker.yaml
gcloud beta app deploy --version=1 cron.yaml
gcloud beta app deploy --version=1 queue.yaml
gcloud beta app deploy --version=1 dispatch.yaml
gcloud beta app deploy --version=1 app.yaml worker.yaml
The initial username and password are admin/admin.
When prompted during deployment with the following messages, remember to press "y". The cursor automatically moves to the next line, and it's easy to forget to press "y". Otherwise, it will remain stuck at this step.
Updating config [cron]...API [cloudscheduler.googleapis.com] not enabled on project [xxx]. Would you like to enable and retry (this will take a few minutes)
Updating config [queue]...API [cloudtasks.googleapis.com] not enabled on project [xxx]. Would you like to enable and retry (this will take a few minutes)
If encountering errors like "Timed out fetching pod", you have the option to delete this app id, recreate a new one and select a different region during deployment.
After successful deployment, go to the GAE console and add your sender address to "Mail API Authorized Senders" to prevent "Unauthorized sender" errors during delivery.
If you have previously deployed Python2 version of KindleEar, it is advisable to create a new project to deploy the Python3 version. Since GAE no longer supports Python 2 deployment, reverting to the original version after overwriting is not possible.
GAE's resources are scalable. Generally, only backend instances (worker.yaml) need to be customized. The default configuration is B2(768MB/1.2GHz). Adjust this configuration based on your RSS volume: increase to B4 for larger volumes and decrease to B1 for smaller volumes. Additionally, if the logs shows a ‘[CRITICAL] WORKER TIMEOUT' error, it requires increasing the ‘–timeout' parameter within the entrypoint section.
If various issues arise, you can always check the logs resolve them one by one based on the error messages.
What is Docker? just think of it as an enhanced version of portable software.
wget -O - https://raw.githubusercontent.com/cdhigh/KindleEar/master/docker/ubuntu_docker.sh | bash
http://example.com
with your own value).wget https://raw.githubusercontent.com/cdhigh/KindleEar/master/docker/ke-docker.sh
chmod +x ke-docker.sh
ke-docker.sh http://example.com
Note 1: After KindleEar updates, rerun the last command to automatically pull and start the updated version.
Note 2: The script will create a data
subdirectory in the current directory (if it doesn't already exist).
Note 3: If you need HTTPS support, copy fullchain.pem
and privkey.pem
to the data
directory, then run the command again.
Note 4: Default image configuration:
/data
gunicorn.conf.py
or default.conf
.If unable to connect, ensure port 80/443 is open. Methods to open port 80/443 vary across platforms, such as iptables or ufw.
For example:
sudo iptables -I INPUT 6 -m state --state NEW -p tcp --dport 80 -j ACCEPT
sudo iptables -I INPUT 7 -m state --state NEW -p tcp --dport 443 -j ACCEPT
sudo netfilter-persistent save
or allow all ports:
sudo iptables -P INPUT ACCEPT
sudo iptables -P FORWARD ACCEPT
sudo iptables -P OUTPUT ACCEPT
sudo iptables -F
3.1 Using Caddy as the web server is recommended, as it can automatically request and renew SSL certificates.
mkdir data #for database and logs
wget https://raw.githubusercontent.com/cdhigh/KindleEar/master/docker/docker-compose.yml
wget https://raw.githubusercontent.com/cdhigh/KindleEar/master/docker/Caddyfile
#important!!! Change the environ variables APP_DOMAIN/DOMAIN
vim ./docker-compose.yml
sudo docker compose up -d
3.2 If you perfer Nginx.
mkdir data #for database and logs
wget https://raw.githubusercontent.com/cdhigh/KindleEar/master/docker/docker-compose-nginx.yml
wget https://raw.githubusercontent.com/cdhigh/KindleEar/master/docker/default.conf
# Change the environment variables APP_DOMAIN/DOMAIN
vim ./docker-compose-nginx.yml
sudo docker compose -f docker-compose-nignx.yml up -d
If HTTPS for Nginx is needed, copy the SSL certificate fullchain.pem/privkey.pem to the data directory, and uncomment the corresponding lines in default.conf/docker-compose-nginx.yml.
sudo docker compose pull && \
sudo docker compose up -d --remove-orphans && \
sudo docker image prune -f
tail -n 100 ./data/gunicorn.error.log
tail -n 100 ./data/gunicorn.access.log
5.2. After setting the environment variable: USE_DOCKER_LOGS="yes"
docker logs container_name
sudo usermod -aG docker your-username
/data
, for example, map /docker/data
to /data
, with "Read/Write" permissions.APP_DOMAIN
.USE_DOCKER_LOGS="yes"
.These are manual deployment steps on Oracle VPS , which can be quite complex. Generally, it's not recommended.
If there are no specific requirements, it's advisable to use Docker images instead.
DATABASE_URL = "sqlite:////home/ubuntu/site/kindleear/database.db"
TASK_QUEUE_SERVICE = "apscheduler"
TASK_QUEUE_BROKER_URL = "redis://127.0.0.1:6379/"
KE_TEMP_DIR = "/tmp"
DOWNLOAD_THREAD_NUM = "3"
Test ping the corresponding IP, if successful, it indicates that the instance configuration is complete.
Connect remotely to the instance using your preferred SSH tool.
3.1 If using puTTY, first convert the ssh private key to ppk format using puttyGen. Open puTTY, the Host format as username@IP, port 22. You can find the username in the "Instance Details" page. Import the private key file under Connection|SSH|Auth|Credentials.
3.2 If using Xshell, choose "Public Key" for authentication method and import the previously saved private key file.
Upon login, it is recommended to first change the root password.
sudo -i
passwd
sudo apt update
sudo apt upgrade
sudo apt install nginx
sudo apt install git python3.10 python3-pip
sudo pip3 install virtualenv
sudo apt install redis-server
sudo systemctl start nginx
sudo systemctl start redis-server
sudo systemctl enable nginx
sudo systemctl enable redis-server
curl localhost #test if nginx works well
sudo apt install vim-common
mkdir ~/site
mkdir ~/log
cd ~/site
#fetch code from github, or you can upload code files by xftp/scp
git clone https://github.com/cdhigh/kindleear.git
chmod -R 775 ~ #nginx user www-data read static resource
cd kindleear
virtualenv --python=python3 venv #create virtual environ
vim ./config.py #start to modify some config items
python3 ./tools/update_req.py docker #update requirements.txt
source ./venv/bin/activate #activate virtual environ
pip install -r requirements.txt #install dependencies
python3 ./main.py db create #create database tables
#open port 80/443
sudo iptables -I INPUT 6 -m state --state NEW -p tcp --dport 80 -j ACCEPT
sudo iptables -I INPUT 7 -m state --state NEW -p tcp --dport 443 -j ACCEPT
sudo netfilter-persistent save
#modify nginx configuration
#1. change the first line to 'user loginname;', for example 'user ubuntu;'
#2. add a line 'client_max_body_size 16M;' to http section
sudo vim /etc/nginx/nginx.conf
vim ./tools/nginx/nginx_default #change server_name if you want
sudo cp -rf ./tools/nginx/nginx_default /etc/nginx/sites-enabled/default
sudo nginx -t #test if nginx config file is correct
#set gunicorn auto start
sudo cp ./tools/nginx/gunicorn.service /usr/lib/systemd/system/gunicorn.service
sudo systemctl daemon-reload
sudo systemctl start gunicorn
sudo systemctl status gunicorn
sudo systemctl enable gunicorn
sudo systemctl restart nginx
sudo systemctl status nginx
# First, update the code using git/ftp/scp, etc. Ensure to preserve the database files.
sudo systemctl restart gunicorn
sudo systemctl status gunicorn # Confirm it is running
Now you can use "http://ip" in your browser to confirm if the deployment was successful. If you have a SSL certificate, you can also proceed to configure Nginx to use SSL. If you already have a domain name, you can bind it to your instance. If not, you can easily apply for one from a free domain registrar like FreeDomain.One or Freenom etc. I applied for a domain name at FreeDomain.One, which was very simple. After successfully applying, you just need to enter the IP address of your Oracle Cloud instance on the page, without any complicated configurations.
To check for errors, use the following commands to query the backend logs:
cat /var/log/nginx/error.log | tail -n 100
cat /home/ubuntu/log/gunicorn.error.log | tail -n 100
cat /home/ubuntu/log/gunicorn.access.log | tail -n 100
DATABASE_URL = "mysql://name:pass@name.mysql.pythonanywhere-services.com/name$default"
TASK_QUEUE_SERVICE = ""
TASK_QUEUE_BROKER_URL = ""
Log in to PythonAnywhere, go to the "Web" tab, click "Add a new web app" on the left, and create a Flask application.
Go to the "Databases" tab, initialize mysql and create a database.
Refer to the UploadingAndDownloadingFiles documentation to upload the code using the git or zip method.
pip install -r requirements.txt
.python /home/yourname/yourdirectory/main.py deliver now
If deployed on PythonAnywhere, the delivery time setting on the web page is invalid, and the delivery time is the time of this Task.
Note: After testing, it is not suitable for our application deployment unless paid, because it has many restrictions. The most fatal restriction is that it implements a whitelist for websites that free users can access. Websites not in its list cannot be accessed.