Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .dtop.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
hosts:
- host: local
dozzle: https://logs.localhost/
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
name: PostgreSQL Backup
name: Backup
on:
schedule:
- cron: '0 0 * * *' # Sync daily at midnight
Expand All @@ -9,7 +9,7 @@ concurrency:
jobs:
pg_dump:
if: vars.SSH_HOSTNAME != ''
name: Capture and store backup
name: PostgreSQL
runs-on: ubuntu-latest
environment:
name: production
Expand Down
File renamed without changes.
10 changes: 10 additions & 0 deletions bin/backup_download.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
#!/usr/bin/env sh

# Download the database dump from the latest GitHub workflow
# Usage: ./backup_download.sh [workflow_id]

set -eux

workflow_id="${1:-$(gh api "repos/{owner}/{repo}/actions/runs" | jq -r '.workflow_runs[] | select(.name == "Backup" and .conclusion == "success") | .id' | sed 's/"//g' | head -n 1)}"

gh run download "$workflow_id" -n backup.dump
12 changes: 12 additions & 0 deletions bin/backup_restore.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#!/usr/bin/env sh

# Restore the PostgreSQL database from a dump file
# Usage: ./backup_restore.sh [dump_file] [database_name] [num_jobs]

set -eux

dump_file="${1:-backup.dump}"
database_name="${2:-postgres}"
num_jobs="${3:-$(getconf _NPROCESSORS_ONLN)}"

pg_restore "$dump_file" -d "$database_name" --no-acl --no-owner --no-privileges -j "$num_jobs" --disable-triggers
1 change: 1 addition & 0 deletions compose.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
include:
- path:
- containers/web/compose.yml
- containers/web/python/compose.yml
- containers/compose.smtp.yml
- containers/compose.postgres.yml
Expand Down
10 changes: 10 additions & 0 deletions containers/web/compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
services:
web:
memswap_limit: 1g # Limit total memory usage (RAM + swap) to 1GB
deploy:
mode: replicated
replicas: 2
resources:
limits:
cpus: '0.25' # Limit to 25% of a CPU
Copy link

Copilot AI Nov 26, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment states "Limit to 50% of a CPU" but the actual value is '0.25' which limits to 25% of a CPU. The comment should say "Limit to 25% of a CPU" to match the configured value.

Copilot uses AI. Check for mistakes.
memory: 512M # Limit to 512MB of RAM
21 changes: 21 additions & 0 deletions docs/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# freePaaS

freePaaS is an open-source platform-as-a-service (PaaS) solution that enables developers to easily deploy, manage, and scale applications in a cloud environment. It provides a user-friendly interface and a variety of tools to streamline the application lifecycle, from development to production.

## Features

- [Easy Deployment](deployment.md): Deploy applications with just a few clicks.
- [Scalability](scaling.md): Automatically scale applications based on demand.
- [Monitoring](monitoring.md): Keep track of application performance and health.
- [Environment Management](enviroment.md): Manage configuration and environment variables effectively.
Copy link

Copilot AI Nov 26, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The link reference has a spelling error: "enviroment.md" should be "environment.md" (missing 'n').

Suggested change
- [Environment Management](enviroment.md): Manage configuration and environment variables effectively.
- [Environment Management](environment.md): Manage configuration and environment variables effectively.

Copilot uses AI. Check for mistakes.
- [Backups](backups.md): Schedule and manage database backups with ease.
- [File Storage](storage.md): Handle file uploads and storage seamlessly.

## Why and How

freePaaS aims to provide a zero touch CD pipeline for developers, allowing them to focus on writing code rather than managing infrastructure.

It is built around best practices to provide simplicity and security, while providing you the freedom to customize anything you want.

freePaaS uses technologies most developers are already familiar with to lower the learning curve and speed up adoption.
No PhD in Kubernetes is required to deploy and manage applications, since we don't use it.
34 changes: 34 additions & 0 deletions docs/backups.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# Backups

## Database backups

