{"id":18026767,"url":"https://github.com/yegor256/threecopies","last_synced_at":"2025-09-07T22:39:24.785Z","repository":{"id":54005516,"uuid":"95348831","full_name":"yegor256/threecopies","owner":"yegor256","description":"Hosted Server Backup Service","archived":false,"fork":false,"pushed_at":"2025-09-03T21:27:01.000Z","size":533,"stargazers_count":36,"open_issues_count":18,"forks_count":5,"subscribers_count":4,"default_branch":"master","last_synced_at":"2025-09-03T23:23:38.002Z","etag":null,"topics":["backup","eolang","java","mysql","web-service"],"latest_commit_sha":null,"homepage":"https://www.threecopies.com","language":"Java","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/yegor256.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.txt","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,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2017-06-25T08:56:13.000Z","updated_at":"2025-08-17T10:46:22.000Z","dependencies_parsed_at":"2024-08-27T20:25:42.947Z","dependency_job_id":"c7373903-105e-4ff9-9b08-d43c60d84375","html_url":"https://github.com/yegor256/threecopies","commit_stats":null,"previous_names":[],"tags_count":16,"template":false,"template_full_name":null,"purl":"pkg:github/yegor256/threecopies","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yegor256%2Fthreecopies","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yegor256%2Fthreecopies/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yegor256%2Fthreecopies/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yegor256%2Fthreecopies/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/yegor256","download_url":"https://codeload.github.com/yegor256/threecopies/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/yegor256%2Fthreecopies/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":274107777,"owners_count":25223459,"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","status":"online","status_checked_at":"2025-09-07T02:00:09.463Z","response_time":67,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":["backup","eolang","java","mysql","web-service"],"created_at":"2024-10-30T08:07:57.404Z","updated_at":"2025-09-07T22:39:24.760Z","avatar_url":"https://github.com/yegor256.png","language":"Java","readme":"\u003cimg alt=\"logo\" src=\"src/main/resources/images/logo.png\" width=\"64px\" height=\"64px\" alt=\"ThreeCopies logo\"/\u003e\n\n[![Managed by Zerocracy](https://www.0crat.com/badge/C3RFVLU72.svg)](https://www.0crat.com/p/C3RFVLU72)\n[![DevOps By Rultor.com](http://www.rultor.com/b/yegor256/threecopies)](http://www.rultor.com/p/yegor256/threecopies)\n\n[![Availability at SixNines](https://www.sixnines.io/b/5c94)](https://www.sixnines.io/h/5c94)\n[![mvn](https://github.com/yegor256/threecopies/actions/workflows/mvn.yml/badge.svg)](https://github.com/yegor256/threecopies/actions/workflows/mvn.yml)\n[![PDD status](http://www.0pdd.com/svg?name=yegor256/threecopies)](http://www.0pdd.com/p?name=yegor256/threecopies)\n[![codecov](https://codecov.io/gh/yegor256/threecopies/branch/master/graph/badge.svg)](https://codecov.io/gh/yegor256/threecopies)\n\n## What does it do?\n\n[ThreeCopies.com](http://www.threecopies.com) is a hosted service that\nregularly archives your server-side resources. We create three\ncopies: hourly, daily and weekly.\n\nWhat's interesting is that the entire product \u003cdel\u003eis\u003c/del\u003e will be written in [EO](http://www.eolang.org),\na truly object-orented programming language.\n\nThe logo is made by [Freepik](http://www.freepik.com) from [flaticon.com](http://www.flaticon.com),\nlicensed by [CC 3.0 BY](http://creativecommons.org/licenses/by/3.0/).\n\n## How to configure\n\nEach script is a bash scenario, which you design yourself. ThreeCopies\njust starts it regularly and records its output. These are some\nrecommendations on how to design the script. There are three parts:\ninput, package, and output. First, you collect some data from your data\nsources (input). Then, you compress and encrypt the data (package). Finally,\nyou store the package somewhere (output).\n\nWe start your script inside\n[yegor256/threecopies](https://hub.docker.com/r/yegor256/threecopies-image/)\nDocker container,\nhere is the\n[`Dockerfile`](https://github.com/yegor256/threecopies-image/blob/master/Dockerfile).\n\nIf you don't want your script to be executed too frequently, you may put\nthis code in front of it (to skip hourly executions, for example):\n\n```bash\nif [ \"${period}\" == \"hour\" ]; then exit 0; fi\n```\n\n### 1. Input\n\nTo retrieve the data from a MySQL database use [mysqldump](https://dev.mysql.com/doc/refman/5.7/en/mysqldump.html):\n\n```bash\nmysqldump --lock-tables=false --host=www.example.com \\\n  --user=username --password=password \\\n  --databases dbname \u003e mysql.sql\n```\nSince this would require to open your mysql port to the internet, which is not advisable from a security perspective, you should probably use a ssh tunnel:\n\n```bash\ncat \u003e file.key \u003c\u003cEOT\n-----BEGIN RSA PRIVATE KEY-----\n\u003cyour ssh private key here\u003e\n-----END RSA PRIVATE KEY-----\nEOT\nchmod 700 file.key\nssh -Nf -i file.key -L3306:localhost:3306 your_user@www.example.com\nrm file.key\n```\nand then connect with the above script:\n\n```bash\nmysqldump --lock-tables=false --host=localhost ...same as above\n```\n\nTo download an entire FTP directory use [wget](https://www.gnu.org/software/wget/):\n\n```bash\nwget --mirror --tries=5 --quiet --output-file=/dev/null \\\n  --ftp-user=username --ftp-password=password \\\n  ftp://ftp.example.com/some-directory\n```\n\n### 2. Package\n\nTo package a directory use [tar](https://help.ubuntu.com/community/BackupYourSystem/TAR):\n\n```bash\ntgz=\"${period}-$(date \"+%Y-%m-%d-%H-%M\").tgz\"\ntar czf \"${tgz}\" some-directory\n```\n\nWe recommend to use exactly that name of your `.tgz` archives. The\n`${period}` environment variable is provided by our server to your\nDocker container, it will either be set to `hour`, `day`, or `week`.\n\n### 3. Output\n\nTo upload a file to Amazon S3, using [s3cmd](http://s3tools.org/s3cmd):\n\n```bash\necho \"[default]\" \u003e ~/.s3cfg\necho \"access_key=AKIAICJKH*****CVLAFA\" \u003e\u003e ~/.s3cfg\necho \"secret_key=yQv3g3ao654Ns**********H1xQSfZlTkseA0haG\" \u003e\u003e ~/.s3cfg\ns3cmd --no-progress put \"${tgz}\" \"s3://backup.example.com/${tgz}\"\n```\n\n## DynamoDB Schema\n\nThe `tc-scripts` table contains all registered scripts:\n\n```\nfields:\n  login/H: GitHub login of the owner\n  name/R: Unique name of the script\n  bash: Bash script\n  hour: Epoch-sec when its recent hourly log was scheduled\n  day: Epoch-sec when its recent daily log was scheduled\n  week: Epoch-sec when its recent weekly log was scheduled\n```\n\nThe `tc-logs` table contains all recent logs:\n\n```\nfields:\n  group/H: Concatenated GitHub login and script name, e.g. \"yegor256/test\"\n  finish/R: Epoch-msec of the script finish (or MAX_LONG if still running)\n  login: GitHub login of the owner\n  period: Either \"hour\", \"day\", or \"week\"\n  ocket: S3 object name for the log\n  ttl: Epoch-sec when the record has to be deleted (by DynamoDB)\n  start: Epoch-msec time of the start\n  container: Docker container name\n  exit: Bash exit code (error if not zero)\nmine (index):\n  login/H\n  finish/R\n```\n\n## How to contribute?\n\nJust submit a pull request. Make sure `mvn -Pqulice install` passes.\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fyegor256%2Fthreecopies","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fyegor256%2Fthreecopies","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fyegor256%2Fthreecopies/lists"}