Compare commits

...
55 Commits
Author SHA1 Message Date
futile 5ee5a2cfb0 oops dont default to that 2026-07-25 21:36:41 +01:00
futile f6cfb706da sometimes do hot backups 2026-07-25 21:31:15 +01:00
futile 7d4f8ca9c5 home: update back urls 2026-07-24 16:43:49 +01:00
futile 3b661a698e update caddyfile 2026-07-24 16:41:00 +01:00
futile 132cc91d06 update caddyfile 2026-07-24 16:31:15 +01:00
futile 0fbe068197 update readme 2026-07-24 13:24:33 +01:00
futile 2ebf7ca958 scripts: update ssh port 2026-07-24 13:23:49 +01:00
futile 08c4c78c8e scripts: add gdu to packages 2026-07-24 11:12:48 +01:00
futile 9ce6a93b99 home: update setup 2026-07-24 11:11:55 +01:00
futile a20dc43559 home: amend terms 2026-07-24 11:11:37 +01:00
futile d56192ce0d home: update style 2026-07-24 11:11:15 +01:00
futile 28ff6a9fdc docs: correctly name cloned dir in setup 2026-07-24 10:33:20 +01:00
futile 2ea01a8824 home: link to privacy/terms history 2026-07-24 10:33:07 +01:00
futile fe775a5a7e home: amend terms 2026-07-24 10:30:23 +01:00
futile 33eb9d7748 home: add a last updated timestamp to terms & privacy 2026-07-24 10:10:59 +01:00
futile 81486654de home: update setup 2026-07-23 21:57:53 +01:00
futile 7228c8c131 home: amend terms 2026-07-23 21:54:55 +01:00
futile 977cfb2197 home: improve setup page 2026-07-23 19:10:19 +01:00
futile 0e98866699 update todo 2026-07-23 18:58:47 +01:00
futile 596aa4c3f2 home: write terms & privacy 2026-07-23 18:55:58 +01:00
futile e5f765dba1 home: simplify back 2026-07-23 17:51:34 +01:00
futile 6a9e5a5b68 docs: add some links 2026-07-23 17:20:31 +01:00
futile d04b908996 update todo 2026-07-23 15:29:22 +01:00
futile 80b92acd7a forgor 2026-07-23 14:23:43 +01:00
futile 2cdda03224 home: apply crossorigin to font preloads 2026-07-23 14:22:52 +01:00
futile 840fd46a73 home: optimise images 2026-07-23 14:21:43 +01:00
futile b7e130a24e home: host inter font ourselves 2026-07-23 14:07:56 +01:00
futile 3b2d0335bd home: hopefully make background image load smoother 2026-07-23 13:19:02 +01:00
futile 29f0490924 home: fix bad convention 2026-07-23 13:15:47 +01:00
futile e447f6d775 home: add setup page 2026-07-23 13:05:12 +01:00
futile 001f2cd741 fak 2026-07-23 12:53:51 +01:00
futile a8521ad139 home: move css files to style/ 2026-07-23 12:52:50 +01:00
futile 3a0ee27b6f home: use avif for clouds background 2026-07-23 12:50:36 +01:00
futile 3c9eac23b4 docs: organise documentation 2026-07-23 11:46:52 +01:00
futile bba89d706a home: css cleanup 2026-07-23 09:33:20 +01:00
futile 1098ba0c38 home: test css improvement 2026-07-23 07:12:20 +01:00
futile 60a9109389 home: update images and css 2026-07-23 07:06:15 +01:00
futile 8d3d9518fa fix the fucking back button 2026-07-22 17:47:51 +01:00
futile 321d3303a4 home: attempt to improve phone sizing 2026-07-22 13:28:09 +01:00
futile d9eb55708c home: add favicon 2026-07-22 13:24:01 +01:00
futile 67c0ee9cba home: update website 2026-07-22 13:21:38 +01:00
futile 74945b5618 update readme 2026-07-22 08:40:44 +01:00
futile dd83e47654 they call me retarded 2026-07-22 05:28:15 +01:00
futile 4527246427 initial version of website 2026-07-22 05:26:19 +01:00
futile 0992e183aa fix 2026-07-21 11:31:17 +01:00
futile 154b9f2ebd update dns setup 2026-07-21 11:25:47 +01:00
futile ebe9063687 fix 2026-07-21 11:02:10 +01:00
futile 24987e25b4 fix 2026-07-21 10:30:48 +01:00
futile e302605d47 update 2026-07-21 10:27:39 +01:00
futile 22178fa47a update readme 2026-07-20 08:06:33 +01:00
futile d2a5bb90da update readme 2026-07-19 11:31:27 +01:00
futile abc2dabd34 add gitea initial setup to readme 2026-07-19 08:51:18 +01:00
futile f929547a91 update readme 2026-07-19 08:37:48 +01:00
futile ae3f68b96a don't backup so often 2026-07-19 08:09:26 +01:00
futile 2231626fb6 gitea on top 2026-07-19 07:20:58 +01:00
26 changed files with 527 additions and 174 deletions
+4 -4
View File
@@ -1,16 +1,16 @@
# stalwart # stalwart
STALWART_PUBLIC_URL=https://m.example.org STALWART_PUBLIC_URL=https://post.example.org
OIDC_KEY=GENERATE_STRING # openssl rand -hex 32 OIDC_KEY=GENERATE_STRING # openssl rand -hex 32
OIDC_SIGNATURE_KEY=GENERATE_PEM # openssl genpkey -algorithm EC -pkeyopt ec_paramgen_curve:secp384r1 -pkeyopt ec_param_enc:named_curve OIDC_SIGNATURE_KEY=GENERATE_PEM # openssl genpkey -algorithm EC -pkeyopt ec_paramgen_curve:secp384r1 -pkeyopt ec_param_enc:named_curve # ONE LINE, IN QUOTES, SEPARATED BY \n
# bulwark # bulwark
JMAP_SERVER_URL=https://m.example.org JMAP_SERVER_URL=https://post.example.org
SESSION_SECRET=GENERATE_STRING # openssl rand -hex 32 SESSION_SECRET=GENERATE_STRING # openssl rand -hex 32
SETTINGS_SYNC_ENABLED=true SETTINGS_SYNC_ENABLED=true
ADMIN_PASSWORD=GENERATE_PASSWORD # tr -dc 'A-Za-z0-9' < /dev/urandom | head -c 20; echo ADMIN_PASSWORD=GENERATE_PASSWORD # tr -dc 'A-Za-z0-9' < /dev/urandom | head -c 20; echo
# vykar # vykar
VYKAR_LABEL=borgbase VYKAR_LABEL=borgbase
VYKAR_URL=https://myrepo.repo.borgbase.com VYKAR_URL=https://REPO.repo.borgbase.com
VYKAR_ACCESS_TOKEN=ACCESS_TOKEN VYKAR_ACCESS_TOKEN=ACCESS_TOKEN
VYKAR_ENCRYPTION_SECRET=GENERATE_STRING # openssl rand -hex 32 VYKAR_ENCRYPTION_SECRET=GENERATE_STRING # openssl rand -hex 32
+1 -1
View File
@@ -1 +1 @@
.env *.env
+25 -4
View File
@@ -3,14 +3,35 @@
# acme_ca https://acme-staging-v02.api.letsencrypt.org/directory # acme_ca https://acme-staging-v02.api.letsencrypt.org/directory
# } # }
mail.yaoi.dog { atom.town {
root * /srv/home
encode zstd
# /index.html -> /
@indexhtml path_regexp idx ^(.*/)index\.html$
redir @indexhtml {re.idx.1} permanent
# /something.html -> /something
@html path_regexp strip ^(.+)\.html$
redir @html {re.strip.1} permanent
# something -> something.html
try_files {path} {path}.html {path}/index.html
file_server
@assets path /assets/*
header @assets Cache-Control "public, max-age=604800, immutable"
}
post.atom.town {
reverse_proxy stalwart:8080 reverse_proxy stalwart:8080
} }
post.yaoi.dog { mail.atom.town {
reverse_proxy bulwark:3000 reverse_proxy bulwark:3000
} }
git.yaoi.dog { git.atom.town {
reverse_proxy forgejo:3000 reverse_proxy gitea:3000
} }
+11 -143
View File
@@ -1,146 +1,14 @@
# thingy! # atom.town
some kind of hosting setup here, you will be at home.
## setup ## directory
1. log into the vps, make sure it's fedora (or else 🔪) - [setup](docs/setup.md)
2. create a new admin user - [caddy](docs/services/caddy.md)
- `sudo useradd -m -G wheel admin` - [stalwart](docs/services/stalwart.md)
- `sudo passwd admin` - [bulwark](docs/services/bulwark.md)
- `sudo su - admin` - [gitea](docs/services/gitea.md)
3. use the system setup script, and log out - [backups](docs/backups.md)
- `sudo dnf install git -y` - [misc](docs/misc.md)
- `git clone https://gitlab.com/futile/thingy` - [todo](docs/todo.md)
- `./thingy/scripts/system-setup.sh`
- `exit`
4. log in again, populate the `.env` and start everything up
- `cd thingy`
- `micro .env`
- `docker compose up`
5. continue with service-specific setups .....
## services
specifics for everything
**currently serving**
- via docker
- **caddy** http server & reverse proxy
- **stalwart** mailserver
- **bulwark** webmail
- via caddy
- `mail.yaoi.dog` mail (server & admin dash)
- `post.yaoi.dog` mail (webmail)
**dns setup**
| type | host | value | notes |
|-------|-----------|---------------------------- |----------------------------|
| `A` | `@` | `<ip>` | apex domain |
| `A` | `mail` | `<ip>` | mailserver |
| `A` | `post` | `<ip>` | webmail |
| `A` | `git` | `<ip>` | forgejo |
| `CAA` | `@` | `0 issue "letsencrypt.org"` | allow caddy to issue certs |
### caddy
todo
### stalwart
**first setup**
1. server identity
- server hostname: `mail.yaoi.dog`
- default email domain: `yaoi.dog`
- automatically obtain tls certificate: `true`
- generate email signing keys: `true`
2. storage
- main data storage: `rocksdb`
- path: `/var/lib/stalwart/`
3. account directory
- directory type: `use internal`
4. logging
- log destination: `console`
5. automatic dns management
- dns server type: `porkbun`
- description: `porkbun`
**further setup**
- settings -> security -> allowed ips
- added `172.18.0.0/24`; reason: `internal`
- settings -> network -> http -> security
- permissive cors policy: `true` **[restart needed]**
- settings -> authentication -> oidc provider
- oauth settings
- key: `secret read from environment variable`
- variable name: `OIDC_KEY`
- openid connect
- signature algorithm: `ECDSA using P-384 and SHA-384`
- signature key: `secret read from environment variable`
- variable name: `OIDC_SIGNATURE_KEY`
**useful links**
- https://stalw.art/docs
- https://testconnectivity.microsoft.com/tests/Imap/input
- https://mail-tester.com
### bulwark
todo
**useful links**
- https://bulwarkmail.org/docs
### forgejo
todo
## backups
backups are done with [vykar](https://vykar.borgbase.com) to [borgbase](https://borgbase.com)
always remember to `docker compose stop` before doing any of this!
**creating**
- if on a new borgbase repo, run `vykar init` first
- to back up, run `sudo vykar backup` (sudo required as we are accessing `/var/lib/docker/volumes/`)
- to back up automatically, run `sudo EDITOR=micro crontab -e` and add the following:
```
TZ=UTC
0 * * * * /home/admin/thingy/scripts/volume-backup.sh
```
**restoring**
the restore process is kind of fucked up but doable
- restore on new system
- run `vykar list` to find a snapshot to use
- `sudo rm -rf /var/lib/docker/volumes/`
- then `sudo vykar restore abcd1234 /var/lib/docker/volumes/`
- figure out the UID:GID for all containers and `sudo chown -R UID:GID /var/lib/docker/volumes/.../_data/` their respective volumes
- restore on same system
- run `vykar list` to find a snapshot to use
- then `sudo vykar restore abcd1234 /var/lib/docker/volumes/`
## todo
- further secure the server (ratelimiting, hardening...)
- more services
- ~~forgejo (need to change host ssh port)~~
- vaultwarden
- ~~tie all services together with an sso~~
- use postgres for everything
## misc
**useful commands**
- `docker exec <service> env`
+6 -5
View File
@@ -9,6 +9,7 @@ services:
- "443:443/udp" - "443:443/udp"
volumes: volumes:
- ./Caddyfile:/etc/caddy/Caddyfile:ro,z - ./Caddyfile:/etc/caddy/Caddyfile:ro,z
- ./home:/srv/home/
- caddy-data:/data - caddy-data:/data
- caddy-config:/config - caddy-config:/config
networks: networks:
@@ -54,9 +55,9 @@ services:
depends_on: depends_on:
- stalwart - stalwart
forgejo: gitea:
image: codeberg.org/forgejo/forgejo:16 image: docker.gitea.com/gitea:1.27.0
container_name: forgejo container_name: gitea
restart: unless-stopped restart: unless-stopped
environment: environment:
- USER_UID=1000 - USER_UID=1000
@@ -64,7 +65,7 @@ services:
ports: ports:
- "22:22" - "22:22"
volumes: volumes:
- forgejo-data:/data - gitea-data:/data
networks: networks:
- services - services
@@ -77,7 +78,7 @@ volumes:
bulwark-config: bulwark-config:
bulwark-state: bulwark-state:
bulwark-telemetry: bulwark-telemetry:
forgejo-data: gitea-data:
networks: networks:
services: services:
+29
View File
@@ -0,0 +1,29 @@
## backups
backups are done with [vykar](https://vykar.borgbase.com) to [borgbase](https://borgbase.com)
always remember to `docker compose stop` before doing any of this!
**creating**
- if on a new borgbase repo, run `vykar init` first
- to back up, run `sudo vykar backup` (sudo required as we are accessing `/var/lib/docker/volumes/`)
- to back up automatically, run `sudo EDITOR=micro crontab -e` and add the following:
```
TZ=UTC
0 6 * * * /home/admin/atom.town/scripts/volume-backup.sh cold
0 0,12,18 * * * /home/admin/atom.town/scripts/volume-backup.sh hot
```
**restoring**
the restore process is kind of fucked up but doable
- restore on new system
- run `vykar list` to find a snapshot to use
- `sudo rm -rf /var/lib/docker/volumes/`
- then `sudo vykar restore abcd1234 /var/lib/docker/volumes/`
- figure out the UID:GID for all containers and `sudo chown -R UID:GID /var/lib/docker/volumes/.../_data/` their respective volumes
- restore on same system
- run `vykar list` to find a snapshot to use
- then `sudo vykar restore abcd1234 /var/lib/docker/volumes/`
+5
View File
@@ -0,0 +1,5 @@
## misc
**useful commands**
- `docker exec <service> env`
+8
View File
@@ -0,0 +1,8 @@
### bulwark
> [!NOTE]
> **todo** // detail setup
**useful links**
- https://bulwarkmail.org/docs
+8
View File
@@ -0,0 +1,8 @@
### caddy
> [!NOTE]
> **todo** // detail setup
**useful links**
- https://caddyserver.com/docs/
+43
View File
@@ -0,0 +1,43 @@
### gitea
**initial setup**
- database settings
- database type: `sqlite3`
- path: `/data/gitea/gitea.db`
- general settings
- site title: `atom.town`
- server domain: `git.atom.town`
- ssh server port: `22`
- gitea base url: `https://git.atom.town/`
- enable update checker: `true`
- email settings
- smtp host: `post.atom.town`
- smtp port: `465`
- send email as: `"Gitea" <system@atom.town>`
- smtp username: `system@atom.town`
- smtp password: `<password>`
- enable email notifications: `true`
- server and third-party service settings
- enable openid sign-in: `false`
- disable self-registration: `false`
- allow registration only through external services: `true`
- enable openid self-registration: `true`
- hidden email domain: `git.atom.town`
- password hash algorithm: `argon2`
</details>
**further setup**
- admin settings -> identity & access -> authentication sources
- add authentication source
- authentication type: `OAuth2`
- authentication name: `Stalwart`
- oauth2 provider: `OpenID Connect`
- client id (key): `gitea`
- client secret: `<secret_from_stalwart>`
- openid connect auto discovery url: `https://post.atom.town/.well-known/openid-configuration`
**useful links**
- https://docs.gitea.com/
+47
View File
@@ -0,0 +1,47 @@
### stalwart
**initial setup**
1. server identity
- server hostname: `post.atom.town`
- default email domain: `atom.town`
- automatically obtain tls certificate: `true`
- generate email signing keys: `true`
2. storage
- main data storage: `rocksdb`
- path: `/var/lib/stalwart/`
3. account directory
- directory type: `use internal`
4. logging
- log destination: `console`
5. automatic dns management
- dns server type: `porkbun`
- description: `porkbun`
**further setup**
- settings -> security -> allowed ips
- added `172.18.0.0/16`; reason: `docker internal`
- settings -> network -> http -> security
- permissive cors policy: `true` **[restart needed]**
- settings -> authentication -> oidc provider
- oauth settings
- key: `secret read from environment variable`
- variable name: `OIDC_KEY`
- openid connect
- signature algorithm: `ECDSA using P-384 and SHA-384`
- signature key: `secret read from environment variable`
- variable name: `OIDC_SIGNATURE_KEY`
- management -> directory -> oauth clients
- create oauth client
- client id: `gitea`
- description: `Gitea`
- client secret: `<generate_secret>`
- redirect uris: `https://git.atom.town/user/oauth2/Stalwart/callback`
**useful links**
- https://stalw.art/docs
- https://testconnectivity.microsoft.com/tests/Imap/input
- https://mail-tester.com
</details>
+45
View File
@@ -0,0 +1,45 @@
## setup
1. log into the vps, make sure it's fedora (or else 🔪)
2. create a new admin user
- `sudo useradd -m -G wheel admin`
- `sudo passwd admin`
- `sudo su - admin`
3. use the system setup script, and log out
- `sudo dnf install git -y`
- `git clone https://git.atom.town/atom/town && mv town atom.town`
- `./atom.town/scripts/system-setup.sh`
- `exit`
4. log in again, populate the `.env` and start everything up
- `cd atom.town`
- `micro .env`
- `docker compose up`
5. continue with service-specific setups .....
## services
specifics for everything
**currently serving**
- via docker
- **caddy** http server & reverse proxy
- **stalwart** mailserver
- **bulwark** webmail
- **gitea** git server
- via caddy
- `atom.town` - homepage
- `post.atom.town` mailserver, mail admin, and oidc
- `mail.atom.town` webmail
- `git.atom.town` git
**dns setup**
| type | host | value | notes |
|-------|-----------|---------------------------- |----------------------------|
| `A` | `@` | `<ip>` | apex domain |
| `A` | `post` | `<ip>` | mailserver |
| `A` | `mail` | `<ip>` | webmail |
| `A` | `git` | `<ip>` | gitea |
| `CAA` | `@` | `0 issue "letsencrypt.org"` | allow caddy to issue certs |
| `MX` | `@` | `post.atom.town.` / `10` | mail record |
+12
View File
@@ -0,0 +1,12 @@
## todo
- [ ] put branding on more stuff (images, themes...)
- [ ] further secure the server (ratelimiting, hardening...)
- [ ] (maybe) user sites or pages hosting
- [ ] (maybe) gitea actions runner
- [ ] more services
- [x] gitea (need to change host ssh port)
- [ ] vaultwarden
- [x] write terms of service & privacy policy
- [x] figure out best way to store .env, other credentials, and various secrets
- [x] tie all services together with an sso
Binary file not shown.
Binary file not shown.
Binary file not shown.

After

Width:  |  Height:  |  Size: 166 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

+27
View File
@@ -0,0 +1,27 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>atom.town</title>
<link rel="stylesheet" href="style/fonts.css">
<link rel="stylesheet" href="style/reset.css">
<link rel="stylesheet" href="style/style.css">
<link rel="icon" type="image/avif" href="assets/logo_icon.avif">
<link rel="preload" as="image" href="assets/clouds.avif">
<link rel="preload" as="font" href="assets/InterVariable-Italic.woff2" crossorigin>
</head>
<body>
<img src="assets/logo.avif" class="logo" />
<div class="flex flex-col gap-8 mt-4">
<p class="font-light">hello, and welcome to atom.town. here, you will be at home.</p>
<div class="flex flex-col w-fit">
<a href="https://mail.atom.town" target="_blank" class="font-normal pop big">webmail</a>
<a href="https://git.atom.town" target="_blank" class="font-normal pop big">git</a>
</div>
<div class="flex flex-col w-fit">
<a href="terms-privacy.html" class="font-normal pop big">terms & privacy</a>
<a href="setup.html" class="font-normal pop big">setup</a>
</div>
</div>
</body>
</html>
+31
View File
@@ -0,0 +1,31 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>atom.town</title>
<link rel="stylesheet" href="style/fonts.css">
<link rel="stylesheet" href="style/reset.css">
<link rel="stylesheet" href="style/style.css">
<link rel="icon" type="image/avif" href="assets/logo_icon.avif">
<link rel="preload" as="image" href="assets/clouds.avif">
<link rel="preload" as="font" href="assets/InterVariable-Italic.woff2" crossorigin>
</head>
<body>
<img src="assets/logo.avif" class="logo" />
<div class="flex flex-col gap-8 mt-4 max-w-md">
<p class="font-light">things that are useful to know</p>
<div class="flex flex-col gap-2">
<h2 class="font-heavy big">email</h2>
<ul class="font-light">
<li>the mailserver lives at <b>post.atom.town</b></li>
<li>incoming mail uses <b>imap</b> with <b>ssl/tls</b> on port <b>993</b></li>
<li>outgoing mail uses <b>smtp</b> with <b>ssl/tls</b> on port <b>465</b></li>
</ul>
<ul class="font-light">
<li>the mailserver also has a few other functions. it is an admin dashboard, which anyone can use to configure their own email account, and also the oidc (auth) provider.</li>
</ul>
</div>
<a href="/index.html" class="self-start font-normal pop">← back</a>
</div>
</body>
</html>
+16
View File
@@ -0,0 +1,16 @@
/* http://rsms.me/inter/font-files/InterVariable.woff2 */
@font-face {
font-family: InterVariable;
font-style: normal;
font-weight: 100 900;
font-display: swap;
src: url("../assets/InterVariable.woff2") format('woff2');
}
/* http://rsms.me/inter/font-files/InterVariable-Italic.woff2 */
@font-face {
font-family: InterVariable;
font-style: italic;
font-weight: 100 900;
font-display: swap;
src: url("../assets/InterVariable-Italic.woff2") format('woff2');
}
+44
View File
@@ -0,0 +1,44 @@
/* CSS reset (https://www.joshwcomeau.com/css/custom-css-reset) */
*, *::before, *::after {
box-sizing: border-box;
}
*:not(dialog) {
margin: 0;
}
@media (prefers-reduced-motion: no-preference) {
html {
interpolate-size: allow-keywords;
}
}
body {
line-height: 1.5;
-webkit-font-smoothing: antialiased;
}
img, picture, video, canvas, svg {
display: block;
max-width: 100%;
}
input, button, textarea, select {
font: inherit;
}
p, h1, h2, h3, h4, h5, h6 {
overflow-wrap: break-word;
}
p {
text-wrap: pretty;
}
h1, h2, h3, h4, h5, h6 {
text-wrap: balance;
}
#root, #__next {
isolation: isolate;
}
/* CSS reset */
+100
View File
@@ -0,0 +1,100 @@
:root {
font-family: InterVariable, sans-serif;
font-feature-settings: 'liga' 1, 'calt' 1;
}
html {
background: url("../assets/clouds.avif"), linear-gradient(180deg, hwb(230 20% 0%) 0%, hwb(230 90% 0%) 110%);
background-repeat: no-repeat;
background-size: cover, cover;
background-attachment: fixed;
}
body {
min-height: 100dvh;
padding: 20px;
}
p, a, li, ul, h2 {
color: white;
font-style: italic;
font-size: 20px;
@media (max-width: 1024px) {
font-size: 40px;
}
}
ul {
list-style-type: "» ";
padding-left: 1em;
}
/* tailwind lite */
:root { --space: 4px; }
.flex { display: flex; }
.flex-col { flex-direction: column; }
.gap-2 { gap: calc(var(--space) * 2); }
.gap-4 { gap: calc(var(--space) * 4); }
.gap-8 { gap: calc(var(--space) * 8); }
.mt-4 { margin-top: calc(var(--space) * 4); }
.self-start { align-self: flex-start; }
.justify-between { justify-content: space-between; }
.w-fit { width: fit-content; }
.items-center { align-items: center; }
.font-extralight { font-weight: 200; }
.font-light { font-weight: 300; }
.font-normal { font-weight: 400; }
.font-heavy { font-weight: 500; }
.max-w-md {
max-width: calc(var(--space) * 180);
@media (max-width: 1024px) {
max-width: calc(var(--space) * 360);
}
}
/* tailwind lite */
.small {
font-size: 16px;
@media (max-width: 1024px) {
font-size: 32px;
}
}
.big {
font-size: 24px;
@media (max-width: 1024px) {
font-size: 48px;
}
}
.pop {
transform-origin: left center;
transition: transform 0.1s ease;
}
.pop:hover {
transform: scale(1.25);
}
.hover {
text-decoration: underline dotted;
text-decoration-thickness: 1px;
}
.logo {
object-fit: contain;
align-self: flex-start;
max-height: 64px;
@media (max-width: 1024px) {
max-height: 128px;
}
}
+39
View File
@@ -0,0 +1,39 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>atom.town</title>
<link rel="stylesheet" href="style/fonts.css">
<link rel="stylesheet" href="style/reset.css">
<link rel="stylesheet" href="style/style.css">
<link rel="icon" type="image/avif" href="assets/logo_icon.avif">
<link rel="preload" as="image" href="assets/clouds.avif">
<link rel="preload" as="font" href="assets/InterVariable-Italic.woff2" crossorigin>
</head>
<body>
<img src="assets/logo.avif" class="logo" />
<div class="flex flex-col gap-8 mt-4 max-w-md">
<p class="font-light">atom.town is an exclusive club of like-minded individuals. by using atom.town, you agree to everything stated on this page.</p>
<div class="flex flex-col gap-2">
<h2 class="font-heavy big">terms</h2>
<ul class="font-light">
<li>you will not use atom.town in any way that would negatively impact other users, nor anyone else.</li>
<li>you will not use atom.town for bulk file storage (storing large files, or large volumes of files), even if such capabilities are present.</li>
<li>for any projects you host (or contribute to) on atom.town, llm usage will be <span title="while atom.town welcomes llms as a useful tool, they should be utilised sparingly, as it is all too easy to fall into the pit of overuse." class="hover">sparse</span>. largely unsupervised or unreviewed code is strongly prohibited.</li>
</ul>
</div>
<div class="flex flex-col gap-2">
<h2 class="font-heavy big">privacy</h2>
<ul class="font-light">
<li>atom.town is hosted on a <a href="https://datalix.eu/privacypolicy" target="_blank">datalix</a> server in germany. atom.town uses <a href="https://www.borgbase.com/privacy" target="_blank">borgbase</a> for backups (which are encrypted before upload).</li>
<li>atom.town (for now, indefinitely) collects ip addresses, account details, and any user data only for the purposes of system administration and provision of services.</li>
<li>atom.town does not share, nor ever will share any information it collects with any third parties, beyond what is absolutely necessary to run the service.</li>
</ul>
</div>
<div class="flex justify-between items-center">
<a href="/index.html" class="self-start font-normal pop">← back</a>
<p class="font-extralight small">updated 2026-07-24 (<a href="https://git.atom.town/atom/town/commits/branch/main/home/terms-privacy.html" target="_blank" class="small">history</a>)</p>
</div>
</div>
</body>
</html>
+8 -10
View File
@@ -19,13 +19,11 @@ function banner() {
fi fi
} }
# https://patorjk.com/software/taag/#p=display&f=Small+Slant
cat << 'EOF' cat << 'EOF'
__ __ _ __ __
/ /_/ / (_)__ ___ ___ __ ___ _/ /____ __ _ / /____ _ _____
/ __/ _ \/ / _ \/ _ `/ // / / _ `/ __/ _ \/ ' \_/ __/ _ \ |/|/ / _ \
\__/_//_/_/_//_/\_, /\_, / \_,_/\__/\___/_/_/_(_)__/\___/__,__/_//_/
/___//___/
..... brought to you by futile ..... brought to you by futile
@@ -80,7 +78,7 @@ banner bottom "updated system"
# install misc # install misc
banner top "installing misc packages" banner top "installing misc packages"
sudo dnf install -y micro btop fastfetch policycoreutils-python-utils sudo dnf install -y micro btop gdu fastfetch policycoreutils-python-utils
curl -fsSL https://vykar.borgbase.com/install.sh | sh curl -fsSL https://vykar.borgbase.com/install.sh | sh
banner bottom "installed misc packages" banner bottom "installed misc packages"
@@ -111,14 +109,14 @@ banner bottom "installed cron"
banner top "configuring sshd" banner top "configuring sshd"
sudo tee /etc/ssh/sshd_config << 'EOF' sudo tee /etc/ssh/sshd_config << 'EOF'
Include /etc/ssh/sshd_config.d/*.conf Include /etc/ssh/sshd_config.d/*.conf
Port 67 Port 66
PermitRootLogin no PermitRootLogin no
PasswordAuthentication no PasswordAuthentication no
KbdInteractiveAuthentication no KbdInteractiveAuthentication no
EOF EOF
sudo semanage port -a -t ssh_port_t -p tcp 67 sudo semanage port -a -t ssh_port_t -p tcp 66
sudo systemctl restart sshd sudo systemctl restart sshd
banner bottom "configuring sshd" banner bottom "configuring sshd"
# finish # finish
echo -e "done! please log out and log back in with \e[1;5mssh -p 67 $(id -un)@$(curl -s https://checkip.amazonaws.com)\e[0m\n" echo -e "done! please log out and log back in with \e[1;5mssh -p 66 $(id -un)@$(curl -s https://checkip.amazonaws.com)\e[0m\n"
+14 -3
View File
@@ -1,26 +1,37 @@
#!/usr/bin/env bash #!/usr/bin/env bash
set -euo pipefail set -euo pipefail
WORKING_DIR="/home/admin/thingy" # todo: better WORKING_DIR="/home/admin/atom.town" # todo: better
LOG_FILE="/var/log/volume-backup.log" LOG_FILE="/var/log/volume-backup.log"
function log() { function log() {
echo "[$(date -Iseconds)] $*" | tee -a "$LOG_FILE" echo "[$(date -Iseconds)] $*" | tee -a "$LOG_FILE"
} }
MODE="${1:-}"
if [[ "$MODE" != "cold" && "$MODE" != "hot" ]]; then
log "usage: $0 [cold|hot]" >&2
exit 1
fi
function cleanup() { function cleanup() {
log "cleanup: starting docker services" if [[ "$MODE" == "cold" ]]; then
log "starting docker services"
docker compose start || true docker compose start || true
fi
log "└───── backup finished ─────┘" log "└───── backup finished ─────┘"
} }
trap cleanup EXIT trap cleanup EXIT
log "┌────── backup started ─────┐" log "┌────── backup started ─────┐"
log "mode: $MODE"
cd "$WORKING_DIR" cd "$WORKING_DIR"
if [[ "$MODE" == "cold" ]]; then
log "stopping docker services" log "stopping docker services"
docker compose stop docker compose stop
fi
log "running backup" log "running backup"
/usr/local/bin/vykar backup /usr/local/bin/vykar backup 2>&1 | tee -a "$LOG_FILE"