PostgreSQL backups are captured daily using [pg_dump](https://www.postgresql.org/docs/current/app-pgdump.html) and stored as repository artifacts in GitHub Actions.

### Durability

By default, GitHub retains workflow artifacts for 90 days. You can [adjust the retention period](https://docs.github.com/en/organizations/managing-organization-settings/configuring-the-retention-period-for-github-actions-artifacts-and-logs-in-your-organization) up to a maximum of 400 days.

Importantly, artifacts are stored independently of your application server, ensuring that backups remain safe even if your server fails.

The backup frequency may be altered in the [`.github/workflows/backup.yml`](../.github/workflows/backup.yml) file. Here you may also configure additional backup targets, such as cloud storage providers.

### Restoration

To restore a backup, download the desired artifact from the GitHub Actions workflow run history. The artifact will be a compressed file containing the SQL dump.

You can restore the database using the built-in database scripts:

```bash
bin/backup_download.sh
bin/backup_restore.sh
```

> [!NOTE]
> Backups are stored in PostgreSQL's [custom format](https://www.postgresql.org/docs/current/app-pgdump.html) which is compressed and allows for more flexible restoration options.

### Privacy

With backups being stored on GitHub, it's crucial to consider the sensitivity of your data. Ensure that your repository is private to prevent unauthorized access to your backups. Additionally, consider encrypting your database dumps before uploading them as artifacts for an added layer of security.

> [!IMPORTANT]
> If you are serving customers in the EU, ensure that you add GitHub as a data processor in your privacy policy to comply with GDPR regulations.
34 changes: 34 additions & 0 deletions docs/deployment.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
# Deployment

Deploying your application with freePaaS is a streamlined process that involves running an installation script and leveraging GitHub Actions for continuous deployment.

## Initial Setup

The primary setup is handled by an interactive script. To start the installation wizard, run the following command from the root of the repository:

```bash
./bin/install.sh
```

This script will guide you through the following steps:

1. **Domain Configuration**: You will be prompted to enter your domain name.
1. **Server Access**: The script will verify SSH access to your server.
1. **GitHub Integration**: It will help you create a GitHub OAuth App for secure authentication.
1. **Repository Configuration**: The script will set up the necessary GitHub repository secrets and variables to enable automated deployments. These include:
- `SSH_HOSTNAME`: Your server's hostname or IP address.
- `SSH_PRIVATE_KEY`: A private SSH key for accessing the server.
- `SSH_KNOWN_HOSTS`: Your server's SSH host key.

## Continuous Deployment

Once the initial setup is complete, your application will be automatically deployed whenever you push changes to the `main` branch. This is handled by the [`.github/workflows/deploy.yml`](../.github/workflows/deploy.yml) GitHub Actions workflow.

The deployment workflow performs the following steps:

1. **Trigger**: The workflow is triggered by a push to the `main` branch (after the `ci` workflow succeeds) or can be triggered manually.
1. **Environment Setup**: It sets up an SSH connection to your production server using the configured secrets.
1. **Remote Deployment**: It establishes a remote Docker context to your server.
1. **Application Start**: It uses `docker compose` to pull the latest images and start the application containers.

Your application will be served via a Caddy reverse proxy, which also handles automatic SSL certificate provisioning.
49 changes: 49 additions & 0 deletions docs/enviroment.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
# Environment
Copy link

Copilot AI Nov 26, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The filename has a spelling error: "enviroment.md" should be "environment.md" (missing 'n').

Copilot uses AI. Check for mistakes.

[12-factor] apps are designed to be portable and resilient by strictly separating configuration from code. This approach allows applications to adapt seamlessly across different environments, such as development, staging, and production.

Your environment variables are stored on GitHub in your repository.

## Default runtime variables

The default variables are set:

- `HOSTNAME`: The hostname of your application.
- `DATABASE_URL`: The URL for your database connection.
- `REDIS_URL`: The URL for your Redis instance.
- `EMAIL_URL`: The URL to your SMTP relay instance.

## Managing variables

GitHub can store multiple environments for a single repository. Each environment can have its own set of variables and secrets. You can create environments such as `development`, `staging`, and `production` to manage different configurations for each stage of your application lifecycle.

If your workflow targets a specific environment, GitHub Actions will automatically load the corresponding variables and secrets for that environment during the workflow run.

> [!IMPORTANT]
> GitHub will inherit secrets from the repository level to the environment level, but not the other way around. Be cautious when naming secrets at both levels to avoid unintentional overrides. Environment-level secrets will take precedence over repository-level secrets with the same name.

### Variables

Variables are stored in plain text and retrievable.

```bash
# With body
gh variable set VARIABLE_NAME --env production --body "variable_value"
# from file
gh variable set VARIABLE_NAME --env production <path/to/file
```

### Secrets

Secrets are securely stored and non-retrievable.

```bash
# With body
gh secret set SECRET_NAME --env production --body "variable_value"
# from file
gh secret set SECRET_NAME --env production <path/to/file
# create a random secret
python -c "import secrets; print(secrets.token_urlsafe())" | gh secret set SECRET_NAME --env production
```

[12-factor]: https://12factor.net/
27 changes: 27 additions & 0 deletions docs/monitoring.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Monitoring

Monitoring is a crucial aspect of managing applications deployed on freePaaS. It allows developers and administrators to keep track of application performance, resource usage, and overall health. freePaaS provides built-in monitoring tools that offer insights into various metrics, enabling proactive management and troubleshooting.

## Built-in Monitoring Tools

freePaaS integrates [Dozzle] and [dtop] to provide real-time monitoring and logging capabilities.

To access the monitoring tools, navigate to the following URLs in your web browser:

- Dozzle: `http://logs.<your-domain>`

To access via shell, use the following commands:

```bash
dtop
```

The bootstrap script creates a `.dtop.yml` configuration file for your project with production and development contexts.

## Application Monitoring

freePaaS provides only basic monitoring tools out of the box to help you assess your container health. For more advanced monitoring, logging, and alerting capabilities, consider integrating third-party services such as [Sentry].
Copy link

Copilot AI Nov 26, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Spelling error: "asses" should be "assess".

Copilot uses AI. Check for mistakes.

[dozzle]: https://dozzle.dev/
[dtop]: https://dtop.dev/
[sentry]: https://sentry.io/welcome/
60 changes: 60 additions & 0 deletions docs/scaling.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
# Scaling

freePaaS allows you to start small and scale your applications as they grow in popularity. There are multiple ways to progressively scale your applications depending on your needs without breaking the bank.

## Scaling services

freePaaS defaults to a highly available web server setup with a minimum of two web servers behind a load balancer. This allows your application to handle more traffic and provides redundancy in case one of the web servers goes down.

You can easily add more web servers to your application by simply adding more containers to the `web` service in your `compose.yml` file.

```yaml
services:
web:
deploy:
replicas: 3 # Increase the number of replicas
```

You may also scale ad-hoc using the Docker CLI:

```bash
docker service scale web=5 # Scale to 5 replicas
```

### Resource management

You can also limit the resources used by each service in your [`containers/web/compose.yml`](../containers/web/compose.yml) file. This allows you to control the amount of CPU and memory used by each service.

```yaml
services:
web:
memswap_limit: 1g # Limit total memory + swap to 1GB
deploy:
resources:
limits:
cpus: '0.50' # Limit to 50% of a CPU
memory: 512M # Limit to 512MB of RAM
reservations:
cpus: '0.25' # Reserve 25% of a CPU
memory: 256M # Reserve 256MB of RAM
```

> [!IMPORTANT]
> Setting resource limits is important to prevent a single service from consuming all available resources on the server, which could lead to performance degradation or crashes. You MUST always set `memswap_limit` to prevent services from using swap space. Swapping will prevent OOM (out of memory) restarts.

## Long term growth strategies

### Scaling Vertically

Most datacenters will offer VPS or dedicated servers in a variety of sizes and the ability to upgrade an existing server to a larger size. This is known as vertical scaling or scaling up.

This will probably be the easiest way to scale your application, especially if you are just starting out. Simply upgrade your server to a larger size and freePaaS will automatically take advantage of the additional resources.

### Scaling Horizontally

When your application outgrows the resources of a single server, you can just add a second one. Docker [Swarm mode](https://docs.docker.com/engine/swarm/) is low effort way to just add more servers to your PaaS. Setup takes minutes and freePaaS will automatically distribute your applications across the available servers.
Copy link

Copilot AI Nov 26, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Grammar error: "is low effort way" should be "is a low-effort way" (missing article and hyphenation).

Suggested change
When your application outgrows the resources of a single server, you can just add a second one. Docker [Swarm mode](https://docs.docker.com/engine/swarm/) is low effort way to just add more servers to your PaaS. Setup takes minutes and freePaaS will automatically distribute your applications across the available servers.
When your application outgrows the resources of a single server, you can just add a second one. Docker [Swarm mode](https://docs.docker.com/engine/swarm/) is a low-effort way to just add more servers to your PaaS. Setup takes minutes and freePaaS will automatically distribute your applications across the available servers.

Copilot uses AI. Check for mistakes.

### Hyperscale

Congratulations, you made it! Your application is so popular that you need to scale beyond a few servers.
Luckily, you are not locked to any specific cloud provider or technology. Since your entire application is already containerized, you can easily migrate to a Kubernetes based solution or a managed container service like AWS ECS, Google GKE or Azure AKS.
21 changes: 21 additions & 0 deletions docs/storage.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# File Storage

freePaaS doesn't offer built-in file storage solutions by default.

Secure storage is a complex topic with many considerations. We recommend using specialized third-party services that are designed to handle file storage securely and efficiently. All major cloud providers offer object storage solutions (compatible with AWS S3) that can be easily integrated into your application.

> [!IMPORTANT]
> Web containers in freePaaS are designed to be stateless, meaning that any files stored locally within the container will be lost if the container is restarted or redeployed. Therefore, it's crucial to use external storage solutions for any files that need to persist beyond the lifecycle of a single container instance.

## Local storage (not recommended)

If you still want to use local storage for development or testing purposes, you can mount a volume to your web container by modifying the `volumes` section in the [`containers/web/compose.yml`](../containers/web/compose.yml) file.

```yaml
services:
web:
volumes:
- /path/on/host:/path/in/container:z
```

This will mount the specified host directory to the container, allowing files to persist across container restarts. However, be aware that this approach may lead to data loss and performance issues in a production environment.