BitWarden http://tech.oeru.org/ en Setting up your own BitWarden password manager and VaultWarden sync server http://tech.oeru.org/setting-your-own-bitwarden-password-manager-and-vaultwarden-sync-server <span class="field field--name-title field--type-string field--label-hidden">Setting up your own BitWarden password manager and VaultWarden sync server</span> <div class="field field-node--field-blog-tags field-name-field-blog-tags field-type-entity-reference field-label-above"> <h3 class="field__label">Blog tags</h3> <div class="field__items"> <div class="field__item field__item--docker-compose"> <span class="field__item-wrapper"><a href="/taxonomy/term/49" hreflang="en">docker-compose</a></span> </div> <div class="field__item field__item--docker"> <span class="field__item-wrapper"><a href="/taxonomy/term/16" hreflang="en">docker</a></span> </div> <div class="field__item field__item--rust"> <span class="field__item-wrapper"><a href="/taxonomy/term/59" hreflang="en">rust</a></span> </div> <div class="field__item field__item--bitwarden"> <span class="field__item-wrapper"><a href="/taxonomy/term/60" hreflang="en">BitWarden</a></span> </div> <div class="field__item field__item--password-keeper"> <span class="field__item-wrapper"><a href="/taxonomy/term/61" hreflang="en">password keeper</a></span> </div> <div class="field__item field__item--privacy"> <span class="field__item-wrapper"><a href="/taxonomy/term/62" hreflang="en">privacy</a></span> </div> <div class="field__item field__item--security"> <span class="field__item-wrapper"><a href="/taxonomy/term/63" hreflang="en">security</a></span> </div> <div class="field__item field__item--vaultwarden"> <span class="field__item-wrapper"><a href="/taxonomy/term/82" hreflang="en">Vaultwarden</a></span> </div> </div> </div> <span class="field field--name-uid field--type-entity-reference field--label-hidden"><a title="View user profile." href="/user/1" class="username">dave</a></span> <span class="field field--name-created field--type-created field--label-hidden">Sat 21/08/2021 - 11:30</span> <div class="field field-node--field-image field-name-field-image field-type-image field-label-hidden has-multiple"> <figure class="field-type-image__figure image-count-1"> <div class="field-type-image__item"> <a href="http://tech.oeru.org/sites/default/files/styles/max_1300x1300/public/2019-04/bitwarden_desktop_app.png?itok=9ZE2TxZh" aria-controls="colorbox" aria-label="{&quot;alt&quot;:&quot;BitWarden desktop app (Electron-based)&quot;}" role="button" title="BitWarden desktop app (Electron-based)" data-colorbox-gallery="gallery-field_image-brHaTiGLDTs" class="colorbox" data-cbox-img-attrs="{&quot;alt&quot;:&quot;BitWarden desktop app (Electron-based)&quot;}"><img src="/sites/default/files/styles/medium/public/2019-04/bitwarden_desktop_app.png?itok=hekOd__9" width="220" height="169" alt="BitWarden desktop app (Electron-based)" loading="lazy" class="image-style-medium" /> </a> </div> </figure> <figure class="field-type-image__figure image-count-2"> <div class="field-type-image__item"> <a href="http://tech.oeru.org/sites/default/files/styles/max_1300x1300/public/2019-04/bitwarden_web_interface_0.png?itok=QShOqyOM" aria-controls="colorbox" aria-label="{&quot;alt&quot;:&quot;BitWarden website interface&quot;}" role="button" title="BitWarden website interface" data-colorbox-gallery="gallery-field_image-brHaTiGLDTs" class="colorbox" data-cbox-img-attrs="{&quot;alt&quot;:&quot;BitWarden website interface&quot;}"><img src="/sites/default/files/styles/medium/public/2019-04/bitwarden_web_interface_0.png?itok=QitHloR0" width="220" height="158" alt="BitWarden website interface" loading="lazy" class="image-style-medium" /> </a> </div> </figure> <figure class="field-type-image__figure image-count-3"> <div class="field-type-image__item"> <a href="http://tech.oeru.org/sites/default/files/styles/max_1300x1300/public/2019-04/bitwarden_desktop_app_logged_in_0.png?itok=FAbPSjim" aria-controls="colorbox" aria-label="{&quot;alt&quot;:&quot;Desktop BitWarden app, with user logged in. &quot;}" role="button" title="Desktop BitWarden app, with user logged in. " data-colorbox-gallery="gallery-field_image-brHaTiGLDTs" class="colorbox" data-cbox-img-attrs="{&quot;alt&quot;:&quot;Desktop BitWarden app, with user logged in. &quot;}"><img src="/sites/default/files/styles/medium/public/2019-04/bitwarden_desktop_app_logged_in_0.png?itok=p9Oarp8h" width="220" height="156" alt="Desktop BitWarden app, with user logged in. " loading="lazy" class="image-style-medium" /> </a> </div> </figure> <figure class="field-type-image__figure image-count-4"> <div class="field-type-image__item"> <a href="http://tech.oeru.org/sites/default/files/styles/max_1300x1300/public/2019-04/bitwarden_adding_new_item_via_web_interface_0.png?itok=_PTdZqjB" aria-controls="colorbox" aria-label="{&quot;alt&quot;:&quot;Web interface for BitWarden with user logged in.&quot;}" role="button" title="Web interface for BitWarden with user logged in." data-colorbox-gallery="gallery-field_image-brHaTiGLDTs" class="colorbox" data-cbox-img-attrs="{&quot;alt&quot;:&quot;Web interface for BitWarden with user logged in.&quot;}"><img src="/sites/default/files/styles/medium/public/2019-04/bitwarden_adding_new_item_via_web_interface_0.png?itok=YQftj3vf" width="220" height="209" alt="Web interface for BitWarden with user logged in." loading="lazy" class="image-style-medium" /> </a> </div> </figure> </div> <div class="clearfix text-formatted field field-node--body field-name-body field-type-text-with-summary field-label-hidden"> <div class="field__items"> <div class="field__item"><p>One of the key requirements of pursuing Good Digital Hygiene is <em>using strong passwords</em>, and a <em>different strong password for every application</em>. This is relatively easy to do in theory, <em>with the aid of clever software</em>, but it's something desperately few people do well in practice. I'm going to explain how I've addressed this issue of digital hygiene for myself, and how you can do it for yourself, <em>and your entire family, social circle, or community</em>.</p> <p>Password Managers (or keepers or safes) have emerged as that "clever software". A good password manager has to do a bunch of things to be really useful:</p> <ol><li>It needs to store your passwords somewhere in an encrypted form (so if someone gets your password database, they can't work out your entire collection of passwords). You only need to remember <em>one </em><em>really strong password/phrase to unlock all of them. </em></li> <li>It needs to work in whatever context you need a password. Like <ol><li>your desktop/laptop, where you need to remember logins for a variety of apps and services,</li> <li>in your browser (for web apps that require authentication), and</li> <li>on your mobile platforms (because most services you use via apps or browsers require authentication)</li> </ol></li> <li>It needs to be cross platform <ol><li>must support Windows, MacOS, and Linux OSs,</li> <li>must support extensions for many browsers like Firefox, Chrome/<a href="https://chromium.org" title="The open source project that underlies Chrome and is 99% identical.">Chromium</a>, Safari, and others, and</li> <li>must support mobile OSs like iOS and Android.</li> </ol></li> <li>It needs to sync data in a timely manner among all the different contexts in which a given user needs it.</li> </ol><p>That's a lot of requirements. There're quite a few efforts that have had a crack at solving this.</p> <p>The <a href="https://www.keepassx.org/">KeePassX</a> community has been addressing this for ages and has created a comprehensive (if variable) ecosystem of apps which work across all of the required platforms, but only with a lot of work.</p> <p>In the proprietary world, there're many options, with a few front runners like 1Password and <a href="https://lastpass.com">LastPass</a>. The former doesn't work on Linux, so it only gets a passing reference and no link :) (update 2019-05-31 - <a href="https://1password.com">1Password</a> has added Linux support). The latter, which I used (grudgingly, mostly because I couldn't get KeePassX to work for me) for a few years, works across all the platforms relevant to me, but it was becoming progressively more invasive and annoying to use. Also, because it has a <em>lot</em> of users, and stores everything (albeit, encrypted) in a centralised cloud repository, it's a <em>big target</em>. Also, with its largely proprietary code, I wasn't happy trusting it. </p> <p>Then I heard about <a href="https://bitwarden.com">BitWarden</a>. They offered a commercial service (with a free tier) that I could quickly try... they supported all the OSs, mobile and desktop, and browsers that I use... <em>and they release their entire codebase </em>(server and clients) <em><strong>under open source licenses.</strong></em> I tried it, it worked for me, I was sold!</p> <p><strong>Update 2020-12-20</strong>: here's a <a href="https://kevq.uk/are-password-managers-worth-it/">nice explanation of why you'd want a password manager</a> and even <a href="https://kevq.uk/bitwarden-an-open-source-alternative-to-lastpass/">a comparison between widely used (proprietary) LastPass and (open source) BitWarden</a>. People reading this might also be interested in learning <a href="https://kevq.uk/how-websites-check-your-password/">how websites check your password.<em>.. without storing a copy of your password</em></a>! Thanks for providing your CC-BY-SA licensed works for us all Kev!</p> <p>Then I decided I wanted to run my own BitWarden server, rather than use their commercial centralised cloud platform (because, as with LastPass, it's a tempting target). That's when I found out the server of BitWarden was written using Microsoft technologies, C# (yeah, it's mostly open source, but it's dirty to me due to its Microsoft legacy), and MS SQL Server, which is a nasty proprietary dependency (especially given how basic the database requirements for this sort of application are).</p> <p>So I was devastated that I couldn't set up my own server without compromising my iron-clad anti-Microsoft position (I've managed to maintain it for the past 25 years)... until another Free and Open Source Software aficionado pointed me at Daniel Garcia's work! Daniel has implemented a <a href="https://github.com/dani-garcia/bitwarden_rs">full (unofficial) BitWarden work-alike using a fully FOSS stack</a>: the Rust language, storing data in SQLite, and (quite thoughtfully) re-using other open source licensed components of the BitWarden system that don't have proprietary dependencies, including the website code and layout (which is part of the server). (he calls the server he's developed <a href="https://github.com/dani-garcia/vaultwarden">VaultWarden</a> to distinguish it from the BitWarden code base. The front-end BitWarden apps talk to VaultWarden the same way!)</p> <p>Daniel's server implementation also unlocks all the "premium" services that BitWarden offers through their hosted service, too... so that's a nice bonus.</p> <p>Another open source developer, <a href="https://github.com/mprasil">mpasil</a>, has created <a href="https://github.com/mprasil/bitwarden_rs">a "fork" of Daniel's project</a> from which he maintains an up-to-date Docker container on hub.docker.com. <strong>Thanks to both Daniel Garcia and mpasil's efforts</strong>, it turns out to be quite straightforward to set up your own Docker-based BitWarden-compatible service!</p> <h2>Creating your own BitWarden Service</h2> <h3>Set up a Virtual Server</h3> <p>The first step is to get yourself an entry-level virtual server or compute instance somewhere. I generally use DigitalOcean (I have no affiliation with the company), but there are many other commodity hosting services (check out Vultr or Linode, for example) around the world which offer comparably (or better) spec'd servers for <strong>USD5.00/month</strong>, or <strong>USD60.00/year</strong> - I encourage you to do a bit of research. For that you get a Gigabyte (GB) of RAM, a processor, and 40GB of SSD (Static Storage Device = faster) storage. That's <em>oodles</em> of grunt for what this application requires.</p> <p>I suggest you create an account for yourself (and I encourage you to use Two Factor Authentication, aka 2FA) and create an Ubuntu 18.04 (or the most recent LTS version - the next will be 20.04, in April 2020 :) ) in the zone nearest to you. You'll need to note the server's IP address (it'll be a series of 4 numbers, 0-254, separated by full stops, e.g. 103.99.72.244). With that, you can <a href="https://www.digitalocean.com/community/tutorials/how-to-use-ssh-to-connect-to-a-remote-server-in-ubuntu">log into it via SSH</a>.</p> <h3>Get your Domain lined up</h3> <p>You will want to have a domain to point at your server, so you don't have to remember the IP number. There're are thousands of domain "registrars" in the world who'll help you do that... You just need to "register" a name, and you pay yearly fee (usually between USD10-30 depending on the country and the "TLD" (Top Level Domain. There're national ones like .nz, .au, .uk, .tv, .sa, .za, etc., or international domains (mostly associated with the US) like .com, .org, .net, and a myriad of others. Countries decide on how much their domains wholesale for and registrars add a margin for the registration service).</p> <p>Here in NZ, I use the services of <a href="https://metaname.net">Metaname</a> (they're local to me in Christchurch, and I know them personally and trust their technical capabilities). If you're not sure who to use, ask your friends. Someone's bound to have recommendations (either positive or negative, in which case you'll know who to avoid).</p> <p>If you want to use your domain for other things besides your BitWarden instance, I'd encourage you to use a <em>subdomain</em>, like (my usual choice) is "safe.domainname", namely the subdomain "safe" of "domainname".</p> <p>Once you have selected and registered your domain, you can set up (usually through a web interface provided by the registrar) an "A Record" which associates your website's name to the IP address of your server. So you should just be able to enter your server's IP address, the domain name (or sub-domain) you want to use for your BitWarden service, and that's it. For a password safe, I tend to use the subdomain "safe", so, for example, safe.mydomain.nz or similar.</p> <p>You might be asked to set a "Time-to-live" (which has to do with the length of time Domain Name Servers are asked to "cache" the association that the A Record specifies) in which case you can put in 3600 seconds or an hour depending on the time units your interface requests... but in most cases that'll be set to a default of an hour automatically.</p> <p>You should be able to test that your A Record has been set correctly by SSHing to your domain name rather than the IP address. It should (after you accept the SSH warning that the server's name has changed) work the same way your original SSH login did.</p> <h3>Set up a Docker Server</h3> <p>Once I've first logged into it as the "root" (full admin) user, here's what I usually do:</p> <ol><li>I create an "unprivileged user", either with my name "dave" or sometimes an "ubuntu" user (some hosting providers create a default unprivileged user of "ubuntu" when you create an Ubuntu-based virtual machine. Some create a "debian" user for Debian-based VMs, etc.) via<br /><code>adduser ubuntu</code></li> <li>I install a few core applications: my preferred editor <a href="https://en.wikipedia.org/wiki/Vim_(text_editor)">vim</a> (<a href="https://en.wikipedia.org/wiki/GNU_nano">nano</a> is another easy option and comes pre-installed on Ubuntu), version control system, <a href="https://en.wikipedia.org/wiki/Git">git</a>, and a very handy configuration tracker, <a href="http://joeyh.name/code/etckeeper/">etckeeper</a>:<br /><code>apt-get update &amp;&amp; apt-get install vim git etckeeper</code></li> <li>I do some basic configuration of git (replace the [tokens] with the real values for you, minus the []):<br /><code>git config --global user.email "[your email]"<br /> git config --global user.name "[your full name, e.g. Jane Doe]"</code></li> <li>Initialise etckeeper - it will track configuration changes you make to your system which can be invaluable in replicating a server or working out what's changed if something breaks.<br /><code>etckeeper init<br /> etckeeper commit -m "initial commit of BitWarden host"</code></li> <li>Install Docker dependencies:<br /><code>apt-get install apt-transport-https ca-certificates curl software-properties-common pwgen</code><br /> Install secure key needed to add the docker.com package repository to your system<br /><code>curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -</code><br /> Confirm the key is valid<br /><code>apt-key fingerprint 0EBFCD88</code><br /> (you should see something like "<code>uid [ unknown] Docker Release (CE deb) &lt;docker@docker.com&gt;</code>" among the 4 lines)</li> <li>Add the repository for your Ubuntu version (this will pick it automatically)<br /><code>add-apt-repository    "deb [arch=amd64] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable"</code></li> <li>Update the package repository to include the packages from docker.com<br /><code>apt-get update</code></li> <li>Install the Community Edition of the Docker service<br /><code>apt-get install docker-ce</code></li> <li>Add your unprivileged user ("ubuntu" in this case - substitute the unprivileged user you created!) to a new "docker" group and add that user to other useful groups:<br /><code>groupadd docker<br /> adduser ubuntu<br /> adduser ubuntu sudoers<br /> adduser ubuntu admin</code><br /><code>adduser ubuntu docker</code></li> <li>Create an SSH key for your unprivileged user and allow logins for that user from external connection:<br /><code>sudo -Hu ubuntu ssh-keygen -t rsa<br /> cp /root/.ssh/authorized_keys /home/ubuntu/.ssh/<br /> chown ubuntu:ubuntu /home/ubuntu/.ssh/<br /> adduser ubuntu ssh</code></li> <li>Install the Python packaging system, "pip" to allow you to install and maintain the Docker Compose framework for managing collections of Docker containers:<br /><code>apt install python-pip<br /> pip install -U pip<br /> pip install docker-compose</code></li> <li>Set a convenience variable for [your domain] here (note: it'll only be recognised for this session, i.e. until you log out):<br /><code>DOMAIN=[your domain]<br /> USER=[unprivileged user, e.g. ubuntu]</code><br /> Below, anytime you see $DOMAIN in a command, it'll be replaced by whatever you put in for [your domain] and similarly $USER...</li> <li>Create directories to hold both the Docker Compose configurations and the persistent data you don't want to lose if you remove your Docker containers (namely your password database and configuration information):<br /><code>mkdir -p /home/docker/$DOMAIN &amp;&amp; mkdir -p /home/data/$DOMAIN<br /> chown -R ${USER}:${USER} /home/data /home/docker/</code></li> <li>Install the NGINX (pronounced "Engine X") webserver which will act as a reverse proxy for the BitWarden service and terminate the encryption via HTTPS:<br /><code>apt-get install nginx-full</code></li> <li>Configure the server's firewill and make an exception for SSH and NGINX services<br /><code>ufw allow OpenSSH<br /> ufw allow "Nginx Full"<br /> ufw enable</code><br /> Check that its running via<br /><code>ufw status</code></li> <li>Create a directory for including files for NGINX<br /><code>cd /etc/nginx</code><br /><code>mkdir includes</code><br /> Choose your text editor for editing files. Here're options for Vim or Nano - you can install and select others. Setting the EDIT shall variable allows you to copy and paste these commands regardless of which editor you prefer as it'll replace the value of $EDIT with the full path to your preferred editor.<br /><code>EDIT=`which nano`</code> or <code>EDIT=`which vim`</code></li> <li>To support encrypted data transfer between external devices and your server using HTTPS,  you need a valid SSL certificate. Until recently, these were costly and hard to get. With <a href="/protecting-your-users-lets-encrypt-ssl-certs">Let's Encrypt</a>, they've become a straightforward and essential part of any good (user-respecting) web site or service. To facilitate getting and periodically renewing your SSL certificate, you need to create the file letsencrypt.conf:<br /><code>$EDIT includes/letsencrypt.conf</code><br /> and enter the following content: <p><blockcode><code>#############################################################################<br /> # Configuration file for Let's Encrypt ACME Challenge location<br /> # This file is already included in listen_xxx.conf files.<br /> # Do NOT include it separately!<br /> #############################################################################<br /> #<br /> # This config enables to access /.well-known/acme-challenge/xxxxxxxxxxx<br /> # on all our sites (HTTP), including all subdomains.<br /> # This is required by ACME Challenge (webroot authentication).<br /> # You can check that this location is working by placing ping.txt here:<br /> # /var/www/letsencrypt/.well-known/acme-challenge/ping.txt<br /> # And pointing your browser to:<br /> # http://xxx.domain.tld/.well-known/acme-challenge/ping.txt<br /> #<br /> # Sources:<br /> # https://community.letsencrypt.org/t/howto-easy-cert-generation-and-renewal-with-nginx/3491<br /> #<br /> # Rule for legitimate ACME Challenge requests<br /> location ^~ /.well-known/acme-challenge/ {<br />     default_type "text/plain";<br />     # this can be any directory, but this name keeps it clear<br />     root /var/www/letsencrypt;<br /> }<br /> # Hide /acme-challenge subdirectory and return 404 on all requests.<br /> # It is somewhat more secure than letting Nginx return 403.<br /> # Ending slash is important!<br /> location = /.well-known/acme-challenge/ {<br />     return 404;<br /> }</code></blockcode></p> </li> <li> <p>Now you need to create the directory described in the letsencrypt.conf file:<br /><code>mkdir /var/www/letsencrypt</code></p> </li> <li> <p>Create "<a href="https://raymii.org/s/tutorials/Strong_SSL_Security_On_nginx.html#Forward_Secrecy_&amp;_Diffie_Hellman_Ephemeral_Parameters">forward secrecy &amp; Diffie Hellman ephemeral parameters</a>" to make your server more secure... The result will be a secure signing key stored in <code>/etc/ssl/certs/dhparam.pem</code> (note, getting enough "entropy" to generate sufficient randomness to calculate this will take a few minutes!<code>):</code><br /><code>openssl dhparam -out /etc/ssl/certs/dhparam.pem 4096</code></p> </li> <li> <p>and then you need to create the reverse proxy configuration file as follows:<br /><code>cd ../sites-available</code><br /><br /> and fill it with this content, replacing all [tokens] with your relevant values:<br /><blockcode><code>#<br /> # HTTP does *soft* redirect to HTTPS<br /> #<br /> server {<br />     # add [IP-Address:]80 in the next line if you want to limit this to a single interface<br />     listen 0.0.0.0:80;<br />     </code></blockcode><blockcode><code>server_name [your domain];<br />     root /home/data/[your domain];<br />     index index.php;<br /><br />     # change the file name of these logs to include your server name<br />     # if hosting many services...<br />     access_log /var/log/nginx/[your domain]_access.log;<br />     error_log /var/log/nginx/[your domain]_error.log;  <br />     include includes/letsencrypt.conf;</code></blockcode><blockcode><br /><br /><code>    # redirect all HTTP traffic to HTTPS.<br />     location / {<br />         return  302 https://[your domain]$request_uri;<br />     }<br /> }</code></blockcode><br /> and make the configuration available to NGINX by linking the file from sites-available into sites-enabled (you can disable the site by removing the link and reloading NGINX)<br /><code>ln -sf sites-available/bitwarden sites-enabled/bitwarden</code><br /> Check to make sure NGINX is happy with the configuration<br /><code>nginx -t </code><br /> If you don't get any errors, you can restart NGINX<br /><code>service nginx restart</code><br /> and it should be configured properly to respond to requests at <code>http://[your domain]/.well-known/acme-challenge/ </code>which is required for creating a Let's Encrypt certificate.<br /><code>$EDIT sites-available/bitwarden</code></p> </li> <li> <p>So now we can create the certificate. You'll need to install the letscencrypt scripts:<br /><code>apt-get install letsencrypt</code><br /> You will be asked to enter some information about yourself, including an email address - this is necessary so that the letsencrypt service can email you if any of your certificates are not successfully updated (they need to be renewed every few weeks - normally this happens automatically!) so that you site and users aren't affected by an expired SSL certificate (a bad look!). Trust me, these folks are the good guys.<br /> You create a certificate for [your domain] with the following command (with relevant substitutions):<br /><code>letsencrypt certonly --webroot -w /var/www/letsencrypt -d $DOMAIN</code><br /> If the process works, you should see a "Congratulations!" message.</p> </li> <li> <p>Edit the nginx configuration file for the BitWarden service again<br /><code>$EDIT sites-available/bitwarden</code><br /> and add the following to the bottom of <code>file (starting the line below the final "}")<br /><blockcode>#<br /> # HTTPS<br /> #<br /> # This assumes you're using Let's Encrypt for your SSL certs (and why wouldn't<br /> # you!?)... https://letsencrypt.org<br /> server {<br />     # add [IP-Address:]443 ssl in the next line if you want to limit this to a single interface<br />     listen 0.0.0.0:443 ssl;<br />     ssl on;<br />     ssl_certificate /etc/letsencrypt/live/[your domain]/fullchain.pem;<br />     ssl_certificate_key /etc/letsencrypt/live/[your domain]/privkey.pem;<br />     ssl_protocols TLSv1 TLSv1.1 TLSv1.2;<br />     # to create this, see https://raymii.org/s/tutorials/Strong_SSL_Security_On_nginx.html<br />     ssl_dhparam /etc/ssl/certs/dhparam.pem;<br />     keepalive_timeout 20s;</blockcode></code><blockcode></blockcode><blockcode><br /><code>    server_name [your domain];<br />     root /home/data/[your domain];<br />     index index.php;</code></blockcode><blockcode><br /><code>    # change the file name of these logs to include your server name<br />     # if hosting many services...<br />     access_log /var/log/nginx/[your domain]_access.log;<br />     error_log /var/log/nginx/[your domain]_error.log;</code></blockcode><blockcode><br /><br /><code>    location /notifications/hub/negotiate {<br />         proxy_pass http://127.0.0.1:8080;<br />         proxy_set_header Upgrade $http_upgrade;<br />         proxy_set_header Connection "upgrade";<br />         proxy_set_header Host $http_host;<br />         proxy_set_header X-Real-IP $remote_addr;<br />         proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;<br />         proxy_set_header X-Forwarded-Host $server_name;<br />         proxy_set_header X-Forwarded-Proto https;<br />         proxy_connect_timeout 2400;<br />         proxy_read_timeout 2400;<br />         proxy_send_timeout 2400;<br />     }</code></blockcode><blockcode><br /><code>    location / {<br />         proxy_pass http://127.0.0.1:8080;<br />         proxy_set_header Upgrade $http_upgrade;<br />         proxy_set_header Connection "upgrade";<br />         proxy_set_header Host $http_host;<br />         proxy_set_header X-Real-IP $remote_addr;<br />         proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;<br />         proxy_set_header X-Forwarded-Host $server_name;<br />         proxy_set_header X-Forwarded-Proto https;<br />         proxy_connect_timeout 2400;<br />         proxy_read_timeout 2400;<br />         proxy_send_timeout 2400;<br />     }</code></blockcode><blockcode><br /><code>    location /notifications/hub {<br />         proxy_pass http://127.0.0.1:3012;<br />         proxy_set_header Upgrade $http_upgrade;<br />         proxy_set_header Connection "upgrade";<br />     }<br />     #<br />     # These "harden" your security<br />     add_header 'Access-Control-Allow-Origin' "*";<br /> }</code></blockcode></p> </li> <li>You should now be able to run<br /><code>nginx -t </code><br /> again, and it you haven't got an accidental errors in the files, it should return no errors. You can restart nginx to make sure it picks up your SSL certificates...<br /><code>service nginx restart</code></li> </ol><p>Now everything is read to set up your BitWarden Docker containers!</p> <h3>Setting up your BitWarden "rust" service</h3> <p>Before we start this part, you'll need a few bits of information. First, you'll need a 64 character random string to be your "admin token"... you can create that like this:<br /><code>pwgen -y 64 1</code></p> <p>copy the result (highlight the text and hit CTRL+SHIFT+C) and paste it somewhere so you can copy-and-paste it into the file below later.</p> <p>Also, if you want your BitWarden server to be able to send out emails, like for password recovery, you'll need to have an "authenticating SMTP email account"... I would recommend setting one up specifically for this purpose. You can use a random gmail account or any other email account that lets you send mail by logging into an SMTP (Simple Mail Transfer Protocol) server, i.e. most mail servers. You'll need to know the SMTP [host name], the [port] (usually 465 or 587), the [login security] (usually "true" or "TLS"), and your authenticating [username] (possibly this is also the email address) and [password]. You'll also need a "[from email] like bitwarden@[your domain] or similar, which will be the sender of email from your server.</p> <p>You're going to be setting up your configuration in the directory we created earlier, so run<br /><code>cd /home/docker/$DOMAIN</code></p> <p>and there<br /><code>$EDIT docker-compose.yml</code></p> <p>copy-and-pasting in the following, replacing the [tokens] appropriately:</p> <p><blockcode><code>version: "3"<br /> services:<br />     app:<br />         image: vaultwarden/server<br />         environment:<br />             - DOMAIN=https://[your domain]<br />             - WEBSOCKET_ENABLED=true<br />             - SIGNUPS_ALLOWED=false<br />             - LOG_FILE=/data/bitwarden.log<br />             - INVITATIONS_ALLOWED=true<br />             - ADMIN_TOKEN=[admin token]<br />             - SMTP_HOST=[host name]<br />             - SMTP_FROM=[from email]<br />             - SMTP_PORT=[port]<br />             - SMTP_SSL=[login security]<br />             - SMTP_USERNAME=[username]<br />             - SMTP_PASSWORD=[password]<br />         volumes:<br />             - /home/data/[your domain]/data/:/data/<br />         ports:<br />             - "127.0.0.1:8080:80"<br />             - "127.0.0.1:3012:3012"<br />         restart:<br />             unless-stopped</code></blockcode></p> <p><em>Note that the indentation has to be exact in this file - Docker Compose will complain otherwise.</em></p> <p>With the docker-compose file completed, you're ready to "pull" your package!</p> <p><code>docker-compose pull</code></p> <p>This will download the BitWarden Docker container from hub.docker.com. Then all you need to do is start it:</p> <p><code>docker-compose up -d &amp;&amp; docker-compose logs -f</code></p> <p>the "up -d" option actually starts the container called "app" which is actually your BitWarden rust server in "daemon" mode, which means it'll keep running unless you tell it to stop. If that's successful, it automatically then shows you the logs of that container. You can exit at any time with CTRL-C which will put you back on the command prompt. If you <em>do</em> want the container to stop, just run</p> <p><code>docker-compose stop</code></p> <p>If your start up was successful, you should see a message like this (albeit your version number could be higher - 1.9.0 is the current version of the Rust implementation at the time of writing):</p> <p><blockcode><code>/--------------------------------------------------------------------\<br /> |                       Starting Bitwarden_RS                        |<br /> |                           Version 1.9.0                            |<br /> |--------------------------------------------------------------------|<br /> | This is an *unofficial* Bitwarden implementation, DO NOT use the   |<br /> | official channels to report bugs/features, regardless of client.   |<br /> | Report URL: https://github.com/dani-garcia/bitwarden_rs/issues/new |<br /> \--------------------------------------------------------------------/</code></blockcode></p> <p>You should now be able to point your browser at <code>http://[your domain]</code> which, in turn, should automatically redirect you to <code><strong>https://</strong>[your domain]</code> and you should see the BitWarden web front end similar to that shown in the attached screen shot!</p> <h3>First Login!</h3> <p>To do your initial login by going to <code><strong>https://</strong>[your domain]<strong>/admin/</strong> and</code> you'll be asked to provide your "admin token" (a random string you created earlier for your docker-compose.yml file, where you should be able to find it) to create a first user with administration privileges. That will allow you to create your initial personal user and other useful stuff.</p> <p>For additional info on setting up these services - and new options as Daniel and his co-developers add them in - consult the <a href="https://github.com/dani-garcia/bitwarden_rs">repository pages</a> and <a href="https://github.com/dani-garcia/bitwarden_rs/issues">issues</a> and for Docker-specific questions, look at <a href="https://github.com/mprasil/bitwarden_rs">mpasil's pages</a>.</p> <h3>Sending Emails</h3> <p>It'll be worth testing if your email services work, like by requesting a password hint! You should be able to see what the server's doing via the</p> <p><code>docker-compose logs -f</code></p> <h2>Tips</h2> <p>I recommend <em>not </em>including your login credentials to your BitWarden instance in your BitWarden database ;) that's the one thing you need to remember. If you need to write it down somewhere, then do so (but make sure you don't include <em>all</em> the info needed to log in on the same piece of paper, that's just asking for trouble).</p> <p>Also, you can easily configure all the BitWarden clients - browser plugins, mobile apps, or the desktop app -  to use your server rather than BitWarden's default hosted service. Just click the "gear" settings icon on each app's interface, and set the "Self-Hosted Environment" Server URL to be your server, i.e. https://[your domain]</p> <h3>Backing it all up</h3> <p>I've created a SQLite backup script (which maintains automatic versioned hourly, daily, weekly, monthly, and yearly database dumps, the content in which is encrypted) <a href="/automatic-versioned-backups-sqlite-docker-compose-container">described in more detail in another post</a>...</p> <h3>Two Factor Authentication</h3> <p>This configuration should allow you to simply turn on Two Factor Authentication for any given BitWarden user.</p> <h3>Keeping it up-to-date</h3> <p>One of the best things about this Docker configuration is that it's very straightforward to upgrade your installation to Daniel's (via mpasil's Docker work) latest server version. Just log into the server as your unprivileged user,</p> <p><code>cd /home/docker/[your domain]<br /> docker-compose  pull<br /> docker-compose up -d &amp;&amp; docker-compose logs -f</code></p> <p>The whole process shouldn't take much more than a minute, with a few seconds downtime only as your new Docker BitWarden container is being created...</p> <p>Hope this helps a few folks! If you find any of the above doesn't work, please let me know in the comments. I'll do my best to make sure this how-to is accurate and up-to-date, and I'll do my best to assist people if they're having trouble.</p> <p>Have (secure and private) fun!</p> </div> </div> </div> <section class="field field-node--field-blog-comments field-name-field-blog-comments field-type-comment field-label-above comment-wrapper"> <a name="comments"></a> <h2 class="comment-field__title">Blog comments</h2> <article data-comment-user-id="0" id="comment-164" class="comment js-comment by-anonymous has-title clearfix"> <div class="comment__container"> <h3 class="comment__title"> <a href="/comment/164#comment-164" class="permalink" rel="bookmark" hreflang="en">Excellent blog</a> <span class="comment__new marker marker--success hidden" data-comment-timestamp="1571734038"></span> </h3> <div class="comment__meta"> <div class="comment__submitted"> <span class="comment__author"><span>cocoonkid (not verified)</span></span> <span class="comment__pubdate">Wed 09/10/2019 - 00:19</span> </div> </div> <div class="comment__content"> <div class="clearfix text-formatted field field-comment--comment-body field-name-comment-body field-type-text-long field-label-hidden"> <div class="field__items"> <div class="field__item"><p>Really appreciate the document. </p> <p>Would love to see these too:</p> <p>To do your initial login, I believe (I&#039;ll test this and update this howto!) you&#039;ll be asked to provide your &quot;admin token&quot; to create a first user with administration privileges.</p> <p>&amp;</p> <p>I&#039;ll add information on my SQLite backup scripts (which maintain automatic versioned hourly, daily, weekly, monthly, and yearly database dumps, the content in which is encrypted)...</p> <p>Thanks!</p> </div> </div> </div> <drupal-render-placeholder callback="comment.lazy_builders:renderLinks" arguments="0=164&amp;1=default&amp;2=en&amp;3=" token="SQxJH8_hmUFGP5a1HuPe5YGDeqKAH7IJWa-lrTf5AVs"></drupal-render-placeholder> </div> </div> </article> <div class="indented"><article data-comment-user-id="1" id="comment-167" class="comment js-comment by-node-author has-title clearfix"> <div class="comment__container"> <h3 class="comment__title"> <a href="/comment/167#comment-167" class="permalink" rel="bookmark" hreflang="en">Fair call! Leave it with me…</a> <span class="comment__new marker marker--success hidden" data-comment-timestamp="1571734079"></span> </h3> <div class="comment__meta"> <div class="comment__submitted"> <span class="comment__author"><a title="View user profile." href="/user/1" class="username">dave</a></span> <span class="comment__pubdate">Tue 22/10/2019 - 21:47</span> </div> </div> <div class="comment__content"> <p class="comment__parent visually-hidden">In reply to <a href="/comment/164#comment-164" class="permalink" rel="bookmark" hreflang="en">Excellent blog</a> by <span>cocoonkid (not verified)</span></p> <div class="clearfix text-formatted field field-comment--comment-body field-name-comment-body field-type-text-long field-label-hidden"> <div class="field__items"> <div class="field__item"><p>Fair call! Leave it with me...</p> </div> </div> </div> <drupal-render-placeholder callback="comment.lazy_builders:renderLinks" arguments="0=167&amp;1=default&amp;2=en&amp;3=" token="5EsOUo5fz0dhfO2bRk_l-ywwj6OH5l8p9nz86QNDu_A"></drupal-render-placeholder> </div> </div> </article> <div class="indented"><article data-comment-user-id="1" id="comment-342" class="comment js-comment by-node-author has-title clearfix"> <div class="comment__container"> <h3 class="comment__title"> <a href="/comment/342#comment-342" class="permalink" rel="bookmark" hreflang="en">Backup script update...</a> <span class="comment__new marker marker--success hidden" data-comment-timestamp="1581631657"></span> </h3> <div class="comment__meta"> <div class="comment__submitted"> <span class="comment__author"><a title="View user profile." href="/user/1" class="username">dave</a></span> <span class="comment__pubdate">Fri 14/02/2020 - 11:07</span> </div> </div> <div class="comment__content"> <p class="comment__parent visually-hidden">In reply to <a href="/comment/167#comment-167" class="permalink" rel="bookmark" hreflang="en">Fair call! Leave it with me…</a> by <a title="View user profile." href="/user/1" class="username">dave</a></p> <div class="clearfix text-formatted field field-comment--comment-body field-name-comment-body field-type-text-long field-label-hidden"> <div class="field__items"> <div class="field__item"><p>I've published a new post which describes the SQLite backup script and points to the publicly visible git repo, linked in the article now. I've also updated the question of the admin code...</p> </div> </div> </div> <drupal-render-placeholder callback="comment.lazy_builders:renderLinks" arguments="0=342&amp;1=default&amp;2=en&amp;3=" token="ukuAKkHDAuErmOn-ice3ptjHTOoqGV13cGbtjg82D9k"></drupal-render-placeholder> </div> </div> </article> </div></div><article data-comment-user-id="0" id="comment-788" class="comment js-comment by-anonymous has-title clearfix"> <div class="comment__container"> <h3 class="comment__title"> <a href="/comment/788#comment-788" class="permalink" rel="bookmark" hreflang="en">Thank You!</a> <span class="comment__new marker marker--success hidden" data-comment-timestamp="1599790208"></span> </h3> <div class="comment__meta"> <div class="comment__submitted"> <span class="comment__author"><span>SS (not verified)</span></span> <span class="comment__pubdate">Tue 08/09/2020 - 07:06</span> </div> </div> <div class="comment__content"> <div class="clearfix text-formatted field field-comment--comment-body field-name-comment-body field-type-text-long field-label-hidden"> <div class="field__items"> <div class="field__item"><p>This is the best tutorial I&#039;ve come across for getting BitWarden up and running on a Pi.</p> <p>It worked the first time through. There a couple nice things that aren&#039;t obvious to the newbie that I tracked down after everything was up and running. Setting a docker restart policy for the BW container that ensures that the container comes up after a power interruption was a pleasant surprise. </p> <p>One thing that isn&#039;t clear to the absolute newbie is that it&#039;s probably better to set up on a subdomain rather than a domain if you want to use NGINX for serving other things. I wasn&#039;t thinking about that when I did the initial setup, and that&#039;s leading to rework... Ideally, I&#039;d like to have BitWarden sitting on a nonobvious subdomain, and serve up other things on the obvious ones, like the bare domain or <a href="http://www.example.xyz">www.example.xyz</a>.</p> <p>Again, thanks for a great post.</p> </div> </div> </div> <drupal-render-placeholder callback="comment.lazy_builders:renderLinks" arguments="0=788&amp;1=default&amp;2=en&amp;3=" token="9n0zD1HbCjrKLmdvYGdyrEz07IZBRPpAphuhUIdiciQ"></drupal-render-placeholder> </div> </div> </article> <div class="indented"><article data-comment-user-id="1" id="comment-793" class="comment js-comment by-node-author has-title clearfix"> <div class="comment__container"> <h3 class="comment__title"> <a href="/comment/793#comment-793" class="permalink" rel="bookmark" hreflang="en">Use a subdomain!</a> <span class="comment__new marker marker--success hidden" data-comment-timestamp="1599792389"></span> </h3> <div class="comment__meta"> <div class="comment__submitted"> <span class="comment__author"><a title="View user profile." href="/user/1" class="username">dave</a></span> <span class="comment__pubdate">Fri 11/09/2020 - 14:46</span> </div> </div> <div class="comment__content"> <p class="comment__parent visually-hidden">In reply to <a href="/comment/788#comment-788" class="permalink" rel="bookmark" hreflang="en">Thank You!</a> by <span>SS (not verified)</span></p> <div class="clearfix text-formatted field field-comment--comment-body field-name-comment-body field-type-text-long field-label-hidden"> <div class="field__items"> <div class="field__item"><p>Thanks for the suggestion, SS - I've added a note regarding using subdomains! And thanks for the positive feedback - hope your BitWarden is providing you with what you need!</p> </div> </div> </div> <drupal-render-placeholder callback="comment.lazy_builders:renderLinks" arguments="0=793&amp;1=default&amp;2=en&amp;3=" token="mDd3QaMURnHddjJwNSFd8gkASpIOnAaSZq2qA6Z7QIM"></drupal-render-placeholder> </div> </div> </article> </div><article data-comment-user-id="0" id="comment-791" class="comment js-comment by-anonymous has-title clearfix"> <div class="comment__container"> <h3 class="comment__title"> <a href="/comment/791#comment-791" class="permalink" rel="bookmark" hreflang="en">Login</a> <span class="comment__new marker marker--success hidden" data-comment-timestamp="1599790281"></span> </h3> <div class="comment__meta"> <div class="comment__submitted"> <span class="comment__author"><span>Daniel Lamb (not verified)</span></span> <span class="comment__pubdate">Fri 11/09/2020 - 04:20</span> </div> </div> <div class="comment__content"> <div class="clearfix text-formatted field field-comment--comment-body field-name-comment-body field-type-text-long field-label-hidden"> <div class="field__items"> <div class="field__item"><p>Hello,<br /> sorry might be being thick here but trying to login after follwing the setup guide and dont know what I should put in the username, I am using the token generated and in the yaml file.</p> <p>Daniel</p> </div> </div> </div> <drupal-render-placeholder callback="comment.lazy_builders:renderLinks" arguments="0=791&amp;1=default&amp;2=en&amp;3=" token="2-gy49yCLhcMgXJLWSm-gmP574jf4pcpE4YajzKnBZ8"></drupal-render-placeholder> </div> </div> </article> <div class="indented"><article data-comment-user-id="1" id="comment-792" class="comment js-comment by-node-author has-title clearfix"> <div class="comment__container"> <h3 class="comment__title"> <a href="/comment/792#comment-792" class="permalink" rel="bookmark" hreflang="en">First login...</a> <span class="comment__new marker marker--success hidden" data-comment-timestamp="1599792248"></span> </h3> <div class="comment__meta"> <div class="comment__submitted"> <span class="comment__author"><a title="View user profile." href="/user/1" class="username">dave</a></span> <span class="comment__pubdate">Fri 11/09/2020 - 14:44</span> </div> </div> <div class="comment__content"> <p class="comment__parent visually-hidden">In reply to <a href="/comment/791#comment-791" class="permalink" rel="bookmark" hreflang="en">Login</a> by <span>Daniel Lamb (not verified)</span></p> <div class="clearfix text-formatted field field-comment--comment-body field-name-comment-body field-type-text-long field-label-hidden"> <div class="field__items"> <div class="field__item"><p>Hi Daniel,</p> <p>Sorry that I wasn't clear - to be honest, I'm not sure what the latest versions use for the first login, but from memory, the very first visitor to a new BitWarden site sees a special login form asking them to enter their Admin Token which then allows them to set up their normal user login details (an email address and passphrase)... If you <em>don't </em>see something like that, then I would expect you could remove the Sqlite db file forcing a reinitialisation of the system.</p> </div> </div> </div> <drupal-render-placeholder callback="comment.lazy_builders:renderLinks" arguments="0=792&amp;1=default&amp;2=en&amp;3=" token="vah-Jl2qUpIYJyQ7onBYSC8CaaSRZgWoiMkqd4n-2B4"></drupal-render-placeholder> </div> </div> </article> </div><article data-comment-user-id="0" id="comment-797" class="comment js-comment by-anonymous has-title clearfix"> <div class="comment__container"> <h3 class="comment__title"> <a href="/comment/797#comment-797" class="permalink" rel="bookmark" hreflang="en">Can you update this for…</a> <span class="comment__new marker marker--success hidden" data-comment-timestamp="1607799359"></span> </h3> <div class="comment__meta"> <div class="comment__submitted"> <span class="comment__author"><span>Terry (not verified)</span></span> <span class="comment__pubdate">Sun 13/12/2020 - 04:54</span> </div> </div> <div class="comment__content"> <div class="clearfix text-formatted field field-comment--comment-body field-name-comment-body field-type-text-long field-label-hidden"> <div class="field__items"> <div class="field__item"><p>Can you update this for Ubuntu 20.xx and Python3? I&#039;ve tried to deploy, and failed.</p> </div> </div> </div> <drupal-render-placeholder callback="comment.lazy_builders:renderLinks" arguments="0=797&amp;1=default&amp;2=en&amp;3=" token="JNMITOrOBjpIJ84n2lKVRIjo67jxAlzBDQN4oiaLke8"></drupal-render-placeholder> </div> </div> </article> <div class="indented"><article data-comment-user-id="1" id="comment-798" class="comment js-comment by-node-author has-title clearfix"> <div class="comment__container"> <h3 class="comment__title"> <a href="/comment/798#comment-798" class="permalink" rel="bookmark" hreflang="en">Hi Terry, If you want to…</a> <span class="comment__new marker marker--success hidden" data-comment-timestamp="1607807686"></span> </h3> <div class="comment__meta"> <div class="comment__submitted"> <span class="comment__author"><a title="View user profile." href="/user/1" class="username">dave</a></span> <span class="comment__pubdate">Sun 13/12/2020 - 10:14</span> </div> </div> <div class="comment__content"> <p class="comment__parent visually-hidden">In reply to <a href="/comment/797#comment-797" class="permalink" rel="bookmark" hreflang="en">Can you update this for…</a> by <span>Terry (not verified)</span></p> <div class="clearfix text-formatted field field-comment--comment-body field-name-comment-body field-type-text-long field-label-hidden"> <div class="field__items"> <div class="field__item"><p>Hi Terry,</p> <p>If you want to use Python3 for Docker Compose, it's easy enough (although it's confusing depending on which distro you're running and whether Python3 is default or has to be designated as <code>python3</code> ... assuming you've got Python3 already installed, you can install pip via <code>sudo apt-get install python3-pip</code> and then you might need to use "pip3" installed by the package manager to install "pip"... e.g. <code>pip3 install pip</code> via the python package (which is independent of your package manager). You should then be able to install and update docker-compose via pip, e.g. <code>sudo pip install docker-compose</code> or, to upgrade, <code>sudo pip install -U docker-compose</code>. And if you want to upgrade pip itself, if you've previously installed pip via pip3, you can use <code>sudo pip install -U pip</code>. It's tricky when you have distro-managed installs and python-installed stuff, but hopefully you can get to the bottom of it - might require a bit of fiddling depending precisely which version/distro of Linux you're using.</p> </div> </div> </div> <drupal-render-placeholder callback="comment.lazy_builders:renderLinks" arguments="0=798&amp;1=default&amp;2=en&amp;3=" token="WTcKgRcmhSZALC_EZySMiwlOW0eOH36nw2wInHSL268"></drupal-render-placeholder> </div> </div> </article> <div class="indented"><article data-comment-user-id="0" id="comment-799" class="comment js-comment by-anonymous has-title clearfix"> <div class="comment__container"> <h3 class="comment__title"> <a href="/comment/799#comment-799" class="permalink" rel="bookmark" hreflang="en">Turns out it wasn&#039;t anything…</a> <span class="comment__new marker marker--success hidden" data-comment-timestamp="1607972415"></span> </h3> <div class="comment__meta"> <div class="comment__submitted"> <span class="comment__author"><span>Terry (not verified)</span></span> <span class="comment__pubdate">Tue 15/12/2020 - 01:20</span> </div> </div> <div class="comment__content"> <p class="comment__parent visually-hidden">In reply to <a href="/comment/798#comment-798" class="permalink" rel="bookmark" hreflang="en">Hi Terry, If you want to…</a> by <a title="View user profile." href="/user/1" class="username">dave</a></p> <div class="clearfix text-formatted field field-comment--comment-body field-name-comment-body field-type-text-long field-label-hidden"> <div class="field__items"> <div class="field__item"><p>Turns out it wasn&#039;t anything to do with python3 or pip, I had previously managed to have them installed &amp; working properly.<br /> Looks like it was something with the docker images host on the weekend when I was doing this as the docker pull command always errored out. I just did it now (Monday morning) and the pull worked, and docker up was successful.<br /> Thanks for the great tutorial!</p> </div> </div> </div> <drupal-render-placeholder callback="comment.lazy_builders:renderLinks" arguments="0=799&amp;1=default&amp;2=en&amp;3=" token="aGMZHpXsn6-Wvj9zGwd7njwt44jqKGsy2xJDZOP41CI"></drupal-render-placeholder> </div> </div> </article> <div class="indented"><article data-comment-user-id="1" id="comment-800" class="comment js-comment by-node-author has-title clearfix"> <div class="comment__container"> <h3 class="comment__title"> <a href="/comment/800#comment-800" class="permalink" rel="bookmark" hreflang="en">I&#039;m pleased to hear it all…</a> <span class="comment__new marker marker--success hidden" data-comment-timestamp="1607972457"></span> </h3> <div class="comment__meta"> <div class="comment__submitted"> <span class="comment__author"><a title="View user profile." href="/user/1" class="username">dave</a></span> <span class="comment__pubdate">Tue 15/12/2020 - 08:00</span> </div> </div> <div class="comment__content"> <p class="comment__parent visually-hidden">In reply to <a href="/comment/799#comment-799" class="permalink" rel="bookmark" hreflang="en">Turns out it wasn&#039;t anything…</a> by <span>Terry (not verified)</span></p> <div class="clearfix text-formatted field field-comment--comment-body field-name-comment-body field-type-text-long field-label-hidden"> <div class="field__items"> <div class="field__item"><p>I'm pleased to hear it all worked out for you! Enjoy!</p> </div> </div> </div> <drupal-render-placeholder callback="comment.lazy_builders:renderLinks" arguments="0=800&amp;1=default&amp;2=en&amp;3=" token="paAK9EdaOFVkj1k6yyTUH6vafn7J3iOShwHJ1ZKj7QU"></drupal-render-placeholder> </div> </div> </article> </div></div></div><article data-comment-user-id="0" id="comment-804" class="comment js-comment by-anonymous has-title clearfix"> <div class="comment__container"> <h3 class="comment__title"> <a href="/comment/804#comment-804" class="permalink" rel="bookmark" hreflang="en">we&#039;ve set up our own locally…</a> <span class="comment__new marker marker--success hidden" data-comment-timestamp="1616005887"></span> </h3> <div class="comment__meta"> <div class="comment__submitted"> <span class="comment__author"><span>Jeff (not verified)</span></span> <span class="comment__pubdate">Thu 18/03/2021 - 04:21</span> </div> </div> <div class="comment__content"> <div class="clearfix text-formatted field field-comment--comment-body field-name-comment-body field-type-text-long field-label-hidden"> <div class="field__items"> <div class="field__item"><p>we&#039;ve set up our own locally hosted bitwarden, &quot;oursite.bitwarden.com&quot; but want to either block or redirect our users from being able to inadvertently go to the main web-based bitwarden.com can you provide suggestions?</p> </div> </div> </div> <drupal-render-placeholder callback="comment.lazy_builders:renderLinks" arguments="0=804&amp;1=default&amp;2=en&amp;3=" token="oRxs6opoJeCa_tsOx_ISwx8am50pKkA07oeZQsnUgzQ"></drupal-render-placeholder> </div> </div> </article> <div class="indented"><article data-comment-user-id="1" id="comment-805" class="comment js-comment by-node-author has-title clearfix"> <div class="comment__container"> <h3 class="comment__title"> <a href="/comment/805#comment-805" class="permalink" rel="bookmark" hreflang="en">Interesting question... I&#039;m…</a> <span class="comment__new marker marker--success hidden" data-comment-timestamp="1616006000"></span> </h3> <div class="comment__meta"> <div class="comment__submitted"> <span class="comment__author"><a title="View user profile." href="/user/1" class="username">dave</a></span> <span class="comment__pubdate">Thu 18/03/2021 - 07:33</span> </div> </div> <div class="comment__content"> <p class="comment__parent visually-hidden">In reply to <a href="/comment/804#comment-804" class="permalink" rel="bookmark" hreflang="en">we&#039;ve set up our own locally…</a> by <span>Jeff (not verified)</span></p> <div class="clearfix text-formatted field field-comment--comment-body field-name-comment-body field-type-text-long field-label-hidden"> <div class="field__items"> <div class="field__item"><p>Interesting question... I'm afraid I can't think of an easy way to achieve that... :/ I'd say the best thing is to create BW users for your users and install and configure their clients for them. That way, they won't be able to lot into the bitwarden.com service with the same credentials....</p> </div> </div> </div> <drupal-render-placeholder callback="comment.lazy_builders:renderLinks" arguments="0=805&amp;1=default&amp;2=en&amp;3=" token="3iv1o5vcthvfWKPqQDTTZJ9Sh8SKnyT6WiOZm9hEpJg"></drupal-render-placeholder> </div> </div> </article> </div><article data-comment-user-id="0" id="comment-812" class="comment js-comment by-anonymous has-title clearfix"> <div class="comment__container"> <h3 class="comment__title"> <a href="/comment/812#comment-812" class="permalink" rel="bookmark" hreflang="en">Anybody who has the URL can…</a> <span class="comment__new marker marker--success hidden" data-comment-timestamp="1629771059"></span> </h3> <div class="comment__meta"> <div class="comment__submitted"> <span class="comment__author"><span>Philippe (not verified)</span></span> <span class="comment__pubdate">Tue 24/08/2021 - 14:09</span> </div> </div> <div class="comment__content"> <div class="clearfix text-formatted field field-comment--comment-body field-name-comment-body field-type-text-long field-label-hidden"> <div class="field__items"> <div class="field__item"><p>Anybody who has the URL can open an Bitwarden account on a self hosted installation. How do I control who can create a new account?</p> </div> </div> </div> <drupal-render-placeholder callback="comment.lazy_builders:renderLinks" arguments="0=812&amp;1=default&amp;2=en&amp;3=" token="CTzzNjnBjtIR96MLtSMFqjSId0xTu7vR_0xyaxdkMto"></drupal-render-placeholder> </div> </div> </article> <div class="indented"><article data-comment-user-id="1" id="comment-813" class="comment js-comment by-node-author has-title clearfix"> <div class="comment__container"> <h3 class="comment__title"> <a href="/comment/813#comment-813" class="permalink" rel="bookmark" hreflang="en">If you log in as an admin …</a> <span class="comment__new marker marker--success hidden" data-comment-timestamp="1629771146"></span> </h3> <div class="comment__meta"> <div class="comment__submitted"> <span class="comment__author"><a title="View user profile." href="/user/1" class="username">dave</a></span> <span class="comment__pubdate">Tue 24/08/2021 - 14:12</span> </div> </div> <div class="comment__content"> <p class="comment__parent visually-hidden">In reply to <a href="/comment/812#comment-812" class="permalink" rel="bookmark" hreflang="en">Anybody who has the URL can…</a> by <span>Philippe (not verified)</span></p> <div class="clearfix text-formatted field field-comment--comment-body field-name-comment-body field-type-text-long field-label-hidden"> <div class="field__items"> <div class="field__item"><p>If you log in as an admin (use the /admin URL - the password is in your docker-compose.yml file) you can disable random sign-ups (e.g. and make it invite-only). You can also disable any existing accounts you don't want there.</p></div> </div> </div> <drupal-render-placeholder callback="comment.lazy_builders:renderLinks" arguments="0=813&amp;1=default&amp;2=en&amp;3=" token="dbxstyS8y3OQ1Z6Vz7AIyPds-SIKszQNJDNpgzL4nHY"></drupal-render-placeholder> </div> </div> </article> </div> <div class="comment-form-wrapper"> <h2 class="comment-form__title">Add new comment</h2> <drupal-render-placeholder callback="comment.lazy_builders:renderForm" arguments="0=node&amp;1=25&amp;2=field_blog_comments&amp;3=comment" token="hKQtrXBA7ErwoC_B3-AO9Vd7GHqkXf0X-QAroc-dhuE"></drupal-render-placeholder> </div> </section> Fri, 20 Aug 2021 23:30:13 +0000 dave 25 at http://tech.oeru.org