{"id":29035362,"url":"https://github.com/miguelrizzi/pythonanywhere-deploy-ssh","last_synced_at":"2025-06-26T12:08:21.094Z","repository":{"id":301049950,"uuid":"1002255627","full_name":"MiguelRizzi/pythonanywhere-deploy-ssh","owner":"MiguelRizzi","description":"A GitHub Action for redeploying Django applications to PythonAnywhere using SSH.","archived":false,"fork":false,"pushed_at":"2025-06-24T23:10:27.000Z","size":34,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-06-24T23:19:09.085Z","etag":null,"topics":["auto-deploy","django","github-actions","pythonanywhere"],"latest_commit_sha":null,"homepage":"","language":"Shell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/MiguelRizzi.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2025-06-15T04:04:56.000Z","updated_at":"2025-06-22T19:47:54.000Z","dependencies_parsed_at":"2025-06-24T23:19:12.737Z","dependency_job_id":"b77bd518-dabf-4c5f-b381-3f5bb8c306bc","html_url":"https://github.com/MiguelRizzi/pythonanywhere-deploy-ssh","commit_stats":null,"previous_names":["miguelrizzi/pythonanywhere-deploy-ssh"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/MiguelRizzi/pythonanywhere-deploy-ssh","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MiguelRizzi%2Fpythonanywhere-deploy-ssh","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MiguelRizzi%2Fpythonanywhere-deploy-ssh/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MiguelRizzi%2Fpythonanywhere-deploy-ssh/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MiguelRizzi%2Fpythonanywhere-deploy-ssh/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/MiguelRizzi","download_url":"https://codeload.github.com/MiguelRizzi/pythonanywhere-deploy-ssh/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/MiguelRizzi%2Fpythonanywhere-deploy-ssh/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":262063486,"owners_count":23252765,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["auto-deploy","django","github-actions","pythonanywhere"],"created_at":"2025-06-26T12:08:20.364Z","updated_at":"2025-06-26T12:08:21.075Z","avatar_url":"https://github.com/MiguelRizzi.png","language":"Shell","readme":"# 🚀 PythonAnywhere Redeploy Action\n\nThis GitHub Action automates the redeployment process of a Django application hosted on [PythonAnywhere](https://www.pythonanywhere.com) using SSH.  \nIt simplifies the workflow of pulling the latest code, installing dependencies, running migrations, and restarting the web server with minimal configuration.   \n\n\n## ✅ Requirements\n\nBefore using this action, make sure that:\n\n- You have a **paid PythonAnywhere account**, as SSH access is only available for paid plans.\n- SSH access is enabled on your PythonAnywhere account.\n- Your Django project is deployed on PythonAnywhere and cloned via Git.\n\n\n## 📦 What does this action do?\n\n- Connects to PythonAnywhere via SSH  \n- Pulls the latest code from the `main` branch  \n- Installs Python dependencies with `pip`  \n- Runs `collectstatic` and `migrate`  \n- Runs tests\n- Restarts the web server by touching the `WSGI` file\n\n\n## 🛠️ Usage\n\n### Workflow example\n\n```yaml\nname: Redeploy to PythonAnywhere\n\non:\n  push:\n    branches:\n      - main\n\njobs:\n  deploy:\n    runs-on: ubuntu-latest\n    steps:\n      - name: Checkout repo\n        uses: actions/checkout@v4\n\n      - name: Redeploy to PythonAnywhere\n        uses: MiguelRizzi/pythonanywhere-deploy-ssh@v1.0.0\n        with:\n          # Optional: specify the SSH host (defaults to ssh.pythonanywhere.com)\n          # ssh_host: ssh.eu.pythonanywhere.com\n\n          # Required: your PythonAnywhere username\n          username: ${{ secrets.PA_USERNAME }}\n\n          # Required (if no ssh_private_key): your PythonAnywhere password\n          # password: ${{ secrets.PA_PASSWORD }}\n\n          # Required (if no password): SSH private key\n          ssh_private_key: ${{ secrets.PA_SSH_PRIVATE_KEY }}\n\n          # Required: target working directory on PythonAnywhere\n          working_directory: ${{ secrets.PA_WORKING_DIRECTORY }}\n\n          # Required: path to your virtual environment\n          venv_directory: ${{ secrets.PA_VENV_DIRECTORY }}\n\n          # Required: path to your WSGI file\n          wsgi_file: /var/www/webapp_name_wsgi.py\n```\n\u003e 💡 Use `ssh.pythonanywhere.com` for US accounts or `ssh.eu.pythonanywhere.com` for EU-based accounts.  \n🔐 You must provide **at least one** of the following:  `password` or `ssh_private_key`\n\n\n## Inputs\n\n| Name      | Description | Required | Example |\n|-----------|-------------|----------|---------|\n| `ssh_host`  | Optional SSH host for PythonAnywhere (default: `ssh.pythonanywhere.com`) | No | `ssh.eu.pythonanywhere.com` |\n| `username`  | Your PythonAnywhere username | Yes | `username` |\n| `password`  | Your PythonAnywhere password | No | `password` |\n| `ssh_private_key`  | SSH private key (optional, but required if `password` is not provided) | No | *contents of your private key* |\n| `working_directory`  | Target working directory on PythonAnywhere | Yes | `/home/username/webapp_name` |\n| `venv_directory`  | Path to the Python virtual environment | Yes | `/home/username/webapp_name/.venv` |\n| `wsgi_file` | Path to the WSGI file to reload the app | Yes | `/var/www/webapp_name_wsgi.py` |\n \n\n## 🔐 Security\n\nAlways store sensitive data like credentials and SSH keys as [GitHub Secrets](https://docs.github.com/en/actions/security-guides/encrypted-secrets):\n\n- **Recommended secrets**:\n  - `username`\n  - `password`\n  - `ssh_private_key`\n\nThese values can expose your account if leaked, even in public forks or workflow logs.\n\n- For paths such as `working_directory`, `venv_directory`, and `wsgi_file`:\n  - Using secrets is **optional**.\n  - You can define them directly in the YAML file if they do not contain sensitive data and remain consistent across environments.\n  - **Using secrets is recommended if:**\n    - They include your username\n    - You want to keep the configuration more private or flexible\n\n## 📂 Creating GitHub Secrets\n\n1. In your GitHub repository, go to **Settings**\n2. Navigate to **Secrets and variables → Actions**\n3. Click **New repository secret**\n4. Name the secret (e.g., `PA_USERNAME`, `PA_SSH_PRIVATE_KEY`, etc.)\n5. Paste the corresponding value\n\nRepeat for each required secret.\n\n\u003e ⚠️ **Do not commit secrets directly into your repository.** Always use GitHub Secrets to store sensitive information.\n\n\n## 📋 Using an SSH Key (Recommended)\n\n### 1. Generate an SSH key (if you don't have one):\n\nIf you don’t already have an SSH key pair for authentication, you can generate one using the following command:\n\n```bash\n$ ssh-keygen -t ed25519\n```\n- When prompted, press Enter to accept the default file location (`~/.ssh/id_ed25519`).\n\n- You may set a passphrase for added security (optional).\n\n### 2. Add the **public key** to PythonAnywhere:\n\nTo add the public key to PythonAnywhere, run the following command:\n\n```bash\n$ ssh-copy-id \u003cusername\u003e@ssh.pythonanywhere.com\n```\nEnter your PythonAnywhere password when prompted.\n\n\u003e 💡 Use `ssh.eu.pythonanywhere.com` for EU-based accounts.\n\n\n### 3. Store the **private key** securely:\nTo store the private key securely, follow these steps:\n- Copy the contents of the private key file (.ssh/id_ed25519) running the command \n```bash\ncat ~/.ssh/id_ed25519\n```\n- Create a new secret in your GitHub repository following the instructions in the [Creating GitHub Secrets](#-creating-github-secrets) section.\n- Paste the contents of the private key into the secret field.\n\n\u003e 💡 Make sure to keep your private key secure and do not share it with anyone.\n\nFor more information on SSH setup, refer to: [SSH Access on PythonAnywhere](https://help.pythonanywhere.com/pages/SSHAccess/)\n\n## ⚠️ Repository Structure\n\nThis action is composed of:\n\n- `action.yml`  \nDefines the input interface of the GitHub Action (required inputs) and specifies the execution environment. In this case, it sets up execution in a Docker container that runs the `deploy.sh` script.\n\n- `deploy.sh`  \nMain script executed inside the container. It uses SSH to connect to PythonAnywhere, performs `git pull`, installs dependencies, runs migrations, collects static files and restarts the web server by touching the `WSGI.py` file.\n\n- `Dockerfile`  \nDefines a custom Docker image based on ubuntu, installs the necessary tools for SSH connections, and copies the required scripts. This ensures the environment has all the necessary tools to perform the redeploy process without relying on the host runner.\n\n- `.github/workflows/example.yml`  \nProvides an example of how to use the action in a workflow. You can use it as a template or reference when setting up your own deployment workflow.\n\n\n## 📝 License\n\nThis GitHub Action is distributed under the [MIT License](https://github.com/MiguelRizzi/pythonanywhere-deploy-ssh/blob/main/LICENSE).\n\n\n---\n\nMade with ❤️ to simplify PythonAnywhere deployments.","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmiguelrizzi%2Fpythonanywhere-deploy-ssh","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmiguelrizzi%2Fpythonanywhere-deploy-ssh","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmiguelrizzi%2Fpythonanywhere-deploy-ssh/lists"}