Skip to content

Instantly share code, notes, and snippets.

@VegarLH
Last active August 23, 2018 21:00
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save VegarLH/1d4daaf15265a010e879df42879ae917 to your computer and use it in GitHub Desktop.
Save VegarLH/1d4daaf15265a010e879df42879ae917 to your computer and use it in GitHub Desktop.
#DigitalOcean #Openbsd #Mastodon #Notes
Notes from my mastodon test instance config.
Assumptions: you own some domain-name and its pointing to the ip of this instance. I'm calling it my.domain
This may or may not work for you. I've moved notes around so things might break.
I'm basically just doing config as described here:
https://github.com/tootsuite/documentation/blob/master/Running-Mastodon/Production-guide.md
# Start: I'm creating the machine on DigitalOcean.
# You can probably skip this part ( 9.)
### DigitalOcean guest creation ###
1.#create digitalocean host. 10$ (non-zfs freebsd host) i did this on a 5$ but upgraded later.
#make sure you have a ssh key added.
2. #connect freebsd@xxx.xxx.xxx.xxx
3. #because the internet says so.
$ sudo swapoff /dev/gpt/swap
4. #(needed to write to raw disk apparently, according to ancient scrolls of mine).
$ sudo sysctl kern.geom.debugflags=0x10
kern.geom.debugflags: 0 -> 16
5. #Fetch the newest OpenBSD
$ fetch http://ftp.eu.openbsd.org/pub/OpenBSD/6.1/amd64/miniroot61.fs
miniroot61.fs 100% of 4480 kB 5297 kBps 00m01s
6. #Owerwrite disk with miniroot
$ sudo dd if=miniroot61.fs of=/dev/vtbd0 bs=512k
8+1 records in
8+1 records out
4587520 bytes transferred in 0.027193 secs (168701557 bytes/sec)
7. sudo reboot
### Installation ###
8.# Access console from DigitalOcean website. Install as you normally would
#my notes:(including full disk encryption etc).
i intall
no (im norwegian)
blah (hostname)
enter (if vio0)
enter (dhcp)
enter (none ipv6)
enter (network setup done)
my.domain
8.8.8.8 (dns)
pwd
pwd
enter (start ssh yes)
enter (xll libs)
enter (dont start xenodm)
enter (dont change default console to com0)
username (set up your user)
fullname
enter (dont allow ssh root login)
Europe/Oslo (Timezone)
! (excape to shell when they are asking which disk to use)
fdisk -i sd0
disklabel -E sd0
a b
enter (default offset)
1G (size)
enter (swap)
a a
enter (default offset)
enter (size the remaining)
RAID (fs type)
w
q
bioctl -c C -l /dev/sd0a softraid0
pwd
pwd
exit (back to installer)
sd2
w (whole)
a (auto)
.. wait 30 secounds..
done
enter (http)
enter (no proxy)
ftp.eu.openbsd.org (use some mirror)
enter (pub/OpenBSD/6.1/amd64)
enter (accept porposed sets).
enter (done)
reboot
enter passphrase to start.
### Configuration ###
9. #ssh to server as your user.
$ su
10. enable doas
# mg /etc/doas.conf
# i am lazy so im allowing for :wheel and using persist when doing server config to avoid typing my password over and over.
permit persist keepenv :wheel
#exit to normal user
$ exit
11. #Add out mastodon instance
$ doas adduser mastodon
Couldn't find /etc/adduser.conf: creating a new adduser configuration file
Reading /etc/shells
Enter your default shell: csh ksh nologin sh [ksh]:
1Your default shell is: ksh -> /bin/ksh
Default login class: authpf bgpd daemon default pbuild staff unbound
[default]:
Enter your default HOME partition: [/home]:
Copy dotfiles from: /etc/skel no [/etc/skel]:
Send welcome message?: /path/file default no [no]:
Do not send message(s)
Prompt for passwords by default (y/n) [y]:
Default encryption method for passwords: auto blowfish [auto]:
Use option ``-silent'' if you don't want to see all warnings and questions.
Reading /etc/shells
Check /etc/master.passwd
Check /etc/group
Ok, let's go.
Don't worry about mistakes. There will be a chance later to correct any input.
Enter username []: mastodon
Enter full name []:
Enter shell csh ksh nologin sh [ksh]:
Uid [1001]:
Login group mastodon [mastodon]:
Login group is ``mastodon''. Invite mastodon into other groups: guest no
[no]:
Login class authpf bgpd daemon default pbuild staff unbound
[default]: daemon
Enter password []:
Disable password logins for the user? (y/n) [n]: y
Name: mastodon
Password: ****
Fullname: mastodon
Uid: 1001
Gid: 1001 (mastodon)
Groups: mastodon
Login Class: daemon
HOME: /home/mastodon
Shell: /bin/ksh
OK? (y/n) [y]:
Added user ``mastodon''
Copy files from /etc/skel to /home/mastodon
Add another user? (y/n) [y]: n
Goodbye!
12. # fix an error, probably mine.
doas mg /etc/installurl
remove tailing /6.1 is its there, should not be there.
13. #Install packages we need:
doas pkg_add curl ImageMagick ffmpeg git libpqxx libxml libxslt nginx node postgresql-client postgresql-server redis ruby-2.3.3 sass
14. # Make the required symlinks
doas su -
ln -sf /usr/local/bin/python2.7 /usr/local/bin/python
ln -sf /usr/local/bin/python2.7-2to3 /usr/local/bin/2to3
ln -sf /usr/local/bin/python2.7-config /usr/local/bin/python-config
ln -sf /usr/local/bin/pydoc2.7 /usr/local/bin/pydoc
ln -sf /usr/local/bin/ruby23 /usr/local/bin/ruby
ln -sf /usr/local/bin/erb23 /usr/local/bin/erb
ln -sf /usr/local/bin/irb23 /usr/local/bin/irb
ln -sf /usr/local/bin/rdoc23 /usr/local/bin/rdoc
ln -sf /usr/local/bin/ri23 /usr/local/bin/ri
ln -sf /usr/local/bin/rake23 /usr/local/bin/rake
ln -sf /usr/local/bin/gem23 /usr/local/bin/gem
#exit to normal user..
$ exit (or ctrl-d)
15. Install yarn
$ doas npm install -g yarn
`-- yarn@0.22.0
...
...
16. # Mostly following steps from
# /usr/local/share/doc/pkg-readmes/postgresql-server-xxx
$ doas -u _postgresql initdb -D /var/postgresql/data -U postgres -E UTF8 -A md5 -W
The files belonging to this database system will be owned by user "_postgresql".
This user must also own the server process.
The database cluster will be initialized with locale "C".
The default text search configuration will be set to "english".
Data page checksums are disabled.
Enter new superuser password:
Enter it again:
creating directory /var/postgresql/data ... ok
creating subdirectories ... ok
selecting default max_connections ... 100
selecting default shared_buffers ... 128MB
selecting dynamic shared memory implementation ... posix
creating configuration files ... ok
running bootstrap script ... ok
performing post-bootstrap initialization ... ok
syncing data to disk ... ok
Success. You can now start the database server using:
pg_ctl -D /var/postgresql/data -l logfile start
17. # things will not run for long with the default values
$ doas mg /etc/sysctl.conf
kern.seminfo.semmni=60
kern.seminfo.semmns=1024
and
$ doas sysctl kern.seminfo.semmni=60
kern.seminfo.semmni: 10 -> 60
$ doas sysctl kern.seminfo.semmns=1024
kern.seminfo.semmns: 60 -> 1024
18: # ajust some limits
$ doas mg /etc/login.conf
postgresql:\
:openfiles=2048:\
:tc=daemon:
#Build new login db.
$ doas [ -f /etc/login.conf.db ] && cap_mkdb /etc/login.conf
#Edit config
$ doas -u _postgresql mkdir /var/postgresql/run
$ doas mg /var/postgresql/data/postgresql.conf
max_connections = 500
unix_socket_directories = '/var/postgresql/run/'
19. #Start stuff
$ doas rcctl start postgresql redis
postgresql(ok)
redis(ok)
20. #create user/db #use some random password
$ psql -h /var/postgresql/run -U postgres
Password for user postgres:
psql (9.6.2)
Type "help" for help.
postgres=# CREATE USER mastodon CREATEDB password '! my awesome pwd !';
CREATE ROLE
postgres=# \q
21. #install bundler.
$ doas gem23 install bundler
Fetching: bundler-1.14.6.gem (100%)
Successfully installed bundler-1.14.6
Parsing documentation for bundler-1.14.6
Installing ri documentation for bundler-1.14.6
Done installing documentation for bundler after 29 seconds
1 gem installed
22. #switch to the mastodon user.
$ doas su - mastodon
$ whoami
mastodon
23. #clone the mastodon repo to a folder called live.
$ cd ~
$ git clone https://github.com/tootsuite/mastodon.git live
Cloning into 'live'...
remote: Counting objects: 26400, done.
remote: Compressing objects: 100% (25/25), done.
remote: Total 26400 (delta 8), reused 0 (delta 0), pack-reused 26375
Receiving objects: 100% (26400/26400), 34.45 MiB | 3.31 MiB/s, done.
Resolving deltas: 100% (15932/15932), done.
Checking out files: 100% (4756/4756), done.
$ cd live/
$ pwd
/home/mastodon/live
24. #run bundle install from the mastodon folder
$ bundle23 install --deployment --without development test
Fetching gem metadata from https://rubygems.org/..............
Fetching version metadata from https://rubygems.org/...
Fetching dependency metadata from https://rubygems.org/..
Installing rake 12.0.0
...
...
25. # Get some coffee after running below.. can take a couple of minutes..
# Got some errors on first run. i lost its output.. sorry. secound run was successfull.
# Happy lucky hat on, from this point o_O
$ yarn install
yarn install v0.22.0
[1/4] Resolving packages...
[2/4] Fetching packages...
warning fsevents@1.0.14: The platform "openbsd" is incompatible with this module.
info "fsevents@1.0.14" is an optional dependency and failed compatibility check. Excluding it from installation.
warning store@1.3.20: The engine "browser" appears to be invalid.
[3/4] Linking dependencies...
warning "react-decoration@1.4.0" has incorrect peer dependency "react-addons-perf@15.3.2".
warning "react-storybook-addon-intl@0.1.0" has incorrect peer dependency "@kadira/storybook@^1.35.1".
[4/4] Building fresh packages...
Done in 83.25s.
26. #Create config.
$ cp .env.production.sample .env.production
$ mg .env.production
REDIS_HOST=localhost
REDIS_PORT=6379
DB_HOST=/var/postgresql/run/
DB_USER=mastodon
DB_NAME=mastodon_production
DB_PASS=! my awesome pwd !
#set LOCAL_DOMAIN to your domain
#set LOCAL_HTTPS=true
exit and generate 3 secrets with
$ bundle23 exec rake secret && bundle23 exec rake secret && bundle23 exec rake secret
#set smtp settings to something valid.
#set any other options you think you want.
#exit to normal user
$exit
27. #create https certificate using builtin tools. (this is kinda awesome)
$ doas mg /etc/httpd.conf
ext_addr=egress
server "my.domain" {
listen on $ext_addr port 80
location "/.well-known/acme-challenge/*" {
root "/acme"
root strip 2
}
}
#force start httpd (to avoid enabling it)
$ doas rcctl -f start httpd
$ doas mg /etc/acme-client.conf
#Add the following to the file
domain my.domain {
# alternative names { blah.my.domain }
domain key "/etc/ssl/private/my.domain.key"
domain certificate "/etc/ssl/my.domain.crt"
domain full chain certificate "/etc/ssl/my.domain.fullchain.pem"
sign with letsencrypt
}
#Now create the keys/certs
$ doas acme-client -vAD my.domain
acme-client: /etc/ssl/private/my.domain.key: generated RSA domain key
acme-client: /etc/acme/letsencrypt-privkey.pem: generated RSA account key
acme-client: https://acme-v01.api.letsencrypt.org/directory: directories
acme-client: acme-v01.api.letsencrypt.org: DNS: 104.98.130.119
acme-client: https://acme-v01.api.letsencrypt.org/acme/new-reg: new-reg
acme-client: https://acme-v01.api.letsencrypt.org/acme/new-authz: req-auth: my.domain
acme-client: /var/www/acme/ugB_2iZvOE6FhoaEOOKg7rQPCkAYQV5OHZK89Xx5_lI: created
acme-client: https://acme-v01.api.letsencrypt.org/acme/challenge/xxxxx: challenge
acme-client: https://acme-v01.api.letsencrypt.org/acme/challenge/xxxxx: status
acme-client: https://acme-v01.api.letsencrypt.org/acme/new-cert: certificate
acme-client: http://cert.int-x3.letsencrypt.org/: full chain
acme-client: cert.int-x3.letsencrypt.org: DNS: 104.93.82.24
acme-client: /etc/ssl/my.domain.crt: created
acme-client: /etc/ssl//my.domain.fullchain.pem: created
$ doas rcctl stop httpd
httpd(ok)
#thats is..
28. #Configure nginx to your requirements. the below works for my test.
$ doas mg /etc/nginx/nginx.conf
#user www;
worker_processes 1;
worker_rlimit_nofile 1024;
events {
worker_connections 800;
}
http {
include mime.types;
default_type application/octet-stream;
index index.html index.htm;
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
server {
listen 80;
listen [::]:80;
server_name my.domain;
return 301 https://$host$request_uri;
}
server_tokens off;
server {
listen 443 ssl;
server_name my.domain;
ssl_protocols TLSv1.2;
ssl_ciphers EECDH+AESGCM:EECDH+AES;
ssl_ecdh_curve prime256v1;
ssl_prefer_server_ciphers on;
ssl_session_cache shared:SSL:10m;
ssl_certificate /etc/ssl/my.domain.fullchain.pem;
ssl_certificate_key /etc/ssl/private/my.domain.key;
keepalive_timeout 70;
sendfile on;
client_max_body_size 0;
root /home/mastodon/live/public;
gzip on;
gzip_disable "msie6";
gzip_vary on;
gzip_proxied any;
gzip_comp_level 6;
gzip_buffers 16 8k;
gzip_http_version 1.1;
gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains";
location / {
try_files $uri @proxy;
}
location @proxy {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto https;
proxy_set_header Proxy "";
proxy_pass_header Server;
proxy_pass http://localhost:3000;
proxy_buffering off;
proxy_redirect off;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
tcp_nodelay on;
}
location /api/v1/streaming {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto https;
proxy_set_header Proxy "";
proxy_pass http://localhost:4000;
proxy_buffering off;
proxy_redirect off;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection $connection_upgrade;
tcp_nodelay on;
}
error_page 500 501 502 503 504 /500.html;
}
}
29. #enable nginx, something about the arg order annoys me, but lets use rcctl anyway.
$ doas rcctl enable nginx
$ doas rcctl start nginx
nginx(ok)
30. # Build mastodon DB
$ doas su - mastodon
$ cd live
$ RAILS_ENV=production bundle23 exec rails db:setup
Created database 'mastonon'
-- enable_extension("plpgsql")
-> 0.0708s
-- create_table("accounts", {:force=>:cascade})
-> 0.1858s
-- create_table("blocks", {:force=>:cascade})
-> 0.0248s
-- create_table("domain_blocks", {:force=>:cascade})
-> 0.0680s
-- create_table("favourites", {:force=>:cascade})
-> 0.0789s
-- create_table("follow_requests", {:force=>:cascade})
-> 0.0498s
-- create_table("follows", {:force=>:cascade})
-> 0.0451s
-- create_table("imports", {:force=>:cascade})
-> 0.0267s
-- create_table("media_attachments", {:force=>:cascade})
-> 0.0715s
-- create_table("mentions", {:force=>:cascade})
-> 0.0740s
-- create_table("mutes", {:force=>:cascade})
-> 0.0370s
-- create_table("notifications", {:force=>:cascade})
-> 0.0698s
-- create_table("oauth_access_grants", {:force=>:cascade})
-> 0.0489s
-- create_table("oauth_access_tokens", {:force=>:cascade})
-> 0.0966s
-- create_table("oauth_applications", {:force=>:cascade})
-> 0.0562s
-- create_table("preview_cards", {:force=>:cascade})
-> 0.0480s
-- create_table("reports", {:force=>:cascade})
-> 0.0333s
-- create_table("settings", {:force=>:cascade})
-> 0.0414s
-- create_table("statuses", {:id=>:bigserial, :force=>:cascade})
-> 0.1069s
-- create_table("statuses_tags", {:id=>false, :force=>:cascade})
-> 0.0199s
-- create_table("stream_entries", {:force=>:cascade})
-> 0.0390s
-- create_table("subscriptions", {:force=>:cascade})
-> 0.0285s
-- create_table("tags", {:force=>:cascade})
-> 0.0330s
-- create_table("users", {:force=>:cascade})
-> 0.0723s
-- create_table("web_settings", {:force=>:cascade})
-> 0.0380s
-- add_foreign_key("statuses", "statuses", {:column=>"reblog_of_id", :on_delete=>:cascade})
-> 0.0190s
-- initialize_schema_migrations_table()
-> 0.0151s
31. #precompile css/js
RAILS_ENV=production bundle23 exec rails assets:precompile
#A lot of output.
INFO -- : Writing /home/mastodon/live/public/assets/ ...
32. #thats it
# i havent created any rc scripts yet so i am just running this in 3 tmux windows. i know..
# the commands should look something like this:
#1
RAILS_ENV=production PORT=3000 bundle23 exec puma -C config/puma.rb
#2
RAILS_ENV=production DB_POOL=5 bundle23 exec sidekiq -c 5 -q default -q mailers -q pull -q push
#3
NODE_ENV=production PORT=4000 npm run start
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment